[clang] edbea62 - [clang] Correctly handle by-reference capture with an initializer that is a pack expansion in lambdas.
Jens Massberg via cfe-commits
cfe-commits at lists.llvm.org
Wed Dec 7 07:01:25 PST 2022
Author: Jens Massberg
Date: 2022-12-07T16:00:58+01:00
New Revision: edbea62f72f7b9a5ee19c709d675d6083789c71f
URL: https://github.com/llvm/llvm-project/commit/edbea62f72f7b9a5ee19c709d675d6083789c71f
DIFF: https://github.com/llvm/llvm-project/commit/edbea62f72f7b9a5ee19c709d675d6083789c71f.diff
LOG: [clang] Correctly handle by-reference capture with an initializer that is a pack expansion in lambdas.
Ensure that the correct information whether an init-capture of a lambda
is passed by reference or by copy. This information is already computed
and has to be passed to the place where `NewInitCaptureType` is
created.
Before this fix it has been checked whether the VarDecl is a reference
type. This doesn't work for packed expansions, as the information
whether it is passed by reference or by copy is stored at the pattern of
a `PackExpansionType` and not at the type itself.
However, as the information has been already computed, we just have to
pass it.
Add tests that lambda captures with var decls which are reference types
are created in the AST and a disgnotics test for pack expansions.
Fixes #49266
Differential Revision: https://reviews.llvm.org/D139125
Added:
clang/test/SemaCXX/lambda-pack-expansion.cpp
Modified:
clang/include/clang/Sema/Sema.h
clang/lib/Sema/SemaLambda.cpp
clang/lib/Sema/TreeTransform.h
clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 984de6307ec6..d699ef527e3b 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7097,7 +7097,8 @@ class Sema final {
unsigned InitStyle, Expr *Init);
/// Add an init-capture to a lambda scope.
- void addInitCapture(sema::LambdaScopeInfo *LSI, VarDecl *Var);
+ void addInitCapture(sema::LambdaScopeInfo *LSI, VarDecl *Var,
+ bool isReferenceType);
/// Note that we have finished the explicit captures for the
/// given lambda.
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 176b9c6a432c..bdca002e740e 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -887,11 +887,12 @@ VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
return NewVD;
}
-void Sema::addInitCapture(LambdaScopeInfo *LSI, VarDecl *Var) {
+void Sema::addInitCapture(LambdaScopeInfo *LSI, VarDecl *Var,
+ bool isReferenceType) {
assert(Var->isInitCapture() && "init capture flag should be set");
- LSI->addCapture(Var, /*isBlock*/false, Var->getType()->isReferenceType(),
- /*isNested*/false, Var->getLocation(), SourceLocation(),
- Var->getType(), /*Invalid*/false);
+ LSI->addCapture(Var, /*isBlock*/ false, isReferenceType,
+ /*isNested*/ false, Var->getLocation(), SourceLocation(),
+ Var->getType(), /*Invalid*/ false);
}
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
@@ -1261,7 +1262,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
}
if (C->Init.isUsable()) {
- addInitCapture(LSI, cast<VarDecl>(Var));
+ addInitCapture(LSI, cast<VarDecl>(Var), C->Kind == LCK_ByRef);
} else {
TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
TryCapture_ExplicitByVal;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 4fa91a69661b..c60c7311bbda 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13149,7 +13149,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
QualType NewInitCaptureType =
getSema().buildLambdaInitCaptureInitialization(
- C->getLocation(), OldVD->getType()->isReferenceType(),
+ C->getLocation(), C->getCaptureKind() == LCK_ByRef,
EllipsisLoc, NumExpansions, OldVD->getIdentifier(),
cast<VarDecl>(C->getCapturedVar())->getInitStyle() !=
VarDecl::CInit,
@@ -13331,7 +13331,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
break;
}
NewVDs.push_back(NewVD);
- getSema().addInitCapture(LSI, NewVD);
+ getSema().addInitCapture(LSI, NewVD, C->getCaptureKind() == LCK_ByRef);
}
if (Invalid)
diff --git a/clang/test/SemaCXX/lambda-pack-expansion.cpp b/clang/test/SemaCXX/lambda-pack-expansion.cpp
new file mode 100644
index 000000000000..e3e968e2704e
--- /dev/null
+++ b/clang/test/SemaCXX/lambda-pack-expansion.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -std=c++20 -Wno-unused-value -fsyntax-only -verify %s
+
+namespace GH49266 {
+struct X {
+ X() = default;
+ X(X const&) = delete; // expected-note {{'X' has been explicitly marked deleted here}}
+};
+
+void take_by_copy(auto &...args) {
+ [...args = args] {}(); // expected-error {{call to deleted constructor}}
+}
+
+void take_by_ref(auto &...args) {
+ [&...args = args] {}(); // args is passed by reference and not copied.
+}
+
+void foo() {
+ X x;
+ take_by_copy(x); // expected-note {{in instantiation of function template specialization}}
+ take_by_ref(x);
+}
+}
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
index 257885cc5d79..6c3a878d97de 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -2306,6 +2306,30 @@ TEST_P(ASTMatchersTest,
hasName("cc"), hasInitializer(integerLiteral(equals(1))))))))));
}
+TEST_P(ASTMatchersTest, LambdaCaptureTest_BindsToCaptureOfReferenceType) {
+ if (!GetParam().isCXX20OrLater()) {
+ return;
+ }
+ auto matcher = lambdaExpr(hasAnyCapture(
+ lambdaCapture(capturesVar(varDecl(hasType(referenceType()))))));
+ EXPECT_TRUE(matches("template <class ...T> void f(T &...args) {"
+ " [&...args = args] () mutable {"
+ " }();"
+ "}"
+ "int main() {"
+ " int a;"
+ " f(a);"
+ "}", matcher));
+ EXPECT_FALSE(matches("template <class ...T> void f(T &...args) {"
+ " [...args = args] () mutable {"
+ " }();"
+ "}"
+ "int main() {"
+ " int a;"
+ " f(a);"
+ "}", matcher));
+}
+
TEST(ASTMatchersTestObjC, ObjCMessageCalees) {
StatementMatcher MessagingFoo =
objcMessageExpr(callee(objcMethodDecl(hasName("foo"))));
More information about the cfe-commits
mailing list