]> granicus.if.org Git - clang/commitdiff
Teach the constant expr evaluator about derived-to-base casts when no virtual bases...
authorAnders Carlsson <andersca@mac.com>
Sun, 31 Oct 2010 20:41:46 +0000 (20:41 +0000)
committerAnders Carlsson <andersca@mac.com>
Sun, 31 Oct 2010 20:41:46 +0000 (20:41 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@117868 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/RecordLayout.h
lib/AST/ExprConstant.cpp
test/CodeGenCXX/global-init.cpp

index 2b3229e8fae958f3cb8bb71164e9d9b6dbc212eb..17fe4adde311c3ee0efdbb79c056a9b0c2bdc85a 100644 (file)
@@ -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 {
index 61f5b136ac0b079c8972746da93c78ed85a578ce..d23eac24d4c233287a91917fb8deb19fc4be2135 100644 (file)
@@ -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<PointerType>()->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))
index 6ff9598afce16789ea8ebfde0b54c14ccd25cfbb..f89e9781319f96687f484568f7048fc63b6d6ed7 100644 (file)
@@ -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