diff options
Diffstat (limited to 'test/SemaCXX/member-pointer-ms.cpp')
-rw-r--r-- | test/SemaCXX/member-pointer-ms.cpp | 175 |
1 files changed, 164 insertions, 11 deletions
diff --git a/test/SemaCXX/member-pointer-ms.cpp b/test/SemaCXX/member-pointer-ms.cpp index 3b2d0fc..7dca121 100644 --- a/test/SemaCXX/member-pointer-ms.cpp +++ b/test/SemaCXX/member-pointer-ms.cpp @@ -1,14 +1,167 @@ -// RUN: %clang_cc1 -cxx-abi microsoft -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++11 -cxx-abi microsoft -fms-compatibility -fsyntax-only -triple=i386-pc-win32 -verify %s +// RUN: %clang_cc1 -std=c++11 -cxx-abi microsoft -fms-compatibility -fsyntax-only -triple=x86_64-pc-win32 -verify %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. +// +// expected-no-diagnostics -// Test that we reject pointers to members of incomplete classes (for now) -struct A; //expected-note{{forward declaration of 'A'}} -int A::*pai1; //expected-error{{incomplete type 'A'}} +// 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 -// Test that we don't allow reinterpret_casts from pointers of one size to -// pointers of a different size. -struct A {}; -struct B {}; -struct C: A, B {}; +// http://llvm.org/PR12070 +struct Foo { + typedef int Foo::*FooInt; + int f; +}; -void (A::*paf)(); -void (C::*pcf)() = reinterpret_cast<void (C::*)()>(paf); //expected-error{{cannot reinterpret_cast from member pointer type}} +enum { + 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 *), + // Unspecified is weird, it's 1 more slot than virtual. + kUnspecifiedDataSize = kVirtualDataSize + 1 * sizeof(int), + kUnspecifiedFunctionSize = kVirtualFunctionSize + 1 * sizeof(void *), +}; + +// incomplete types +class __single_inheritance IncSingle; +class __multiple_inheritance IncMultiple; +class __virtual_inheritance IncVirtual; +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, ""); + +// An incomplete type with an unspecified inheritance model seems to take one +// more slot than virtual. It's not clear what it's used for yet. +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; +template <> class __single_inheritance X<IncSingle>; +template <> class __multiple_inheritance X<IncMultiple>; +template <> class __virtual_inheritance X<IncVirtual>; +// 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, ""); +// FIXME: Clang fails this assert because it locks in the inheritance model at +// the point of the typedef instead of the first usage, while MSVC does not. +//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)(); +}; |