diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index cb5d1c235951f..e1312b614bbbd 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -339,6 +339,7 @@ Bug Fixes to Attribute Support Bug Fixes to C++ Support ^^^^^^^^^^^^^^^^^^^^^^^^ +- Fixed a crash when a function template is defined as a non-template friend with a global scope qualifier. (#GH185341) - Fixed a crash on error recovery when dealing with invalid templates. (#GH183075) - Fixed a crash when instantiating ``requires`` expressions involving substitution failures in C++ concepts. (#GH176402) - Fixed an incorrect template argument deduction when matching packs of template diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 2ae6e5de0e3ee..96796b8afd24f 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -18306,6 +18306,17 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, LookupResult Previous(*this, NameInfo, LookupOrdinaryName, RedeclarationKind::ForExternalRedeclaration); +if (D.isFunctionDefinition() && SS.isNotEmpty()) { + auto Kind = SS.getScopeRep().getKind(); + if (Kind == NestedNameSpecifier::Kind::Global || + Kind == NestedNameSpecifier::Kind::Namespace) { + Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def) + << SS.getScopeRep() << FixItHint::CreateRemoval(SS.getRange()); + SS.clear(); + Previous.clear(); + } +} + bool isTemplateId = D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId; // There are five cases here. @@ -18502,20 +18513,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, // only if the class is a non-local class, and the function name is // unqualified. if (D.isFunctionDefinition()) { - // Qualified friend function definition. - if (SS.isNotEmpty()) { - // FIXME: We should only do this if the scope specifier names the - // innermost enclosing namespace; otherwise the fixit changes the - // meaning of the code. - SemaDiagnosticBuilder DB = - Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def); - - DB << SS.getScopeRep(); - if (DC->isFileContext()) - DB << FixItHint::CreateRemoval(SS.getRange()); - - // Friend function defined in a local class. - } else if (FunctionContainingLocalClass) { + if (FunctionContainingLocalClass) { Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class); // Per [basic.pre]p4, a template-id is not a name. Therefore, if we have diff --git a/clang/test/SemaCXX/gh185341.cpp b/clang/test/SemaCXX/gh185341.cpp new file mode 100644 index 0000000000000..d5de1331486e3 --- /dev/null +++ b/clang/test/SemaCXX/gh185341.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s + +template +struct D; + +template +void foo(D); + +template +struct D { + friend void ::foo(D) {} // expected-error {{friend function definition cannot be qualified with '::'}} +}; + +int main() { + foo(D{}); +}