diff options
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 63 | ||||
-rw-r--r-- | test/CodeGenCXX/derived-to-base.cpp | 16 |
2 files changed, 58 insertions, 21 deletions
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 1141dd6b02..92e87826a2 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -1153,30 +1153,51 @@ LValue CodeGenFunction::EmitConditionalOperator(const ConditionalOperator* E) { /// all the reasons that casts are permitted with aggregate result, including /// noop aggregate casts, and cast from scalar to union. LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { - // If this is an aggregate-to-aggregate cast, just use the input's address as - // the lvalue. - if (E->getCastKind() == CastExpr::CK_NoOp || - E->getCastKind() == CastExpr::CK_ConstructorConversion || - E->getCastKind() == CastExpr::CK_UserDefinedConversion) + switch (E->getCastKind()) { + default: + // If this is an lvalue cast, treat it as a no-op. + // FIXME: We shouldn't need to check for this explicitly! + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) + if (ICE->isLvalueCast()) + return EmitLValue(E->getSubExpr()); + + assert(0 && "Unhandled cast!"); + + case CastExpr::CK_NoOp: + case CastExpr::CK_ConstructorConversion: + case CastExpr::CK_UserDefinedConversion: return EmitLValue(E->getSubExpr()); + + case CastExpr::CK_DerivedToBase: { + const RecordType *DerivedClassTy = + E->getSubExpr()->getType()->getAs<RecordType>(); + CXXRecordDecl *DerivedClassDecl = + cast<CXXRecordDecl>(DerivedClassTy->getDecl()); + + const RecordType *BaseClassTy = E->getType()->getAs<RecordType>(); + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseClassTy->getDecl()); + + LValue LV = EmitLValue(E->getSubExpr()); + + // Perform the derived-to-base conversion + llvm::Value *Base = + GetAddressCXXOfBaseClass(LV.getAddress(), DerivedClassDecl, + BaseClassDecl, /*NullCheckValue=*/false); + + return LValue::MakeAddr(Base, E->getType().getCVRQualifiers(), + getContext().getObjCGCAttrKind(E->getType()), + E->getType().getAddressSpace()); + } - // If this is an lvalue cast, treat it as a no-op. - // FIXME: We shouldn't need to check for this explicitly! - if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) - if (ICE->isLvalueCast()) - return EmitLValue(E->getSubExpr()); - - // Otherwise, we must have a cast from scalar to union. - assert(E->getCastKind() == CastExpr::CK_ToUnion && - "Expected scalar-to-union cast"); - - // Casts are only lvalues when the source and destination types are the same. - llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType())); - EmitAnyExpr(E->getSubExpr(), Temp, false); + case CastExpr::CK_ToUnion: { + llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType())); + EmitAnyExpr(E->getSubExpr(), Temp, false); - return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType()), - E->getType().getAddressSpace()); + return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(), + getContext().getObjCGCAttrKind(E->getType()), + E->getType().getAddressSpace()); + } + } } //===--------------------------------------------------------------------===// diff --git a/test/CodeGenCXX/derived-to-base.cpp b/test/CodeGenCXX/derived-to-base.cpp new file mode 100644 index 0000000000..63492d604d --- /dev/null +++ b/test/CodeGenCXX/derived-to-base.cpp @@ -0,0 +1,16 @@ +// RUN: clang-cc -emit-llvm %s -o - +struct A { + void f(); + + int a; +}; + +struct B : A { + double b; +}; + +void f() { + B b; + + b.f(); +} |