diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -534,6 +534,9 @@ (`#62494 `_) - Fix handling of generic lambda used as template arguments. (`#62611 `_) +- Allow omitting ``typename`` in the parameter declaration of a friend + constructor declaration. + (`#63119 `_) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -5820,9 +5820,12 @@ // therefore, we know that this is a constructor. // Due to an ambiguity with implicit typename, the above is not enough. // Additionally, check to see if we are a friend. + // If we parsed a scope specifier as well as friend, + // we might be parsing a friend constructor. bool IsConstructor = false; - if (isDeclarationSpecifier(IsFriend ? ImplicitTypenameContext::No - : ImplicitTypenameContext::Yes)) + if (isDeclarationSpecifier(IsFriend && !SS.isSet() + ? ImplicitTypenameContext::No + : ImplicitTypenameContext::Yes)) IsConstructor = true; else if (Tok.is(tok::identifier) || (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) { diff --git a/clang/test/CXX/temp/temp.res/p4.cpp b/clang/test/CXX/temp/temp.res/p4.cpp --- a/clang/test/CXX/temp/temp.res/p4.cpp +++ b/clang/test/CXX/temp/temp.res/p4.cpp @@ -170,3 +170,18 @@ template C::C(T::type) {} + +namespace GH63119 { +struct X { + X(int); + X(auto); + void f(int); +}; +template struct S { + friend X::X(T::type); + friend X::X(T::type = (int)(void(*)(typename T::type))(nullptr)); // expected-error {{friend declaration specifying a default argument must be a definition}} + friend X::X(T::type = (int)(void(*)(T::type))(nullptr)); // expected-error {{friend declaration specifying a default argument must be a definition}} \ + // expected-error {{expected expression}} + friend void X::f(T::type); +}; +}