llvm-project/clang/test/SemaCXX/member-pointer-ms.cpp
David Majnemer 4bb0980d96 MS ABI: Add support for #pragma pointers_to_members
Introduce a notion of a 'current representation method' for
pointers-to-members.

When starting out, this is set to 'best case' (representation method is
chosen by examining the class, selecting the smallest representation
that would work given the class definition or lack thereof).

This pragma allows the translation unit to dictate exactly what
representation to use, similar to how the inheritance model keywords
operate.

N.B.  PCH support is forthcoming.

Differential Revision: http://llvm-reviews.chandlerc.com/D2723

llvm-svn: 201105
2014-02-10 19:50:15 +00:00

228 lines
9.0 KiB
C++

// RUN: %clang_cc1 -std=c++11 -fms-compatibility -fsyntax-only -triple=i386-pc-win32 -verify %s
// RUN: %clang_cc1 -std=c++11 -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.
//
// 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;
};
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 *),
};
// 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, "");
static_assert(__alignof(int IncSingle::*) == kSingleDataAlign, "");
static_assert(__alignof(int IncMultiple::*) == kMultipleDataAlign, "");
static_assert(__alignof(int IncVirtual::*) == kVirtualDataAlign, "");
static_assert(__alignof(void (IncSingle::*)()) == kSingleFunctionAlign, "");
static_assert(__alignof(void (IncMultiple::*)()) == kMultipleFunctionAlign, "");
static_assert(__alignof(void (IncVirtual::*)()) == kVirtualFunctionAlign, "");
// 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, "");
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)();
};
int Virtual::*CastTest = reinterpret_cast<int Virtual::*>(&AA::x);
// expected-error@-1 {{cannot reinterpret_cast from member pointer type}}
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 {};
}
#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'}}