From 06524af944fcdebba05ea4f4dddf612ccee421d7 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 6 Feb 2014 21:49:08 +0000 Subject: [PATCH] PR18128: a lambda capture-default is not permitted for a non-local lambda expression. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@200948 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 2 ++ lib/Sema/SemaLambda.cpp | 19 ++++++++++++++++++- test/SemaCXX/lambda-expressions.cpp | 22 +++++++++++++++++++++- unittests/ASTMatchers/ASTMatchersTest.cpp | 2 +- 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 550e9c11b4..c06a086eaf 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -952,6 +952,8 @@ def err_capture_of_abstract_type : Error< "by-copy capture of value of abstract type %0">; def err_capture_of_incomplete_type : Error< "by-copy capture of variable %0 with incomplete type %1">; +def err_capture_default_non_local : Error< + "non-local lambda expression cannot have a capture-default">; def err_multiple_final_overriders : Error< "virtual function %q0 has more than one final overrider in %1">; diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 5d282cb6fc..8c1b57fd0f 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -256,7 +256,7 @@ CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange, IsGenericLambda, CaptureDefault); DC->addDecl(Class); - + return Class; } @@ -935,6 +935,23 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, ExplicitResultType, !Method->isConst()); + // C++11 [expr.prim.lambda]p9: + // A lambda-expression whose smallest enclosing scope is a block scope is a + // local lambda expression; any other lambda expression shall not have a + // capture-default or simple-capture in its lambda-introducer. + // + // For simple-captures, this is covered by the check below that any named + // entity is a variable that can be captured. + // + // For DR1632, we also allow a capture-default in any context where we can + // odr-use 'this' (in particular, in a default initializer for a non-static + // data member). + if (Intro.Default != LCD_None && !Class->getParent()->isFunctionOrMethod() && + (getCurrentThisType().isNull() || + CheckCXXThisCapture(SourceLocation(), /*Explicit*/true, + /*BuildAndDiagnose*/false))) + Diag(Intro.DefaultLoc, diag::err_capture_default_non_local); + // Distinct capture names, for diagnostics. llvm::SmallSet CaptureNames; diff --git a/test/SemaCXX/lambda-expressions.cpp b/test/SemaCXX/lambda-expressions.cpp index 28a2a744f5..018df002db 100644 --- a/test/SemaCXX/lambda-expressions.cpp +++ b/test/SemaCXX/lambda-expressions.cpp @@ -291,7 +291,7 @@ namespace NSDMIs_in_lambdas { void f() { []() { S s; }; } auto x = []{ struct S { int n, m = n; }; }; - auto y = [&]{ struct S { int n, m = n; }; }; + auto y = [&]{ struct S { int n, m = n; }; }; // expected-error {{non-local lambda expression cannot have a capture-default}} void g() { auto z = [&]{ struct S { int n, m = n; }; }; } } @@ -324,3 +324,23 @@ namespace CaptureAbstract { [=] { return s.n; }; // expected-error {{abstract}} } } + +namespace PR18128 { + auto l = [=]{}; // expected-error {{non-local lambda expression cannot have a capture-default}} + + struct S { + int n; + int (*f())[true ? 1 : ([=]{ return n; }(), 0)]; + // expected-error@-1 {{non-local lambda expression cannot have a capture-default}} + // expected-error@-2 {{invalid use of non-static data member 'n'}} + // expected-error@-3 {{a lambda expression may not appear inside of a constant expression}} + int g(int k = ([=]{ return n; }(), 0)); + // expected-error@-1 {{non-local lambda expression cannot have a capture-default}} + // expected-error@-2 {{invalid use of non-static data member 'n'}} + + int a = [=]{ return n; }(); // ok + int b = [=]{ return [=]{ return n; }(); }(); // ok + int c = []{ int k = 0; return [=]{ return k; }(); }(); // ok + int d = []{ return [=]{ return n; }(); }(); // expected-error {{'this' cannot be implicitly captured in this context}} + }; +} diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp index a76903fc4a..8825174c49 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -1000,7 +1000,7 @@ TEST(Matcher, Call) { } TEST(Matcher, Lambda) { - EXPECT_TRUE(matches("auto f = [&] (int i) { return i; };", + EXPECT_TRUE(matches("auto f = [] (int i) { return i; };", lambdaExpr())); } -- 2.40.0