90 lines
2.9 KiB
Rust
90 lines
2.9 KiB
Rust
|
// 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.start().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()));
|
||
|
}
|