PR c++/38796, Core issue 906
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 26 Oct 2009 19:07:14 +0000 (19:07 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 26 Oct 2009 19:07:14 +0000 (19:07 +0000)
gcc/cp
* cp-tree.h (DECL_DEFAULTED_OUTSIDE_CLASS_P): New.
(DECL_DEFAULTED_IN_CLASS_P): New.
* class.c (user_provided_p): Non-static.
(check_methods): Use it.
(check_bases_and_members): Check defaulted fns.
(defaultable_fn_p): Move and rename to...
* method.c (defaultable_fn_check): ...this.
(defaulted_late_check): New.
* pt.c (tsubst_decl): Call it.
* decl2.c (grokfield): Adjust.
* decl.c (cp_finish_decl): Adjust.
(grok_special_member_properties): Use user_provided_p.
libstdc++-v3
* include/std/future (~Future_result_base): Default outside class
body.
* include/std/system_error (error_category()): Likewise.
* libsupc++/nested_exception.h (nested_exception): Remove
exception specifications from defaulted methods.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@153565 138bc75d-0d04-0410-961f-82ee72b054a4

21 files changed:
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/method.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/defaulted15.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/defaulted16.C [new file with mode: 0644]
libstdc++-v3/ChangeLog
libstdc++-v3/include/std/future
libstdc++-v3/include/std/system_error
libstdc++-v3/libsupc++/nested_exception.h
libstdc++-v3/testsuite/30_threads/packaged_task/cons/assign_neg.cc
libstdc++-v3/testsuite/30_threads/packaged_task/cons/copy_neg.cc
libstdc++-v3/testsuite/30_threads/promise/cons/assign_neg.cc
libstdc++-v3/testsuite/30_threads/promise/cons/copy_neg.cc
libstdc++-v3/testsuite/30_threads/shared_future/cons/assign_neg.cc
libstdc++-v3/testsuite/30_threads/unique_future/cons/assign_neg.cc
libstdc++-v3/testsuite/30_threads/unique_future/cons/copy_neg.cc

index 2f7ec52..50212a9 100644 (file)
@@ -1,3 +1,19 @@
+2009-10-26  Jason Merrill  <jason@redhat.com>
+
+       PR c++/38796, Core issue 906
+       * cp-tree.h (DECL_DEFAULTED_OUTSIDE_CLASS_P): New.
+       (DECL_DEFAULTED_IN_CLASS_P): New.
+       * class.c (user_provided_p): Non-static.
+       (check_methods): Use it.
+       (check_bases_and_members): Check defaulted fns.
+       (defaultable_fn_p): Move and rename to...
+       * method.c (defaultable_fn_check): ...this.
+       (defaulted_late_check): New.
+       * pt.c (tsubst_decl): Call it.
+       * decl2.c (grokfield): Adjust.
+       * decl.c (cp_finish_decl): Adjust.
+       (grok_special_member_properties): Use user_provided_p.
+
 2009-10-26  Dodji Seketeli  <dodji@redhat.com>
 
        PR c++/41785
index d29d661..d737bdf 100644 (file)
@@ -3843,7 +3843,7 @@ check_methods (tree t)
            VEC_safe_push (tree, gc, CLASSTYPE_PURE_VIRTUALS (t), x);
        }
       /* All user-provided destructors are non-trivial.  */
-      if (DECL_DESTRUCTOR_P (x) && !DECL_DEFAULTED_FN (x))
+      if (DECL_DESTRUCTOR_P (x) && user_provided_p (x))
        TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1;
     }
 }
@@ -4174,17 +4174,17 @@ type_has_user_nondefault_constructor (tree t)
 }
 
 /* Returns true iff FN is a user-provided function, i.e. user-declared
-   and not defaulted at its first declaration.  */
+   and not defaulted at its first declaration; or explicit, private,
+   protected, or non-const.  */
 
-static bool
+bool
 user_provided_p (tree fn)
 {
   if (TREE_CODE (fn) == TEMPLATE_DECL)
     return true;
   else
     return (!DECL_ARTIFICIAL (fn)
-           && !(DECL_DEFAULTED_FN (fn)
-                && DECL_INITIALIZED_IN_CLASS_P (fn)));
+           && !DECL_DEFAULTED_IN_CLASS_P (fn));
 }
 
 /* Returns true iff class T has a user-provided constructor.  */
@@ -4238,31 +4238,6 @@ type_has_user_provided_default_constructor (tree t)
   return false;
 }
 
-/* Returns true if FN can be explicitly defaulted.  */
-
-bool
-defaultable_fn_p (tree fn)
-{
-  if (DECL_CONSTRUCTOR_P (fn))
-    {
-      if (FUNCTION_FIRST_USER_PARMTYPE (fn) == void_list_node)
-       return true;
-      else if (copy_fn_p (fn) > 0
-              && (TREE_CHAIN (FUNCTION_FIRST_USER_PARMTYPE (fn))
-                  == void_list_node))
-       return true;
-      else
-       return false;
-    }
-  else if (DECL_DESTRUCTOR_P (fn))
-    return true;
-  else if (DECL_ASSIGNMENT_OPERATOR_P (fn)
-          && DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR)
-    return copy_fn_p (fn);
-  else
-    return false;
-}
-
 /* Remove all zero-width bit-fields from T.  */
 
 static void
@@ -4356,6 +4331,7 @@ check_bases_and_members (tree t)
   tree access_decls;
   bool saved_complex_asn_ref;
   bool saved_nontrivial_dtor;
+  tree fn;
 
   /* By default, we use const reference arguments and generate default
      constructors.  */
@@ -4453,6 +4429,31 @@ check_bases_and_members (tree t)
                                   cant_have_const_ctor,
                                   no_const_asn_ref);
 
+  /* Check defaulted declarations here so we have cant_have_const_ctor
+     and don't need to worry about clones.  */
+  for (fn = TYPE_METHODS (t); fn; fn = TREE_CHAIN (fn))
+    if (DECL_DEFAULTED_IN_CLASS_P (fn))
+      {
+       int copy = copy_fn_p (fn);
+       if (copy > 0)
+         {
+           bool imp_const_p
+             = (DECL_CONSTRUCTOR_P (fn) ? !cant_have_const_ctor
+                : !no_const_asn_ref);
+           bool fn_const_p = (copy == 2);
+
+           if (fn_const_p && !imp_const_p)
+             /* If the function is defaulted outside the class, we just
+                give the synthesis error.  */
+             error ("%q+D declared to take const reference, but implicit "
+                    "declaration would take non-const", fn);
+           else if (imp_const_p && !fn_const_p)
+             error ("%q+D declared to take non-const reference cannot be "
+                    "defaulted in the class body", fn);
+         }
+       defaulted_late_check (fn);
+      }
+
   if (LAMBDA_TYPE_P (t))
     {
       /* "The closure type associated with a lambda-expression has a deleted
index 3d826b9..ea28e9f 100644 (file)
@@ -2815,10 +2815,18 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
 #define DECL_DELETED_FN(DECL) \
   (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (DECL))->u.base.threadprivate_or_deleted_p)
 
-/* Nonzero if DECL was declared with '= default'.  */
+/* Nonzero if DECL was declared with '= default' (maybe implicitly).  */
 #define DECL_DEFAULTED_FN(DECL) \
   (LANG_DECL_FN_CHECK (DECL)->defaulted_p)
 
+/* Nonzero if DECL is explicitly defaulted in the class body.  */
+#define DECL_DEFAULTED_IN_CLASS_P(DECL)                                        \
+  (DECL_DEFAULTED_FN (DECL) && DECL_INITIALIZED_IN_CLASS_P (DECL))
+/* Nonzero if DECL was defaulted outside the class body.  */
+#define DECL_DEFAULTED_OUTSIDE_CLASS_P(DECL)                           \
+  (DECL_DEFAULTED_FN (DECL)                                            \
+   && !(DECL_ARTIFICIAL (DECL) || DECL_INITIALIZED_IN_CLASS_P (DECL)))
+
 /* Record whether a typedef for type `int' was actually `signed int'.  */
 #define C_TYPEDEF_EXPLICITLY_SIGNED(EXP) DECL_LANG_FLAG_1 (EXP)
 
@@ -4483,9 +4491,11 @@ extern void check_for_override                   (tree, tree);
 extern void push_class_stack                   (void);
 extern void pop_class_stack                    (void);
 extern bool type_has_user_nondefault_constructor (tree);
+extern bool user_provided_p                    (tree);
 extern bool type_has_user_provided_constructor  (tree);
 extern bool type_has_user_provided_default_constructor (tree);
-extern bool defaultable_fn_p                   (tree);
+extern void defaulted_late_check               (tree);
+extern bool defaultable_fn_check               (tree);
 extern void fixup_type_variants                        (tree);
 extern tree* decl_cloned_function_p            (const_tree, bool);
 extern void clone_function_decl                        (tree, int);
index c772ca5..ead3f33 100644 (file)
@@ -5603,17 +5603,10 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
        }
       else if (init == ridpointers[(int)RID_DEFAULT])
        {
-         if (!defaultable_fn_p (decl))
-           {
-             error ("%qD cannot be defaulted", decl);
-             DECL_INITIAL (decl) = NULL_TREE;
-           }
+         if (defaultable_fn_check (decl))
+           DECL_DEFAULTED_FN (decl) = 1;
          else
-           {
-             DECL_DEFAULTED_FN (decl) = 1;
-             FOR_EACH_CLONE (clone, decl)
-               DECL_DEFAULTED_FN (clone) = 1;
-           }
+           DECL_INITIAL (decl) = NULL_TREE;
        }
     }
     
@@ -9866,9 +9859,9 @@ grokparms (tree parmlist, tree *parms)
    0  if D is not a copy constructor or copy assignment
       operator.
    1  if D is a copy constructor or copy assignment operator whose
-      first parameter is a reference to const qualified T.
-   2  if D is a copy constructor or copy assignment operator whose
       first parameter is a reference to non-const qualified T.
+   2  if D is a copy constructor or copy assignment operator whose
+      first parameter is a reference to const qualified T.
 
    This function can be used as a predicate. Positive values indicate
    a copy constructor and nonzero values indicate a copy assignment
@@ -9977,10 +9970,6 @@ move_fn_p (const_tree d)
 
 /* Remember any special properties of member function DECL.  */
 
-#define DECL_DEFAULTED_IN_CLASS_P(DECL)                                        \
- (DECL_DEFAULTED_FN (DECL)                                             \
-  && (DECL_ARTIFICIAL (DECL) || DECL_INITIALIZED_IN_CLASS_P (DECL)))
-
 void
 grok_special_member_properties (tree decl)
 {
@@ -10007,7 +9996,7 @@ grok_special_member_properties (tree decl)
             are no other parameters or else all other parameters have
             default arguments.  */
          TYPE_HAS_INIT_REF (class_type) = 1;
-         if (!DECL_DEFAULTED_IN_CLASS_P (decl))
+         if (user_provided_p (decl))
            TYPE_HAS_COMPLEX_INIT_REF (class_type) = 1;
          if (ctor > 1)
            TYPE_HAS_CONST_INIT_REF (class_type) = 1;
@@ -10015,8 +10004,7 @@ grok_special_member_properties (tree decl)
       else if (sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (decl)))
        {
          TYPE_HAS_DEFAULT_CONSTRUCTOR (class_type) = 1;
-         if (TREE_CODE (decl) == TEMPLATE_DECL
-             || !DECL_DEFAULTED_IN_CLASS_P (decl))
+         if (user_provided_p (decl))
            TYPE_HAS_COMPLEX_DFLT (class_type) = 1;
        }
       else if (is_list_ctor (decl))
@@ -10035,7 +10023,7 @@ grok_special_member_properties (tree decl)
       if (assop)
        {
          TYPE_HAS_ASSIGN_REF (class_type) = 1;
-         if (!DECL_DEFAULTED_IN_CLASS_P (decl))
+         if (user_provided_p (decl))
            TYPE_HAS_COMPLEX_ASSIGN_REF (class_type) = 1;
          if (assop != 1)
            TYPE_HAS_CONST_ASSIGN_REF (class_type) = 1;
index 3e8c0d7..592ee08 100644 (file)
@@ -862,9 +862,7 @@ grokfield (const cp_declarator *declarator,
            }
          else if (init == ridpointers[(int)RID_DEFAULT])
            {
-             if (!defaultable_fn_p (value))
-               error ("%qD cannot be defaulted", value);
-             else
+             if (defaultable_fn_check (value))
                {
                  DECL_DEFAULTED_FN (value) = 1;
                  DECL_INITIALIZED_IN_CLASS_P (value) = 1;
index e8b28d8..266406c 100644 (file)
@@ -1130,6 +1130,88 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
   return fn;
 }
 
+/* Gives any errors about defaulted functions which need to be deferred
+   until the containing class is complete.  */
+
+void
+defaulted_late_check (tree fn)
+{
+  /* Complain about invalid signature for defaulted fn.  */
+  tree ctx = DECL_CONTEXT (fn);
+  special_function_kind kind = special_function_p (fn);
+  bool fn_const_p = (copy_fn_p (fn) == 2);
+  tree implicit_fn = implicitly_declare_fn (kind, ctx, fn_const_p);
+
+  if (!same_type_p (TREE_TYPE (TREE_TYPE (fn)),
+                   TREE_TYPE (TREE_TYPE (implicit_fn)))
+      || !compparms (TYPE_ARG_TYPES (TREE_TYPE (fn)),
+                    TYPE_ARG_TYPES (TREE_TYPE (implicit_fn))))
+    {
+      error ("defaulted declaration %q+D", fn);
+      error_at (DECL_SOURCE_LOCATION (fn),
+               "does not match expected signature %qD", implicit_fn);
+    }
+}
+
+/* Returns true iff FN can be explicitly defaulted, and gives any
+   errors if defaulting FN is ill-formed.  */
+
+bool
+defaultable_fn_check (tree fn)
+{
+  special_function_kind kind = sfk_none;
+
+  if (DECL_CONSTRUCTOR_P (fn))
+    {
+      if (FUNCTION_FIRST_USER_PARMTYPE (fn) == void_list_node)
+       kind = sfk_constructor;
+      else if (copy_fn_p (fn) > 0
+              && (TREE_CHAIN (FUNCTION_FIRST_USER_PARMTYPE (fn))
+                  == void_list_node))
+       kind = sfk_copy_constructor;
+      else if (move_fn_p (fn))
+       kind = sfk_move_constructor;
+    }
+  else if (DECL_DESTRUCTOR_P (fn))
+    kind = sfk_destructor;
+  else if (DECL_ASSIGNMENT_OPERATOR_P (fn)
+          && DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR
+          && copy_fn_p (fn))
+    kind = sfk_assignment_operator;
+
+  if (kind == sfk_none)
+    {
+      error ("%qD cannot be defaulted", fn);
+      return false;
+    }
+  else
+    {
+      tree t = FUNCTION_FIRST_USER_PARMTYPE (fn);
+      for (; t && t != void_list_node; t = TREE_CHAIN (t))
+       if (TREE_PURPOSE (t))
+         {
+           error ("defaulted function %q+D with default argument", fn);
+           break;
+         }
+      if (TYPE_BEING_DEFINED (DECL_CONTEXT (fn)))
+       {
+         if (DECL_NONCONVERTING_P (fn))
+           error ("%qD declared explicit cannot be defaulted in the class "
+                  "body", fn);
+         if (current_access_specifier != access_public_node)
+           error ("%qD declared with non-public access cannot be defaulted "
+                  "in the class body", fn);
+         if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)))
+           error ("function %q+D defaulted on its first declaration "
+                  "must not have an exception-specification", fn);
+       }
+      else if (!processing_template_decl)
+       defaulted_late_check (fn);
+
+      return true;
+    }
+}
+
 /* Add an implicit declaration to TYPE for the kind of function
    indicated by SFK.  Return the FUNCTION_DECL for the new implicit
    declaration.  */
index e80bc30..f480682 100644 (file)
@@ -8848,6 +8848,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
              = remove_attribute ("visibility", DECL_ATTRIBUTES (r));
          }
        determine_visibility (r);
+       if (DECL_DEFAULTED_OUTSIDE_CLASS_P (r)
+           && !processing_template_decl)
+         defaulted_late_check (r);
 
        apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,
                                        args, complain, in_decl);
index cc89a76..0556d76 100644 (file)
@@ -1,3 +1,9 @@
+2009-10-26  Jason Merrill  <jason@redhat.com>
+
+       PR c++/38796
+       * g++.dg/cpp0x/defaulted15.C: New.
+       * g++.dg/cpp0x/defaulted16.C: New.
+
 2009-10-26  Dodji Seketeli  <dodji@redhat.com>
 
        PR c++/41785
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted15.C b/gcc/testsuite/g++.dg/cpp0x/defaulted15.C
new file mode 100644 (file)
index 0000000..092b560
--- /dev/null
@@ -0,0 +1,43 @@
+// PR c++/38796
+// { dg-options -std=c++0x }
+
+struct A
+{
+  A (int);
+  A (const A& = 1) = default;  // { dg-error "default argument" }
+  void operator= (const A&) = default; // { dg-error "defaulted|match" }
+};
+
+struct B
+{
+private:
+  B() = default;               // { dg-error "access" }
+};
+
+struct C
+{
+protected:
+  ~C() = default;              // { dg-error "access" }
+};
+
+struct D
+{
+private:
+  D& operator= (const D&) = default; // { dg-error "access" }
+};
+
+struct E
+{
+  explicit E (const E&) = default; // { dg-error "explicit" }
+};
+
+struct F
+{
+  F(F&) = default;             // { dg-error "non-const" }
+};
+
+struct G: public F
+{
+  // Can't be const because F copy ctor isn't.
+  G(const G&) = default;       // { dg-error "const" }
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted16.C b/gcc/testsuite/g++.dg/cpp0x/defaulted16.C
new file mode 100644 (file)
index 0000000..741b43d
--- /dev/null
@@ -0,0 +1,13 @@
+// Test that non-inline default causes the function to be defined even if
+// it isn't used.
+
+// { dg-options -std=c++0x }
+// { dg-final { scan-assembler "_ZN1AC1Ev" } }
+
+struct A
+{
+  A();
+};
+
+A::A() = default;
+
index c13bb40..3e29ea5 100644 (file)
@@ -1,3 +1,12 @@
+2009-10-26  Jason Merrill  <jason@redhat.com>
+
+       Core issue 906
+       * include/std/future (~Future_result_base): Default outside class
+       body.
+       * include/std/system_error (error_category()): Likewise.
+       * libsupc++/nested_exception.h (nested_exception): Remove
+       exception specifications from defaulted methods.
+
 009-10-20  Paolo Carlini  <paolo.carlini@oracle.com>
 
         PR libstdc++/41773
index f922dcd..00f5c48 100644 (file)
@@ -130,9 +130,11 @@ namespace std
     };
 
   protected:
-    ~_Future_result_base() = default;
+    ~_Future_result_base();
   };
 
+  inline _Future_result_base::~_Future_result_base() = default;
+
   // TODO: use template alias when available
   /*
    template<typename _Res>
index 7f462a2..8647411 100644 (file)
@@ -64,7 +64,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
   class error_category
   {
   protected:
-    error_category() = default;
+    error_category();
 
   public:
     virtual ~error_category() { }
@@ -100,6 +100,8 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
     { return this != &__other; }
   };
 
+  inline error_category::error_category() = default;
+
   // DR 890.
   _GLIBCXX_CONST const error_category& system_category() throw ();
   _GLIBCXX_CONST const error_category& generic_category() throw ();
index 752c595..d4e1347 100644 (file)
@@ -57,9 +57,9 @@ namespace std
   public:
     nested_exception() throw() : _M_ptr(current_exception()) { }
 
-    nested_exception(const nested_exception&) throw() = default;
+    nested_exception(const nested_exception&) = default;
 
-    nested_exception& operator=(const nested_exception&) throw() = default;
+    nested_exception& operator=(const nested_exception&) = default;
 
     virtual ~nested_exception() = default;
 
index 0bad6ba..588a27e 100644 (file)
@@ -33,4 +33,4 @@ void test01()
 }
 
 // { dg-error "used here" "" { target *-*-* } 32 }
-// { dg-error "deleted function" "" { target *-*-* } 862 }
+// { dg-error "deleted function" "" { target *-*-* } 864 }
index 655ca8c..d0d0622 100644 (file)
@@ -32,4 +32,4 @@ void test01()
 }
 
 // { dg-error "used here" "" { target *-*-* } 31 }
-// { dg-error "deleted function" "" { target *-*-* } 861 }
+// { dg-error "deleted function" "" { target *-*-* } 863 }
index f2fbf17..b97d3ba 100644 (file)
@@ -33,4 +33,4 @@ void test01()
 }
 
 // { dg-error "used here" "" { target *-*-* } 32 }
-// { dg-error "deleted function" "" { target *-*-* } 588 }
+// { dg-error "deleted function" "" { target *-*-* } 590 }
index 17757ae..f94cffb 100644 (file)
@@ -32,4 +32,4 @@ void test01()
 }
 
 // { dg-error "used here" "" { target *-*-* } 31 }
-// { dg-error "deleted function" "" { target *-*-* } 572 }
+// { dg-error "deleted function" "" { target *-*-* } 574 }
index 868e0b8..61563e3 100644 (file)
@@ -35,4 +35,4 @@ void test01()
 }
 
 // { dg-error "used here" "" { target *-*-* } 34 }
-// { dg-error "deleted function" "" { target *-*-* } 481 }
+// { dg-error "deleted function" "" { target *-*-* } 483 }
index f8f5a69..9783124 100644 (file)
@@ -35,4 +35,4 @@ void test01()
 }
 
 // { dg-error "used here" "" { target *-*-* } 34 }
-// { dg-error "deleted function" "" { target *-*-* } 401 }
+// { dg-error "deleted function" "" { target *-*-* } 403 }
index 95b5a1d..4b59899 100644 (file)
@@ -34,4 +34,4 @@ void test01()
 }
 
 // { dg-error "used here" "" { target *-*-* } 33 }
-// { dg-error "deleted function" "" { target *-*-* } 400 }
+// { dg-error "deleted function" "" { target *-*-* } 402 }