[clang] 0dcfd0c - [clang][Interp] Support alignof()
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 10 23:38:34 PST 2022
Author: Timm Bäder
Date: 2022-11-11T08:38:06+01:00
New Revision: 0dcfd0ce020b4d5fb8d9eb549150d750a6bab68d
URL: https://github.com/llvm/llvm-project/commit/0dcfd0ce020b4d5fb8d9eb549150d750a6bab68d
DIFF: https://github.com/llvm/llvm-project/commit/0dcfd0ce020b4d5fb8d9eb549150d750a6bab68d.diff
LOG: [clang][Interp] Support alignof()
Support alignof() and __alignof() expressions.
Fixes #58816
Differential Revision: https://reviews.llvm.org/D137240
Added:
clang/test/AST/Interp/class-layout.cpp
Modified:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/test/AST/Interp/cxx20.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index b01c428060da5..0d5c26c7634a3 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -362,13 +362,34 @@ bool ByteCodeExprGen<Emitter>::VisitConstantExpr(const ConstantExpr *E) {
return this->visit(E->getSubExpr());
}
+static CharUnits AlignOfType(QualType T, const ASTContext &ASTCtx,
+ UnaryExprOrTypeTrait Kind) {
+ bool AlignOfReturnsPreferred =
+ ASTCtx.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver7;
+
+ // C++ [expr.alignof]p3:
+ // When alignof is applied to a reference type, the result is the
+ // alignment of the referenced type.
+ if (const auto *Ref = T->getAs<ReferenceType>())
+ T = Ref->getPointeeType();
+
+ // __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)
+ return ASTCtx.toCharUnitsFromBits(ASTCtx.getPreferredTypeAlign(T));
+
+ return ASTCtx.getTypeAlignInChars(T);
+}
+
template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitUnaryExprOrTypeTraitExpr(
const UnaryExprOrTypeTraitExpr *E) {
+ UnaryExprOrTypeTrait Kind = E->getKind();
+ ASTContext &ASTCtx = Ctx.getASTContext();
- if (E->getKind() == UETT_SizeOf) {
+ if (Kind == UETT_SizeOf) {
QualType ArgType = E->getTypeOfArgument();
-
CharUnits Size;
if (ArgType->isVoidType() || ArgType->isFunctionType())
Size = CharUnits::One();
@@ -376,7 +397,37 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryExprOrTypeTraitExpr(
if (ArgType->isDependentType() || !ArgType->isConstantSizeType())
return false;
- Size = Ctx.getASTContext().getTypeSizeInChars(ArgType);
+ Size = ASTCtx.getTypeSizeInChars(ArgType);
+ }
+
+ return this->emitConst(Size.getQuantity(), E);
+ }
+
+ if (Kind == UETT_AlignOf || Kind == UETT_PreferredAlignOf) {
+ CharUnits Size;
+
+ if (E->isArgumentType()) {
+ QualType ArgType = E->getTypeOfArgument();
+
+ Size = AlignOfType(ArgType, ASTCtx, Kind);
+ } else {
+ // Argument is an expression, not a type.
+ const Expr *Arg = E->getArgumentExpr()->IgnoreParens();
+
+ // The kinds of expressions that we have special-case logic here for
+ // should be kept up to date with the special checks for those
+ // expressions in Sema.
+
+ // alignof decl is always accepted, even if it doesn't make sense: we
+ // default to 1 in those cases.
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(Arg))
+ Size = ASTCtx.getDeclAlign(DRE->getDecl(),
+ /*RefAsPointee*/ true);
+ else if (const auto *ME = dyn_cast<MemberExpr>(Arg))
+ Size = ASTCtx.getDeclAlign(ME->getMemberDecl(),
+ /*RefAsPointee*/ true);
+ else
+ Size = AlignOfType(Arg->getType(), ASTCtx, Kind);
}
return this->emitConst(Size.getQuantity(), E);
diff --git a/clang/test/AST/Interp/class-layout.cpp b/clang/test/AST/Interp/class-layout.cpp
new file mode 100644
index 0000000000000..41a964780b642
--- /dev/null
+++ b/clang/test/AST/Interp/class-layout.cpp
@@ -0,0 +1,698 @@
+// 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), "");
+ _Static_assert(_Alignof(A[]) == _Alignof(A), "");
+
+ _Static_assert(_Alignof(int[]) == _Alignof(int), "");
+ _Static_assert(_Alignof(char[]) == _Alignof(char), "");
+
+ // __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(_Alignof(B[]) == 1, "");
+ //_Static_assert(__builtin_offsetof(B, n) == 1, ""); FIXME
+#else
+ _Static_assert(_Alignof(B) == _Alignof(int), "");
+ _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(_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(t1[]) == 4, "");
+_Static_assert(_Alignof(t2) == 1, "");
+_Static_assert(_Alignof(t2[]) == 1, "");
+#else
+_Static_assert(_Alignof(t1) == 4, "");
+_Static_assert(_Alignof(t1[]) == 4, "");
+_Static_assert(_Alignof(t2) == 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
+}
diff --git a/clang/test/AST/Interp/cxx20.cpp b/clang/test/AST/Interp/cxx20.cpp
index ec273f0713410..6445abd402a02 100644
--- a/clang/test/AST/Interp/cxx20.cpp
+++ b/clang/test/AST/Interp/cxx20.cpp
@@ -1,6 +1,10 @@
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify %s
// RUN: %clang_cc1 -std=c++20 -verify=ref %s
+void test_alignas_operand() {
+ alignas(8) char dummy;
+ static_assert(__alignof(dummy) == 8);
+}
constexpr int getMinus5() {
int a = 10;
More information about the cfe-commits
mailing list