182 lines · cpp
1// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -mconstructor-aliases -triple=i386-pc-win32 | FileCheck %s2 3struct Left {4 virtual void left();5};6 7struct Right {8 virtual void right();9};10 11struct ChildNoOverride : Left, Right {12};13 14struct ChildOverride : Left, Right {15 virtual void left();16 virtual void right();17};18 19extern "C" void foo(void *);20 21void call_left_no_override(ChildNoOverride *child) {22// CHECK-LABEL: define dso_local void @"?call_left_no_override23// CHECK: %[[CHILD:.*]] = load ptr24 25 child->left();26// Only need to cast 'this' to Left*.27// CHECK: %[[VFTABLE:.*]] = load ptr, ptr %[[CHILD]]28// CHECK: %[[VFUN:.*]] = getelementptr inbounds ptr, ptr %[[VFTABLE]], i64 029// CHECK: %[[VFUN_VALUE:.*]] = load ptr, ptr %[[VFUN]]30// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](ptr {{[^,]*}} %[[CHILD]])31// CHECK: ret32}33 34void ChildOverride::left() {35// CHECK-LABEL: define dso_local x86_thiscallcc void @"?left@ChildOverride@@UAEXXZ"36// CHECK-SAME: (ptr {{[^,]*}} %[[THIS:.*]])37//38// No need to adjust 'this' as the ChildOverride's layout begins with Left.39// CHECK: %[[THIS_ADDR:.*]] = alloca ptr, align 440// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]], align 441 42 foo(this);43// CHECK: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]44// CHECK: call void @foo(ptr noundef %[[THIS]])45// CHECK: ret46}47 48void call_left_override(ChildOverride *child) {49// CHECK-LABEL: define dso_local void @"?call_left_override50// CHECK: %[[CHILD:.*]] = load ptr51 52 child->left();53// CHECK: %[[VFTABLE:.*]] = load ptr, ptr %[[CHILD]]54// CHECK: %[[VFUN:.*]] = getelementptr inbounds ptr, ptr %[[VFTABLE]], i64 055// CHECK: %[[VFUN_VALUE:.*]] = load ptr, ptr %[[VFUN]]56//57// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](ptr {{[^,]*}} %[[CHILD]])58// CHECK: ret59}60 61void call_right_no_override(ChildNoOverride *child) {62// CHECK-LABEL: define dso_local void @"?call_right_no_override63// CHECK: %[[CHILD:.*]] = load ptr64 65 child->right();66// When calling a right base's virtual method, one needs to adjust 'this' at67// the caller site.68//69// CHECK: %[[RIGHT_i8:.*]] = getelementptr inbounds i8, ptr %[[CHILD]], i32 470//71// CHECK: %[[VFTABLE:.*]] = load ptr, ptr %[[RIGHT_i8]]72// CHECK: %[[VFUN:.*]] = getelementptr inbounds ptr, ptr %[[VFTABLE]], i64 073// CHECK: %[[VFUN_VALUE:.*]] = load ptr, ptr %[[VFUN]]74// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](ptr {{[^,]*}} %[[RIGHT_i8]])75// CHECK: ret76}77 78void ChildOverride::right() {79// CHECK-LABEL: define dso_local x86_thiscallcc void @"?right@ChildOverride@@UAEXXZ"(ptr80//81// ChildOverride::right gets 'this' cast to Right* in ECX (i.e. this+4) so we82// need to adjust 'this' before use.83//84// CHECK: %[[THIS_ADDR:.*]] = alloca ptr, align 485// CHECK: store ptr %[[ECX:.*]], ptr %[[THIS_ADDR]], align 486// CHECK: %[[THIS_RELOAD:.*]] = load ptr, ptr %[[THIS_ADDR]]87// CHECK: %[[THIS_ADJUSTED:.*]] = getelementptr inbounds i8, ptr %[[THIS_RELOAD]], i32 -488 89 foo(this);90// CHECK: call void @foo(ptr noundef %[[THIS_ADJUSTED]])91// CHECK: ret92}93 94void call_right_override(ChildOverride *child) {95// CHECK-LABEL: define dso_local void @"?call_right_override96// CHECK: %[[CHILD:.*]] = load ptr97 98 child->right();99// When calling a right child's virtual method, one needs to adjust 'this' at100// the caller site.101//102// CHECK: %[[RIGHT:.*]] = getelementptr inbounds i8, ptr %[[CHILD]], i32 4103//104// CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8, ptr %[[CHILD]], i32 4105// CHECK: %[[VFTABLE:.*]] = load ptr, ptr %[[VFPTR_i8]]106// CHECK: %[[VFUN:.*]] = getelementptr inbounds ptr, ptr %[[VFTABLE]], i64 0107// CHECK: %[[VFUN_VALUE:.*]] = load ptr, ptr %[[VFUN]]108//109// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](ptr noundef %[[RIGHT]])110// CHECK: ret111}112 113struct GrandchildOverride : ChildOverride {114 virtual void right();115};116 117void GrandchildOverride::right() {118// CHECK-LABEL: define dso_local x86_thiscallcc void @"?right@GrandchildOverride@@UAEXXZ"(ptr119//120// CHECK: %[[THIS_ADDR:.*]] = alloca ptr, align 4121// CHECK: store ptr %[[ECX:.*]], ptr %[[THIS_ADDR]], align 4122// CHECK: %[[THIS_RELOAD:.*]] = load ptr, ptr %[[THIS_ADDR]]123// CHECK: %[[THIS_ADJUSTED:.*]] = getelementptr inbounds i8, ptr %[[THIS_RELOAD]], i32 -4124 125 foo(this);126// CHECK: call void @foo(ptr noundef %[[THIS_ADJUSTED]])127// CHECK: ret128}129 130void call_grandchild_right(GrandchildOverride *obj) {131 // Just make sure we don't crash.132 obj->right();133}134 135void emit_ctors() {136 Left l;137 // CHECK-LABEL: define {{.*}} @"??0Left@@QAE@XZ"138 // CHECK-NOT: getelementptr139 // CHECK: store ptr @"??_7Left@@6B@"140 // CHECK: ret141 142 Right r;143 // CHECK-LABEL: define {{.*}} @"??0Right@@QAE@XZ"144 // CHECK-NOT: getelementptr145 // CHECK: store ptr @"??_7Right@@6B@"146 // CHECK: ret147 148 ChildOverride co;149 // CHECK-LABEL: define {{.*}} @"??0ChildOverride@@QAE@XZ"150 // CHECK: %[[THIS:.*]] = load ptr, ptr151 // CHECK: store ptr @"??_7ChildOverride@@6BLeft@@@", ptr %[[THIS]]152 // CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i32 4153 // CHECK: store ptr @"??_7ChildOverride@@6BRight@@@", ptr %[[VFPTR_i8]]154 // CHECK: ret155 156 GrandchildOverride gc;157 // CHECK-LABEL: define {{.*}} @"??0GrandchildOverride@@QAE@XZ"158 // CHECK: %[[THIS:.*]] = load ptr, ptr159 // CHECK: store ptr @"??_7GrandchildOverride@@6BLeft@@@", ptr %[[THIS]]160 // CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i32 4161 // CHECK: store ptr @"??_7GrandchildOverride@@6BRight@@@", ptr %[[VFPTR_i8]]162 // CHECK: ret163}164 165struct LeftWithNonVirtualDtor {166 virtual void left();167 ~LeftWithNonVirtualDtor();168};169 170struct AsymmetricChild : LeftWithNonVirtualDtor, Right {171 virtual ~AsymmetricChild();172};173 174void call_asymmetric_child_complete_dtor() {175 // CHECK-LABEL: define dso_local void @"?call_asymmetric_child_complete_dtor@@YAXXZ"176 AsymmetricChild obj;177 // CHECK: call x86_thiscallcc noundef ptr @"??0AsymmetricChild@@QAE@XZ"(ptr {{[^,]*}} %[[OBJ:.*]])178 // CHECK-NOT: getelementptr179 // CHECK: call x86_thiscallcc void @"??1AsymmetricChild@@UAE@XZ"(ptr {{[^,]*}} %[[OBJ]])180 // CHECK: ret181}182