Skip to content

Commit 4a80865

Browse files
committed
Add parser tests for statement boundary insertion
1 parent c6c18a0 commit 4a80865

File tree

1 file changed

+104
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)