@@ -2178,23 +2178,110 @@ namespace {
2178
2178
class ExtractTypeForDeductionGuide
2179
2179
: public TreeTransform<ExtractTypeForDeductionGuide> {
2180
2180
llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs;
2181
+ ClassTemplateDecl *NestedPattern;
2182
+ const MultiLevelTemplateArgumentList *OuterInstantiationArgs;
2183
+ std::optional<TemplateDeclInstantiator> TypedefNameInstantiator;
2181
2184
2182
2185
public:
2183
2186
typedef TreeTransform<ExtractTypeForDeductionGuide> Base;
2184
2187
ExtractTypeForDeductionGuide (
2185
2188
Sema &SemaRef,
2186
- llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs)
2187
- : Base(SemaRef), MaterializedTypedefs(MaterializedTypedefs) {}
2189
+ llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs,
2190
+ ClassTemplateDecl *NestedPattern,
2191
+ const MultiLevelTemplateArgumentList *OuterInstantiationArgs)
2192
+ : Base(SemaRef), MaterializedTypedefs(MaterializedTypedefs),
2193
+ NestedPattern (NestedPattern),
2194
+ OuterInstantiationArgs(OuterInstantiationArgs) {
2195
+ if (OuterInstantiationArgs)
2196
+ TypedefNameInstantiator.emplace (
2197
+ SemaRef, SemaRef.getASTContext ().getTranslationUnitDecl (),
2198
+ *OuterInstantiationArgs);
2199
+ }
2188
2200
2189
2201
TypeSourceInfo *transform (TypeSourceInfo *TSI) { return TransformType (TSI); }
2190
2202
2203
+ // / Returns true if it's safe to substitute \p Typedef with
2204
+ // / \p OuterInstantiationArgs.
2205
+ bool mightReferToOuterTemplateParameters (TypedefNameDecl *Typedef) {
2206
+ if (!NestedPattern)
2207
+ return false ;
2208
+
2209
+ static auto WalkUp = [](DeclContext *DC, DeclContext *TargetDC) {
2210
+ if (DC->Equals (TargetDC))
2211
+ return true ;
2212
+ while (DC->isRecord ()) {
2213
+ if (DC->Equals (TargetDC))
2214
+ return true ;
2215
+ DC = DC->getParent ();
2216
+ }
2217
+ return false ;
2218
+ };
2219
+
2220
+ if (WalkUp (Typedef->getDeclContext (), NestedPattern->getTemplatedDecl ()))
2221
+ return true ;
2222
+ if (WalkUp (NestedPattern->getTemplatedDecl (), Typedef->getDeclContext ()))
2223
+ return true ;
2224
+ return false ;
2225
+ }
2226
+
2227
+ QualType
2228
+ RebuildTemplateSpecializationType (TemplateName Template,
2229
+ SourceLocation TemplateNameLoc,
2230
+ TemplateArgumentListInfo &TemplateArgs) {
2231
+ if (!OuterInstantiationArgs ||
2232
+ !isa_and_present<TypeAliasTemplateDecl>(Template.getAsTemplateDecl ()))
2233
+ return Base::RebuildTemplateSpecializationType (Template, TemplateNameLoc,
2234
+ TemplateArgs);
2235
+
2236
+ auto *TATD = cast<TypeAliasTemplateDecl>(Template.getAsTemplateDecl ());
2237
+ auto *Pattern = TATD;
2238
+ while (Pattern->getInstantiatedFromMemberTemplate ())
2239
+ Pattern = Pattern->getInstantiatedFromMemberTemplate ();
2240
+ if (!mightReferToOuterTemplateParameters (Pattern->getTemplatedDecl ()))
2241
+ return Base::RebuildTemplateSpecializationType (Template, TemplateNameLoc,
2242
+ TemplateArgs);
2243
+
2244
+ Decl *NewD =
2245
+ TypedefNameInstantiator->InstantiateTypeAliasTemplateDecl (TATD);
2246
+ if (!NewD)
2247
+ return QualType ();
2248
+
2249
+ auto *NewTATD = cast<TypeAliasTemplateDecl>(NewD);
2250
+ MaterializedTypedefs.push_back (NewTATD->getTemplatedDecl ());
2251
+
2252
+ return Base::RebuildTemplateSpecializationType (
2253
+ TemplateName (NewTATD), TemplateNameLoc, TemplateArgs);
2254
+ }
2255
+
2191
2256
QualType TransformTypedefType (TypeLocBuilder &TLB, TypedefTypeLoc TL) {
2192
2257
ASTContext &Context = SemaRef.getASTContext ();
2193
2258
TypedefNameDecl *OrigDecl = TL.getTypedefNameDecl ();
2194
2259
TypedefNameDecl *Decl = OrigDecl;
2195
2260
// Transform the underlying type of the typedef and clone the Decl only if
2196
2261
// the typedef has a dependent context.
2197
- if (OrigDecl->getDeclContext ()->isDependentContext ()) {
2262
+ bool InDependentContext = OrigDecl->getDeclContext ()->isDependentContext ();
2263
+
2264
+ // A typedef/alias Decl within the NestedPattern may reference the outer
2265
+ // template parameters. They're substituted with corresponding instantiation
2266
+ // arguments here and in RebuildTemplateSpecializationType() above.
2267
+ // Otherwise, we would have a CTAD guide with "dangling" template
2268
+ // parameters.
2269
+ // For example,
2270
+ // template <class T> struct Outer {
2271
+ // using Alias = S<T>;
2272
+ // template <class U> struct Inner {
2273
+ // Inner(Alias);
2274
+ // };
2275
+ // };
2276
+ if (OuterInstantiationArgs && InDependentContext &&
2277
+ TL.getTypePtr ()->isInstantiationDependentType ()) {
2278
+ Decl = cast_if_present<TypedefNameDecl>(
2279
+ TypedefNameInstantiator->InstantiateTypedefNameDecl (
2280
+ OrigDecl, /* IsTypeAlias=*/ isa<TypeAliasDecl>(OrigDecl)));
2281
+ if (!Decl)
2282
+ return QualType ();
2283
+ MaterializedTypedefs.push_back (Decl);
2284
+ } else if (InDependentContext) {
2198
2285
TypeLocBuilder InnerTLB;
2199
2286
QualType Transformed =
2200
2287
TransformType (InnerTLB, OrigDecl->getTypeSourceInfo ()->getTypeLoc ());
@@ -2541,16 +2628,18 @@ struct ConvertConstructorToDeductionGuideTransform {
2541
2628
// defined outside of the surrounding class template. That is T in the
2542
2629
// above example.
2543
2630
if (NestedPattern) {
2544
- NewParam = transformFunctionTypeParam (NewParam, OuterInstantiationArgs,
2545
- MaterializedTypedefs);
2631
+ NewParam = transformFunctionTypeParam (
2632
+ NewParam, OuterInstantiationArgs, MaterializedTypedefs,
2633
+ /* TransformingOuterPatterns=*/ true );
2546
2634
if (!NewParam)
2547
2635
return QualType ();
2548
2636
}
2549
2637
// Then, transform all the references to template parameters that are
2550
2638
// defined at the class template and the constructor. In this example,
2551
2639
// they're U and V, respectively.
2552
2640
NewParam =
2553
- transformFunctionTypeParam (NewParam, Args, MaterializedTypedefs);
2641
+ transformFunctionTypeParam (NewParam, Args, MaterializedTypedefs,
2642
+ /* TransformingOuterPatterns=*/ false );
2554
2643
if (!NewParam)
2555
2644
return QualType ();
2556
2645
ParamTypes.push_back (NewParam->getType ());
@@ -2594,7 +2683,8 @@ struct ConvertConstructorToDeductionGuideTransform {
2594
2683
2595
2684
ParmVarDecl *transformFunctionTypeParam (
2596
2685
ParmVarDecl *OldParam, MultiLevelTemplateArgumentList &Args,
2597
- llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs) {
2686
+ llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs,
2687
+ bool TransformingOuterPatterns) {
2598
2688
TypeSourceInfo *OldDI = OldParam->getTypeSourceInfo ();
2599
2689
TypeSourceInfo *NewDI;
2600
2690
if (auto PackTL = OldDI->getTypeLoc ().getAs <PackExpansionTypeLoc>()) {
@@ -2617,7 +2707,9 @@ struct ConvertConstructorToDeductionGuideTransform {
2617
2707
// members of the current instantiations with the definitions of those
2618
2708
// typedefs, avoiding triggering instantiation of the deduced type during
2619
2709
// deduction.
2620
- NewDI = ExtractTypeForDeductionGuide (SemaRef, MaterializedTypedefs)
2710
+ NewDI = ExtractTypeForDeductionGuide (
2711
+ SemaRef, MaterializedTypedefs, NestedPattern,
2712
+ TransformingOuterPatterns ? &Args : nullptr )
2621
2713
.transform (NewDI);
2622
2714
2623
2715
// Resolving a wording defect, we also inherit default arguments from the
0 commit comments