blob: f35941c81f953a1c41bea379c96526f09c7a88d9 [file] [log] [blame]
commit 61d1cce2f83571c00f76144d42a2dea2cb3ab1ca
Author: Yuanfang Chen <yuanfang.chen@sony.com>
Date: Tue Sep 7 15:28:19 2021 -0700
PR45881: Properly use CXXThisOverride for templated lambda
- `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 c3d2ebb60f604.
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D102531
---
clang/lib/Sema/SemaExprCXX.cpp | 9 +++----
clang/lib/Sema/SemaTemplate.cpp | 6 ++++-
clang/lib/Sema/SemaTemplateDeduction.cpp | 21 ++++++++++++---
clang/test/SemaCXX/cxx1z-lambda-star-this.cpp | 10 ++++++++
clang/test/SemaCXX/cxx20-lambda-decltype-this.cpp | 31 +++++++++++++++++++++++
5 files changed, 68 insertions(+), 9 deletions(-)
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index ba2e17c4a631..e30e1bb7df78 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -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 "
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 5d26f2d2c11a..6682b17f4e14 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -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());
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 5d93a1792226..f0a9e820c028 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -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()) {
diff --git a/clang/test/SemaCXX/cxx1z-lambda-star-this.cpp b/clang/test/SemaCXX/cxx1z-lambda-star-this.cpp
index 2426e8f5a207..5a471fd6b694 100644
--- a/clang/test/SemaCXX/cxx1z-lambda-star-this.cpp
+++ b/clang/test/SemaCXX/cxx1z-lambda-star-this.cpp
@@ -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
diff --git a/clang/test/SemaCXX/cxx20-lambda-decltype-this.cpp b/clang/test/SemaCXX/cxx20-lambda-decltype-this.cpp
new file mode 100644
index 000000000000..161a2bcb25d7
--- /dev/null
+++ b/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