@@ -2250,10 +2250,24 @@ class ExtractTypeForDeductionGuide
2250
2250
struct ConvertConstructorToDeductionGuideTransform {
2251
2251
ConvertConstructorToDeductionGuideTransform(Sema &S,
2252
2252
ClassTemplateDecl *Template)
2253
- : SemaRef(S), Template(Template) {}
2253
+ : SemaRef(S), Template(Template) {
2254
+ // If the template is nested, then we need to use the original
2255
+ // pattern to iterate over the constructors.
2256
+ ClassTemplateDecl *Pattern = Template;
2257
+ while (Pattern->getInstantiatedFromMemberTemplate()) {
2258
+ if (Pattern->isMemberSpecialization())
2259
+ break;
2260
+ Pattern = Pattern->getInstantiatedFromMemberTemplate();
2261
+ NestedPattern = Pattern;
2262
+ }
2263
+
2264
+ if (NestedPattern)
2265
+ OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(Template);
2266
+ }
2254
2267
2255
2268
Sema &SemaRef;
2256
2269
ClassTemplateDecl *Template;
2270
+ ClassTemplateDecl *NestedPattern = nullptr;
2257
2271
2258
2272
DeclContext *DC = Template->getDeclContext();
2259
2273
CXXRecordDecl *Primary = Template->getTemplatedDecl();
@@ -2266,6 +2280,10 @@ struct ConvertConstructorToDeductionGuideTransform {
2266
2280
// depth-0 template parameters.
2267
2281
unsigned Depth1IndexAdjustment = Template->getTemplateParameters()->size();
2268
2282
2283
+ // Instantiation arguments for the outermost depth-1 templates
2284
+ // when the template is nested
2285
+ MultiLevelTemplateArgumentList OuterInstantiationArgs;
2286
+
2269
2287
/// Transform a constructor declaration into a deduction guide.
2270
2288
NamedDecl *transformConstructor(FunctionTemplateDecl *FTD,
2271
2289
CXXConstructorDecl *CD) {
@@ -2284,21 +2302,43 @@ struct ConvertConstructorToDeductionGuideTransform {
2284
2302
if (FTD) {
2285
2303
TemplateParameterList *InnerParams = FTD->getTemplateParameters();
2286
2304
SmallVector<NamedDecl *, 16> AllParams;
2305
+ SmallVector<TemplateArgument, 16> Depth1Args;
2287
2306
AllParams.reserve(TemplateParams->size() + InnerParams->size());
2288
2307
AllParams.insert(AllParams.begin(),
2289
2308
TemplateParams->begin(), TemplateParams->end());
2290
2309
SubstArgs.reserve(InnerParams->size());
2310
+ Depth1Args.reserve(InnerParams->size());
2291
2311
2292
2312
// Later template parameters could refer to earlier ones, so build up
2293
2313
// a list of substituted template arguments as we go.
2294
2314
for (NamedDecl *Param : *InnerParams) {
2295
2315
MultiLevelTemplateArgumentList Args;
2296
2316
Args.setKind(TemplateSubstitutionKind::Rewrite);
2297
- Args.addOuterTemplateArguments(SubstArgs );
2317
+ Args.addOuterTemplateArguments(Depth1Args );
2298
2318
Args.addOuterRetainedLevel();
2319
+ if (NestedPattern)
2320
+ Args.addOuterRetainedLevels(NestedPattern->getTemplateDepth());
2299
2321
NamedDecl *NewParam = transformTemplateParameter(Param, Args);
2300
2322
if (!NewParam)
2301
2323
return nullptr;
2324
+
2325
+ // Constraints require that we substitute depth-1 arguments
2326
+ // to match depths when substituted for evaluation later
2327
+ Depth1Args.push_back(SemaRef.Context.getCanonicalTemplateArgument(
2328
+ SemaRef.Context.getInjectedTemplateArg(NewParam)));
2329
+
2330
+ if (NestedPattern) {
2331
+ TemplateDeclInstantiator Instantiator(SemaRef, DC,
2332
+ OuterInstantiationArgs);
2333
+ Instantiator.setEvaluateConstraints(false);
2334
+ SemaRef.runWithSufficientStackSpace(NewParam->getLocation(), [&] {
2335
+ NewParam = cast<NamedDecl>(Instantiator.Visit(NewParam));
2336
+ });
2337
+ }
2338
+
2339
+ assert(NewParam->getTemplateDepth() == 0 &&
2340
+ "Unexpected template parameter depth");
2341
+
2302
2342
AllParams.push_back(NewParam);
2303
2343
SubstArgs.push_back(SemaRef.Context.getCanonicalTemplateArgument(
2304
2344
SemaRef.Context.getInjectedTemplateArg(NewParam)));
@@ -2309,8 +2349,10 @@ struct ConvertConstructorToDeductionGuideTransform {
2309
2349
if (Expr *InnerRC = InnerParams->getRequiresClause()) {
2310
2350
MultiLevelTemplateArgumentList Args;
2311
2351
Args.setKind(TemplateSubstitutionKind::Rewrite);
2312
- Args.addOuterTemplateArguments(SubstArgs );
2352
+ Args.addOuterTemplateArguments(Depth1Args );
2313
2353
Args.addOuterRetainedLevel();
2354
+ if (NestedPattern)
2355
+ Args.addOuterRetainedLevels(NestedPattern->getTemplateDepth());
2314
2356
ExprResult E = SemaRef.SubstExpr(InnerRC, Args);
2315
2357
if (E.isInvalid())
2316
2358
return nullptr;
@@ -2333,6 +2375,9 @@ struct ConvertConstructorToDeductionGuideTransform {
2333
2375
Args.addOuterRetainedLevel();
2334
2376
}
2335
2377
2378
+ if (NestedPattern)
2379
+ Args.addOuterRetainedLevels(NestedPattern->getTemplateDepth());
2380
+
2336
2381
FunctionProtoTypeLoc FPTL = CD->getTypeSourceInfo()->getTypeLoc()
2337
2382
.getAsAdjusted<FunctionProtoTypeLoc>();
2338
2383
assert(FPTL && "no prototype for constructor declaration");
@@ -2394,7 +2439,7 @@ struct ConvertConstructorToDeductionGuideTransform {
2394
2439
// substitute it directly.
2395
2440
auto *NewTTP = TemplateTypeParmDecl::Create(
2396
2441
SemaRef.Context, DC, TTP->getBeginLoc(), TTP->getLocation(),
2397
- /*Depth*/ 0 , Depth1IndexAdjustment + TTP->getIndex(),
2442
+ TTP->getDepth() - 1 , Depth1IndexAdjustment + TTP->getIndex(),
2398
2443
TTP->getIdentifier(), TTP->wasDeclaredWithTypename(),
2399
2444
TTP->isParameterPack(), TTP->hasTypeConstraint(),
2400
2445
TTP->isExpandedParameterPack()
@@ -2429,7 +2474,8 @@ struct ConvertConstructorToDeductionGuideTransform {
2429
2474
// the index of the parameter once it's done.
2430
2475
auto *NewParam =
2431
2476
cast<TemplateParmDecl>(SemaRef.SubstDecl(OldParam, DC, Args));
2432
- assert(NewParam->getDepth() == 0 && "unexpected template param depth");
2477
+ assert(NewParam->getDepth() == OldParam->getDepth() - 1 &&
2478
+ "unexpected template param depth");
2433
2479
NewParam->setPosition(NewParam->getPosition() + Depth1IndexAdjustment);
2434
2480
return NewParam;
2435
2481
}
@@ -2446,6 +2492,9 @@ struct ConvertConstructorToDeductionGuideTransform {
2446
2492
for (auto *OldParam : TL.getParams()) {
2447
2493
ParmVarDecl *NewParam =
2448
2494
transformFunctionTypeParam(OldParam, Args, MaterializedTypedefs);
2495
+ if (NestedPattern && NewParam)
2496
+ NewParam = transformFunctionTypeParam(NewParam, OuterInstantiationArgs,
2497
+ MaterializedTypedefs);
2449
2498
if (!NewParam)
2450
2499
return QualType();
2451
2500
ParamTypes.push_back(NewParam->getType());
@@ -2655,9 +2704,12 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
2655
2704
// FIXME: Skip constructors for which deduction must necessarily fail (those
2656
2705
// for which some class template parameter without a default argument never
2657
2706
// appears in a deduced context).
2707
+ ClassTemplateDecl *Pattern =
2708
+ Transform.NestedPattern ? Transform.NestedPattern : Transform.Template;
2709
+ ContextRAII SavedContext(*this, Pattern->getTemplatedDecl());
2658
2710
llvm::SmallPtrSet<NamedDecl *, 8> ProcessedCtors;
2659
2711
bool AddedAny = false;
2660
- for (NamedDecl *D : LookupConstructors(Transform.Primary )) {
2712
+ for (NamedDecl *D : LookupConstructors(Pattern->getTemplatedDecl() )) {
2661
2713
D = D->getUnderlyingDecl();
2662
2714
if (D->isInvalidDecl() || D->isImplicit())
2663
2715
continue;
@@ -2703,6 +2755,8 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
2703
2755
Transform.buildSimpleDeductionGuide(Transform.DeducedType))
2704
2756
->getTemplatedDecl())
2705
2757
->setDeductionCandidateKind(DeductionCandidate::Copy);
2758
+
2759
+ SavedContext.pop();
2706
2760
}
2707
2761
2708
2762
/// Diagnose the presence of a default template argument on a
0 commit comments