Skip to content

Commit e3f2d45

Browse files
committed
rollup merge of rust-lang#23872: huonw/eager-lexing
Conflicts: src/libsyntax/parse/lexer/mod.rs
2 parents acdb0f9 + 606f50c commit e3f2d45

File tree

5 files changed

+76
-16
lines changed

5 files changed

+76
-16
lines changed

src/libsyntax/parse/lexer/mod.rs

+26-14
Original file line numberDiff line numberDiff line change
@@ -620,8 +620,8 @@ impl<'a> StringReader<'a> {
620620
let base = 10;
621621

622622
// find the integer representing the name
623-
self.scan_digits(base);
624-
let encoded_name: u32 = self.with_str_from(start_bpos, |s| {
623+
self.scan_digits(base, base);
624+
let encoded_name : u32 = self.with_str_from(start_bpos, |s| {
625625
u32::from_str_radix(s, 10).unwrap_or_else(|_| {
626626
panic!("expected digits representing a name, got {:?}, {}, range [{:?},{:?}]",
627627
s, whence, start_bpos, self.last_pos);
@@ -638,7 +638,7 @@ impl<'a> StringReader<'a> {
638638

639639
// find the integer representing the ctxt
640640
let start_bpos = self.last_pos;
641-
self.scan_digits(base);
641+
self.scan_digits(base, base);
642642
let encoded_ctxt : ast::SyntaxContext = self.with_str_from(start_bpos, |s| {
643643
u32::from_str_radix(s, 10).unwrap_or_else(|_| {
644644
panic!("expected digits representing a ctxt, got {:?}, {}", s, whence);
@@ -652,16 +652,28 @@ impl<'a> StringReader<'a> {
652652
ctxt: encoded_ctxt, }
653653
}
654654

655-
/// Scan through any digits (base `radix`) or underscores, and return how
656-
/// many digits there were.
657-
fn scan_digits(&mut self, radix: u32) -> usize {
655+
/// Scan through any digits (base `scan_radix`) or underscores,
656+
/// and return how many digits there were.
657+
///
658+
/// `real_radix` represents the true radix of the number we're
659+
/// interested in, and errors will be emitted for any digits
660+
/// between `real_radix` and `scan_radix`.
661+
fn scan_digits(&mut self, real_radix: u32, scan_radix: u32) -> usize {
662+
assert!(real_radix <= scan_radix);
658663
let mut len = 0;
659664
loop {
660665
let c = self.curr;
661666
if c == Some('_') { debug!("skipping a _"); self.bump(); continue; }
662-
match c.and_then(|cc| cc.to_digit(radix)) {
667+
match c.and_then(|cc| cc.to_digit(scan_radix)) {
663668
Some(_) => {
664669
debug!("{:?} in scan_digits", c);
670+
// check that the hypothetical digit is actually
671+
// in range for the true radix
672+
if c.unwrap().to_digit(real_radix).is_none() {
673+
self.err_span_(self.last_pos, self.pos,
674+
&format!("invalid digit for a base {} literal",
675+
real_radix));
676+
}
665677
len += 1;
666678
self.bump();
667679
}
@@ -680,19 +692,19 @@ impl<'a> StringReader<'a> {
680692

681693
if c == '0' {
682694
match self.curr.unwrap_or('\0') {
683-
'b' => { self.bump(); base = 2; num_digits = self.scan_digits(2); }
684-
'o' => { self.bump(); base = 8; num_digits = self.scan_digits(8); }
685-
'x' => { self.bump(); base = 16; num_digits = self.scan_digits(16); }
695+
'b' => { self.bump(); base = 2; num_digits = self.scan_digits(2, 10); }
696+
'o' => { self.bump(); base = 8; num_digits = self.scan_digits(8, 10); }
697+
'x' => { self.bump(); base = 16; num_digits = self.scan_digits(16, 16); }
686698
'0'...'9' | '_' | '.' => {
687-
num_digits = self.scan_digits(10) + 1;
699+
num_digits = self.scan_digits(10, 10) + 1;
688700
}
689701
_ => {
690702
// just a 0
691703
return token::Integer(self.name_from(start_bpos));
692704
}
693705
}
694706
} else if c.is_digit(10) {
695-
num_digits = self.scan_digits(10) + 1;
707+
num_digits = self.scan_digits(10, 10) + 1;
696708
} else {
697709
num_digits = 0;
698710
}
@@ -711,7 +723,7 @@ impl<'a> StringReader<'a> {
711723
// with a number
712724
self.bump();
713725
if self.curr.unwrap_or('\0').is_digit(10) {
714-
self.scan_digits(10);
726+
self.scan_digits(10, 10);
715727
self.scan_float_exponent();
716728
}
717729
let last_pos = self.last_pos;
@@ -934,7 +946,7 @@ impl<'a> StringReader<'a> {
934946
if self.curr_is('-') || self.curr_is('+') {
935947
self.bump();
936948
}
937-
if self.scan_digits(10) == 0 {
949+
if self.scan_digits(10, 10) == 0 {
938950
self.err_span_(self.last_pos, self.pos, "expected at least one digit in exponent")
939951
}
940952
}

src/libsyntax/parse/mod.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,20 @@ pub fn integer_lit(s: &str, suffix: Option<&str>, sd: &SpanHandler, sp: Span) ->
736736

737737
let res = match u64::from_str_radix(s, base).ok() {
738738
Some(r) => r,
739-
None => { sd.span_err(sp, "int literal is too large"); 0 }
739+
None => {
740+
// small bases are lexed as if they were base 10, e.g, the string
741+
// might be `0b10201`. This will cause the conversion above to fail,
742+
// but these cases have errors in the lexer: we don't want to emit
743+
// two errors, and we especially don't want to emit this error since
744+
// it isn't necessarily true.
745+
let already_errored = base < 10 &&
746+
s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base));
747+
748+
if !already_errored {
749+
sd.span_err(sp, "int literal is too large");
750+
}
751+
0
752+
}
740753
};
741754

742755
// adjust the sign

src/test/parse-fail/issue-1802-1.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010

1111
// error-pattern:no valid digits found for number
1212
fn main() {
13-
log(error, 0b42);
13+
log(error, 0b);
1414
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2014 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+
fn main() {
12+
0b121; //~ ERROR invalid digit for a base 2 literal
13+
0b10_10301; //~ ERROR invalid digit for a base 2 literal
14+
0b30; //~ ERROR invalid digit for a base 2 literal
15+
0b41; //~ ERROR invalid digit for a base 2 literal
16+
0b5; //~ ERROR invalid digit for a base 2 literal
17+
0b6; //~ ERROR invalid digit for a base 2 literal
18+
0b7; //~ ERROR invalid digit for a base 2 literal
19+
0b8; //~ ERROR invalid digit for a base 2 literal
20+
0b9; //~ ERROR invalid digit for a base 2 literal
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2014 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+
fn main() {
12+
0o18; //~ ERROR invalid digit for a base 8 literal
13+
0o1234_9_5670; //~ ERROR invalid digit for a base 8 literal
14+
}

0 commit comments

Comments
 (0)