microsoft-abi-thunks.cpp 5.07 KB
// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 >%t 2>&1
// RUN: FileCheck --check-prefix=MANGLING %s < %t
// RUN: FileCheck --check-prefix=XMANGLING %s < %t
// RUN: FileCheck --check-prefix=CODEGEN %s < %t
// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -triple=x86_64-pc-win32 2>&1 | FileCheck --check-prefix=MANGLING-X64 %s

void foo(void *);

struct A {
  virtual ~A();
  virtual void public_f();
  // Make sure we don't emit unneeded thunks:
  // XMANGLING-NOT: @"?public_f@A@@QAEXXZ"
 protected:
  virtual void protected_f();
 private:
  virtual void private_f();
};

struct B {
  virtual ~B();
  virtual void public_f();
 protected:
  virtual void protected_f();
 private:
  virtual void private_f();
};


struct C : A, B {
  C();

  virtual ~C();
  // MANGLING-DAG: declare {{.*}} @"??1C@@UAE@XZ"({{.*}})
  // MANGLING-DAG: define {{.*}} @"??_GC@@UAEPAXI@Z"({{.*}})
  // MANGLING-DAG: define {{.*}} @"??_EC@@W3AEPAXI@Z"({{.*}}) {{.*}} comdat
  // MANGLING-X64-DAG: declare {{.*}} @"??1C@@UEAA@XZ"({{.*}})
  // MANGLING-X64-DAG: define {{.*}} @"??_GC@@UEAAPEAXI@Z"({{.*}})
  // MANGLING-X64-DAG: define {{.*}} @"??_EC@@W7EAAPEAXI@Z"({{.*}}) {{.*}} comdat

  // Overrides public_f() of two subobjects with distinct vfptrs, thus needs a thunk.
  virtual void public_f();
  // MANGLING-DAG: @"?public_f@C@@UAEXXZ"
  // MANGLING-DAG: @"?public_f@C@@W3AEXXZ"
  // MANGLING-X64-DAG: @"?public_f@C@@UEAAXXZ"
  // MANGLING-X64-DAG: @"?public_f@C@@W7EAAXXZ"
 protected:
  virtual void protected_f();
  // MANGLING-DAG: @"?protected_f@C@@MAEXXZ"
  // MANGLING-DAG: @"?protected_f@C@@O3AEXXZ"
  // MANGLING-X64-DAG: @"?protected_f@C@@MEAAXXZ"
  // MANGLING-X64-DAG: @"?protected_f@C@@O7EAAXXZ"

 private:
  virtual void private_f();
  // MANGLING-DAG: @"?private_f@C@@EAEXXZ"
  // MANGLING-DAG: @"?private_f@C@@G3AEXXZ"
  // MANGLING-X64-DAG: @"?private_f@C@@EEAAXXZ"
  // MANGLING-X64-DAG: @"?private_f@C@@G7EAAXXZ"
};

C::C() {}  // Emits vftable and forces thunk generation.

// CODEGEN-LABEL: define linkonce_odr dso_local x86_thiscallcc i8* @"??_EC@@W3AEPAXI@Z"(%struct.C* %this, i32 %should_call_delete) {{.*}} comdat
// CODEGEN:   getelementptr i8, i8* {{.*}}, i32 -4
// FIXME: should actually call _EC, not _GC.
// CODEGEN:   call x86_thiscallcc i8* @"??_GC@@UAEPAXI@Z"
// CODEGEN: ret

// CODEGEN-LABEL: define linkonce_odr dso_local x86_thiscallcc void @"?public_f@C@@W3AEXXZ"(%struct.C*
// CODEGEN:   getelementptr i8, i8* {{.*}}, i32 -4
// CODEGEN:   call x86_thiscallcc void @"?public_f@C@@UAEXXZ"(%struct.C*
// CODEGEN: ret

void zoo(C* obj) {
  delete obj;
}

struct D {
  virtual B* goo();
};

struct E : D {
  E();
  virtual C* goo();
  // MANGLING-DAG: @"?goo@E@@UAEPAUC@@XZ"
  // MANGLING-DAG: @"?goo@E@@QAEPAUB@@XZ"
  // MANGLING-X64-DAG: @"?goo@E@@UEAAPEAUC@@XZ"
  // MANGLING-X64-DAG: @"?goo@E@@QEAAPEAUB@@XZ"
};

E::E() {}  // Emits vftable and forces thunk generation.

// CODEGEN-LABEL: define weak_odr dso_local x86_thiscallcc %struct.C* @"?goo@E@@QAEPAUB@@XZ"{{.*}} comdat
// CODEGEN:   call x86_thiscallcc %struct.C* @"?goo@E@@UAEPAUC@@XZ"
// CODEGEN:   getelementptr inbounds i8, i8* {{.*}}, i32 4
// CODEGEN: ret

struct F : virtual A, virtual B {
  virtual void own_method();
  virtual ~F();
};

F f;  // Just make sure we don't crash, e.g. mangling the complete dtor.

struct G : C { };

struct H : E {
  virtual G* goo();
  // MANGLING-DAG: @"?goo@H@@UAEPAUG@@XZ"
  // MANGLING-DAG: @"?goo@H@@QAEPAUB@@XZ"
  // MANGLING-DAG: @"?goo@H@@QAEPAUC@@XZ"
  // MANGLING-X64-DAG: @"?goo@H@@UEAAPEAUG@@XZ"
  // MANGLING-X64-DAG: @"?goo@H@@QEAAPEAUB@@XZ"
  // MANGLING-X64-DAG: @"?goo@H@@QEAAPEAUC@@XZ"
};

H h;

struct I : D {
  I();
  virtual F* goo();
};

I::I() {}  // Emits vftable and forces thunk generation.

// CODEGEN-LABEL: define weak_odr dso_local x86_thiscallcc %struct.{{[BF]}}* @"?goo@I@@QAEPAUB@@XZ"{{.*}} comdat
// CODEGEN: %[[ORIG_RET:.*]] = call x86_thiscallcc %struct.F* @"?goo@I@@UAEPAUF@@XZ"
// CODEGEN: %[[ORIG_RET_i8:.*]] = bitcast %struct.F* %[[ORIG_RET]] to i8*
// CODEGEN: %[[VBPTR_i8:.*]] = getelementptr inbounds i8, i8* %[[ORIG_RET_i8]], i32 4
// CODEGEN: %[[VBPTR:.*]] = bitcast i8* %[[VBPTR_i8]] to i32**
// CODEGEN: %[[VBTABLE:.*]] = load i32*, i32** %[[VBPTR]]
// CODEGEN: %[[VBASE_OFFSET_PTR:.*]] = getelementptr inbounds i32, i32* %[[VBTABLE]], i32 2
// CODEGEN: %[[VBASE_OFFSET:.*]] = load i32, i32* %[[VBASE_OFFSET_PTR]]
// CODEGEN: %[[RES_i8:.*]] = getelementptr inbounds i8, i8* %[[VBPTR_i8]], i32 %[[VBASE_OFFSET]]
// CODEGEN: %[[RES:.*]] = bitcast i8* %[[RES_i8]] to %struct.F*
// CODEGEN: phi %struct.F* {{.*}} %[[RES]]
// CODEGEN: ret %struct.{{[BF]}}*

namespace CrashOnThunksForAttributedType {
// We used to crash on this because the type of foo is an AttributedType, not
// FunctionType, and we had to look through the sugar.
struct A {
  virtual void __stdcall foo();
};
struct B {
  virtual void __stdcall foo();
};
struct C : A, B {
  virtual void __stdcall foo();
};
C c;
}

namespace {
struct E : D {
  E();
  virtual C* goo();
};
E::E() {}
E e;
// Class with internal linkage has internal linkage thunks.
// CODEGEN: define internal x86_thiscallcc %struct.C* @"?goo@E@?A0x{{[^@]*}}@@QAEPAUB@@XZ"
}