https://github.com/Sirraide created https://github.com/llvm/llvm-project/pull/105121
Diagnose this early after parsing declaration specifiers; this allows us to issue a better diagnostic. This also checks for `concept friend` and concept declarations w/o a template-head because it’s easiest to do that at the same time. Fixes #45182. >From 1cc581a3b3af057793c11a862b8facfba2aef926 Mon Sep 17 00:00:00 2001 From: Sirraide <aeternalm...@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 <aeternalm...@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 <aeternalm...@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 <aeternalm...@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}} }; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits