1 // force-host
2 // no-prefer-dynamic
3
4 // These are tests for syntax that is accepted by the Rust parser but
5 // unconditionally rejected semantically after macro expansion. Attribute macros
6 // are permitted to accept such syntax as long as they replace it with something
7 // that makes sense to Rust.
8 //
9 // We also inspect some of the spans to verify the syntax is not triggering the
10 // lossy string reparse hack (https://github.com/rust-lang/rust/issues/43081).
11
12 #![crate_type = "proc-macro"]
13 #![feature(proc_macro_span)]
14
15 extern crate proc_macro;
16 use proc_macro::{token_stream, Delimiter, TokenStream, TokenTree};
17 use std::path::Component;
18
19 // unsafe mod m {
20 // pub unsafe mod inner;
21 // }
22 #[proc_macro_attribute]
expect_unsafe_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream23 pub fn expect_unsafe_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream {
24 let tokens = &mut input.into_iter();
25 expect(tokens, "unsafe");
26 expect(tokens, "mod");
27 expect(tokens, "m");
28 let tokens = &mut expect_brace(tokens);
29 expect(tokens, "pub");
30 expect(tokens, "unsafe");
31 expect(tokens, "mod");
32 let ident = expect(tokens, "inner");
33 expect(tokens, ";");
34 check_useful_span(ident, "unsafe-mod.rs");
35 TokenStream::new()
36 }
37
38 // unsafe extern {
39 // type T;
40 // }
41 #[proc_macro_attribute]
expect_unsafe_foreign_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream42 pub fn expect_unsafe_foreign_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream {
43 let tokens = &mut input.into_iter();
44 expect(tokens, "unsafe");
45 expect(tokens, "extern");
46 let tokens = &mut expect_brace(tokens);
47 expect(tokens, "type");
48 let ident = expect(tokens, "T");
49 expect(tokens, ";");
50 check_useful_span(ident, "unsafe-foreign-mod.rs");
51 TokenStream::new()
52 }
53
54 // unsafe extern "C++" {}
55 #[proc_macro_attribute]
expect_unsafe_extern_cpp_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream56 pub fn expect_unsafe_extern_cpp_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream {
57 let tokens = &mut input.into_iter();
58 expect(tokens, "unsafe");
59 expect(tokens, "extern");
60 let abi = expect(tokens, "\"C++\"");
61 expect_brace(tokens);
62 check_useful_span(abi, "unsafe-foreign-mod.rs");
63 TokenStream::new()
64 }
65
expect(tokens: &mut token_stream::IntoIter, expected: &str) -> TokenTree66 fn expect(tokens: &mut token_stream::IntoIter, expected: &str) -> TokenTree {
67 match tokens.next() {
68 Some(token) if token.to_string() == expected => token,
69 wrong => panic!("unexpected token: {:?}, expected `{}`", wrong, expected),
70 }
71 }
72
expect_brace(tokens: &mut token_stream::IntoIter) -> token_stream::IntoIter73 fn expect_brace(tokens: &mut token_stream::IntoIter) -> token_stream::IntoIter {
74 match tokens.next() {
75 Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => {
76 group.stream().into_iter()
77 }
78 wrong => panic!("unexpected token: {:?}, expected `{{`", wrong),
79 }
80 }
81
check_useful_span(token: TokenTree, expected_filename: &str)82 fn check_useful_span(token: TokenTree, expected_filename: &str) {
83 let span = token.span();
84 assert!(span.column() < span.end().column());
85
86 let source_path = span.source_file().path();
87 let filename = source_path.components().last().unwrap();
88 assert_eq!(filename, Component::Normal(expected_filename.as_ref()));
89 }
90