]> granicus.if.org Git - clang/commitdiff
When determining the target function of an explicit instantiation, make
authorJohn McCall <rjmccall@apple.com>
Wed, 7 Jun 2017 23:00:05 +0000 (23:00 +0000)
committerJohn McCall <rjmccall@apple.com>
Wed, 7 Jun 2017 23:00:05 +0000 (23:00 +0000)
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

lib/Sema/SemaTemplate.cpp
test/CXX/temp/temp.decls/temp.mem/p5.cpp

index 7e5e2a1862a12a1b5a5a140efa252c52e2d2117e..341e0abc1c34f32296658652f4c36e21115b26e3 100644 (file)
@@ -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<FunctionDecl>(*Result);
+    // Ignore access control bits, we don't need them for redeclaration checking.
+    Specialization = cast<FunctionDecl>(*Result);
+  }
 
   // C++11 [except.spec]p4
   // In an explicit instantiation an exception-specification may be specified,
index 1e061fa33d3a45d1b0507220279752342667c8cd..a41ea6b5e109ed9a6d5af0f1fefa61cfe40accb8 100644 (file)
@@ -77,3 +77,16 @@ void test_X0(X0 x0, const X0 &x0c) {
   x0.operator float *();
   x0c.operator const char*();
 }
+
+namespace PR14211 {
+template <class U> struct X {
+  void foo(U){}
+  template <class T> void foo(T){}
+
+  template <class T> void bar(T){}
+  void bar(U){}
+};
+
+template void X<int>::foo(int);
+template void X<int>::bar(int);
+}