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,
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);
}
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();
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.
// 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;})); }