On 9/19/24 5:35 PM, Marek Polacek wrote:
On Tue, Sep 17, 2024 at 12:50:46PM -0400, Jason Merrill wrote:
On 9/16/24 7:14 PM, Marek Polacek wrote:
+/* Mark an explicitly defaulted function FN as =deleted and warn.
+   IMPLICIT_FN is the corresponding special member function that
+   would have been implicitly declared.  */
+
+void
+maybe_delete_defaulted_fn (tree fn, tree implicit_fn)
+{
+  if (DECL_ARTIFICIAL (fn) || !DECL_DEFAULTED_IN_CLASS_P (fn))
+    return;
+
+  DECL_DELETED_FN (fn) = true;
+
+  if (!warn_defaulted_fn_deleted)
+    return;

The flag shouldn't affect the error cases; I'd drop this check.

Dropped.

+  auto_diagnostic_group d;
+  const special_function_kind kind = special_function_p (fn);
+  tree parmtype
+    = TREE_VALUE (DECL_XOBJ_MEMBER_FUNCTION_P (fn)
+                 ? TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn)))
+                 : FUNCTION_FIRST_USER_PARMTYPE (fn));
+  const bool illformed_p
+    /* [dcl.fct.def.default] "if F1 is an assignment operator"...  */
+    = (SFK_ASSIGN_P (kind)
+       /* "and the return type of F1 differs from the return type of F2"  */
+       && (!same_type_p (TREE_TYPE (TREE_TYPE (fn)),
+                        TREE_TYPE (TREE_TYPE (implicit_fn)))
+          /* "or F1's non-object parameter type is not a reference,
+             the program is ill-formed"  */
+          || !TYPE_REF_P (parmtype)));
+  /* Decide if we want to emit a pedwarn, error, or a warning.  */
+  diagnostic_t diag_kind;
+  if (cxx_dialect >= cxx20)
+    diag_kind = illformed_p ? DK_ERROR : DK_WARNING;
+  else
+    diag_kind = DK_PEDWARN;

Error should be errors in all standard modes; it doesn't make sense to have
a softer diagnostic in an older mode when it's ill-formed in all.

Non-errors should be warnings or pedwarns depending on the standard mode.

Aaah, I misunderstood.  Hopefully I got it right this time.
+  /* Don't warn for template instantiations.  */
+  if (DECL_TEMPLATE_INSTANTIATION (fn) && diag_kind == DK_WARNING)
+    return;
+
+  const char *wmsg;
+  switch (kind)
+    {
+    case sfk_copy_constructor:
+      wmsg = G_("explicitly defaulted copy constructor is implicitly deleted "
+               "because its declared type does not match the type of an "
+               "implicit copy constructor");
+      break;
+    case sfk_move_constructor:
+      wmsg = G_("explicitly defaulted move constructor is implicitly deleted "
+               "because its declared type does not match the type of an "
+               "implicit move constructor");
+      break;
+    case sfk_copy_assignment:
+      wmsg = G_("explicitly defaulted copy assignment operator is implicitly "
+               "deleted because its declared type does not match the type "
+               "of an implicit copy assignment operator");
+      break;
+    case sfk_move_assignment:
+      wmsg = G_("explicitly defaulted move assignment operator is implicitly "
+               "deleted because its declared type does not match the type "
+               "of an implicit move assignment operator");
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  if (emit_diagnostic (diag_kind, DECL_SOURCE_LOCATION (fn),
+                      OPT_Wdefaulted_function_deleted, wmsg))

Let's not pass the OPT when DK_ERROR.

Done.

I've added new tests to cover -Wno-defaulted-function-deleted.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

OK.

-- >8 --
This PR points out the we're not implementing [dcl.fct.def.default]
properly.  Consider e.g.

   struct C {
      C(const C&&) = default;
   };

where we wrongly emit an error, but the move ctor should be just =deleted.
According to [dcl.fct.def.default], if the type of the special member
function differs from the type of the corresponding special member function
that would have been implicitly declared in a way other than as allowed
by 2.1-4, the function is defined as deleted.  There's an exception for
assignment operators in which case the program is ill-formed.

clang++ has a warning for when we delete an explicitly-defaulted function
so this patch adds it too.

When the code is ill-formed, we emit an error in all modes.  Otherwise,
we emit a pedwarn in C++17 and a warning in C++20.

        PR c++/116162

gcc/c-family/ChangeLog:

        * c.opt (Wdefaulted-function-deleted): New.

gcc/cp/ChangeLog:

        * class.cc (check_bases_and_members): Don't set DECL_DELETED_FN here,
        leave it to defaulted_late_check.
        * cp-tree.h (maybe_delete_defaulted_fn): Declare.
        (defaulted_late_check): Add a tristate parameter.
        * method.cc (maybe_delete_defaulted_fn): New.
        (defaulted_late_check): Add a tristate parameter.  Call
        maybe_delete_defaulted_fn instead of giving an error.

gcc/ChangeLog:

        * doc/invoke.texi: Document -Wdefaulted-function-deleted.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp0x/defaulted15.C: Add dg-warning/dg-error.
        * g++.dg/cpp0x/defaulted51.C: Likewise.
        * g++.dg/cpp0x/defaulted52.C: Likewise.
        * g++.dg/cpp0x/defaulted53.C: Likewise.
        * g++.dg/cpp0x/defaulted54.C: Likewise.
        * g++.dg/cpp0x/defaulted56.C: Likewise.
        * g++.dg/cpp0x/defaulted57.C: Likewise.
        * g++.dg/cpp0x/defaulted58.C: Likewise.
        * g++.dg/cpp0x/defaulted59.C: Likewise.
        * g++.dg/cpp0x/defaulted63.C: New test.
        * g++.dg/cpp0x/defaulted64.C: New test.
        * g++.dg/cpp0x/defaulted65.C: New test.
        * g++.dg/cpp0x/defaulted66.C: New test.
        * g++.dg/cpp0x/defaulted67.C: New test.
        * g++.dg/cpp0x/defaulted68.C: New test.
        * g++.dg/cpp0x/defaulted69.C: New test.
        * g++.dg/cpp23/defaulted1.C: New test.
---
  gcc/c-family/c.opt                       |  4 +
  gcc/cp/class.cc                          | 27 ++-----
  gcc/cp/cp-tree.h                         |  3 +-
  gcc/cp/method.cc                         | 98 +++++++++++++++++++++---
  gcc/doc/invoke.texi                      |  9 +++
  gcc/testsuite/g++.dg/cpp0x/defaulted15.C |  3 +-
  gcc/testsuite/g++.dg/cpp0x/defaulted51.C |  2 +-
  gcc/testsuite/g++.dg/cpp0x/defaulted52.C |  2 +-
  gcc/testsuite/g++.dg/cpp0x/defaulted53.C |  3 +-
  gcc/testsuite/g++.dg/cpp0x/defaulted54.C |  1 +
  gcc/testsuite/g++.dg/cpp0x/defaulted56.C |  6 +-
  gcc/testsuite/g++.dg/cpp0x/defaulted57.C |  6 +-
  gcc/testsuite/g++.dg/cpp0x/defaulted58.C |  1 +
  gcc/testsuite/g++.dg/cpp0x/defaulted59.C |  3 +-
  gcc/testsuite/g++.dg/cpp0x/defaulted63.C | 39 ++++++++++
  gcc/testsuite/g++.dg/cpp0x/defaulted64.C | 27 +++++++
  gcc/testsuite/g++.dg/cpp0x/defaulted65.C | 25 ++++++
  gcc/testsuite/g++.dg/cpp0x/defaulted66.C | 35 +++++++++
  gcc/testsuite/g++.dg/cpp0x/defaulted67.C | 23 ++++++
  gcc/testsuite/g++.dg/cpp0x/defaulted68.C | 35 +++++++++
  gcc/testsuite/g++.dg/cpp0x/defaulted69.C | 24 ++++++
  gcc/testsuite/g++.dg/cpp23/defaulted1.C  | 23 ++++++
  22 files changed, 359 insertions(+), 40 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/cpp0x/defaulted63.C
  create mode 100644 gcc/testsuite/g++.dg/cpp0x/defaulted64.C
  create mode 100644 gcc/testsuite/g++.dg/cpp0x/defaulted65.C
  create mode 100644 gcc/testsuite/g++.dg/cpp0x/defaulted66.C
  create mode 100644 gcc/testsuite/g++.dg/cpp0x/defaulted67.C
  create mode 100644 gcc/testsuite/g++.dg/cpp0x/defaulted68.C
  create mode 100644 gcc/testsuite/g++.dg/cpp0x/defaulted69.C
  create mode 100644 gcc/testsuite/g++.dg/cpp23/defaulted1.C

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index ec23249c959..98a35f043c7 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -629,6 +629,10 @@ Wdeclaration-missing-parameter-type
  C ObjC Var(warn_declaration_missing_parameter) Warning Init(1)
  Warn for missing parameter types in function declarations.
+Wdefaulted-function-deleted
+C++ ObjC++ Var(warn_defaulted_fn_deleted) Init(1) Warning
+Warn when an explicitly defaulted function is deleted.
+
  Wdelete-incomplete
  C++ ObjC++ Var(warn_delete_incomplete) Init(1) Warning
  Warn when deleting a pointer to incomplete type.
diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 950d83b0ea4..646072d4f20 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -6488,27 +6488,14 @@ check_bases_and_members (tree t)
    for (fn = TYPE_FIELDS (t); fn; fn = DECL_CHAIN (fn))
      if (DECL_DECLARES_FUNCTION_P (fn)
        && !DECL_ARTIFICIAL (fn)
-       && DECL_DEFAULTED_IN_CLASS_P (fn))
-      {
+       && DECL_DEFAULTED_IN_CLASS_P (fn)
        /* ...except handle comparisons later, in finish_struct_1.  */
-       if (special_function_p (fn) == sfk_comparison)
-         continue;
-
-       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.  Core Issue #1331 says this is
-                no longer ill-formed, it is defined as deleted instead.  */
-             DECL_DELETED_FN (fn) = true;
-         }
-       defaulted_late_check (fn);
+       && special_function_p (fn) != sfk_comparison)
+      {
+       bool imp_const_p
+         = (DECL_CONSTRUCTOR_P (fn) ? !cant_have_const_ctor
+            : !no_const_asn_ref);
+       defaulted_late_check (fn, imp_const_p);
        }
if (LAMBDA_TYPE_P (t))
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7baa2ccbe1e..32252e7f32f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6929,7 +6929,8 @@ extern bool type_build_ctor_call          (tree);
  extern bool type_build_dtor_call              (tree);
  extern void explain_non_literal_class         (tree);
  extern void inherit_targ_abi_tags             (tree);
-extern void defaulted_late_check               (tree);
+extern void maybe_delete_defaulted_fn          (tree, tree);
+extern void defaulted_late_check               (tree, tristate = 
tristate::unknown ());
  extern bool defaultable_fn_check              (tree);
  extern void check_abi_tags                    (tree);
  extern tree missing_abi_tags                  (tree);
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 21c06c744c9..d704db2af06 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -3509,11 +3509,89 @@ implicitly_declare_fn (special_function_kind kind, tree 
type,
    return fn;
  }
+/* Mark an explicitly defaulted function FN as =deleted and warn.
+   IMPLICIT_FN is the corresponding special member function that
+   would have been implicitly declared.  */
+
+void
+maybe_delete_defaulted_fn (tree fn, tree implicit_fn)
+{
+  if (DECL_ARTIFICIAL (fn) || !DECL_DEFAULTED_IN_CLASS_P (fn))
+    return;
+
+  DECL_DELETED_FN (fn) = true;
+
+  auto_diagnostic_group d;
+  const special_function_kind kind = special_function_p (fn);
+  tree parmtype
+    = TREE_VALUE (DECL_XOBJ_MEMBER_FUNCTION_P (fn)
+                 ? TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn)))
+                 : FUNCTION_FIRST_USER_PARMTYPE (fn));
+  const bool illformed_p
+    /* [dcl.fct.def.default] "if F1 is an assignment operator"...  */
+    = (SFK_ASSIGN_P (kind)
+       /* "and the return type of F1 differs from the return type of F2"  */
+       && (!same_type_p (TREE_TYPE (TREE_TYPE (fn)),
+                        TREE_TYPE (TREE_TYPE (implicit_fn)))
+          /* "or F1's non-object parameter type is not a reference,
+             the program is ill-formed"  */
+          || !TYPE_REF_P (parmtype)));
+  /* Decide if we want to emit a pedwarn, error, or a warning.  */
+  diagnostic_t diag_kind;
+  int opt;
+  if (illformed_p)
+    {
+      diag_kind = DK_ERROR;
+      opt = 0;
+    }
+  else
+    {
+      diag_kind = cxx_dialect >= cxx20 ? DK_WARNING : DK_PEDWARN;
+      opt = OPT_Wdefaulted_function_deleted;
+    }
+
+  /* Don't warn for template instantiations.  */
+  if (DECL_TEMPLATE_INSTANTIATION (fn) && diag_kind == DK_WARNING)
+    return;
+
+  const char *wmsg;
+  switch (kind)
+    {
+    case sfk_copy_constructor:
+      wmsg = G_("explicitly defaulted copy constructor is implicitly deleted "
+               "because its declared type does not match the type of an "
+               "implicit copy constructor");
+      break;
+    case sfk_move_constructor:
+      wmsg = G_("explicitly defaulted move constructor is implicitly deleted "
+               "because its declared type does not match the type of an "
+               "implicit move constructor");
+      break;
+    case sfk_copy_assignment:
+      wmsg = G_("explicitly defaulted copy assignment operator is implicitly "
+               "deleted because its declared type does not match the type "
+               "of an implicit copy assignment operator");
+      break;
+    case sfk_move_assignment:
+      wmsg = G_("explicitly defaulted move assignment operator is implicitly "
+               "deleted because its declared type does not match the type "
+               "of an implicit move assignment operator");
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  if (emit_diagnostic (diag_kind, DECL_SOURCE_LOCATION (fn), opt, wmsg))
+    inform (DECL_SOURCE_LOCATION (fn),
+           "expected signature: %qD", implicit_fn);
+}
+
  /* Gives any errors about defaulted functions which need to be deferred
-   until the containing class is complete.  */
+   until the containing class is complete.  IMP_CONST is false or true
+   if we are called from check_bases_and_members and signals whether
+   the implicit function has a non-object parameter of type const C&.  */
void
-defaulted_late_check (tree fn)
+defaulted_late_check (tree fn, tristate imp_const/*=tristate::unknown()*/)
  {
    /* Complain about invalid signature for defaulted fn.  */
    tree ctx = DECL_CONTEXT (fn);
@@ -3534,8 +3612,14 @@ defaulted_late_check (tree fn)
      }
bool fn_const_p = (copy_fn_p (fn) == 2);
+  /* "if F2 has a non-object parameter of type const C&, the corresponding
+     non-object parameter of F1 may be of type C&."  But not the other way
+     around.  */
+  if (fn_const_p && imp_const.is_false ())
+    fn_const_p = false;
    tree implicit_fn = implicitly_declare_fn (kind, ctx, fn_const_p,
-                                           NULL, NULL);
+                                           /*pattern_fn=*/NULL_TREE,
+                                           /*inherited_parms=*/NULL_TREE);
    tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn));
/* Includes special handling for a default xobj operator. */
@@ -3564,13 +3648,7 @@ defaulted_late_check (tree fn)
    if (!same_type_p (TREE_TYPE (TREE_TYPE (fn)),
                    TREE_TYPE (TREE_TYPE (implicit_fn)))
        || !compare_fn_params (fn, implicit_fn))
-    {
-      auto_diagnostic_group d;
-      error ("defaulted declaration %q+D does not match the "
-            "expected signature", fn);
-      inform (DECL_SOURCE_LOCATION (fn),
-             "expected signature: %qD", implicit_fn);
-    }
+    maybe_delete_defaulted_fn (fn, implicit_fn);
if (DECL_DELETED_FN (implicit_fn))
      {
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 2bcf71c35f7..032adfff5fc 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -251,6 +251,7 @@ in the following sections.
  -Wcomma-subscript  -Wconditionally-supported
  -Wno-conversion-null  -Wctad-maybe-unsupported
  -Wctor-dtor-privacy  -Wdangling-reference
+-Wno-defaulted-function-deleted
  -Wno-delete-incomplete
  -Wdelete-non-virtual-dtor  -Wno-deprecated-array-compare
  -Wdeprecated-copy -Wdeprecated-copy-dtor
@@ -4798,6 +4799,14 @@ not caught by reference. @option{-Wcatch-value} is 
enabled by @option{-Wall}.
  @item -Wconditionally-supported @r{(C++ and Objective-C++ only)}
  Warn for conditionally-supported (C++11 [intro.defs]) constructs.
+@opindex Wdefaulted-function-deleted
+@opindex Wno-defaulted-function-deleted
+@item -Wno-defaulted-function-deleted @r{(C++ and Objective-C++ only)}
+Warn when an explicitly defaulted function is deleted by the compiler.
+That can occur when the function's declared type does not match the type
+of the function that would have been implicitly declared.  This warning
+is enabled by default.
+
  @opindex Wdelete-incomplete
  @opindex Wno-delete-incomplete
  @item -Wno-delete-incomplete @r{(C++ and Objective-C++ only)}
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted15.C 
b/gcc/testsuite/g++.dg/cpp0x/defaulted15.C
index 1e0b3545840..6bd02d74dc3 100644
--- a/gcc/testsuite/g++.dg/cpp0x/defaulted15.C
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted15.C
@@ -48,7 +48,8 @@ struct F
struct G: public F
  {
-  G(const G&) = default;
+  G(const G&) = default;  // { dg-error "implicitly deleted" "" { target 
c++17_down } }
+                         // { dg-warning "implicitly deleted" "" { target 
c++20 } .-1 }
  };
struct H
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted51.C 
b/gcc/testsuite/g++.dg/cpp0x/defaulted51.C
index 0a7d308707c..d81baa0059d 100644
--- a/gcc/testsuite/g++.dg/cpp0x/defaulted51.C
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted51.C
@@ -4,7 +4,7 @@
  template<int> struct A
  {
    A();
-  A(volatile A&) = default;  // { dg-error "defaulted" }
+  A(volatile A&) = default;  // { dg-error "defaulted" "" { target c++17_down 
} }
  };
struct B
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted52.C 
b/gcc/testsuite/g++.dg/cpp0x/defaulted52.C
index c617230b493..e6128f40aeb 100644
--- a/gcc/testsuite/g++.dg/cpp0x/defaulted52.C
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted52.C
@@ -13,7 +13,7 @@ template<typename T> struct W
  {
    W();
    // This should now compile and be =deleted.
-  W(const W&) = default;
+  W(const W&) = default; // { dg-error "implicitly deleted" "" { target 
c++17_down } }
    T t;
  };
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted53.C b/gcc/testsuite/g++.dg/cpp0x/defaulted53.C
index 8147e7e2ad1..cc039672277 100644
--- a/gcc/testsuite/g++.dg/cpp0x/defaulted53.C
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted53.C
@@ -14,7 +14,8 @@ struct R
struct S
  {
-  S& operator=(const S&) = default;
+  S& operator=(const S&) = default; // { dg-error "implicitly deleted" "" { 
target c++17_down } }
+                                   // { dg-warning "implicitly deleted" "" { 
target c++20 } .-1 }
    M m;
  };
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted54.C b/gcc/testsuite/g++.dg/cpp0x/defaulted54.C
index f8ddc4e47ce..04cc0cd7eeb 100644
--- a/gcc/testsuite/g++.dg/cpp0x/defaulted54.C
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted54.C
@@ -11,6 +11,7 @@ template<typename T> struct W
  {
    W();
    W(const W&) = default; // { dg-error "binding" }
+// { dg-error "implicitly deleted" "" { target c++17_down } .-1 }
    T t;
  };
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted56.C b/gcc/testsuite/g++.dg/cpp0x/defaulted56.C
index e7ce12c5566..0e36fd293f6 100644
--- a/gcc/testsuite/g++.dg/cpp0x/defaulted56.C
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted56.C
@@ -11,12 +11,14 @@ struct S
struct T
  {
-  constexpr T(volatile T &) = default; // { dg-error "defaulted" }
+  constexpr T(volatile T &) = default; // { dg-error "defaulted" "" { target 
c++17_down } }
+                                      // { dg-warning "implicitly deleted" "" 
{ target c++20 } .-1 }
  };
struct U
  {
-  constexpr U(const volatile U &) = default; // { dg-error "defaulted" }
+  constexpr U(const volatile U &) = default; // { dg-error "defaulted" "" { 
target c++17_down } }
+                                            // { dg-warning "implicitly deleted" 
"" { target c++20 } .-1 }
  };
struct V
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted57.C 
b/gcc/testsuite/g++.dg/cpp0x/defaulted57.C
index 37fb7dd6e1d..feca9662b4a 100644
--- a/gcc/testsuite/g++.dg/cpp0x/defaulted57.C
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted57.C
@@ -11,12 +11,14 @@ struct S
struct T
  {
-  T& operator=(volatile T &) = default; // { dg-error "defaulted" }
+  T& operator=(volatile T &) = default; // { dg-error "defaulted" "" { target 
c++17_down } }
+                                       // { dg-warning "implicitly deleted" "" 
{ target c++20 } .-1 }
  };
struct U
  {
-  U& operator=(const volatile U &) = default; // { dg-error "defaulted" }
+  U& operator=(const volatile U &) = default; // { dg-error "defaulted" "" { 
target c++17_down } }
+                                             // { dg-warning "implicitly deleted" 
"" { target c++20 } .-1 }
  };
struct V
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted58.C 
b/gcc/testsuite/g++.dg/cpp0x/defaulted58.C
index 920a4ad0c6d..6ddae46cd63 100644
--- a/gcc/testsuite/g++.dg/cpp0x/defaulted58.C
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted58.C
@@ -11,6 +11,7 @@ template<typename T> struct W
  {
    W() = default;
    W& operator=(const W&) = default; // { dg-error "binding" }
+// { dg-error "implicitly deleted" "" { target c++17_down } .-1 }
    T t;
  };
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted59.C b/gcc/testsuite/g++.dg/cpp0x/defaulted59.C
index 4f871d7f5b1..26510b4ee33 100644
--- a/gcc/testsuite/g++.dg/cpp0x/defaulted59.C
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted59.C
@@ -8,5 +8,6 @@ struct M
struct W : public M
  {
-  W(const W&) = default;
+  W(const W&) = default; // { dg-error "implicitly deleted" "" { target 
c++17_down } }
+                        // { dg-warning "implicitly deleted" "" { target c++20 
} .-1 }
  };
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted63.C 
b/gcc/testsuite/g++.dg/cpp0x/defaulted63.C
new file mode 100644
index 00000000000..99f92ff69c5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted63.C
@@ -0,0 +1,39 @@
+// PR c++/116162
+// { dg-do compile { target c++11 } }
+
+struct C0 {
+  C0(C0&) = default;
+};
+
+struct C1 {
+  C1(volatile C1&) = default; // { dg-warning "implicitly deleted" "" { target 
c++20 } }
+                             // { dg-error "does not match" "" { target 
c++17_down } .-1 }
+};
+
+struct C2 {
+  C2(const C2&) = default;
+};
+
+struct C3 {
+  C3(const volatile C3&) = default;  // { dg-warning "implicitly deleted" "" { 
target c++20 } }
+                                     // { dg-error "does not match" "" { 
target c++17_down } .-1 }
+};
+
+struct M0 {
+  M0(M0&&) = default;
+};
+
+struct M1 {
+  M1(const M1&&) = default; // { dg-warning "implicitly deleted" "" { target 
c++20 } }
+                           // { dg-error "does not match" "" { target 
c++17_down } .-1 }
+};
+
+struct M2 {
+  M2(volatile M2&&) = default; // { dg-warning "implicitly deleted" "" { 
target c++20 } }
+                               // { dg-error "does not match" "" { target 
c++17_down } .-1 }
+};
+
+struct M3 {
+  M3(const volatile M3&&) = default;  // { dg-warning "implicitly deleted" "" 
{ target c++20 } }
+                                     // { dg-error "does not match" "" { 
target c++17_down } .-1 }
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted64.C 
b/gcc/testsuite/g++.dg/cpp0x/defaulted64.C
new file mode 100644
index 00000000000..f20030192c3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted64.C
@@ -0,0 +1,27 @@
+// PR c++/116162
+// { dg-do compile { target c++11 } }
+
+struct M
+{
+  M& operator=(M&&);
+};
+
+struct R
+{
+  R& operator=(R&&) = default;
+  M m;
+};
+
+struct S
+{
+  S& operator=(const S&&) = default; // { dg-warning "implicitly deleted" "" { 
target c++20 } }
+                                    // { dg-error "does not match" "" { target 
c++17_down } .-1 }
+
+  M m;
+};
+
+struct T
+{
+  T operator=(T&&) = default; // { dg-error "defaulted" }
+  M m;
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted65.C 
b/gcc/testsuite/g++.dg/cpp0x/defaulted65.C
new file mode 100644
index 00000000000..88ca1d96084
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted65.C
@@ -0,0 +1,25 @@
+// PR c++/116162
+// { dg-do compile { target c++11 } }
+
+struct S
+{
+  S& operator=(S &&) = default;
+};
+
+struct T
+{
+  T& operator=(volatile T &&) = default; // { dg-error "defaulted" "" { target 
c++17_down } }
+                                        // { dg-warning "implicitly deleted" 
"" { target c++20 } .-1 }
+};
+
+struct U
+{
+  U& operator=(const volatile U &&) = default; // { dg-error "defaulted" "" { 
target c++17_down } }
+                                              // { dg-warning "implicitly deleted" 
"" { target c++20 } .-1 }
+};
+
+struct V
+{
+  V& operator=(const V &&) = default; // { dg-error "defaulted" "" { target 
c++17_down } }
+                                     // { dg-warning "implicitly deleted" "" { 
target c++20 } .-1 }
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted66.C 
b/gcc/testsuite/g++.dg/cpp0x/defaulted66.C
new file mode 100644
index 00000000000..00d3e43e89f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted66.C
@@ -0,0 +1,35 @@
+// PR c++/116162
+// { dg-do compile { target c++11 } }
+// Check that there is no -Wdefaulted-function-deleted for template
+// instantiations.
+
+template<typename>
+struct C {
+   C();
+   C(const C&&) = default; // { dg-error "implicitly deleted" "" { target 
c++17_down} }
+};
+
+struct D {
+  D(const D&&) = default; // { dg-error "implicitly deleted" "" { target 
c++17_down} }
+  // { dg-warning "implicitly deleted" "" { target c++20 } .-1 }
+};
+
+struct M {
+  M();
+  // So that W wouldn't have had "const W&" copy ctor if it were
+  // implicitly declared.
+  M(M&);
+};
+
+struct W {
+   W();
+   W(const W&) = default; // { dg-error "implicitly deleted" "" { target 
c++17_down} }
+   // { dg-warning "implicitly deleted" "" { target c++20 } .-1 }
+   M m;
+};
+
+void
+g ()
+{
+  C<int> c;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted67.C 
b/gcc/testsuite/g++.dg/cpp0x/defaulted67.C
new file mode 100644
index 00000000000..a47761c3a26
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted67.C
@@ -0,0 +1,23 @@
+// PR c++/116162
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-Wno-defaulted-function-deleted" }
+
+struct S
+{
+  S& operator=(S &&) = default;
+};
+
+struct T
+{
+  T& operator=(volatile T &&) = default;
+};
+
+struct U
+{
+  U& operator=(const volatile U &&) = default;
+};
+
+struct V
+{
+  V& operator=(const V &&) = default;
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted68.C 
b/gcc/testsuite/g++.dg/cpp0x/defaulted68.C
new file mode 100644
index 00000000000..c8c1261de42
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted68.C
@@ -0,0 +1,35 @@
+// PR c++/116162
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-Wno-defaulted-function-deleted" }
+
+struct C0 {
+  C0(C0&) = default;
+};
+
+struct C1 {
+  C1(volatile C1&) = default;
+};
+
+struct C2 {
+  C2(const C2&) = default;
+};
+
+struct C3 {
+  C3(const volatile C3&) = default;
+};
+
+struct M0 {
+  M0(M0&&) = default;
+};
+
+struct M1 {
+  M1(const M1&&) = default;
+};
+
+struct M2 {
+  M2(volatile M2&&) = default;
+};
+
+struct M3 {
+  M3(const volatile M3&&) = default;
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted69.C 
b/gcc/testsuite/g++.dg/cpp0x/defaulted69.C
new file mode 100644
index 00000000000..a466259dfd7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted69.C
@@ -0,0 +1,24 @@
+// PR c++/116162
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-Wno-defaulted-function-deleted" }
+
+struct M
+{
+  M& operator=(M&);
+};
+
+struct T
+{
+  // if F1 is an assignment operator, and the return type of F1 differs
+  // from the return type,  the program is ill-formed.
+  T operator=(T&) = default; // { dg-error "defaulted" }
+  M m;
+};
+
+struct U
+{
+  // if F1's non-object parameter type is not a reference, the program
+  // is ill-formed.
+  U& operator=(U) = default; // { dg-error "defaulted" }
+  M m;
+};
diff --git a/gcc/testsuite/g++.dg/cpp23/defaulted1.C 
b/gcc/testsuite/g++.dg/cpp23/defaulted1.C
new file mode 100644
index 00000000000..00cf894fa1d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/defaulted1.C
@@ -0,0 +1,23 @@
+// PR c++/116162
+// { dg-do compile { target c++23 } }
+
+struct M
+{
+  M& operator=(M&);
+};
+
+struct T
+{
+  // if F1 is an assignment operator, and the return type of F1 differs
+  // from the return type,  the program is ill-formed.
+  T operator=(this T&, T&) = default; // { dg-error "defaulted" }
+  M m;
+};
+
+struct U
+{
+  // if F1's non-object parameter type is not a reference, the program
+  // is ill-formed.
+  U& operator=(this U&, U) = default; // { dg-error "defaulted" }
+  M m;
+};

base-commit: cee868ae0dfb5bef590a0a82426d32ba1d2b1a92

Reply via email to