summary refs log tree commit diff
path: root/tests/mir-opt/copy-prop/borrowed_local.rs
blob: 68cdc57483a2d3df8912d155122c29456d64a42e (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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
//@ test-mir-pass: CopyProp

#![feature(custom_mir, core_intrinsics, freeze)]
#![allow(unused_assignments)]
extern crate core;
use core::intrinsics::mir::*;
use core::marker::Freeze;

fn opaque(_: impl Sized) -> bool {
    true
}

fn cmp_ref(a: &u8, b: &u8) -> bool {
    std::ptr::eq(a as *const u8, b as *const u8)
}

#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
fn compare_address() -> bool {
    // CHECK-LABEL: fn compare_address(
    // CHECK: bb0: {
    // CHECK-NEXT: _1 = const 5_u8;
    // CHECK-NEXT: _2 = &_1;
    // CHECK-NEXT: _3 = copy _1;
    // CHECK-NEXT: _4 = &_3;
    // CHECK-NEXT: _0 = cmp_ref(copy _2, copy _4)
    // CHECK: bb1: {
    // CHECK-NEXT: _0 = opaque::<u8>(copy _3)
    mir! {
        {
            let a = 5_u8;
            let r1 = &a;
            let b = a;
            // We cannot propagate the place `a`.
            let r2 = &b;
            Call(RET = cmp_ref(r1, r2), ReturnTo(next), UnwindContinue())
        }
        next = {
            // But we can propagate the value `a`.
            Call(RET = opaque(b), ReturnTo(ret), UnwindContinue())
        }
        ret = {
            Return()
        }
    }
}

/// Generic type `T` is `Freeze`, so shared borrows are immutable.
#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
fn borrowed<T: Copy + Freeze>(x: T) -> bool {
    // CHECK-LABEL: fn borrowed(
    // CHECK: bb0: {
    // CHECK-NEXT: _2 = copy _1;
    // CHECK-NEXT: _3 = &_1;
    // CHECK-NEXT: _0 = opaque::<&T>(copy _3)
    // CHECK: bb1: {
    // CHECK-NEXT: _0 = opaque::<T>(copy _2)
    mir! {
        {
            let a = x;
            let r1 = &x;
            Call(RET = opaque(r1), ReturnTo(next), UnwindContinue())
        }
        next = {
            Call(RET = opaque(a), ReturnTo(ret), UnwindContinue())
        }
        ret = {
            Return()
        }
    }
}

/// Generic type `T` is not known to be `Freeze`, so shared borrows may be mutable.
#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
fn non_freeze<T: Copy>(x: T) -> bool {
    // CHECK-LABEL: fn non_freeze(
    // CHECK: bb0: {
    // CHECK-NEXT: _2 = copy _1;
    // CHECK-NEXT: _3 = &_1;
    // CHECK-NEXT: _0 = opaque::<&T>(copy _3)
    // CHECK: bb1: {
    // CHECK-NEXT: _0 = opaque::<T>(copy _2)
    mir! {
        {
            let a = x;
            let r1 = &x;
            Call(RET = opaque(r1), ReturnTo(next), UnwindContinue())
        }
        next = {
            Call(RET = opaque(a), ReturnTo(ret), UnwindContinue())
        }
        ret = {
            Return()
        }
    }
}

/// We must not unify a borrowed local with another that may be written-to before the borrow is
/// read again. As we have no aliasing model yet, this means forbidding unifying borrowed locals.
fn borrow_in_loop() {
    // CHECK-LABEL: fn borrow_in_loop(
    // CHECK: debug c => [[c:_.*]];
    // CHECK: debug p => [[p:_.*]];
    // CHECK: debug a => [[a:_.*]];
    // CHECK: debug b => [[b:_.*]];
    // CHECK-NOT: &[[a]]
    // CHECK-NOT: &[[b]]
    // CHECK: [[a]] = Not({{.*}});
    // CHECK-NOT: &[[a]]
    // CHECK-NOT: &[[b]]
    // CHECK: [[b]] = Not({{.*}});
    // CHECK-NOT: &[[a]]
    // CHECK-NOT: &[[b]]
    // CHECK: &[[c]]
    // CHECK-NOT: &[[a]]
    // CHECK-NOT: &[[b]]
    let mut c;
    let mut p = &false;
    loop {
        let a = !*p;
        let b = !*p;
        c = a;
        p = &c;
        if a != b {
            return;
        }
    }
}

fn main() {
    assert!(!compare_address());
    non_freeze(5);
    borrow_in_loop();
}

// EMIT_MIR borrowed_local.compare_address.CopyProp.diff
// EMIT_MIR borrowed_local.borrowed.CopyProp.diff
// EMIT_MIR borrowed_local.non_freeze.CopyProp.diff
// EMIT_MIR borrowed_local.borrow_in_loop.CopyProp.diff