• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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