From: Richard Smith Date: Sun, 2 Jun 2013 00:09:52 +0000 (+0000) Subject: PR12848: When emitting a local variable declared 'constexpr', always initialize it... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e67ca5803ac9e39cc31ed1ad9576e1626c8141eb;p=clang PR12848: When emitting a local variable declared 'constexpr', always initialize it with a store or a memcpy, not by emitting the initializer expression. This is not required for correctness, but more closely aligns with people's expectations, and is cheap (since we've already evaluated the initializer). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@183082 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 9741f5878e..4b19b54df5 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -840,19 +840,19 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { bool NRVO = getLangOpts().ElideConstructors && D.isNRVOVariable(); - // If this value is a POD array or struct with a statically - // determinable constant initializer, there are optimizations we can do. + // If this value is an array or struct with a statically determinable + // constant initializer, there are optimizations we can do. // // TODO: We should constant-evaluate the initializer of any variable, // as long as it is initialized by a constant expression. Currently, // isConstantInitializer produces wrong answers for structs with // reference or bitfield members, and a few other cases, and checking // for POD-ness protects us from some of these. - if (D.getInit() && - (Ty->isArrayType() || Ty->isRecordType()) && - (Ty.isPODType(getContext()) || - getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) && - D.getInit()->isConstantInitializer(getContext(), false)) { + if (D.getInit() && (Ty->isArrayType() || Ty->isRecordType()) && + (D.isConstexpr() || + ((Ty.isPODType(getContext()) || + getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) && + D.getInit()->isConstantInitializer(getContext(), false)))) { // If the variable's a const type, and it's neither an NRVO // candidate nor a __block variable and has no mutable members, @@ -1080,7 +1080,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { capturedByInit ? emission.Address : emission.getObjectAddress(*this); llvm::Constant *constant = 0; - if (emission.IsConstantAggregate) { + if (emission.IsConstantAggregate || D.isConstexpr()) { assert(!capturedByInit && "constant init contains a capturing block?"); constant = CGM.EmitConstantInit(D, this); } @@ -1091,6 +1091,13 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { return EmitExprAsInit(Init, &D, lv, capturedByInit); } + if (!emission.IsConstantAggregate) { + // For simple scalar/complex initialization, store the value directly. + LValue lv = MakeAddrLValue(Loc, type, alignment); + lv.setNonGC(true); + return EmitStoreThroughLValue(RValue::get(constant), lv, true); + } + // If this is a simple aggregate initialization, we can optimize it // in various ways. bool isVolatile = type.isVolatileQualified(); diff --git a/test/CodeGenCXX/blocks-cxx11.cpp b/test/CodeGenCXX/blocks-cxx11.cpp index 3f0380abbd..42d33ae856 100644 --- a/test/CodeGenCXX/blocks-cxx11.cpp +++ b/test/CodeGenCXX/blocks-cxx11.cpp @@ -46,7 +46,7 @@ namespace test_complex_int { void test() { constexpr _Complex int x = 500; takeABlock(^{ takeItByValue(x); }); - // CHECK: store i32 500, + // CHECK: store { i32, i32 } { i32 500, i32 0 }, // CHECK: store i32 500, // CHECK-NEXT: store i32 0, diff --git a/test/CodeGenCXX/const-init-cxx11.cpp b/test/CodeGenCXX/const-init-cxx11.cpp index 833adba8ba..9e5b5ef091 100644 --- a/test/CodeGenCXX/const-init-cxx11.cpp +++ b/test/CodeGenCXX/const-init-cxx11.cpp @@ -330,6 +330,10 @@ namespace PR13273 { extern const S s {}; } +// CHECK: @_ZZN12LocalVarInit3aggEvE1a = internal constant {{.*}} i32 101 +// CHECK: @_ZZN12LocalVarInit4ctorEvE1a = internal constant {{.*}} i32 102 +// CHECK: @_ZZN12LocalVarInit8mutable_EvE1a = private unnamed_addr constant {{.*}} i32 103 + // Constant initialization tests go before this point, // dynamic initialization tests go after. @@ -356,6 +360,40 @@ namespace PR13273 { // CHECK-NOT: } // CHECK: call {{.*}}cxa_atexit{{.*}}@_ZN19NonLiteralConstexpr4BothD1Ev +// PR12848: Don't emit dynamic initializers for local constexpr variables. +namespace LocalVarInit { + constexpr int f(int n) { return n; } + struct Agg { int k; }; + struct Ctor { constexpr Ctor(int n) : k(n) {} int k; }; + struct Mutable { constexpr Mutable(int n) : k(n) {} mutable int k; }; + + // CHECK: define {{.*}} @_ZN12LocalVarInit6scalarEv + // CHECK-NOT: call + // CHECK: store i32 100, + // CHECK-NOT: call + // CHECK: ret i32 100 + int scalar() { constexpr int a = { f(100) }; return a; } + + // CHECK: define {{.*}} @_ZN12LocalVarInit3aggEv + // CHECK-NOT: call + // CHECK: ret i32 101 + int agg() { constexpr Agg a = { f(101) }; return a.k; } + + // CHECK: define {{.*}} @_ZN12LocalVarInit4ctorEv + // CHECK-NOT: call + // CHECK: ret i32 102 + int ctor() { constexpr Ctor a = { f(102) }; return a.k; } + + // CHECK: define {{.*}} @_ZN12LocalVarInit8mutable_Ev + // CHECK-NOT: call + // CHECK: call {{.*}}memcpy{{.*}} @_ZZN12LocalVarInit8mutable_EvE1a + // CHECK-NOT: call + // Can't fold return value due to 'mutable'. + // CHECK-NOT: ret i32 103 + // CHECK: } + int mutable_() { constexpr Mutable a = { f(103) }; return a.k; } +} + namespace CrossFuncLabelDiff { // Make sure we refuse to constant-fold the variable b. constexpr long a(bool x) { return x ? 0 : (long)&&lbl + (0 && ({lbl: 0;})); }