diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7097,7 +7097,8 @@ 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 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -887,11 +887,12 @@ 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 @@ } if (C->Init.isUsable()) { - addInitCapture(LSI, cast(Var)); + addInitCapture(LSI, cast(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 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -13149,7 +13149,7 @@ QualType NewInitCaptureType = getSema().buildLambdaInitCaptureInitialization( - C->getLocation(), OldVD->getType()->isReferenceType(), + C->getLocation(), C->getCaptureKind() == LCK_ByRef, EllipsisLoc, NumExpansions, OldVD->getIdentifier(), cast(C->getCapturedVar())->getInitStyle() != VarDecl::CInit, @@ -13331,7 +13331,7 @@ 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 --- /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 --- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -2306,6 +2306,30 @@ 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 void f(T &...args) {" + " [&...args = args] () mutable {" + " }();" + "}" + "int main() {" + " int a;" + " f(a);" + "}", matcher)); + EXPECT_FALSE(matches("template void f(T &...args) {" + " [...args = args] () mutable {" + " }();" + "}" + "int main() {" + " int a;" + " f(a);" + "}", matcher)); +} + TEST(ASTMatchersTestObjC, ObjCMessageCalees) { StatementMatcher MessagingFoo = objcMessageExpr(callee(objcMethodDecl(hasName("foo"))));