diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 2efb7acb9724..baec13ba627c 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2053,6 +2053,13 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( // typedef (C++ [dcl.typedef]p4). if (Previous.isSingleTagDecl()) Previous.clear(); + + // Filter out previous declarations that don't match the scope. The only + // effect this has is to remove declarations found in inline namespaces + // for friend declarations with unqualified names. + SemaRef.FilterLookupForScope(Previous, DC, /*Scope*/ nullptr, + /*ConsiderLinkage*/ true, + QualifierLoc.hasQualifier()); } SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous, diff --git a/clang/test/SemaTemplate/friend.cpp b/clang/test/SemaTemplate/friend.cpp index 777682be3f1b..283c7732ccff 100644 --- a/clang/test/SemaTemplate/friend.cpp +++ b/clang/test/SemaTemplate/friend.cpp @@ -122,3 +122,22 @@ namespace qualified_friend_finds_nothing { namespace N { void f(int); } B bi; // ok?! } + +namespace PR37556 { + inline namespace N { int x1, x2, y1, y2; } // expected-note 2{{previous}} + struct X { + friend void x1(int); + friend void PR37556::x2(int); // expected-error {{different kind}} + }; + template struct Y { + friend void y1(T); + friend void PR37556::y2(T); // expected-error {{different kind}} + }; + template struct Y; + template struct Z { + friend void z1(T); + friend void PR37556::z2(T); // expected-error {{does not match any}} + }; + inline namespace N { int z1, z2; } + template struct Z; +}