From: Anders Carlsson Date: Sun, 18 Oct 2009 23:09:21 +0000 (+0000) Subject: When binding a reference to a temporary, it's important that other temporaries create... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e1b7ea1b025c54b082f838ede2f483e657481fdc;p=clang When binding a reference to a temporary, it's important that other temporaries created as on the RHS are destroyed before emitting the dtor for the temporary. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84451 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 01a057f674..01fb766dfb 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -78,24 +78,18 @@ RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E, RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, QualType DestType, bool IsInitializer) { + bool ShouldDestroyTemporaries = false; + unsigned OldNumLiveTemporaries = 0; + if (const CXXExprWithTemporaries *TE = dyn_cast(E)) { - // If we shouldn't destroy the temporaries, just emit the - // child expression. - if (!TE->shouldDestroyTemporaries()) - return EmitReferenceBindingToExpr(TE->getSubExpr(), DestType, - IsInitializer); - - // Keep track of the current cleanup stack depth. - unsigned OldNumLiveTemporaries = LiveTemporaries.size(); - - RValue RV = EmitReferenceBindingToExpr(TE->getSubExpr(), DestType, - IsInitializer); - - // Pop temporaries. - while (LiveTemporaries.size() > OldNumLiveTemporaries) - PopCXXTemporary(); + ShouldDestroyTemporaries = TE->shouldDestroyTemporaries(); + + if (ShouldDestroyTemporaries) { + // Keep track of the current cleanup stack depth. + OldNumLiveTemporaries = LiveTemporaries.size(); + } - return RV; + E = TE->getSubExpr(); } RValue Val; @@ -105,6 +99,12 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, if (LV.isSimple()) return RValue::get(LV.getAddress()); Val = EmitLoadOfLValue(LV, E->getType()); + + if (ShouldDestroyTemporaries) { + // Pop temporaries. + while (LiveTemporaries.size() > OldNumLiveTemporaries) + PopCXXTemporary(); + } } else { const CXXRecordDecl *BaseClassDecl = 0; const CXXRecordDecl *DerivedClassDecl = 0; @@ -124,6 +124,12 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, Val = EmitAnyExprToTemp(E, /*IsAggLocVolatile=*/false, IsInitializer); + if (ShouldDestroyTemporaries) { + // Pop temporaries. + while (LiveTemporaries.size() > OldNumLiveTemporaries) + PopCXXTemporary(); + } + if (IsInitializer) { // We might have to destroy the temporary variable. if (const RecordType *RT = E->getType()->getAs()) { diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp index 32d46b3e10..682aab310d 100644 --- a/test/CodeGenCXX/references.cpp +++ b/test/CodeGenCXX/references.cpp @@ -107,3 +107,26 @@ void h() { const C& c = D(); } +namespace T { + struct A { + A(); + ~A(); + }; + + struct B { + B(); + ~B(); + A f(); + }; + + void f() { + // CHECK: call void @_ZN1T1BC1Ev + // CHECK: call void @_ZN1T1B1fEv + // CHECK: call void @_ZN1T1BD1Ev + const A& a = B().f(); + // CHECK: call void @_ZN1T1fEv + f(); + // CHECK: call void @_ZN1T1AD1Ev + } +} +