Skip to content

Commit 8b5f606

Browse files
authored
[Clang] [Parser] Improve diagnostic for friend concept (#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.
1 parent d010ec6 commit 8b5f606

File tree

4 files changed

+31
-0
lines changed

4 files changed

+31
-0
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ Improvements to Clang's diagnostics
241241

242242
- Don't emit duplicated dangling diagnostics. (#GH93386).
243243

244+
- Improved diagnostic when trying to befriend a concept. (#GH45182).
245+
244246
Improvements to Clang's time-trace
245247
----------------------------------
246248

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,9 @@ def warn_cxx23_variadic_friends : Warning<
974974
"variadic 'friend' declarations are incompatible with C++ standards before C++2c">,
975975
DefaultIgnore, InGroup<CXXPre26Compat>;
976976

977+
def err_friend_concept : Error<
978+
"friend declaration cannot be a concept">;
979+
977980
// C++11 default member initialization
978981
def ext_nonstatic_member_init : ExtWarn<
979982
"default member initializer for non-static data member is a C++11 "

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3139,6 +3139,19 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration(
31393139
return Actions.BuildDeclaratorGroup(Decls);
31403140
}
31413141

3142+
// Befriending a concept is invalid and would already fail if
3143+
// we did nothing here, but this allows us to issue a more
3144+
// helpful diagnostic.
3145+
if (Tok.is(tok::kw_concept)) {
3146+
Diag(Tok.getLocation(),
3147+
DS.isFriendSpecified() || NextToken().is(tok::kw_friend)
3148+
? diag::err_friend_concept
3149+
: diag::
3150+
err_concept_decls_may_only_appear_in_global_namespace_scope);
3151+
SkipUntil(tok::semi, tok::r_brace, StopBeforeMatch);
3152+
return nullptr;
3153+
}
3154+
31423155
ParsingDeclarator DeclaratorInfo(*this, DS, DeclAttrs,
31433156
DeclaratorContext::Member);
31443157
if (TemplateInfo.TemplateParams)

clang/test/Parser/friend-concept.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
2+
3+
template<class>
4+
concept fooable = true;
5+
6+
struct S {
7+
template<class> friend concept x = requires { requires true; }; // expected-error {{friend declaration cannot be a concept}}
8+
template<class> friend concept fooable; // expected-error {{friend declaration cannot be a concept}}
9+
template<class> concept friend fooable; // expected-error {{expected unqualified-id}}
10+
friend concept fooable; // expected-error {{friend declaration cannot be a concept}}
11+
concept friend fooable; // expected-error {{friend declaration cannot be a concept}}
12+
concept fooable; // expected-error {{concept declarations may only appear in global or namespace scope}}
13+
};

0 commit comments

Comments
 (0)