Skip to content

Commit 303fd1b

Browse files
committed
Format & Comments
1 parent 25f493d commit 303fd1b

File tree

5 files changed

+105
-42
lines changed

5 files changed

+105
-42
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10146,6 +10146,7 @@ class Sema final {
1014610146
/// We are building deduction guides for a class.
1014710147
BuildingDeductionGuides,
1014810148

10149+
/// We are instantiating a type alias template declaration.
1014910150
TypeAliasTemplateInstantiation,
1015010151
} Kind;
1015110152

clang/lib/Sema/SemaConcept.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -615,13 +615,18 @@ bool Sema::SetupConstraintScope(
615615
// reference the original primary template.
616616
// We walk up the instantiated template chain so that nested lambdas get
617617
// handled properly.
618-
FunctionTemplateDecl *FromMemTempl =
619-
PrimaryTemplate->getInstantiatedFromMemberTemplate();
620-
while (FromMemTempl && FromMemTempl->getInstantiatedFromMemberTemplate())
621-
FromMemTempl = FromMemTempl->getInstantiatedFromMemberTemplate();
622-
if (FromMemTempl && addInstantiatedParametersToScope(
623-
FD, FromMemTempl->getTemplatedDecl(), Scope, MLTAL))
624-
return true;
618+
// Note that we shall not collect instantiated parameters from
619+
// 'intermediate' transformed function templates but the primary template
620+
// for which we have built up the template arguments relative to. Otherwise,
621+
// we may have mismatched template parameter depth!
622+
if (FunctionTemplateDecl *FromMemTempl =
623+
PrimaryTemplate->getInstantiatedFromMemberTemplate()) {
624+
while (FromMemTempl->getInstantiatedFromMemberTemplate())
625+
FromMemTempl = FromMemTempl->getInstantiatedFromMemberTemplate();
626+
if (addInstantiatedParametersToScope(FD, FromMemTempl->getTemplatedDecl(),
627+
Scope, MLTAL))
628+
return true;
629+
}
625630

626631
return false;
627632
}

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4344,8 +4344,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
43444344
return QualType();
43454345

43464346
InstantiatingTemplate InstTemplate(
4347-
*this, Pattern->getTypeSourceInfo()->getTypeLoc().getBeginLoc(),
4348-
AliasTemplate, TemplateArgLists.getInnermost());
4347+
*this, /*PointOfInstantiation=*/AliasTemplate->getBeginLoc(),
4348+
/*Template=*/AliasTemplate,
4349+
/*TemplateArgs=*/TemplateArgLists.getInnermost());
43494350
CanonType =
43504351
SubstType(Pattern->getUnderlyingType(), TemplateArgLists,
43514352
AliasTemplate->getLocation(), AliasTemplate->getDeclName());

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 65 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -283,8 +283,7 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
283283
return Response::ChangeDecl(FTD->getLexicalDeclContext());
284284
}
285285

286-
Response HandleRecordDecl(Sema &SemaRef,
287-
const CXXRecordDecl *Rec,
286+
Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec,
288287
MultiLevelTemplateArgumentList &Result,
289288
ASTContext &Context,
290289
bool ForConstraintInstantiation) {
@@ -318,35 +317,68 @@ Response HandleRecordDecl(Sema &SemaRef,
318317
if (Rec->isLambda()) {
319318
if (const Decl *LCD = Rec->getLambdaContextDecl())
320319
return Response::ChangeDecl(LCD);
320+
// Attempt to retrieve the template arguments for a using alias declaration.
321+
// This is necessary for constraint checking, since we always keep
322+
// constraints relative to the primary template.
321323
if (ForConstraintInstantiation && !SemaRef.CodeSynthesisContexts.empty()) {
322324
for (auto &CSC : llvm::reverse(SemaRef.CodeSynthesisContexts)) {
323-
if (CSC.Kind == Sema::CodeSynthesisContext::SynthesisKind::TypeAliasTemplateInstantiation) {
324-
auto *TATD = cast<TypeAliasTemplateDecl>(CSC.Entity), *CurrentTATD = TATD;
325-
FunctionDecl *LambdaCallOperator = Rec->getLambdaCallOperator();
326-
while (true) {
327-
auto *FTD = dyn_cast_if_present<FunctionTemplateDecl>(
328-
LambdaCallOperator->getDescribedTemplate());
329-
if (FTD && FTD->getInstantiatedFromMemberTemplate()) {
330-
LambdaCallOperator =
331-
FTD->getInstantiatedFromMemberTemplate()->getTemplatedDecl();
332-
} else if (auto *Prev = cast<CXXMethodDecl>(LambdaCallOperator)
333-
->getInstantiatedFromMemberFunction())
334-
LambdaCallOperator = Prev;
335-
else
336-
break;
337-
}
338-
while (TATD->getInstantiatedFromMemberTemplate())
339-
TATD = TATD->getInstantiatedFromMemberTemplate();
340-
// Constraint template parameters have a deeper depth.
341-
if (cast<CXXRecordDecl>(LambdaCallOperator->getDeclContext())
342-
->getTemplateDepth() == TATD->getTemplateDepth() &&
343-
getLambdaAwareParentOfDeclContext(LambdaCallOperator) ==
344-
TATD->getDeclContext()) {
345-
Result.addOuterTemplateArguments(CurrentTATD,
346-
CSC.template_arguments(),
347-
/*Final=*/false);
348-
return Response::ChangeDecl(CurrentTATD->getDeclContext());
349-
}
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());
350382
}
351383
}
352384
}
@@ -447,7 +479,8 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
447479
R = HandleFunction(Function, Result, Pattern, RelativeToPrimary,
448480
ForConstraintInstantiation);
449481
} else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) {
450-
R = HandleRecordDecl(*this, Rec, Result, Context, ForConstraintInstantiation);
482+
R = HandleRecordDecl(*this, Rec, Result, Context,
483+
ForConstraintInstantiation);
451484
} else if (const auto *CSD =
452485
dyn_cast<ImplicitConceptSpecializationDecl>(CurDecl)) {
453486
R = HandleImplicitConceptSpecializationDecl(CSD, Result);
@@ -1583,7 +1616,8 @@ namespace {
15831616
CXXRecordDecl::LambdaDependencyKind
15841617
ComputeLambdaDependency(LambdaScopeInfo *LSI) {
15851618
auto &CCS = SemaRef.CodeSynthesisContexts.back();
1586-
if (CCS.Kind == Sema::CodeSynthesisContext::TypeAliasTemplateInstantiation) {
1619+
if (CCS.Kind ==
1620+
Sema::CodeSynthesisContext::TypeAliasTemplateInstantiation) {
15871621
unsigned TypeAliasDeclDepth = CCS.Entity->getTemplateDepth();
15881622
if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels())
15891623
return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;

clang/lib/Sema/TreeTransform.h

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -767,8 +767,10 @@ class TreeTransform {
767767
/// the body.
768768
StmtResult SkipLambdaBody(LambdaExpr *E, Stmt *Body);
769769

770-
CXXRecordDecl::LambdaDependencyKind ComputeLambdaDependency(LambdaScopeInfo *LSI) {
771-
return static_cast<CXXRecordDecl::LambdaDependencyKind>(LSI->Lambda->getLambdaDependencyKind());
770+
CXXRecordDecl::LambdaDependencyKind
771+
ComputeLambdaDependency(LambdaScopeInfo *LSI) {
772+
return static_cast<CXXRecordDecl::LambdaDependencyKind>(
773+
LSI->Lambda->getLambdaDependencyKind());
772774
}
773775

774776
QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL);
@@ -13940,8 +13942,28 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
1394013942
/*IsInstantiation*/ true);
1394113943
SavedContext.pop();
1394213944

13945+
// Recompute the dependency of the lambda so that we can defer the lambda call
13946+
// construction until after we have sufficient template arguments. For
13947+
// example, template <class> struct S {
13948+
// template <class U>
13949+
// using Type = decltype([](U){}(42.0));
13950+
// };
13951+
// void foo() {
13952+
// using T = S<int>::Type<float>;
13953+
// ^~~~~~
13954+
// }
13955+
// We would end up here from instantiating the S<int> as we're ensuring the
13956+
// completeness. That would make us transform the lambda call expression
13957+
// despite the fact that we don't see the argument for U yet. We have a
13958+
// mechanism that circumvents the semantic checking if the CallExpr is
13959+
// dependent. We can harness that by recomputing the lambda dependency from
13960+
// the instantiation arguments. I'm putting it here rather than the above
13961+
// since we can see transformed lambda parameters in case that they're
13962+
// useful for calculation.
1394313963
DependencyKind = getDerived().ComputeLambdaDependency(&LSICopy);
1394413964
Class->setLambdaDependencyKind(DependencyKind);
13965+
// Clean up the type cache created previously. Then, we re-create a type for
13966+
// such Decl with the new DependencyKind.
1394513967
Class->setTypeForDecl(nullptr);
1394613968
getSema().Context.getTypeDeclType(Class);
1394713969

0 commit comments

Comments
 (0)