]> granicus.if.org Git - clang/commitdiff
PR31514: Add recursive self-instantiation check during template argument
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sun, 8 Jan 2017 22:45:21 +0000 (22:45 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sun, 8 Jan 2017 22:45:21 +0000 (22:45 +0000)
deduction in partial ordering.

This prevents us from crashing due to attempting to instantiate the same class
template specialization definition multiple times. (Debug builds also appear to
sometimes hit the stack limit before hitting the instantiation depth limit in
this case.)

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@291407 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaTemplateInstantiate.cpp
test/SemaTemplate/alias-templates.cpp
test/SemaTemplate/deduction.cpp

index 160c9f090788dbde942a03c24f87318f33aba276..ba4a5b7bc0d789cdee348107eb809b5e6ce5a5cb 100644 (file)
@@ -2280,16 +2280,18 @@ namespace {
   };
 }
 
-bool Sema::InstantiateClassTemplateSpecialization(
-    SourceLocation PointOfInstantiation,
+/// Get the instantiation pattern to use to instantiate the definition of a
+/// given ClassTemplateSpecializationDecl (either the pattern of the primary
+/// template or of a partial specialization).
+static CXXRecordDecl *
+getPatternForClassTemplateSpecialization(
+    Sema &S, SourceLocation PointOfInstantiation,
     ClassTemplateSpecializationDecl *ClassTemplateSpec,
     TemplateSpecializationKind TSK, bool Complain) {
-  // Perform the actual instantiation on the canonical declaration.
-  ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
-                                         ClassTemplateSpec->getCanonicalDecl());
-  if (ClassTemplateSpec->isInvalidDecl())
-    return true;
-  
+  Sema::InstantiatingTemplate Inst(S, PointOfInstantiation, ClassTemplateSpec);
+  if (Inst.isInvalid() || Inst.isAlreadyInstantiating())
+    return nullptr;
+
   ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
   CXXRecordDecl *Pattern = nullptr;
 
@@ -2309,15 +2311,13 @@ bool Sema::InstantiateClassTemplateSpecialization(
   for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
     ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
     TemplateDeductionInfo Info(FailedCandidates.getLocation());
-    if (TemplateDeductionResult Result
-          = DeduceTemplateArguments(Partial,
-                                    ClassTemplateSpec->getTemplateArgs(),
-                                    Info)) {
+    if (Sema::TemplateDeductionResult Result = S.DeduceTemplateArguments(
+            Partial, ClassTemplateSpec->getTemplateArgs(), Info)) {
       // Store the failed-deduction information for use in diagnostics, later.
       // TODO: Actually use the failed-deduction info?
       FailedCandidates.addCandidate().set(
           DeclAccessPair::make(Template, AS_public), Partial,
-          MakeDeductionFailureInfo(Context, Result, Info));
+          MakeDeductionFailureInfo(S.Context, Result, Info));
       (void)Result;
     } else {
       Matched.push_back(PartialSpecMatchResult());
@@ -2347,9 +2347,8 @@ bool Sema::InstantiateClassTemplateSpecialization(
       for (SmallVectorImpl<MatchResult>::iterator P = Best + 1,
                                                PEnd = Matched.end();
            P != PEnd; ++P) {
-        if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial,
-                                                    PointOfInstantiation) 
-              == P->Partial)
+        if (S.getMoreSpecializedPartialSpecialization(
+                P->Partial, Best->Partial, PointOfInstantiation) == P->Partial)
           Best = P;
       }
       
@@ -2360,9 +2359,9 @@ bool Sema::InstantiateClassTemplateSpecialization(
                                                PEnd = Matched.end();
            P != PEnd; ++P) {
         if (P != Best &&
-            getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial,
-                                                    PointOfInstantiation)
-              != Best->Partial) {
+            S.getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial,
+                                                      PointOfInstantiation) !=
+                Best->Partial) {
           Ambiguous = true;
           break;
         }
@@ -2370,20 +2369,20 @@ bool Sema::InstantiateClassTemplateSpecialization(
        
       if (Ambiguous) {
         // Partial ordering did not produce a clear winner. Complain.
+        Inst.Clear();
         ClassTemplateSpec->setInvalidDecl();
-        Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous)
+        S.Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous)
           << ClassTemplateSpec;
         
         // Print the matching partial specializations.
         for (SmallVectorImpl<MatchResult>::iterator P = Matched.begin(),
                                                  PEnd = Matched.end();
              P != PEnd; ++P)
-          Diag(P->Partial->getLocation(), diag::note_partial_spec_match)
-            << getTemplateArgumentBindingsText(
-                                            P->Partial->getTemplateParameters(),
-                                               *P->Args);
+          S.Diag(P->Partial->getLocation(), diag::note_partial_spec_match)
+            << S.getTemplateArgumentBindingsText(
+                   P->Partial->getTemplateParameters(), *P->Args);
 
-        return true;
+        return nullptr;
       }
     }
     
@@ -2416,13 +2415,27 @@ bool Sema::InstantiateClassTemplateSpecialization(
     Pattern = OrigTemplate->getTemplatedDecl();
   }
 
-  bool Result = InstantiateClass(PointOfInstantiation, ClassTemplateSpec, 
-                                 Pattern,
-                                getTemplateInstantiationArgs(ClassTemplateSpec),
-                                 TSK,
-                                 Complain);
+  return Pattern;
+}
 
-  return Result;
+bool Sema::InstantiateClassTemplateSpecialization(
+    SourceLocation PointOfInstantiation,
+    ClassTemplateSpecializationDecl *ClassTemplateSpec,
+    TemplateSpecializationKind TSK, bool Complain) {
+  // Perform the actual instantiation on the canonical declaration.
+  ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
+      ClassTemplateSpec->getCanonicalDecl());
+  if (ClassTemplateSpec->isInvalidDecl())
+    return true;
+
+  CXXRecordDecl *Pattern = getPatternForClassTemplateSpecialization(
+      *this, PointOfInstantiation, ClassTemplateSpec, TSK, Complain);
+  if (!Pattern)
+    return true;
+
+  return InstantiateClass(PointOfInstantiation, ClassTemplateSpec, Pattern,
+                          getTemplateInstantiationArgs(ClassTemplateSpec), TSK,
+                          Complain);
 }
 
 /// \brief Instantiates the definitions of all of the member
index bcdc84e19f7e74125af2dd7f7030b5b42536acbd..d70e86817849f82519301098697f0cf1d16ecbf9 100644 (file)
@@ -244,3 +244,13 @@ namespace redecl {
   template<typename = void> using A = int;
   A<> a; // ok
 }
+
+namespace PR31514 {
+  template<typename T, typename> using EnableTupleSize = T;
+
+  template<typename T> struct tuple_size { static const int value = 0; };
+  template<typename T> struct tuple_size<EnableTupleSize<const T, decltype(tuple_size<T>::value)>> {};
+  template<typename T> struct tuple_size<EnableTupleSize<volatile T, decltype(tuple_size<T>::value)>> {};
+
+  tuple_size<const int> t;
+}
index 2275a8b3b7ad2d8cc664adfb8b4da036effa8e5e..c25bf68b0621c23fffa94af916f8fce2179e3db3 100644 (file)
@@ -342,7 +342,7 @@ namespace deduction_substitution_failure {
 
   template<typename T, typename U> struct A {};
   template<typename T> struct A<T, typename Fail<T>::error> {}; // expected-note {{instantiation of}}
-  A<int, int> ai; // expected-note {{during template argument deduction for class template partial specialization 'A<T, typename Fail<T>::error>' [with T = int]}}
+  A<int, int> ai; // expected-note {{during template argument deduction for class template partial specialization 'A<T, typename Fail<T>::error>' [with T = int]}} expected-note {{in instantiation of template class 'deduction_substitution_failure::A<int, int>'}}
 
   template<typename T, typename U> int B; // expected-warning 0-1 {{extension}}
   template<typename T> int B<T, typename Fail<T>::error> {}; // expected-note {{instantiation of}}