// RUN: clang-cc -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 #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-NEXT:entry: // CHECK-LL-NEXT: %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: br i1 false, label %cast.null, label %cast.notnull // CHECK-LL: cast.notnull: // CHECK-LL-NEXT: br label %cast.end // CHECK-LL: cast.null: // CHECK-LL-NEXT: br label %cast.end // CHECK-LL: cast.end: // CHECK-LL-NEXT: %0 = phi %class.test1_A* [ bitcast (%class.test1_D* @test1_d to %class.test1_A*), %cast.notnull ], [ null, %cast.null ] // CHECK-LL-NEXT: store %class.test1_A* %0, %class.test1_A** %bp // CHECK-LL-NEXT: br i1 false, label %cast.null2, label %cast.notnull1 // CHECK-LL: cast.notnull1: // CHECK-LL-NEXT: %vtable = load i8** bitcast (%class.test1_D* @test1_d to i8**) // CHECK-LL-NEXT: %vbase.offset.ptr = getelementptr i8* %vtable, i64 -24 // CHECK-LL-NEXT: %1 = bitcast i8* %vbase.offset.ptr to i64* // CHECK-LL-NEXT: %vbase.offset = load i64* %1 // CHECK-LL-NEXT: %add.ptr = getelementptr i8* getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0), i64 %vbase.offset // CHECK-LL-NEXT: %2 = bitcast i8* %add.ptr to %class.test1_A* // CHECK-LL-NEXT: br label %cast.end3 // CHECK-LL: cast.null2: // CHECK-LL-NEXT: br label %cast.end3 // CHECK-LL: cast.end3: // CHECK-LL-NEXT: %3 = phi %class.test1_A* [ %2, %cast.notnull1 ], [ null, %cast.null2 ] // CHECK-LL-NEXT: store %class.test1_A* %3, %class.test1_A** %ap // CHECK-LL-NEXT: %tmp = load %class.test1_A** %bp // CHECK-LL-NEXT: %4 = icmp ne %class.test1_A* %tmp, null // CHECK-LL-NEXT: br i1 %4, label %5, label %9 // CHECK-LL: ;