summaryrefslogtreecommitdiffstats
path: root/src/test/ui/print_type_sizes/niche-filling.rs
blob: 0716cee21c6626a71670081e752d2abdddc11775 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// compile-flags: -Z print-type-sizes
// 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(start)]
#![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: NonZeroU32::new(1).unwrap(), 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,
}

#[start]
fn start(_: isize, _: *const *const u8) -> isize {
    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();

    0
}