[clang] [Clang][Sema] Refactor collection of multi-level template argument lists (PR #106585)
Younan Zhang via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 29 18:59:06 PDT 2024
================
@@ -171,374 +139,379 @@ bool isLambdaEnclosedByTypeAliasDecl(
.TraverseType(Underlying);
}
-// Add template arguments from a variable template instantiation.
-Response
-HandleVarTemplateSpec(const VarTemplateSpecializationDecl *VarTemplSpec,
- MultiLevelTemplateArgumentList &Result,
- bool SkipForSpecialization) {
- // 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();
-
- // 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 (!SkipForSpecialization)
- Result.addOuterTemplateArguments(
- Partial, VarTemplSpec->getTemplateInstantiationArgs().asArray(),
- /*Final=*/false);
- if (Partial->isMemberSpecialization())
- return Response::Done();
- } else {
- VarTemplateDecl *Tmpl = Specialized.get<VarTemplateDecl *>();
- if (!SkipForSpecialization)
- Result.addOuterTemplateArguments(
- Tmpl, VarTemplSpec->getTemplateInstantiationArgs().asArray(),
- /*Final=*/false);
- if (Tmpl->isMemberSpecialization())
- return Response::Done();
+struct TemplateInstantiationArgumentCollecter
+ : DeclVisitor<TemplateInstantiationArgumentCollecter, Decl *> {
+ Sema &S;
+ MultiLevelTemplateArgumentList &Result;
+ std::optional<ArrayRef<TemplateArgument>> Innermost;
+ bool RelativeToPrimary;
+ bool ForConstraintInstantiation;
+
+ TemplateInstantiationArgumentCollecter(
+ Sema &S, MultiLevelTemplateArgumentList &Result,
+ std::optional<ArrayRef<TemplateArgument>> Innermost,
+ bool RelativeToPrimary, bool ForConstraintInstantiation)
+ : S(S), Result(Result), Innermost(Innermost),
+ RelativeToPrimary(RelativeToPrimary),
+ ForConstraintInstantiation(ForConstraintInstantiation) {}
+
+ Decl *Done() { return nullptr; }
+
+ Decl *ChangeDecl(const Decl *D) {
+ RelativeToPrimary = false;
+ return const_cast<Decl *>(D);
}
- 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(std::nullopt);
- return Response::Done();
-}
+ Decl *ChangeDecl(const DeclContext *DC) {
+ return ChangeDecl(Decl::castFromDeclContext(DC));
+ }
-Response HandlePartialClassTemplateSpec(
- const ClassTemplatePartialSpecializationDecl *PartialClassTemplSpec,
- MultiLevelTemplateArgumentList &Result, bool SkipForSpecialization) {
- if (!SkipForSpecialization)
- Result.addOuterRetainedLevels(PartialClassTemplSpec->getTemplateDepth());
- return Response::Done();
-}
+ Decl *UseNextDecl(const Decl *D) { return ChangeDecl(D->getDeclContext()); }
-// Add template arguments from a class template instantiation.
-Response
-HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec,
- MultiLevelTemplateArgumentList &Result,
- bool SkipForSpecialization) {
- if (!ClassTemplSpec->isClassScopeExplicitSpecialization()) {
- // We're done when we hit an explicit specialization.
- if (ClassTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization &&
- !isa<ClassTemplatePartialSpecializationDecl>(ClassTemplSpec))
- return Response::Done();
+ Decl *DontClearRelativeToPrimaryNextDecl(const Decl *D) {
+ return const_cast<Decl *>(Decl::castFromDeclContext(D->getDeclContext()));
+ }
- if (!SkipForSpecialization)
- Result.addOuterTemplateArguments(
- const_cast<ClassTemplateSpecializationDecl *>(ClassTemplSpec),
- ClassTemplSpec->getTemplateInstantiationArgs().asArray(),
- /*Final=*/false);
+ void AddInnermostTemplateArguments(const Decl *D) {
+ assert(Innermost);
+ Result.addOuterTemplateArguments(const_cast<Decl *>(D), *Innermost,
+ /*Final=*/false);
+ Innermost.reset();
+ }
- // 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();
-
- // If this was instantiated from a partial template specialization, we need
- // to get the next level of declaration context from the partial
- // specialization, as the ClassTemplateSpecializationDecl's
- // DeclContext/LexicalDeclContext will be for the primary template.
- if (auto *InstFromPartialTempl = ClassTemplSpec->getSpecializedTemplateOrPartial()
- .dyn_cast<ClassTemplatePartialSpecializationDecl *>())
- return Response::ChangeDecl(InstFromPartialTempl->getLexicalDeclContext());
+ void AddOuterTemplateArguments(const Decl *D, ArrayRef<TemplateArgument> Args,
+ bool Final) {
+ Result.addOuterTemplateArguments(const_cast<Decl *>(D), Args, Final);
}
- return Response::UseNextDecl(ClassTemplSpec);
-}
-Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
- MultiLevelTemplateArgumentList &Result,
- const FunctionDecl *Pattern, bool RelativeToPrimary,
- bool ForConstraintInstantiation,
- bool ForDefaultArgumentSubstitution) {
- // 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(const_cast<FunctionDecl *>(Function),
- TemplateArgs->asArray(),
- /*Final=*/false);
+ Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTPD) {
+ if (Innermost)
+ AddInnermostTemplateArguments(TTPD);
+ else if (ForConstraintInstantiation)
+ AddOuterTemplateArguments(nullptr, std::nullopt, /*Final=*/false);
- if (RelativeToPrimary &&
- (Function->getTemplateSpecializationKind() ==
- TSK_ExplicitSpecialization ||
- (Function->getFriendObjectKind() &&
- !Function->getPrimaryTemplate()->getFriendObjectKind())))
- return Response::UseNextDecl(Function);
-
- // If this function was instantiated from a specialized member that is
- // a function template, we're done.
- assert(Function->getPrimaryTemplate() && "No function template?");
- if (!ForDefaultArgumentSubstitution &&
- 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()) {
+ for (unsigned Depth = TTPD->getDepth() + 1; Depth--;)
+ AddOuterTemplateArguments(nullptr, std::nullopt, /*Final=*/false);
+
+ return Done();
+ }
+
+ Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *FTD) {
assert(
(ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
- "Outer template not instantiated?");
+ "outer template not instantiated?");
+
+ if (Innermost)
+ AddInnermostTemplateArguments(FTD);
+ else if (ForConstraintInstantiation)
+ AddOuterTemplateArguments(FTD, FTD->getInjectedTemplateArgs(),
+ /*Final=*/false);
+
+ if (FTD->isMemberSpecialization())
+ return Done();
+
+ if (FTD->getFriendObjectKind())
+ return ChangeDecl(FTD->getLexicalDeclContext());
----------------
zyn0217 wrote:
This is nice: My CWG 2369 implementation could also benefit from it without having to check if the declaration itself is a somewhat friend object to determine what to visit after an `Innermost`.
This also matches the direction that @mizvekov and I have discussed previously in my refactoring PR: we should reuse the `ChangeDecl` logic in each handling.
https://github.com/llvm/llvm-project/pull/106585
More information about the cfe-commits
mailing list