| //@ aux-build:attr-stmt-expr.rs |
| //@ aux-build:test-macros.rs |
| //@ compile-flags: -Z span-debug |
| //@ check-pass |
| |
| #![feature(proc_macro_hygiene)] |
| #![feature(stmt_expr_attributes)] |
| #![feature(rustc_attrs)] |
| #![allow(dead_code)] |
| |
| #![no_std] // Don't load unnecessary hygiene information from std |
| extern crate std; |
| |
| extern crate attr_stmt_expr; |
| extern crate test_macros; |
| use attr_stmt_expr::{expect_let, expect_my_macro_stmt, expect_expr, expect_my_macro_expr}; |
| use test_macros::print_attr; |
| |
| // We don't use `std::println` so that we avoid loading hygiene |
| // information from libstd, which would affect the SyntaxContext ids |
| macro_rules! my_macro { |
| ($($tt:tt)*) => { () } |
| } |
| |
| |
| fn print_str(string: &'static str) { |
| // macros are handled a bit differently |
| #[expect_my_macro_expr] |
| my_macro!("{}", string) |
| } |
| |
| macro_rules! make_stmt { |
| ($stmt:stmt) => { |
| #[print_attr] |
| #[rustc_dummy] |
| $stmt; // This semicolon is *not* passed to the macro, |
| // since `$stmt` is already a statement. |
| } |
| } |
| |
| macro_rules! second_make_stmt { |
| ($stmt:stmt) => { |
| make_stmt!($stmt); |
| } |
| } |
| |
| // The macro will see a semicolon here |
| #[print_attr] |
| struct ItemWithSemi; |
| |
| |
| fn main() { |
| make_stmt!(struct Foo {}); |
| |
| #[print_attr] |
| #[expect_let] |
| let string = "Hello, world!"; |
| |
| #[print_attr] |
| #[expect_my_macro_stmt] |
| my_macro!("{}", string); |
| |
| #[print_attr] |
| second_make_stmt!(#[allow(dead_code)] struct Bar {}); |
| |
| #[print_attr] |
| #[rustc_dummy] |
| struct Other {}; |
| |
| // The macro also sees a semicolon, |
| // for consistency with the `ItemWithSemi` case above. |
| #[print_attr] |
| #[rustc_dummy] |
| struct NonBracedStruct; |
| |
| #[expect_expr] |
| print_str("string") |
| } |