diff options
author | Jason Merrill <jason@redhat.com> | 2020-06-16 00:20:58 -0400 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2020-06-17 15:08:42 -0400 |
commit | da2c9054f1596b71e3c81efd62b6cef348e445b4 (patch) | |
tree | 59b9bf926db8129c48e0f022ac5217fd6e932596 | |
parent | d2384b7b24f8557b66f6958a05ea99ff4307e75c (diff) | |
download | gcc-da2c9054f1596b71e3c81efd62b6cef348e445b4.zip gcc-da2c9054f1596b71e3c81efd62b6cef348e445b4.tar.gz gcc-da2c9054f1596b71e3c81efd62b6cef348e445b4.tar.bz2 |
c++: Treat in-class default/delete as definitions.
We were complaining about a constrained defaulted non-template friend in a
template class because funcdef_flag wasn't set. grokdeclarator would set it
for default/delete, but grokfield wasn't passing the 'initialized' values
needed. Fixing that revealed some errors in existing tests that we weren't
diagnosing. Since we accepted them for so long, I'm reducing the error to a
pedwarn to ease compiler upgrade.
gcc/cp/ChangeLog:
* decl2.c (grokfield): Pass SD_DEFAULTED and SD_DELETED.
* decl.c (duplicate_decls): Reduce error for delete
after earlier declaration to pedwarn.
gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/pr62101.C: Expect error.
* g++.dg/cpp0x/pr80259.C: Expect error.
* g++.dg/cpp2a/concepts-friend8.C: New test.
-rw-r--r-- | gcc/cp/decl.c | 8 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 29 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/pr62101.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/pr80259.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/concepts-friend8.C | 12 |
5 files changed, 37 insertions, 16 deletions
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 539609e..1d960be 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2067,13 +2067,19 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) "previous declaration of %qD", olddecl); } + /* [dcl.fct.def.delete] A deleted definition of a function shall be the + first declaration of the function or, for an explicit specialization + of a function template, the first declaration of that + specialization. */ if (!(DECL_TEMPLATE_INSTANTIATION (olddecl) && DECL_TEMPLATE_SPECIALIZATION (newdecl))) { if (DECL_DELETED_FN (newdecl)) { auto_diagnostic_group d; - error_at (newdecl_loc, "deleted definition of %qD", newdecl); + pedwarn (newdecl_loc, OPT_Wpedantic, + "deleted definition of %qD is not first declaration", + newdecl); inform (olddecl_loc, "previous declaration of %qD", olddecl); } diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 449c86c..93e3034 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -838,7 +838,17 @@ grokfield (const cp_declarator *declarator, && TREE_CHAIN (init) == NULL_TREE) init = NULL_TREE; - value = grokdeclarator (declarator, declspecs, FIELD, init != 0, &attrlist); + int initialized; + if (init == ridpointers[(int)RID_DELETE]) + initialized = SD_DELETED; + else if (init == ridpointers[(int)RID_DEFAULT]) + initialized = SD_DEFAULTED; + else if (init) + initialized = SD_INITIALIZED; + else + initialized = SD_UNINITIALIZED; + + value = grokdeclarator (declarator, declspecs, FIELD, initialized, &attrlist); if (! value || value == error_mark_node) /* friend or constructor went bad. */ return error_mark_node; @@ -916,18 +926,8 @@ grokfield (const cp_declarator *declarator, { if (init == ridpointers[(int)RID_DELETE]) { - if (friendp && decl_defined_p (value)) - { - error ("redefinition of %q#D", value); - inform (DECL_SOURCE_LOCATION (value), - "%q#D previously defined here", value); - } - else - { - DECL_DELETED_FN (value) = 1; - DECL_DECLARED_INLINE_P (value) = 1; - DECL_INITIAL (value) = error_mark_node; - } + DECL_DELETED_FN (value) = 1; + DECL_DECLARED_INLINE_P (value) = 1; } else if (init == ridpointers[(int)RID_DEFAULT]) { @@ -936,6 +936,9 @@ grokfield (const cp_declarator *declarator, DECL_DEFAULTED_FN (value) = 1; DECL_INITIALIZED_IN_CLASS_P (value) = 1; DECL_DECLARED_INLINE_P (value) = 1; + /* grokfndecl set this to error_mark_node, but we want to + leave it unset until synthesize_method. */ + DECL_INITIAL (value) = NULL_TREE; } } else if (TREE_CODE (init) == DEFERRED_PARSE) diff --git a/gcc/testsuite/g++.dg/cpp0x/pr62101.C b/gcc/testsuite/g++.dg/cpp0x/pr62101.C index 5fc579c..07ab1b7 100644 --- a/gcc/testsuite/g++.dg/cpp0x/pr62101.C +++ b/gcc/testsuite/g++.dg/cpp0x/pr62101.C @@ -17,7 +17,7 @@ void g(Y, double); struct Y { // { dg-prune-output "note" } - friend void g(Y, int) = delete; + friend void g(Y, int) = delete; // { dg-error "not first declaration" } friend void g(Y, double) {} }; diff --git a/gcc/testsuite/g++.dg/cpp0x/pr80259.C b/gcc/testsuite/g++.dg/cpp0x/pr80259.C index 9d2a109..adb354b 100644 --- a/gcc/testsuite/g++.dg/cpp0x/pr80259.C +++ b/gcc/testsuite/g++.dg/cpp0x/pr80259.C @@ -7,7 +7,7 @@ void bar (); struct A { friend void foo () = delete; // { dg-error "redefinition of" } - friend void bar () = delete; // { dg-message "previously defined here" } + friend void bar () = delete; // { dg-error "not first declaration" } }; void bar () {} // { dg-error "redefinition of" } diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-friend8.C b/gcc/testsuite/g++.dg/cpp2a/concepts-friend8.C new file mode 100644 index 0000000..e4930bb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-friend8.C @@ -0,0 +1,12 @@ +// { dg-do compile { target c++20 } } + +template <class T> +struct A +{ + friend bool operator==(const A&, const A&) requires true = default; +}; + +int main() +{ + A<int>() == A<int>(); +} |