Skip to content

Commit

Permalink
PR45881: Properly use CXXThisOverride for templated lambda
Browse files Browse the repository at this point in the history
- `this` used in lambda expression parameter declarations needs no capture.
- Set up CXXThisOverride for default template arguments of a lambda.

A similar fix to this is c3d2ebb.

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D102531
  • Loading branch information
Yuanfang Chen committed Sep 8, 2021
1 parent 79c00d3 commit 61d1cce
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 9 deletions.
9 changes: 4 additions & 5 deletions clang/lib/Sema/SemaExprCXX.cpp
Expand Up @@ -1137,11 +1137,10 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda(
}
}

// 2) We've run out of ScopeInfos but check if CurDC is a lambda (which can
// happen during instantiation of its nested generic lambda call operator)
if (isLambdaCallOperator(CurDC)) {
assert(CurLSI && "While computing 'this' capture-type for a generic "
"lambda, we must have a corresponding LambdaScopeInfo");
// 2) We've run out of ScopeInfos but check 1. if CurDC is a lambda (which
// can happen during instantiation of its nested generic lambda call
// operator); 2. if we're in a lambda scope (lambda body).
if (CurLSI && isLambdaCallOperator(CurDC)) {
assert(isGenericLambdaCallOperatorSpecialization(CurLSI->CallOperator) &&
"While computing 'this' capture-type for a generic lambda, when we "
"run out of enclosing LSI's, yet the enclosing DC is a "
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Sema/SemaTemplate.cpp
Expand Up @@ -5110,7 +5110,11 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
TemplateArgLists.addOuterTemplateArguments(None);

Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
bool ForLambdaCallOperator = false;
if (const auto *Rec = dyn_cast<CXXRecordDecl>(Template->getDeclContext()))
ForLambdaCallOperator = Rec->isLambda();
Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext(),
!ForLambdaCallOperator);
ArgType =
SemaRef.SubstType(ArgType, TemplateArgLists,
Param->getDefaultArgumentLoc(), Param->getDeclName());
Expand Down
21 changes: 18 additions & 3 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Expand Up @@ -2858,9 +2858,24 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
return Sema::TDK_Incomplete;
}

TemplateArgumentLoc DefArg = S.SubstDefaultTemplateArgumentIfAvailable(
TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param, Builder,
HasDefaultArg);
TemplateArgumentLoc DefArg;
{
Qualifiers ThisTypeQuals;
CXXRecordDecl *ThisContext = nullptr;
if (auto *Rec = dyn_cast<CXXRecordDecl>(TD->getDeclContext()))
if (Rec->isLambda())
if (auto *Method = dyn_cast<CXXMethodDecl>(Rec->getDeclContext())) {
ThisContext = Method->getParent();
ThisTypeQuals = Method->getMethodQualifiers();
}

Sema::CXXThisScopeRAII ThisScope(S, ThisContext, ThisTypeQuals,
S.getLangOpts().CPlusPlus17);

DefArg = S.SubstDefaultTemplateArgumentIfAvailable(
TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param, Builder,
HasDefaultArg);
}

// If there was no default argument, deduction is incomplete.
if (DefArg.getArgument().isNull()) {
Expand Down
10 changes: 10 additions & 0 deletions clang/test/SemaCXX/cxx1z-lambda-star-this.cpp
Expand Up @@ -298,3 +298,13 @@ class A {

} // namespace PR32831

namespace PR45881 {
struct A {
void f();
};
int id(A*);
void A::f() {
auto z = [*this](auto z2, decltype(z2(this)) z3){};
z(id,3);
}
} // namespace PR45881
31 changes: 31 additions & 0 deletions clang/test/SemaCXX/cxx20-lambda-decltype-this.cpp
@@ -0,0 +1,31 @@
// RUN: %clang_cc1 -std=c++2a -fsyntax-only -emit-llvm-only %s
// RUN: %clang_cc1 -std=c++2a -fsyntax-only -fdelayed-template-parsing %s
// RUN: %clang_cc1 -std=c++2a -fsyntax-only -fms-extensions %s
// RUN: %clang_cc1 -std=c++2a -fsyntax-only -fdelayed-template-parsing -fms-extensions %s

namespace PR45881 {
struct A {
void f();
};
int id(A*);
void A::f() {
auto z = [*this](auto z2, decltype(z2(this)) z3){};
z(id,3);
}

struct B {
void f();
};
void B::f() {
auto z = []<typename TT, typename TTT=decltype(TT()(this))>(){return 0;};
z.template operator()<int(*)(B*)>();
}

struct C {
void f();
};
void C::f() {
auto z = []<typename TT, decltype(TT()(this)) n>(){return 0;};
z.template operator()<int(*)(C*), 8>();
}
} // namespace PR45881

0 comments on commit 61d1cce

Please sign in to comment.