rust/tests/ui/parser/macro/statement-boundaries.rs
2024-05-11 15:49:50 -07:00

105 lines
3.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//@ run-pass
//@ edition:2021
// This is a test of several uses of rustc_ast::util::classify::expr_requires_semi_to_be_stmt
// by the Rust parser, which relates to the insertion of statement boundaries
// after certain kinds of expressions if they appear at the head of a statement.
#![allow(unused_braces, unused_unsafe)]
macro_rules! unit {
() => {
{ () }
};
}
#[derive(Copy, Clone)]
struct X;
fn main() {
let x = X;
// There is a statement boundary before `|x| x`, so it's a closure.
let _: fn(X) -> X = { if true {} |x| x };
let _: fn(X) -> X = { if true {} else {} |x| x };
let _: fn(X) -> X = { match () { () => {} } |x| x };
let _: fn(X) -> X = { { () } |x| x };
let _: fn(X) -> X = { unsafe {} |x| x };
let _: fn(X) -> X = { while false {} |x| x };
let _: fn(X) -> X = { loop { break; } |x| x };
let _: fn(X) -> X = { for _ in 0..0 {} |x| x };
let _: fn(X) -> X = { const {} |x| x };
let _: fn(X) -> X = { unit! {} |x| x };
// No statement boundary, so `|x| x` is 2× BitOr operation.
() = { "" |x| x };
() = { ("") |x| x };
() = { [""] |x| x };
() = { unit!() |x| x };
() = { unit![] |x| x };
// All the same cases, but as a match arm.
() = match x {
// Statement boundary before `| X`, which becomes a new arm with leading vert.
X if false => if true {} | X if false => {}
X if false => if true {} else {} | X if false => {}
X if false => match () { () => {} } | X if false => {}
X if false => { () } | X if false => {}
X if false => unsafe {} | X if false => {}
X if false => while false {} | X if false => {}
X if false => loop { break; } | X if false => {}
X if false => for _ in 0..0 {} | X if false => {}
X if false => const {} | X if false => {}
// No statement boundary, so `| X` is BitOr.
X if false => "" | X,
X if false => ("") | X,
X if false => [""] | X,
X if false => unit! {} | X, // !! inconsistent with braced mac call in statement position
X if false => unit!() | X,
X if false => unit![] | X,
X => {}
};
// Test how the statement boundary logic interacts with macro metavariables /
// "invisible delimiters".
macro_rules! assert_statement_boundary {
($expr:expr) => {
let _: fn(X) -> X = { $expr |x| x };
() = match X {
X if false => $expr | X if false => {}
X => {}
};
};
}
macro_rules! assert_no_statement_boundary {
($expr:expr) => {
() = { $expr |x| x };
() = match x {
X if false => $expr | X,
X => {}
};
};
}
assert_statement_boundary!(if true {});
assert_no_statement_boundary!("");
}
impl std::ops::BitOr<X> for () {
type Output = ();
fn bitor(self, _: X) {}
}
impl std::ops::BitOr<X> for &str {
type Output = ();
fn bitor(self, _: X) {}
}
impl<T, const N: usize> std::ops::BitOr<X> for [T; N] {
type Output = ();
fn bitor(self, _: X) {}
}