@@ -80,6 +80,81 @@ struct Response {
80
80
return R;
81
81
}
82
82
};
83
+
84
+ // Retrieve the primary template for a lambda call operator. It's
85
+ // unfortunate that we only have the mappings of call operators rather
86
+ // than lambda classes.
87
+ const FunctionDecl *
88
+ getPrimaryTemplateOfGenericLambda (const FunctionDecl *LambdaCallOperator) {
89
+ while (true ) {
90
+ if (auto *FTD = dyn_cast_if_present<FunctionTemplateDecl>(
91
+ LambdaCallOperator->getDescribedTemplate ());
92
+ FTD && FTD->getInstantiatedFromMemberTemplate ()) {
93
+ LambdaCallOperator =
94
+ FTD->getInstantiatedFromMemberTemplate ()->getTemplatedDecl ();
95
+ } else if (auto *Prev = cast<CXXMethodDecl>(LambdaCallOperator)
96
+ ->getInstantiatedFromMemberFunction ())
97
+ LambdaCallOperator = Prev;
98
+ else
99
+ break ;
100
+ }
101
+ return LambdaCallOperator;
102
+ }
103
+
104
+ struct EnclosingTypeAliasTemplateDetails {
105
+ TypeAliasTemplateDecl *Template = nullptr ;
106
+ TypeAliasTemplateDecl *PrimaryTypeAliasDecl = nullptr ;
107
+ ArrayRef<TemplateArgument> AssociatedTemplateArguments;
108
+
109
+ explicit operator bool () noexcept { return Template; }
110
+ };
111
+
112
+ // Find the enclosing type alias template Decl from CodeSynthesisContexts, as
113
+ // well as its primary template and instantiating template arguments.
114
+ EnclosingTypeAliasTemplateDetails
115
+ getEnclosingTypeAliasTemplateDecl (Sema &SemaRef) {
116
+ for (auto &CSC : llvm::reverse (SemaRef.CodeSynthesisContexts )) {
117
+ if (CSC.Kind != Sema::CodeSynthesisContext::SynthesisKind::
118
+ TypeAliasTemplateInstantiation)
119
+ continue ;
120
+ EnclosingTypeAliasTemplateDetails Result;
121
+ auto *TATD = cast<TypeAliasTemplateDecl>(CSC.Entity ),
122
+ *Next = TATD->getInstantiatedFromMemberTemplate ();
123
+ Result = {
124
+ /* Template=*/ TATD,
125
+ /* PrimaryTypeAliasDecl=*/ TATD,
126
+ /* AssociatedTemplateArguments=*/ CSC.template_arguments (),
127
+ };
128
+ while (Next) {
129
+ Result.PrimaryTypeAliasDecl = Next;
130
+ Next = Next->getInstantiatedFromMemberTemplate ();
131
+ }
132
+ return Result;
133
+ }
134
+ return {};
135
+ }
136
+
137
+ // Check if we are currently inside of a lambda expression that is
138
+ // surrounded by a using alias declaration. e.g.
139
+ // template <class> using type = decltype([](auto) { ^ }());
140
+ // By checking if:
141
+ // 1. The lambda expression and the using alias declaration share the
142
+ // same declaration context.
143
+ // 2. They have the same template depth.
144
+ // We have to do so since a TypeAliasTemplateDecl (or a TypeAliasDecl) is never
145
+ // a DeclContext, nor does it have an associated specialization Decl from which
146
+ // we could collect these template arguments.
147
+ bool isLambdaEnclosedByTypeAliasDecl (
148
+ const FunctionDecl *PrimaryLambdaCallOperator,
149
+ const TypeAliasTemplateDecl *PrimaryTypeAliasDecl) {
150
+ return cast<CXXRecordDecl>(PrimaryLambdaCallOperator->getDeclContext ())
151
+ ->getTemplateDepth () ==
152
+ PrimaryTypeAliasDecl->getTemplateDepth () &&
153
+ getLambdaAwareParentOfDeclContext (
154
+ const_cast <FunctionDecl *>(PrimaryLambdaCallOperator)) ==
155
+ PrimaryTypeAliasDecl->getDeclContext ();
156
+ }
157
+
83
158
// Add template arguments from a variable template instantiation.
84
159
Response
85
160
HandleVarTemplateSpec (const VarTemplateSpecializationDecl *VarTemplSpec,
@@ -176,7 +251,7 @@ HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec,
176
251
return Response::UseNextDecl (ClassTemplSpec);
177
252
}
178
253
179
- Response HandleFunction (const FunctionDecl *Function,
254
+ Response HandleFunction (Sema &SemaRef, const FunctionDecl *Function,
180
255
MultiLevelTemplateArgumentList &Result,
181
256
const FunctionDecl *Pattern, bool RelativeToPrimary,
182
257
bool ForConstraintInstantiation) {
@@ -207,8 +282,23 @@ Response HandleFunction(const FunctionDecl *Function,
207
282
208
283
// If this function is a generic lambda specialization, we are done.
209
284
if (!ForConstraintInstantiation &&
210
- isGenericLambdaCallOperatorOrStaticInvokerSpecialization (Function))
285
+ isGenericLambdaCallOperatorOrStaticInvokerSpecialization (Function)) {
286
+ // TypeAliasTemplateDecls should be taken into account, e.g.
287
+ // when we're deducing the return type of a lambda.
288
+ //
289
+ // template <class> int Value = 0;
290
+ // template <class T>
291
+ // using T = decltype([]<int U = 0>() { return Value<T>; }());
292
+ //
293
+ if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl (SemaRef)) {
294
+ if (isLambdaEnclosedByTypeAliasDecl (
295
+ /* PrimaryLambdaCallOperator=*/ getPrimaryTemplateOfGenericLambda (
296
+ Function),
297
+ /* PrimaryTypeAliasDecl=*/ TypeAlias.PrimaryTypeAliasDecl ))
298
+ return Response::UseNextDecl (Function);
299
+ }
211
300
return Response::Done ();
301
+ }
212
302
213
303
} else if (Function->getDescribedFunctionTemplate ()) {
214
304
assert (
@@ -283,7 +373,7 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
283
373
return Response::ChangeDecl (FTD->getLexicalDeclContext ());
284
374
}
285
375
286
- Response HandleRecordDecl (const CXXRecordDecl *Rec,
376
+ Response HandleRecordDecl (Sema &SemaRef, const CXXRecordDecl *Rec,
287
377
MultiLevelTemplateArgumentList &Result,
288
378
ASTContext &Context,
289
379
bool ForConstraintInstantiation) {
@@ -312,11 +402,39 @@ Response HandleRecordDecl(const CXXRecordDecl *Rec,
312
402
return Response::ChangeDecl (Rec->getLexicalDeclContext ());
313
403
}
314
404
315
- // This is to make sure we pick up the VarTemplateSpecializationDecl that this
316
- // lambda is defined inside of.
317
- if (Rec->isLambda ())
405
+ // This is to make sure we pick up the VarTemplateSpecializationDecl or the
406
+ // TypeAliasTemplateDecl that this lambda is defined inside of.
407
+ if (Rec->isLambda ()) {
318
408
if (const Decl *LCD = Rec->getLambdaContextDecl ())
319
409
return Response::ChangeDecl (LCD);
410
+ // Retrieve the template arguments for a using alias declaration.
411
+ // This is necessary for constraint checking, since we always keep
412
+ // constraints relative to the primary template.
413
+ if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl (SemaRef)) {
414
+ const FunctionDecl *PrimaryLambdaCallOperator =
415
+ getPrimaryTemplateOfGenericLambda (Rec->getLambdaCallOperator ());
416
+ if (isLambdaEnclosedByTypeAliasDecl (PrimaryLambdaCallOperator,
417
+ TypeAlias.PrimaryTypeAliasDecl )) {
418
+ Result.addOuterTemplateArguments (TypeAlias.Template ,
419
+ TypeAlias.AssociatedTemplateArguments ,
420
+ /* Final=*/ false );
421
+ // Visit the parent of the current type alias declaration rather than
422
+ // the lambda thereof.
423
+ // E.g., in the following example:
424
+ // struct S {
425
+ // template <class> using T = decltype([]<Concept> {} ());
426
+ // };
427
+ // void foo() {
428
+ // S::T var;
429
+ // }
430
+ // The instantiated lambda expression (which we're visiting at 'var')
431
+ // has a function DeclContext 'foo' rather than the Record DeclContext
432
+ // S. This seems to be an oversight to me that we may want to set a
433
+ // Sema Context from the CXXScopeSpec before substituting into T.
434
+ return Response::ChangeDecl (TypeAlias.Template ->getDeclContext ());
435
+ }
436
+ }
437
+ }
320
438
321
439
return Response::UseNextDecl (Rec);
322
440
}
@@ -410,10 +528,11 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
410
528
R = HandleClassTemplateSpec (ClassTemplSpec, Result,
411
529
SkipForSpecialization);
412
530
} else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) {
413
- R = HandleFunction (Function, Result, Pattern, RelativeToPrimary,
531
+ R = HandleFunction (* this , Function, Result, Pattern, RelativeToPrimary,
414
532
ForConstraintInstantiation);
415
533
} else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) {
416
- R = HandleRecordDecl (Rec, Result, Context, ForConstraintInstantiation);
534
+ R = HandleRecordDecl (*this , Rec, Result, Context,
535
+ ForConstraintInstantiation);
417
536
} else if (const auto *CSD =
418
537
dyn_cast<ImplicitConceptSpecializationDecl>(CurDecl)) {
419
538
R = HandleImplicitConceptSpecializationDecl (CSD, Result);
@@ -470,6 +589,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
470
589
case BuildingBuiltinDumpStructCall:
471
590
case LambdaExpressionSubstitution:
472
591
case BuildingDeductionGuides:
592
+ case TypeAliasTemplateInstantiation:
473
593
return false ;
474
594
475
595
// This function should never be called when Kind's value is Memoization.
@@ -615,6 +735,15 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
615
735
PointOfInstantiation, InstantiationRange, Param, Template,
616
736
TemplateArgs) {}
617
737
738
+ Sema::InstantiatingTemplate::InstantiatingTemplate (
739
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
740
+ TypeAliasTemplateDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
741
+ SourceRange InstantiationRange)
742
+ : InstantiatingTemplate(
743
+ SemaRef, Sema::CodeSynthesisContext::TypeAliasTemplateInstantiation,
744
+ PointOfInstantiation, InstantiationRange, /* Entity=*/ Template,
745
+ /* Template=*/ nullptr , TemplateArgs) {}
746
+
618
747
Sema::InstantiatingTemplate::InstantiatingTemplate (
619
748
Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template,
620
749
NamedDecl *Param, ArrayRef<TemplateArgument> TemplateArgs,
@@ -1132,6 +1261,8 @@ void Sema::PrintInstantiationStack() {
1132
1261
Diags.Report (Active->PointOfInstantiation ,
1133
1262
diag::note_building_deduction_guide_here);
1134
1263
break ;
1264
+ case CodeSynthesisContext::TypeAliasTemplateInstantiation:
1265
+ break ;
1135
1266
}
1136
1267
}
1137
1268
}
@@ -1209,6 +1340,7 @@ std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
1209
1340
break ;
1210
1341
1211
1342
case CodeSynthesisContext::Memoization:
1343
+ case CodeSynthesisContext::TypeAliasTemplateInstantiation:
1212
1344
break ;
1213
1345
}
1214
1346
@@ -1534,6 +1666,18 @@ namespace {
1534
1666
SubstTemplateTypeParmPackTypeLoc TL,
1535
1667
bool SuppressObjCLifetime);
1536
1668
1669
+ CXXRecordDecl::LambdaDependencyKind
1670
+ ComputeLambdaDependency (LambdaScopeInfo *LSI) {
1671
+ auto &CCS = SemaRef.CodeSynthesisContexts .back ();
1672
+ if (CCS.Kind ==
1673
+ Sema::CodeSynthesisContext::TypeAliasTemplateInstantiation) {
1674
+ unsigned TypeAliasDeclDepth = CCS.Entity ->getTemplateDepth ();
1675
+ if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels ())
1676
+ return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
1677
+ }
1678
+ return inherited::ComputeLambdaDependency (LSI);
1679
+ }
1680
+
1537
1681
ExprResult TransformLambdaExpr (LambdaExpr *E) {
1538
1682
LocalInstantiationScope Scope (SemaRef, /* CombineWithOuterScope=*/ true );
1539
1683
Sema::ConstraintEvalRAII<TemplateInstantiator> RAII (*this );
0 commit comments