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