]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
DR 1402 PR c++/53733
authorJason Merrill <jason@redhat.com>
Tue, 10 Jul 2012 00:03:23 +0000 (20:03 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 10 Jul 2012 00:03:23 +0000 (20:03 -0400)
DR 1402
PR c++/53733
* cp-tree.h (FNDECL_SUPPRESS_IMPLICIT_DECL): New.
(struct lang_decl_fn): Add suppress_implicit_decl field.
* method.c (implicitly_declare_fn): Check it.
(process_subob_fn): Add no_implicit_p parm.
(walk_field_subobs, synthesized_method_walk): Likewise.
(maybe_explain_implicit_delete): Adjust.
(explain_implicit_non_constexpr): Adjust.

From-SVN: r189396

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/method.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/defaulted21.C
gcc/testsuite/g++.dg/cpp0x/defaulted36.C [new file with mode: 0644]

index e4c5506986c83fff1804ad5037234bb8c76a2836..310b44259b987bb97eb3c381a6ef8944520be689 100644 (file)
@@ -1,5 +1,15 @@
 2012-07-10  Jason Merrill  <jason@redhat.com>
 
+       DR 1402
+       PR c++/53733
+       * cp-tree.h (FNDECL_SUPPRESS_IMPLICIT_DECL): New.
+       (struct lang_decl_fn): Add suppress_implicit_decl field.
+       * method.c (implicitly_declare_fn): Check it.
+       (process_subob_fn): Add no_implicit_p parm.
+       (walk_field_subobs, synthesized_method_walk): Likewise.
+       (maybe_explain_implicit_delete): Adjust.
+       (explain_implicit_non_constexpr): Adjust.
+
        * method.c (synthesized_method_walk): Avoid changing
        EH spec based on cleanups in other places, too.
 
index 713001e121f2b86d022f72b56d7e868d7e86bd2d..10efa2a663a43797f74569d36628132199ed40f9 100644 (file)
@@ -1940,7 +1940,7 @@ struct GTY(()) lang_decl_fn {
   unsigned thunk_p : 1;
   unsigned this_thunk_p : 1;
   unsigned hidden_friend_p : 1;
-  /* 1 spare bit.  */
+  unsigned suppress_implicit_decl : 1;
 
   /* For a non-thunk function decl, this is a tree list of
      friendly classes. For a thunk function decl, it is the
@@ -3107,6 +3107,12 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
 #define DECL_HIDDEN_FRIEND_P(NODE) \
   (LANG_DECL_FN_CHECK (DECL_COMMON_CHECK (NODE))->hidden_friend_p)
 
+/* Nonzero if NODE is a FUNCTION_DECL generated by implicitly_declare_fn
+   that we shouldn't actually declare implicitly; it is only used for
+   comparing to an =default declaration.  */
+#define FNDECL_SUPPRESS_IMPLICIT_DECL(NODE) \
+  (LANG_DECL_FN_CHECK (DECL_COMMON_CHECK (NODE))->suppress_implicit_decl)
+
 /* Nonzero if DECL has been declared threadprivate by
    #pragma omp threadprivate.  */
 #define CP_DECL_THREADPRIVATE_P(DECL) \
index 7ea2de9ac8ea2980543a52b6113242727b98ced0..79edf81b24f7da28a1fd54c1318fdddb0dc9c0eb 100644 (file)
@@ -922,7 +922,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)
@@ -948,12 +948,10 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
        }
     }
 
+  /* Core 1402: A non-trivial copy op suppresses the implicit
+     declaration of the move ctor/op=.  */
   if (move_p && !move_fn_p (fn) && !trivial_fn_p (fn))
-    {
-      if (msg)
-       error (msg, arg);
-      goto bad;
-    }
+    *no_implicit_p = true;
 
   if (constexpr_p && !DECL_DECLARED_CONSTEXPR_P (fn))
     {
@@ -980,8 +978,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))
@@ -1079,7 +1077,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;
        }
 
@@ -1096,7 +1095,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);
     }
 }
 
@@ -1110,7 +1109,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;
@@ -1198,6 +1197,9 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
   if (trivial_p)
     *trivial_p = expected_trivial;
 
+  if (no_implicit_p)
+    *no_implicit_p = false;
+
   /* 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
@@ -1256,7 +1258,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
@@ -1269,7 +1271,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
             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,
+                           deleted_p, NULL, NULL, NULL,
                            basetype);
        }
 
@@ -1310,13 +1312,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, NULL, NULL,
-                               deleted_p, NULL, NULL,
+                               deleted_p, NULL, NULL, NULL,
                                basetype);
            }
        }
@@ -1331,13 +1333,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, NULL, NULL,
                       deleted_p, NULL,
-                      NULL, flags, complain);
+                      NULL, NULL, flags, complain);
 
   pop_scope (scope);
 
@@ -1407,7 +1410,7 @@ maybe_explain_implicit_delete (tree decl)
                 "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;
@@ -1427,7 +1430,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
@@ -1451,6 +1454,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
@@ -1520,7 +1524,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;
@@ -1585,6 +1589,7 @@ 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;
@@ -1777,6 +1782,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
index 41e3c64ead9ccacca943bc762c5485eae958f51a..9787afecf44b4f1dc62762028794d3b0a159135b 100644 (file)
@@ -1,5 +1,9 @@
 2012-07-10  Jason Merrill  <jason@redhat.com>
 
+       PR c++/53733
+       * g++.dg/cpp0x/defaulted36.C: New.
+       * g++.dg/cpp0x/defaulted21.C: Adjust.
+
        * g++.dg/cpp0x/implicit13.C: Add vbase and member tests.
 
 2012-07-09  Sterling Augustine  <saugustine@google.com>
index 30a4a7c7d0174820d929defea5a97180751cb81b..51505dc460e9af22e42c548dac28f7c6c51796b2 100644 (file)
@@ -3,7 +3,8 @@
 
 struct U {
   U();
-  U(U const&);
+private:
+  U(U const&);                 // { dg-error "private" }
 };
 
 struct X {
@@ -13,7 +14,7 @@ struct X {
 };
 
 X::X(X&&)=default;             // { dg-message "implicitly deleted" }
-// { dg-error "does not have a move constructor" "" { target *-*-* } 15 }
+// { dg-prune-output "within this context" }
 
 X f() {
   return X();
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted36.C b/gcc/testsuite/g++.dg/cpp0x/defaulted36.C
new file mode 100644 (file)
index 0000000..1360f60
--- /dev/null
@@ -0,0 +1,24 @@
+// PR c++/53733
+// { dg-do compile { target c++11 } }
+
+template<typename T>
+struct wrap
+{
+  wrap() = default;
+  wrap(wrap&&) = default; // Line 5
+  wrap(const wrap&) = default;
+
+  T t;
+};
+
+struct S {
+  S() = default;
+  S(const S&){}
+  S(S&&) = default;
+};
+
+typedef wrap<const S> W;
+
+W get() { return W(); } // Line 19
+
+int main() {}