llvm/clang/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp

// RUN: %clang_cc1 -std=c++11 -fno-rtti -emit-llvm -triple=i386-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK32
// RUN: %clang_cc1 -std=c++11 -fno-rtti -emit-llvm -triple=x86_64-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK64

struct S {
  int x, y, z;
};

// U is not trivially copyable, and requires inalloca to pass by value.
struct U {
  int u;
  U();
  ~U();
  U(const U &);
};

struct B;

struct C {
  virtual void foo();
  virtual int bar(int, double);
  virtual S baz(int);
  virtual S qux(U);
  virtual void thud(...);
  virtual void (B::*plugh())();
};

namespace {
struct D {
  virtual void foo();
};
}

void f() {
  void (C::*ptr)();
  ptr = &C::foo;
  ptr = &C::foo; // Don't crash trying to define the thunk twice :)

  int (C::*ptr2)(int, double);
  ptr2 = &C::bar;

  S (C::*ptr3)(int);
  ptr3 = &C::baz;

  void (D::*ptr4)();
  ptr4 = &D::foo;

  S (C::*ptr5)(U);
  ptr5 = &C::qux;

  void (C::*ptr6)(...);
  ptr6 = &C::thud;

  auto ptr7 = &C::plugh;


// CHECK32-LABEL: define dso_local void @"?f@@YAXXZ"()
// CHECK32: store ptr @"??_9C@@$BA@AE", ptr %ptr
// CHECK32: store ptr @"??_9C@@$B3AE", ptr %ptr2
// CHECK32: store ptr @"??_9C@@$B7AE", ptr %ptr3
// CHECK32: store ptr @"??_9D@?A0x{{[^@]*}}@@$BA@AE", ptr %ptr4
// CHECK32: }
//
// CHECK64-LABEL: define dso_local void @"?f@@YAXXZ"()
// CHECK64: store ptr @"??_9C@@$BA@AA", ptr %ptr
// CHECK64: store ptr @"??_9C@@$B7AA", ptr %ptr2
// CHECK64: store ptr @"??_9C@@$BBA@AA", ptr %ptr3
// CHECK64: store ptr @"??_9D@?A0x{{[^@]*}}@@$BA@AA", ptr %ptr
// CHECK64: }
}


// Thunk for calling the 1st virtual function in C with no parameters.
// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"??_9C@@$BA@AE"(ptr noundef %this, ...)
// CHECK32: #[[ATTR:[0-9]+]]
// CHECK32-NOT:             unnamed_addr
// CHECK32:                 comdat
// CHECK32: [[VPTR:%.*]] = getelementptr inbounds ptr, ptr %{{.*}}, i64 0
// CHECK32: [[CALLEE:%.*]] = load ptr, ptr [[VPTR]]
// CHECK32: musttail call x86_thiscallcc void (ptr, ...) [[CALLEE]](ptr noundef %{{.*}}, ...)
// CHECK32-NEXT: ret void
// CHECK32: }
//
// CHECK64-LABEL: define linkonce_odr void @"??_9C@@$BA@AA"(ptr noundef %this, ...)
// CHECK64: #[[ATTR:[0-9]+]]
// CHECK64-NOT:             unnamed_addr
// CHECK64:                 comdat
// CHECK64: [[VPTR:%.*]] = getelementptr inbounds ptr, ptr %{{.*}}, i64 0
// CHECK64: [[CALLEE:%.*]] = load ptr, ptr [[VPTR]]
// CHECK64: musttail call void (ptr, ...) [[CALLEE]](ptr noundef %{{.*}}, ...)
// CHECK64-NEXT: ret void
// CHECK64: }

// Thunk for calling the 2nd virtual function in C, taking int and double as parameters, returning int.
// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"??_9C@@$B3AE"(ptr noundef %this, ...)
// CHECK32: #[[ATTR]] comdat
// CHECK32: [[VPTR:%.*]] = getelementptr inbounds ptr, ptr %{{.*}}, i64 1
// CHECK32: [[CALLEE:%.*]] = load ptr, ptr [[VPTR]]
// CHECK32: musttail call x86_thiscallcc void (ptr, ...) [[CALLEE]](ptr noundef %{{.*}}, ...)
// CHECK32-NEXT: ret void
// CHECK32: }
//
// CHECK64-LABEL: define linkonce_odr void @"??_9C@@$B7AA"(ptr noundef %this, ...)
// CHECK64: #[[ATTR]] comdat
// CHECK64: [[VPTR:%.*]] = getelementptr inbounds ptr, ptr %{{.*}}, i64 1
// CHECK64: [[CALLEE:%.*]] = load ptr, ptr [[VPTR]]
// CHECK64: musttail call void (ptr, ...) [[CALLEE]](ptr noundef %{{.*}}, ...)
// CHECK64-NEXT: ret void
// CHECK64: }

// Thunk for calling the 3rd virtual function in C, taking an int parameter, returning a struct.
// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"??_9C@@$B7AE"(ptr noundef %this, ...)
// CHECK32: #[[ATTR]] comdat
// CHECK32: [[VPTR:%.*]] = getelementptr inbounds ptr, ptr %{{.*}}, i64 2
// CHECK32: [[CALLEE:%.*]] = load ptr, ptr [[VPTR]]
// CHECK32: musttail call x86_thiscallcc void (ptr, ...) [[CALLEE]](ptr noundef %{{.*}}, ...)
// CHECK32-NEXT: ret void
// CHECK32: }
//
// CHECK64-LABEL: define linkonce_odr void @"??_9C@@$BBA@AA"(ptr noundef %this, ...)
// CHECK64: #[[ATTR]] comdat
// CHECK64: [[VPTR:%.*]] = getelementptr inbounds ptr, ptr %{{.*}}, i64 2
// CHECK64: [[CALLEE:%.*]] = load ptr, ptr [[VPTR]]
// CHECK64: musttail call void (ptr, ...) [[CALLEE]](ptr noundef %{{.*}}, ...)
// CHECK64-NEXT: ret void
// CHECK64: }

// Thunk for calling the virtual function in internal class D.
// CHECK32-LABEL: define internal x86_thiscallcc void @"??_9D@?A0x{{[^@]*}}@@$BA@AE"(ptr noundef %this, ...)
// CHECK32: #[[ATTR]]
// CHECK32: [[VPTR:%.*]] = getelementptr inbounds ptr, ptr %{{.*}}, i64 0
// CHECK32: [[CALLEE:%.*]] = load ptr, ptr [[VPTR]]
// CHECK32: musttail call x86_thiscallcc void (ptr, ...) [[CALLEE]](ptr noundef %{{.*}}, ...)
// CHECK32-NEXT: ret void
// CHECK32: }
//
// CHECK64-LABEL: define internal void @"??_9D@?A0x{{[^@]*}}@@$BA@AA"(ptr noundef %this, ...)
// CHECK64: #[[ATTR]]
// CHECK64: [[VPTR:%.*]] = getelementptr inbounds ptr, ptr %{{.*}}, i64 0
// CHECK64: [[CALLEE:%.*]] = load ptr, ptr [[VPTR]]
// CHECK64: musttail call void (ptr, ...) [[CALLEE]](ptr noundef %{{.*}}, ...)
// CHECK64-NEXT: ret void
// CHECK64: }

// Thunk for calling the fourth virtual function in C, taking a struct parameter
// and returning a struct.
// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"??_9C@@$BM@AE"(ptr noundef %this, ...) {{.*}} comdat
// CHECK32: [[VPTR:%.*]] = getelementptr inbounds ptr, ptr %{{.*}}, i64 3
// CHECK32: [[CALLEE:%.*]] = load ptr, ptr [[VPTR]]
// CHECK32: musttail call x86_thiscallcc void (ptr, ...) [[CALLEE]](ptr noundef %{{.*}}, ...)
// CHECK32-NEXT: ret void
// CHECK32: }
//
// CHECK64-LABEL: define linkonce_odr void @"??_9C@@$BBI@AA"(ptr noundef %this, ...) {{.*}} comdat
// CHECK64: [[VPTR:%.*]] = getelementptr inbounds ptr, ptr %{{.*}}, i64 3
// CHECK64: [[CALLEE:%.*]] = load ptr, ptr [[VPTR]]
// CHECK64: musttail call void (ptr, ...) [[CALLEE]](ptr noundef %{{.*}}, ...)
// CHECK64: ret void
// CHECK64: }

// Thunk for calling the fifth virtual function in C which uses the __cdecl calling convention.
// CHECK32-LABEL: define linkonce_odr void @"??_9C@@$BBA@AA"(ptr noundef %this, ...) {{.*}} comdat align 2 {
// CHECK32: [[VPTR:%.*]] = getelementptr inbounds ptr, ptr %{{.*}}, i64 4
// CHECK32: [[CALLEE:%.*]] = load ptr, ptr [[VPTR]]
// CHECK32: musttail call void (ptr, ...) [[CALLEE]](ptr noundef %{{.*}}, ...)
// CHECK32: ret void
// CHECK32: }
//
// CHECK64-LABEL: define linkonce_odr void @"??_9C@@$BCA@AA"(ptr noundef %this, ...) {{.*}} comdat align 2 {
// CHECK64: [[VPTR:%.*]] = getelementptr inbounds ptr, ptr %{{.*}}, i64 4
// CHECK64: [[CALLEE:%.*]] = load ptr, ptr [[VPTR]]
// CHECK64: musttail call void (ptr, ...) [[CALLEE]](ptr noundef %{{.*}}, ...)
// CHECK64: ret void
// CHECK64: }

// CHECK32: define linkonce_odr x86_thiscallcc void @"??_9C@@$BBE@AE"(ptr noundef %this, ...) {{.*}} comdat align 2 {
// CHECK32: [[VPTR:%.*]] = getelementptr inbounds ptr, ptr %{{.*}}, i64 5
// CHECK32: [[CALLEE:%.*]] = load ptr, ptr [[VPTR]]
// CHECK32: musttail call x86_thiscallcc void (ptr, ...) [[CALLEE]](ptr noundef %{{.*}}, ...)
// CHECK32: ret void
// CHECK32: }

// CHECK64: define linkonce_odr void @"??_9C@@$BCI@AA"(ptr noundef %this, ...) {{.*}} comdat align 2 {
// CHECK64: [[VPTR:%.*]] = getelementptr inbounds ptr, ptr %{{.*}}, i64 5
// CHECK64: [[CALLEE:%.*]] = load ptr, ptr [[VPTR]]
// CHECK64: musttail call void (ptr, ...) [[CALLEE]](ptr noundef %{{.*}}, ...)
// CHECK64: ret void
// CHECK64: }

// CHECK32: #[[ATTR]] = {{{.*}}"thunk"{{.*}}}