summaryrefslogtreecommitdiffstats
path: root/tests/mir-opt/sroa/structs.rs
blob: 73563e12c94fcd4d7cabbe976906624a40d99a70 (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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// skip-filecheck
// unit-test: ScalarReplacementOfAggregates
// compile-flags: -Cpanic=abort
// no-prefer-dynamic

struct Tag(usize);

#[repr(C)]
struct S(Tag, Tag, Tag);

impl Drop for Tag {
    #[inline(never)]
    fn drop(&mut self) {}
}

pub fn dropping() {
    S(Tag(0), Tag(1), Tag(2)).1;
}

pub fn enums(a: usize) -> usize {
    if let Some(a) = Some(a) { a } else { 0 }
}

pub fn structs(a: f32) -> f32 {
    struct U {
        _foo: usize,
        a: f32,
    }

    U { _foo: 0, a }.a
}

pub fn unions(a: f32) -> u32 {
    union Repr {
        f: f32,
        u: u32,
    }
    unsafe { Repr { f: a }.u }
}

#[derive(Copy, Clone)]
struct Foo {
    a: u8,
    b: (),
    c: &'static str,
    d: Option<isize>,
}

fn g() -> u32 {
    3
}

pub fn flat() {
    let Foo { a, b, c, d } = Foo { a: 5, b: (), c: "a", d: Some(-4) };
    let _ = a;
    let _ = b;
    let _ = c;
    let _ = d;
}

#[repr(C)]
struct Escaping {
    a: u32,
    b: u32,
    c: u32,
}

fn f(a: *const u32) {
    println!("{}", unsafe { *a.add(2) });
}

// `f` uses the `&e.a` to access `e.c`. This is UB according to Miri today; however,
// T-opsem has not finalized that decision and as such rustc should not rely on
// it. If SROA were to rely on it, it would be (almost) correct to turn `e` into
// three distinct locals - one for each field - and pass a reference to only one
// of them to `f`. However, this would lead to a miscompilation because `b` and `c`
// might no longer appear right after `a` in memory.
pub fn escaping() {
    f(&Escaping { a: 1, b: 2, c: g() }.a);
}

fn copies(x: Foo) {
    let y = x;
    let t = y.a;
    let u = y.c;
    let z = y;
    let a = z.b;
}

fn ref_copies(x: &Foo) {
    let y = *x;
    let t = y.a;
    let u = y.c;
}

fn constant() {
    const U: (usize, u8) = (5, 9);
    let y = U;
    let t = y.0;
    let u = y.1;
}

fn main() {
    dropping();
    enums(5);
    structs(5.);
    unions(5.);
    flat();
    escaping();
    copies(Foo { a: 5, b: (), c: "a", d: Some(-4) });
    ref_copies(&Foo { a: 5, b: (), c: "a", d: Some(-4) });
    constant();
}

// EMIT_MIR structs.dropping.ScalarReplacementOfAggregates.diff
// EMIT_MIR structs.enums.ScalarReplacementOfAggregates.diff
// EMIT_MIR structs.structs.ScalarReplacementOfAggregates.diff
// EMIT_MIR structs.unions.ScalarReplacementOfAggregates.diff
// EMIT_MIR structs.flat.ScalarReplacementOfAggregates.diff
// EMIT_MIR structs.escaping.ScalarReplacementOfAggregates.diff
// EMIT_MIR structs.copies.ScalarReplacementOfAggregates.diff
// EMIT_MIR structs.ref_copies.ScalarReplacementOfAggregates.diff
// EMIT_MIR structs.constant.ScalarReplacementOfAggregates.diff