Skip to content

Commit 208d23a

Browse files
committed
Auto merge of #41961 - kennytm:fix-35829, r=petrochenkov
Fix #35829 (`quote!()` does not handle `br#"…"#`) Fix issue #35829 (syntax extension's `quote_expr!()` does not handle `b"…"` and proc_macro's `quote!()` does not handle `r#"…"#`) * Handles `b"…"`, `br#"…"#` and `...` for `quote_expr!()`. * Refactored the match statement to allow it to complain loudly on any unhandled token. * Similarly, proc_macro's `quote!()` did not handle `br#"…"#` or `r#"…"#`, so this PR fixes it too.
2 parents 42e3732 + 115854e commit 208d23a

File tree

4 files changed

+103
-41
lines changed

4 files changed

+103
-41
lines changed

src/libproc_macro_plugin/quote.rs

+13-3
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,14 @@ impl<'a> Quote for &'a str {
133133
}
134134
}
135135

136+
impl Quote for usize {
137+
fn quote(&self) -> TokenStream {
138+
let integer_symbol = Symbol::intern(&self.to_string());
139+
TokenTree::Token(DUMMY_SP, Token::Literal(token::Lit::Integer(integer_symbol), None))
140+
.into()
141+
}
142+
}
143+
136144
impl Quote for Ident {
137145
fn quote(&self) -> TokenStream {
138146
// FIXME(jseyfried) quote hygiene
@@ -193,15 +201,17 @@ impl Quote for token::BinOpToken {
193201
impl Quote for Lit {
194202
fn quote(&self) -> TokenStream {
195203
macro_rules! gen_match {
196-
($($i:ident),*) => {
204+
($($i:ident),*; $($raw:ident),*) => {
197205
match *self {
198206
$( Lit::$i(lit) => quote!(::syntax::parse::token::Lit::$i((quote lit))), )*
199-
_ => panic!("Unsupported literal"),
207+
$( Lit::$raw(lit, n) => {
208+
quote!(::syntax::parse::token::Lit::$raw((quote lit), (quote n)))
209+
})*
200210
}
201211
}
202212
}
203213

204-
gen_match!(Byte, Char, Float, Str_, Integer, ByteStr)
214+
gen_match!(Byte, Char, Float, Str_, Integer, ByteStr; StrRaw, ByteStrRaw)
205215
}
206216
}
207217

src/libsyntax/ext/quote.rs

+20-36
Original file line numberDiff line numberDiff line change
@@ -612,16 +612,20 @@ fn mk_delim(cx: &ExtCtxt, sp: Span, delim: token::DelimToken) -> P<ast::Expr> {
612612
#[allow(non_upper_case_globals)]
613613
fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
614614
macro_rules! mk_lit {
615-
($name: expr, $suffix: expr, $($args: expr),*) => {{
616-
let inner = cx.expr_call(sp, mk_token_path(cx, sp, $name), vec![$($args),*]);
615+
($name: expr, $suffix: expr, $content: expr $(, $count: expr)*) => {{
616+
let name = mk_name(cx, sp, ast::Ident::with_empty_ctxt($content));
617+
let inner = cx.expr_call(sp, mk_token_path(cx, sp, $name), vec![
618+
name $(, cx.expr_usize(sp, $count))*
619+
]);
617620
let suffix = match $suffix {
618621
Some(name) => cx.expr_some(sp, mk_name(cx, sp, ast::Ident::with_empty_ctxt(name))),
619622
None => cx.expr_none(sp)
620623
};
621624
cx.expr_call(sp, mk_token_path(cx, sp, "Literal"), vec![inner, suffix])
622625
}}
623626
}
624-
match *tok {
627+
628+
let name = match *tok {
625629
token::BinOp(binop) => {
626630
return cx.expr_call(sp, mk_token_path(cx, sp, "BinOp"), vec![mk_binop(cx, sp, binop)]);
627631
}
@@ -639,34 +643,14 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
639643
vec![mk_delim(cx, sp, delim)]);
640644
}
641645

642-
token::Literal(token::Byte(i), suf) => {
643-
let e_byte = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i));
644-
return mk_lit!("Byte", suf, e_byte);
645-
}
646-
647-
token::Literal(token::Char(i), suf) => {
648-
let e_char = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i));
649-
return mk_lit!("Char", suf, e_char);
650-
}
651-
652-
token::Literal(token::Integer(i), suf) => {
653-
let e_int = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i));
654-
return mk_lit!("Integer", suf, e_int);
655-
}
656-
657-
token::Literal(token::Float(fident), suf) => {
658-
let e_fident = mk_name(cx, sp, ast::Ident::with_empty_ctxt(fident));
659-
return mk_lit!("Float", suf, e_fident);
660-
}
661-
662-
token::Literal(token::Str_(ident), suf) => {
663-
return mk_lit!("Str_", suf, mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident)))
664-
}
665-
666-
token::Literal(token::StrRaw(ident, n), suf) => {
667-
return mk_lit!("StrRaw", suf, mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident)),
668-
cx.expr_usize(sp, n))
669-
}
646+
token::Literal(token::Byte(i), suf) => return mk_lit!("Byte", suf, i),
647+
token::Literal(token::Char(i), suf) => return mk_lit!("Char", suf, i),
648+
token::Literal(token::Integer(i), suf) => return mk_lit!("Integer", suf, i),
649+
token::Literal(token::Float(i), suf) => return mk_lit!("Float", suf, i),
650+
token::Literal(token::Str_(i), suf) => return mk_lit!("Str_", suf, i),
651+
token::Literal(token::StrRaw(i, n), suf) => return mk_lit!("StrRaw", suf, i, n),
652+
token::Literal(token::ByteStr(i), suf) => return mk_lit!("ByteStr", suf, i),
653+
token::Literal(token::ByteStrRaw(i, n), suf) => return mk_lit!("ByteStrRaw", suf, i, n),
670654

671655
token::Ident(ident) => {
672656
return cx.expr_call(sp,
@@ -688,10 +672,6 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
688672

689673
token::Interpolated(_) => panic!("quote! with interpolated token"),
690674

691-
_ => ()
692-
}
693-
694-
let name = match *tok {
695675
token::Eq => "Eq",
696676
token::Lt => "Lt",
697677
token::Le => "Le",
@@ -706,6 +686,7 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
706686
token::At => "At",
707687
token::Dot => "Dot",
708688
token::DotDot => "DotDot",
689+
token::DotDotDot => "DotDotDot",
709690
token::Comma => "Comma",
710691
token::Semi => "Semi",
711692
token::Colon => "Colon",
@@ -718,7 +699,10 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
718699
token::Question => "Question",
719700
token::Underscore => "Underscore",
720701
token::Eof => "Eof",
721-
_ => panic!("unhandled token in quote!"),
702+
703+
token::Whitespace | token::SubstNt(_) | token::Comment | token::Shebang(_) => {
704+
panic!("unhandled token in quote!");
705+
}
722706
};
723707
mk_token_path(cx, sp, name)
724708
}
+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// ignore-stage1
12+
// ignore-cross-compile
13+
#![feature(quote, rustc_private)]
14+
15+
extern crate syntax;
16+
17+
use syntax::ext::base::{ExtCtxt, DummyResolver};
18+
use syntax::ext::expand::ExpansionConfig;
19+
use syntax::parse::ParseSess;
20+
use syntax::codemap::{FilePathMapping, dummy_spanned};
21+
use syntax::print::pprust::expr_to_string;
22+
use syntax::ast::{Expr, ExprKind, LitKind, StrStyle, RangeLimits};
23+
use syntax::symbol::Symbol;
24+
use syntax::ptr::P;
25+
26+
use std::rc::Rc;
27+
28+
fn main() {
29+
let parse_sess = ParseSess::new(FilePathMapping::empty());
30+
let exp_cfg = ExpansionConfig::default("issue_35829".to_owned());
31+
let mut resolver = DummyResolver;
32+
let cx = ExtCtxt::new(&parse_sess, exp_cfg, &mut resolver);
33+
34+
// check byte string
35+
let byte_string = quote_expr!(&cx, b"one");
36+
let byte_string_lit_kind = LitKind::ByteStr(Rc::new(b"one".to_vec()));
37+
assert_eq!(byte_string.node, ExprKind::Lit(P(dummy_spanned(byte_string_lit_kind))));
38+
39+
// check raw byte string
40+
let raw_byte_string = quote_expr!(&cx, br###"#"two"#"###);
41+
let raw_byte_string_lit_kind = LitKind::ByteStr(Rc::new(b"#\"two\"#".to_vec()));
42+
assert_eq!(raw_byte_string.node, ExprKind::Lit(P(dummy_spanned(raw_byte_string_lit_kind))));
43+
44+
// check dotdotdot
45+
let closed_range = quote_expr!(&cx, 0 ... 1);
46+
assert_eq!(closed_range.node, ExprKind::Range(
47+
Some(quote_expr!(&cx, 0)),
48+
Some(quote_expr!(&cx, 1)),
49+
RangeLimits::Closed
50+
));
51+
52+
// test case from 35829
53+
let expr_35829 = quote_expr!(&cx, std::io::stdout().write(b"one"));
54+
assert_eq!(expr_to_string(&expr_35829), r#"std::io::stdout().write(b"one")"#);
55+
}

src/test/run-pass-fulldeps/macro-quote-1.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,24 @@
1717
extern crate syntax;
1818
extern crate syntax_pos;
1919

20-
use syntax::ast::Ident;
21-
use syntax::parse::token;
20+
use syntax::ast::{Ident, Name};
21+
use syntax::parse::token::{self, Token, Lit};
2222
use syntax::tokenstream::TokenTree;
2323

2424
fn main() {
2525
let true_tok = token::Ident(Ident::from_str("true"));
2626
assert!(quote!(true).eq_unspanned(&true_tok.into()));
27+
28+
// issue #35829, extended check to proc_macro.
29+
let triple_dot_tok = Token::DotDotDot;
30+
assert!(quote!(...).eq_unspanned(&triple_dot_tok.into()));
31+
32+
let byte_str_tok = Token::Literal(Lit::ByteStr(Name::intern("one")), None);
33+
assert!(quote!(b"one").eq_unspanned(&byte_str_tok.into()));
34+
35+
let byte_str_raw_tok = Token::Literal(Lit::ByteStrRaw(Name::intern("#\"two\"#"), 3), None);
36+
assert!(quote!(br###"#"two"#"###).eq_unspanned(&byte_str_raw_tok.into()));
37+
38+
let str_raw_tok = Token::Literal(Lit::StrRaw(Name::intern("#\"three\"#"), 2), None);
39+
assert!(quote!(r##"#"three"#"##).eq_unspanned(&str_raw_tok.into()));
2740
}

0 commit comments

Comments
 (0)