summaryrefslogtreecommitdiffstats
path: root/src/test/ui/closures/2229_closure_analysis/repr_packed.rs
blob: 3ed780f51c73b6b6f4a54130faccad04c9afbdfc (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
// edition:2021

#![feature(rustc_attrs)]

// `u8` aligned at a byte and are unaffected by repr(packed).
// Therefore we can precisely (and safely) capture references to both the fields.
fn test_alignment_not_affected() {
    #[repr(packed)]
    struct Foo { x: u8, y: u8 }

    let mut foo = Foo { x: 0, y: 0 };

    let mut c = #[rustc_capture_analysis]
    //~^ ERROR: attributes on expressions are experimental
    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
    || {
    //~^ ERROR: First Pass analysis includes:
    //~| ERROR: Min Capture analysis includes:
        let z1: &u8 = &foo.x;
        //~^ NOTE: Capturing foo[(0, 0)] -> ImmBorrow
        //~| NOTE: Min Capture foo[(0, 0)] -> ImmBorrow
        let z2: &mut u8 = &mut foo.y;
        //~^ NOTE: Capturing foo[(1, 0)] -> MutBorrow
        //~| NOTE: Min Capture foo[(1, 0)] -> MutBorrow

        *z2 = 42;

        println!("({}, {})", z1, z2);
    };

    c();
}

// `String`, `u16` are not aligned at a one byte boundry and are thus affected by repr(packed).
//
// Here we test that the closure doesn't capture a reference point to `foo.x` but
// rather capture `foo` entirely.
fn test_alignment_affected() {
    #[repr(packed)]
    struct Foo { x: String, y: u16 }

    let mut foo = Foo { x: String::new(), y: 0 };

    let mut c = #[rustc_capture_analysis]
    //~^ ERROR: attributes on expressions are experimental
    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
    || {
    //~^ ERROR: First Pass analysis includes:
    //~| ERROR: Min Capture analysis includes:
        let z1: &String = &foo.x;
        //~^ NOTE: Capturing foo[] -> ImmBorrow
        let z2: &mut u16 = &mut foo.y;
        //~^ NOTE: Capturing foo[] -> MutBorrow
        //~| NOTE: Min Capture foo[] -> MutBorrow


        *z2 = 42;

        println!("({}, {})", z1, z2);
    };

    c();
}

// Given how the closure desugaring is implemented (at least at the time of writing this test),
// we don't need to truncate the captured path to a reference into a packed-struct if the field
// being referenced will be moved into the closure, since it's safe to move out a field from a
// packed-struct.
//
// However to avoid surprises for the user, or issues when the closure is
// inlined we will truncate the capture to access just the struct regardless of if the field
// might get moved into the closure.
fn test_truncation_when_ref_and_move() {
    #[repr(packed)]
    struct Foo { x: String }

    let mut foo = Foo { x: String::new() };

    let c = #[rustc_capture_analysis]
    //~^ ERROR: attributes on expressions are experimental
    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
    || {
    //~^ ERROR: First Pass analysis includes:
    //~| ERROR: Min Capture analysis includes:
        println!("{}", foo.x);
        //~^ NOTE: Capturing foo[] -> ImmBorrow
        //~| NOTE: Min Capture foo[] -> ByValue
        //~| NOTE: foo[] used here
        let _z = foo.x;
        //~^ NOTE: Capturing foo[(0, 0)] -> ByValue
        //~| NOTE: foo[] captured as ByValue here
    };

    c();
}

fn main() {
    test_truncation_when_ref_and_move();
    test_alignment_affected();
    test_alignment_not_affected();
}