rust/tests/ui/parser/macro/statement-boundaries.rs

105 lines
3.1 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

//@ 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) {}
}