[clang] [Clang] [Parser] Improve diagnostic for `friend concept` (PR #105121)

via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 22 14:33:24 PDT 2024


https://github.com/Sirraide updated https://github.com/llvm/llvm-project/pull/105121

>From 1cc581a3b3af057793c11a862b8facfba2aef926 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Tue, 20 Aug 2024 18:40:18 +0200
Subject: [PATCH 1/4] [Clang] [Parser] Improve diagnostic for 'friend concept'

---
 clang/include/clang/Basic/DiagnosticParseKinds.td |  3 +++
 clang/lib/Parse/ParseDeclCXX.cpp                  |  9 +++++++++
 clang/test/Parser/friend-concept.cpp              | 11 +++++++++++
 3 files changed, 23 insertions(+)
 create mode 100644 clang/test/Parser/friend-concept.cpp

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 62a97b36737e72..953d40b8e5fa56 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -971,6 +971,9 @@ def warn_cxx23_variadic_friends : Warning<
   "variadic 'friend' declarations are incompatible with C++ standards before C++2c">,
   DefaultIgnore, InGroup<CXXPre26Compat>;
 
+def err_friend_concept : Error<
+  "friend declaration cannot be a concept">;
+
 // C++11 default member initialization
 def ext_nonstatic_member_init : ExtWarn<
   "default member initializer for non-static data member is a C++11 "
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 18c5fe6056b472..400745fd73fd9b 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -3139,6 +3139,15 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration(
     return Actions.BuildDeclaratorGroup(Decls);
   }
 
+  // Befriending a concept is invalid and would already fail if
+  // we did nothing here, but this allows us to issue a more
+  // helpful diagnostic.
+  if (Tok.is(tok::kw_concept)) {
+    Diag(Tok.getLocation(), diag::err_friend_concept);
+    SkipUntil(tok::semi, tok::r_brace, StopBeforeMatch);
+    return nullptr;
+  }
+
   ParsingDeclarator DeclaratorInfo(*this, DS, DeclAttrs,
                                    DeclaratorContext::Member);
   if (TemplateInfo.TemplateParams)
diff --git a/clang/test/Parser/friend-concept.cpp b/clang/test/Parser/friend-concept.cpp
new file mode 100644
index 00000000000000..d032a31b1de9bd
--- /dev/null
+++ b/clang/test/Parser/friend-concept.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
+
+template<class>
+concept fooable = true;
+
+struct S {
+  template<class> friend concept fooable; // expected-error {{friend declaration cannot be a concept}}
+  template<class> concept friend fooable; // expected-error {{expected unqualified-id}}
+  friend concept fooable; // expected-error {{friend declaration cannot be a concept}}
+  concept friend fooable; // expected-error {{friend declaration cannot be a concept}}
+};

>From fe042f6a37c9cf4c735e0a973f9fdfbb38492ebd Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Tue, 20 Aug 2024 18:43:51 +0200
Subject: [PATCH 2/4] Add release note

---
 clang/docs/ReleaseNotes.rst | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index e3fac712de4662..7fd856a8e6d16b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -233,6 +233,8 @@ Improvements to Clang's diagnostics
 
 - Clang now diagnoses when the result of a [[nodiscard]] function is discarded after being cast in C. Fixes #GH104391.
 
+- Improved diagnostic when trying to befriend a concept. (#GH45182).
+
 Improvements to Clang's time-trace
 ----------------------------------
 

>From c329d5d6d630be3a7705804df8d22e775a10e073 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Tue, 20 Aug 2024 18:50:20 +0200
Subject: [PATCH 3/4] Not every declaration in a class is a friend

---
 clang/lib/Parse/ParseDeclCXX.cpp     | 6 +++++-
 clang/test/Parser/friend-concept.cpp | 2 +-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 400745fd73fd9b..9e8e5c90721c8d 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -3143,7 +3143,11 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration(
   // we did nothing here, but this allows us to issue a more
   // helpful diagnostic.
   if (Tok.is(tok::kw_concept)) {
-    Diag(Tok.getLocation(), diag::err_friend_concept);
+    Diag(Tok.getLocation(),
+         DS.isFriendSpecified()
+             ? diag::err_friend_concept
+             : diag::
+                   err_concept_decls_may_only_appear_in_global_namespace_scope);
     SkipUntil(tok::semi, tok::r_brace, StopBeforeMatch);
     return nullptr;
   }
diff --git a/clang/test/Parser/friend-concept.cpp b/clang/test/Parser/friend-concept.cpp
index d032a31b1de9bd..66536a1bd4ad9d 100644
--- a/clang/test/Parser/friend-concept.cpp
+++ b/clang/test/Parser/friend-concept.cpp
@@ -7,5 +7,5 @@ struct S {
   template<class> friend concept fooable; // expected-error {{friend declaration cannot be a concept}}
   template<class> concept friend fooable; // expected-error {{expected unqualified-id}}
   friend concept fooable; // expected-error {{friend declaration cannot be a concept}}
-  concept friend fooable; // expected-error {{friend declaration cannot be a concept}}
+  concept friend fooable; // expected-error {{concept declarations may only appear in global or namespace scope}}
 };

>From 8d09f2a02a089b28d4ea177970724e964b9ef43d Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Tue, 20 Aug 2024 19:00:06 +0200
Subject: [PATCH 4/4] Also check for 'concept friend'

---
 clang/lib/Parse/ParseDeclCXX.cpp     | 2 +-
 clang/test/Parser/friend-concept.cpp | 4 +++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 9e8e5c90721c8d..7ca27d00c0bcbf 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -3144,7 +3144,7 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration(
   // helpful diagnostic.
   if (Tok.is(tok::kw_concept)) {
     Diag(Tok.getLocation(),
-         DS.isFriendSpecified()
+         DS.isFriendSpecified() || NextToken().is(tok::kw_friend)
              ? diag::err_friend_concept
              : diag::
                    err_concept_decls_may_only_appear_in_global_namespace_scope);
diff --git a/clang/test/Parser/friend-concept.cpp b/clang/test/Parser/friend-concept.cpp
index 66536a1bd4ad9d..d771ca4d4178ed 100644
--- a/clang/test/Parser/friend-concept.cpp
+++ b/clang/test/Parser/friend-concept.cpp
@@ -4,8 +4,10 @@ template<class>
 concept fooable = true;
 
 struct S {
+  template<class> friend concept x = requires { requires true; }; // expected-error {{friend declaration cannot be a concept}}
   template<class> friend concept fooable; // expected-error {{friend declaration cannot be a concept}}
   template<class> concept friend fooable; // expected-error {{expected unqualified-id}}
   friend concept fooable; // expected-error {{friend declaration cannot be a concept}}
-  concept friend fooable; // expected-error {{concept declarations may only appear in global or namespace scope}}
+  concept friend fooable; // expected-error {{friend declaration cannot be a concept}}
+  concept fooable; // expected-error {{concept declarations may only appear in global or namespace scope}}
 };



More information about the cfe-commits mailing list