From: Anders Carlsson Date: Sun, 31 Oct 2010 20:41:46 +0000 (+0000) Subject: Teach the constant expr evaluator about derived-to-base casts when no virtual bases... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5c5a764fcd256df6f6cfbce5cdd2a2dfb2c45e95;p=clang Teach the constant expr evaluator about derived-to-base casts when no virtual bases are involved. Fixes PR5974. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@117868 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h index 2b3229e8fa..17fe4adde3 100644 --- a/include/clang/AST/RecordLayout.h +++ b/include/clang/AST/RecordLayout.h @@ -16,6 +16,7 @@ #include "llvm/System/DataTypes.h" #include "llvm/ADT/DenseMap.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/DeclCXX.h" namespace clang { diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 61f5b136ac..d23eac24d4 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -568,6 +568,42 @@ bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) { case CK_AnyPointerToBlockPointerCast: return Visit(SubExpr); + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: { + LValue BaseLV; + if (!EvaluatePointer(E->getSubExpr(), BaseLV, Info)) + return false; + + // Now figure out the necessary offset to add to the baseLV to get from + // the derived class to the base class. + uint64_t Offset = 0; + + QualType Ty = E->getSubExpr()->getType(); + const CXXRecordDecl *DerivedDecl = + Ty->getAs()->getPointeeType()->getAsCXXRecordDecl(); + + for (CastExpr::path_const_iterator PathI = E->path_begin(), + PathE = E->path_end(); PathI != PathE; ++PathI) { + const CXXBaseSpecifier *Base = *PathI; + + // FIXME: If the base is virtual, we'd need to determine the type of the + // most derived class and we don't support that right now. + if (Base->isVirtual()) + return false; + + const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl(); + const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl); + + Offset += Layout.getBaseClassOffset(BaseDecl); + DerivedDecl = BaseDecl; + } + + Result.Base = BaseLV.getLValueBase(); + Result.Offset = BaseLV.getLValueOffset() + + CharUnits::fromQuantity(Offset / Info.Ctx.getCharWidth()); + return true; + } + case CK_IntegralToPointer: { APValue Value; if (!EvaluateIntegerOrLValue(SubExpr, Value, Info)) diff --git a/test/CodeGenCXX/global-init.cpp b/test/CodeGenCXX/global-init.cpp index 6ff9598afc..f89e978131 100644 --- a/test/CodeGenCXX/global-init.cpp +++ b/test/CodeGenCXX/global-init.cpp @@ -17,6 +17,11 @@ struct D { ~D(); }; // It's okay if we ever implement the IR-generation optimization to remove this. // CHECK: @_ZN5test3L3varE = internal constant i8* getelementptr inbounds ([7 x i8]* +// PR6205: The casts should not require global initializers +// CHECK: @_ZN6PR59741cE = external global %"struct.PR5974::C" +// CHECK: @_ZN6PR59741aE = global %"struct.PR5974::A"* bitcast (%"struct.PR5974::C"* @_ZN6PR59741cE to %"struct.PR5974::A"*), align 8 +// CHECK: @_ZN6PR59741bE = global %"struct.PR5974::A"* bitcast (i8* getelementptr (%"struct.PR5974::C"* @_ZN6PR59741cE, i32 0, i32 0, i64 4) to %"struct.PR5974::A"*), align 8 + // CHECK: call void @_ZN1AC1Ev(%struct.A* @a) // CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @a, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*)) A a; @@ -64,6 +69,17 @@ namespace test3 { const char *test() { return var; } } +namespace PR5974 { + struct A { int a; }; + struct B { int b; }; + struct C : A, B { int c; }; + + extern C c; + + // These should not require global initializers. + A* a = &c; + B* b = &c; +} // CHECK: define internal void [[TEST1_Z_INIT:@.*]]() // CHECK: load i32* @_ZN5test1L1yE // CHECK-NEXT: xor