[clang] [Clang] Substitute for the type aliases inside of a CTAD guide (PR #94740)
Younan Zhang via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 4 07:48:33 PDT 2024
================
@@ -2220,23 +2220,103 @@ namespace {
class ExtractTypeForDeductionGuide
: public TreeTransform<ExtractTypeForDeductionGuide> {
llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs;
+ ClassTemplateDecl *NestedPattern;
+ const MultiLevelTemplateArgumentList *OuterInstantiationArgs;
public:
typedef TreeTransform<ExtractTypeForDeductionGuide> Base;
ExtractTypeForDeductionGuide(
Sema &SemaRef,
- llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs)
- : Base(SemaRef), MaterializedTypedefs(MaterializedTypedefs) {}
+ llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs,
+ ClassTemplateDecl *NestedPattern,
+ const MultiLevelTemplateArgumentList *OuterInstantiationArgs)
+ : Base(SemaRef), MaterializedTypedefs(MaterializedTypedefs),
+ NestedPattern(NestedPattern),
+ OuterInstantiationArgs(OuterInstantiationArgs) {}
TypeSourceInfo *transform(TypeSourceInfo *TSI) { return TransformType(TSI); }
+ /// Returns true if it's safe to substitute \p Typedef with
+ /// \p OuterInstantiationArgs.
+ bool mightReferToOuterTemplateParameters(TypedefNameDecl *Typedef) {
+ if (!NestedPattern)
+ return false;
+
+ static auto WalkUp = [](DeclContext *DC, DeclContext *TargetDC) {
+ if (DC->Equals(TargetDC))
+ return true;
+ while (DC->isRecord()) {
+ if (DC->Equals(TargetDC))
+ return true;
+ DC = DC->getParent();
+ }
+ return false;
+ };
+
+ if (WalkUp(Typedef->getDeclContext(), NestedPattern->getTemplatedDecl()))
+ return true;
+ if (WalkUp(NestedPattern->getTemplatedDecl(), Typedef->getDeclContext()))
+ return true;
+ return false;
+ }
+
+ QualType
+ RebuildTemplateSpecializationType(TemplateName Template,
+ SourceLocation TemplateNameLoc,
+ TemplateArgumentListInfo &TemplateArgs) {
+ if (!OuterInstantiationArgs ||
+ !isa_and_present<TypeAliasTemplateDecl>(Template.getAsTemplateDecl()))
+ return Base::RebuildTemplateSpecializationType(Template, TemplateNameLoc,
+ TemplateArgs);
+
+ auto *TATD = cast<TypeAliasTemplateDecl>(Template.getAsTemplateDecl());
+ auto *Pattern = TATD;
+ while (Pattern->getInstantiatedFromMemberTemplate())
+ Pattern = Pattern->getInstantiatedFromMemberTemplate();
+ if (!mightReferToOuterTemplateParameters(Pattern->getTemplatedDecl()))
+ return Base::RebuildTemplateSpecializationType(Template, TemplateNameLoc,
+ TemplateArgs);
+
+ Decl *NewD = SemaRef.SubstDecl(
+ TATD, SemaRef.getASTContext().getTranslationUnitDecl(),
----------------
zyn0217 wrote:
> There is a subtle difference:
Thanks for spotting that! This is indeed something I've overlooked.
Looking at the `SubstDecl` again, I think we can take the middle-ground approach: we call `TemplateDeclInstantiator::InstantiateTypeAliasTemplateDecl()` directly when we want to instantiate a TypedefNameDecl.
This is a plausible approach to me because
1) We could save the recursion into the `DeclVisitor` from `SubstDecl` because we already know the `Decl` is a `TypedefDecl`.
2) This avoids the accidental Decl injection, although we have to tweak the `TemplateDeclInstantiator` a bit.
3) Re: `So an alternative would be to reuse this Decl rather than creating a new one`: granted that we could find that instantiated Decl, we still have to *copy* the Decl, which is in part a duplicate work of the instantiation logic, because we want the transformed Decl to live in the CXXDeductionGuideDecl - I think we can still leverage this instantiation mechanism to keep it intelligible.
https://github.com/llvm/llvm-project/pull/94740
More information about the cfe-commits
mailing list