diff options
Diffstat (limited to 'tests/ui/print_type_sizes')
29 files changed, 774 insertions, 0 deletions
diff --git a/tests/ui/print_type_sizes/anonymous.rs b/tests/ui/print_type_sizes/anonymous.rs new file mode 100644 index 000000000..2b008ca3b --- /dev/null +++ b/tests/ui/print_type_sizes/anonymous.rs @@ -0,0 +1,23 @@ +// compile-flags: -Z print-type-sizes +// build-pass + +// All of the types that occur in this function are uninteresting, in +// that one cannot control the sizes of these types with the same sort +// of enum-variant manipulation tricks. + +#![feature(start)] + +#[start] +fn start(_: isize, _: *const *const u8) -> isize { + let _byte: u8 = 0; + let _word: usize = 0; + let _tuple: (u8, usize)= (0, 0); + let _array: [u8; 128] = [0; 128]; + let _fn: fn (u8) -> u8 = id; + let _diverging: fn (u8) -> ! = bye; + + fn id(x: u8) -> u8 { x }; + fn bye(_: u8) -> ! { loop { } } + + 0 +} diff --git a/tests/ui/print_type_sizes/async.rs b/tests/ui/print_type_sizes/async.rs new file mode 100644 index 000000000..1598b0696 --- /dev/null +++ b/tests/ui/print_type_sizes/async.rs @@ -0,0 +1,11 @@ +// compile-flags: -Z print-type-sizes --crate-type lib +// edition:2021 +// build-pass +// ignore-pass + +async fn wait() {} + +pub async fn test(arg: [u8; 8192]) { + wait().await; + drop(arg); +} diff --git a/tests/ui/print_type_sizes/async.stdout b/tests/ui/print_type_sizes/async.stdout new file mode 100644 index 000000000..6e47bb493 --- /dev/null +++ b/tests/ui/print_type_sizes/async.stdout @@ -0,0 +1,34 @@ +print-type-size type: `[async fn body@$DIR/async.rs:8:36: 11:2]`: 16386 bytes, alignment: 1 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `Suspend0`: 16385 bytes +print-type-size field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes +print-type-size field `.arg`: 8192 bytes +print-type-size field `.__awaitee`: 1 bytes +print-type-size variant `Unresumed`: 8192 bytes +print-type-size field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes +print-type-size variant `Returned`: 8192 bytes +print-type-size field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes +print-type-size variant `Panicked`: 8192 bytes +print-type-size field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes +print-type-size type: `std::mem::ManuallyDrop<[u8; 8192]>`: 8192 bytes, alignment: 1 bytes +print-type-size field `.value`: 8192 bytes +print-type-size type: `std::mem::MaybeUninit<[u8; 8192]>`: 8192 bytes, alignment: 1 bytes +print-type-size variant `MaybeUninit`: 8192 bytes +print-type-size field `.uninit`: 0 bytes +print-type-size field `.value`: 8192 bytes +print-type-size type: `[async fn body@$DIR/async.rs:6:17: 6:19]`: 1 bytes, alignment: 1 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `Unresumed`: 0 bytes +print-type-size variant `Returned`: 0 bytes +print-type-size variant `Panicked`: 0 bytes +print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async.rs:6:17: 6:19]>`: 1 bytes, alignment: 1 bytes +print-type-size field `.value`: 1 bytes +print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async.rs:6:17: 6:19]>`: 1 bytes, alignment: 1 bytes +print-type-size variant `MaybeUninit`: 1 bytes +print-type-size field `.uninit`: 0 bytes +print-type-size field `.value`: 1 bytes +print-type-size type: `std::task::Poll<()>`: 1 bytes, alignment: 1 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `Ready`: 0 bytes +print-type-size field `.0`: 0 bytes +print-type-size variant `Pending`: 0 bytes diff --git a/tests/ui/print_type_sizes/generator.rs b/tests/ui/print_type_sizes/generator.rs new file mode 100644 index 000000000..d1cd36274 --- /dev/null +++ b/tests/ui/print_type_sizes/generator.rs @@ -0,0 +1,18 @@ +// compile-flags: -Z print-type-sizes --crate-type=lib +// build-pass +// ignore-pass + +#![feature(generators, generator_trait)] + +use std::ops::Generator; + +fn generator<const C: usize>(array: [u8; C]) -> impl Generator<Yield = (), Return = ()> { + move |()| { + yield (); + let _ = array; + } +} + +pub fn foo() { + let _ = generator([0; 8192]); +} diff --git a/tests/ui/print_type_sizes/generator.stdout b/tests/ui/print_type_sizes/generator.stdout new file mode 100644 index 000000000..28d4a6e6c --- /dev/null +++ b/tests/ui/print_type_sizes/generator.stdout @@ -0,0 +1,10 @@ +print-type-size type: `[generator@$DIR/generator.rs:10:5: 10:14]`: 8193 bytes, alignment: 1 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `Unresumed`: 8192 bytes +print-type-size field `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes +print-type-size variant `Returned`: 8192 bytes +print-type-size field `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes +print-type-size variant `Panicked`: 8192 bytes +print-type-size field `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes +print-type-size variant `Suspend0`: 8192 bytes +print-type-size field `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes diff --git a/tests/ui/print_type_sizes/generator_discr_placement.rs b/tests/ui/print_type_sizes/generator_discr_placement.rs new file mode 100644 index 000000000..1a85fe95b --- /dev/null +++ b/tests/ui/print_type_sizes/generator_discr_placement.rs @@ -0,0 +1,23 @@ +// compile-flags: -Z print-type-sizes --crate-type lib +// build-pass +// ignore-pass + +// Tests a generator that has its discriminant as the *final* field. + +// Avoid emitting panic handlers, like the rest of these tests... +#![feature(generators)] + +pub fn foo() { + let a = || { + { + let w: i32 = 4; + yield; + drop(w); + } + { + let z: i32 = 7; + yield; + drop(z); + } + }; +} diff --git a/tests/ui/print_type_sizes/generator_discr_placement.stdout b/tests/ui/print_type_sizes/generator_discr_placement.stdout new file mode 100644 index 000000000..7f8f4ccae --- /dev/null +++ b/tests/ui/print_type_sizes/generator_discr_placement.stdout @@ -0,0 +1,11 @@ +print-type-size type: `[generator@$DIR/generator_discr_placement.rs:11:13: 11:15]`: 8 bytes, alignment: 4 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `Suspend0`: 7 bytes +print-type-size padding: 3 bytes +print-type-size field `.w`: 4 bytes, alignment: 4 bytes +print-type-size variant `Suspend1`: 7 bytes +print-type-size padding: 3 bytes +print-type-size field `.z`: 4 bytes, alignment: 4 bytes +print-type-size variant `Unresumed`: 0 bytes +print-type-size variant `Returned`: 0 bytes +print-type-size variant `Panicked`: 0 bytes diff --git a/tests/ui/print_type_sizes/generics.rs b/tests/ui/print_type_sizes/generics.rs new file mode 100644 index 000000000..05097087d --- /dev/null +++ b/tests/ui/print_type_sizes/generics.rs @@ -0,0 +1,51 @@ +// compile-flags: -Z print-type-sizes --crate-type=lib +// build-pass +// ignore-pass +// ^-- needed because `--pass check` does not emit the output needed. +// FIXME: consider using an attribute instead of side-effects. + +// This file illustrates how generics are handled: types have to be +// monomorphized, in the MIR of the original function in which they +// occur, to have their size reported. + +#[derive(Copy, Clone)] +pub struct Pair<T> { + _car: T, + _cdr: T, +} + +impl<T> Pair<T> { + fn new(a: T, d: T) -> Self { + Pair { + _car: a, + _cdr: d, + } + } +} + +#[derive(Copy, Clone)] +pub struct SevenBytes([u8; 7]); +pub struct FiftyBytes([u8; 50]); + +pub struct ZeroSized; + +impl SevenBytes { + fn new() -> Self { SevenBytes([0; 7]) } +} + +impl FiftyBytes { + fn new() -> Self { FiftyBytes([0; 50]) } +} + +pub fn f1<T:Copy>(x: T) { + let _v: Pair<T> = Pair::new(x, x); + let _v2: Pair<FiftyBytes> = + Pair::new(FiftyBytes::new(), FiftyBytes::new()); +} + +pub fn start() { + let _b: Pair<u8> = Pair::new(0, 0); + let _s: Pair<SevenBytes> = Pair::new(SevenBytes::new(), SevenBytes::new()); + let ref _z: ZeroSized = ZeroSized; + f1::<SevenBytes>(SevenBytes::new()); +} diff --git a/tests/ui/print_type_sizes/generics.stdout b/tests/ui/print_type_sizes/generics.stdout new file mode 100644 index 000000000..0f02f3979 --- /dev/null +++ b/tests/ui/print_type_sizes/generics.stdout @@ -0,0 +1,14 @@ +print-type-size type: `Pair<FiftyBytes>`: 100 bytes, alignment: 1 bytes +print-type-size field `._car`: 50 bytes +print-type-size field `._cdr`: 50 bytes +print-type-size type: `FiftyBytes`: 50 bytes, alignment: 1 bytes +print-type-size field `.0`: 50 bytes +print-type-size type: `Pair<SevenBytes>`: 14 bytes, alignment: 1 bytes +print-type-size field `._car`: 7 bytes +print-type-size field `._cdr`: 7 bytes +print-type-size type: `SevenBytes`: 7 bytes, alignment: 1 bytes +print-type-size field `.0`: 7 bytes +print-type-size type: `Pair<u8>`: 2 bytes, alignment: 1 bytes +print-type-size field `._car`: 1 bytes +print-type-size field `._cdr`: 1 bytes +print-type-size type: `ZeroSized`: 0 bytes, alignment: 1 bytes diff --git a/tests/ui/print_type_sizes/multiple_types.rs b/tests/ui/print_type_sizes/multiple_types.rs new file mode 100644 index 000000000..915903892 --- /dev/null +++ b/tests/ui/print_type_sizes/multiple_types.rs @@ -0,0 +1,13 @@ +// compile-flags: -Z print-type-sizes --crate-type=lib +// build-pass + +// This file illustrates that when multiple structural types occur in +// a function, every one of them is included in the output. + +pub struct SevenBytes([u8; 7]); +pub struct FiftyBytes([u8; 50]); + +pub enum Enum { + Small(SevenBytes), + Large(FiftyBytes), +} diff --git a/tests/ui/print_type_sizes/multiple_types.stdout b/tests/ui/print_type_sizes/multiple_types.stdout new file mode 100644 index 000000000..641188154 --- /dev/null +++ b/tests/ui/print_type_sizes/multiple_types.stdout @@ -0,0 +1,10 @@ +print-type-size type: `Enum`: 51 bytes, alignment: 1 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `Large`: 50 bytes +print-type-size field `.0`: 50 bytes +print-type-size variant `Small`: 7 bytes +print-type-size field `.0`: 7 bytes +print-type-size type: `FiftyBytes`: 50 bytes, alignment: 1 bytes +print-type-size field `.0`: 50 bytes +print-type-size type: `SevenBytes`: 7 bytes, alignment: 1 bytes +print-type-size field `.0`: 7 bytes diff --git a/tests/ui/print_type_sizes/niche-filling.rs b/tests/ui/print_type_sizes/niche-filling.rs new file mode 100644 index 000000000..5e620f248 --- /dev/null +++ b/tests/ui/print_type_sizes/niche-filling.rs @@ -0,0 +1,97 @@ +// compile-flags: -Z print-type-sizes --crate-type=lib +// build-pass +// ignore-pass +// ^-- needed because `--pass check` does not emit the output needed. +// FIXME: consider using an attribute instead of side-effects. + +// This file illustrates how niche-filling enums are handled, +// modelled after cases like `Option<&u32>`, `Option<bool>` and such. +// +// It uses NonZeroU32 rather than `&_` or `Unique<_>`, because +// the test is not set up to deal with target-dependent pointer width. +// +// It avoids using u64/i64 because on some targets that is only 4-byte +// aligned (while on most it is 8-byte aligned) and so the resulting +// padding and overall computed sizes can be quite different. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +use std::num::NonZeroU32; + +pub enum MyOption<T> { None, Some(T) } + +#[rustc_layout_scalar_valid_range_start(0)] +#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] +pub struct MyNotNegativeOne { + _i: i32, +} + +impl<T> Default for MyOption<T> { + fn default() -> Self { MyOption::None } +} + +pub enum EmbeddedDiscr { + None, + Record { pre: u8, val: NonZeroU32, post: u16 }, +} + +impl Default for EmbeddedDiscr { + fn default() -> Self { EmbeddedDiscr::None } +} + +#[derive(Default)] +pub struct IndirectNonZero { + pre: u8, + nested: NestedNonZero, + post: u16, +} + +pub struct NestedNonZero { + pre: u8, + val: NonZeroU32, + post: u16, +} + +impl Default for NestedNonZero { + fn default() -> Self { + NestedNonZero { pre: 0, val: unsafe { NonZeroU32::new_unchecked(1) }, post: 0 } + } +} + +pub enum Enum4<A, B, C, D> { + One(A), + Two(B), + Three(C), + Four(D) +} + +pub union Union1<A: Copy> { + a: A, +} + +pub union Union2<A: Copy, B: Copy> { + a: A, + b: B, +} + +pub fn test() { + let _x: MyOption<NonZeroU32> = Default::default(); + let _y: EmbeddedDiscr = Default::default(); + let _z: MyOption<IndirectNonZero> = Default::default(); + let _a: MyOption<bool> = Default::default(); + let _b: MyOption<char> = Default::default(); + let _c: MyOption<std::cmp::Ordering> = Default::default(); + let _d: MyOption<MyOption<u8>> = Default::default(); + let _e: Enum4<(), char, (), ()> = Enum4::One(()); + let _f: Enum4<(), (), bool, ()> = Enum4::One(()); + let _g: Enum4<(), (), (), MyOption<u8>> = Enum4::One(()); + let _h: MyOption<MyNotNegativeOne> = Default::default(); + + // Unions do not currently participate in niche filling. + let _i: MyOption<Union2<NonZeroU32, u32>> = Default::default(); + + // ...even when theoretically possible. + let _j: MyOption<Union1<NonZeroU32>> = Default::default(); + let _k: MyOption<Union2<NonZeroU32, NonZeroU32>> = Default::default(); +} diff --git a/tests/ui/print_type_sizes/niche-filling.stdout b/tests/ui/print_type_sizes/niche-filling.stdout new file mode 100644 index 000000000..d1753c26c --- /dev/null +++ b/tests/ui/print_type_sizes/niche-filling.stdout @@ -0,0 +1,112 @@ +print-type-size type: `IndirectNonZero`: 12 bytes, alignment: 4 bytes +print-type-size field `.nested`: 8 bytes +print-type-size field `.post`: 2 bytes +print-type-size field `.pre`: 1 bytes +print-type-size end padding: 1 bytes +print-type-size type: `MyOption<IndirectNonZero>`: 12 bytes, alignment: 4 bytes +print-type-size variant `Some`: 12 bytes +print-type-size field `.0`: 12 bytes +print-type-size variant `None`: 0 bytes +print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `Record`: 7 bytes +print-type-size field `.pre`: 1 bytes +print-type-size field `.post`: 2 bytes +print-type-size field `.val`: 4 bytes +print-type-size variant `None`: 0 bytes +print-type-size type: `MyOption<Union1<std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes +print-type-size discriminant: 4 bytes +print-type-size variant `Some`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size variant `None`: 0 bytes +print-type-size type: `MyOption<Union2<std::num::NonZeroU32, std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes +print-type-size discriminant: 4 bytes +print-type-size variant `Some`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size variant `None`: 0 bytes +print-type-size type: `MyOption<Union2<std::num::NonZeroU32, u32>>`: 8 bytes, alignment: 4 bytes +print-type-size discriminant: 4 bytes +print-type-size variant `Some`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size variant `None`: 0 bytes +print-type-size type: `NestedNonZero`: 8 bytes, alignment: 4 bytes +print-type-size field `.val`: 4 bytes +print-type-size field `.post`: 2 bytes +print-type-size field `.pre`: 1 bytes +print-type-size end padding: 1 bytes +print-type-size type: `Enum4<(), char, (), ()>`: 4 bytes, alignment: 4 bytes +print-type-size variant `Two`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size variant `One`: 0 bytes +print-type-size field `.0`: 0 bytes +print-type-size variant `Three`: 0 bytes +print-type-size field `.0`: 0 bytes +print-type-size variant `Four`: 0 bytes +print-type-size field `.0`: 0 bytes +print-type-size type: `MyNotNegativeOne`: 4 bytes, alignment: 4 bytes +print-type-size field `._i`: 4 bytes +print-type-size type: `MyOption<MyNotNegativeOne>`: 4 bytes, alignment: 4 bytes +print-type-size variant `Some`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size variant `None`: 0 bytes +print-type-size type: `MyOption<char>`: 4 bytes, alignment: 4 bytes +print-type-size variant `Some`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size variant `None`: 0 bytes +print-type-size type: `MyOption<std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes +print-type-size variant `Some`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size variant `None`: 0 bytes +print-type-size type: `Union1<std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes +print-type-size variant `Union1`: 4 bytes +print-type-size field `.a`: 4 bytes +print-type-size type: `Union2<std::num::NonZeroU32, std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes +print-type-size variant `Union2`: 4 bytes +print-type-size field `.a`: 4 bytes +print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes +print-type-size type: `Union2<std::num::NonZeroU32, u32>`: 4 bytes, alignment: 4 bytes +print-type-size variant `Union2`: 4 bytes +print-type-size field `.a`: 4 bytes +print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes +print-type-size type: `std::num::NonZeroU32`: 4 bytes, alignment: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size type: `Enum4<(), (), (), MyOption<u8>>`: 2 bytes, alignment: 1 bytes +print-type-size variant `Four`: 2 bytes +print-type-size field `.0`: 2 bytes +print-type-size variant `One`: 0 bytes +print-type-size field `.0`: 0 bytes +print-type-size variant `Two`: 0 bytes +print-type-size field `.0`: 0 bytes +print-type-size variant `Three`: 0 bytes +print-type-size field `.0`: 0 bytes +print-type-size type: `MyOption<MyOption<u8>>`: 2 bytes, alignment: 1 bytes +print-type-size variant `Some`: 2 bytes +print-type-size field `.0`: 2 bytes +print-type-size variant `None`: 0 bytes +print-type-size type: `MyOption<u8>`: 2 bytes, alignment: 1 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `Some`: 1 bytes +print-type-size field `.0`: 1 bytes +print-type-size variant `None`: 0 bytes +print-type-size type: `Enum4<(), (), bool, ()>`: 1 bytes, alignment: 1 bytes +print-type-size variant `Three`: 1 bytes +print-type-size field `.0`: 1 bytes +print-type-size variant `One`: 0 bytes +print-type-size field `.0`: 0 bytes +print-type-size variant `Two`: 0 bytes +print-type-size field `.0`: 0 bytes +print-type-size variant `Four`: 0 bytes +print-type-size field `.0`: 0 bytes +print-type-size type: `MyOption<bool>`: 1 bytes, alignment: 1 bytes +print-type-size variant `Some`: 1 bytes +print-type-size field `.0`: 1 bytes +print-type-size variant `None`: 0 bytes +print-type-size type: `MyOption<std::cmp::Ordering>`: 1 bytes, alignment: 1 bytes +print-type-size variant `Some`: 1 bytes +print-type-size field `.0`: 1 bytes +print-type-size variant `None`: 0 bytes +print-type-size type: `std::cmp::Ordering`: 1 bytes, alignment: 1 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `Less`: 0 bytes +print-type-size variant `Equal`: 0 bytes +print-type-size variant `Greater`: 0 bytes diff --git a/tests/ui/print_type_sizes/no_duplicates.rs b/tests/ui/print_type_sizes/no_duplicates.rs new file mode 100644 index 000000000..2ec5d9e64 --- /dev/null +++ b/tests/ui/print_type_sizes/no_duplicates.rs @@ -0,0 +1,19 @@ +// compile-flags: -Z print-type-sizes --crate-type=lib +// build-pass +// ignore-pass +// ^-- needed because `--pass check` does not emit the output needed. +// FIXME: consider using an attribute instead of side-effects. + +// This file illustrates that when the same type occurs repeatedly +// (even if multiple functions), it is only printed once in the +// print-type-sizes output. + +pub struct SevenBytes([u8; 7]); + +pub fn f1() { + let _s: SevenBytes = SevenBytes([0; 7]); +} + +pub fn test() { + let _s: SevenBytes = SevenBytes([0; 7]); +} diff --git a/tests/ui/print_type_sizes/no_duplicates.stdout b/tests/ui/print_type_sizes/no_duplicates.stdout new file mode 100644 index 000000000..50180f356 --- /dev/null +++ b/tests/ui/print_type_sizes/no_duplicates.stdout @@ -0,0 +1,2 @@ +print-type-size type: `SevenBytes`: 7 bytes, alignment: 1 bytes +print-type-size field `.0`: 7 bytes diff --git a/tests/ui/print_type_sizes/packed.rs b/tests/ui/print_type_sizes/packed.rs new file mode 100644 index 000000000..5ddfe4bf4 --- /dev/null +++ b/tests/ui/print_type_sizes/packed.rs @@ -0,0 +1,59 @@ +// compile-flags: -Z print-type-sizes --crate-type=lib +// build-pass +// ignore-pass +// ^-- needed because `--pass check` does not emit the output needed. +// FIXME: consider using an attribute instead of side-effects. + +// This file illustrates how packing is handled; it should cause +// the elimination of padding that would normally be introduced +// to satisfy alignment desirata. +// +// It avoids using u64/i64 because on some targets that is only 4-byte +// aligned (while on most it is 8-byte aligned) and so the resulting +// padding and overall computed sizes can be quite different. + +#![allow(dead_code)] + +#[derive(Default)] +#[repr(packed)] +pub struct Packed1 { + a: u8, + b: u8, + g: i32, + c: u8, + h: i16, + d: u8, +} + +#[derive(Default)] +#[repr(packed(2))] +pub struct Packed2 { + a: u8, + b: u8, + g: i32, + c: u8, + h: i16, + d: u8, +} + +#[derive(Default)] +#[repr(packed(2))] +#[repr(C)] +pub struct Packed2C { + a: u8, + b: u8, + g: i32, + c: u8, + h: i16, + d: u8, +} + +#[derive(Default)] +pub struct Padded { + a: u8, + b: u8, + g: i32, + c: u8, + h: i16, + d: u8, +} diff --git a/tests/ui/print_type_sizes/packed.stdout b/tests/ui/print_type_sizes/packed.stdout new file mode 100644 index 000000000..58e1bac9e --- /dev/null +++ b/tests/ui/print_type_sizes/packed.stdout @@ -0,0 +1,31 @@ +print-type-size type: `Packed2C`: 12 bytes, alignment: 2 bytes +print-type-size field `.a`: 1 bytes +print-type-size field `.b`: 1 bytes +print-type-size field `.g`: 4 bytes +print-type-size field `.c`: 1 bytes +print-type-size padding: 1 bytes +print-type-size field `.h`: 2 bytes +print-type-size field `.d`: 1 bytes +print-type-size end padding: 1 bytes +print-type-size type: `Padded`: 12 bytes, alignment: 4 bytes +print-type-size field `.g`: 4 bytes +print-type-size field `.h`: 2 bytes +print-type-size field `.a`: 1 bytes +print-type-size field `.b`: 1 bytes +print-type-size field `.c`: 1 bytes +print-type-size field `.d`: 1 bytes +print-type-size end padding: 2 bytes +print-type-size type: `Packed1`: 10 bytes, alignment: 1 bytes +print-type-size field `.a`: 1 bytes +print-type-size field `.b`: 1 bytes +print-type-size field `.g`: 4 bytes +print-type-size field `.c`: 1 bytes +print-type-size field `.h`: 2 bytes +print-type-size field `.d`: 1 bytes +print-type-size type: `Packed2`: 10 bytes, alignment: 2 bytes +print-type-size field `.g`: 4 bytes +print-type-size field `.h`: 2 bytes +print-type-size field `.a`: 1 bytes +print-type-size field `.b`: 1 bytes +print-type-size field `.c`: 1 bytes +print-type-size field `.d`: 1 bytes diff --git a/tests/ui/print_type_sizes/padding.rs b/tests/ui/print_type_sizes/padding.rs new file mode 100644 index 000000000..f41c677dc --- /dev/null +++ b/tests/ui/print_type_sizes/padding.rs @@ -0,0 +1,28 @@ +// compile-flags: -Z print-type-sizes --crate-type=lib +// build-pass + +// This file illustrates how padding is handled: alignment +// requirements can lead to the introduction of padding, either before +// fields or at the end of the structure as a whole. +// +// It avoids using u64/i64 because on some targets that is only 4-byte +// aligned (while on most it is 8-byte aligned) and so the resulting +// padding and overall computed sizes can be quite different. + +#![allow(dead_code)] + +struct S { + a: bool, + b: bool, + g: i32, +} + +enum E1 { + A(i32, i8), + B(S), +} + +enum E2 { + A(i8, i32), + B(S), +} diff --git a/tests/ui/print_type_sizes/padding.stdout b/tests/ui/print_type_sizes/padding.stdout new file mode 100644 index 000000000..9afdf7624 --- /dev/null +++ b/tests/ui/print_type_sizes/padding.stdout @@ -0,0 +1,23 @@ +print-type-size type: `E1`: 12 bytes, alignment: 4 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `B`: 11 bytes +print-type-size padding: 3 bytes +print-type-size field `.0`: 8 bytes, alignment: 4 bytes +print-type-size variant `A`: 7 bytes +print-type-size field `.1`: 1 bytes +print-type-size padding: 2 bytes +print-type-size field `.0`: 4 bytes, alignment: 4 bytes +print-type-size type: `E2`: 12 bytes, alignment: 4 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `B`: 11 bytes +print-type-size padding: 3 bytes +print-type-size field `.0`: 8 bytes, alignment: 4 bytes +print-type-size variant `A`: 7 bytes +print-type-size field `.0`: 1 bytes +print-type-size padding: 2 bytes +print-type-size field `.1`: 4 bytes, alignment: 4 bytes +print-type-size type: `S`: 8 bytes, alignment: 4 bytes +print-type-size field `.g`: 4 bytes +print-type-size field `.a`: 1 bytes +print-type-size field `.b`: 1 bytes +print-type-size end padding: 2 bytes diff --git a/tests/ui/print_type_sizes/repr-align.rs b/tests/ui/print_type_sizes/repr-align.rs new file mode 100644 index 000000000..0bd11ebc9 --- /dev/null +++ b/tests/ui/print_type_sizes/repr-align.rs @@ -0,0 +1,32 @@ +// compile-flags: -Z print-type-sizes --crate-type=lib +// build-pass +// ignore-pass +// ^-- needed because `--pass check` does not emit the output needed. +// FIXME: consider using an attribute instead of side-effects. + +// This file illustrates how padding is handled: alignment +// requirements can lead to the introduction of padding, either before +// fields or at the end of the structure as a whole. +// +// It avoids using u64/i64 because on some targets that is only 4-byte +// aligned (while on most it is 8-byte aligned) and so the resulting +// padding and overall computed sizes can be quite different. + +#![allow(dead_code)] + +#[repr(align(16))] +#[derive(Default)] +struct A(i32); + +enum E { + A(i32), + B(A) +} + +#[derive(Default)] +pub struct S { + a: i32, + b: i32, + c: A, + d: i8, +} diff --git a/tests/ui/print_type_sizes/repr-align.stdout b/tests/ui/print_type_sizes/repr-align.stdout new file mode 100644 index 000000000..33671bd8e --- /dev/null +++ b/tests/ui/print_type_sizes/repr-align.stdout @@ -0,0 +1,16 @@ +print-type-size type: `E`: 32 bytes, alignment: 16 bytes +print-type-size discriminant: 4 bytes +print-type-size variant `B`: 28 bytes +print-type-size padding: 12 bytes +print-type-size field `.0`: 16 bytes, alignment: 16 bytes +print-type-size variant `A`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size type: `S`: 32 bytes, alignment: 16 bytes +print-type-size field `.c`: 16 bytes +print-type-size field `.a`: 4 bytes +print-type-size field `.b`: 4 bytes +print-type-size field `.d`: 1 bytes +print-type-size end padding: 7 bytes +print-type-size type: `A`: 16 bytes, alignment: 16 bytes +print-type-size field `.0`: 4 bytes +print-type-size end padding: 12 bytes diff --git a/tests/ui/print_type_sizes/repr_int_c.rs b/tests/ui/print_type_sizes/repr_int_c.rs new file mode 100644 index 000000000..6b103776a --- /dev/null +++ b/tests/ui/print_type_sizes/repr_int_c.rs @@ -0,0 +1,19 @@ +// compile-flags: -Z print-type-sizes --crate-type=lib +// build-pass + +// This test makes sure that the tag is not grown for `repr(C)` or `repr(u8)` +// variants (see https://github.com/rust-lang/rust/issues/50098 for the original bug). + +#![allow(dead_code)] + +#[repr(C, u8)] +enum ReprCu8 { + A(u16), + B, +} + +#[repr(u8)] +enum Repru8 { + A(u16), + B, +} diff --git a/tests/ui/print_type_sizes/repr_int_c.stdout b/tests/ui/print_type_sizes/repr_int_c.stdout new file mode 100644 index 000000000..254b3c7a8 --- /dev/null +++ b/tests/ui/print_type_sizes/repr_int_c.stdout @@ -0,0 +1,12 @@ +print-type-size type: `ReprCu8`: 4 bytes, alignment: 2 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `A`: 3 bytes +print-type-size padding: 1 bytes +print-type-size field `.0`: 2 bytes, alignment: 2 bytes +print-type-size variant `B`: 1 bytes +print-type-size type: `Repru8`: 4 bytes, alignment: 2 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `A`: 3 bytes +print-type-size padding: 1 bytes +print-type-size field `.0`: 2 bytes, alignment: 2 bytes +print-type-size variant `B`: 0 bytes diff --git a/tests/ui/print_type_sizes/uninhabited.rs b/tests/ui/print_type_sizes/uninhabited.rs new file mode 100644 index 000000000..86fab7b50 --- /dev/null +++ b/tests/ui/print_type_sizes/uninhabited.rs @@ -0,0 +1,13 @@ +// compile-flags: -Z print-type-sizes --crate-type=lib +// build-pass +// ignore-pass +// ^-- needed because `--pass check` does not emit the output needed. +// FIXME: consider using an attribute instead of side-effects. + +#![feature(never_type)] + +pub fn test() { + let _x: Option<!> = None; + let _y: Result<u32, !> = Ok(42); + let _z: Result<!, !> = loop {}; +} diff --git a/tests/ui/print_type_sizes/uninhabited.stdout b/tests/ui/print_type_sizes/uninhabited.stdout new file mode 100644 index 000000000..5eb5384bc --- /dev/null +++ b/tests/ui/print_type_sizes/uninhabited.stdout @@ -0,0 +1,6 @@ +print-type-size type: `std::result::Result<u32, !>`: 4 bytes, alignment: 4 bytes +print-type-size variant `Ok`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size type: `std::option::Option<!>`: 0 bytes, alignment: 1 bytes +print-type-size variant `None`: 0 bytes +print-type-size type: `std::result::Result<!, !>`: 0 bytes, alignment: 1 bytes diff --git a/tests/ui/print_type_sizes/variants.rs b/tests/ui/print_type_sizes/variants.rs new file mode 100644 index 000000000..5a3020520 --- /dev/null +++ b/tests/ui/print_type_sizes/variants.rs @@ -0,0 +1,18 @@ +// compile-flags: -Z print-type-sizes --crate-type=lib +// build-pass + +// This file illustrates two things: +// +// 1. Only types that appear in a monomorphized function appear in the +// print-type-sizes output, and +// +// 2. For an enum, the print-type-sizes output will also include the +// size of each variant. + +pub struct SevenBytes([u8; 7]); +pub struct FiftyBytes([u8; 50]); + +pub enum Enum { + Small(SevenBytes), + Large(FiftyBytes), +} diff --git a/tests/ui/print_type_sizes/variants.stdout b/tests/ui/print_type_sizes/variants.stdout new file mode 100644 index 000000000..641188154 --- /dev/null +++ b/tests/ui/print_type_sizes/variants.stdout @@ -0,0 +1,10 @@ +print-type-size type: `Enum`: 51 bytes, alignment: 1 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `Large`: 50 bytes +print-type-size field `.0`: 50 bytes +print-type-size variant `Small`: 7 bytes +print-type-size field `.0`: 7 bytes +print-type-size type: `FiftyBytes`: 50 bytes, alignment: 1 bytes +print-type-size field `.0`: 50 bytes +print-type-size type: `SevenBytes`: 7 bytes, alignment: 1 bytes +print-type-size field `.0`: 7 bytes diff --git a/tests/ui/print_type_sizes/zero-sized-fields.rs b/tests/ui/print_type_sizes/zero-sized-fields.rs new file mode 100644 index 000000000..09415824d --- /dev/null +++ b/tests/ui/print_type_sizes/zero-sized-fields.rs @@ -0,0 +1,43 @@ +// compile-flags: -Z print-type-sizes --crate-type=lib +// build-pass +// ignore-pass + +// At one point, zero-sized fields such as those in this file were causing +// incorrect output from `-Z print-type-sizes`. + +struct S1 { + x: u32, + y: u32, + tag: (), +} + +struct Void(); +struct Empty {} + +struct S5<TagW, TagZ> { + tagw: TagW, + w: u32, + unit: (), + x: u32, + void: Void, + y: u32, + empty: Empty, + z: u32, + tagz: TagZ, +} + +pub fn test() { + let _s1: S1 = S1 { x: 0, y: 0, tag: () }; + + let _s5: S5<(), Empty> = S5 { + tagw: (), + w: 1, + unit: (), + x: 2, + void: Void(), + y: 3, + empty: Empty {}, + z: 4, + tagz: Empty {}, + }; +} diff --git a/tests/ui/print_type_sizes/zero-sized-fields.stdout b/tests/ui/print_type_sizes/zero-sized-fields.stdout new file mode 100644 index 000000000..72f59c4bb --- /dev/null +++ b/tests/ui/print_type_sizes/zero-sized-fields.stdout @@ -0,0 +1,16 @@ +print-type-size type: `S5<(), Empty>`: 16 bytes, alignment: 4 bytes +print-type-size field `.tagw`: 0 bytes +print-type-size field `.unit`: 0 bytes +print-type-size field `.void`: 0 bytes +print-type-size field `.empty`: 0 bytes +print-type-size field `.tagz`: 0 bytes +print-type-size field `.w`: 4 bytes +print-type-size field `.x`: 4 bytes +print-type-size field `.y`: 4 bytes +print-type-size field `.z`: 4 bytes +print-type-size type: `S1`: 8 bytes, alignment: 4 bytes +print-type-size field `.tag`: 0 bytes +print-type-size field `.x`: 4 bytes +print-type-size field `.y`: 4 bytes +print-type-size type: `Empty`: 0 bytes, alignment: 1 bytes +print-type-size type: `Void`: 0 bytes, alignment: 1 bytes |