| // 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 |
| } |
| |
| fn label_break_match(c: u8, xe: u8, ye: i8) { |
| let mut x = 0; |
| let y = 'a: { |
| match c { |
| 0 => break 'a 0, |
| v if { if v % 2 == 0 { break 'a 1; }; v % 3 == 0 } => { x += 1; }, |
| v if { 'b: { break 'b v == 5; } } => { x = 41; }, |
| _ => 'b: { //~ WARNING `'b` shadows a label |
| break 'b (); |
| }, |
| } |
| x += 1; |
| -1 |
| }; |
| |
| assert_eq!(x, xe); |
| assert_eq!(y, ye); |
| } |
| |
| #[allow(unused_labels)] |
| fn label_break_macro() { |
| macro_rules! mac1 { |
| ($target:lifetime, $val:expr) => { |
| break $target $val; |
| }; |
| } |
| let x: u8 = 'a: { |
| 'b: { |
| mac1!('b, 1); |
| }; |
| 0 |
| }; |
| assert_eq!(x, 0); |
| let x: u8 = 'a: { //~ WARNING `'a` shadows a label |
| 'b: { //~ WARNING `'b` shadows a label |
| if true { |
| mac1!('a, 1); |
| } |
| }; |
| 0 |
| }; |
| assert_eq!(x, 1); |
| } |
| |
| 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); |
| |
| label_break_match(0, 0, 0); |
| label_break_match(1, 1, -1); |
| label_break_match(2, 0, 1); |
| label_break_match(3, 2, -1); |
| label_break_match(5, 42, -1); |
| label_break_match(7, 1, -1); |
| |
| label_break_macro(); |
| } |