about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2019-03-02 10:38:20 -0800
committerEsteban Küber <esteban@kuber.com.ar>2019-03-08 16:56:31 -0800
commit0a505a71d3b8d61e982b305caf6d39c227c05957 (patch)
treeae9b56e65d089bcfdee6db0f5620213863f75d9d
parent2a65cbeea78c2c79b1030a0012cdea475104a44f (diff)
downloadrust-0a505a71d3b8d61e982b305caf6d39c227c05957.tar.gz
rust-0a505a71d3b8d61e982b305caf6d39c227c05957.zip
Parse lifetimes that start with a number and give specific error
-rw-r--r--src/libsyntax/parse/lexer/mod.rs24
-rw-r--r--src/test/ui/parser/numeric-lifetime.rs8
-rw-r--r--src/test/ui/parser/numeric-lifetime.stderr24
3 files changed, 50 insertions, 6 deletions
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index a7cde5fbb92..f45f5e65312 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -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))
 
@@ -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));
                 }
 
@@ -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 {
@@ -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]
diff --git a/src/test/ui/parser/numeric-lifetime.rs b/src/test/ui/parser/numeric-lifetime.rs
new file mode 100644
index 00000000000..3483975a3cb
--- /dev/null
+++ b/src/test/ui/parser/numeric-lifetime.rs
@@ -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
+}
diff --git a/src/test/ui/parser/numeric-lifetime.stderr b/src/test/ui/parser/numeric-lifetime.stderr
new file mode 100644
index 00000000000..1bbc508d57d
--- /dev/null
+++ b/src/test/ui/parser/numeric-lifetime.stderr
@@ -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`.