OSDN Git Service

* method.c (process_subob_fn): Make sure no_implicit_p is non-null
[pf3gnuchains/gcc-fork.git] / gcc / cp / method.c
index 9b9eb9a..c4947d1 100644 (file)
@@ -140,11 +140,12 @@ make_thunk (tree function, bool this_adjusting,
   THUNK_VIRTUAL_OFFSET (thunk) = virtual_offset;
   THUNK_ALIAS (thunk) = NULL_TREE;
 
-  /* The thunk itself is not a constructor or destructor, even if
-     the thing it is thunking to is.  */
   DECL_INTERFACE_KNOWN (thunk) = 1;
   DECL_NOT_REALLY_EXTERN (thunk) = 1;
+  DECL_COMDAT (thunk) = DECL_COMDAT (function);
   DECL_SAVED_FUNCTION_DATA (thunk) = NULL;
+  /* The thunk itself is not a constructor or destructor, even if
+     the thing it is thunking to is.  */
   DECL_DESTRUCTOR_P (thunk) = 0;
   DECL_CONSTRUCTOR_P (thunk) = 0;
   DECL_EXTERNAL (thunk) = 1;
@@ -282,7 +283,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
   tree virtual_offset;
   HOST_WIDE_INT fixed_offset, virtual_value;
   bool this_adjusting = DECL_THIS_THUNK_P (thunk_fndecl);
-  struct cgraph_node *funcn;
+  struct cgraph_node *funcn, *thunk_node;
 
   /* We should have called finish_thunk to give it a name.  */
   gcc_assert (DECL_NAME (thunk_fndecl));
@@ -338,12 +339,13 @@ use_thunk (tree thunk_fndecl, bool emit_p)
   DECL_EXTERNAL (thunk_fndecl) = 0;
   /* The linkage of the function may have changed.  FIXME in linkage
      rewrite.  */
+  gcc_assert (DECL_INTERFACE_KNOWN (function));
   TREE_PUBLIC (thunk_fndecl) = TREE_PUBLIC (function);
   DECL_VISIBILITY (thunk_fndecl) = DECL_VISIBILITY (function);
   DECL_VISIBILITY_SPECIFIED (thunk_fndecl)
     = DECL_VISIBILITY_SPECIFIED (function);
-  if (DECL_ONE_ONLY (function) || DECL_WEAK (function))
-    make_decl_one_only (thunk_fndecl, cxx_comdat_group (thunk_fndecl));
+  DECL_COMDAT (thunk_fndecl) = DECL_COMDAT (function);
+  DECL_WEAK (thunk_fndecl) = DECL_WEAK (function);
 
   if (flag_syntax_only)
     {
@@ -384,9 +386,11 @@ use_thunk (tree thunk_fndecl, bool emit_p)
   TREE_ASM_WRITTEN (thunk_fndecl) = 1;
   funcn = cgraph_get_node (function);
   gcc_checking_assert (funcn);
-  cgraph_add_thunk (funcn, thunk_fndecl, function,
-                   this_adjusting, fixed_offset, virtual_value,
-                   virtual_offset, alias);
+  thunk_node = cgraph_add_thunk (funcn, thunk_fndecl, function,
+                                this_adjusting, fixed_offset, virtual_value,
+                                virtual_offset, alias);
+  if (DECL_ONE_ONLY (function))
+    cgraph_add_to_same_comdat_group (thunk_node, funcn);
 
   if (!this_adjusting
       || !targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
@@ -513,7 +517,8 @@ do_build_copy_constructor (tree fndecl)
       for (vbases = CLASSTYPE_VBASECLASSES (current_class_type), i = 0;
           VEC_iterate (tree, vbases, i, binfo); i++)
        {
-         init = build_base_path (PLUS_EXPR, parm, binfo, 1);
+         init = build_base_path (PLUS_EXPR, parm, binfo, 1,
+                                 tf_warning_or_error);
          if (move_p)
            init = move (init);
          member_init_list
@@ -528,7 +533,8 @@ do_build_copy_constructor (tree fndecl)
          if (BINFO_VIRTUAL_P (base_binfo))
            continue;
 
-         init = build_base_path (PLUS_EXPR, parm, base_binfo, 1);
+         init = build_base_path (PLUS_EXPR, parm, base_binfo, 1,
+                                 tf_warning_or_error);
          if (move_p)
            init = move (init);
          member_init_list
@@ -621,7 +627,8 @@ do_build_copy_assign (tree fndecl)
 
          /* We must convert PARM directly to the base class
             explicitly since the base class may be ambiguous.  */
-         converted_parm = build_base_path (PLUS_EXPR, parm, base_binfo, 1);
+         converted_parm = build_base_path (PLUS_EXPR, parm, base_binfo, 1,
+                                           tf_warning_or_error);
          if (move_p)
            converted_parm = move (converted_parm);
          /* Call the base class assignment operator.  */
@@ -916,7 +923,7 @@ get_copy_assign (tree type)
 
 static void
 process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
-                 bool *deleted_p, bool *constexpr_p,
+                 bool *deleted_p, bool *constexpr_p, bool *no_implicit_p,
                  const char *msg, tree arg)
 {
   if (!fn || fn == error_mark_node)
@@ -942,30 +949,19 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
        }
     }
 
-  if (move_p && !move_fn_p (fn) && !trivial_fn_p (fn))
-    {
-      if (msg)
-       error (msg, arg);
-      goto bad;
-    }
+  /* Core 1402: A non-trivial copy op suppresses the implicit
+     declaration of the move ctor/op=.  */
+  if (no_implicit_p && move_p && !move_fn_p (fn) && !trivial_fn_p (fn))
+    *no_implicit_p = true;
 
-  if (constexpr_p)
+  if (constexpr_p && !DECL_DECLARED_CONSTEXPR_P (fn))
     {
-      /* If this is a specialization of a constexpr template, we need to
-        force the instantiation now so that we know whether or not it's
-        really constexpr.  */
-      if (DECL_DECLARED_CONSTEXPR_P (fn) && DECL_TEMPLATE_INSTANTIATION (fn)
-         && !DECL_TEMPLATE_INSTANTIATED (fn))
-       instantiate_decl (fn, /*defer_ok*/false, /*expl_class*/false);
-      if (!DECL_DECLARED_CONSTEXPR_P (fn))
+      *constexpr_p = false;
+      if (msg)
        {
-         *constexpr_p = false;
-         if (msg)
-           {
-             inform (0, "defaulted constructor calls non-constexpr "
-                     "%q+D", fn);
-             explain_invalid_constexpr_fn (fn);
-           }
+         inform (0, "defaulted constructor calls non-constexpr "
+                 "%q+D", fn);
+         explain_invalid_constexpr_fn (fn);
        }
     }
 
@@ -983,8 +979,8 @@ static void
 walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
                   int quals, bool copy_arg_p, bool move_p,
                   bool assign_p, tree *spec_p, bool *trivial_p,
-                  bool *deleted_p, bool *constexpr_p, const char *msg,
-                  int flags, tsubst_flags_t complain)
+                  bool *deleted_p, bool *constexpr_p, bool *no_implicit_p,
+                  const char *msg, int flags, tsubst_flags_t complain)
 {
   tree field;
   for (field = fields; field; field = DECL_CHAIN (field))
@@ -1019,32 +1015,54 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
        }
       else if (sfk == sfk_constructor)
        {
-         bool bad = true;
+         bool bad;
+
+         if (DECL_INITIAL (field))
+           {
+             if (msg && DECL_INITIAL (field) == error_mark_node)
+               inform (0, "initializer for %q+#D is invalid", field);
+             if (trivial_p)
+               *trivial_p = false;
+#if 0
+             /* Core 1351: If the field has an NSDMI that could throw, the
+                default constructor is noexcept(false).  FIXME this is
+                broken by deferred parsing and 1360 saying we can't lazily
+                declare a non-trivial default constructor.  Also this
+                needs to do deferred instantiation.  Disable until the
+                conflict between 1351 and 1360 is resolved.  */
+             if (spec_p && !expr_noexcept_p (DECL_INITIAL (field), complain))
+               *spec_p = noexcept_false_spec;
+#endif
+
+             /* Don't do the normal processing.  */
+             continue;
+           }
+
+         bad = false;
          if (CP_TYPE_CONST_P (mem_type)
-             && (!CLASS_TYPE_P (mem_type)
-                 || !type_has_user_provided_default_constructor (mem_type)))
+             && default_init_uninitialized_part (mem_type))
            {
              if (msg)
                error ("uninitialized non-static const member %q#D",
                       field);
+             bad = true;
            }
          else if (TREE_CODE (mem_type) == REFERENCE_TYPE)
            {
              if (msg)
                error ("uninitialized non-static reference member %q#D",
                       field);
+             bad = true;
            }
-         else
-           bad = false;
 
          if (bad && deleted_p)
            *deleted_p = true;
 
          /* For an implicitly-defined default constructor to be constexpr,
-            every member must have a user-provided default constructor.  */
-         /* FIXME will need adjustment for non-static data member
-            initializers.  */
-         if (constexpr_p && !CLASS_TYPE_P (mem_type))
+            every member must have a user-provided default constructor or
+            an explicit initializer.  */
+         if (constexpr_p && !CLASS_TYPE_P (mem_type)
+             && TREE_CODE (DECL_CONTEXT (field)) != UNION_TYPE)
            {
              *constexpr_p = false;
              if (msg)
@@ -1060,7 +1078,8 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
        {
          walk_field_subobs (TYPE_FIELDS (mem_type), fnname, sfk, quals,
                             copy_arg_p, move_p, assign_p, spec_p, trivial_p,
-                            deleted_p, constexpr_p, msg, flags, complain);
+                            deleted_p, constexpr_p, no_implicit_p,
+                            msg, flags, complain);
          continue;
        }
 
@@ -1077,7 +1096,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
       rval = locate_fn_flags (mem_type, fnname, argtype, flags, complain);
 
       process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
-                       constexpr_p, msg, field);
+                       constexpr_p, no_implicit_p, msg, field);
     }
 }
 
@@ -1091,7 +1110,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
 static void
 synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
                         tree *spec_p, bool *trivial_p, bool *deleted_p,
-                        bool *constexpr_p, bool diag)
+                        bool *constexpr_p, bool *no_implicit_p, bool diag)
 {
   tree binfo, base_binfo, scope, fnname, rval, argtype;
   bool move_p, copy_arg_p, assign_p, expected_trivial, check_vdtor;
@@ -1104,6 +1123,9 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
   if (spec_p)
     *spec_p = (cxx_dialect >= cxx0x ? noexcept_true_spec : empty_except_spec);
 
+  if (no_implicit_p)
+    *no_implicit_p = false;
+
   if (deleted_p)
     {
       /* "The closure type associated with a lambda-expression has a deleted
@@ -1189,12 +1211,19 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
      resolution, so a constructor can be trivial even if it would otherwise
      call a non-trivial constructor.  */
   if (expected_trivial
-      && !diag
       && (!copy_arg_p || cxx_dialect < cxx0x))
     {
       if (constexpr_p && sfk == sfk_constructor)
-       *constexpr_p = synthesized_default_constructor_is_constexpr (ctype);
-      return;
+       {
+         bool cx = trivial_default_constructor_is_constexpr (ctype);
+         *constexpr_p = cx;
+         if (diag && !cx && TREE_CODE (ctype) == UNION_TYPE)
+           /* A trivial constructor doesn't have any NSDMI.  */
+           inform (input_location, "defaulted default constructor does "
+                   "not initialize any non-static data member");
+       }
+      if (!diag)
+       return;
     }
 
   ++cp_unevaluated_operand;
@@ -1237,7 +1266,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
       rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
 
       process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
-                       constexpr_p, msg, basetype);
+                       constexpr_p, no_implicit_p, msg, basetype);
       if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype))
        {
          /* In a constructor we also need to check the subobject
@@ -1245,9 +1274,12 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
          rval = locate_fn_flags (base_binfo, complete_dtor_identifier,
                                  NULL_TREE, flags, complain);
          /* Note that we don't pass down trivial_p; the subobject
-            destructors don't affect triviality of the constructor.  */
-         process_subob_fn (rval, false, spec_p, NULL,
-                           deleted_p, NULL, NULL,
+            destructors don't affect triviality of the constructor.  Nor
+            do they affect constexpr-ness (a constant expression doesn't
+            throw) or exception-specification (a throw from one of the
+            dtors would be a double-fault).  */
+         process_subob_fn (rval, false, NULL, NULL,
+                           deleted_p, NULL, NULL, NULL,
                            basetype);
        }
 
@@ -1288,13 +1320,13 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
          rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
 
          process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
-                           constexpr_p, msg, basetype);
+                           constexpr_p, no_implicit_p, msg, basetype);
          if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype))
            {
              rval = locate_fn_flags (base_binfo, complete_dtor_identifier,
                                      NULL_TREE, flags, complain);
-             process_subob_fn (rval, false, spec_p, NULL,
-                               deleted_p, NULL, NULL,
+             process_subob_fn (rval, false, NULL, NULL,
+                               deleted_p, NULL, NULL, NULL,
                                basetype);
            }
        }
@@ -1309,13 +1341,14 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
           "constructor or trivial copy constructor");
   walk_field_subobs (TYPE_FIELDS (ctype), fnname, sfk, quals,
                     copy_arg_p, move_p, assign_p, spec_p, trivial_p,
-                    deleted_p, constexpr_p, msg, flags, complain);
+                    deleted_p, constexpr_p, no_implicit_p,
+                    msg, flags, complain);
   if (ctor_p)
     walk_field_subobs (TYPE_FIELDS (ctype), complete_dtor_identifier,
                       sfk_destructor, TYPE_UNQUALIFIED, false,
-                      false, false, spec_p, NULL,
+                      false, false, NULL, NULL,
                       deleted_p, NULL,
-                      NULL, flags, complain);
+                      NULL, NULL, flags, complain);
 
   pop_scope (scope);
 
@@ -1357,22 +1390,35 @@ maybe_explain_implicit_delete (tree decl)
        {
          informed = true;
          if (sfk == sfk_constructor)
-           error ("a lambda closure type has a deleted default constructor");
+           inform (DECL_SOURCE_LOCATION (decl),
+                   "a lambda closure type has a deleted default constructor");
          else if (sfk == sfk_copy_assignment)
-           error ("a lambda closure type has a deleted copy assignment operator");
+           inform (DECL_SOURCE_LOCATION (decl),
+                   "a lambda closure type has a deleted copy assignment operator");
          else
            informed = false;
        }
+      else if (DECL_ARTIFICIAL (decl)
+              && (sfk == sfk_copy_assignment
+                  || sfk == sfk_copy_constructor)
+              && (type_has_user_declared_move_constructor (ctype)
+                  || type_has_user_declared_move_assign (ctype)))
+       {
+         inform (0, "%q+#D is implicitly declared as deleted because %qT "
+                "declares a move constructor or move assignment operator",
+                decl, ctype);
+         informed = true;
+       }
       if (!informed)
        {
          tree parm_type = TREE_VALUE (FUNCTION_FIRST_USER_PARMTYPE (decl));
          bool const_p = CP_TYPE_CONST_P (non_reference (parm_type));
          tree scope = push_scope (ctype);
-         error ("%qD is implicitly deleted because the default "
+         inform (0, "%q+#D is implicitly deleted because the default "
                 "definition would be ill-formed:", decl);
          pop_scope (scope);
          synthesized_method_walk (ctype, sfk, const_p,
-                                  NULL, NULL, NULL, NULL, true);
+                                  NULL, NULL, NULL, NULL, NULL, true);
        }
 
       input_location = loc;
@@ -1392,7 +1438,7 @@ explain_implicit_non_constexpr (tree decl)
   bool dummy;
   synthesized_method_walk (DECL_CLASS_CONTEXT (decl),
                           special_function_p (decl), const_p,
-                          NULL, NULL, NULL, &dummy, true);
+                          NULL, NULL, NULL, &dummy, NULL, true);
 }
 
 /* Implicitly declare the special function indicated by KIND, as a
@@ -1416,6 +1462,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
   bool deleted_p;
   bool trivial_p;
   bool constexpr_p;
+  bool no_implicit_p;
 
   /* Because we create declarations for implicitly declared functions
      lazily, we may be creating the declaration for a member of TYPE
@@ -1485,7 +1532,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
     }
 
   synthesized_method_walk (type, kind, const_p, &raises, &trivial_p,
-                          &deleted_p, &constexpr_p, false);
+                          &deleted_p, &constexpr_p, &no_implicit_p, false);
   /* Don't bother marking a deleted constructor as constexpr.  */
   if (deleted_p)
     constexpr_p = false;
@@ -1550,6 +1597,8 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
       DECL_DELETED_FN (fn) = deleted_p;
       DECL_DECLARED_CONSTEXPR_P (fn) = constexpr_p;
     }
+  FNDECL_SUPPRESS_IMPLICIT_DECL (fn) = no_implicit_p;
+  DECL_EXTERNAL (fn) = true;
   DECL_NOT_REALLY_EXTERN (fn) = 1;
   DECL_DECLARED_INLINE_P (fn) = 1;
   gcc_assert (!TREE_USED (fn));
@@ -1725,6 +1774,15 @@ lazily_declare_fn (special_function_kind sfk, tree type)
   /* Declare the function.  */
   fn = implicitly_declare_fn (sfk, type, const_p);
 
+  /* [class.copy]/8 If the class definition declares a move constructor or
+     move assignment operator, the implicitly declared copy constructor is
+     defined as deleted.... */
+  if ((sfk == sfk_copy_assignment
+       || sfk == sfk_copy_constructor)
+      && (type_has_user_declared_move_constructor (type)
+         || type_has_user_declared_move_assign (type)))
+    DECL_DELETED_FN (fn) = true;
+
   /* For move variants, rather than declare them as deleted we just
      don't declare them at all.  */
   if (DECL_DELETED_FN (fn)
@@ -1732,6 +1790,10 @@ lazily_declare_fn (special_function_kind sfk, tree type)
          || sfk == sfk_move_assignment))
     return NULL_TREE;
 
+  /* We also suppress implicit move if it would call a non-trivial copy.  */
+  if (FNDECL_SUPPRESS_IMPLICIT_DECL (fn))
+    return NULL_TREE;
+
   /* A destructor may be virtual.  */
   if (sfk == sfk_destructor
       || sfk == sfk_move_assignment