// Template Instantiation Support
//===----------------------------------------------------------------------===/
+namespace {
+namespace TemplateInstArgsHelpers {
+struct Response {
+ const Decl *NextDecl = nullptr;
+ bool IsDone = false;
+ bool ClearRelativeToPrimary = true;
+ static Response Done() {
+ Response R;
+ R.IsDone = true;
+ return R;
+ }
+ static Response ChangeDecl(const Decl *ND) {
+ Response R;
+ R.NextDecl = ND;
+ return R;
+ }
+ static Response ChangeDecl(const DeclContext *Ctx) {
+ Response R;
+ R.NextDecl = Decl::castFromDeclContext(Ctx);
+ return R;
+ }
+
+ static Response UseNextDecl(const Decl *CurDecl) {
+ return ChangeDecl(CurDecl->getDeclContext());
+ }
+
+ static Response DontClearRelativeToPrimaryNextDecl(const Decl *CurDecl) {
+ Response R = Response::UseNextDecl(CurDecl);
+ R.ClearRelativeToPrimary = false;
+ return R;
+ }
+};
+// Add template arguments from a variable template instantiation.
+Response
+HandleVarTemplateSpec(const VarTemplateSpecializationDecl *VarTemplSpec,
+ MultiLevelTemplateArgumentList &Result) {
+ // For a class-scope explicit specialization, there are no template arguments
+ // at this level, but there may be enclosing template arguments.
+ if (VarTemplSpec->isClassScopeExplicitSpecialization())
+ return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec);
+
+ // We're done when we hit an explicit specialization.
+ if (VarTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization &&
+ !isa<VarTemplatePartialSpecializationDecl>(VarTemplSpec))
+ return Response::Done();
+
+ Result.addOuterTemplateArguments(
+ &VarTemplSpec->getTemplateInstantiationArgs());
+
+ // If this variable template specialization was instantiated from a
+ // specialized member that is a variable template, we're done.
+ assert(VarTemplSpec->getSpecializedTemplate() && "No variable template?");
+ llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
+ Specialized = VarTemplSpec->getSpecializedTemplateOrPartial();
+ if (VarTemplatePartialSpecializationDecl *Partial =
+ Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
+ if (Partial->isMemberSpecialization())
+ return Response::Done();
+ } else {
+ VarTemplateDecl *Tmpl = Specialized.get<VarTemplateDecl *>();
+ if (Tmpl->isMemberSpecialization())
+ return Response::Done();
+ }
+ return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec);
+}
+
+// If we have a template template parameter with translation unit context,
+// then we're performing substitution into a default template argument of
+// this template template parameter before we've constructed the template
+// that will own this template template parameter. In this case, we
+// use empty template parameter lists for all of the outer templates
+// to avoid performing any substitutions.
+Response
+HandleDefaultTempArgIntoTempTempParam(const TemplateTemplateParmDecl *TTP,
+ MultiLevelTemplateArgumentList &Result) {
+ for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I)
+ Result.addOuterTemplateArguments(None);
+ return Response::Done();
+}
+
+// Add template arguments from a class template instantiation.
+Response
+HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec,
+ MultiLevelTemplateArgumentList &Result) {
+ if (!ClassTemplSpec->isClassScopeExplicitSpecialization()) {
+ // We're done when we hit an explicit specialization.
+ if (ClassTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization &&
+ !isa<ClassTemplatePartialSpecializationDecl>(ClassTemplSpec))
+ return Response::Done();
+
+ Result.addOuterTemplateArguments(
+ &ClassTemplSpec->getTemplateInstantiationArgs());
+
+ // If this class template specialization was instantiated from a
+ // specialized member that is a class template, we're done.
+ assert(ClassTemplSpec->getSpecializedTemplate() && "No class template?");
+ if (ClassTemplSpec->getSpecializedTemplate()->isMemberSpecialization())
+ return Response::Done();
+ }
+ return Response::UseNextDecl(ClassTemplSpec);
+}
+
+Response HandleFunction(const FunctionDecl *Function,
+ MultiLevelTemplateArgumentList &Result,
+ const FunctionDecl *Pattern, bool RelativeToPrimary,
+ bool ForConstraintInstantiation) {
+ // Add template arguments from a function template specialization.
+ if (!RelativeToPrimary &&
+ Function->getTemplateSpecializationKindForInstantiation() ==
+ TSK_ExplicitSpecialization)
+ return Response::Done();
+
+ if (!RelativeToPrimary &&
+ Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
+ // This is an implicit instantiation of an explicit specialization. We
+ // don't get any template arguments from this function but might get
+ // some from an enclosing template.
+ return Response::UseNextDecl(Function);
+ } else if (const TemplateArgumentList *TemplateArgs =
+ Function->getTemplateSpecializationArgs()) {
+ // Add the template arguments for this specialization.
+ Result.addOuterTemplateArguments(TemplateArgs);
+
+ // If this function was instantiated from a specialized member that is
+ // a function template, we're done.
+ assert(Function->getPrimaryTemplate() && "No function template?");
+ if (Function->getPrimaryTemplate()->isMemberSpecialization())
+ return Response::Done();
+
+ // If this function is a generic lambda specialization, we are done.
+ if (!ForConstraintInstantiation &&
+ isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
+ return Response::Done();
+
+ } else if (Function->getDescribedFunctionTemplate()) {
+ assert(
+ (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+ "Outer template not instantiated?");
+ }
+ // If this is a friend declaration and it declares an entity at
+ // namespace scope, take arguments from its lexical parent
+ // instead of its semantic parent, unless of course the pattern we're
+ // instantiating actually comes from the file's context!
+ if (Function->getFriendObjectKind() &&
+ Function->getNonTransparentDeclContext()->isFileContext() &&
+ (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) {
+ return Response::ChangeDecl(Function->getLexicalDeclContext());
+ }
+ return Response::UseNextDecl(Function);
+}
+
+Response HandleRecordDecl(const CXXRecordDecl *Rec,
+ MultiLevelTemplateArgumentList &Result,
+ ASTContext &Context,
+ bool ForConstraintInstantiation) {
+ if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) {
+ assert(
+ (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+ "Outer template not instantiated?");
+ if (ClassTemplate->isMemberSpecialization())
+ return Response::Done();
+ if (ForConstraintInstantiation) {
+ QualType RecordType = Context.getTypeDeclType(Rec);
+ QualType Injected = cast<InjectedClassNameType>(RecordType)
+ ->getInjectedSpecializationType();
+ const auto *InjectedType = cast<TemplateSpecializationType>(Injected);
+ Result.addOuterTemplateArguments(InjectedType->template_arguments());
+ }
+ }
+
+ bool IsFriend = Rec->getFriendObjectKind() ||
+ (Rec->getDescribedClassTemplate() &&
+ Rec->getDescribedClassTemplate()->getFriendObjectKind());
+ if (ForConstraintInstantiation && IsFriend &&
+ Rec->getNonTransparentDeclContext()->isFileContext()) {
+ return Response::ChangeDecl(Rec->getLexicalDeclContext());
+ }
+
+ // This is to make sure we pick up the VarTemplateSpecializationDecl that this
+ // lambda is defined inside of.
+ if (Rec->isLambda())
+ if (const Decl *LCD = Rec->getLambdaContextDecl())
+ return Response::ChangeDecl(LCD);
+
+ return Response::UseNextDecl(Rec);
+}
+
+Response HandleGenericDeclContext(const Decl *CurDecl) {
+ return Response::UseNextDecl(CurDecl);
+}
+} // namespace TemplateInstArgsHelpers
+} // namespace
+
/// Retrieve the template argument list(s) that should be used to
/// instantiate the definition of the given declaration.
///
-/// \param D the declaration for which we are computing template instantiation
+/// \param ND the declaration for which we are computing template instantiation
/// arguments.
///
-/// \param Innermost if non-NULL, the innermost template argument list.
+/// \param Innermost if non-NULL, specifies a template argument list for the
+/// template declaration passed as ND.
///
/// \param RelativeToPrimary true if we should get the template
/// arguments relative to the primary template, even when we're
/// template specializations.
///
/// \param Pattern If non-NULL, indicates the pattern from which we will be
-/// instantiating the definition of the given declaration, \p D. This is
+/// instantiating the definition of the given declaration, \p ND. This is
/// used to determine the proper set of template instantiation arguments for
/// friend function template specializations.
///
-/// \param LookBeyondLambda Indicates that this collection of arguments should
-/// continue looking when it encounters a lambda generic call operator.
-///
-/// \param IncludeContainingStructArgs Indicates that this collection of
-/// arguments should include arguments for any class template that this
-/// declaration is included inside of.
+/// \param ForConstraintInstantiation when collecting arguments,
+/// ForConstraintInstantiation indicates we should continue looking when
+/// encountering a lambda generic call operator, and continue looking for
+/// arguments on an enclosing class template.
MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
- const NamedDecl *D, const TemplateArgumentList *Innermost,
- bool RelativeToPrimary, const FunctionDecl *Pattern, bool LookBeyondLambda,
- bool IncludeContainingStructArgs) {
+ const NamedDecl *ND, const TemplateArgumentList *Innermost,
+ bool RelativeToPrimary, const FunctionDecl *Pattern,
+ bool ForConstraintInstantiation) {
+ assert(ND && "Can't find arguments for a decl if one isn't provided");
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
if (Innermost)
Result.addOuterTemplateArguments(Innermost);
- const auto *Ctx = dyn_cast<DeclContext>(D);
- if (!Ctx) {
- Ctx = D->getDeclContext();
-
- // Add template arguments from a variable template instantiation. For a
- // class-scope explicit specialization, there are no template arguments
- // at this level, but there may be enclosing template arguments.
- const auto *Spec = dyn_cast<VarTemplateSpecializationDecl>(D);
- if (Spec && !Spec->isClassScopeExplicitSpecialization()) {
- // We're done when we hit an explicit specialization.
- if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization &&
- !isa<VarTemplatePartialSpecializationDecl>(Spec))
- return Result;
-
- Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs());
-
- // If this variable template specialization was instantiated from a
- // specialized member that is a variable template, we're done.
- assert(Spec->getSpecializedTemplate() && "No variable template?");
- llvm::PointerUnion<VarTemplateDecl*,
- VarTemplatePartialSpecializationDecl*> Specialized
- = Spec->getSpecializedTemplateOrPartial();
- if (VarTemplatePartialSpecializationDecl *Partial =
- Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
- if (Partial->isMemberSpecialization())
- return Result;
- } else {
- VarTemplateDecl *Tmpl = Specialized.get<VarTemplateDecl *>();
- if (Tmpl->isMemberSpecialization())
- return Result;
- }
- }
-
- // If we have a template template parameter with translation unit context,
- // then we're performing substitution into a default template argument of
- // this template template parameter before we've constructed the template
- // that will own this template template parameter. In this case, we
- // use empty template parameter lists for all of the outer templates
- // to avoid performing any substitutions.
- if (Ctx->isTranslationUnit()) {
- if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
- for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I)
- Result.addOuterTemplateArguments(None);
- return Result;
- }
- }
- }
-
- while (!Ctx->isFileContext()) {
- // Add template arguments from a class template instantiation.
- const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Ctx);
- if (Spec && !Spec->isClassScopeExplicitSpecialization()) {
- // We're done when we hit an explicit specialization.
- if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization &&
- !isa<ClassTemplatePartialSpecializationDecl>(Spec))
- break;
-
- Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs());
-
- // If this class template specialization was instantiated from a
- // specialized member that is a class template, we're done.
- assert(Spec->getSpecializedTemplate() && "No class template?");
- if (Spec->getSpecializedTemplate()->isMemberSpecialization())
- break;
- }
- // Add template arguments from a function template specialization.
- else if (const auto *Function = dyn_cast<FunctionDecl>(Ctx)) {
- if (!RelativeToPrimary &&
- Function->getTemplateSpecializationKindForInstantiation() ==
- TSK_ExplicitSpecialization)
- break;
-
- if (!RelativeToPrimary && Function->getTemplateSpecializationKind() ==
- TSK_ExplicitSpecialization) {
- // This is an implicit instantiation of an explicit specialization. We
- // don't get any template arguments from this function but might get
- // some from an enclosing template.
- } else if (const TemplateArgumentList *TemplateArgs
- = Function->getTemplateSpecializationArgs()) {
- // Add the template arguments for this specialization.
- Result.addOuterTemplateArguments(TemplateArgs);
-
- // If this function was instantiated from a specialized member that is
- // a function template, we're done.
- assert(Function->getPrimaryTemplate() && "No function template?");
- if (Function->getPrimaryTemplate()->isMemberSpecialization())
- break;
-
- // If this function is a generic lambda specialization, we are done.
- if (!LookBeyondLambda &&
- isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
- break;
-
- } else if (Function->getDescribedFunctionTemplate()) {
- assert((IncludeContainingStructArgs ||
- Result.getNumSubstitutedLevels() == 0) &&
- "Outer template not instantiated?");
- }
-
- // If this is a friend declaration and it declares an entity at
- // namespace scope, take arguments from its lexical parent
- // instead of its semantic parent, unless of course the pattern we're
- // instantiating actually comes from the file's context!
- if (Function->getFriendObjectKind() &&
- Function->getNonTransparentDeclContext()->isFileContext() &&
- (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) {
- Ctx = Function->getLexicalDeclContext();
- RelativeToPrimary = false;
- continue;
- }
- } else if (const auto *Rec = dyn_cast<CXXRecordDecl>(Ctx)) {
- if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) {
- assert((IncludeContainingStructArgs ||
- Result.getNumSubstitutedLevels() == 0) &&
- "Outer template not instantiated?");
- if (ClassTemplate->isMemberSpecialization())
- break;
- if (IncludeContainingStructArgs) {
- QualType RecordType = Context.getTypeDeclType(Rec);
- QualType Injected = cast<InjectedClassNameType>(RecordType)
- ->getInjectedSpecializationType();
- const auto *InjectedType = cast<TemplateSpecializationType>(Injected);
- Result.addOuterTemplateArguments(InjectedType->template_arguments());
+ const Decl *CurDecl = ND;
+
+ while (!CurDecl->isFileContextDecl()) {
+ using namespace TemplateInstArgsHelpers;
+ Response R;
+ if (const auto *VarTemplSpec =
+ dyn_cast<VarTemplateSpecializationDecl>(CurDecl)) {
+ R = HandleVarTemplateSpec(VarTemplSpec, Result);
+ } else if (const auto *ClassTemplSpec =
+ dyn_cast<ClassTemplateSpecializationDecl>(CurDecl)) {
+ R = HandleClassTemplateSpec(ClassTemplSpec, Result);
+ } else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) {
+ R = HandleFunction(Function, Result, Pattern, RelativeToPrimary,
+ ForConstraintInstantiation);
+ } else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) {
+ R = HandleRecordDecl(Rec, Result, Context, ForConstraintInstantiation);
+ } else if (!isa<DeclContext>(CurDecl)) {
+ R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl);
+ if (CurDecl->getDeclContext()->isTranslationUnit()) {
+ if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) {
+ R = HandleDefaultTempArgIntoTempTempParam(TTP, Result);
}
}
- bool IsFriend = Rec->getFriendObjectKind() ||
- (Rec->getDescribedClassTemplate() &&
- Rec->getDescribedClassTemplate()->getFriendObjectKind());
- if (IncludeContainingStructArgs && IsFriend &&
- Rec->getNonTransparentDeclContext()->isFileContext() &&
- (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) {
- Ctx = Rec->getLexicalDeclContext();
- RelativeToPrimary = false;
- continue;
- }
+ } else {
+ R = HandleGenericDeclContext(CurDecl);
}
- Ctx = Ctx->getParent();
- RelativeToPrimary = false;
+ if (R.IsDone)
+ return Result;
+ if (R.ClearRelativeToPrimary)
+ RelativeToPrimary = false;
+ assert(R.NextDecl);
+ CurDecl = R.NextDecl;
}
return Result;