Skip to content

Commit 5aac067

Browse files
committed
Add parser tests for statement boundary insertion
1 parent cfe4bb7 commit 5aac067

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//@ run-pass
2+
//@ edition:2021
3+
4+
// This is a test of several uses of rustc_ast::util::classify::expr_requires_semi_to_be_stmt
5+
// by the Rust parser, which relates to the insertion of statement boundaries
6+
// after certain kinds of expressions if they appear at the head of a statement.
7+
8+
#![feature(inline_const)]
9+
#![allow(unused_braces, unused_unsafe)]
10+
11+
macro_rules! unit {
12+
() => {
13+
{ () }
14+
};
15+
}
16+
17+
#[derive(Copy, Clone)]
18+
struct X;
19+
20+
fn main() {
21+
let x = X;
22+
23+
// There is a statement boundary before `|x| x`, so it's a closure.
24+
let _: fn(X) -> X = { if true {} |x| x };
25+
let _: fn(X) -> X = { if true {} else {} |x| x };
26+
let _: fn(X) -> X = { match () { () => {} } |x| x };
27+
let _: fn(X) -> X = { { () } |x| x };
28+
let _: fn(X) -> X = { unsafe {} |x| x };
29+
let _: fn(X) -> X = { while false {} |x| x };
30+
let _: fn(X) -> X = { loop { break; } |x| x };
31+
let _: fn(X) -> X = { for _ in 0..0 {} |x| x };
32+
let _: fn(X) -> X = { const {} |x| x };
33+
let _: fn(X) -> X = { unit! {} |x| x };
34+
35+
// No statement boundary, so `|x| x` is 2× BitOr operation.
36+
() = { "" |x| x };
37+
() = { ("") |x| x };
38+
() = { [""] |x| x };
39+
() = { unit!() |x| x };
40+
() = { unit![] |x| x };
41+
42+
// All the same cases, but as a match arm.
43+
() = match x {
44+
// Statement boundary before `| X`, which becomes a new arm with leading vert.
45+
X if false => if true {} | X if false => {}
46+
X if false => if true {} else {} | X if false => {}
47+
X if false => match () { () => {} } | X if false => {}
48+
X if false => { () } | X if false => {}
49+
X if false => unsafe {} | X if false => {}
50+
X if false => while false {} | X if false => {}
51+
X if false => loop { break; } | X if false => {}
52+
X if false => for _ in 0..0 {} | X if false => {}
53+
X if false => const {} | X if false => {}
54+
55+
// No statement boundary, so `| X` is BitOr.
56+
X if false => "" | X,
57+
X if false => ("") | X,
58+
X if false => [""] | X,
59+
X if false => unit! {} | X, // !! inconsistent with braced mac call in statement position
60+
X if false => unit!() | X,
61+
X if false => unit![] | X,
62+
63+
X => {}
64+
};
65+
66+
// Test how the statement boundary logic interacts with macro metavariables /
67+
// "invisible delimiters".
68+
macro_rules! assert_statement_boundary {
69+
($expr:expr) => {
70+
let _: fn(X) -> X = { $expr |x| x };
71+
72+
() = match X {
73+
X if false => $expr | X if false => {}
74+
X => {}
75+
};
76+
};
77+
}
78+
macro_rules! assert_no_statement_boundary {
79+
($expr:expr) => {
80+
() = { $expr |x| x };
81+
82+
() = match x {
83+
X if false => $expr | X,
84+
X => {}
85+
};
86+
};
87+
}
88+
assert_statement_boundary!(if true {});
89+
assert_no_statement_boundary!("");
90+
}
91+
92+
impl std::ops::BitOr<X> for () {
93+
type Output = ();
94+
fn bitor(self, _: X) {}
95+
}
96+
97+
impl std::ops::BitOr<X> for &str {
98+
type Output = ();
99+
fn bitor(self, _: X) {}
100+
}
101+
102+
impl<T, const N: usize> std::ops::BitOr<X> for [T; N] {
103+
type Output = ();
104+
fn bitor(self, _: X) {}
105+
}

0 commit comments

Comments
 (0)