diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 48 | ||||
| -rw-r--r-- | clang/test/CodeGenCXX/references.cpp | 9 |
2 files changed, 53 insertions, 4 deletions
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 2834dfeb780..01a057f6745 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/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<CXXExprWithTemporaries>(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<CastExpr>(E->IgnoreParenNoopCasts(getContext()))) { + if (CE->getCastKind() == CastExpr::CK_DerivedToBase) { + E = CE->getSubExpr(); + + BaseClassDecl = + cast<CXXRecordDecl>(CE->getType()->getAs<RecordType>()->getDecl()); + DerivedClassDecl = + cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->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/clang/test/CodeGenCXX/references.cpp b/clang/test/CodeGenCXX/references.cpp index c235521d43b..32d46b3e104 100644 --- a/clang/test/CodeGenCXX/references.cpp +++ b/clang/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(); +} + |

