r344801 - PR24164, PR39336: init-captures are not distinct full-expressions.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 19 12:01:34 PDT 2018
Author: rsmith
Date: Fri Oct 19 12:01:34 2018
New Revision: 344801
URL: http://llvm.org/viewvc/llvm-project?rev=344801&view=rev
Log:
PR24164, PR39336: init-captures are not distinct full-expressions.
Rather, they are subexpressions of the enclosing lambda-expression, and
any temporaries in them are destroyed at the end of that
full-expression, or when the corresponding lambda-expression is
destroyed if they are lifetime-extended.
Modified:
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/AST/Expr.cpp
cfe/trunk/lib/CodeGen/CGExprCXX.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/lib/Sema/SemaLambda.cpp
cfe/trunk/test/CXX/special/class.temporary/p6.cpp
cfe/trunk/test/CodeGenCXX/cxx1y-init-captures.cpp
cfe/trunk/test/SemaCXX/cxx1y-init-captures.cpp
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=344801&r1=344800&r2=344801&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Oct 19 12:01:34 2018
@@ -5315,8 +5315,7 @@ public:
}
ExprResult ActOnFinishFullExpr(Expr *Expr, SourceLocation CC,
bool DiscardedValue = false,
- bool IsConstexpr = false,
- bool IsLambdaInitCaptureInitializer = false);
+ bool IsConstexpr = false);
StmtResult ActOnFinishFullStmt(Stmt *Stmt);
// Marks SS invalid if it represents an incomplete type.
Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=344801&r1=344800&r2=344801&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Fri Oct 19 12:01:34 2018
@@ -3255,11 +3255,8 @@ bool Expr::HasSideEffects(const ASTConte
case LambdaExprClass: {
const LambdaExpr *LE = cast<LambdaExpr>(this);
- for (LambdaExpr::capture_iterator I = LE->capture_begin(),
- E = LE->capture_end(); I != E; ++I)
- if (I->getCaptureKind() == LCK_ByCopy)
- // FIXME: Only has a side-effect if the variable is volatile or if
- // the copy would invoke a non-trivial copy constructor.
+ for (Expr *E : LE->capture_inits())
+ if (E->HasSideEffects(Ctx, IncludePossibleEffects))
return true;
return false;
}
Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=344801&r1=344800&r2=344801&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Fri Oct 19 12:01:34 2018
@@ -2252,7 +2252,6 @@ llvm::Value *CodeGenFunction::EmitDynami
}
void CodeGenFunction::EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Slot) {
- RunCleanupsScope Scope(*this);
LValue SlotLV = MakeAddrLValue(Slot.getAddress(), E->getType());
CXXRecordDecl::field_iterator CurField = E->getLambdaClass()->field_begin();
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=344801&r1=344800&r2=344801&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Oct 19 12:01:34 2018
@@ -7764,41 +7764,24 @@ Sema::CorrectDelayedTyposInExpr(Expr *E,
ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
bool DiscardedValue,
- bool IsConstexpr,
- bool IsLambdaInitCaptureInitializer) {
+ bool IsConstexpr) {
ExprResult FullExpr = FE;
if (!FullExpr.get())
return ExprError();
- // If we are an init-expression in a lambdas init-capture, we should not
- // diagnose an unexpanded pack now (will be diagnosed once lambda-expr
- // containing full-expression is done).
- // template<class ... Ts> void test(Ts ... t) {
- // test([&a(t)]() { <-- (t) is an init-expr that shouldn't be diagnosed now.
- // return a;
- // }() ...);
- // }
- // FIXME: This is a hack. It would be better if we pushed the lambda scope
- // when we parse the lambda introducer, and teach capturing (but not
- // unexpanded pack detection) to walk over LambdaScopeInfos which don't have a
- // corresponding class yet (that is, have LambdaScopeInfo either represent a
- // lambda where we've entered the introducer but not the body, or represent a
- // lambda where we've entered the body, depending on where the
- // parser/instantiation has got to).
- if (!IsLambdaInitCaptureInitializer &&
- DiagnoseUnexpandedParameterPack(FullExpr.get()))
+ if (DiagnoseUnexpandedParameterPack(FullExpr.get()))
return ExprError();
- // Top-level expressions default to 'id' when we're in a debugger.
- if (DiscardedValue && getLangOpts().DebuggerCastResultToId &&
- FullExpr.get()->getType() == Context.UnknownAnyTy) {
- FullExpr = forceUnknownAnyToType(FullExpr.get(), Context.getObjCIdType());
- if (FullExpr.isInvalid())
- return ExprError();
- }
-
if (DiscardedValue) {
+ // Top-level expressions default to 'id' when we're in a debugger.
+ if (getLangOpts().DebuggerCastResultToId &&
+ FullExpr.get()->getType() == Context.UnknownAnyTy) {
+ FullExpr = forceUnknownAnyToType(FullExpr.get(), Context.getObjCIdType());
+ if (FullExpr.isInvalid())
+ return ExprError();
+ }
+
FullExpr = CheckPlaceholderExpr(FullExpr.get());
if (FullExpr.isInvalid())
return ExprError();
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=344801&r1=344800&r2=344801&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Fri Oct 19 12:01:34 2018
@@ -6786,6 +6786,20 @@ static void visitLocalsRetainedByInitial
return;
}
+ // The lifetime of an init-capture is that of the closure object constructed
+ // by a lambda-expression.
+ if (auto *LE = dyn_cast<LambdaExpr>(Init)) {
+ for (Expr *E : LE->capture_inits()) {
+ if (!E)
+ continue;
+ if (E->isGLValue())
+ visitLocalsRetainedByReferenceBinding(Path, E, RK_ReferenceBinding,
+ Visit);
+ else
+ visitLocalsRetainedByInitializer(Path, E, Visit, true);
+ }
+ }
+
if (isa<CallExpr>(Init) || isa<CXXConstructExpr>(Init))
return visitLifetimeBoundArguments(Path, Init, Visit);
Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=344801&r1=344800&r2=344801&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Fri Oct 19 12:01:34 2018
@@ -775,16 +775,6 @@ QualType Sema::buildLambdaInitCaptureIni
if (Result.isInvalid())
return QualType();
- Init = Result.getAs<Expr>();
-
- // The init-capture initialization is a full-expression that must be
- // processed as one before we enter the declcontext of the lambda's
- // call-operator.
- Result = ActOnFinishFullExpr(Init, Loc, /*DiscardedValue*/ false,
- /*IsConstexpr*/ false,
- /*IsLambdaInitCaptureInitializer*/ true);
- if (Result.isInvalid())
- return QualType();
Init = Result.getAs<Expr>();
return DeducedType;
Modified: cfe/trunk/test/CXX/special/class.temporary/p6.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.temporary/p6.cpp?rev=344801&r1=344800&r2=344801&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.temporary/p6.cpp (original)
+++ cfe/trunk/test/CXX/special/class.temporary/p6.cpp Fri Oct 19 12:01:34 2018
@@ -1,4 +1,15 @@
-// RUN: %clang_cc1 -std=c++17 %s -emit-llvm -o - | FileCheck %s --implicit-check-not='call{{.*}}dtor'
+// RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --implicit-check-not='call{{.*}}dtor'
+
+namespace std {
+ typedef decltype(sizeof(int)) size_t;
+
+ template <class E>
+ struct initializer_list {
+ const E *begin;
+ size_t size;
+ initializer_list() : begin(nullptr), size(0) {}
+ };
+}
void then();
@@ -8,6 +19,14 @@ struct dtor {
dtor ctor();
+auto &&lambda = [a = {ctor()}] {};
+// CHECK-LABEL: define
+// CHECK: call {{.*}}ctor
+// CHECK: call {{.*}}atexit{{.*}}global_array_dtor
+
+// CHECK-LABEL: define{{.*}}global_array_dtor
+// CHECK: call {{.*}}dtor
+
// [lifetime extension occurs if the object was obtained by]
// -- a temporary materialization conversion
// CHECK-LABEL: ref_binding
@@ -186,5 +205,36 @@ void comma() {
// CHECK: call {{.*}}then
then();
// CHECK: call {{.*}}dtor
+ // CHECK: }
+}
+
+
+// This applies recursively: if an object is lifetime-extended and contains a
+// reference, the referent is also extended.
+// CHECK-LABEL: init_capture_ref
+void init_capture_ref() {
+ // CHECK: call {{.*}}ctor
+ auto x = [&a = (const dtor&)ctor()] {};
+ // CHECK: call {{.*}}then
+ then();
+ // CHECK: call {{.*}}dtor
+ // CHECK: }
+}
+// CHECK-LABEL: init_capture_ref_indirect
+void init_capture_ref_indirect() {
+ // CHECK: call {{.*}}ctor
+ auto x = [&a = (const dtor&)ctor()] {};
+ // CHECK: call {{.*}}then
+ then();
+ // CHECK: call {{.*}}dtor
+ // CHECK: }
+}
+// CHECK-LABEL: init_capture_init_list
+void init_capture_init_list() {
+ // CHECK: call {{.*}}ctor
+ auto x = [a = {ctor()}] {};
+ // CHECK: call {{.*}}then
+ then();
+ // CHECK: call {{.*}}dtor
// CHECK: }
}
Modified: cfe/trunk/test/CodeGenCXX/cxx1y-init-captures.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx1y-init-captures.cpp?rev=344801&r1=344800&r2=344801&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx1y-init-captures.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/cxx1y-init-captures.cpp Fri Oct 19 12:01:34 2018
@@ -38,6 +38,19 @@ void g() {
// CHECK: add nsw i32
+// CHECK-LABEL: define void @_Z18init_capture_dtorsv
+void init_capture_dtors() {
+ // Ensure that init-captures are not treated as separate full-expressions.
+ struct HasDtor { ~HasDtor() {} };
+ void some_function_call();
+ void other_function_call();
+ // CHECK: call {{.*}}some_function_call
+ // CHECK: call {{.*}}HasDtorD
+ ([x = (HasDtor(), 0)]{}, some_function_call());
+ // CHECK: call {{.*}}other_function_call
+ other_function_call();
+}
+
int h(int a) {
// CHECK-LABEL: define i32 @_Z1hi(
// CHECK: %[[A_ADDR:.*]] = alloca i32,
Modified: cfe/trunk/test/SemaCXX/cxx1y-init-captures.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-init-captures.cpp?rev=344801&r1=344800&r2=344801&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1y-init-captures.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx1y-init-captures.cpp Fri Oct 19 12:01:34 2018
@@ -144,13 +144,13 @@ int test(T t = T{}) {
};
}
{ // will need to capture x in outer lambda
- const int x = 10; //expected-note 2{{declared}}
- auto L = [z = x](char a) { //expected-note 2{{begins}}
- auto M = [&y = x](T b) { //expected-error 2{{cannot be implicitly captured}}
+ const int x = 10; //expected-note {{declared}}
+ auto L = [z = x](char a) { //expected-note {{begins}}
+ auto M = [&y = x](T b) { //expected-error {{cannot be implicitly captured}}
return y;
};
return M;
- };
+ };
}
{
// no captures
More information about the cfe-commits
mailing list