brintos

brintos / llvm-project-archived public Read only

0
0
Text · 35.9 KiB · 8defb68 Raw
995 lines · cpp
1// RUN: %clang_cc1 -std=c++11 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -fms-extensions | FileCheck -allow-deprecated-dag-overlap %s2// RUN: %clang_cc1 -std=c++11 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=x86_64-pc-win32 -fms-extensions | FileCheck %s -check-prefix=X643// RUN: %clang_cc1 -std=c++17 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=x86_64-pc-win32 -fms-extensions | FileCheck %s -check-prefix=X644// RUN: %clang_cc1 -std=c++11 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -DINCOMPLETE_VIRTUAL -fms-extensions -verify5// RUN: %clang_cc1 -std=c++11 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -DINCOMPLETE_VIRTUAL -DMEMFUN -fms-extensions -verify6 7namespace pr37399 {8template <typename T>9struct Functor {10  void (T::*PtrToMemberFunction)();11};12// CHECK-DAG: %"struct.pr37399::Functor" = type { ptr }13 14template <typename SomeType>15class SimpleDerivedFunctor;16template <typename SomeType>17class SimpleDerivedFunctor : public Functor<SimpleDerivedFunctor<SomeType>> {};18// CHECK-DAG: %"class.pr37399::SimpleDerivedFunctor" = type { %"struct.pr37399::Functor" }19 20SimpleDerivedFunctor<void> SimpleFunctor;21// CHECK-DAG: @"?SimpleFunctor@pr37399@@3V?$SimpleDerivedFunctor@X@1@A" = dso_local global %"class.pr37399::SimpleDerivedFunctor" zeroinitializer, align 422 23short Global = 0;24template <typename SomeType>25class DerivedFunctor;26template <typename SomeType>27class DerivedFunctor28    : public Functor<DerivedFunctor<void>> {29public:30  void Foo() {31    Global = 42;32  }33};34 35class MultipleBase {36public:37  MultipleBase() : Value() {}38  short Value;39};40// CHECK-DAG: %"class.pr37399::MultipleBase" = type { i16 }41 42template <typename SomeType>43class MultiplyDerivedFunctor;44template <typename SomeType>45class MultiplyDerivedFunctor46    : public Functor<MultiplyDerivedFunctor<void>>,47      public MultipleBase {48public:49  void Foo() {50    MultipleBase::Value = 42*2;51  }52};53 54class VirtualBase {55public:56  VirtualBase() : Value() {}57  short Value;58};59// CHECK-DAG: %"class.pr37399::VirtualBase" = type { i16 }60 61template <typename SomeType>62class VirtBaseFunctor63    : public Functor<SomeType>,64      public virtual VirtualBase{};65template <typename SomeType>66class VirtuallyDerivedFunctor;67template <typename SomeType>68class VirtuallyDerivedFunctor69    : public VirtBaseFunctor<VirtuallyDerivedFunctor<void>>,70      public virtual VirtualBase {71public:72  void Foo() {73    VirtualBase::Value = 42*3;74  }75};76} // namespace pr3739977 78pr37399::DerivedFunctor<int>           BFunctor;79// CHECK-DAG: @"?BFunctor@@3V?$DerivedFunctor@H@pr37399@@A" = dso_local global %"[[BFUNCTOR:class.pr37399::DerivedFunctor(\.[0-9]+)?]]" zeroinitializer, align 880// CHECK-DAG: %"[[BFUNCTOR]]" = type { %"[[BFUNCTORBASE:struct.pr37399::Functor(\.[0-9]+)?]]" }81// CHECK-DAG: %"[[BFUNCTORBASE]]" = type { { ptr, i32, i32, i32 } }82pr37399::DerivedFunctor<void>          AFunctor;83// CHECK-DAG: @"?AFunctor@@3V?$DerivedFunctor@X@pr37399@@A" = dso_local global %"[[AFUNCTOR:class.pr37399::DerivedFunctor(\.[0-9]+)?]]" zeroinitializer, align 884// CHECK-DAG: %"[[AFUNCTOR]]" = type { %"[[AFUNCTORBASE:struct.pr37399::Functor(\.[0-9]+)?]]" }85// CHECK-DAG: %"[[AFUNCTORBASE]]" = type { { ptr, i32, i32, i32 } }86 87pr37399::MultiplyDerivedFunctor<int>   DFunctor;88// CHECK-DAG: @"?DFunctor@@3V?$MultiplyDerivedFunctor@H@pr37399@@A" = dso_local global %"[[DFUNCTOR:class.pr37399::MultiplyDerivedFunctor(\.[0-9]+)?]]" zeroinitializer, align 889// CHECK-DAG: %"[[DFUNCTOR]]" = type { %"[[DFUNCTORBASE:struct.pr37399::Functor(\.[0-9]+)?]]", %"class.pr37399::MultipleBase", [6 x i8] }90// CHECK-DAG: %"[[DFUNCTORBASE]]" = type { { ptr, i32, i32, i32 } }91pr37399::MultiplyDerivedFunctor<void>  CFunctor;92// CHECK-DAG: @"?CFunctor@@3V?$MultiplyDerivedFunctor@X@pr37399@@A" = dso_local global %"[[CFUNCTOR:class.pr37399::MultiplyDerivedFunctor(\.[0-9]+)?]]" zeroinitializer, align 893// CHECK-DAG: %"[[CFUNCTOR]]" = type { %"[[CFUNCTORBASE:struct.pr37399::Functor(\.[0-9]+)?]]", %"class.pr37399::MultipleBase", [6 x i8] }94// CHECK-DAG: %"[[CFUNCTORBASE]]" = type { { ptr, i32, i32, i32 } }95 96pr37399::VirtuallyDerivedFunctor<int>  FFunctor;97// CHECK-DAG: @"?FFunctor@@3V?$VirtuallyDerivedFunctor@H@pr37399@@A" = dso_local global %"[[FFUNCTOR:class.pr37399::VirtuallyDerivedFunctor(\.[0-9]+)?]]" zeroinitializer, align 898// CHECK-DAG: %"[[FFUNCTOR]]" = type { %"class.pr37399::VirtBaseFunctor.base", %"class.pr37399::VirtualBase" }99pr37399::VirtuallyDerivedFunctor<void> EFunctor;100// CHECK-DAG: @"?EFunctor@@3V?$VirtuallyDerivedFunctor@X@pr37399@@A" = dso_local global %"[[EFUNCTOR:class.pr37399::VirtuallyDerivedFunctor(\.[0-9]+)?]]" zeroinitializer, align 8101// CHECK-DAG: %"[[EFUNCTOR]]" = type { %"class.pr37399::VirtBaseFunctor.base", %"class.pr37399::VirtualBase" }102 103// CHECK-DAG: %"class.pr37399::VirtBaseFunctor.base" = type <{ %"[[VFUNCTORBASE:struct.pr37399::Functor(\.[0-9]+)?]]", ptr, [4 x i8] }>104// CHECK-DAG: %"[[VFUNCTORBASE]]" = type { { ptr, i32, i32, i32 } }105 106namespace pr37399 {107void SingleInheritanceFnPtrCall() {108  BFunctor.PtrToMemberFunction = &DerivedFunctor<void>::Foo;109  (AFunctor.*(BFunctor.PtrToMemberFunction))();110}111void MultipleInheritanceFnPtrCall() {112  DFunctor.PtrToMemberFunction = &MultiplyDerivedFunctor<void>::Foo;113  Global = CFunctor.MultipleBase::Value;114  (CFunctor.*(DFunctor.PtrToMemberFunction))();115  Global = CFunctor.MultipleBase::Value;116}117void VirtualInheritanceFnPtrCall() {118  FFunctor.PtrToMemberFunction = &VirtuallyDerivedFunctor<void>::Foo;119  Global = EFunctor.VirtualBase::Value;120  (EFunctor.*(FFunctor.PtrToMemberFunction))();121  Global = EFunctor.VirtualBase::Value;122}123} // namespace pr37399124 125namespace pr43803 {126// This case is interesting because it exercises conversion between member127// pointer types when emitting constants.128 129struct B;130struct C { int B::*option; };131extern const C table[3];132struct A {133  int x, y;134  // Test the indirect case.135  struct {136    int z;137  };138};139struct B : A {};140const C table[] = {141    {&B::x},142    {&B::y},143    {&B::z},144};145 146// CHECK: @"?table@pr43803@@3QBUC@1@B" = dso_local constant [3 x %"struct.pr43803::C"]147// CHECK-SAME: [%"struct.pr43803::C" { { i32, i32, i32 } zeroinitializer, [4 x i8] undef },148// CHECK-SAME:  %"struct.pr43803::C" { { i32, i32, i32 } { i32 4, i32 0, i32 0 }, [4 x i8] undef },149// CHECK-SAME:  %"struct.pr43803::C" { { i32, i32, i32 } { i32 8, i32 0, i32 0 }, [4 x i8] undef }]150}151 152namespace pr48687 {153template <typename T> struct A {154  T value;155  static constexpr auto address = &A<T>::value;156};157extern template class A<float>;158template class A<float>;159// CHECK: @"?address@?$A@M@pr48687@@2QQ12@MQ12@" = weak_odr dso_local constant i32 0, comdat, align 4160}161 162struct PR26313_Y;163typedef void (PR26313_Y::*PR26313_FUNC)();164struct PR26313_X {165  PR26313_FUNC *ptr;166  PR26313_X();167};168PR26313_X::PR26313_X() {}169void PR26313_f(PR26313_FUNC *p) { delete p; }170 171struct PR26313_Z;172int PR26313_Z::**a = nullptr;173int PR26313_Z::*b = *a;174// CHECK-DAG: @"?a@@3PAPQPR26313_Z@@HA" = dso_local global ptr null, align 4175// CHECK-DAG: @"?b@@3PQPR26313_Z@@HQ1@" = dso_local global { i32, i32, i32 } { i32 0, i32 0, i32 -1 }, align 4176 177namespace PR20947 {178struct A;179int A::**a = nullptr;180// CHECK-DAG: @"?a@PR20947@@3PAPQA@1@HA" = dso_local global ptr null, align 4181 182struct B;183int B::*&b = b;184// CHECK-DAG: @"?b@PR20947@@3AAPQB@1@HA" = dso_local global ptr null, align 4185}186 187namespace PR20017 {188template <typename T>189struct A {190  int T::*m_fn1() { return nullptr; }191};192struct B;193auto a = &A<B>::m_fn1;194// CHECK-DAG: @"?a@PR20017@@3P8?$A@UB@PR20017@@@1@AEPQB@1@HXZQ21@" = dso_local global ptr @"?m_fn1@?$A@UB@PR20017@@@PR20017@@QAEPQB@2@HXZ", align 4195}196 197#ifndef INCOMPLETE_VIRTUAL198struct B1 {199  void foo();200  int b;201};202struct B2 {203  int b2;204  void foo();205};206struct Single : B1 {207  void foo();208};209struct Multiple : B1, B2 {210  int m;211  void foo();212};213struct Virtual : virtual B1 {214  int v;215  void foo();216};217 218struct POD {219  int a;220  int b;221};222 223struct Polymorphic {224  virtual void myVirtual();225  int a;226  int b;227};228 229// This class uses the virtual inheritance model, yet its vbptr offset is not 0.230// We still use zero for the null field offset, despite it being a valid field231// offset.232struct NonZeroVBPtr : POD, Virtual {233  int n;234  void foo();235};236 237struct Unspecified;238struct UnspecSingle;239 240// Check that we can lower the LLVM types and get the null initializers right.241int Single     ::*s_d_memptr;242int Polymorphic::*p_d_memptr;243int Multiple   ::*m_d_memptr;244int Virtual    ::*v_d_memptr;245int NonZeroVBPtr::*n_d_memptr;246int Unspecified::*u_d_memptr;247int UnspecSingle::*us_d_memptr;248// CHECK: @"?s_d_memptr@@3PQSingle@@HQ1@" = dso_local global i32 -1, align 4249// CHECK: @"?p_d_memptr@@3PQPolymorphic@@HQ1@" = dso_local global i32 0, align 4250// CHECK: @"?m_d_memptr@@3PQMultiple@@HQ1@" = dso_local global i32 -1, align 4251// CHECK: @"?v_d_memptr@@3PQVirtual@@HQ1@" = dso_local global { i32, i32 }252// CHECK:   { i32 0, i32 -1 }, align 4253// CHECK: @"?n_d_memptr@@3PQNonZeroVBPtr@@HQ1@" = dso_local global { i32, i32 }254// CHECK:   { i32 0, i32 -1 }, align 4255// CHECK: @"?u_d_memptr@@3PQUnspecified@@HQ1@" = dso_local global { i32, i32, i32 }256// CHECK:   { i32 0, i32 0, i32 -1 }, align 4257// CHECK: @"?us_d_memptr@@3PQUnspecSingle@@HQ1@" = dso_local global { i32, i32, i32 }258// CHECK:   { i32 0, i32 0, i32 -1 }, align 4259 260void (Single  ::*s_f_memptr)();261void (Multiple::*m_f_memptr)();262void (Virtual ::*v_f_memptr)();263// CHECK: @"?s_f_memptr@@3P8Single@@AEXXZQ1@" = dso_local global ptr null, align 4264// CHECK: @"?m_f_memptr@@3P8Multiple@@AEXXZQ1@" = dso_local global { ptr, i32 } zeroinitializer, align 4265// CHECK: @"?v_f_memptr@@3P8Virtual@@AEXXZQ1@" = dso_local global { ptr, i32, i32 } zeroinitializer, align 4266 267// We can define Unspecified after locking in the inheritance model.268struct Unspecified : Multiple, Virtual {269  void foo();270  int u;271};272 273struct UnspecSingle {274  void foo();275};276 277// Test memptr emission in a constant expression.278namespace Const {279void (Single     ::*s_f_mp)() = &Single::foo;280void (Multiple   ::*m_f_mp)() = &B2::foo;281void (Virtual    ::*v_f_mp)() = &Virtual::foo;282void (Unspecified::*u_f_mp)() = &Unspecified::foo;283void (UnspecSingle::*us_f_mp)() = &UnspecSingle::foo;284// CHECK: @"?s_f_mp@Const@@3P8Single@@AEXXZQ2@" =285// CHECK:   global ptr @"?foo@Single@@QAEXXZ", align 4286// CHECK: @"?m_f_mp@Const@@3P8Multiple@@AEXXZQ2@" =287// CHECK:   global { ptr, i32 } { ptr @"?foo@B2@@QAEXXZ", i32 4 }, align 4288// CHECK: @"?v_f_mp@Const@@3P8Virtual@@AEXXZQ2@" =289// CHECK:   global { ptr, i32, i32 } { ptr @"?foo@Virtual@@QAEXXZ", i32 0, i32 0 }, align 4290// CHECK: @"?u_f_mp@Const@@3P8Unspecified@@AEXXZQ2@" =291// CHECK:   global { ptr, i32, i32, i32 } { ptr @"?foo@Unspecified@@QAEXXZ", i32 0, i32 0, i32 0 }, align 4292// CHECK: @"?us_f_mp@Const@@3P8UnspecSingle@@AEXXZQ2@" =293// CHECK:   global { ptr, i32, i32, i32 } { ptr @"?foo@UnspecSingle@@QAEXXZ", i32 0, i32 0, i32 0 }, align 4294}295 296namespace CastParam {297// This exercises ConstExprEmitter instead of ValueDecl::evaluateValue.  The298// extra reinterpret_cast for the parameter type requires more careful folding.299// FIXME: Or does it?  If reinterpret_casts are no-ops, we should be able to300// strip them in evaluateValue() and just proceed as normal with an APValue.301struct A {302  int a;303  void foo(A *p);304};305struct B { int b; };306struct C : B, A { int c; };307 308void (A::*ptr1)(void *) = (void (A::*)(void *)) &A::foo;309// CHECK: @"?ptr1@CastParam@@3P8A@1@AEXPAX@ZQ21@" =310// CHECK:   global ptr @"?foo@A@CastParam@@QAEXPAU12@@Z", align 4311 312// Try a reinterpret_cast followed by a memptr conversion.313void (C::*ptr2)(void *) = (void (C::*)(void *)) (void (A::*)(void *)) &A::foo;314// CHECK: @"?ptr2@CastParam@@3P8C@1@AEXPAX@ZQ21@" =315// CHECK:   global { ptr, i32 } { ptr @"?foo@A@CastParam@@QAEXPAU12@@Z", i32 4 }, align 4316 317void (C::*ptr3)(void *) = (void (C::*)(void *)) (void (A::*)(void *)) (void (A::*)(A *)) 0;318// CHECK: @"?ptr3@CastParam@@3P8C@1@AEXPAX@ZQ21@" =319// CHECK:   global { ptr, i32 } zeroinitializer, align 4320 321struct D : C {322  virtual void isPolymorphic();323  int d;324};325 326// Try a cast that changes the inheritance model.  Null for D is 0, but null for327// C is -1.  We need the cast to long in order to hit the non-APValue path.328int C::*ptr4 = (int C::*) (int D::*) (long D::*) 0;329// CHECK: @"?ptr4@CastParam@@3PQC@1@HQ21@" = dso_local global i32 -1, align 4330 331// MSVC rejects this but we accept it.332int C::*ptr5 = (int C::*) (long D::*) 0;333// CHECK: @"?ptr5@CastParam@@3PQC@1@HQ21@" = dso_local global i32 -1, align 4334}335 336struct UnspecWithVBPtr;337int UnspecWithVBPtr::*forceUnspecWithVBPtr;338struct UnspecWithVBPtr : B1, virtual B2 {339  int u;340  void foo();341};342 343// Test emitting non-virtual member pointers in a non-constexpr setting.344void EmitNonVirtualMemberPointers() {345  void (Single     ::*s_f_memptr)() = &Single::foo;346  void (Multiple   ::*m_f_memptr)() = &Multiple::foo;347  void (Virtual    ::*v_f_memptr)() = &Virtual::foo;348  void (Unspecified::*u_f_memptr)() = &Unspecified::foo;349  void (UnspecWithVBPtr::*u2_f_memptr)() = &UnspecWithVBPtr::foo;350// CHECK: define dso_local void @"?EmitNonVirtualMemberPointers@@YAXXZ"() {{.*}} {351// CHECK:   alloca ptr, align 4352// CHECK:   alloca { ptr, i32 }, align 4353// CHECK:   alloca { ptr, i32, i32 }, align 4354// CHECK:   alloca { ptr, i32, i32, i32 }, align 4355// CHECK:   store ptr @"?foo@Single@@QAEXXZ", ptr %{{.*}}, align 4356// CHECK:   store { ptr, i32 }357// CHECK:     { ptr @"?foo@Multiple@@QAEXXZ", i32 0 },358// CHECK:     ptr %{{.*}}, align 4359// CHECK:   store { ptr, i32, i32 }360// CHECK:     { ptr @"?foo@Virtual@@QAEXXZ", i32 0, i32 0 },361// CHECK:     ptr %{{.*}}, align 4362// CHECK:   store { ptr, i32, i32, i32 }363// CHECK:     { ptr @"?foo@Unspecified@@QAEXXZ", i32 0, i32 0, i32 0 },364// CHECK:     ptr %{{.*}}, align 4365// CHECK:   store { ptr, i32, i32, i32 }366// CHECK:     { ptr @"?foo@UnspecWithVBPtr@@QAEXXZ",367// CHECK:       i32 0, i32 0, i32 0 },368// CHECK:     ptr %{{.*}}, align 4369// CHECK:   ret void370// CHECK: }371}372 373void podMemPtrs() {374  int POD::*memptr;375  memptr = &POD::a;376  memptr = &POD::b;377  if (memptr)378    memptr = 0;379// Check that member pointers use the right offsets and that null is -1.380// CHECK:      define dso_local void @"?podMemPtrs@@YAXXZ"() {{.*}} {381// CHECK:        %[[memptr:.*]] = alloca i32, align 4382// CHECK-NEXT:   store i32 0, ptr %[[memptr]], align 4383// CHECK-NEXT:   store i32 4, ptr %[[memptr]], align 4384// CHECK-NEXT:   %[[memptr_val:.*]] = load i32, ptr %[[memptr]], align 4385// CHECK-NEXT:   %{{.*}} = icmp ne i32 %[[memptr_val]], -1386// CHECK-NEXT:   br i1 %{{.*}}, label %{{.*}}, label %{{.*}}387// CHECK:        store i32 -1, ptr %[[memptr]], align 4388// CHECK:        ret void389// CHECK:      }390}391 392void polymorphicMemPtrs() {393  int Polymorphic::*memptr;394  memptr = &Polymorphic::a;395  memptr = &Polymorphic::b;396  if (memptr)397    memptr = 0;398// Member pointers for polymorphic classes include the vtable slot in their399// offset and use 0 to represent null.400// CHECK:      define dso_local void @"?polymorphicMemPtrs@@YAXXZ"() {{.*}} {401// CHECK:        %[[memptr:.*]] = alloca i32, align 4402// CHECK-NEXT:   store i32 4, ptr %[[memptr]], align 4403// CHECK-NEXT:   store i32 8, ptr %[[memptr]], align 4404// CHECK-NEXT:   %[[memptr_val:.*]] = load i32, ptr %[[memptr]], align 4405// CHECK-NEXT:   %{{.*}} = icmp ne i32 %[[memptr_val]], 0406// CHECK-NEXT:   br i1 %{{.*}}, label %{{.*}}, label %{{.*}}407// CHECK:        store i32 0, ptr %[[memptr]], align 4408// CHECK:        ret void409// CHECK:      }410}411 412bool nullTestDataUnspecified(int Unspecified::*mp) {413  return mp;414// CHECK: define dso_local noundef zeroext i1 @"?nullTestDataUnspecified@@YA_NPQUnspecified@@H@Z"{{.*}} {415// CHECK:   %{{.*}} = load { i32, i32, i32 }, ptr %{{.*}}, align 4416// CHECK:   store { i32, i32, i32 } {{.*}} align 4417// CHECK:   %[[mp:.*]] = load { i32, i32, i32 }, ptr %{{.*}}, align 4418// CHECK:   %[[mp0:.*]] = extractvalue { i32, i32, i32 } %[[mp]], 0419// CHECK:   %[[cmp0:.*]] = icmp ne i32 %[[mp0]], 0420// CHECK:   %[[mp1:.*]] = extractvalue { i32, i32, i32 } %[[mp]], 1421// CHECK:   %[[cmp1:.*]] = icmp ne i32 %[[mp1]], 0422// CHECK:   %[[and0:.*]] = or i1 %[[cmp0]], %[[cmp1]]423// CHECK:   %[[mp2:.*]] = extractvalue { i32, i32, i32 } %[[mp]], 2424// CHECK:   %[[cmp2:.*]] = icmp ne i32 %[[mp2]], -1425// CHECK:   %[[and1:.*]] = or i1 %[[and0]], %[[cmp2]]426// CHECK:   ret i1 %[[and1]]427// CHECK: }428 429// Pass this large type indirectly.430// X64-LABEL: define dso_local noundef zeroext i1 @"?nullTestDataUnspecified@@431// X64:             (ptr dead_on_return noundef %0)432}433 434bool nullTestFunctionUnspecified(void (Unspecified::*mp)()) {435  return mp;436// CHECK: define dso_local noundef zeroext i1 @"?nullTestFunctionUnspecified@@YA_NP8Unspecified@@AEXXZ@Z"{{.*}} {437// CHECK:   %{{.*}} = load { ptr, i32, i32, i32 }, ptr %{{.*}}, align 4438// CHECK:   store { ptr, i32, i32, i32 } {{.*}} align 4439// CHECK:   %[[mp:.*]] = load { ptr, i32, i32, i32 }, ptr %{{.*}}, align 4440// CHECK:   %[[mp0:.*]] = extractvalue { ptr, i32, i32, i32 } %[[mp]], 0441// CHECK:   %[[cmp0:.*]] = icmp ne ptr %[[mp0]], null442// CHECK:   ret i1 %[[cmp0]]443// CHECK: }444}445 446int loadDataMemberPointerVirtual(Virtual *o, int Virtual::*memptr) {447  return o->*memptr;448// Test that we can unpack this aggregate member pointer and load the member449// data pointer.450// CHECK: define dso_local noundef i32 @"?loadDataMemberPointerVirtual@@YAHPAUVirtual@@PQ1@H@Z"{{.*}} {451// CHECK:   %[[o:.*]] = load ptr, ptr %{{.*}}, align 4452// CHECK:   %[[memptr:.*]] = load { i32, i32 }, ptr %{{.*}}, align 4453// CHECK:   %[[memptr0:.*]] = extractvalue { i32, i32 } %[[memptr:.*]], 0454// CHECK:   %[[memptr1:.*]] = extractvalue { i32, i32 } %[[memptr:.*]], 1455// CHECK:   %[[vbptr:.*]] = getelementptr inbounds i8, ptr %[[o]], i32 0456// CHECK:   %[[vbtable:.*]] = load ptr, ptr %[[vbptr_a:.*]]457// CHECK:   %[[memptr1_shr:.*]] = ashr exact i32 %[[memptr1]], 2458// CHECK:   %[[v7:.*]] = getelementptr inbounds i32, ptr %[[vbtable]], i32 %[[memptr1_shr]]459// CHECK:   %[[vbase_offs:.*]] = load i32, ptr %[[v7]]460// CHECK:   %[[v10:.*]] = getelementptr inbounds i8, ptr %[[vbptr]], i32 %[[vbase_offs]]461// CHECK:   %[[offset:.*]] = getelementptr inbounds i8, ptr %[[v10]], i32 %[[memptr0]]462// CHECK:   %[[v12:.*]] = load i32, ptr %[[offset]]463// CHECK:   ret i32 %[[v12]]464// CHECK: }465 466// A two-field data memptr on x64 gets coerced to i64 and is passed in a467// register or memory.468// X64-LABEL: define dso_local noundef i32 @"?loadDataMemberPointerVirtual@@YAHPEAUVirtual@@PEQ1@H@Z"469// X64:             (ptr noundef %o, i64 %memptr.coerce)470}471 472int loadDataMemberPointerUnspecified(Unspecified *o, int Unspecified::*memptr) {473  return o->*memptr;474// Test that we can unpack this aggregate member pointer and load the member475// data pointer.476// CHECK: define dso_local noundef i32 @"?loadDataMemberPointerUnspecified@@YAHPAUUnspecified@@PQ1@H@Z"{{.*}} {477// CHECK:   %[[o:.*]] = load ptr, ptr %{{.*}}, align 4478// CHECK:   %[[memptr:.*]] = load { i32, i32, i32 }, ptr %{{.*}}, align 4479// CHECK:   %[[memptr0:.*]] = extractvalue { i32, i32, i32 } %[[memptr:.*]], 0480// CHECK:   %[[memptr1:.*]] = extractvalue { i32, i32, i32 } %[[memptr:.*]], 1481// CHECK:   %[[memptr2:.*]] = extractvalue { i32, i32, i32 } %[[memptr:.*]], 2482// CHECK:   %[[is_vbase:.*]] = icmp ne i32 %[[memptr2]], 0483// CHECK:   br i1 %[[is_vbase]], label %[[vadjust:.*]], label %[[skip:.*]]484//485// CHECK: [[vadjust]]486// CHECK:   %[[vbptr:.*]] = getelementptr inbounds i8, ptr %[[o]], i32 %[[memptr1]]487// CHECK:   %[[vbtable:.*]] = load ptr, ptr %[[vbptr_a:.*]]488// CHECK:   %[[memptr2_shr:.*]] = ashr exact i32 %[[memptr2]], 2489// CHECK:   %[[v7:.*]] = getelementptr inbounds i32, ptr %[[vbtable]], i32 %[[memptr2_shr]]490// CHECK:   %[[vbase_offs:.*]] = load i32, ptr %[[v7]]491// CHECK:   %[[base_adj:.*]] = getelementptr inbounds i8, ptr %[[vbptr]], i32 %[[vbase_offs]]492//493// CHECK: [[skip]]494// CHECK:   %[[new_base:.*]] = phi ptr [ %[[o]], %{{.*}} ], [ %[[base_adj]], %[[vadjust]] ]495// CHECK:   %[[offset:.*]] = getelementptr inbounds i8, ptr %[[new_base]], i32 %[[memptr0]]496// CHECK:   %[[v12:.*]] = load i32, ptr %[[offset]]497// CHECK:   ret i32 %[[v12]]498// CHECK: }499}500 501void callMemberPointerSingle(Single *o, void (Single::*memptr)()) {502  (o->*memptr)();503// Just look for an indirect thiscall.504// CHECK: define dso_local void @"?callMemberPointerSingle@@{{.*}} {{.*}} {505// CHECK:   call x86_thiscallcc void %{{.*}}({{.*}} %{{.*}})506// CHECK:   ret void507// CHECK: }508 509// X64-LABEL: define dso_local void @"?callMemberPointerSingle@@510// X64:           (ptr noundef %o, ptr %memptr)511// X64:   ret void512}513 514void callMemberPointerMultiple(Multiple *o, void (Multiple::*memptr)()) {515  (o->*memptr)();516// CHECK: define dso_local void @"?callMemberPointerMultiple@@{{.*}} {517// CHECK:   %[[memptr0:.*]] = extractvalue { ptr, i32 } %{{.*}}, 0518// CHECK:   %[[memptr1:.*]] = extractvalue { ptr, i32 } %{{.*}}, 1519// CHECK:   %[[this_adjusted:.*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 %[[memptr1]]520// CHECK:   call x86_thiscallcc void %[[memptr0]]({{.*}} %[[this_adjusted]])521// CHECK:   ret void522// CHECK: }523}524 525void callMemberPointerVirtualBase(Virtual *o, void (Virtual::*memptr)()) {526  (o->*memptr)();527// This shares a lot with virtual data member pointers.528// CHECK: define dso_local void @"?callMemberPointerVirtualBase@@{{.*}} {529// CHECK:   %[[memptr0:.*]] = extractvalue { ptr, i32, i32 } %{{.*}}, 0530// CHECK:   %[[memptr1:.*]] = extractvalue { ptr, i32, i32 } %{{.*}}, 1531// CHECK:   %[[memptr2:.*]] = extractvalue { ptr, i32, i32 } %{{.*}}, 2532// CHECK:   %[[vbptr:.*]] = getelementptr inbounds i8, ptr %{{.*}}, i32 0533// CHECK:   %[[vbtable:.*]] = load ptr, ptr %[[vbptr_a:.*]]534// CHECK:   %[[memptr2_shr:.*]] = ashr exact i32 %[[memptr2]], 2535// CHECK:   %[[v7:.*]] = getelementptr inbounds i32, ptr %[[vbtable]], i32 %[[memptr2_shr]]536// CHECK:   %[[vbase_offs:.*]] = load i32, ptr %[[v7]]537// CHECK:   %[[v10:.*]] = getelementptr inbounds i8, ptr %[[vbptr]], i32 %[[vbase_offs]]538// CHECK:   %[[this_adjusted:.*]] = getelementptr inbounds i8, ptr %[[v10]], i32 %[[memptr1]]539// CHECK:   call x86_thiscallcc void %[[memptr0]]({{.*}} %[[this_adjusted]])540// CHECK:   ret void541// CHECK: }542}543 544bool compareSingleFunctionMemptr(void (Single::*l)(), void (Single::*r)()) {545  return l == r;546// Should only be one comparison here.547// CHECK: define dso_local noundef zeroext i1 @"?compareSingleFunctionMemptr@@YA_NP8Single@@AEXXZ0@Z"{{.*}} {548// CHECK-NOT: icmp549// CHECK:   %[[r:.*]] = icmp eq550// CHECK-NOT: icmp551// CHECK:   ret i1 %[[r]]552// CHECK: }553 554// X64-LABEL: define dso_local noundef zeroext i1 @"?compareSingleFunctionMemptr@@555// X64:             (ptr %{{[^,]*}}, ptr %{{[^)]*}})556}557 558bool compareNeqSingleFunctionMemptr(void (Single::*l)(), void (Single::*r)()) {559  return l != r;560// Should only be one comparison here.561// CHECK: define dso_local noundef zeroext i1 @"?compareNeqSingleFunctionMemptr@@YA_NP8Single@@AEXXZ0@Z"{{.*}} {562// CHECK-NOT: icmp563// CHECK:   %[[r:.*]] = icmp ne564// CHECK-NOT: icmp565// CHECK:   ret i1 %[[r]]566// CHECK: }567}568 569bool unspecFuncMemptrEq(void (Unspecified::*l)(), void (Unspecified::*r)()) {570  return l == r;571// CHECK: define dso_local noundef zeroext i1 @"?unspecFuncMemptrEq@@YA_NP8Unspecified@@AEXXZ0@Z"{{.*}} {572// CHECK:   %[[lhs0:.*]] = extractvalue { ptr, i32, i32, i32 } %[[l:.*]], 0573// CHECK:   %{{.*}} = extractvalue { ptr, i32, i32, i32 } %[[r:.*]], 0574// CHECK:   %[[cmp0:.*]] = icmp eq ptr %[[lhs0]], %{{.*}}575// CHECK:   %{{.*}} = extractvalue { ptr, i32, i32, i32 } %[[l]], 1576// CHECK:   %{{.*}} = extractvalue { ptr, i32, i32, i32 } %[[r]], 1577// CHECK:   %[[cmp1:.*]] = icmp eq i32578// CHECK:   %{{.*}} = extractvalue { ptr, i32, i32, i32 } %[[l]], 2579// CHECK:   %{{.*}} = extractvalue { ptr, i32, i32, i32 } %[[r]], 2580// CHECK:   %[[cmp2:.*]] = icmp eq i32581// CHECK:   %[[res12:.*]] = and i1 %[[cmp1]], %[[cmp2]]582// CHECK:   %{{.*}} = extractvalue { ptr, i32, i32, i32 } %[[l]], 3583// CHECK:   %{{.*}} = extractvalue { ptr, i32, i32, i32 } %[[r]], 3584// CHECK:   %[[cmp3:.*]] = icmp eq i32585// CHECK:   %[[res123:.*]] = and i1 %[[res12]], %[[cmp3]]586// CHECK:   %[[iszero:.*]] = icmp eq ptr %[[lhs0]], null587// CHECK:   %[[bits_or_null:.*]] = or i1 %[[res123]], %[[iszero]]588// CHECK:   %{{.*}} = and i1 %[[bits_or_null]], %[[cmp0]]589// CHECK:   ret i1 %{{.*}}590// CHECK: }591 592// X64-LABEL: define dso_local noundef zeroext i1 @"?unspecFuncMemptrEq@@593// X64:             (ptr dead_on_return noundef %0, ptr dead_on_return noundef %1)594}595 596bool unspecFuncMemptrNeq(void (Unspecified::*l)(), void (Unspecified::*r)()) {597  return l != r;598// CHECK: define dso_local noundef zeroext i1 @"?unspecFuncMemptrNeq@@YA_NP8Unspecified@@AEXXZ0@Z"{{.*}} {599// CHECK:   %[[lhs0:.*]] = extractvalue { ptr, i32, i32, i32 } %[[l:.*]], 0600// CHECK:   %{{.*}} = extractvalue { ptr, i32, i32, i32 } %[[r:.*]], 0601// CHECK:   %[[cmp0:.*]] = icmp ne ptr %[[lhs0]], %{{.*}}602// CHECK:   %{{.*}} = extractvalue { ptr, i32, i32, i32 } %[[l]], 1603// CHECK:   %{{.*}} = extractvalue { ptr, i32, i32, i32 } %[[r]], 1604// CHECK:   %[[cmp1:.*]] = icmp ne i32605// CHECK:   %{{.*}} = extractvalue { ptr, i32, i32, i32 } %[[l]], 2606// CHECK:   %{{.*}} = extractvalue { ptr, i32, i32, i32 } %[[r]], 2607// CHECK:   %[[cmp2:.*]] = icmp ne i32608// CHECK:   %[[res12:.*]] = or i1 %[[cmp1]], %[[cmp2]]609// CHECK:   %{{.*}} = extractvalue { ptr, i32, i32, i32 } %[[l]], 3610// CHECK:   %{{.*}} = extractvalue { ptr, i32, i32, i32 } %[[r]], 3611// CHECK:   %[[cmp3:.*]] = icmp ne i32612// CHECK:   %[[res123:.*]] = or i1 %[[res12]], %[[cmp3]]613// CHECK:   %[[iszero:.*]] = icmp ne ptr %[[lhs0]], null614// CHECK:   %[[bits_or_null:.*]] = and i1 %[[res123]], %[[iszero]]615// CHECK:   %{{.*}} = or i1 %[[bits_or_null]], %[[cmp0]]616// CHECK:   ret i1 %{{.*}}617// CHECK: }618}619 620bool unspecDataMemptrEq(int Unspecified::*l, int Unspecified::*r) {621  return l == r;622// CHECK: define dso_local noundef zeroext i1 @"?unspecDataMemptrEq@@YA_NPQUnspecified@@H0@Z"{{.*}} {623// CHECK:   extractvalue { i32, i32, i32 } %{{.*}}, 0624// CHECK:   extractvalue { i32, i32, i32 } %{{.*}}, 0625// CHECK:   icmp eq i32626// CHECK:   extractvalue { i32, i32, i32 } %{{.*}}, 1627// CHECK:   extractvalue { i32, i32, i32 } %{{.*}}, 1628// CHECK:   icmp eq i32629// CHECK:   extractvalue { i32, i32, i32 } %{{.*}}, 2630// CHECK:   extractvalue { i32, i32, i32 } %{{.*}}, 2631// CHECK:   icmp eq i32632// CHECK:   and i1633// CHECK:   and i1634// CHECK:   ret i1635// CHECK: }636 637// X64-LABEL: define dso_local noundef zeroext i1 @"?unspecDataMemptrEq@@638// X64:             (ptr dead_on_return noundef %0, ptr dead_on_return noundef %1)639}640 641void (Multiple::*convertB2FuncToMultiple(void (B2::*mp)()))() {642  return mp;643// CHECK: define dso_local i64 @"?convertB2FuncToMultiple@@YAP8Multiple@@AEXXZP8B2@@AEXXZ@Z"{{.*}} {644// CHECK:   store645// CHECK:   %[[mp:.*]] = load ptr, ptr %{{.*}}, align 4646// CHECK:   icmp ne ptr %[[mp]], null647// CHECK:   br i1 %{{.*}} label %{{.*}}, label %{{.*}}648//649//        memptr.convert:                                   ; preds = %entry650// CHECK:   insertvalue { ptr, i32 } poison, ptr %[[mp]], 0651// CHECK:   insertvalue { ptr, i32 } %{{.*}}, i32 4, 1652// CHECK:   br label653//654//        memptr.converted:                                 ; preds = %memptr.convert, %entry655// CHECK:   phi { ptr, i32 } [ zeroinitializer, %{{.*}} ], [ {{.*}} ]656// CHECK: }657}658 659void (B2::*convertMultipleFuncToB2(void (Multiple::*mp)()))() {660// FIXME: cl emits warning C4407 on this code because of the representation661// change.  We might want to do the same.662  return static_cast<void (B2::*)()>(mp);663// FIXME: We should return ptr instead of i32 here.  The ptrtoint cast prevents664// LLVM from optimizing away the branch.  This is likely a bug in665// lib/CodeGen/Targets/X86.cpp with how we classify memptr types for returns.666//667// CHECK: define dso_local i32 @"?convertMultipleFuncToB2@@YAP8B2@@AEXXZP8Multiple@@AEXXZ@Z"{{.*}} {668// CHECK:   store669// CHECK:   %[[src:.*]] = load { ptr, i32 }, ptr %{{.*}}, align 4670// CHECK:   extractvalue { ptr, i32 } %[[src]], 0671// CHECK:   icmp ne ptr %{{.*}}, null672// CHECK:   br i1 %{{.*}}, label %{{.*}}, label %{{.*}}673//674//        memptr.convert:                                   ; preds = %entry675// CHECK:   %[[fp:.*]] = extractvalue { ptr, i32 } %[[src]], 0676// CHECK:   br label677//678//        memptr.converted:                                 ; preds = %memptr.convert, %entry679// CHECK:   phi ptr [ null, %{{.*}} ], [ %[[fp]], %{{.*}} ]680// CHECK: }681}682 683namespace Test1 {684 685struct A { int a; };686struct B { int b; };687struct C : virtual A { int c; };688struct D : B, C { int d; };689 690void (D::*convertCToD(void (C::*mp)()))() {691  return mp;692// CHECK: define dso_local void @"?convertCToD@Test1@@YAP8D@1@AEXXZP8C@1@AEXXZ@Z"{{.*}} {693// CHECK:   store694// CHECK:   load { ptr, i32, i32 }, ptr %{{.*}}, align 4695// CHECK:   extractvalue { ptr, i32, i32 } %{{.*}}, 0696// CHECK:   icmp ne ptr %{{.*}}, null697// CHECK:   br i1 %{{.*}}, label %{{.*}}, label %{{.*}}698//699//        memptr.convert:                                   ; preds = %entry700// CHECK:   extractvalue { ptr, i32, i32 } %{{.*}}, 0701// CHECK:   %[[nvoff:.*]] = extractvalue { ptr, i32, i32 } %{{.*}}, 1702// CHECK:   %[[vbidx:.*]] = extractvalue { ptr, i32, i32 } %{{.*}}, 2703// CHECK:   %[[is_nvbase:.*]] = icmp eq i32 %[[vbidx]], 0704// CHECK:   %[[nv_disp:.*]] = add nsw i32 %[[nvoff]], 4705// CHECK:   %[[nv_adj:.*]] = select i1 %[[is_nvbase]], i32 %[[nv_disp]], i32 0706// CHECK:   %[[dst_adj:.*]] = select i1 %[[is_nvbase]], i32 4, i32 0707// CHECK:   %[[adj:.*]] = sub nsw i32 %[[nv_adj]], %[[dst_adj]]708// CHECK:   insertvalue { ptr, i32, i32 } poison, ptr {{.*}}, 0709// CHECK:   insertvalue { ptr, i32, i32 } {{.*}}, i32 %[[adj]], 1710// CHECK:   insertvalue { ptr, i32, i32 } {{.*}}, i32 {{.*}}, 2711// CHECK:   br label712//713//        memptr.converted:                                 ; preds = %memptr.convert, %entry714// CHECK:   phi { ptr, i32, i32 } [ { ptr null, i32 0, i32 -1 }, {{.*}} ], [ {{.*}} ]715// CHECK: }716}717 718}719 720namespace Test2 {721// Test that we dynamically convert between different null reps.722 723struct A { int a; };724struct B : A { int b; };725struct C : A {726  int c;727  virtual void hasVfPtr();728};729 730int A::*reinterpret(int B::*mp) {731  return reinterpret_cast<int A::*>(mp);732// CHECK: define dso_local i32 @"?reinterpret@Test2@@YAPQA@1@HPQB@1@H@Z"{{.*}}  {733// CHECK-NOT: select734// CHECK:   ret i32735// CHECK: }736}737 738int A::*reinterpret(int C::*mp) {739  return reinterpret_cast<int A::*>(mp);740// CHECK: define dso_local i32 @"?reinterpret@Test2@@YAPQA@1@HPQC@1@H@Z"{{.*}}  {741// CHECK:   %[[mp:.*]] = load i32, ptr742// CHECK:   %[[cmp:.*]] = icmp ne i32 %[[mp]], 0743// CHECK:   select i1 %[[cmp]], i32 %[[mp]], i32 -1744// CHECK: }745}746 747}748 749namespace Test3 {750// Make sure we cast 'this' to ptr before using GEP.751 752struct A {753  int a;754  int b;755};756 757int *load_data(A *a, int A::*mp) {758  return &(a->*mp);759// CHECK-LABEL: define dso_local noundef ptr @"?load_data@Test3@@YAPAHPAUA@1@PQ21@H@Z"{{.*}}  {760// CHECK:    %[[a:.*]] = load ptr, ptr %{{.*}}, align 4761// CHECK:    %[[mp:.*]] = load i32, ptr %{{.*}}, align 4762// CHECK:    getelementptr inbounds i8, ptr %[[a]], i32 %[[mp]]763// CHECK: }764}765 766}767 768namespace Test4 {769 770struct A        { virtual void f(); };771struct B        { virtual void g(); };772struct C : A, B { virtual void g(); };773 774void (C::*getmp())() {775  return &C::g;776}777// CHECK-LABEL: define dso_local i64 @"?getmp@Test4@@YAP8C@1@AEXXZXZ"()778// CHECK: store { ptr, i32 } { ptr @"??_9C@Test4@@$BA@AE", i32 4 }, ptr %{{.*}}779//780 781// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"??_9C@Test4@@$BA@AE"(ptr noundef %this, ...) {{.*}} comdat782// CHECK-NOT:  getelementptr783// CHECK:  load ptr, ptr %{{.*}}784// CHECK:  getelementptr inbounds ptr, ptr %{{.*}}, i64 0785// CHECK-NOT:  getelementptr786// CHECK:  musttail call x86_thiscallcc void (ptr, ...) %787 788}789 790namespace pr20007 {791struct A {792  void f();793  void f(int);794};795struct B : public A {};796void test() { void (B::*a)() = &B::f; }797// CHECK-LABEL: define dso_local void @"?test@pr20007@@YAXXZ"798// CHECK: store ptr @"?f@A@pr20007@@QAEXXZ"799}800 801namespace pr20007_kw {802struct A {803  void f();804  void f(int);805};806struct __single_inheritance B;807struct B : public A {};808void test() { void (B::*a)() = &B::f; }809// CHECK-LABEL: define dso_local void @"?test@pr20007_kw@@YAXXZ"810// CHECK: store ptr @"?f@A@pr20007_kw@@QAEXXZ"811}812 813namespace pr20007_pragma {814struct A {815  void f();816  void f(int);817};818struct B : public A {};819void test() { (void)(void (B::*)()) &B::f; }820#pragma pointers_to_members(full_generality, virtual_inheritance)821static_assert(sizeof(int B::*) == 4, "");822static_assert(sizeof(int A::*) == 4, "");823#pragma pointers_to_members(best_case)824// CHECK-LABEL: define dso_local void @"?test@pr20007_pragma@@YAXXZ"825}826 827namespace pr20007_pragma2 {828struct A {829};830struct B : public A {831  void f();832};833void test() { (void)&B::f; }834#pragma pointers_to_members(full_generality, virtual_inheritance)835static_assert(sizeof(int B::*) == 4, "");836static_assert(sizeof(int A::*) == 12, "");837#pragma pointers_to_members(best_case)838// CHECK-LABEL: define dso_local void @"?test@pr20007_pragma2@@YAXXZ"839}840 841namespace pr23823 {842struct Base { void Method(); };843struct Child : Base {};844void use(void (Child::*const &)());845void f() { use(&Child::Method); }846#pragma pointers_to_members(full_generality, virtual_inheritance)847static_assert(sizeof(int Base::*) == 4, "");848static_assert(sizeof(int Child::*) == 4, "");849#pragma pointers_to_members(best_case)850}851 852namespace pr19987 {853template <typename T>854struct S {855  int T::*x;856};857 858struct U : S<U> {};859 860static_assert(sizeof(S<U>::x) == 12, "");861}862 863#else864struct __virtual_inheritance A;865#ifdef MEMFUN866int foo(A *a, int (A::*mp)()) {867    return (a->*mp)(); // expected-error{{requires a complete class type}}868}869#else870int foo(A *a, int A::*mp) {871    return a->*mp; // expected-error{{requires a complete class type}}872}873#endif874#endif875 876namespace pr23878 {877struct A { virtual void g(); };878struct B { virtual void f(); };879struct C : virtual B { void f(); };880struct D : A, C {};881 882typedef void (D::*DMemPtrTy)();883 884// CHECK-LABEL: define dso_local void @"?get_memptr@pr23878@@YAP8D@1@AEXXZXZ"885// CHECK: @"??_9C@pr23878@@$BA@AE", i32 0, i32 4886DMemPtrTy get_memptr() { return &D::f; }887}888 889class C {};890 891typedef void (C::*f)();892 893class CA : public C {894public:895  void OnHelp(void);896  int OnHelp(int);897};898 899// CHECK-LABEL: foo_fun900void foo_fun() {901  // CHECK: store ptr @"?OnHelp@CA@@QAEXXZ", ptr902  f func = (f)&CA::OnHelp;903}904namespace PR24703 {905struct S;906 907void f(int S::*&p) {}908// CHECK-LABEL: define dso_local void @"?f@PR24703@@YAXAAPQS@1@H@Z"(909}910 911namespace ReferenceToMPTWithIncompleteClass {912struct S;913struct J;914struct K;915extern K *k;916 917// CHECK-LABEL: @"?f@ReferenceToMPTWithIncompleteClass@@YAIAAPQS@1@H@Z"(918// CHECK: ret i32 12919unsigned f(int S::*&p) { return sizeof p; }920 921// CHECK-LABEL: @"?g@ReferenceToMPTWithIncompleteClass@@YA_NAAPQJ@1@H0@Z"(922bool g(int J::*&p, int J::*&q) { return p == q; }923 924// CHECK-LABEL: @"?h@ReferenceToMPTWithIncompleteClass@@YAHAAPQK@1@H@Z"(925int h(int K::*&p) { return k->*p; }926}927 928namespace PMFInTemplateArgument {929template <class C, int (C::*M)(int)>930void JSMethod();931class A {932  int printd(int);933  void printd();934};935void A::printd() { JSMethod<A, &A::printd>(); }936// CHECK-LABEL: @"??$JSMethod@VA@PMFInTemplateArgument@@$1?printd@12@AAEHH@Z@PMFInTemplateArgument@@YAXXZ"(937}938 939namespace MissingMSInheritanceAttr {940// This is a regression test for an assertion failure that occurred when941// compiling for C++17. The issue concerned a failure to propagate a942// MSInheritanceAttr attribute for the explicit template instantiation943// definition prior to it being required to complete the specialization944// definition in order to determine its alignment so as to resolve a945// lookup for a deallocation function for the virtual destructor.946template <typename>947class a;948struct b {949  typedef void (a<int>::*f)();950  f d;951};952template <typename>953class a {954  virtual ~a();955  b e;956};957extern template class a<int>;958template class a<int>;959#ifdef _WIN64960static_assert(sizeof(b::d) == 24, "");961static_assert(sizeof(void (a<int>::*)()) == 24, "");962#else963static_assert(sizeof(b::d) == 16, "");964static_assert(sizeof(void (a<int>::*)()) == 16, "");965#endif966}967 968namespace ContainerOf {969  using size_t = unsigned long long;970 971  struct List {972    int data;973  };974 975  struct Node {976    int data;977    struct List list1;978    struct List list2;979  };980 981  // CHECK-LABEL: define{{.*}} ptr @"?getOwner@ContainerOf@@982  // CHECK: %memptr.offset = getelementptr i8, ptr null, {{.*}}983  Node* getOwner(List *list, List Node::*member) {984    size_t offset = reinterpret_cast<size_t>(&((Node*)nullptr->*member));985    return reinterpret_cast<Node*>(reinterpret_cast<char*>(list) - offset);986  }987}988 989namespace GH144081 {990  struct A;991  template<int A::*> void f() {}992  template void f<nullptr>();993  // CHECK-LABEL: define{{.*}} void @"??$f@$0A@@GH144081@@YAXXZ"994} // namespace GH144081995