Skip to content

Commit

Permalink
Parse lifetimes that start with a number and give specific error
Browse files Browse the repository at this point in the history
  • Loading branch information
estebank committed Mar 9, 2019
1 parent 2a65cbe commit 0a505a7
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 6 deletions.
24 changes: 18 additions & 6 deletions src/libsyntax/parse/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1423,15 +1423,17 @@ impl<'a> StringReader<'a> {

// If the character is an ident start not followed by another single
// quote, then this is a lifetime name:
if ident_start(Some(c2)) && !self.ch_is('\'') {
if (ident_start(Some(c2)) || c2.is_numeric()) && !self.ch_is('\'') {
while ident_continue(self.ch) {
self.bump();
}
// lifetimes shouldn't end with a single quote
// if we find one, then this is an invalid character literal
if self.ch_is('\'') {
self.err_span_(start_with_quote, self.next_pos,
"character literal may only contain one codepoint");
self.err_span_(
start_with_quote,
self.next_pos,
"character literal may only contain one codepoint");
self.bump();
return Ok(token::Literal(token::Err(Symbol::intern("??")), None))

Expand All @@ -1444,6 +1446,16 @@ impl<'a> StringReader<'a> {
self.mk_ident(&format!("'{}", lifetime_name))
});

if c2.is_numeric() {
// this is a recovered lifetime written `'1`, error but accept it
self.err_span_(
start_with_quote,
self.pos,
"lifetimes can't start with a number",
);
}


return Ok(token::Lifetime(ident));
}

Expand Down Expand Up @@ -1873,13 +1885,14 @@ fn is_block_doc_comment(s: &str) -> bool {
res
}

/// Determine whether `c` is a valid start for an ident.
fn ident_start(c: Option<char>) -> bool {
let c = match c {
Some(c) => c,
None => return false,
};

(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c > '\x7f' && c.is_xid_start())
(c.is_alphabetic() || c == '_' || (c > '\x7f' && c.is_xid_start()))
}

fn ident_continue(c: Option<char>) -> bool {
Expand All @@ -1888,8 +1901,7 @@ fn ident_continue(c: Option<char>) -> bool {
None => return false,
};

(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' ||
(c > '\x7f' && c.is_xid_continue())
(c.is_alphabetic() || c.is_numeric() || c == '_' || (c > '\x7f' && c.is_xid_continue()))
}

#[inline]
Expand Down
8 changes: 8 additions & 0 deletions src/test/ui/parser/numeric-lifetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
struct S<'1> { s: &'1 usize }
//~^ ERROR lifetimes can't start with a number
//~| ERROR lifetimes can't start with a number
fn main() {
// verify that the parse error doesn't stop type checking
let x: usize = "";
//~^ ERROR mismatched types
}
24 changes: 24 additions & 0 deletions src/test/ui/parser/numeric-lifetime.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
error: lifetimes can't start with a number
--> $DIR/numeric-lifetime.rs:1:10
|
LL | struct S<'1> { s: &'1 usize }
| ^^

error: lifetimes can't start with a number
--> $DIR/numeric-lifetime.rs:1:20
|
LL | struct S<'1> { s: &'1 usize }
| ^^

error[E0308]: mismatched types
--> $DIR/numeric-lifetime.rs:6:20
|
LL | let x: usize = "";
| ^^ expected usize, found reference
|
= note: expected type `usize`
found type `&'static str`

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0308`.

0 comments on commit 0a505a7

Please sign in to comment.