Skip to content

Commit 92f8cfb

Browse files
committed
[Clang][Sema] Revisit the lambda within a type alias template decl
1 parent 3ea9ed4 commit 92f8cfb

File tree

2 files changed

+64
-35
lines changed

2 files changed

+64
-35
lines changed

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "clang/AST/Expr.h"
2121
#include "clang/AST/ExprConcepts.h"
2222
#include "clang/AST/PrettyDeclStackTrace.h"
23+
#include "clang/AST/RecursiveASTVisitor.h"
2324
#include "clang/AST/Type.h"
2425
#include "clang/AST/TypeLoc.h"
2526
#include "clang/AST/TypeVisitor.h"
@@ -87,12 +88,19 @@ struct Response {
8788
// than lambda classes.
8889
const FunctionDecl *
8990
getPrimaryTemplateOfGenericLambda(const FunctionDecl *LambdaCallOperator) {
91+
if (!isLambdaCallOperator(LambdaCallOperator))
92+
return LambdaCallOperator;
9093
while (true) {
9194
if (auto *FTD = dyn_cast_if_present<FunctionTemplateDecl>(
9295
LambdaCallOperator->getDescribedTemplate());
9396
FTD && FTD->getInstantiatedFromMemberTemplate()) {
9497
LambdaCallOperator =
9598
FTD->getInstantiatedFromMemberTemplate()->getTemplatedDecl();
99+
} else if (LambdaCallOperator->getPrimaryTemplate()) {
100+
// Cases where the lambda operator is instantiated in
101+
// TemplateDeclInstantiator::VisitCXXMethodDecl.
102+
LambdaCallOperator =
103+
LambdaCallOperator->getPrimaryTemplate()->getTemplatedDecl();
96104
} else if (auto *Prev = cast<CXXMethodDecl>(LambdaCallOperator)
97105
->getInstantiatedFromMemberFunction())
98106
LambdaCallOperator = Prev;
@@ -138,22 +146,30 @@ getEnclosingTypeAliasTemplateDecl(Sema &SemaRef) {
138146
// Check if we are currently inside of a lambda expression that is
139147
// surrounded by a using alias declaration. e.g.
140148
// template <class> using type = decltype([](auto) { ^ }());
141-
// By checking if:
142-
// 1. The lambda expression and the using alias declaration share the
143-
// same declaration context.
144-
// 2. They have the same template depth.
145149
// We have to do so since a TypeAliasTemplateDecl (or a TypeAliasDecl) is never
146150
// a DeclContext, nor does it have an associated specialization Decl from which
147151
// we could collect these template arguments.
148152
bool isLambdaEnclosedByTypeAliasDecl(
149-
const FunctionDecl *PrimaryLambdaCallOperator,
153+
const FunctionDecl *LambdaCallOperator,
150154
const TypeAliasTemplateDecl *PrimaryTypeAliasDecl) {
151-
return cast<CXXRecordDecl>(PrimaryLambdaCallOperator->getDeclContext())
152-
->getTemplateDepth() ==
153-
PrimaryTypeAliasDecl->getTemplateDepth() &&
154-
getLambdaAwareParentOfDeclContext(
155-
const_cast<FunctionDecl *>(PrimaryLambdaCallOperator)) ==
156-
PrimaryTypeAliasDecl->getDeclContext();
155+
struct Visitor : RecursiveASTVisitor<Visitor> {
156+
Visitor(const FunctionDecl *CallOperator) : CallOperator(CallOperator) {}
157+
bool VisitLambdaExpr(const LambdaExpr *LE) {
158+
// Return true to bail out of the traversal, implying the Decl contains
159+
// the lambda.
160+
return getPrimaryTemplateOfGenericLambda(LE->getCallOperator()) !=
161+
CallOperator;
162+
}
163+
const FunctionDecl *CallOperator;
164+
};
165+
166+
QualType Underlying =
167+
PrimaryTypeAliasDecl->getTemplatedDecl()->getUnderlyingType();
168+
169+
if (auto *DT = dyn_cast<DecltypeType>(Underlying.getTypePtr()))
170+
return !Visitor(getPrimaryTemplateOfGenericLambda(LambdaCallOperator))
171+
.TraverseStmt(DT->getUnderlyingExpr());
172+
return false;
157173
}
158174

159175
// Add template arguments from a variable template instantiation.
@@ -283,23 +299,8 @@ Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
283299

284300
// If this function is a generic lambda specialization, we are done.
285301
if (!ForConstraintInstantiation &&
286-
isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) {
287-
// TypeAliasTemplateDecls should be taken into account, e.g.
288-
// when we're deducing the return type of a lambda.
289-
//
290-
// template <class> int Value = 0;
291-
// template <class T>
292-
// using T = decltype([]<int U = 0>() { return Value<T>; }());
293-
//
294-
if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(SemaRef)) {
295-
if (isLambdaEnclosedByTypeAliasDecl(
296-
/*PrimaryLambdaCallOperator=*/getPrimaryTemplateOfGenericLambda(
297-
Function),
298-
/*PrimaryTypeAliasDecl=*/TypeAlias.PrimaryTypeAliasDecl))
299-
return Response::UseNextDecl(Function);
300-
}
302+
isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
301303
return Response::Done();
302-
}
303304

304305
} else if (Function->getDescribedFunctionTemplate()) {
305306
assert(
@@ -412,9 +413,7 @@ Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec,
412413
// This is necessary for constraint checking, since we always keep
413414
// constraints relative to the primary template.
414415
if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(SemaRef)) {
415-
const FunctionDecl *PrimaryLambdaCallOperator =
416-
getPrimaryTemplateOfGenericLambda(Rec->getLambdaCallOperator());
417-
if (isLambdaEnclosedByTypeAliasDecl(PrimaryLambdaCallOperator,
416+
if (isLambdaEnclosedByTypeAliasDecl(Rec->getLambdaCallOperator(),
418417
TypeAlias.PrimaryTypeAliasDecl)) {
419418
Result.addOuterTemplateArguments(TypeAlias.Template,
420419
TypeAlias.AssociatedTemplateArguments,
@@ -1670,12 +1669,17 @@ namespace {
16701669

16711670
CXXRecordDecl::LambdaDependencyKind
16721671
ComputeLambdaDependency(LambdaScopeInfo *LSI) {
1673-
auto &CCS = SemaRef.CodeSynthesisContexts.back();
1674-
if (CCS.Kind ==
1675-
Sema::CodeSynthesisContext::TypeAliasTemplateInstantiation) {
1676-
unsigned TypeAliasDeclDepth = CCS.Entity->getTemplateDepth();
1672+
if (auto TypeAlias =
1673+
TemplateInstArgsHelpers::getEnclosingTypeAliasTemplateDecl(
1674+
getSema());
1675+
TypeAlias && TemplateInstArgsHelpers::isLambdaEnclosedByTypeAliasDecl(
1676+
LSI->CallOperator, TypeAlias.PrimaryTypeAliasDecl)) {
1677+
unsigned TypeAliasDeclDepth = TypeAlias.Template->getTemplateDepth();
16771678
if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels())
16781679
return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
1680+
for (const TemplateArgument &TA : TypeAlias.AssociatedTemplateArguments)
1681+
if (TA.isDependent())
1682+
return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
16791683
}
16801684
return inherited::ComputeLambdaDependency(LSI);
16811685
}

clang/test/SemaTemplate/alias-template-with-lambdas.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,37 @@ namespace GH82104 {
9494
template <typename, typename...> int Zero = 0;
9595

9696
template <typename T, typename...U>
97-
using T14 = decltype([]<int V = 0>() { return Zero<T, U...>; }());
97+
using T14 = decltype([]<int V = 0>(auto Param) {
98+
return Zero<T, U...> + V + (int)sizeof(Param);
99+
}("hello"));
98100

99101
template <typename T> using T15 = T14<T, T>;
100102

101103
static_assert(__is_same(T15<char>, int));
102104

103105
} // namespace GH82104
104106

107+
namespace GH89853 {
108+
template <typename = void>
109+
static constexpr auto innocuous = []<int m> { return m; };
110+
111+
template <auto Pred = innocuous<>>
112+
using broken = decltype(Pred.template operator()<42>());
113+
114+
broken<> *boom;
115+
116+
template <auto Pred =
117+
[]<const char c> {
118+
(void)static_cast<char>(c);
119+
}>
120+
using broken2 = decltype(Pred.template operator()<42>());
121+
122+
broken2<> *boom2;
123+
124+
template <auto Pred = []<const char m> { return m; }>
125+
using broken3 = decltype(Pred.template operator()<42>());
126+
127+
broken3<> *boom3;
128+
}
129+
105130
} // namespace lambda_calls

0 commit comments

Comments
 (0)