aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnders Carlsson <andersca@mac.com>2009-09-12 16:16:49 +0000
committerAnders Carlsson <andersca@mac.com>2009-09-12 16:16:49 +0000
commit0ee33cf81eb7e7e53a897efb772edf4d53af5bf1 (patch)
treed462f832b62e8270835369c755ffdc597641c434
parentf4d5eb4866a27d497f0bb75b12c2ffd48ad4d9c0 (diff)
Handle CK_DerivedToBase when emitting lvalue casts.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@81614 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/CodeGen/CGExpr.cpp63
-rw-r--r--test/CodeGenCXX/derived-to-base.cpp16
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();
+}