mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 21:56:04 +00:00
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:
parent
18c205ecdf
commit
3f48c603fb
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user