Skip to content

Commit 55ff45a

Browse files
committed
Support negative numbers in Literal::from_str
1 parent 331da58 commit 55ff45a

File tree

3 files changed

+56
-22
lines changed

3 files changed

+56
-22
lines changed

compiler/rustc_expand/src/proc_macro_server.rs

+41-22
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::base::{ExtCtxt, ResolverExpand};
22

33
use rustc_ast as ast;
4-
use rustc_ast::token::{self, Nonterminal, NtIdent, TokenKind};
4+
use rustc_ast::token::{self, Nonterminal, NtIdent};
55
use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens};
66
use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
77
use rustc_ast_pretty::pprust;
@@ -537,30 +537,49 @@ impl server::Ident for Rustc<'_> {
537537

538538
impl server::Literal for Rustc<'_> {
539539
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(()),
554550
};
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() {
558555
return Err(());
559556
}
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+
564583
Ok(Literal { lit, span: self.call_site })
565584
}
566585
fn debug_kind(&mut self, literal: &Self::Literal) -> String {

compiler/rustc_span/src/symbol.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,10 @@ impl Symbol {
15881588
self.0.as_u32()
15891589
}
15901590

1591+
pub fn len(self) -> usize {
1592+
with_interner(|interner| interner.get(self).len())
1593+
}
1594+
15911595
pub fn is_empty(self) -> bool {
15921596
self == kw::Empty
15931597
}

src/test/ui/proc-macro/auxiliary/api/parse.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
use proc_macro::Literal;
22

33
pub fn test() {
4+
test_display_literal();
45
test_parse_literal();
56
}
67

8+
fn test_display_literal() {
9+
assert_eq!(Literal::isize_unsuffixed(-10).to_string(), "- 10");
10+
assert_eq!(Literal::isize_suffixed(-10).to_string(), "- 10isize");
11+
}
12+
713
fn test_parse_literal() {
814
assert_eq!("1".parse::<Literal>().unwrap().to_string(), "1");
915
assert_eq!("1.0".parse::<Literal>().unwrap().to_string(), "1.0");
@@ -12,12 +18,17 @@ fn test_parse_literal() {
1218
assert_eq!("b\"\"".parse::<Literal>().unwrap().to_string(), "b\"\"");
1319
assert_eq!("r##\"\"##".parse::<Literal>().unwrap().to_string(), "r##\"\"##");
1420
assert_eq!("10ulong".parse::<Literal>().unwrap().to_string(), "10ulong");
21+
assert_eq!("-10ulong".parse::<Literal>().unwrap().to_string(), "- 10ulong");
1522

23+
assert!("true".parse::<Literal>().is_err());
24+
assert!(".8".parse::<Literal>().is_err());
1625
assert!("0 1".parse::<Literal>().is_err());
1726
assert!("'a".parse::<Literal>().is_err());
1827
assert!(" 0".parse::<Literal>().is_err());
1928
assert!("0 ".parse::<Literal>().is_err());
2029
assert!("/* comment */0".parse::<Literal>().is_err());
2130
assert!("0/* comment */".parse::<Literal>().is_err());
2231
assert!("0// comment".parse::<Literal>().is_err());
32+
assert!("- 10".parse::<Literal>().is_err());
33+
assert!("-'x'".parse::<Literal>().is_err());
2334
}

0 commit comments

Comments
 (0)