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