// RUN: %clang_cc1 -I%S -triple x86_64-apple-darwin -std=c++0x -emit-llvm %s -o %t.ll // RUN: FileCheck -check-prefix LL --input-file=%t.ll %s // XFAIL: win32 #include class test1_A { virtual void f() { } }; class test1_B { virtual void g() { } }; class test1_D : public virtual test1_A, private test1_B {}; class test1_E : public test1_D, public test1_B {}; class test1_F : public test1_E, public test1_D {}; extern test1_D test1_d; extern test1_F test1_f; extern "C" int printf(const char *str...); #define S(V, N) if (V) printf("PASS: %d\n", N); else printf("FAIL: %d\n", N) void test1() { test1_B* bp = (test1_B*)&test1_d; test1_A* ap = &test1_d; // This throws // test1_D& dr = dynamic_cast(*bp); test1_D* dp = dynamic_cast(bp); S(dp == 0, 1); ap = dynamic_cast(bp); S(ap == 0, 2); bp = dynamic_cast(ap); S(bp == 0, 3); ap = dynamic_cast(&test1_d); S(ap != 0, 4); // FIXME: Doesn't work yet, gcc fails this at compile time. We'd need access // control for this to work. // bp = dynamic_cast(&test1_d); // S(bp == 0, 5); { test1_A* ap = &test1_f; S(ap != 0, 6); test1_D* dp = dynamic_cast(ap); S(dp == 0, 7); // cast from virtual base test1_E* ep1 = dynamic_cast(ap); S(ep1 != 0, 8); } dp = dynamic_cast(&test1_d); S(dp == &test1_d, 9); const test1_D *cdp = dynamic_cast(&test1_d); S(cdp == &test1_d, 10); dp = dynamic_cast((test1_A*)0); S(dp == 0, 11); ap = dynamic_cast(&test1_d); S(ap == (test1_A*)&test1_d, 12); test1_E* ep = dynamic_cast(&test1_f); S(ep == (test1_E*)&test1_f, 13); void *vp = dynamic_cast(ap); S(vp == &test1_d, 14); const void *cvp = dynamic_cast(ap); S(cvp == &test1_d, 15); } // CHECK-LL: define void @_Z5test1v() nounwind { // CHECK-LL: [[bp:%.*]] = alloca %class.test1_A*, align 8 // CHECK-LL-NEXT: [[ap:%.*]] = alloca %class.test1_A*, align 8 // CHECK-LL-NEXT: [[dp:%.*]] = alloca %class.test1_D*, align 8 // CHECK-LL-NEXT: [[ap37:%.*]] = alloca %class.test1_A*, align 8 // CHECK-LL-NEXT: [[dp53:%.*]] = alloca %class.test1_D*, align 8 // CHECK-LL-NEXT: [[ep1:%.*]] = alloca %class.test1_E*, align 8 // CHECK-LL-NEXT: [[cdp:%.*]] = alloca %class.test1_D*, align 8 // CHECK-LL-NEXT: [[ep:%.*]] = alloca %class.test1_E*, align 8 // CHECK-LL-NEXT: [[vp:%.*]] = alloca i8*, align 8 // CHECK-LL-NEXT: [[cvp:%.*]] = alloca i8*, align 8 // CHECK-LL-NEXT: store %class.test1_A* bitcast (%class.test1_D* @test1_d to %class.test1_A*), %class.test1_A** [[bp]] // CHECK-LL-NEXT: br i1 false, label %[[castnull2:.*]], label %[[castnotnull1:.*]] // CHECK-LL: [[castnotnull1]] // CHECK-LL-NEXT: [[vtable:%.*]] = load i8** bitcast (%class.test1_D* @test1_d to i8**) // CHECK-LL-NEXT: [[vbaseoffsetptr:%.*]] = getelementptr i8* [[vtable]], i64 -24 // CHECK-LL-NEXT: [[v1:%.*]] = bitcast i8* [[vbaseoffsetptr]] to i64* // CHECK-LL-NEXT: [[vbaseoffset:%.*]] = load i64* [[v1]] // CHECK-LL-NEXT: [[addptr:%.*]] = getelementptr i8* getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0), i64 [[vbaseoffset:.*]] // CHECK-LL-NEXT: [[v2:%.*]] = bitcast i8* [[addptr]] to %class.test1_A* // CHECK-LL-NEXT: br label %[[castend3:.*]] // CHECK-LL: [[castnull2]] // CHECK-LL-NEXT: br label %[[castend3]] // CHECK-LL: [[castend3]] // CHECK-LL-NEXT: [[v3:%.*]] = phi %class.test1_A* [ [[v2]], %[[castnotnull1]] ], [ null, %[[castnull2]] ] // CHECK-LL-NEXT: store %class.test1_A* [[v3]], %class.test1_A** [[ap]] // CHECK-LL-NEXT: [[tmp:%.*]] = load %class.test1_A** [[bp]] // CHECK-LL-NEXT: [[v4:%.*]] = icmp ne %class.test1_A* [[tmp]], null // CHECK-LL-NEXT: br i1 [[v4]], label %[[v5:.*]], label %[[v9:.*]] // CHECK-LL: ;