From: John McCall Date: Wed, 7 Jun 2017 23:00:05 +0000 (+0000) Subject: When determining the target function of an explicit instantiation, make X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ce43b3d0fc30e1d4dc015dfba0bd44bb4c0a20e0;p=clang When determining the target function of an explicit instantiation, make sure that non-template functions don't end up in the candidate set. Fixes PR14211. Patch by Don Hinton! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@304951 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 7e5e2a1862..341e0abc1c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -8957,7 +8957,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // A member function [...] of a class template can be explicitly // instantiated from the member definition associated with its class // template. - UnresolvedSet<8> Matches; + UnresolvedSet<8> TemplateMatches; + FunctionDecl *NonTemplateMatch = nullptr; AttributeList *Attr = D.getDeclSpec().getAttributes().getList(); TemplateSpecCandidateSet FailedCandidates(D.getIdentifierLoc()); for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); @@ -8968,11 +8969,13 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, QualType Adjusted = adjustCCAndNoReturn(R, Method->getType(), /*AdjustExceptionSpec*/true); if (Context.hasSameUnqualifiedType(Method->getType(), Adjusted)) { - Matches.clear(); - - Matches.addDecl(Method, P.getAccess()); - if (Method->getTemplateSpecializationKind() == TSK_Undeclared) - break; + if (Method->getPrimaryTemplate()) { + TemplateMatches.addDecl(Method, P.getAccess()); + } else { + // FIXME: Can this assert ever happen? Needs a test. + assert(!NonTemplateMatch && "Multiple NonTemplateMatches"); + NonTemplateMatch = Method; + } } } } @@ -9011,22 +9014,25 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, continue; } - Matches.addDecl(Specialization, P.getAccess()); + TemplateMatches.addDecl(Specialization, P.getAccess()); } - // Find the most specialized function template specialization. - UnresolvedSetIterator Result = getMostSpecialized( - Matches.begin(), Matches.end(), FailedCandidates, - D.getIdentifierLoc(), - PDiag(diag::err_explicit_instantiation_not_known) << Name, - PDiag(diag::err_explicit_instantiation_ambiguous) << Name, - PDiag(diag::note_explicit_instantiation_candidate)); - - if (Result == Matches.end()) - return true; + FunctionDecl *Specialization = NonTemplateMatch; + if (!Specialization) { + // Find the most specialized function template specialization. + UnresolvedSetIterator Result = getMostSpecialized( + TemplateMatches.begin(), TemplateMatches.end(), FailedCandidates, + D.getIdentifierLoc(), + PDiag(diag::err_explicit_instantiation_not_known) << Name, + PDiag(diag::err_explicit_instantiation_ambiguous) << Name, + PDiag(diag::note_explicit_instantiation_candidate)); + + if (Result == TemplateMatches.end()) + return true; - // Ignore access control bits, we don't need them for redeclaration checking. - FunctionDecl *Specialization = cast(*Result); + // Ignore access control bits, we don't need them for redeclaration checking. + Specialization = cast(*Result); + } // C++11 [except.spec]p4 // In an explicit instantiation an exception-specification may be specified, diff --git a/test/CXX/temp/temp.decls/temp.mem/p5.cpp b/test/CXX/temp/temp.decls/temp.mem/p5.cpp index 1e061fa33d..a41ea6b5e1 100644 --- a/test/CXX/temp/temp.decls/temp.mem/p5.cpp +++ b/test/CXX/temp/temp.decls/temp.mem/p5.cpp @@ -77,3 +77,16 @@ void test_X0(X0 x0, const X0 &x0c) { x0.operator float *(); x0c.operator const char*(); } + +namespace PR14211 { +template struct X { + void foo(U){} + template void foo(T){} + + template void bar(T){} + void bar(U){} +}; + +template void X::foo(int); +template void X::bar(int); +}