diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -910,6 +910,25 @@ .Build(Updater, /*AllowOverwrite*/ true); } +class HasAnyMaterializeTemporaryExpr : + public ConstStmtVisitor { +public: + bool VisitArraySubscriptExpr(const ArraySubscriptExpr *A) { + return Visit(A->getBase()) || Visit(A->getIdx()); + } + bool VisitCastExpr(const CastExpr *C) { + return Visit(C->getSubExpr()); + } + bool VisitInitListExpr(const InitListExpr *I) { + return llvm::any_of(I->inits(), [this](const Expr *II) { + return Visit(II); + }); + } + bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *) { + return true; + } +}; + //===----------------------------------------------------------------------===// // ConstExprEmitter //===----------------------------------------------------------------------===// @@ -1215,11 +1234,6 @@ return Visit(E->getSubExpr(), T); } - llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E, - QualType T) { - return Visit(E->getSubExpr(), T); - } - llvm::Constant *EmitArrayInitialization(InitListExpr *ILE, QualType T) { auto *CAT = CGM.getContext().getAsConstantArrayType(ILE->getType()); assert(CAT && "can't emit array init for non-constant-bound array"); @@ -1279,6 +1293,13 @@ if (ILE->isTransparent()) return Visit(ILE->getInit(0), T); + // If we have any MaterializeTemporaryExpr's in the InitListExpr, bail so + // that EmitArrayInitialization or EmitRecordInitialization don't corrupt + // the generated object. + HasAnyMaterializeTemporaryExpr H; + if (H.Visit(ILE)) + return nullptr; + if (ILE->getType()->isArrayType()) return EmitArrayInitialization(ILE, T); @@ -1322,7 +1343,12 @@ assert(CGM.getContext().hasSameUnqualifiedType(Ty, Arg->getType()) && "argument to copy ctor is of wrong type"); - return Visit(Arg, Ty); + // Look through the temporary; it's just converting the value to an + // lvalue to pass it to the constructor. + if (auto *MTE = dyn_cast(Arg)) + return Visit(MTE->getSubExpr(), Ty); + // Don't try to support arbitrary lvalue-to-rvalue conversions for now. + return nullptr; } return CGM.EmitNullConstant(Ty); @@ -1654,12 +1680,8 @@ InConstantContext = D.hasConstantInitialization(); QualType destType = D.getType(); - - // Try to emit the initializer. Note that this can allow some things that - // are not allowed by tryEmitPrivateForMemory alone. - if (auto value = D.evaluateValue()) { - return tryEmitPrivateForMemory(*value, destType); - } + const Expr *E = D.getInit(); + assert(E && "No initializer to emit"); // FIXME: Implement C++11 [basic.start.init]p2: if the initializer of a // reference is a constant expression, and the reference binds to a temporary, @@ -1667,16 +1689,19 @@ // incorrectly emit a prvalue constant in this case, and the calling code // interprets that as the (pointer) value of the reference, rather than the // desired value of the referee. - if (destType->isReferenceType()) - return nullptr; + if (!destType->isLValueReferenceType()) { + QualType nonMemoryDestType = getNonMemoryType(CGM, destType); + if (llvm::Constant *C = ConstExprEmitter(*this).Visit(const_cast(E), + nonMemoryDestType)) + return emitForMemory(C, destType); + } - const Expr *E = D.getInit(); - assert(E && "No initializer to emit"); + // Try to emit the initializer. Note that this can allow some things that + // are not allowed by tryEmitPrivateForMemory alone. + if (APValue *value = D.evaluateValue()) + return tryEmitPrivateForMemory(*value, destType); - auto nonMemoryDestType = getNonMemoryType(CGM, destType); - auto C = - ConstExprEmitter(*this).Visit(const_cast(E), nonMemoryDestType); - return (C ? emitForMemory(C, destType) : nullptr); + return nullptr; } llvm::Constant * @@ -1743,6 +1768,10 @@ QualType destType) { assert(!destType->isVoidType() && "can't emit a void constant"); + if (llvm::Constant *C = + ConstExprEmitter(*this).Visit(const_cast(E), destType)) + return C; + Expr::EvalResult Result; bool Success = false; @@ -1752,13 +1781,10 @@ else Success = E->EvaluateAsRValue(Result, CGM.getContext(), InConstantContext); - llvm::Constant *C; if (Success && !Result.HasSideEffects) - C = tryEmitPrivate(Result.Val, destType); - else - C = ConstExprEmitter(*this).Visit(const_cast(E), destType); + return tryEmitPrivate(Result.Val, destType); - return C; + return nullptr; } llvm::Constant *CodeGenModule::getNullPointer(llvm::PointerType *T, QualType QT) { diff --git a/clang/test/CodeGenCXX/const-init-cxx11.cpp b/clang/test/CodeGenCXX/const-init-cxx11.cpp --- a/clang/test/CodeGenCXX/const-init-cxx11.cpp +++ b/clang/test/CodeGenCXX/const-init-cxx11.cpp @@ -88,7 +88,7 @@ struct E {}; struct Test2 : X, X, X, X {}; - // CHECK: @_ZN9BaseClass2t2E ={{.*}} constant {{.*}} undef + // CHECK: @_ZN9BaseClass2t2E ={{.*}} constant {{.*}} zeroinitializer, align 1 extern constexpr Test2 t2 = Test2(); struct __attribute((packed)) PackedD { double y = 2; }; diff --git a/clang/test/CodeGenCXX/const-init-cxx1y.cpp b/clang/test/CodeGenCXX/const-init-cxx1y.cpp --- a/clang/test/CodeGenCXX/const-init-cxx1y.cpp +++ b/clang/test/CodeGenCXX/const-init-cxx1y.cpp @@ -34,8 +34,8 @@ // 'c.temporary', not the value as modified by the partial evaluation within // the initialization of 'c.x'. A c = { 10, (++c.temporary, b.x) }; - // CHECK: @_ZGRN21ModifyStaticTemporary1cE_ = internal global i32 10 // CHECK: @_ZN21ModifyStaticTemporary1cE ={{.*}} global {{.*}} zeroinitializer + // CHECK: @_ZGRN21ModifyStaticTemporary1cE_ = internal global i32 10 } // CHECK: @_ZGRN28VariableTemplateWithConstRef1iIvEE_ = linkonce_odr constant i32 5, align 4 @@ -64,6 +64,8 @@ // CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE6_ = linkonce_odr global {{.*}} { ptr @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE7_ } // CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE_ = linkonce_odr global %"struct.VariableTemplateWithPack::S" { ptr @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE0_, ptr @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE2_, ptr @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE4_, ptr @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE6_ } // CHECK: @_ZN24VariableTemplateWithPack1pE ={{.*}} global {{.*}} @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE_ +// CHECK: @_ZGR1z_ = internal global [2 x i32] [i32 10, i32 2], align 4 +// CHECK: @z = global { ptr, i32 } { ptr @_ZGR1z_, i32 10 }, align 8 namespace VariableTemplateWithPack { struct A { const int &r; @@ -85,3 +87,7 @@ // CHECK: store // CHECK: load {{.*}} @_ZN21ModifyStaticTemporary1bE // CHECK: store {{.*}} @_ZN21ModifyStaticTemporary1cE + +typedef int v[2]; +struct Z { int &&x, y; }; +Z z = { v{1,2}[0], z.x = 10 }; diff --git a/clang/test/CodeGenOpenCL/amdgpu-nullptr.cl b/clang/test/CodeGenOpenCL/amdgpu-nullptr.cl --- a/clang/test/CodeGenOpenCL/amdgpu-nullptr.cl +++ b/clang/test/CodeGenOpenCL/amdgpu-nullptr.cl @@ -57,7 +57,7 @@ // CHECK: @fold_generic ={{.*}} local_unnamed_addr addrspace(1) global ptr null, align 8 generic int *fold_generic = (global int*)(generic float*)(private char*)0; -// CHECK: @fold_priv ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), align 4 +// CHECK: @fold_priv ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(5) addrspacecast (ptr addrspace(1) null to ptr addrspace(5)), align 4 private short *fold_priv = (private short*)(generic int*)(global void*)0; // CHECK: @fold_priv_arith ={{.*}} local_unnamed_addr addrspace(1) global ptr addrspace(5) inttoptr (i32 9 to ptr addrspace(5)), align 4