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 ed75a64..c4947d1 100644 (file)
@@ -1,7 +1,7 @@
 /* Handle the hair of processing (but not expanding) inline functions.
    Also manage function and variable name overloading.
    Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 #include "tm_p.h"
 #include "target.h"
+#include "common/common-target.h"
 #include "tree-pass.h"
 #include "diagnostic.h"
 #include "cgraph.h"
@@ -139,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;
@@ -259,7 +261,10 @@ make_alias_for_thunk (tree function)
 
   if (!flag_syntax_only)
     {
-      struct cgraph_node *aliasn = cgraph_same_body_alias (alias, function);
+      struct cgraph_node *funcn, *aliasn;
+      funcn = cgraph_get_node (function);
+      gcc_checking_assert (funcn);
+      aliasn = cgraph_same_body_alias (funcn, alias, function);
       DECL_ASSEMBLER_NAME (function);
       gcc_assert (aliasn != NULL);
     }
@@ -278,6 +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, *thunk_node;
 
   /* We should have called finish_thunk to give it a name.  */
   gcc_assert (DECL_NAME (thunk_fndecl));
@@ -333,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)
     {
@@ -349,7 +356,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
   push_to_top_level ();
 
   if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function)
-      && targetm.have_named_sections)
+      && targetm_common.have_named_sections)
     {
       resolve_unique_section (function, 0, flag_function_sections);
 
@@ -371,14 +378,19 @@ use_thunk (tree thunk_fndecl, bool emit_p)
       DECL_CONTEXT (x) = thunk_fndecl;
       SET_DECL_RTL (x, NULL);
       DECL_HAS_VALUE_EXPR_P (x) = 0;
+      TREE_ADDRESSABLE (x) = 0;
       t = x;
     }
   a = nreverse (t);
   DECL_ARGUMENTS (thunk_fndecl) = a;
   TREE_ASM_WRITTEN (thunk_fndecl) = 1;
-  cgraph_add_thunk (thunk_fndecl, function,
-                   this_adjusting, fixed_offset, virtual_value,
-                   virtual_offset, alias);
+  funcn = cgraph_get_node (function);
+  gcc_checking_assert (funcn);
+  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,
@@ -505,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
@@ -520,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
@@ -583,6 +597,7 @@ do_build_copy_assign (tree fndecl)
   tree compound_stmt;
   bool move_p = move_fn_p (fndecl);
   bool trivial = trivial_fn_p (fndecl);
+  int flags = LOOKUP_NORMAL | LOOKUP_NONVIRTUAL | LOOKUP_DEFAULTED;
 
   compound_stmt = begin_compound_stmt (0);
   parm = convert_from_reference (parm);
@@ -612,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.  */
@@ -622,7 +638,7 @@ do_build_copy_assign (tree fndecl)
                                        ansi_assopname (NOP_EXPR),
                                        &parmvec,
                                        base_binfo,
-                                       LOOKUP_NORMAL | LOOKUP_NONVIRTUAL,
+                                       flags,
                                         tf_warning_or_error));
          release_tree_vector (parmvec);
        }
@@ -835,10 +851,10 @@ locate_fn_flags (tree type, tree name, tree argtype, int flags,
 /* Locate the dtor of TYPE.  */
 
 tree
-get_dtor (tree type)
+get_dtor (tree type, tsubst_flags_t complain)
 {
   tree fn = locate_fn_flags (type, complete_dtor_identifier, NULL_TREE,
-                            LOOKUP_NORMAL, tf_warning_or_error);
+                            LOOKUP_NORMAL, complain);
   if (fn == error_mark_node)
     return NULL_TREE;
   return fn;
@@ -875,13 +891,13 @@ get_default_ctor (tree type)
 /* Locate the copy ctor of TYPE.  */
 
 tree
-get_copy_ctor (tree type)
+get_copy_ctor (tree type, tsubst_flags_t complain)
 {
   int quals = (TYPE_HAS_CONST_COPY_CTOR (type)
               ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED);
   tree argtype = build_stub_type (type, quals, false);
   tree fn = locate_fn_flags (type, complete_ctor_identifier, argtype,
-                            LOOKUP_NORMAL, tf_warning_or_error);
+                            LOOKUP_NORMAL, complain);
   if (fn == error_mark_node)
     return NULL_TREE;
   return fn;
@@ -907,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)
@@ -916,7 +932,7 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
   if (spec_p)
     {
       tree raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
-      *spec_p = merge_exception_specifiers (*spec_p, raises);
+      *spec_p = merge_exception_specifiers (*spec_p, raises, fn);
     }
 
   if (!trivial_fn_p (fn))
@@ -933,16 +949,22 @@ 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))
+  /* 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 && !DECL_DECLARED_CONSTEXPR_P (fn))
     {
+      *constexpr_p = false;
       if (msg)
-       error (msg, arg);
-      goto bad;
+       {
+         inform (0, "defaulted constructor calls non-constexpr "
+                 "%q+D", fn);
+         explain_invalid_constexpr_fn (fn);
+       }
     }
 
-  if (constexpr_p && !DECL_DECLARED_CONSTEXPR_P (fn))
-    *constexpr_p = false;
-
   return;
 
  bad:
@@ -957,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))
@@ -993,33 +1015,60 @@ 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))
-           *constexpr_p = false;
+            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)
+               inform (0, "defaulted default constructor does not "
+                       "initialize %q+#D", field);
+           }
        }
 
       if (!CLASS_TYPE_P (mem_type))
@@ -1029,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;
        }
 
@@ -1046,20 +1096,21 @@ 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);
     }
 }
 
 /* The caller wants to generate an implicit declaration of SFK for CTYPE
    which is const if relevant and CONST_P is set.  If spec_p, trivial_p and
    deleted_p are non-null, set their referent appropriately.  If diag is
-   true, we're being called from maybe_explain_implicit_delete to give
-   errors.  */
+   true, we're either being called from maybe_explain_implicit_delete to
+   give errors, or if constexpr_p is non-null, from
+   explain_invalid_constexpr_fn.  */
 
 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;
@@ -1068,14 +1119,12 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
   tsubst_flags_t complain;
   const char *msg;
   bool ctor_p;
-  tree cleanup_spec;
-  bool cleanup_trivial = true;
-  bool cleanup_deleted = false;
 
-  cleanup_spec
-    = (cxx_dialect >= cxx0x ? noexcept_true_spec : empty_except_spec);
   if (spec_p)
-    *spec_p = cleanup_spec;
+    *spec_p = (cxx_dialect >= cxx0x ? noexcept_true_spec : empty_except_spec);
+
+  if (no_implicit_p)
+    *no_implicit_p = false;
 
   if (deleted_p)
     {
@@ -1152,21 +1201,30 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
   if (trivial_p)
     *trivial_p = expected_trivial;
 
-#ifndef ENABLE_CHECKING
   /* The TYPE_HAS_COMPLEX_* flags tell us about constraints from base
      class versions and other properties of the type.  But a subobject
      class can be trivially copyable and yet have overload resolution
      choose a template constructor for initialization, depending on
      rvalueness and cv-quals.  So we can't exit early for copy/move
-     methods in C++0x.  */
+     methods in C++0x.  The same considerations apply in C++98/03, but
+     there the definition of triviality does not consider overload
+     resolution, so a constructor can be trivial even if it would otherwise
+     call a non-trivial constructor.  */
   if (expected_trivial
       && (!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;
     }
-#endif
 
   ++cp_unevaluated_operand;
   ++c_inhibit_evaluation_warnings;
@@ -1175,12 +1233,12 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
 
   if (diag)
     {
-      flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE;
+      flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE|LOOKUP_DEFAULTED;
       complain = tf_warning_or_error;
     }
   else
     {
-      flags = LOOKUP_PROTECT|LOOKUP_SPECULATIVE;
+      flags = LOOKUP_PROTECT|LOOKUP_SPECULATIVE|LOOKUP_DEFAULTED;
       complain = tf_none;
     }
 
@@ -1208,15 +1266,20 @@ 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
             destructors for cleanup of partially constructed objects.  */
          rval = locate_fn_flags (base_binfo, complete_dtor_identifier,
                                  NULL_TREE, flags, complain);
-         process_subob_fn (rval, false, &cleanup_spec, &cleanup_trivial,
-                           &cleanup_deleted, NULL, NULL,
+         /* Note that we don't pass down trivial_p; the subobject
+            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);
        }
 
@@ -1257,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, &cleanup_spec, &cleanup_trivial,
-                               &cleanup_deleted, NULL, NULL,
+             process_subob_fn (rval, false, NULL, NULL,
+                               deleted_p, NULL, NULL, NULL,
                                basetype);
            }
        }
@@ -1278,35 +1341,19 @@ 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, &cleanup_spec, &cleanup_trivial,
-                      &cleanup_deleted, NULL,
-                      NULL, flags, complain);
+                      false, false, NULL, NULL,
+                      deleted_p, NULL,
+                      NULL, NULL, flags, complain);
 
   pop_scope (scope);
 
   --cp_unevaluated_operand;
   --c_inhibit_evaluation_warnings;
-
-  /* If the constructor isn't trivial, consider the subobject cleanups.  */
-  if (ctor_p && trivial_p && !*trivial_p)
-    {
-      if (deleted_p && cleanup_deleted)
-       *deleted_p = true;
-      if (spec_p)
-       *spec_p = merge_exception_specifiers (*spec_p, cleanup_spec);
-    }
-
-#ifdef ENABLE_CHECKING
-  /* If we expected this to be trivial but it isn't, then either we're in
-     C++0x mode and this is a copy/move ctor/op= or there's an error.  */
-  gcc_assert (!(trivial_p && expected_trivial && !*trivial_p)
-             || (copy_arg_p && cxx_dialect >= cxx0x)
-             || errorcount);
-#endif
 }
 
 /* DECL is a deleted function.  If it's implicitly deleted, explain why and
@@ -1318,25 +1365,20 @@ maybe_explain_implicit_delete (tree decl)
   /* If decl is a clone, get the primary variant.  */
   decl = DECL_ORIGIN (decl);
   gcc_assert (DECL_DELETED_FN (decl));
-  if (DECL_DEFAULTED_FN (decl)
-      && DECL_INITIAL (decl) == NULL_TREE)
+  if (DECL_DEFAULTED_FN (decl))
     {
       /* Not marked GTY; it doesn't need to be GC'd or written to PCH.  */
-      static htab_t explained_htab;
-      void **slot;
+      static struct pointer_set_t *explained;
 
       special_function_kind sfk;
       location_t loc;
       bool informed;
       tree ctype;
 
-      if (!explained_htab)
-       explained_htab = htab_create (37, htab_hash_pointer,
-                                     htab_eq_pointer, NULL);
-      slot = htab_find_slot (explained_htab, decl, INSERT);
-      if (*slot)
+      if (!explained)
+       explained = pointer_set_create ();
+      if (pointer_set_insert (explained, decl))
        return true;
-      *slot = decl;
 
       sfk = special_function_p (decl);
       ctype = DECL_CONTEXT (decl);
@@ -1348,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;
@@ -1372,6 +1427,20 @@ maybe_explain_implicit_delete (tree decl)
   return false;
 }
 
+/* DECL is a defaulted function which was declared constexpr.  Explain why
+   it can't be constexpr.  */
+
+void
+explain_implicit_non_constexpr (tree decl)
+{
+  tree parm_type = TREE_VALUE (FUNCTION_FIRST_USER_PARMTYPE (decl));
+  bool const_p = CP_TYPE_CONST_P (non_reference (parm_type));
+  bool dummy;
+  synthesized_method_walk (DECL_CLASS_CONTEXT (decl),
+                          special_function_p (decl), const_p,
+                          NULL, NULL, NULL, &dummy, NULL, true);
+}
+
 /* Implicitly declare the special function indicated by KIND, as a
    member of TYPE.  For copy constructors and assignment operators,
    CONST_P indicates whether these functions should take a const
@@ -1393,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
@@ -1462,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;
@@ -1505,8 +1575,11 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
       /* Note that this parameter is *not* marked DECL_ARTIFICIAL; we
         want its type to be included in the mangled function
         name.  */
-      DECL_ARGUMENTS (fn) = cp_build_parm_decl (NULL_TREE, rhs_parm_type);
-      TREE_READONLY (DECL_ARGUMENTS (fn)) = 1;
+      tree decl = cp_build_parm_decl (NULL_TREE, rhs_parm_type);
+      TREE_READONLY (decl) = 1;
+      retrofit_lang_decl (decl);
+      DECL_PARM_INDEX (decl) = DECL_PARM_LEVEL (decl) = 1;
+      DECL_ARGUMENTS (fn) = decl;
     }
   /* Add the "this" parameter.  */
   this_parm = build_this_parm (fn_type, TYPE_UNQUALIFIED);
@@ -1524,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));
@@ -1562,19 +1637,37 @@ defaulted_late_check (tree fn)
   if (DECL_DEFAULTED_IN_CLASS_P (fn))
     {
       tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn));
+      if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)))
+       {
+         maybe_instantiate_noexcept (fn);
+         if (!comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)),
+                                 eh_spec, ce_normal))
+           error ("function %q+D defaulted on its first declaration "
+                  "with an exception-specification that differs from "
+                  "the implicit declaration %q#D", fn, implicit_fn);
+       }
       TREE_TYPE (fn) = build_exception_variant (TREE_TYPE (fn), eh_spec);
       if (DECL_DECLARED_CONSTEXPR_P (implicit_fn))
-       /* Hmm...should we do this for out-of-class too? Should it be OK to
-          add constexpr later like inline, rather than requiring
-          declarations to match?  */
-       DECL_DECLARED_CONSTEXPR_P (fn) = true;
+       {
+         /* Hmm...should we do this for out-of-class too? Should it be OK to
+            add constexpr later like inline, rather than requiring
+            declarations to match?  */
+         DECL_DECLARED_CONSTEXPR_P (fn) = true;
+         if (kind == sfk_constructor)
+           TYPE_HAS_CONSTEXPR_CTOR (ctx) = true;
+       }
     }
 
   if (!DECL_DECLARED_CONSTEXPR_P (implicit_fn)
       && DECL_DECLARED_CONSTEXPR_P (fn))
     {
       if (!CLASSTYPE_TEMPLATE_INSTANTIATION (ctx))
-       error ("%qD cannot be declared as constexpr", fn);
+       {
+         error ("explicitly defaulted function %q+D cannot be declared "
+                "as constexpr because the implicit declaration is not "
+                "constexpr:", fn);
+         explain_implicit_non_constexpr (fn);
+       }
       DECL_DECLARED_CONSTEXPR_P (fn) = false;
     }
 
@@ -1590,6 +1683,12 @@ defaultable_fn_check (tree fn)
 {
   special_function_kind kind = sfk_none;
 
+  if (template_parm_scope_p ())
+    {
+      error ("a template cannot be defaulted");
+      return false;
+    }
+
   if (DECL_CONSTRUCTOR_P (fn))
     {
       if (FUNCTION_FIRST_USER_PARMTYPE (fn) == void_list_node)
@@ -1627,14 +1726,7 @@ defaultable_fn_check (tree fn)
            break;
          }
       if (TYPE_BEING_DEFINED (DECL_CONTEXT (fn)))
-       {
-         if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)))
-           error ("function %q+D defaulted on its first declaration "
-                  "must not have an exception-specification", fn);
-         if (DECL_VIRTUAL_P (fn))
-           error ("%qD declared virtual cannot be defaulted in the class "
-                  "body", fn);
-       }
+       /* Defer checking.  */;
       else if (!processing_template_decl)
        defaulted_late_check (fn);
 
@@ -1682,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)
@@ -1689,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