diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -86,6 +86,26 @@ /// The kind of substitution described by this argument list. TemplateSubstitutionKind Kind = TemplateSubstitutionKind::Specialization; + mutable bool EarlySubstitution = false; + + class SubstitutionRAII { + bool *EarlySubstitution, OldEarlySubstitution; + friend class MultiLevelTemplateArgumentList; + + SubstitutionRAII(bool &EarlySubstitution, bool NewEarlySubstitution) + : EarlySubstitution(&EarlySubstitution), + OldEarlySubstitution( + std::exchange(EarlySubstitution, NewEarlySubstitution)) {} + + public: + SubstitutionRAII(SubstitutionRAII &&other) + : EarlySubstitution(std::exchange(other.EarlySubstitution, + &other.OldEarlySubstitution)), + OldEarlySubstitution(other.OldEarlySubstitution) {} + SubstitutionRAII(const SubstitutionRAII &) = delete; + SubstitutionRAII &operator=(const SubstitutionRAII &) = delete; + ~SubstitutionRAII() { *EarlySubstitution = OldEarlySubstitution; } + }; public: /// Construct an empty set of template argument lists. @@ -128,11 +148,8 @@ /// Determine how many of the \p OldDepth outermost template parameter /// lists would be removed by substituting these arguments. unsigned getNewDepth(unsigned OldDepth) const { - if (OldDepth < NumRetainedOuterLevels) - return OldDepth; - if (OldDepth < getNumLevels()) - return NumRetainedOuterLevels; - return OldDepth - TemplateArgumentLists.size(); + return EarlySubstitution ? OldDepth + : OldDepth - getNumSubstitutedLevels(); } /// Retrieve the template argument at a given depth and index. @@ -197,6 +214,16 @@ const ArgList &getInnermost() const { return TemplateArgumentLists.front(); } + + /// Get a scope object to perform early substitution. + SubstitutionRAII getEarlySubstitutionRAII() const { + return SubstitutionRAII(EarlySubstitution, true); + } + + /// Get a scope object to perform late substitution. + SubstitutionRAII getLateSubstitutionRAII() const { + return SubstitutionRAII(EarlySubstitution, false); + } }; /// The context in which partial ordering of function templates occurs. diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -959,8 +959,12 @@ this->Entity = Entity; } - unsigned TransformTemplateDepth(unsigned Depth) { - return TemplateArgs.getNewDepth(Depth); + unsigned TransformTemplateDepth(unsigned OldDepth) { + if (OldDepth < TemplateArgs.getNumRetainedOuterLevels()) + return OldDepth; + if (OldDepth < TemplateArgs.getNumLevels()) + return TemplateArgs.getNumRetainedOuterLevels(); + return OldDepth - TemplateArgs.getNumSubstitutedLevels(); } bool TryExpandParameterPacks(SourceLocation EllipsisLoc, @@ -1854,7 +1858,7 @@ TransformDecl(TL.getNameLoc(), OldTTPDecl)); QualType Result = getSema().Context.getTemplateTypeParmType( - T->getDepth() - TemplateArgs.getNumSubstitutedLevels(), T->getIndex(), + TemplateArgs.getNewDepth(T->getDepth()), T->getIndex(), T->isParameterPack(), NewTTPDecl); TemplateTypeParmTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1029,8 +1029,9 @@ // will contain the instantiations of the template parameters. LocalInstantiationScope Scope(SemaRef); - TemplateParameterList *TempParams = D->getTemplateParameters(); - TemplateParameterList *InstParams = SubstTemplateParams(TempParams); + auto EarlySubstitutionScope = TemplateArgs.getEarlySubstitutionRAII(); + TemplateParameterList *InstParams = + SubstTemplateParams(D->getTemplateParameters()); if (!InstParams) return nullptr; @@ -2757,7 +2758,7 @@ TemplateTypeParmDecl *Inst = TemplateTypeParmDecl::Create( SemaRef.Context, Owner, D->getBeginLoc(), D->getLocation(), - D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getIndex(), + TemplateArgs.getNewDepth(D->getDepth()), D->getIndex(), D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack(), D->hasTypeConstraint(), NumExpanded); @@ -2910,14 +2911,14 @@ if (IsExpandedParameterPack) Param = NonTypeTemplateParmDecl::Create( SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), - D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), - D->getPosition(), D->getIdentifier(), T, DI, ExpandedParameterPackTypes, + TemplateArgs.getNewDepth(D->getDepth()), D->getPosition(), + D->getIdentifier(), T, DI, ExpandedParameterPackTypes, ExpandedParameterPackTypesAsWritten); else Param = NonTypeTemplateParmDecl::Create( SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), - D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), - D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI); + TemplateArgs.getNewDepth(D->getDepth()), D->getPosition(), + D->getIdentifier(), T, D->isParameterPack(), DI); if (AutoTypeLoc AutoLoc = DI->getTypeLoc().getContainedAutoTypeLoc()) if (AutoLoc.isConstrained()) @@ -3051,13 +3052,13 @@ if (IsExpandedParameterPack) Param = TemplateTemplateParmDecl::Create( SemaRef.Context, Owner, D->getLocation(), - D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), - D->getPosition(), D->getIdentifier(), InstParams, ExpandedParams); + TemplateArgs.getNewDepth(D->getDepth()), D->getPosition(), + D->getIdentifier(), InstParams, ExpandedParams); else Param = TemplateTemplateParmDecl::Create( SemaRef.Context, Owner, D->getLocation(), - D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), - D->getPosition(), D->isParameterPack(), D->getIdentifier(), InstParams); + TemplateArgs.getNewDepth(D->getDepth()), D->getPosition(), + D->isParameterPack(), D->getIdentifier(), InstParams); if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { NestedNameSpecifierLoc QualifierLoc = D->getDefaultArgument().getTemplateQualifierLoc(); @@ -4021,6 +4022,7 @@ if (Expr *E = L->getRequiresClause()) { EnterExpressionEvaluationContext ConstantEvaluated( SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); + auto LateSubstitutionScope = TemplateArgs.getLateSubstitutionRAII(); ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs); if (Res.isInvalid() || !Res.isUsable()) { return nullptr; diff --git a/clang/test/AST/ast-dump-template-decls.cpp b/clang/test/AST/ast-dump-template-decls.cpp --- a/clang/test/AST/ast-dump-template-decls.cpp +++ b/clang/test/AST/ast-dump-template-decls.cpp @@ -121,7 +121,7 @@ // CHECK-NEXT: BuiltinType 0x{{[^ ]*}} 'void' // CHECK-NEXT: FunctionProtoType 0x{{[^ ]*}} 'void (int)' cdecl // CHECK-NEXT: SubstTemplateTypeParmType 0x{{[^ ]*}} 'void' sugar -// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'U' dependent depth 0 index 0 +// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'U' dependent depth 1 index 0 // CHECK-NEXT: TemplateTypeParm 0x{{[^ ]*}} 'U' // CHECK-NEXT: BuiltinType 0x{{[^ ]*}} 'void' // CHECK-NEXT: SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar