// RUN: %clang_cc1 -std=c++11 -fms-compatibility -fsyntax-only -triple=i386-pc-win32 -verify -DVMB %s // RUN: %clang_cc1 -std=c++11 -fms-compatibility -fsyntax-only -triple=x86_64-pc-win32 -verify -DVMB %s // RUN: %clang_cc1 -std=c++11 -fms-compatibility -fsyntax-only -triple=x86_64-pc-win32 -verify -DVMV -fms-memptr-rep=virtual %s // // This file should also give no diagnostics when run through cl.exe from MSVS // 2012, which supports C++11 and static_assert. It should pass for both 64-bit // and 32-bit x86. // // Test the size of various member pointer combinations: // - complete and incomplete // - single, multiple, and virtual inheritance (and unspecified for incomplete) // - data and function pointers // - templated with declared specializations with annotations // - template that can be instantiated // http://llvm.org/PR12070 struct Foo { typedef int Foo::*FooInt; int f; }; #ifdef VMB enum { kSingleDataAlign = 1 * sizeof(int), kSingleFunctionAlign = 1 * sizeof(void *), kMultipleDataAlign = 1 * sizeof(int), // Everything with more than 1 field is 8 byte aligned, except virtual data // member pointers on x64 (ugh). kMultipleFunctionAlign = 8, #ifdef _M_X64 kVirtualDataAlign = 4, #else kVirtualDataAlign = 8, #endif kVirtualFunctionAlign = 8, kUnspecifiedDataAlign = 8, kUnspecifiedFunctionAlign = 8, kSingleDataSize = 1 * sizeof(int), kSingleFunctionSize = 1 * sizeof(void *), kMultipleDataSize = 1 * sizeof(int), kMultipleFunctionSize = 2 * sizeof(void *), kVirtualDataSize = 2 * sizeof(int), kVirtualFunctionSize = 2 * sizeof(int) + 1 * sizeof(void *), kUnspecifiedDataSize = 3 * sizeof(int), kUnspecifiedFunctionSize = 2 * sizeof(int) + 2 * sizeof(void *), }; #elif VMV enum { // Everything with more than 1 field is 8 byte aligned, except virtual data // member pointers on x64 (ugh). #ifdef _M_X64 kVirtualDataAlign = 4, #else kVirtualDataAlign = 8, #endif kMultipleDataAlign = kVirtualDataAlign, kSingleDataAlign = kVirtualDataAlign, kUnspecifiedFunctionAlign = 8, kVirtualFunctionAlign = kUnspecifiedFunctionAlign, kMultipleFunctionAlign = kUnspecifiedFunctionAlign, kSingleFunctionAlign = kUnspecifiedFunctionAlign, kUnspecifiedDataSize = 3 * sizeof(int), kVirtualDataSize = kUnspecifiedDataSize, kMultipleDataSize = kUnspecifiedDataSize, kSingleDataSize = kUnspecifiedDataSize, kUnspecifiedFunctionSize = 2 * sizeof(int) + 2 * sizeof(void *), kVirtualFunctionSize = kUnspecifiedFunctionSize, kMultipleFunctionSize = kUnspecifiedFunctionSize, kSingleFunctionSize = kUnspecifiedFunctionSize, }; #else #error "test doesn't yet support this mode!" #endif // incomplete types #ifdef VMB class __single_inheritance IncSingle; class __multiple_inheritance IncMultiple; class __virtual_inheritance IncVirtual; #else class IncSingle; class IncMultiple; class IncVirtual; #endif static_assert(sizeof(int IncSingle::*) == kSingleDataSize, ""); static_assert(sizeof(int IncMultiple::*) == kMultipleDataSize, ""); static_assert(sizeof(int IncVirtual::*) == kVirtualDataSize, ""); static_assert(sizeof(void (IncSingle::*)()) == kSingleFunctionSize, ""); static_assert(sizeof(void (IncMultiple::*)()) == kMultipleFunctionSize, ""); static_assert(sizeof(void (IncVirtual::*)()) == kVirtualFunctionSize, ""); static_assert(__alignof(int IncSingle::*) == __alignof(void *), ""); static_assert(__alignof(int IncMultiple::*) == __alignof(void *), ""); static_assert(__alignof(int IncVirtual::*) == __alignof(void *), ""); static_assert(__alignof(void (IncSingle::*)()) == __alignof(void *), ""); static_assert(__alignof(void (IncMultiple::*)()) == __alignof(void *), ""); static_assert(__alignof(void (IncVirtual::*)()) == __alignof(void *), ""); // An incomplete type with an unspecified inheritance model seems to take one // more slot than virtual. class IncUnspecified; static_assert(sizeof(int IncUnspecified::*) == kUnspecifiedDataSize, ""); static_assert(sizeof(void (IncUnspecified::*)()) == kUnspecifiedFunctionSize, ""); // complete types struct B1 { }; struct B2 { }; struct Single { }; struct Multiple : B1, B2 { }; struct Virtual : virtual B1 { }; static_assert(sizeof(int Single::*) == kSingleDataSize, ""); static_assert(sizeof(int Multiple::*) == kMultipleDataSize, ""); static_assert(sizeof(int Virtual::*) == kVirtualDataSize, ""); static_assert(sizeof(void (Single::*)()) == kSingleFunctionSize, ""); static_assert(sizeof(void (Multiple::*)()) == kMultipleFunctionSize, ""); static_assert(sizeof(void (Virtual::*)()) == kVirtualFunctionSize, ""); // Test both declared and defined templates. template class X; #ifdef VMB template <> class __single_inheritance X; template <> class __multiple_inheritance X; template <> class __virtual_inheritance X; #else template <> class X; template <> class X; template <> class X; #endif // Don't declare X. static_assert(sizeof(int X::*) == kSingleDataSize, ""); static_assert(sizeof(int X::*) == kMultipleDataSize, ""); static_assert(sizeof(int X::*) == kVirtualDataSize, ""); static_assert(sizeof(int X::*) == kUnspecifiedDataSize, ""); static_assert(sizeof(void (X::*)()) == kSingleFunctionSize, ""); static_assert(sizeof(void (X::*)()) == kMultipleFunctionSize, ""); static_assert(sizeof(void (X::*)()) == kVirtualFunctionSize, ""); static_assert(sizeof(void (X::*)()) == kUnspecifiedFunctionSize, ""); template struct Y : T { }; static_assert(sizeof(int Y::*) == kSingleDataSize, ""); static_assert(sizeof(int Y::*) == kMultipleDataSize, ""); static_assert(sizeof(int Y::*) == kVirtualDataSize, ""); static_assert(sizeof(void (Y::*)()) == kSingleFunctionSize, ""); static_assert(sizeof(void (Y::*)()) == kMultipleFunctionSize, ""); static_assert(sizeof(void (Y::*)()) == kVirtualFunctionSize, ""); struct A { int x; void bar(); }; struct B : A { virtual void foo(); }; static_assert(sizeof(int B::*) == kSingleDataSize, ""); // A non-primary base class uses the multiple inheritance model for member // pointers. static_assert(sizeof(void (B::*)()) == kMultipleFunctionSize, ""); struct AA { int x; virtual void foo(); }; struct BB : AA { void bar(); }; struct CC : BB { virtual void baz(); }; static_assert(sizeof(void (CC::*)()) == kSingleFunctionSize, ""); // We start out unspecified. struct ForwardDecl1; struct ForwardDecl2; // Re-declare to force us to iterate decls when adding attributes. struct ForwardDecl1; struct ForwardDecl2; typedef int ForwardDecl1::*MemPtr1; typedef int ForwardDecl2::*MemPtr2; MemPtr1 variable_forces_sizing; struct ForwardDecl1 : B { virtual void foo(); }; struct ForwardDecl2 : B { virtual void foo(); }; static_assert(sizeof(variable_forces_sizing) == kUnspecifiedDataSize, ""); static_assert(sizeof(MemPtr1) == kUnspecifiedDataSize, ""); static_assert(sizeof(MemPtr2) == kSingleDataSize, ""); struct MemPtrInBody { typedef int MemPtrInBody::*MemPtr; int a; operator MemPtr() const { return a ? &MemPtrInBody::a : 0; } }; static_assert(sizeof(MemPtrInBody::MemPtr) == kSingleDataSize, ""); // Passing a member pointer through a template should get the right size. template struct SingleTemplate; template struct SingleTemplate { static_assert(sizeof(int T::*) == kSingleDataSize, ""); static_assert(sizeof(void (T::*)()) == kSingleFunctionSize, ""); }; template struct UnspecTemplate; template struct UnspecTemplate { static_assert(sizeof(int T::*) == kUnspecifiedDataSize, ""); static_assert(sizeof(void (T::*)()) == kUnspecifiedFunctionSize, ""); }; struct NewUnspecified; SingleTemplate tmpl_single; UnspecTemplate tmpl_unspec; struct NewUnspecified { }; static_assert(sizeof(void (NewUnspecified::*)()) == kUnspecifiedFunctionSize, ""); template struct MemPtrInTemplate { // We can't require that the template arg be complete until we're // instantiated. int T::*data_ptr; void (T::*func_ptr)(); }; #ifdef VMB int Virtual::*CastTest = reinterpret_cast(&AA::x); // expected-error@-1 {{cannot reinterpret_cast from member pointer type}} #endif namespace ErrorTest { template struct __single_inheritance A; // expected-warning@-1 {{inheritance model ignored on primary template}} template struct __multiple_inheritance A; // expected-warning@-1 {{inheritance model ignored on partial specialization}} template <> struct __single_inheritance A; struct B {}; // expected-note {{B defined here}} struct __multiple_inheritance B; // expected-error{{inheritance model does not match definition}} struct __multiple_inheritance C {}; // expected-error{{inheritance model does not match definition}} // expected-note@-1 {{C defined here}} struct __virtual_inheritance D; struct D : virtual B {}; } #ifdef VMB namespace PR20017 { template struct A { int T::*f(); }; struct B; auto a = &A::f; struct B {}; void q() { A b; (b.*a)(); } } #pragma pointers_to_members(full_generality, multiple_inheritance) struct TrulySingleInheritance; static_assert(sizeof(int TrulySingleInheritance::*) == kMultipleDataSize, ""); #pragma pointers_to_members(best_case) // This definition shouldn't conflict with the increased generality that the // multiple_inheritance model gave to TrulySingleInheritance. struct TrulySingleInheritance {}; // Even if a definition proceeds the first mention of a pointer to member, we // still give the record the fully general representation. #pragma pointers_to_members(full_generality, virtual_inheritance) struct SingleInheritanceAsVirtualAfterPragma {}; static_assert(sizeof(int SingleInheritanceAsVirtualAfterPragma::*) == 12, ""); #pragma pointers_to_members(best_case) // The above holds even if the pragma comes after the definition. struct SingleInheritanceAsVirtualBeforePragma {}; #pragma pointers_to_members(virtual_inheritance) static_assert(sizeof(int SingleInheritanceAsVirtualBeforePragma::*) == 12, ""); #pragma pointers_to_members(single) // expected-error{{unexpected 'single'}} #endif