|
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