@@ -79,6 +79,81 @@ struct Response {
79
79
return R;
80
80
}
81
81
};
82
+
83
+ // Retrieve the primary template for a lambda call operator. It's
84
+ // unfortunate that we only have the mappings of call operators rather
85
+ // than lambda classes.
86
+ const FunctionDecl *
87
+ getPrimaryTemplateOfGenericLambda (const FunctionDecl *LambdaCallOperator) {
88
+ while (true ) {
89
+ if (auto *FTD = dyn_cast_if_present<FunctionTemplateDecl>(
90
+ LambdaCallOperator->getDescribedTemplate ());
91
+ FTD && FTD->getInstantiatedFromMemberTemplate ()) {
92
+ LambdaCallOperator =
93
+ FTD->getInstantiatedFromMemberTemplate ()->getTemplatedDecl ();
94
+ } else if (auto *Prev = cast<CXXMethodDecl>(LambdaCallOperator)
95
+ ->getInstantiatedFromMemberFunction ())
96
+ LambdaCallOperator = Prev;
97
+ else
98
+ break ;
99
+ }
100
+ return LambdaCallOperator;
101
+ }
102
+
103
+ struct EnclosingTypeAliasTemplateDetails {
104
+ TypeAliasTemplateDecl *Template = nullptr ;
105
+ TypeAliasTemplateDecl *PrimaryTypeAliasDecl = nullptr ;
106
+ ArrayRef<TemplateArgument> AssociatedTemplateArguments;
107
+
108
+ explicit operator bool () noexcept { return Template; }
109
+ };
110
+
111
+ // Find the enclosing type alias template Decl from CodeSynthesisContexts, as
112
+ // well as its primary template and instantiating template arguments.
113
+ EnclosingTypeAliasTemplateDetails
114
+ getEnclosingTypeAliasTemplateDecl (Sema &SemaRef) {
115
+ for (auto &CSC : llvm::reverse (SemaRef.CodeSynthesisContexts )) {
116
+ if (CSC.Kind != Sema::CodeSynthesisContext::SynthesisKind::
117
+ TypeAliasTemplateInstantiation)
118
+ continue ;
119
+ EnclosingTypeAliasTemplateDetails Result;
120
+ auto *TATD = cast<TypeAliasTemplateDecl>(CSC.Entity ),
121
+ *Next = TATD->getInstantiatedFromMemberTemplate ();
122
+ Result = {
123
+ /* Template=*/ TATD,
124
+ /* PrimaryTypeAliasDecl=*/ TATD,
125
+ /* AssociatedTemplateArguments=*/ CSC.template_arguments (),
126
+ };
127
+ while (Next) {
128
+ Result.PrimaryTypeAliasDecl = Next;
129
+ Next = Next->getInstantiatedFromMemberTemplate ();
130
+ }
131
+ return Result;
132
+ }
133
+ return {};
134
+ }
135
+
136
+ // Check if we are currently inside of a lambda expression that is
137
+ // surrounded by a using alias declaration. e.g.
138
+ // template <class> using type = decltype([](auto) { ^ }());
139
+ // By checking if:
140
+ // 1. The lambda expression and the using alias declaration share the
141
+ // same declaration context.
142
+ // 2. They have the same template depth.
143
+ // We have to do so since a TypeAliasTemplateDecl (or a TypeAliasDecl) is never
144
+ // a DeclContext, nor does it have an associated specialization Decl from which
145
+ // we could collect these template arguments.
146
+ bool isLambdaEnclosedByTypeAliasDecl (
147
+ const FunctionDecl *PrimaryLambdaCallOperator,
148
+ const TypeAliasTemplateDecl *PrimaryTypeAliasDecl) {
149
+ return cast<CXXRecordDecl>(PrimaryLambdaCallOperator->getDeclContext ())
150
+ ->getTemplateDepth () ==
151
+ PrimaryTypeAliasDecl->getTemplateDepth () &&
152
+ getLambdaAwareParentOfDeclContext (
153
+ const_cast <FunctionDecl *>(PrimaryLambdaCallOperator)) ==
154
+ PrimaryTypeAliasDecl->getDeclContext ();
155
+ }
156
+
82
157
// Add template arguments from a variable template instantiation.
83
158
Response
84
159
HandleVarTemplateSpec (const VarTemplateSpecializationDecl *VarTemplSpec,
@@ -175,7 +250,7 @@ HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec,
175
250
return Response::UseNextDecl (ClassTemplSpec);
176
251
}
177
252
178
- Response HandleFunction (const FunctionDecl *Function,
253
+ Response HandleFunction (Sema &SemaRef, const FunctionDecl *Function,
179
254
MultiLevelTemplateArgumentList &Result,
180
255
const FunctionDecl *Pattern, bool RelativeToPrimary,
181
256
bool ForConstraintInstantiation) {
@@ -206,8 +281,23 @@ Response HandleFunction(const FunctionDecl *Function,
206
281
207
282
// If this function is a generic lambda specialization, we are done.
208
283
if (!ForConstraintInstantiation &&
209
- isGenericLambdaCallOperatorOrStaticInvokerSpecialization (Function))
284
+ isGenericLambdaCallOperatorOrStaticInvokerSpecialization (Function)) {
285
+ // TypeAliasTemplateDecls should be taken into account, e.g.
286
+ // when we're deducing the return type of a lambda.
287
+ //
288
+ // template <class> int Value = 0;
289
+ // template <class T>
290
+ // using T = decltype([]<int U = 0>() { return Value<T>; }());
291
+ //
292
+ if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl (SemaRef)) {
293
+ if (isLambdaEnclosedByTypeAliasDecl (
294
+ /* PrimaryLambdaCallOperator=*/ getPrimaryTemplateOfGenericLambda (
295
+ Function),
296
+ /* PrimaryTypeAliasDecl=*/ TypeAlias.PrimaryTypeAliasDecl ))
297
+ return Response::UseNextDecl (Function);
298
+ }
210
299
return Response::Done ();
300
+ }
211
301
212
302
} else if (Function->getDescribedFunctionTemplate ()) {
213
303
assert (
@@ -311,74 +401,36 @@ Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec,
311
401
return Response::ChangeDecl (Rec->getLexicalDeclContext ());
312
402
}
313
403
314
- // This is to make sure we pick up the VarTemplateSpecializationDecl that this
315
- // lambda is defined inside of.
404
+ // This is to make sure we pick up the VarTemplateSpecializationDecl or the
405
+ // TypeAliasTemplateDecl that this lambda is defined inside of.
316
406
if (Rec->isLambda ()) {
317
407
if (const Decl *LCD = Rec->getLambdaContextDecl ())
318
408
return Response::ChangeDecl (LCD);
319
- // Attempt to retrieve the template arguments for a using alias declaration.
409
+ // Retrieve the template arguments for a using alias declaration.
320
410
// This is necessary for constraint checking, since we always keep
321
411
// constraints relative to the primary template.
322
- if (ForConstraintInstantiation && !SemaRef.CodeSynthesisContexts .empty ()) {
323
- for (auto &CSC : llvm::reverse (SemaRef.CodeSynthesisContexts )) {
324
- if (CSC.Kind != Sema::CodeSynthesisContext::SynthesisKind::
325
- TypeAliasTemplateInstantiation)
326
- continue ;
327
- auto *TATD = cast<TypeAliasTemplateDecl>(CSC.Entity ),
328
- *CurrentTATD = TATD;
329
- FunctionDecl *LambdaCallOperator = Rec->getLambdaCallOperator ();
330
- // Retrieve the 'primary' template for a lambda call operator. It's
331
- // unfortunate that we only have the mappings of call operators rather
332
- // than lambda classes.
333
- while (true ) {
334
- auto *FTD = dyn_cast_if_present<FunctionTemplateDecl>(
335
- LambdaCallOperator->getDescribedTemplate ());
336
- if (FTD && FTD->getInstantiatedFromMemberTemplate ()) {
337
- LambdaCallOperator =
338
- FTD->getInstantiatedFromMemberTemplate ()->getTemplatedDecl ();
339
- } else if (auto *Prev = cast<CXXMethodDecl>(LambdaCallOperator)
340
- ->getInstantiatedFromMemberFunction ())
341
- LambdaCallOperator = Prev;
342
- else
343
- break ;
344
- }
345
- // Same applies for type alias Decl. We perform this to obtain the
346
- // "canonical" template parameter depths.
347
- while (TATD->getInstantiatedFromMemberTemplate ())
348
- TATD = TATD->getInstantiatedFromMemberTemplate ();
349
- // Tell if we're currently inside of a lambda expression that is
350
- // surrounded by a using alias declaration. e.g.
351
- // template <class> using type = decltype([](auto) { ^ }());
352
- // By checking if:
353
- // 1. The lambda expression and the using alias declaration share the
354
- // same declaration context.
355
- // 2. They have the same template depth.
356
- // Then we assume the template arguments from the using alias
357
- // declaration are essential for constraint instantiation. We have to do
358
- // so since a TypeAliasTemplateDecl (or a TypeAliasDecl) is never a
359
- // DeclContext, nor does it have an associated specialization Decl from
360
- // which we could collect these template arguments.
361
- if (cast<CXXRecordDecl>(LambdaCallOperator->getDeclContext ())
362
- ->getTemplateDepth () == TATD->getTemplateDepth () &&
363
- getLambdaAwareParentOfDeclContext (LambdaCallOperator) ==
364
- TATD->getDeclContext ()) {
365
- Result.addOuterTemplateArguments (CurrentTATD,
366
- CSC.template_arguments (),
367
- /* Final=*/ false );
368
- // Visit the parent of the current type alias declaration rather than
369
- // the lambda thereof. We have the following case:
370
- // struct S {
371
- // template <class> using T = decltype([]<Concept> {} ());
372
- // };
373
- // void foo() {
374
- // S::T var;
375
- // }
376
- // The instantiated lambda expression (which we're visiting at 'var')
377
- // has a function DeclContext 'foo' rather than the Record DeclContext
378
- // S. This seems to be an oversight that we may want to set a Sema
379
- // Context from the CXXScopeSpec before substituting into T to me.
380
- return Response::ChangeDecl (CurrentTATD->getDeclContext ());
381
- }
412
+ if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl (SemaRef)) {
413
+ const FunctionDecl *PrimaryLambdaCallOperator =
414
+ getPrimaryTemplateOfGenericLambda (Rec->getLambdaCallOperator ());
415
+ if (isLambdaEnclosedByTypeAliasDecl (PrimaryLambdaCallOperator,
416
+ TypeAlias.PrimaryTypeAliasDecl )) {
417
+ Result.addOuterTemplateArguments (TypeAlias.Template ,
418
+ TypeAlias.AssociatedTemplateArguments ,
419
+ /* Final=*/ false );
420
+ // Visit the parent of the current type alias declaration rather than
421
+ // the lambda thereof.
422
+ // E.g., in the following example:
423
+ // struct S {
424
+ // template <class> using T = decltype([]<Concept> {} ());
425
+ // };
426
+ // void foo() {
427
+ // S::T var;
428
+ // }
429
+ // The instantiated lambda expression (which we're visiting at 'var')
430
+ // has a function DeclContext 'foo' rather than the Record DeclContext
431
+ // S. This seems to be an oversight to me that we may want to set a
432
+ // Sema Context from the CXXScopeSpec before substituting into T.
433
+ return Response::ChangeDecl (TypeAlias.Template ->getDeclContext ());
382
434
}
383
435
}
384
436
}
@@ -475,7 +527,7 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
475
527
R = HandleClassTemplateSpec (ClassTemplSpec, Result,
476
528
SkipForSpecialization);
477
529
} else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) {
478
- R = HandleFunction (Function, Result, Pattern, RelativeToPrimary,
530
+ R = HandleFunction (* this , Function, Result, Pattern, RelativeToPrimary,
479
531
ForConstraintInstantiation);
480
532
} else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) {
481
533
R = HandleRecordDecl (*this , Rec, Result, Context,
@@ -689,7 +741,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
689
741
: InstantiatingTemplate(
690
742
SemaRef, Sema::CodeSynthesisContext::TypeAliasTemplateInstantiation,
691
743
PointOfInstantiation, InstantiationRange, /* Entity=*/ Template,
692
- nullptr , TemplateArgs) {}
744
+ /* Template= */ nullptr , TemplateArgs) {}
693
745
694
746
Sema::InstantiatingTemplate::InstantiatingTemplate (
695
747
Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template,
0 commit comments