|
1 | 1 | use crate::base::{ExtCtxt, ResolverExpand}; |
2 | 2 |
|
3 | 3 | use rustc_ast as ast; |
4 | | -use rustc_ast::token::{self, Nonterminal, NtIdent, TokenKind}; |
| 4 | +use rustc_ast::token::{self, Nonterminal, NtIdent}; |
5 | 5 | use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens}; |
6 | 6 | use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing}; |
7 | 7 | use rustc_ast_pretty::pprust; |
@@ -537,30 +537,49 @@ impl server::Ident for Rustc<'_> { |
537 | 537 |
|
538 | 538 | impl server::Literal for Rustc<'_> { |
539 | 539 | fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> { |
540 | | - let override_span = None; |
541 | | - let stream = parse_stream_from_source_str( |
542 | | - FileName::proc_macro_source_code(s), |
543 | | - s.to_owned(), |
544 | | - self.sess, |
545 | | - override_span, |
546 | | - ); |
547 | | - if stream.len() != 1 { |
548 | | - return Err(()); |
549 | | - } |
550 | | - let tree = stream.into_trees().next().unwrap(); |
551 | | - let token = match tree { |
552 | | - tokenstream::TokenTree::Token(token) => token, |
553 | | - tokenstream::TokenTree::Delimited { .. } => return Err(()), |
| 540 | + let name = FileName::proc_macro_source_code(s); |
| 541 | + let mut parser = rustc_parse::new_parser_from_source_str(self.sess, name, s.to_owned()); |
| 542 | + |
| 543 | + let first_span = parser.token.span.data(); |
| 544 | + let minus_present = parser.eat(&token::BinOp(token::Minus)); |
| 545 | + |
| 546 | + let lit_span = parser.token.span.data(); |
| 547 | + let mut lit = match parser.token.kind { |
| 548 | + token::Literal(lit) => lit, |
| 549 | + _ => return Err(()), |
554 | 550 | }; |
555 | | - let span_data = token.span.data(); |
556 | | - if (span_data.hi.0 - span_data.lo.0) as usize != s.len() { |
557 | | - // There is a comment or whitespace adjacent to the literal. |
| 551 | + |
| 552 | + // Check no comment or whitespace surrounding the (possibly negative) |
| 553 | + // literal, or more tokens after it. |
| 554 | + if (lit_span.hi.0 - first_span.lo.0) as usize != s.len() { |
558 | 555 | return Err(()); |
559 | 556 | } |
560 | | - let lit = match token.kind { |
561 | | - TokenKind::Literal(lit) => lit, |
562 | | - _ => return Err(()), |
563 | | - }; |
| 557 | + |
| 558 | + if minus_present { |
| 559 | + // If minus is present, check no comment or whitespace in between it |
| 560 | + // and the literal token. |
| 561 | + if first_span.hi.0 != lit_span.lo.0 { |
| 562 | + return Err(()); |
| 563 | + } |
| 564 | + |
| 565 | + // Check literal is a kind we allow to be negated in a proc macro token. |
| 566 | + match lit.kind { |
| 567 | + token::LitKind::Bool |
| 568 | + | token::LitKind::Byte |
| 569 | + | token::LitKind::Char |
| 570 | + | token::LitKind::Str |
| 571 | + | token::LitKind::StrRaw(_) |
| 572 | + | token::LitKind::ByteStr |
| 573 | + | token::LitKind::ByteStrRaw(_) |
| 574 | + | token::LitKind::Err => return Err(()), |
| 575 | + token::LitKind::Integer | token::LitKind::Float => {} |
| 576 | + } |
| 577 | + |
| 578 | + // Synthesize a new symbol that includes the minus sign. |
| 579 | + let symbol = Symbol::intern(&s[..1 + lit.symbol.len()]); |
| 580 | + lit = token::Lit::new(lit.kind, symbol, lit.suffix); |
| 581 | + } |
| 582 | + |
564 | 583 | Ok(Literal { lit, span: self.call_site }) |
565 | 584 | } |
566 | 585 | fn debug_kind(&mut self, literal: &Self::Literal) -> String { |
|
0 commit comments