================ @@ -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(), + *OuterInstantiationArgs); + if (!NewD) + return QualType(); + + auto *NewTATD = cast<TypeAliasTemplateDecl>(NewD); + MaterializedTypedefs.push_back(NewTATD->getTemplatedDecl()); + + return Base::RebuildTemplateSpecializationType( + TemplateName(NewTATD), TemplateNameLoc, TemplateArgs); + } + QualType TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { ASTContext &Context = SemaRef.getASTContext(); TypedefNameDecl *OrigDecl = TL.getTypedefNameDecl(); TypedefNameDecl *Decl = OrigDecl; // Transform the underlying type of the typedef and clone the Decl only if // the typedef has a dependent context. - if (OrigDecl->getDeclContext()->isDependentContext()) { + bool InDependentContext = OrigDecl->getDeclContext()->isDependentContext(); + + // A typedef/alias Decl within the NestedPattern may reference the outer + // template parameters. They're substituted with corresponding instantiation + // arguments here and in RebuildTemplateSpecializationType() above. + // Otherwise, we would have a CTAD guide with "dangling" template + // parameters. + // For example, + // template <class T> struct Outer { + // using Alias = S<T>; + // template <class U> struct Inner { + // Inner(Alias); + // }; + // }; + if (OuterInstantiationArgs && InDependentContext) { + Decl = cast_if_present<TypedefNameDecl>(SemaRef.SubstDecl( ---------------- zyn0217 wrote:
Done. We now substitute these only if they involve any template parameters. https://github.com/llvm/llvm-project/pull/94740 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits