diff mbox series

[pushed] c++: Treat in-class default/delete as definitions.

Message ID 20200617190919.16478-1-jason@redhat.com
State New
Headers show
Series [pushed] c++: Treat in-class default/delete as definitions. | expand

Commit Message

Jason Merrill June 17, 2020, 7:09 p.m. UTC
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.

Tested x86_64-pc-linux-gnu, applying to trunk.

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.
---
 gcc/cp/decl.c                                 |  8 ++++-
 gcc/cp/decl2.c                                | 29 ++++++++++---------
 gcc/testsuite/g++.dg/cpp0x/pr62101.C          |  2 +-
 gcc/testsuite/g++.dg/cpp0x/pr80259.C          |  2 +-
 gcc/testsuite/g++.dg/cpp2a/concepts-friend8.C | 12 ++++++++
 5 files changed, 37 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-friend8.C


base-commit: d2384b7b24f8557b66f6958a05ea99ff4307e75c
diff mbox series

Patch

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 539609e8ada..1d960be1ee6 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 449c86c66c9..93e30340454 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 5fc579c7661..07ab1b76fbc 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 9d2a109bcf3..adb354b4ee8 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 00000000000..e4930bbf80c
--- /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>();
+}