Correctly destroy reference temporaries with global storage. Remove ErrorUnsupported call when binding a global reference to a non-lvalue. Fixes PR7326.

llvm-svn: 106983
This commit is contained in:
Anders Carlsson 2010-06-27 17:52:15 +00:00
parent 18c205ecdf
commit 3f48c603fb
3 changed files with 62 additions and 22 deletions

View File

@ -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

View File

@ -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<VarDecl>(InitializedDecl)) {
if (VD->hasGlobalStorage()) {
llvm::Constant *DtorFn =
CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
CGF.EmitCXXGlobalDtorRegistration(DtorFn,
cast<llvm::Constant>(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);

View File

@ -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();
}
}