================ @@ -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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits