summary refs log tree commit diff
path: root/src/test/ui/proc-macro/auxiliary/expand-expr.rs
blob: 2bc34f3c6bfc072a427d6041e3249ce4faa41117 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// force-host
// no-prefer-dynamic

#![crate_type = "proc-macro"]
#![deny(warnings)]
#![feature(proc_macro_expand, proc_macro_span)]

extern crate proc_macro;

use proc_macro::*;
use std::str::FromStr;

#[proc_macro]
pub fn expand_expr_is(input: TokenStream) -> TokenStream {
    let mut iter = input.into_iter();
    let mut expected_tts = Vec::new();
    loop {
        match iter.next() {
            Some(TokenTree::Punct(ref p)) if p.as_char() == ',' => break,
            Some(tt) => expected_tts.push(tt),
            None => panic!("expected comma"),
        }
    }

    let expected = expected_tts.into_iter().collect::<TokenStream>();
    let expanded = iter.collect::<TokenStream>().expand_expr().expect("expand_expr failed");
    assert!(
        expected.to_string() == expanded.to_string(),
        "assert failed\nexpected: `{}`\nexpanded: `{}`",
        expected.to_string(),
        expanded.to_string()
    );

    TokenStream::new()
}

#[proc_macro]
pub fn expand_expr_fail(input: TokenStream) -> TokenStream {
    match input.expand_expr() {
        Ok(ts) => panic!("expand_expr unexpectedly succeeded: `{}`", ts),
        Err(_) => TokenStream::new(),
    }
}

#[proc_macro]
pub fn check_expand_expr_file(ts: TokenStream) -> TokenStream {
    // Check that the passed in `file!()` invocation and a parsed `file!`
    // invocation expand to the same literal.
    let input_t = ts.expand_expr().expect("expand_expr failed on macro input").to_string();
    let parse_t = TokenStream::from_str("file!{}")
    .unwrap()
        .expand_expr()
        .expect("expand_expr failed on internal macro")
        .to_string();
    assert_eq!(input_t, parse_t);

    // Check that the literal matches `Span::call_site().source_file().path()`
    let expect_t =
        Literal::string(&Span::call_site().source_file().path().to_string_lossy()).to_string();
    assert_eq!(input_t, expect_t);

    TokenStream::new()
}

#[proc_macro]
pub fn recursive_expand(_: TokenStream) -> TokenStream {
    // Recursively call until we hit the recursion limit and get an error.
    //
    // NOTE: This doesn't panic if expansion fails because that'll cause a very
    // large number of errors to fill the output.
    TokenStream::from_str("recursive_expand!{}")
        .unwrap()
        .expand_expr()
        .unwrap_or(std::iter::once(TokenTree::Literal(Literal::u32_suffixed(0))).collect())
}

#[proc_macro]
pub fn echo_pm(input: TokenStream) -> TokenStream {
    input
}