xref: /llvm-project/clang/test/CodeGenCXX/dynamic-cast-exact.cpp (revision 0f46e31cfbf415fcd3d3ce121bef94e92c6ccfc8)
1 // RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions -std=c++11 -o - -O1 -disable-llvm-passes | FileCheck %s --implicit-check-not='call {{.*}} @__dynamic_cast'
2 struct Offset { virtual ~Offset(); };
3 struct A { virtual ~A(); };
4 struct B final : Offset, A { };
5 
6 struct C { virtual ~C(); int c; };
7 struct D : A { int d; };
8 struct E : A { int e; };
9 struct F : virtual A { int f; };
10 struct G : virtual A { int g; };
11 struct H final : C, D, E, F, G { int h; };
12 
13 // CHECK-LABEL: @_Z7inexactP1A
inexact(A * a)14 C *inexact(A *a) {
15   // CHECK: call {{.*}} @__dynamic_cast
16   return dynamic_cast<C*>(a);
17 }
18 
19 // CHECK-LABEL: @_Z12exact_singleP1A
exact_single(A * a)20 B *exact_single(A *a) {
21   // CHECK: %[[PTR_NULL:.*]] = icmp eq ptr %[[PTR:.*]], null
22   // CHECK: br i1 %[[PTR_NULL]], label %[[LABEL_FAILED:.*]], label %[[LABEL_NOTNULL:.*]]
23 
24   // CHECK: [[LABEL_NOTNULL]]:
25   // CHECK: %[[VPTR:.*]] = load ptr, ptr %[[PTR]]
26   // CHECK: %[[MATCH:.*]] = icmp eq ptr %[[VPTR]], getelementptr inbounds inrange(-16, 16) ({ [4 x ptr], [4 x ptr] }, ptr @_ZTV1B, i32 0, i32 1, i32 2)
27   // CHECK: %[[RESULT:.*]] = getelementptr inbounds i8, ptr %[[PTR]], i64 -8
28   // CHECK: br i1 %[[MATCH]], label %[[LABEL_END:.*]], label %[[LABEL_FAILED]]
29 
30   // CHECK: [[LABEL_FAILED]]:
31   // CHECK: br label %[[LABEL_END]]
32 
33   // CHECK: [[LABEL_END]]:
34   // CHECK: phi ptr [ %[[RESULT]], %[[LABEL_NOTNULL]] ], [ null, %[[LABEL_FAILED]] ]
35   return dynamic_cast<B*>(a);
36 }
37 
38 // CHECK-LABEL: @_Z9exact_refR1A
exact_ref(A & a)39 B &exact_ref(A &a) {
40   // CHECK: %[[PTR_NULL:.*]] = icmp eq ptr %[[PTR:.*]], null
41   // CHECK: br i1 %[[PTR_NULL]], label %[[LABEL_FAILED:.*]], label %[[LABEL_NOTNULL:.*]]
42 
43   // CHECK: [[LABEL_NOTNULL]]:
44   // CHECK: %[[VPTR:.*]] = load ptr, ptr %[[PTR]]
45   // CHECK: %[[MATCH:.*]] = icmp eq ptr %[[VPTR]], getelementptr inbounds inrange(-16, 16) ({ [4 x ptr], [4 x ptr] }, ptr @_ZTV1B, i32 0, i32 1, i32 2)
46   // CHECK: %[[RESULT:.*]] = getelementptr inbounds i8, ptr %[[PTR]], i64 -8
47   // CHECK: br i1 %[[MATCH]], label %[[LABEL_END:.*]], label %[[LABEL_FAILED]]
48 
49   // CHECK: [[LABEL_FAILED]]:
50   // CHECK: call {{.*}} @__cxa_bad_cast
51   // CHECK: unreachable
52 
53   // CHECK: [[LABEL_END]]:
54   // CHECK: ret ptr %[[RESULT]]
55   return dynamic_cast<B&>(a);
56 }
57 
58 // CHECK-LABEL: @_Z11exact_multiP1A
exact_multi(A * a)59 H *exact_multi(A *a) {
60   // CHECK: %[[PTR_NULL:.*]] = icmp eq ptr %[[PTR:.*]], null
61   // CHECK: br i1 %[[PTR_NULL]], label %[[LABEL_FAILED:.*]], label %[[LABEL_NOTNULL:.*]]
62 
63   // CHECK: [[LABEL_NOTNULL]]:
64   // CHECK: %[[VPTR:.*]] = load ptr, ptr %[[PTR]]
65   // CHECK: %[[OFFSET_TO_TOP_SLOT:.*]] = getelementptr inbounds i64, ptr %[[VPTR]], i64 -2
66   // CHECK: %[[OFFSET_TO_TOP:.*]] = load i64, ptr %[[OFFSET_TO_TOP_SLOT]]
67   // CHECK: %[[RESULT:.*]] = getelementptr inbounds i8, ptr %[[PTR]], i64 %[[OFFSET_TO_TOP]]
68   // CHECK: %[[DERIVED_VPTR:.*]] = load ptr, ptr %[[RESULT]]
69   // CHECK: %[[MATCH:.*]] = icmp eq ptr %[[DERIVED_VPTR]], getelementptr inbounds inrange(-24, 16) ({ [5 x ptr], [4 x ptr], [4 x ptr], [6 x ptr], [6 x ptr] }, ptr @_ZTV1H, i32 0, i32 0, i32 3)
70   // CHECK: br i1 %[[MATCH]], label %[[LABEL_END:.*]], label %[[LABEL_FAILED]]
71 
72   // CHECK: [[LABEL_FAILED]]:
73   // CHECK: br label %[[LABEL_END]]
74 
75   // CHECK: [[LABEL_END]]:
76   // CHECK: phi ptr [ %[[RESULT]], %[[LABEL_NOTNULL]] ], [ null, %[[LABEL_FAILED]] ]
77   return dynamic_cast<H*>(a);
78 }
79 
80 namespace GH64088 {
81   // Ensure we mark the B vtable as used here, because we're going to emit a
82   // reference to it.
83   // CHECK: define {{.*}} @_ZN7GH640881BD0
84   struct A { virtual ~A(); };
85   struct B final : A { virtual ~B() = default; };
cast(A * p)86   B *cast(A *p) { return dynamic_cast<B*>(p); }
87 }
88