From: Anders Carlsson Date: Thu, 15 Oct 2009 00:51:46 +0000 (+0000) Subject: Handle X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b3f744252a460c45e2e77053491285978286c384;p=clang Handle struct A { }; struct B : A { }; void f() { const A& a = B(); } correctly. (This now does the offset conversion if necessary and calls the destructor when a goes out of scope). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84162 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 2834dfeb78..01a057f674 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -78,6 +78,26 @@ RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E, RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, QualType DestType, bool IsInitializer) { + 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(); + + return RV; + } + RValue Val; if (E->isLvalue(getContext()) == Expr::LV_Valid) { // Emit the expr as an lvalue. @@ -86,9 +106,21 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, return RValue::get(LV.getAddress()); Val = EmitLoadOfLValue(LV, E->getType()); } else { - // FIXME: Initializers don't work with casts yet. For example - // const A& a = B(); - // if B inherits from A. + const CXXRecordDecl *BaseClassDecl = 0; + const CXXRecordDecl *DerivedClassDecl = 0; + + if (const CastExpr *CE = + dyn_cast(E->IgnoreParenNoopCasts(getContext()))) { + if (CE->getCastKind() == CastExpr::CK_DerivedToBase) { + E = CE->getSubExpr(); + + BaseClassDecl = + cast(CE->getType()->getAs()->getDecl()); + DerivedClassDecl = + cast(E->getType()->getAs()->getDecl()); + } + } + Val = EmitAnyExprToTemp(E, /*IsAggLocVolatile=*/false, IsInitializer); @@ -106,6 +138,16 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, } } } + + // Check if need to perform the derived-to-base cast. + if (BaseClassDecl) { + llvm::Value *Derived = Val.getAggregateAddr(); + + llvm::Value *Base = + GetAddressCXXOfBaseClass(Derived, DerivedClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + return RValue::get(Base); + } } if (Val.isAggregate()) { diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp index c235521d43..32d46b3e10 100644 --- a/test/CodeGenCXX/references.cpp +++ b/test/CodeGenCXX/references.cpp @@ -1,4 +1,4 @@ -// RUN: clang-cc -verify -emit-llvm -o %t %s +// RUN: clang-cc -verify -emit-llvm -o - %s | FileCheck %s void t1() { extern int& a; @@ -100,3 +100,10 @@ void f(A* a) { void *foo = 0; void * const & kFoo = foo; +struct D : C { D(); ~D(); }; + +void h() { + // CHECK: call void @_ZN1DD1Ev + const C& c = D(); +} +