CGF.Builder.CreateUnreachable();
}
+/// \brief Compute the src2dst_offset hint as described in the
+/// Itanium C++ ABI [2.9.7]
+static CharUnits computeOffsetHint(ASTContext &Context,
+ const CXXRecordDecl *Src,
+ const CXXRecordDecl *Dst) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+
+ // If Dst is not derived from Src we can skip the whole computation below and
+ // return that Src is not a public base of Dst. Record all inheritance paths.
+ if (!Dst->isDerivedFrom(Src, Paths))
+ return CharUnits::fromQuantity(-2ULL);
+
+ unsigned NumPublicPaths = 0;
+ CharUnits Offset;
+
+ // Now walk all possible inheritance paths.
+ for (CXXBasePaths::paths_iterator I = Paths.begin(), E = Paths.end();
+ I != E; ++I) {
+ if (I->Access != AS_public) // Ignore non-public inheritance.
+ continue;
+
+ ++NumPublicPaths;
+
+ for (CXXBasePath::iterator J = I->begin(), JE = I->end(); J != JE; ++J) {
+ // If the path contains a virtual base class we can't give any hint.
+ // -1: no hint.
+ if (J->Base->isVirtual())
+ return CharUnits::fromQuantity(-1ULL);
+
+ if (NumPublicPaths > 1) // Won't use offsets, skip computation.
+ continue;
+
+ // Accumulate the base class offsets.
+ const ASTRecordLayout &L = Context.getASTRecordLayout(J->Class);
+ Offset += L.getBaseClassOffset(J->Base->getType()->getAsCXXRecordDecl());
+ }
+ }
+
+ // -2: Src is not a public base of Dst.
+ if (NumPublicPaths == 0)
+ return CharUnits::fromQuantity(-2ULL);
+
+ // -3: Src is a multiple public base type but never a virtual base type.
+ if (NumPublicPaths > 1)
+ return CharUnits::fromQuantity(-3ULL);
+
+ // Otherwise, the Src type is a unique public nonvirtual base type of Dst.
+ // Return the offset of Src from the origin of Dst.
+ return Offset;
+}
+
static llvm::Value *
EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
QualType SrcTy, QualType DestTy,
llvm::Value *DestRTTI =
CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType());
- // FIXME: Actually compute a hint here.
- llvm::Value *OffsetHint = llvm::ConstantInt::get(PtrDiffLTy, -1ULL);
+ // Compute the offset hint.
+ const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
+ const CXXRecordDecl *DestDecl = DestRecordTy->getAsCXXRecordDecl();
+ llvm::Value *OffsetHint =
+ llvm::ConstantInt::get(PtrDiffLTy,
+ computeOffsetHint(CGF.getContext(), SrcDecl,
+ DestDecl).getQuantity());
// Emit the call to __dynamic_cast.
Value = CGF.EmitCastToVoidPtr(Value);
--- /dev/null
+// RUN: %clang_cc1 -triple x86_64-apple-darwin12 -emit-llvm -o - %s | FileCheck %s
+
+class A { virtual ~A() {} };
+class B { virtual ~B() {} };
+
+class C : A { char x; };
+class D : public A { short y; };
+class E : public A, public B { int z; };
+class F : public virtual A { long long w; };
+class G : virtual A { long long w; };
+
+class H : public E { int a; };
+class I : public F { char b; };
+
+class J : public H { char q; };
+class K : public C, public B { char q; };
+
+class XA : public A { };
+class XB : public A { };
+class XC : public virtual A { };
+class X : public XA, public XB, public XC { };
+
+void test(A *a, B *b) {
+ volatile C *ac = dynamic_cast<C *>(a);
+// CHECK: call i8* @__dynamic_cast(i8* %2, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1C to i8*), i64 -2)
+ volatile D *ad = dynamic_cast<D *>(a);
+// CHECK: call i8* @__dynamic_cast(i8* %8, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1D to i8*), i64 0)
+ volatile E *ae = dynamic_cast<E *>(a);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }* @_ZTI1E to i8*), i64 0)
+ volatile F *af = dynamic_cast<F *>(a);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1F to i8*), i64 -1)
+ volatile G *ag = dynamic_cast<G *>(a);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1G to i8*), i64 -2)
+ volatile H *ah = dynamic_cast<H *>(a);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1H to i8*), i64 0)
+ volatile I *ai = dynamic_cast<I *>(a);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1I to i8*), i64 -1)
+ volatile J *aj = dynamic_cast<J *>(a);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1J to i8*), i64 0)
+ volatile K *ak = dynamic_cast<K *>(a);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }* @_ZTI1K to i8*), i64 -2)
+ volatile X *ax = dynamic_cast<X *>(a);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 }* @_ZTI1X to i8*), i64 -1)
+
+ volatile E *be = dynamic_cast<E *>(b);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1B to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }* @_ZTI1E to i8*), i64 8)
+ volatile G *bg = dynamic_cast<G *>(b);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1B to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1G to i8*), i64 -2)
+ volatile J *bj = dynamic_cast<J *>(b);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1B to i8*), i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1J to i8*), i64 8)
+ volatile K *bk = dynamic_cast<K *>(b);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1B to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }* @_ZTI1K to i8*), i64 16)
+}