From fb5b7b4af2c46a2ac2117a49b3209569e7b6ddad Mon Sep 17 00:00:00 2001 From: Nika Layzell Date: Sun, 19 Jun 2022 13:56:04 -0400 Subject: [PATCH] proc_macro: Fix expand_expr expansion of bool literals Previously, the expand_expr method would expand bool literals as a `Literal` token containing a `LitKind::Bool`, rather than as an `Ident`. This is not a valid token, and the `LitKind::Bool` case needs to be handled seperately. Tests were added to more deeply compare the streams in the expand-expr test suite to catch mistakes like this in the future. --- .../rustc_expand/src/proc_macro_server.rs | 4 ++ .../ui/proc-macro/auxiliary/expand-expr.rs | 71 ++++++++++++++++++- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 1e4193a5a16cc..e5c8f1c4d9ae0 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -448,6 +448,10 @@ impl server::TokenStream for Rustc<'_, '_> { // We don't use `TokenStream::from_ast` as the tokenstream currently cannot // be recovered in the general case. match &expr.kind { + ast::ExprKind::Lit(l) if l.token.kind == token::Bool => { + Ok(tokenstream::TokenTree::token(token::Ident(l.token.symbol, false), l.span) + .into()) + } ast::ExprKind::Lit(l) => { Ok(tokenstream::TokenTree::token(token::Literal(l.token), l.span).into()) } diff --git a/src/test/ui/proc-macro/auxiliary/expand-expr.rs b/src/test/ui/proc-macro/auxiliary/expand-expr.rs index 2bc34f3c6bfc0..5463e79d74e0a 100644 --- a/src/test/ui/proc-macro/auxiliary/expand-expr.rs +++ b/src/test/ui/proc-macro/auxiliary/expand-expr.rs @@ -10,6 +10,72 @@ extern crate proc_macro; use proc_macro::*; use std::str::FromStr; +// Flatten the TokenStream, removing any toplevel `Delimiter::None`s for +// comparison. +fn flatten(ts: TokenStream) -> Vec { + ts.into_iter() + .flat_map(|tt| match &tt { + TokenTree::Group(group) if group.delimiter() == Delimiter::None => { + flatten(group.stream()) + } + _ => vec![tt], + }) + .collect() +} + +// Assert that two TokenStream values are roughly equal to one-another. +fn assert_ts_eq(lhs: &TokenStream, rhs: &TokenStream) { + let ltts = flatten(lhs.clone()); + let rtts = flatten(rhs.clone()); + + if ltts.len() != rtts.len() { + panic!( + "expected the same number of tts ({} == {})\nlhs:\n{:#?}\nrhs:\n{:#?}", + ltts.len(), + rtts.len(), + lhs, + rhs + ) + } + + for (ltt, rtt) in ltts.iter().zip(&rtts) { + match (ltt, rtt) { + (TokenTree::Group(l), TokenTree::Group(r)) => { + assert_eq!( + l.delimiter(), + r.delimiter(), + "expected delimiters to match for {:?} and {:?}", + l, + r + ); + assert_ts_eq(&l.stream(), &r.stream()); + } + (TokenTree::Punct(l), TokenTree::Punct(r)) => assert_eq!( + (l.as_char(), l.spacing()), + (r.as_char(), r.spacing()), + "expected punct to match for {:?} and {:?}", + l, + r + ), + (TokenTree::Ident(l), TokenTree::Ident(r)) => assert_eq!( + l.to_string(), + r.to_string(), + "expected ident to match for {:?} and {:?}", + l, + r + ), + (TokenTree::Literal(l), TokenTree::Literal(r)) => assert_eq!( + l.to_string(), + r.to_string(), + "expected literal to match for {:?} and {:?}", + l, + r + ), + (l, r) => panic!("expected type to match for {:?} and {:?}", l, r), + } + } +} + #[proc_macro] pub fn expand_expr_is(input: TokenStream) -> TokenStream { let mut iter = input.into_iter(); @@ -31,6 +97,9 @@ pub fn expand_expr_is(input: TokenStream) -> TokenStream { expanded.to_string() ); + // Also compare the raw tts to make sure they line up. + assert_ts_eq(&expected, &expanded); + TokenStream::new() } @@ -48,7 +117,7 @@ pub fn check_expand_expr_file(ts: TokenStream) -> TokenStream { // 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() + .unwrap() .expand_expr() .expect("expand_expr failed on internal macro") .to_string();