294 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			294 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
| // 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 <typename T> class X;
 | |
| #ifdef VMB
 | |
| template <> class __single_inheritance   X<IncSingle>;
 | |
| template <> class __multiple_inheritance X<IncMultiple>;
 | |
| template <> class __virtual_inheritance  X<IncVirtual>;
 | |
| #else
 | |
| template <> class X<IncSingle>;
 | |
| template <> class X<IncMultiple>;
 | |
| template <> class X<IncVirtual>;
 | |
| #endif
 | |
| // Don't declare X<IncUnspecified>.
 | |
| static_assert(sizeof(int X<IncSingle>::*)           == kSingleDataSize, "");
 | |
| static_assert(sizeof(int X<IncMultiple>::*)         == kMultipleDataSize, "");
 | |
| static_assert(sizeof(int X<IncVirtual>::*)          == kVirtualDataSize, "");
 | |
| static_assert(sizeof(int X<IncUnspecified>::*)      == kUnspecifiedDataSize, "");
 | |
| static_assert(sizeof(void (X<IncSingle>::*)())      == kSingleFunctionSize, "");
 | |
| static_assert(sizeof(void (X<IncMultiple>::*)())    == kMultipleFunctionSize, "");
 | |
| static_assert(sizeof(void (X<IncVirtual>::*)())     == kVirtualFunctionSize, "");
 | |
| static_assert(sizeof(void (X<IncUnspecified>::*)()) == kUnspecifiedFunctionSize, "");
 | |
| 
 | |
| template <typename T>
 | |
| struct Y : T { };
 | |
| static_assert(sizeof(int Y<Single>::*)        == kSingleDataSize, "");
 | |
| static_assert(sizeof(int Y<Multiple>::*)      == kMultipleDataSize, "");
 | |
| static_assert(sizeof(int Y<Virtual>::*)       == kVirtualDataSize, "");
 | |
| static_assert(sizeof(void (Y<Single>::*)())   == kSingleFunctionSize, "");
 | |
| static_assert(sizeof(void (Y<Multiple>::*)()) == kMultipleFunctionSize, "");
 | |
| static_assert(sizeof(void (Y<Virtual>::*)())  == 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<typename T>
 | |
| struct SingleTemplate;
 | |
| template<typename T>
 | |
| struct SingleTemplate<void (T::*)(void)> {
 | |
|   static_assert(sizeof(int T::*) == kSingleDataSize, "");
 | |
|   static_assert(sizeof(void (T::*)()) == kSingleFunctionSize, "");
 | |
| };
 | |
| 
 | |
| template<typename T>
 | |
| struct UnspecTemplate;
 | |
| template<typename T>
 | |
| struct UnspecTemplate<void (T::*)(void)> {
 | |
|   static_assert(sizeof(int T::*) == kUnspecifiedDataSize, "");
 | |
|   static_assert(sizeof(void (T::*)()) == kUnspecifiedFunctionSize, "");
 | |
| };
 | |
| 
 | |
| struct NewUnspecified;
 | |
| SingleTemplate<void (IncSingle::*)()> tmpl_single;
 | |
| UnspecTemplate<void (NewUnspecified::*)()> tmpl_unspec;
 | |
| 
 | |
| struct NewUnspecified { };
 | |
| 
 | |
| static_assert(sizeof(void (NewUnspecified::*)()) == kUnspecifiedFunctionSize, "");
 | |
| 
 | |
| template <typename T>
 | |
| 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<int Virtual::*>(&AA::x);
 | |
|   // expected-error@-1 {{cannot reinterpret_cast from member pointer type}}
 | |
| #endif
 | |
| 
 | |
| namespace ErrorTest {
 | |
| template <typename T, typename U> struct __single_inheritance A;
 | |
|   // expected-warning@-1 {{inheritance model ignored on primary template}}
 | |
| template <typename T> struct __multiple_inheritance A<T, T>;
 | |
|   // expected-warning@-1 {{inheritance model ignored on partial specialization}}
 | |
| template <> struct __single_inheritance A<int, float>;
 | |
| 
 | |
| 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 <typename T>
 | |
| struct A {
 | |
|   int T::*f();
 | |
| };
 | |
| 
 | |
| struct B;
 | |
| 
 | |
| auto a = &A<B>::f;
 | |
| 
 | |
| struct B {};
 | |
| 
 | |
| void q() {
 | |
|   A<B> 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
 |