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")))); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits