Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/15?
-- >8 --
This does three things:
1) [dcl.fct.def.default]/2.6 says "if F1 is explicitly defaulted on its
first declaration, it is defined as deleted;", but I wasn't heeding the
"on its first declaration" part, so fix that;
2) when the decl is actually ill-formed, don't talk about it being
implicitly deleted, because it's not;
3) there is no need to export maybe_delete_defaulted_fn.
PR c++/119964
gcc/cp/ChangeLog:
* cp-tree.h (maybe_delete_defaulted_fn): Remove.
* method.cc (maybe_delete_defaulted_fn): Make static. Refactor. If FN
is not explicitly defaulted on its first declaration, emit an error.
gcc/testsuite/ChangeLog:
* g++.dg/cpp1y/defaulted1.C: New test.
* g++.dg/cpp1y/defaulted2.C: New test.
---
gcc/cp/cp-tree.h | 1 -
gcc/cp/method.cc | 51 +++++++++++++------------
gcc/testsuite/g++.dg/cpp1y/defaulted1.C | 17 +++++++++
gcc/testsuite/g++.dg/cpp1y/defaulted2.C | 15 ++++++++
4 files changed, 58 insertions(+), 26 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp1y/defaulted1.C
create mode 100644 gcc/testsuite/g++.dg/cpp1y/defaulted2.C
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c6e284d060c..972600b6fae 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7180,7 +7180,6 @@ 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 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);
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index ef8370fac5b..ca143a5175f 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -3648,49 +3648,49 @@ implicitly_declare_fn (special_function_kind kind, tree
type,
return fn;
}
-/* Mark an explicitly defaulted function FN as =deleted and warn.
+/* Maybe mark an explicitly defaulted function FN as =deleted and warn,
+ or emit an error, as per [dcl.fct.def.default].
IMPLICIT_FN is the corresponding special member function that
- would have been implicitly declared. */
+ would have been implicitly declared. We've already compared FN and
+ IMPLICIT_FN and they are not the same. */
-void
+static void
maybe_delete_defaulted_fn (tree fn, tree implicit_fn)
{
- if (DECL_ARTIFICIAL (fn) || !DECL_DEFAULTED_IN_CLASS_P (fn))
+ if (DECL_ARTIFICIAL (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)
+ if (/* [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. */
- enum diagnostics::kind diag_kind;
- int opt;
- if (illformed_p)
- {
- diag_kind = diagnostics::kind::error;
- opt = 0;
- }
- else
- {
- diag_kind = (cxx_dialect >= cxx20
- ? diagnostics::kind::warning
- : diagnostics::kind::pedwarn);
- opt = OPT_Wdefaulted_function_deleted;
+ || !TYPE_REF_P (parmtype)))
+ /* If F1 is *not* explicitly defaulted on its first declaration, the
+ program is ill-formed. */
+ || !DECL_DEFAULTED_IN_CLASS_P (fn))
+ {
+ error ("defaulted declaration %q+D does not match the expected "
+ "signature", fn);
+ inform (DECL_SOURCE_LOCATION (fn), "expected signature: %qD",
+ implicit_fn);
+ return;
}
+ DECL_DELETED_FN (fn) = true;
+
+ const enum diagnostics::kind diag_kind = (cxx_dialect >= cxx20
+ ? diagnostics::kind::warning
+ : diagnostics::kind::pedwarn);
+
/* Don't warn for template instantiations. */
if (DECL_TEMPLATE_INSTANTIATION (fn)
&& diag_kind == diagnostics::kind::warning)
@@ -3722,7 +3722,8 @@ maybe_delete_defaulted_fn (tree fn, tree implicit_fn)
default:
gcc_unreachable ();
}
- if (emit_diagnostic (diag_kind, DECL_SOURCE_LOCATION (fn), opt, wmsg))
+ if (emit_diagnostic (diag_kind, DECL_SOURCE_LOCATION (fn),
+ OPT_Wdefaulted_function_deleted, wmsg))
inform (DECL_SOURCE_LOCATION (fn),
"expected signature: %qD", implicit_fn);
}
diff --git a/gcc/testsuite/g++.dg/cpp1y/defaulted1.C
b/gcc/testsuite/g++.dg/cpp1y/defaulted1.C
new file mode 100644
index 00000000000..7b38f975d41
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/defaulted1.C
@@ -0,0 +1,17 @@
+// PR c++/119964
+// { dg-do compile { target c++14 } }
+
+struct A {
+ int i;
+ constexpr A(int v) : i(v) {}
+ constexpr A(const A&&);
+};
+
+constexpr int f() {
+ A a(1);
+ A b = static_cast<const A&&>( a );
+ return b.i;
+}
+
+constexpr A::A(const A&&) = default; // { dg-error "does not match the
expected signature" }
+static_assert(f () == 1, "");
diff --git a/gcc/testsuite/g++.dg/cpp1y/defaulted2.C
b/gcc/testsuite/g++.dg/cpp1y/defaulted2.C
new file mode 100644
index 00000000000..9e5e6a69eea
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/defaulted2.C
@@ -0,0 +1,15 @@
+// PR c++/119964
+// { dg-do compile { target c++14 } }
+
+struct A {
+ int i;
+ constexpr A(int v) : i(v) {}
+ constexpr A(const A&&) = default; // { dg-error "implicitly deleted" "" {
target c++17_down } }
+ // { dg-warning "implicitly deleted" ""
{ target c++20 } .-1 }
+};
+
+constexpr int f() {
+ A a(1);
+ A b = static_cast<const A&&>( a ); // { dg-error "use of deleted function"
}
+ return b.i;
+}
base-commit: b7f137e56867dd3aa1f05f3409f146391dec131c
--
2.51.1