Further P0135 refinement.
authorJason Merrill <jason@redhat.com>
Sat, 8 Oct 2016 16:23:26 +0000 (12:23 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Sat, 8 Oct 2016 16:23:26 +0000 (12:23 -0400)
* call.c (build_user_type_conversion_1): Consider conversions from
a single element in an initializer-list.
(build_temp): Undo early_elide_copy change.
(build_over_call): Check that we don't try to copy a TARGET_EXPR
in C++17 mode.  Set user_conv_p here.
(convert_like_real): Not here.
(check_self_delegation): Split out from...
(build_special_member_call): ...here.  Handle C++17 copy elision.
* cvt.c (early_elide_copy): Remove.
(ocp_convert): Undo early_elide_copy change.
* except.c (build_throw): Likewise.
* init.c (expand_default_init): Likewise.
* typeck.c (cp_build_modify_expr): Likewise.

From-SVN: r240889

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/except.c
gcc/cp/init.c
gcc/cp/typeck.c
gcc/testsuite/g++.dg/cpp0x/initlist12.C
gcc/testsuite/g++.dg/cpp1z/elide1.C
libstdc++-v3/testsuite/20_util/variant/compile.cc

index da2ca0750cfd9c14aa2da4d0ec730908dd3e2546..0bd0457f01a7c283cb57f93fe453c3319af83f95 100644 (file)
@@ -1,3 +1,20 @@
+2016-10-07  Jason Merrill  <jason@redhat.com>
+
+       Further P0135 refinement.
+       * call.c (build_user_type_conversion_1): Consider conversions from
+       a single element in an initializer-list.
+       (build_temp): Undo early_elide_copy change.
+       (build_over_call): Check that we don't try to copy a TARGET_EXPR
+       in C++17 mode.  Set user_conv_p here.
+       (convert_like_real): Not here.
+       (check_self_delegation): Split out from...
+       (build_special_member_call): ...here.  Handle C++17 copy elision.
+       * cvt.c (early_elide_copy): Remove.
+       (ocp_convert): Undo early_elide_copy change.
+       * except.c (build_throw): Likewise.
+       * init.c (expand_default_init): Likewise.
+       * typeck.c (cp_build_modify_expr): Likewise.
+
 2016-10-07  Nathan Sidwell  <nathan@acm.org>
 
        PR c++/64433
index 6feaf7e22c9563132a08f401b186a29bf27ad74c..4bee487857d7a63a19ef498fe87686b293195d1c 100644 (file)
@@ -3671,6 +3671,14 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags,
        creating a garbage BASELINK; constructors can't be inherited.  */
     ctors = lookup_fnfields_slot (totype, complete_ctor_identifier);
 
+  /* FIXME P0135 doesn't say what to do in C++17 about list-initialization from
+     a single element.  For now, let's handle constructors as before and also
+     consider conversion operators from the element.  */
+  if (cxx_dialect >= cxx1z
+      && BRACE_ENCLOSED_INITIALIZER_P (expr)
+      && CONSTRUCTOR_NELTS (expr) == 1)
+    fromtype = TREE_TYPE (CONSTRUCTOR_ELT (expr, 0)->value);
+
   if (MAYBE_CLASS_TYPE_P (fromtype))
     {
       tree to_nonref = non_reference (totype);
@@ -3745,7 +3753,13 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags,
     }
 
   if (conv_fns)
-    first_arg = expr;
+    {
+      if (BRACE_ENCLOSED_INITIALIZER_P (expr))
+       /* FIXME see above about C++17.  */
+       first_arg = CONSTRUCTOR_ELT (expr, 0)->value;
+      else
+       first_arg = expr;
+    }
 
   for (; conv_fns; conv_fns = TREE_CHAIN (conv_fns))
     {
@@ -6367,11 +6381,6 @@ build_temp (tree expr, tree type, int flags,
 
   *diagnostic_kind = DK_UNSPECIFIED;
 
-  if (TREE_CODE (expr) == CONSTRUCTOR)
-    expr = get_target_expr_sfinae (expr, complain);
-  if (early_elide_copy (type, expr))
-    return expr;
-
   /* If the source is a packed field, calling the copy constructor will require
      binding the field to the reference parameter to the copy constructor, and
      we'll end up with an infinite loop.  If we can use a bitwise copy, then
@@ -6563,7 +6572,6 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
       {
        struct z_candidate *cand = convs->cand;
        tree convfn = cand->fn;
-       unsigned i;
 
        /* When converting from an init list we consider explicit
           constructors, but actually trying to call one is an error.  */
@@ -6609,12 +6617,10 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 
        expr = mark_rvalue_use (expr);
 
-       /* Set user_conv_p on the argument conversions, so rvalue/base
-          handling knows not to allow any more UDCs.  */
-       for (i = 0; i < cand->num_convs; ++i)
-         cand->convs[i]->user_conv_p = true;
-
-       expr = build_over_call (cand, LOOKUP_NORMAL, complain);
+       /* Pass LOOKUP_NO_CONVERSION so rvalue/base handling knows not to allow
+          any more UDCs.  */
+       expr = build_over_call (cand, LOOKUP_NORMAL|LOOKUP_NO_CONVERSION,
+                               complain);
 
        /* If this is a constructor or a function returning an aggr type,
           we need to build up a TARGET_EXPR.  */
@@ -6792,6 +6798,10 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
        flags |= LOOKUP_ONLYCONVERTING;
       if (convs->rvaluedness_matches_p)
        flags |= LOOKUP_PREFER_RVALUE;
+      if (TREE_CODE (expr) == TARGET_EXPR
+         && TARGET_EXPR_LIST_INIT_P (expr))
+       /* Copy-list-initialization doesn't actually involve a copy.  */
+       return expr;
       expr = build_temp (expr, totype, flags, &diag_kind, complain);
       if (diag_kind && complain)
        {
@@ -7710,6 +7720,13 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
                       "  (you can disable this with -fno-deduce-init-list)");
            }
        }
+
+      /* Set user_conv_p on the argument conversions, so rvalue/base handling
+        knows not to allow any more UDCs.  This needs to happen after we
+        process cand->warnings.  */
+      if (flags & LOOKUP_NO_CONVERSION)
+       conv->user_conv_p = true;
+
       val = convert_like_with_context (conv, arg, fn, i - is_method,
                                       conversion_warning
                                       ? complain
@@ -7825,8 +7842,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
         subobject.  */
       if (CHECKING_P && cxx_dialect >= cxx1z)
        gcc_assert (TREE_CODE (arg) != TARGET_EXPR
-                   // FIXME we shouldn't copy for direct-init either
-                   || !(flags & LOOKUP_ONLYCONVERTING)
+                   || seen_error ()
                    /* See unsafe_copy_elision_p.  */
                    || DECL_BASE_CONSTRUCTOR_P (fn));
 
@@ -8089,6 +8105,19 @@ in_charge_arg_for_name (tree name)
   return NULL_TREE;
 }
 
+/* We've built up a constructor call RET.  Complain if it delegates to the
+   constructor we're currently compiling.  */
+
+static void
+check_self_delegation (tree ret)
+{
+  if (TREE_CODE (ret) == TARGET_EXPR)
+    ret = TARGET_EXPR_INITIAL (ret);
+  tree fn = cp_get_callee_fndecl (ret);
+  if (fn && DECL_ABSTRACT_ORIGIN (fn) == current_function_decl)
+    error ("constructor delegates to itself");
+}
+
 /* Build a call to a constructor, destructor, or an assignment
    operator for INSTANCE, an expression with class type.  NAME
    indicates the special member function to call; *ARGS are the
@@ -8162,6 +8191,38 @@ build_special_member_call (tree instance, tree name, vec<tree, va_gc> **args,
 
   gcc_assert (instance != NULL_TREE);
 
+  /* In C++17, "If the initializer expression is a prvalue and the
+     cv-unqualified version of the source type is the same class as the class
+     of the destination, the initializer expression is used to initialize the
+     destination object."  Handle that here to avoid doing overload
+     resolution.  */
+  if (cxx_dialect >= cxx1z
+      && args && vec_safe_length (*args) == 1
+      && name == complete_ctor_identifier)
+    {
+      tree arg = (**args)[0];
+
+      /* FIXME P0135 doesn't say how to handle direct initialization from a
+        type with a suitable conversion operator.  Let's handle it like
+        copy-initialization, but allowing explict conversions.  */
+      if (!reference_related_p (class_type, TREE_TYPE (arg)))
+       arg = perform_implicit_conversion_flags (class_type, arg,
+                                                tf_warning, flags);
+      if (TREE_CODE (arg) == TARGET_EXPR
+         && (same_type_ignoring_top_level_qualifiers_p
+             (class_type, TREE_TYPE (arg))))
+       {
+         if (is_dummy_object (instance))
+           return arg;
+         if ((complain & tf_error)
+             && (flags & LOOKUP_DELEGATING_CONS))
+           check_self_delegation (arg);
+         /* Avoid change of behavior on Wunused-var-2.C.  */
+         mark_lvalue_use (instance);
+         return build2 (INIT_EXPR, class_type, instance, arg);
+       }
+    }
+
   fns = lookup_fnfields (binfo, name, 1);
 
   /* When making a call to a constructor or destructor for a subobject
@@ -8206,11 +8267,8 @@ build_special_member_call (tree instance, tree name, vec<tree, va_gc> **args,
 
   if ((complain & tf_error)
       && (flags & LOOKUP_DELEGATING_CONS)
-      && name == complete_ctor_identifier 
-      && TREE_CODE (ret) == CALL_EXPR
-      && (DECL_ABSTRACT_ORIGIN (TREE_OPERAND (CALL_EXPR_FN (ret), 0))
-         == current_function_decl))
-    error ("constructor delegates to itself");
+      && name == complete_ctor_identifier)
+    check_self_delegation (ret);
 
   return ret;
 }
index 6a086277c34b6886ef1f0ca5c40cc66efba832f1..8b0442f9ff435907cfd691398e7674431f76140a 100644 (file)
@@ -5692,7 +5692,6 @@ extern tree convert_to_reference          (tree, tree, int, int, tree,
                                                 tsubst_flags_t);
 extern tree convert_from_reference             (tree);
 extern tree force_rvalue                       (tree, tsubst_flags_t);
-extern bool early_elide_copy                   (tree, tree);
 extern tree ocp_convert                                (tree, tree, int, int,
                                                 tsubst_flags_t);
 extern tree cp_convert                         (tree, tree, tsubst_flags_t);
index 063457f1c5e5c8cf28a244e4aea358649858aa87..2f5f15a2c8269c6f0ea003737b2828c4ee7ba203 100644 (file)
@@ -658,27 +658,6 @@ cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
   return result;
 }
 
-/* Returns true if we should avoid even doing overload resolution for copying
-   EXPR to initialize a TYPE.  */
-
-bool
-early_elide_copy (tree type, tree expr)
-{
-  if (TREE_CODE (expr) != TARGET_EXPR)
-    return false;
-  /* List-initialization and direct-initialization don't involve a copy.  */
-  if (TARGET_EXPR_LIST_INIT_P (expr)
-      || TARGET_EXPR_DIRECT_INIT_P (expr))
-    return true;
-  /* In C++17, "If the initializer expression is a prvalue and the
-     cv-unqualified version of the source type is the same class as the class
-     of the destination, the initializer expression is used to initialize the
-     destination object."  */
-  return (cxx_dialect >= cxx1z
-         && (same_type_ignoring_top_level_qualifiers_p
-             (type, TREE_TYPE (expr))));
-}
-
 /* Conversion...
 
    FLAGS indicates how we should behave.  */
@@ -714,8 +693,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
   if (error_operand_p (e))
     return error_mark_node;
 
-  if (MAYBE_CLASS_TYPE_P (type) && (convtype & CONV_FORCE_TEMP)
-      && !early_elide_copy (type, e))
+  if (MAYBE_CLASS_TYPE_P (type) && (convtype & CONV_FORCE_TEMP))
     /* We need a new temporary; don't take this shortcut.  */;
   else if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (e)))
     {
index 2f88082bf5e7ba2f0f2a4813dbf85b5f4b22751f..1c60b08bb1089a1167e6cae836057ee24a1f0e4f 100644 (file)
@@ -683,7 +683,7 @@ build_throw (tree exp)
       object = cp_build_indirect_ref (object, RO_NULL, tf_warning_or_error);
 
       /* And initialize the exception object.  */
-      if (CLASS_TYPE_P (temp_type) && !early_elide_copy (temp_type, exp))
+      if (CLASS_TYPE_P (temp_type))
        {
          int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING;
          vec<tree, va_gc> *exp_vec;
index a873bb165c16fbc1e0b2d9bc8ef0a8c106e21b3b..b4b5e0acd45e7a8c81ab6ba7486973aa65ca5703 100644 (file)
@@ -1644,13 +1644,6 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
        init = reshape_init (type, init, complain);
     }
 
-  /* Also pull out a TARGET_EXPR that we want to avoid copying.  */
-  if (init && true_exp == exp
-      && TREE_CODE (init) == TREE_LIST
-      && list_length (init) == 1
-      && early_elide_copy (type, TREE_VALUE (init)))
-    init = TREE_VALUE (init);
-
   if (init && BRACE_ENCLOSED_INITIALIZER_P (init)
       && CP_AGGREGATE_TYPE_P (type))
     /* A brace-enclosed initializer for an aggregate.  In C++0x this can
@@ -1661,12 +1654,14 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
      initializer, whether that happened just above or in
      cp_parser_late_parsing_nsdmi.
 
-     A TARGET_EXPR for which early_elide_copy is true represents the whole
-     initialization, so we shouldn't build up another ctor call.  */
-
+     A TARGET_EXPR with TARGET_EXPR_DIRECT_INIT_P or TARGET_EXPR_LIST_INIT_P
+     set represents the whole initialization, so we shouldn't build up
+     another ctor call.  */
   if (init
       && (TREE_CODE (init) == CONSTRUCTOR
-         || early_elide_copy (type, init))
+         || (TREE_CODE (init) == TARGET_EXPR
+             && (TARGET_EXPR_DIRECT_INIT_P (init)
+                 || TARGET_EXPR_LIST_INIT_P (init))))
       && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (init), type))
     {
       /* Early initialization via a TARGET_EXPR only works for
index 64562698854124f5e485400f1b5780b292a39539..569442f38ac095bada11908f21bf74a1e528e953 100644 (file)
@@ -7639,8 +7639,6 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
        }
       else if (! MAYBE_CLASS_TYPE_P (lhstype))
        /* Do the default thing.  */;
-      else if (early_elide_copy (lhstype, rhs))
-       /* Do the default thing.  */;
       else
        {
          vec<tree, va_gc> *rhs_vec = make_tree_vector_single (rhs);
index 5efdc6711dd3b893f5be5635f01b5a2ac9fd02a6..f72a6dac5255502c0d0c51aa44040189b8e1c406 100644 (file)
@@ -1,6 +1,5 @@
 // PR c++/38698
 // { dg-do compile { target c++11 } }
-// { dg-prune-output "note" }
 
 struct A
 {
index 71476e239709a05bca702d415a5ca607c9dc620a..48b89b10b294e74d8574525e37d4daf8523932ea 100644 (file)
@@ -23,3 +23,10 @@ A f() {
   else
     return A();
 }
+
+A* ap = new A(f());
+
+struct B {
+  A a;
+  B(): a(A()) {}
+};
index 85a697f5e29eeb2155b348f5221a2297f8f9325b..4016d9e2c7d619f3a3b42dca56ac56eca67cbf70 100644 (file)
@@ -91,8 +91,8 @@ void move_ctor()
 {
   static_assert(is_move_constructible_v<variant<int, string>>, "");
   static_assert(!is_move_constructible_v<variant<AllDeleted, string>>, "");
-  static_assert(!noexcept(variant<int, Empty>(variant<int, Empty>())), "");
-  static_assert(noexcept(variant<int, DefaultNoexcept>(variant<int, DefaultNoexcept>())), "");
+  static_assert(!noexcept(variant<int, Empty>(declval<variant<int, Empty>>())), "");
+  static_assert(noexcept(variant<int, DefaultNoexcept>(declval<variant<int, DefaultNoexcept>>())), "");
 }
 
 void arbitrary_ctor()