@@ -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 (
@@ -312,74 +402,36 @@ Response HandleRecordDecl(Sema &SemaRef, 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.
405
+ // This is to make sure we pick up the VarTemplateSpecializationDecl or the
406
+ // TypeAliasTemplateDecl that this lambda is defined inside of.
317
407
if (Rec->isLambda ()) {
318
408
if (const Decl *LCD = Rec->getLambdaContextDecl ())
319
409
return Response::ChangeDecl (LCD);
320
- // Attempt to retrieve the template arguments for a using alias declaration.
410
+ // Retrieve the template arguments for a using alias declaration.
321
411
// This is necessary for constraint checking, since we always keep
322
412
// constraints relative to the primary template.
323
- if (ForConstraintInstantiation && !SemaRef.CodeSynthesisContexts .empty ()) {
324
- for (auto &CSC : llvm::reverse (SemaRef.CodeSynthesisContexts )) {
325
- if (CSC.Kind != Sema::CodeSynthesisContext::SynthesisKind::
326
- TypeAliasTemplateInstantiation)
327
- continue ;
328
- auto *TATD = cast<TypeAliasTemplateDecl>(CSC.Entity ),
329
- *CurrentTATD = TATD;
330
- FunctionDecl *LambdaCallOperator = Rec->getLambdaCallOperator ();
331
- // Retrieve the 'primary' template for a lambda call operator. It's
332
- // unfortunate that we only have the mappings of call operators rather
333
- // than lambda classes.
334
- while (true ) {
335
- auto *FTD = dyn_cast_if_present<FunctionTemplateDecl>(
336
- LambdaCallOperator->getDescribedTemplate ());
337
- if (FTD && FTD->getInstantiatedFromMemberTemplate ()) {
338
- LambdaCallOperator =
339
- FTD->getInstantiatedFromMemberTemplate ()->getTemplatedDecl ();
340
- } else if (auto *Prev = cast<CXXMethodDecl>(LambdaCallOperator)
341
- ->getInstantiatedFromMemberFunction ())
342
- LambdaCallOperator = Prev;
343
- else
344
- break ;
345
- }
346
- // Same applies for type alias Decl. We perform this to obtain the
347
- // "canonical" template parameter depths.
348
- while (TATD->getInstantiatedFromMemberTemplate ())
349
- TATD = TATD->getInstantiatedFromMemberTemplate ();
350
- // Tell if we're currently inside of a lambda expression that is
351
- // surrounded by a using alias declaration. e.g.
352
- // template <class> using type = decltype([](auto) { ^ }());
353
- // By checking if:
354
- // 1. The lambda expression and the using alias declaration share the
355
- // same declaration context.
356
- // 2. They have the same template depth.
357
- // Then we assume the template arguments from the using alias
358
- // declaration are essential for constraint instantiation. We have to do
359
- // so since a TypeAliasTemplateDecl (or a TypeAliasDecl) is never a
360
- // DeclContext, nor does it have an associated specialization Decl from
361
- // which we could collect these template arguments.
362
- if (cast<CXXRecordDecl>(LambdaCallOperator->getDeclContext ())
363
- ->getTemplateDepth () == TATD->getTemplateDepth () &&
364
- getLambdaAwareParentOfDeclContext (LambdaCallOperator) ==
365
- TATD->getDeclContext ()) {
366
- Result.addOuterTemplateArguments (CurrentTATD,
367
- CSC.template_arguments (),
368
- /* Final=*/ false );
369
- // Visit the parent of the current type alias declaration rather than
370
- // the lambda thereof. We have the following case:
371
- // struct S {
372
- // template <class> using T = decltype([]<Concept> {} ());
373
- // };
374
- // void foo() {
375
- // S::T var;
376
- // }
377
- // The instantiated lambda expression (which we're visiting at 'var')
378
- // has a function DeclContext 'foo' rather than the Record DeclContext
379
- // S. This seems to be an oversight that we may want to set a Sema
380
- // Context from the CXXScopeSpec before substituting into T to me.
381
- return Response::ChangeDecl (CurrentTATD->getDeclContext ());
382
- }
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 ());
383
435
}
384
436
}
385
437
}
@@ -476,7 +528,7 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
476
528
R = HandleClassTemplateSpec (ClassTemplSpec, Result,
477
529
SkipForSpecialization);
478
530
} else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) {
479
- R = HandleFunction (Function, Result, Pattern, RelativeToPrimary,
531
+ R = HandleFunction (* this , Function, Result, Pattern, RelativeToPrimary,
480
532
ForConstraintInstantiation);
481
533
} else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) {
482
534
R = HandleRecordDecl (*this , Rec, Result, Context,
@@ -690,7 +742,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
690
742
: InstantiatingTemplate(
691
743
SemaRef, Sema::CodeSynthesisContext::TypeAliasTemplateInstantiation,
692
744
PointOfInstantiation, InstantiationRange, /* Entity=*/ Template,
693
- nullptr , TemplateArgs) {}
745
+ /* Template= */ nullptr , TemplateArgs) {}
694
746
695
747
Sema::InstantiatingTemplate::InstantiatingTemplate (
696
748
Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template,
0 commit comments