diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index 7fdb895e8edf..3f4919fbe9c4 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -93,13 +93,9 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, EmitDeclDestroy(*this, D, DeclPtr); return; } - if (Init->isLvalue(getContext()) == Expr::LV_Valid) { - RValue RV = EmitReferenceBindingToExpr(Init, &D); - EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, T); - return; - } - ErrorUnsupported(Init, - "global variable that binds reference to a non-lvalue"); + + RValue RV = EmitReferenceBindingToExpr(Init, &D); + EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, T); } void @@ -373,11 +369,7 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, if (D.getType()->isReferenceType()) { QualType T = D.getType(); - // We don't want to pass true for IsInitializer here, because a static - // reference to a temporary does not extend its lifetime. - // FIXME: This is incorrect. - RValue RV = EmitReferenceBindingToExpr(D.getInit(), - /*InitializedDecl=*/0); + RValue RV = EmitReferenceBindingToExpr(D.getInit(), &D); EmitStoreOfScalar(RV.getScalarVal(), GV, /*Volatile=*/false, T); } else diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 0d5369d0d3c1..2bda5adb42b0 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -308,9 +308,9 @@ EmitExprForReferenceBinding(CodeGenFunction& CGF, const Expr* E, // the object we're binding to. QualType T = Adjustment.Field.Field->getType().getNonReferenceType() .getUnqualifiedType(); - Object = CGF.CreateTempAlloca(CGF.ConvertType(T), "lv"); - LValue TempLV = - LValue::MakeAddr(Object, Qualifiers::fromCVRMask(CVR)); + Object = CreateReferenceTemporary(CGF, T, InitializedDecl); + LValue TempLV = LValue::MakeAddr(Object, + Qualifiers::fromCVRMask(CVR)); CGF.EmitStoreThroughLValue(CGF.EmitLoadOfLValue(LV, T), TempLV, T); break; } @@ -348,20 +348,34 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, ReferenceTemporaryDtor, InitializedDecl); + if (!ReferenceTemporaryDtor) + return RValue::get(Value); + // Make sure to call the destructor for the reference temporary. - if (ReferenceTemporaryDtor) { + if (const VarDecl *VD = dyn_cast_or_null(InitializedDecl)) { + if (VD->hasGlobalStorage()) { + llvm::Constant *DtorFn = + CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete); + CGF.EmitCXXGlobalDtorRegistration(DtorFn, + cast(ReferenceTemporary)); + + return RValue::get(Value); + } + } + + { DelayedCleanupBlock Scope(*this); EmitCXXDestructorCall(ReferenceTemporaryDtor, Dtor_Complete, /*ForVirtualBase=*/false, ReferenceTemporary); // Make sure to jump to the exit block. EmitBranch(Scope.getCleanupExitBlock()); + } - if (Exceptions) { - EHCleanupBlock Cleanup(*this); - EmitCXXDestructorCall(ReferenceTemporaryDtor, Dtor_Complete, - /*ForVirtualBase=*/false, ReferenceTemporary); - } + if (Exceptions) { + EHCleanupBlock Cleanup(*this); + EmitCXXDestructorCall(ReferenceTemporaryDtor, Dtor_Complete, + /*ForVirtualBase=*/false, ReferenceTemporary); } return RValue::get(Value); diff --git a/clang/test/CodeGenCXX/references.cpp b/clang/test/CodeGenCXX/references.cpp index ed0c6f9d2d24..d2ad98013553 100644 --- a/clang/test/CodeGenCXX/references.cpp +++ b/clang/test/CodeGenCXX/references.cpp @@ -160,7 +160,7 @@ const int &f2() { return 0; } namespace N1 { const int foo = 1; // CHECK: @_ZN2N14test - int test(const int& arg = foo) { + void test(const int& arg = foo) { // Ensure this array is on the stack where we can set values instead of // being a global constant. // CHECK: %args_array = alloca @@ -224,3 +224,37 @@ namespace N2 { i = 19; } } + +namespace N3 { + +// PR7326 + +struct A { + explicit A(int); + ~A(); +}; + +// CHECK: define internal void @__cxx_global_var_init +// CHECK: call void @_ZN2N31AC1Ei(%"class.N2::X"* @_ZGRN2N35sA123E, i32 123) +// CHECK: call i32 @__cxa_atexit +// CHECK: ret void +const A &sA123 = A(123); +} + +namespace N4 { + +struct A { + A(); + ~A(); +}; + +void f() { + // CHECK: define void @_ZN2N41fEv + // CHECK: call void @_ZN2N41AC1Ev(%"class.N2::X"* @_ZGRZN2N41fEvE2ar) + // CHECK: call i32 @__cxa_atexit + // CHECK: ret void + static const A& ar = A(); + +} +} +