xref: /llvm-project/clang/test/CodeGenCXX/ptrauth-apple-kext-indirect-virtual-dtor-call.cpp (revision 1b8ab2f08998d3220e5d95003d47bb3d7cac966b)
1 // RUN: %clang_cc1 -triple arm64-apple-ios -std=c++98 -fptrauth-calls -fapple-kext -fno-rtti -disable-O0-optnone -emit-llvm -o - %s | FileCheck %s
2 
3 // CHECK: @_ZTV5TemplIiE = internal unnamed_addr constant { [7 x ptr] } { [7 x ptr] [ptr null, ptr null, ptr ptrauth (ptr @_ZN5TemplIiED1Ev, i32 0, i64 57986, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV5TemplIiE, i32 0, i32 0, i32 2)), ptr ptrauth (ptr @_ZN5TemplIiED0Ev, i32 0, i64 22856, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV5TemplIiE, i32 0, i32 0, i32 3)), ptr ptrauth (ptr @_ZN5TemplIiE1fEv, i32 0, i64 22189, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV5TemplIiE, i32 0, i32 0, i32 4)), ptr ptrauth (ptr @_ZN5TemplIiE1gEv, i32 0, i64 9912, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV5TemplIiE, i32 0, i32 0, i32 5)), ptr null] }, align 8
4 
5 struct B1 {
6   virtual ~B1();
7 };
8 
~B1()9 B1::~B1() {}
10 
DELETE(B1 * pb1)11 void DELETE(B1 *pb1) {
12   pb1->B1::~B1();
13 }
14 // CHECK-LABEL: define void @_ZN2B1D0Ev
15 // CHECK: [[T1:%.*]] = load ptr, ptr getelementptr inbounds (ptr, ptr @_ZTV2B1, i64 2)
16 // CHECK-NEXT: [[B1:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr getelementptr inbounds (ptr, ptr @_ZTV2B1, i64 2) to i64), i64 14635)
17 // CHECK-NEXT: call noundef ptr [[T1]](ptr noundef nonnull align 8 dereferenceable(8) [[T2:%.*]]) [ "ptrauth"(i32 0, i64 [[B1]]) ]
18 // CHECK-LABEL: define void @_Z6DELETEP2B1
19 // CHECK: [[T3:%.*]] = load ptr, ptr getelementptr inbounds (ptr, ptr @_ZTV2B1, i64 2)
20 // CHECK-NEXT: [[B3:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr getelementptr inbounds (ptr, ptr @_ZTV2B1, i64 2) to i64), i64 14635)
21 // CHECK-NEXT:  call noundef ptr [[T3]](ptr noundef nonnull align 8 dereferenceable(8) [[T4:%.*]]) [ "ptrauth"(i32 0, i64 [[B3]])
22 
23 template<class T>
24 struct Templ {
25   virtual ~Templ(); // Out-of-line so that the destructor doesn't cause a vtable
fTempl26   virtual void f() {}
gTempl27   virtual void g() {}
28 };
29 template<class T>
30 struct SubTempl : public Templ<T> {
~SubTemplSubTempl31   virtual ~SubTempl() {} // override
fSubTempl32   virtual void f() {} // override
gSubTempl33   virtual void g() {} // override
34 };
35 
f(SubTempl<int> * t)36 void f(SubTempl<int>* t) {
37   // Qualified calls go through the (qualified) vtable in apple-kext mode.
38   // Since t's this pointer points to SubTempl's vtable, the call needs
39   // to load Templ<int>'s vtable.  Hence, Templ<int>::g needs to be
40   // instantiated in this TU, for it's referenced by the vtable.
41   // (This happens only in apple-kext mode; elsewhere virtual calls can always
42   // use the vtable pointer off this instead of having to load the vtable
43   // symbol.)
44   t->Templ::~Templ();
45 }
46 
47 // CHECK: getelementptr inbounds (ptr, ptr @_ZTV5TemplIiE, i64 2)
48 // CHECK: declare void @_ZN5TemplIiED0Ev(ptr noundef nonnull align 8 dereferenceable(8))
49 // CHECK: define internal void @_ZN5TemplIiE1fEv(ptr noundef nonnull align 8 dereferenceable(8) %this)
50 // CHECK: define internal void @_ZN5TemplIiE1gEv(ptr noundef nonnull align 8 dereferenceable(8) %this)
51