diff options
Diffstat (limited to 'test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp')
-rw-r--r-- | test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp | 152 |
1 files changed, 150 insertions, 2 deletions
diff --git a/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp index 7c223ca..2f0fffe 100644 --- a/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp +++ b/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp @@ -1,9 +1,9 @@ -// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -o %t +// RUN: %clang_cc1 %s -fno-rtti -triple=i386-pc-win32 -emit-llvm -o %t // RUN: FileCheck %s < %t // RUN: FileCheck --check-prefix=CHECK2 %s < %t // For now, just make sure x86_64 doesn't crash. -// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=x86_64-pc-win32 -emit-llvm -o %t +// RUN: %clang_cc1 %s -fno-rtti -triple=x86_64-pc-win32 -emit-llvm -o %t struct VBase { virtual ~VBase(); @@ -312,3 +312,151 @@ D::~D() { } } + +namespace test2 { +struct A { A(); }; +struct B : virtual A { B() {} }; +struct C : B, A { C() {} }; + +// PR18435: Order mattered here. We were generating code for the delegating +// call to B() from C(). +void callC() { C x; } + +// CHECK-LABEL: define linkonce_odr x86_thiscallcc %"struct.test2::C"* @"\01??0C@test2@@QAE@XZ" +// CHECK: (%"struct.test2::C"* returned %this, i32 %is_most_derived) +// CHECK: br i1 +// Virtual bases +// CHECK: call x86_thiscallcc %"struct.test2::A"* @"\01??0A@test2@@QAE@XZ"(%"struct.test2::A"* %{{.*}}) +// CHECK: br label +// Non-virtual bases +// CHECK: call x86_thiscallcc %"struct.test2::B"* @"\01??0B@test2@@QAE@XZ"(%"struct.test2::B"* %{{.*}}, i32 0) +// CHECK: call x86_thiscallcc %"struct.test2::A"* @"\01??0A@test2@@QAE@XZ"(%"struct.test2::A"* %{{.*}}) +// CHECK: ret + +// CHECK2-LABEL: define linkonce_odr x86_thiscallcc %"struct.test2::B"* @"\01??0B@test2@@QAE@XZ" +// CHECK2: (%"struct.test2::B"* returned %this, i32 %is_most_derived) +// CHECK2: call x86_thiscallcc %"struct.test2::A"* @"\01??0A@test2@@QAE@XZ"(%"struct.test2::A"* %{{.*}}) +// CHECK2: ret + +} + +namespace test3 { +// PR19104: A non-virtual call of a virtual method doesn't use vftable thunks, +// so requires only static adjustment which is different to the one used +// for virtual calls. +struct A { + virtual void foo(); +}; + +struct B : virtual A { + virtual void bar(); +}; + +struct C : virtual A { + virtual void foo(); +}; + +struct D : B, C { + virtual void bar(); + int field; // Laid out between C and A subobjects in D. +}; + +void D::bar() { + // CHECK-LABEL: define x86_thiscallcc void @"\01?bar@D@test3@@UAEXXZ"(%"struct.test3::D"* %this) + + C::foo(); + // Shouldn't need any vbtable lookups. All we have to do is adjust to C*, + // then compensate for the adjustment performed in the C::foo() prologue. + // CHECK-NOT: load i8** + // CHECK: %[[OBJ_i8:.*]] = bitcast %"struct.test3::D"* %{{.*}} to i8* + // CHECK: %[[C_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 8 + // CHECK: %[[C:.*]] = bitcast i8* %[[C_i8]] to %"struct.test3::C"* + // CHECK: %[[C_i8:.*]] = bitcast %"struct.test3::C"* %[[C]] to i8* + // CHECK: %[[ARG:.*]] = getelementptr i8* %[[C_i8]], i32 4 + // CHECK: call x86_thiscallcc void @"\01?foo@C@test3@@UAEXXZ"(i8* %[[ARG]]) + // CHECK: ret +} +} + +namespace test4{ +// PR19172: We used to merge method vftable locations wrong. + +struct A { + virtual ~A() {} +}; + +struct B { + virtual ~B() {} +}; + +struct C : virtual A, B { + virtual ~C(); +}; + +void foo(void*); + +C::~C() { + // CHECK-LABEL: define x86_thiscallcc void @"\01??1C@test4@@UAE@XZ"(%"struct.test4::C"* %this) + + // In this case "this" points to the most derived class, so no GEPs needed. + // CHECK-NOT: getelementptr + // CHECK-NOT: bitcast + // CHECK: %[[VFPTR_i8:.*]] = bitcast %"struct.test4::C"* %{{.*}} to [1 x i8*]** + // CHECK: store [1 x i8*]* @"\01??_7C@test4@@6BB@1@@", [1 x i8*]** %[[VFPTR_i8]] + + foo(this); + // CHECK: ret +} + +void destroy(C *obj) { + // CHECK-LABEL: define void @"\01?destroy@test4@@YAXPAUC@1@@Z"(%"struct.test4::C"* %obj) + + delete obj; + // CHECK: %[[VPTR:.*]] = bitcast %"struct.test4::C"* %[[OBJ:.*]] to void (%"struct.test4::C"*, i32)*** + // CHECK: %[[VFTABLE:.*]] = load void (%"struct.test4::C"*, i32)*** %[[VPTR]] + // CHECK: %[[VFTENTRY:.*]] = getelementptr inbounds void (%"struct.test4::C"*, i32)** %[[VFTABLE]], i64 0 + // CHECK: %[[VFUN:.*]] = load void (%"struct.test4::C"*, i32)** %[[VFTENTRY]] + // CHECK: call x86_thiscallcc void %[[VFUN]](%"struct.test4::C"* %[[OBJ]], i32 1) + // CHECK: ret +} + +struct D { + virtual void d(); +}; + +// The first non-virtual base doesn't have a vdtor, +// but "this adjustment" is not needed. +struct E : D, B, virtual A { + virtual ~E(); +}; + +E::~E() { + // CHECK-LABEL: define x86_thiscallcc void @"\01??1E@test4@@UAE@XZ"(%"struct.test4::E"* %this) + + // In this case "this" points to the most derived class, so no GEPs needed. + // CHECK-NOT: getelementptr + // CHECK-NOT: bitcast + // CHECK: %[[VFPTR_i8:.*]] = bitcast %"struct.test4::E"* %{{.*}} to [1 x i8*]** + // CHECK: store [1 x i8*]* @"\01??_7E@test4@@6BD@1@@", [1 x i8*]** %[[VFPTR_i8]] + foo(this); +} + +void destroy(E *obj) { + // CHECK-LABEL: define void @"\01?destroy@test4@@YAXPAUE@1@@Z"(%"struct.test4::E"* %obj) + + // CHECK-NOT: getelementptr + // CHECK: %[[OBJ_i8:.*]] = bitcast %"struct.test4::E"* %[[OBJ:.*]] to i8* + // CHECK: %[[B_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 4 + // CHECK: %[[VPTR:.*]] = bitcast i8* %[[B_i8]] to void (%"struct.test4::E"*, i32)*** + // CHECK: %[[VFTABLE:.*]] = load void (%"struct.test4::E"*, i32)*** %[[VPTR]] + // CHECK: %[[VFTENTRY:.*]] = getelementptr inbounds void (%"struct.test4::E"*, i32)** %[[VFTABLE]], i64 0 + // CHECK: %[[VFUN:.*]] = load void (%"struct.test4::E"*, i32)** %[[VFTENTRY]] + // CHECK: %[[OBJ_i8:.*]] = bitcast %"struct.test4::E"* %[[OBJ]] to i8* + // CHECK: %[[B_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 4 + // FIXME: in fact, the call should take i8* and the bitcast is redundant. + // CHECK: %[[B_as_E:.*]] = bitcast i8* %[[B_i8]] to %"struct.test4::E"* + // CHECK: call x86_thiscallcc void %[[VFUN]](%"struct.test4::E"* %[[B_as_E]], i32 1) + delete obj; +} + +} |