From: Richard Smith Date: Sun, 8 Jan 2017 22:45:21 +0000 (+0000) Subject: PR31514: Add recursive self-instantiation check during template argument X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=64f15d6d009732951aa9c549c52fa67a03ae13b7;p=clang PR31514: Add recursive self-instantiation check during template argument 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 --- diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 160c9f0907..ba4a5b7bc0 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -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( - 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::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::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( + 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 diff --git a/test/SemaTemplate/alias-templates.cpp b/test/SemaTemplate/alias-templates.cpp index bcdc84e19f..d70e868178 100644 --- a/test/SemaTemplate/alias-templates.cpp +++ b/test/SemaTemplate/alias-templates.cpp @@ -244,3 +244,13 @@ namespace redecl { template using A = int; A<> a; // ok } + +namespace PR31514 { + template using EnableTupleSize = T; + + template struct tuple_size { static const int value = 0; }; + template struct tuple_size::value)>> {}; + template struct tuple_size::value)>> {}; + + tuple_size t; +} diff --git a/test/SemaTemplate/deduction.cpp b/test/SemaTemplate/deduction.cpp index 2275a8b3b7..c25bf68b06 100644 --- a/test/SemaTemplate/deduction.cpp +++ b/test/SemaTemplate/deduction.cpp @@ -342,7 +342,7 @@ namespace deduction_substitution_failure { template struct A {}; template struct A::error> {}; // expected-note {{instantiation of}} - A ai; // expected-note {{during template argument deduction for class template partial specialization 'A::error>' [with T = int]}} + A ai; // expected-note {{during template argument deduction for class template partial specialization 'A::error>' [with T = int]}} expected-note {{in instantiation of template class 'deduction_substitution_failure::A'}} template int B; // expected-warning 0-1 {{extension}} template int B::error> {}; // expected-note {{instantiation of}}