Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -422,10 +422,10 @@ template bool ByteCodeExprGen::VisitUnaryExprOrTypeTraitExpr( const UnaryExprOrTypeTraitExpr *E) { + UnaryExprOrTypeTrait Kind = E->getKind(); + QualType ArgType = E->getTypeOfArgument(); - if (E->getKind() == UETT_SizeOf) { - QualType ArgType = E->getTypeOfArgument(); - + if (Kind == UETT_SizeOf) { CharUnits Size; if (ArgType->isVoidType() || ArgType->isFunctionType()) Size = CharUnits::One(); @@ -436,6 +436,32 @@ Size = Ctx.getASTContext().getTypeSizeInChars(ArgType); } + return this->emitConst(Size.getQuantity(), E); + } else if (Kind == UETT_AlignOf || Kind == UETT_PreferredAlignOf) { + // C++ [expr.alignof]p3: + // When alignof is applied to a reference type, the result is the + // alignment of the referenced type. + if (const ReferenceType *Ref = ArgType->getAs()) + ArgType = Ref->getPointeeType(); + + CharUnits Size; + if (ArgType.getQualifiers().hasUnaligned()) + Size = CharUnits::One(); + else { + bool AlignOfReturnsPreferred = + Ctx.getASTContext().getLangOpts().getClangABICompat() <= + LangOptions::ClangABI::Ver7; + + // __alignof is defined to return the preferred alignment. + // Before 8, clang returned the preferred alignment for alignof and + // _Alignof as well. + if (Kind == UETT_PreferredAlignOf || AlignOfReturnsPreferred) + Size = Ctx.getASTContext().toCharUnitsFromBits( + Ctx.getASTContext().getPreferredTypeAlign(ArgType.getTypePtr())); + else + Size = Ctx.getASTContext().getTypeAlignInChars(ArgType.getTypePtr()); + } + return this->emitConst(Size.getQuantity(), E); } Index: clang/test/AST/Interp/class-layout.cpp =================================================================== --- /dev/null +++ clang/test/AST/Interp/class-layout.cpp @@ -0,0 +1,687 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -fexperimental-new-constant-interpreter -std=c++98 -Wno-inaccessible-base -Wno-c++11-extensions +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -fexperimental-new-constant-interpreter -std=c++11 -Wno-inaccessible-base +// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -fsyntax-only -verify -fexperimental-new-constant-interpreter -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=15 +// RUN: %clang_cc1 -triple x86_64-scei-ps4 %s -fsyntax-only -verify -fexperimental-new-constant-interpreter -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=6 +// RUN: %clang_cc1 -triple x86_64-sie-ps5 %s -fsyntax-only -verify -fexperimental-new-constant-interpreter -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=6 +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -fexperimental-new-constant-interpreter -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=6 -DCLANG_ABI_COMPAT=6 +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -fexperimental-new-constant-interpreter -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=14 -DCLANG_ABI_COMPAT=14 +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -fexperimental-new-constant-interpreter -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=15 -DCLANG_ABI_COMPAT=15 +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -fexperimental-new-constant-interpreter -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=16 -DCLANG_ABI_COMPAT=16 +// expected-no-diagnostics + +// FIXME: This is a copy of clang/test/SemaCXX/class-layout.cpp, but with the +// __builtin_offsetof calls commented out. Once that is supported in the +// new interpreter, we might as well remove this duplicated file and +// just use the one in SemaCXX/. + +#define SA(n, p) int a##n[(p) ? 1 : -1] + +struct A { + int a; + char b; +}; + +SA(0, sizeof(A) == 8); + +struct B : A { + char c; +}; + +SA(1, sizeof(B) == 12); + +struct C { +// Make fields private so C won't be a POD type. +private: + int a; + char b; +}; + +SA(2, sizeof(C) == 8); + +struct D : C { + char c; +}; + +SA(3, sizeof(D) == 8); + +struct __attribute__((packed)) E { + char b; + int a; +}; + +SA(4, sizeof(E) == 5); + +struct __attribute__((packed)) F : E { + char d; +}; + +SA(5, sizeof(F) == 6); + +struct G { G(); }; +struct H : G { }; + +SA(6, sizeof(H) == 1); + +struct I { + char b; + int a; +} __attribute__((packed)); + +SA(6_1, sizeof(I) == 5); + +// PR5580 +namespace PR5580 { + +class A { bool iv0 : 1; }; +SA(7, sizeof(A) == 1); + +class B : A { bool iv0 : 1; }; +SA(8, sizeof(B) == 2); + +struct C { bool iv0 : 1; }; +SA(9, sizeof(C) == 1); + +struct D : C { bool iv0 : 1; }; +SA(10, sizeof(D) == 2); + +} + +namespace Test1 { + +// Test that we don't assert on this hierarchy. +struct A { }; +struct B : A { virtual void b(); }; +class C : virtual A { int c; }; +struct D : virtual B { }; +struct E : C, virtual D { }; +class F : virtual E { }; +struct G : virtual E, F { }; + +SA(0, sizeof(G) == 24); + +} + +namespace Test2 { + +// Test that this somewhat complex class structure is laid out correctly. +struct A { }; +struct B : A { virtual void b(); }; +struct C : virtual B { }; +struct D : virtual A { }; +struct E : virtual B, D { }; +struct F : E, virtual C { }; +struct G : virtual F, A { }; +struct H { G g; }; + +SA(0, sizeof(H) == 24); + +} + +namespace PR16537 { +namespace test1 { + struct pod_in_11_only { + private: + long long x; + }; + + struct tail_padded_pod_in_11_only { + pod_in_11_only pod11; + char tail_padding; + }; + + struct might_use_tail_padding : public tail_padded_pod_in_11_only { + char may_go_into_tail_padding; + }; + + SA(0, sizeof(might_use_tail_padding) == 16); +} + +namespace test2 { + struct pod_in_11_only { + private: + long long x; + }; + + struct tail_padded_pod_in_11_only { + pod_in_11_only pod11 __attribute__((aligned(16))); + }; + + struct might_use_tail_padding : public tail_padded_pod_in_11_only { + char may_go_into_tail_padding; + }; + + SA(0, sizeof(might_use_tail_padding) == 16); +} + +namespace test3 { + struct pod_in_11_only { + private: + long long x; + }; + + struct tail_padded_pod_in_11_only { + pod_in_11_only pod11; + char tail_padding; + }; + + struct second_base { + char foo; + }; + + struct might_use_tail_padding : public tail_padded_pod_in_11_only, public second_base { + + }; + SA(0, sizeof(might_use_tail_padding) == 16); +} + +namespace test4 { + struct pod_in_11_only { + private: + long long x; + }; + + struct tail_padded_pod_in_11_only { + pod_in_11_only pod11; + char tail_padding; + }; + + struct second_base { + char foo; + }; + + struct might_use_tail_padding : public tail_padded_pod_in_11_only, public second_base { + char may_go_into_tail_padding; + }; + SA(0, sizeof(might_use_tail_padding) == 16); +} + +namespace test5 { + struct pod_in_11_only { + private: + long long x; + }; + + struct pod_in_11_only2 { + private: + long long x; + }; + + struct tail_padded_pod_in_11_only { + pod_in_11_only pod11; + char tail_padding; + }; + + struct second_base { + pod_in_11_only2 two; + char foo; + }; + + struct might_use_tail_padding : public tail_padded_pod_in_11_only, public second_base { + char may_go_into_tail_padding; + }; + SA(0, sizeof(might_use_tail_padding) == 32); +} + +namespace test6 { + struct pod_in_11_only { + private: + long long x; + }; + + struct pod_in_11_only2 { + private: + long long x; + }; + + struct tail_padded_pod_in_11_only { + pod_in_11_only pod11; + char tail_padding; + }; + + struct second_base { + pod_in_11_only2 two; + char foo; + }; + + struct might_use_tail_padding : public tail_padded_pod_in_11_only, public second_base { + char may_go_into_tail_padding; + }; + SA(0, sizeof(might_use_tail_padding) == 32); +} + +namespace test7 { + struct pod_in_11_only { + private: + long long x; + }; + + struct tail_padded_pod_in_11_only { + pod_in_11_only pod11; + pod_in_11_only pod12; + char tail_padding; + }; + + struct might_use_tail_padding : public tail_padded_pod_in_11_only { + char may_go_into_tail_padding; + }; + + SA(0, sizeof(might_use_tail_padding) == 24); +} + +namespace test8 { + struct pod_in_11_only { + private: + long long x; + }; + + struct tail_padded_pod_in_11_only { + pod_in_11_only pod11; + char tail_padding; + }; + + struct another_layer { + tail_padded_pod_in_11_only pod; + char padding; + }; + + struct might_use_tail_padding : public another_layer { + char may_go_into_tail_padding; + }; + + SA(0, sizeof(might_use_tail_padding) == 24); +} + +namespace test9 { + struct pod_in_11_only { + private: + long long x; + }; + + struct tail_padded_pod_in_11_only { + pod_in_11_only pod11; + char tail_padding; + }; + + struct another_layer : tail_padded_pod_in_11_only { + }; + + struct might_use_tail_padding : public another_layer { + char may_go_into_tail_padding; + }; + + SA(0, sizeof(might_use_tail_padding) == 16); +} + +namespace test10 { + struct pod_in_11_only { + private: + long long x; + }; + + struct A { + pod_in_11_only a; + char apad; + }; + + struct B { + char b; + }; + + struct C { + pod_in_11_only c; + char cpad; + }; + + struct D { + char d; + }; + + struct might_use_tail_padding : public A, public B, public C, public D { + }; + + SA(0, sizeof(might_use_tail_padding) == 32); +} + +namespace test11 { + struct pod_in_11_only { + private: + long long x; + }; + + struct A { + pod_in_11_only a; + char apad; + }; + + struct B { + char b_pre; + pod_in_11_only b; + char bpad; + }; + + struct C { + char c_pre; + pod_in_11_only c; + char cpad; + }; + + struct D { + char d_pre; + pod_in_11_only d; + char dpad; + }; + + struct might_use_tail_padding : public A, public B, public C, public D { + char m; + }; + + SA(0, sizeof(might_use_tail_padding) == 88); +} + +namespace test12 { + struct pod_in_11_only { + private: + long long x; + }; + + struct A { + pod_in_11_only a __attribute__((aligned(128))); + }; + + struct B { + char bpad; + }; + + struct C { + char cpad; + }; + + struct D { + char dpad; + }; + + struct might_use_tail_padding : public A, public B, public C, public D { + char m; + }; + SA(0, sizeof(might_use_tail_padding) == 128); +} + +namespace test13 { + struct pod_in_11_only { + private: + long long x; + }; + + struct A { + pod_in_11_only a; + char apad; + }; + + struct B { + }; + + struct C { + char c_pre; + pod_in_11_only c; + char cpad; + }; + + struct D { + }; + + struct might_use_tail_padding : public A, public B, public C, public D { + char m; + }; + SA(0, sizeof(might_use_tail_padding) == 40); +} + +namespace test14 { + struct pod_in_11_only { + private: + long long x; + }; + + struct A { + pod_in_11_only a; + char apad; + }; + + struct might_use_tail_padding : public A { + struct { + int : 0; + } x; + }; + SA(0, sizeof(might_use_tail_padding) == 16); +} + +namespace test15 { + struct pod_in_11_only { + private: + long long x; + }; + + struct A { + pod_in_11_only a; + char apad; + }; + + struct might_use_tail_padding : public A { + struct { + char a:1; + char b:2; + char c:2; + char d:2; + char e:1; + } x; + }; + SA(0, sizeof(might_use_tail_padding) == 16); +} + +namespace test16 { + struct pod_in_11_only { + private: + long long x; + }; + + struct A { + pod_in_11_only a; + char apad; + }; + + struct B { + char bpod; + pod_in_11_only b; + char bpad; + }; + + struct C : public A, public B { + }; + + struct D : public C { + }; + + struct might_use_tail_padding : public D { + char m; + }; + SA(0, sizeof(might_use_tail_padding) == 40); +} + +namespace test17 { + struct pod_in_11_only { + private: + long long x; + }; + + struct A { + pod_in_11_only a __attribute__((aligned(512))); + }; + + struct B { + char bpad; + pod_in_11_only foo; + char btail; + }; + + struct C { + char cpad; + }; + + struct D { + char dpad; + }; + + struct might_use_tail_padding : public A, public B, public C, public D { + char a; + }; + SA(0, sizeof(might_use_tail_padding) == 512); +} + +namespace test18 { + struct pod_in_11_only { + private: + long long x; + }; + + struct A { + pod_in_11_only a; + char apad; + }; + + struct B { + char bpod; + pod_in_11_only b; + char bpad; + }; + + struct A1 { + pod_in_11_only a; + char apad; + }; + + struct B1 { + char bpod; + pod_in_11_only b; + char bpad; + }; + + struct C : public A, public B { + }; + + struct D : public A1, public B1 { + }; + + struct E : public D, public C { + }; + + struct F : public E { + }; + + struct might_use_tail_padding : public F { + char m; + }; + SA(0, sizeof(might_use_tail_padding) == 80); +} +} // namespace PR16537 + +namespace PR37275 { + struct X { char c; }; + + struct A { int n; }; + _Static_assert(_Alignof(A) == _Alignof(int), ""); + + // __attribute__((packed)) does not apply to base classes. + struct __attribute__((packed)) B : X, A {}; +#if defined(CLANG_ABI_COMPAT) && CLANG_ABI_COMPAT <= 6 + _Static_assert(_Alignof(B) == 1, ""); + //_Static_assert(__builtin_offsetof(B, n) == 1, ""); FIXME +#else + _Static_assert(_Alignof(B) == _Alignof(int), ""); + //_Static_assert(__builtin_offsetof(B, n) == 4, ""); FIXME +#endif + + // #pragma pack does, though. +#pragma pack(push, 2) + struct C : X, A {}; + _Static_assert(_Alignof(C) == 2, ""); + //_Static_assert(__builtin_offsetof(C, n) == 2, ""); FIXME + + struct __attribute__((packed)) D : X, A {}; +#if defined(CLANG_ABI_COMPAT) && CLANG_ABI_COMPAT <= 6 + _Static_assert(_Alignof(D) == 1, ""); + //_Static_assert(__builtin_offsetof(D, n) == 1, ""); FIXME +#else + _Static_assert(_Alignof(D) == 2, ""); + //_Static_assert(__builtin_offsetof(D, n) == 2, ""); FIXME +#endif +#pragma pack(pop) +} + +namespace non_pod { +struct t1 { +protected: + int a; +}; +// GCC prints warning: ignoring packed attribute because of unpacked non-POD field 't1 t2::v1'` +struct t2 { + char c1; + short s1; + char c2; + t1 v1; +} __attribute__((packed)); +#if defined(CLANG_ABI_COMPAT) && CLANG_ABI_COMPAT <= 15 +_Static_assert(_Alignof(t1) == 4, ""); +_Static_assert(_Alignof(t2) == 1, ""); +#else +_Static_assert(_Alignof(t1) == 4, ""); +_Static_assert(_Alignof(t2) == 4, ""); +#endif +_Static_assert(sizeof(t2) == 8, ""); // it's still packing the rest of the struct +} // namespace non_pod + +namespace non_pod_packed { +struct t1 { +protected: + int a; +} __attribute__((packed)); +struct t2 { + t1 v1; +} __attribute__((packed)); +_Static_assert(_Alignof(t1) == 1, ""); +_Static_assert(_Alignof(t2) == 1, ""); +} // namespace non_pod_packed + +namespace non_pod_packed_packed { +struct B { + int b; +}; +struct FromB : B { +} __attribute__((packed)); +struct C { + char a[3]; + FromB b; +} __attribute__((packed)); +//_Static_assert(__builtin_offsetof(C, b) == 3, ""); FIXME +} + +namespace cxx11_pod { +struct t1 { + t1() = default; + t1(const t1&) = delete; + ~t1() = delete; + t1(t1&&) = default; + int a; + char c; +}; +struct t2 { + t1 v1; +} __attribute__((packed)); +_Static_assert(_Alignof(t2) == 1, ""); +struct t3 : t1 { + char c; +}; +#if defined(CLANG_ABI_COMPAT) && CLANG_ABI_COMPAT <= 15 +_Static_assert(sizeof(t3) == 8, ""); +#else +_Static_assert(sizeof(t3) == 12, ""); +#endif +}