зеркало из https://github.com/microsoft/clang.git
294 строки
10 KiB
C++
294 строки
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
|