summary refs log tree commit diff
path: root/src/test/ui/for-loop-while/label_break_value.rs
blob: 18930ac811e80b10c9d414f5980b8b1bd4c7d23c (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
// run-pass
#![allow(dead_code)]
#![allow(unused_assignments)]
#![feature(label_break_value)]

// Test control flow to follow label_break_value semantics
fn label_break(a: bool, b: bool) -> u32 {
    let mut v = 0;
    'b: {
        v = 1;
        if a {
            break 'b;
        }
        v = 2;
        if b {
            break 'b;
        }
        v = 3;
    }
    return v;
}

// Test that values can be returned
fn break_value(a: bool, b: bool) -> u32 {
    let result = 'block: {
        if a { break 'block 1; }
        if b { break 'block 2; }
        3
    };
    result
}

// Test nesting of labeled blocks
// here we only check that it compiles
fn label_break_nested() {
    'b: {
        println!("hi");
        if false {
            break 'b;
        }
        'c: {
            if false {
                break 'b;
            }
            break 'c;
        }
        println!("hello");
        if true {
            break 'b;
        }
    }
}

// Tests for mixing labeled blocks with loop constructs
// This function should be the identity function
fn label_break_mixed(v: u32) -> u32 {
    let mut r = 0;
    'b: {
        // Unlabeled break still works
        // (only crossing boundaries is an error)
        loop {
            break;
        }
        if v == 0 {
            break 'b;
        }
        // Labeled breaking an inner loop still works
        'c: loop {
            if r == 1 {
                break 'c;
            }
            r += 1;
        }
        assert_eq!(r, 1);
        if v == 1 {
            break 'b;
        }
        // Labeled breaking an outer loop still works
        'd: loop {
            {
                if v == r {
                    break 'b;
                }
                if r == 5 {
                    break 'd;
                }
                r += 1;
            }
        }
        assert_eq!(r, 5);
        assert!(v > r);
        // Here we test return from inside a labeled block
        return v;
    }
    r
}

pub fn main() {
    assert_eq!(label_break(true, false), 1);
    assert_eq!(label_break(false, true), 2);
    assert_eq!(label_break(false, false), 3);

    assert_eq!(break_value(true, false), 1);
    assert_eq!(break_value(false, true), 2);
    assert_eq!(break_value(false, false), 3);

    assert_eq!(label_break_mixed(0), 0);
    assert_eq!(label_break_mixed(1), 1);
    assert_eq!(label_break_mixed(2), 2);
    assert_eq!(label_break_mixed(3), 3);
    assert_eq!(label_break_mixed(4), 4);
    assert_eq!(label_break_mixed(5), 5);
    assert_eq!(label_break_mixed(6), 6);

    // FIXME: ensure that labeled blocks work if produced by macros and in match arms
}