//@ force-host //@ no-prefer-dynamic // These are tests for syntax that is accepted by the Rust parser but // unconditionally rejected semantically after macro expansion. Attribute macros // are permitted to accept such syntax as long as they replace it with something // that makes sense to Rust. // // We also inspect some of the spans to verify the syntax is not triggering the // lossy string reparse hack (https://github.com/rust-lang/rust/issues/43081). #![crate_type = "proc-macro"] #![feature(proc_macro_span)] extern crate proc_macro; use proc_macro::{token_stream, Delimiter, TokenStream, TokenTree}; use std::path::Component; // unsafe mod m { // pub unsafe mod inner; // } #[proc_macro_attribute] pub fn expect_unsafe_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream { let tokens = &mut input.into_iter(); expect(tokens, "unsafe"); expect(tokens, "mod"); expect(tokens, "m"); let tokens = &mut expect_brace(tokens); expect(tokens, "pub"); expect(tokens, "unsafe"); expect(tokens, "mod"); let ident = expect(tokens, "inner"); expect(tokens, ";"); check_useful_span(ident, "unsafe-mod.rs"); TokenStream::new() } // unsafe extern { // type T; // } #[proc_macro_attribute] pub fn expect_unsafe_foreign_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream { let tokens = &mut input.into_iter(); expect(tokens, "unsafe"); expect(tokens, "extern"); let tokens = &mut expect_brace(tokens); expect(tokens, "type"); let ident = expect(tokens, "T"); expect(tokens, ";"); check_useful_span(ident, "unsafe-foreign-mod.rs"); TokenStream::new() } // unsafe extern "C++" {} #[proc_macro_attribute] pub fn expect_unsafe_extern_cpp_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream { let tokens = &mut input.into_iter(); expect(tokens, "unsafe"); expect(tokens, "extern"); let abi = expect(tokens, "\"C++\""); expect_brace(tokens); check_useful_span(abi, "unsafe-foreign-mod.rs"); TokenStream::new() } fn expect(tokens: &mut token_stream::IntoIter, expected: &str) -> TokenTree { match tokens.next() { Some(token) if token.to_string() == expected => token, wrong => panic!("unexpected token: {:?}, expected `{}`", wrong, expected), } } fn expect_brace(tokens: &mut token_stream::IntoIter) -> token_stream::IntoIter { match tokens.next() { Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => { group.stream().into_iter() } wrong => panic!("unexpected token: {:?}, expected `{{`", wrong), } } fn check_useful_span(token: TokenTree, expected_filename: &str) { let span = token.span(); assert!(span.column() < span.end().column()); let source_path = span.source_file().path(); let filename = source_path.components().last().unwrap(); assert_eq!(filename, Component::Normal(expected_filename.as_ref())); }