cb424d7448
verify-patch-sanity.py validates every active recipe .patch has internally- consistent hunk line counts — catching the 'malformed patch at line N' failure at commit/CI/preflight time instead of hours into a cook. This cycle hit that class three times (qtwaylandscanner, sddm, xwayland), each only discovered when cookbook tried to apply the patch. Running it across the repo found 29 latent malformed patches (validated against GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22'). They were harmless only because they sit in vendored recipes (baked, not re- applied) — but would fail on any version-bump re-derivation. --fix recounts the hunk headers (body untouched) and repaired all 29. Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test (test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats (empty placeholders, bare-@@ git hunks).
382 lines
12 KiB
C++
382 lines
12 KiB
C++
// RUN: %clang_cc1 -std=c++2a -fsyntax-only -triple x86_64-windows-msvc -fms-compatibility -fdump-record-layouts %s | FileCheck %s
|
|
|
|
namespace Empty {
|
|
struct A {};
|
|
struct A2 {};
|
|
struct A3 { [[msvc::no_unique_address]] A a; };
|
|
struct alignas(8) A4 {};
|
|
|
|
struct B {
|
|
[[msvc::no_unique_address]] A a;
|
|
char b;
|
|
};
|
|
static_assert(sizeof(B) == 1);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct Empty::B
|
|
// CHECK-NEXT: 0 | struct Empty::A a (empty)
|
|
// CHECK-NEXT: 0 | char b
|
|
// CHECK-NEXT: | [sizeof=1, align=1,
|
|
// CHECK-NEXT: | nvsize=1, nvalign=1]
|
|
|
|
struct C {
|
|
[[msvc::no_unique_address]] A a;
|
|
[[msvc::no_unique_address]] A2 a2;
|
|
char c;
|
|
};
|
|
static_assert(sizeof(C) == 1);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct Empty::C
|
|
// CHECK-NEXT: 0 | struct Empty::A a (empty)
|
|
// CHECK-NEXT: 0 | struct Empty::A2 a2 (empty)
|
|
// CHECK-NEXT: 0 | char c
|
|
// CHECK-NEXT: | [sizeof=1, align=1,
|
|
// CHECK-NEXT: | nvsize=1, nvalign=1]
|
|
|
|
struct D {
|
|
[[msvc::no_unique_address]] A3 a;
|
|
int i;
|
|
};
|
|
static_assert(sizeof(D) == 8);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct Empty::D
|
|
// CHECK-NEXT: 0 | struct Empty::A3 a (empty)
|
|
// CHECK-NEXT: 0 | struct Empty::A a (empty)
|
|
// CHECK-NEXT: 4 | int i
|
|
// CHECK-NEXT: | [sizeof=8, align=4,
|
|
// CHECK-NEXT: | nvsize=8, nvalign=4]
|
|
|
|
struct E {
|
|
[[msvc::no_unique_address]] A a1;
|
|
[[msvc::no_unique_address]] A a2;
|
|
char e;
|
|
};
|
|
static_assert(sizeof(E) == 2);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct Empty::E
|
|
// CHECK-NEXT: 0 | struct Empty::A a1 (empty)
|
|
// CHECK-NEXT: 1 | struct Empty::A a2 (empty)
|
|
// CHECK-NEXT: 0 | char e
|
|
// CHECK-NEXT: | [sizeof=2, align=1,
|
|
// CHECK-NEXT: | nvsize=2, nvalign=1]
|
|
|
|
struct F {
|
|
~F();
|
|
[[msvc::no_unique_address]] A a1;
|
|
[[msvc::no_unique_address]] A a2;
|
|
char f;
|
|
};
|
|
static_assert(sizeof(F) == 2);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct Empty::F
|
|
// CHECK-NEXT: 0 | struct Empty::A a1 (empty)
|
|
// CHECK-NEXT: 1 | struct Empty::A a2 (empty)
|
|
// CHECK-NEXT: 0 | char f
|
|
// CHECK-NEXT: | [sizeof=2, align=1,
|
|
// CHECK-NEXT: | nvsize=2, nvalign=1]
|
|
|
|
struct G { [[msvc::no_unique_address]] A a; ~G(); };
|
|
static_assert(sizeof(G) == 1);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct Empty::G
|
|
// CHECK-NEXT: 0 | struct Empty::A a (empty)
|
|
// CHECK-NEXT: | [sizeof=1, align=1,
|
|
// CHECK-NEXT: | nvsize=1, nvalign=1]
|
|
|
|
struct H {
|
|
[[msvc::no_unique_address]] A a;
|
|
[[msvc::no_unique_address]] A b;
|
|
~H();
|
|
};
|
|
static_assert(sizeof(H) == 2);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct Empty::H
|
|
// CHECK-NEXT: 0 | struct Empty::A a (empty)
|
|
// CHECK-NEXT: 1 | struct Empty::A b (empty)
|
|
// CHECK-NEXT: | [sizeof=2, align=1,
|
|
// CHECK-NEXT: | nvsize=2, nvalign=1]
|
|
|
|
struct I {
|
|
[[msvc::no_unique_address]] A4 a;
|
|
[[msvc::no_unique_address]] A4 b;
|
|
};
|
|
static_assert(sizeof(I) == 16);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct Empty::I
|
|
// CHECK-NEXT: 0 | struct Empty::A4 a (empty)
|
|
// CHECK-NEXT: 8 | struct Empty::A4 b (empty)
|
|
// CHECK-NEXT: | [sizeof=16, align=8,
|
|
// CHECK-NEXT: | nvsize=16, nvalign=8]
|
|
|
|
struct J {
|
|
[[msvc::no_unique_address]] A4 a;
|
|
A4 b;
|
|
};
|
|
static_assert(sizeof(J) == 16);
|
|
|
|
// MSVC puts a and b at the same offset.
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct Empty::J
|
|
// CHECK-NEXT: 0 | struct Empty::A4 a (empty)
|
|
// CHECK-NEXT: 8 | struct Empty::A4 b (empty)
|
|
// CHECK-NEXT: | [sizeof=16, align=8,
|
|
// CHECK-NEXT: | nvsize=16, nvalign=8]
|
|
|
|
struct K {
|
|
[[msvc::no_unique_address]] A4 a;
|
|
[[msvc::no_unique_address]] char c;
|
|
[[msvc::no_unique_address]] A4 b;
|
|
};
|
|
static_assert(sizeof(K) == 16);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct Empty::K
|
|
// CHECK-NEXT: 0 | struct Empty::A4 a (empty)
|
|
// CHECK-NEXT: 0 | char c
|
|
// CHECK-NEXT: 8 | struct Empty::A4 b (empty)
|
|
// CHECK-NEXT: | [sizeof=16, align=8,
|
|
// CHECK-NEXT: | nvsize=16, nvalign=8]
|
|
|
|
struct OversizedEmpty : A {
|
|
~OversizedEmpty();
|
|
[[msvc::no_unique_address]] A a;
|
|
};
|
|
static_assert(sizeof(OversizedEmpty) == 1);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct Empty::OversizedEmpty
|
|
// CHECK-NEXT: 0 | struct Empty::A (base) (empty)
|
|
// CHECK-NEXT: 0 | struct Empty::A a (empty)
|
|
// CHECK-NEXT: | [sizeof=1, align=1,
|
|
// CHECK-NEXT: | nvsize=1, nvalign=1]
|
|
|
|
struct HasOversizedEmpty {
|
|
[[msvc::no_unique_address]] OversizedEmpty m;
|
|
};
|
|
static_assert(sizeof(HasOversizedEmpty) == 1);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct Empty::HasOversizedEmpty
|
|
// CHECK-NEXT: 0 | struct Empty::OversizedEmpty m (empty)
|
|
// CHECK-NEXT: 0 | struct Empty::A (base) (empty)
|
|
// CHECK-NEXT: 0 | struct Empty::A a (empty)
|
|
// CHECK-NEXT: | [sizeof=1, align=1,
|
|
// CHECK-NEXT: | nvsize=1, nvalign=1]
|
|
|
|
struct EmptyWithNonzeroDSize {
|
|
[[msvc::no_unique_address]] A a;
|
|
int x;
|
|
[[msvc::no_unique_address]] A b;
|
|
int y;
|
|
[[msvc::no_unique_address]] A c;
|
|
};
|
|
static_assert(sizeof(EmptyWithNonzeroDSize) == 8);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct Empty::EmptyWithNonzeroDSize
|
|
// CHECK-NEXT: 0 | struct Empty::A a (empty)
|
|
// CHECK-NEXT: 0 | int x
|
|
// CHECK-NEXT: 1 | struct Empty::A b (empty)
|
|
// CHECK-NEXT: 4 | int y
|
|
// CHECK-NEXT: 2 | struct Empty::A c (empty)
|
|
// CHECK-NEXT: | [sizeof=8, align=4,
|
|
// CHECK-NEXT: | nvsize=8, nvalign=4]
|
|
|
|
struct EmptyWithNonzeroDSizeNonPOD {
|
|
~EmptyWithNonzeroDSizeNonPOD();
|
|
[[msvc::no_unique_address]] A a;
|
|
int x;
|
|
[[msvc::no_unique_address]] A b;
|
|
int y;
|
|
[[msvc::no_unique_address]] A c;
|
|
};
|
|
static_assert(sizeof(EmptyWithNonzeroDSizeNonPOD) == 8);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct Empty::EmptyWithNonzeroDSizeNonPOD
|
|
// CHECK-NEXT: 0 | struct Empty::A a (empty)
|
|
// CHECK-NEXT: 0 | int x
|
|
// CHECK-NEXT: 1 | struct Empty::A b (empty)
|
|
// CHECK-NEXT: 4 | int y
|
|
// CHECK-NEXT: 2 | struct Empty::A c (empty)
|
|
// CHECK-NEXT: | [sizeof=8, align=4,
|
|
// CHECK-NEXT: | nvsize=8, nvalign=4]
|
|
}
|
|
|
|
namespace POD {
|
|
struct A { int n; char c[3]; };
|
|
struct B { [[msvc::no_unique_address]] A a; char d; };
|
|
static_assert(sizeof(B) == 12);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct POD::B
|
|
// CHECK-NEXT: 0 | struct POD::A a
|
|
// CHECK-NEXT: 0 | int n
|
|
// CHECK-NEXT: 4 | char[3] c
|
|
// CHECK-NEXT: 8 | char d
|
|
// CHECK-NEXT: | [sizeof=12, align=4,
|
|
// CHECK-NEXT: | nvsize=12, nvalign=4]
|
|
}
|
|
|
|
namespace NonPOD {
|
|
struct A { int n; char c[3]; ~A(); };
|
|
struct B { [[msvc::no_unique_address]] A a; char d; };
|
|
static_assert(sizeof(B) == 12);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct NonPOD::B
|
|
// CHECK-NEXT: 0 | struct NonPOD::A a
|
|
// CHECK-NEXT: 0 | int n
|
|
// CHECK-NEXT: 4 | char[3] c
|
|
// CHECK-NEXT: 8 | char d
|
|
// CHECK-NEXT: | [sizeof=12, align=4,
|
|
// CHECK-NEXT: | nvsize=12, nvalign=4]
|
|
}
|
|
|
|
namespace VBases {
|
|
// The nvsize of an object includes the complete size of its empty subobjects
|
|
// (although it's unclear why). Ensure this corner case is handled properly.
|
|
struct Empty {};
|
|
struct alignas(8) A {}; // dsize 0, nvsize 0, size 8
|
|
struct B : A { char c; }; // dsize 1, nvsize 8, size 8
|
|
static_assert(sizeof(B) == 8);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct VBases::B
|
|
// CHECK-NEXT: 0 | struct VBases::A (base) (empty)
|
|
// CHECK-NEXT: 0 | char c
|
|
// CHECK-NEXT: | [sizeof=8, align=8,
|
|
// CHECK-NEXT: | nvsize=8, nvalign=8]
|
|
|
|
struct V { int n; };
|
|
|
|
struct C : B, virtual V {};
|
|
static_assert(sizeof(C) == 24);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct VBases::C
|
|
// CHECK-NEXT: 0 | struct VBases::B (base)
|
|
// CHECK-NEXT: 0 | struct VBases::A (base) (empty)
|
|
// CHECK-NEXT: 0 | char c
|
|
// CHECK-NEXT: 8 | (C vbtable pointer)
|
|
// CHECK-NEXT: 16 | struct VBases::V (virtual base)
|
|
// CHECK-NEXT: 16 | int n
|
|
// CHECK-NEXT: | [sizeof=24, align=8,
|
|
// CHECK-NEXT: | nvsize=16, nvalign=8]
|
|
|
|
struct D : virtual Empty {
|
|
[[msvc::no_unique_address]] Empty a;
|
|
};
|
|
static_assert(sizeof(D) == 16);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct VBases::D
|
|
// CHECK-NEXT: 0 | (D vbtable pointer)
|
|
// CHECK-NEXT: 8 | struct VBases::Empty a
|
|
// CHECK-NEXT: 16 | struct VBases::Empty (virtual base) (empty)
|
|
// CHECK-NEXT: | [sizeof=16, align=8,
|
|
// CHECK-NEXT: | nvsize=16, nvalign=8]
|
|
|
|
struct E : virtual V {
|
|
[[msvc::no_unique_address]] B b;
|
|
};
|
|
static_assert(sizeof(E) == 24);
|
|
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct VBases::E
|
|
// CHECK-NEXT: 0 | (E vbtable pointer)
|
|
// CHECK-NEXT: 8 | struct VBases::B b
|
|
// CHECK-NEXT: 8 | struct VBases::A (base) (empty)
|
|
// CHECK-NEXT: 8 | char c
|
|
// CHECK-NEXT: 16 | struct VBases::V (virtual base)
|
|
// CHECK-NEXT: 16 | int n
|
|
// CHECK-NEXT: | [sizeof=24, align=8,
|
|
// CHECK-NEXT: | nvsize=16, nvalign=8]
|
|
|
|
struct X : virtual A { [[msvc::no_unique_address]] A a; };
|
|
struct F : virtual A {
|
|
[[msvc::no_unique_address]] A a;
|
|
[[msvc::no_unique_address]] X x;
|
|
};
|
|
static_assert(sizeof(F) == 24);
|
|
|
|
// MSVC places x after a and the total size is 48.
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct VBases::F
|
|
// CHECK-NEXT: 0 | (F vbtable pointer)
|
|
// CHECK-NEXT: 8 | struct VBases::A a (empty)
|
|
// CHECK-NEXT: 8 | struct VBases::X x
|
|
// CHECK-NEXT: 8 | (X vbtable pointer)
|
|
// CHECK-NEXT: 16 | struct VBases::A a (empty)
|
|
// CHECK-NEXT: 24 | struct VBases::A (virtual base) (empty)
|
|
// CHECK-NEXT: 24 | struct VBases::A (virtual base) (empty)
|
|
// CHECK-NEXT: | [sizeof=24, align=8,
|
|
// CHECK-NEXT: | nvsize=24, nvalign=8]
|
|
|
|
struct G : virtual Empty {
|
|
int i;
|
|
[[msvc::no_unique_address]] A a;
|
|
};
|
|
static_assert(sizeof(G) == 16);
|
|
|
|
// MSVC places a at offset 12.
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct VBases::G
|
|
// CHECK-NEXT: 0 | (G vbtable pointer)
|
|
// CHECK-NEXT: 8 | int i
|
|
// CHECK-NEXT: 8 | struct VBases::A a (empty)
|
|
// CHECK-NEXT: 16 | struct VBases::Empty (virtual base) (empty)
|
|
// CHECK-NEXT: | [sizeof=16, align=8,
|
|
// CHECK-NEXT: | nvsize=16, nvalign=8]
|
|
}
|
|
|
|
namespace ZeroSize {
|
|
struct empty {};
|
|
|
|
union empty_union {};
|
|
|
|
struct empty_union_container {
|
|
[[msvc::no_unique_address]] empty_union x;
|
|
};
|
|
|
|
union union_of_empty {
|
|
[[msvc::no_unique_address]] empty x;
|
|
};
|
|
|
|
struct struct_of_empty {
|
|
[[msvc::no_unique_address]] empty x;
|
|
};
|
|
|
|
struct union_of_empty_container {
|
|
[[msvc::no_unique_address]] union_of_empty x;
|
|
};
|
|
static_assert(sizeof(union_of_empty_container) == 1);
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct ZeroSize::union_of_empty_container
|
|
// CHECK-NOT: (empty)
|
|
// CHECK: 0 | union ZeroSize::union_of_empty x (empty)
|
|
// CHECK: 0 | struct ZeroSize::empty x (empty)
|
|
// CHECK: | [sizeof=1, align=1,
|
|
// CHECK: | nvsize=1, nvalign=1]
|
|
|
|
struct struct_of_empty_container {
|
|
[[msvc::no_unique_address]] struct_of_empty x;
|
|
};
|
|
static_assert(sizeof(struct_of_empty_container) == 1);
|
|
// CHECK:*** Dumping AST Record Layout
|
|
// CHECK: 0 | struct ZeroSize::struct_of_empty_container
|
|
// CHECK-NOT: (empty)
|
|
// CHECK: 0 | struct ZeroSize::struct_of_empty x (empty)
|
|
// CHECK: 0 | struct ZeroSize::empty x (empty)
|
|
// CHECK: | [sizeof=1, align=1,
|
|
// CHECK: | nvsize=1, nvalign=1]
|
|
|
|
}
|