Tweak path parsing logic
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 2509fd1..463ec33 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3620,7 +3620,7 @@
// Parse box pat
let subpat = self.parse_pat()?;
pat = PatKind::Box(subpat);
- } else if self.token.is_ident() && self.token.is_path_start() &&
+ } else if self.token.is_ident() && !self.token.is_any_keyword() &&
self.look_ahead(1, |t| match *t {
token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) |
token::DotDotDot | token::ModSep | token::Not => false,
@@ -3871,6 +3871,11 @@
})
}
+ fn is_union_item(&mut self) -> bool {
+ self.token.is_keyword(keywords::Union) &&
+ self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword())
+ }
+
fn parse_stmt_without_recovery(&mut self,
macro_legacy_warnings: bool)
-> PResult<'a, Option<Stmt>> {
@@ -3885,10 +3890,10 @@
node: StmtKind::Local(self.parse_local(attrs.into())?),
span: mk_sp(lo, self.prev_span.hi),
}
- } else if self.token.is_path_start() && self.token != token::Lt && {
- !self.check_keyword(keywords::Union) ||
- self.look_ahead(1, |t| *t == token::Not || *t == token::ModSep)
- } {
+ // Starts like a simple path, but not a union item.
+ } else if self.token.is_path_start() &&
+ !self.token.is_qpath_start() &&
+ !self.is_union_item() {
let pth = self.parse_path(PathStyle::Expr)?;
if !self.eat(&token::Not) {
@@ -4599,6 +4604,10 @@
token::Ident(ident) => { this.bump(); codemap::respan(this.prev_span, ident) }
_ => unreachable!()
};
+ let isolated_self = |this: &mut Self, n| {
+ this.look_ahead(n, |t| t.is_keyword(keywords::SelfValue)) &&
+ this.look_ahead(n + 1, |t| t != &token::ModSep)
+ };
// Parse optional self parameter of a method.
// Only a limited set of initial token sequences is considered self parameters, anything
@@ -4611,22 +4620,22 @@
// &'lt self
// &'lt mut self
// ¬_self
- if self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) {
+ if isolated_self(self, 1) {
self.bump();
(SelfKind::Region(None, Mutability::Immutable), expect_ident(self))
} else if self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) &&
- self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) {
+ isolated_self(self, 2) {
self.bump();
self.bump();
(SelfKind::Region(None, Mutability::Mutable), expect_ident(self))
} else if self.look_ahead(1, |t| t.is_lifetime()) &&
- self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) {
+ isolated_self(self, 2) {
self.bump();
let lt = self.parse_lifetime()?;
(SelfKind::Region(Some(lt), Mutability::Immutable), expect_ident(self))
} else if self.look_ahead(1, |t| t.is_lifetime()) &&
self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) &&
- self.look_ahead(3, |t| t.is_keyword(keywords::SelfValue)) {
+ isolated_self(self, 3) {
self.bump();
let lt = self.parse_lifetime()?;
self.bump();
@@ -4641,12 +4650,12 @@
// *mut self
// *not_self
// Emit special error for `self` cases.
- if self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) {
+ if isolated_self(self, 1) {
self.bump();
self.span_err(self.span, "cannot pass `self` by raw pointer");
(SelfKind::Value(Mutability::Immutable), expect_ident(self))
} else if self.look_ahead(1, |t| t.is_mutability()) &&
- self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) {
+ isolated_self(self, 2) {
self.bump();
self.bump();
self.span_err(self.span, "cannot pass `self` by raw pointer");
@@ -4656,7 +4665,7 @@
}
}
token::Ident(..) => {
- if self.token.is_keyword(keywords::SelfValue) {
+ if isolated_self(self, 0) {
// self
// self: TYPE
let eself_ident = expect_ident(self);
@@ -4667,7 +4676,7 @@
(SelfKind::Value(Mutability::Immutable), eself_ident)
}
} else if self.token.is_keyword(keywords::Mut) &&
- self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) {
+ isolated_self(self, 1) {
// mut self
// mut self: TYPE
self.bump();
@@ -5958,8 +5967,7 @@
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
}
- if self.check_keyword(keywords::Union) &&
- self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) {
+ if self.is_union_item() {
// UNION ITEM
self.bump();
let (ident, item_, extra_attrs) = self.parse_item_union()?;
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 26b5b99..4d0da66 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -159,10 +159,8 @@
/// Returns `true` if the token can appear at the start of an expression.
pub fn can_begin_expr(&self) -> bool {
match *self {
- OpenDelim(_) => true,
+ OpenDelim(..) => true,
Ident(..) => true,
- Underscore => true,
- Tilde => true,
Literal(..) => true,
Not => true,
BinOp(Minus) => true,
@@ -172,6 +170,7 @@
OrOr => true, // in lambda syntax
AndAnd => true, // double borrow
DotDot | DotDotDot => true, // range notation
+ Lt | BinOp(Shl) => true, // associated path
ModSep => true,
Interpolated(NtExpr(..)) => true,
Interpolated(NtIdent(..)) => true,
@@ -236,8 +235,12 @@
self.is_keyword(keywords::Const)
}
+ pub fn is_qpath_start(&self) -> bool {
+ self == &Lt || self == &BinOp(Shl)
+ }
+
pub fn is_path_start(&self) -> bool {
- self == &ModSep || self == &Lt || self.is_path() ||
+ self == &ModSep || self.is_qpath_start() || self.is_path() ||
self.is_path_segment_keyword() || self.is_ident() && !self.is_any_keyword()
}
diff --git a/src/test/compile-fail/associated-path-shl.rs b/src/test/compile-fail/associated-path-shl.rs
new file mode 100644
index 0000000..6bc1102
--- /dev/null
+++ b/src/test/compile-fail/associated-path-shl.rs
@@ -0,0 +1,20 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that associated paths starting with `<<` are successfully parsed.
+
+fn main() {
+ let _: <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
+ let _ = <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
+ let <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
+ let 0 ... <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
+ //~^ ERROR only char and numeric types are allowed in range patterns
+ <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
+}
diff --git a/src/test/parse-fail/keyword-super-as-identifier.rs b/src/test/compile-fail/keyword-self-as-identifier.rs
similarity index 81%
copy from src/test/parse-fail/keyword-super-as-identifier.rs
copy to src/test/compile-fail/keyword-self-as-identifier.rs
index a48683a..6508747 100644
--- a/src/test/parse-fail/keyword-super-as-identifier.rs
+++ b/src/test/compile-fail/keyword-self-as-identifier.rs
@@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags: -Z parse-only
-
fn main() {
- let super = "foo"; //~ error: expected identifier, found keyword `super`
+ let Self = "foo"; //~ ERROR unresolved unit struct/variant or constant `Self`
}
diff --git a/src/test/parse-fail/keyword-super-as-identifier.rs b/src/test/compile-fail/keyword-super-as-identifier.rs
similarity index 81%
rename from src/test/parse-fail/keyword-super-as-identifier.rs
rename to src/test/compile-fail/keyword-super-as-identifier.rs
index a48683a..5317055 100644
--- a/src/test/parse-fail/keyword-super-as-identifier.rs
+++ b/src/test/compile-fail/keyword-super-as-identifier.rs
@@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags: -Z parse-only
-
fn main() {
- let super = "foo"; //~ error: expected identifier, found keyword `super`
+ let super = "foo"; //~ ERROR unresolved unit struct/variant or constant `super`
}
diff --git a/src/test/parse-fail/keyword-super.rs b/src/test/compile-fail/keyword-super.rs
similarity index 81%
rename from src/test/parse-fail/keyword-super.rs
rename to src/test/compile-fail/keyword-super.rs
index 671be8c..9ac9e80 100644
--- a/src/test/parse-fail/keyword-super.rs
+++ b/src/test/compile-fail/keyword-super.rs
@@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags: -Z parse-only
-
fn main() {
- let super: isize; //~ ERROR expected identifier, found keyword `super`
+ let super: isize; //~ ERROR unresolved unit struct/variant or constant `super`
}
diff --git a/src/test/compile-fail/self-vs-path-ambiguity.rs b/src/test/compile-fail/self-vs-path-ambiguity.rs
new file mode 100644
index 0000000..9753014
--- /dev/null
+++ b/src/test/compile-fail/self-vs-path-ambiguity.rs
@@ -0,0 +1,23 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that `self::foo` is parsed as a general pattern and not a self argument.
+
+struct S;
+
+impl S {
+ fn f(self::S: S) {}
+ fn g(&self::S: &S) {}
+ fn h(&mut self::S: &mut S) {}
+ fn i(&'a self::S: &S) {} //~ ERROR unexpected lifetime `'a` in pattern
+ //~^ ERROR expected one of `)` or `mut`, found `'a`
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/self_type_keyword-2.rs b/src/test/compile-fail/self_type_keyword-2.rs
index 613f54e..118d3d8 100644
--- a/src/test/compile-fail/self_type_keyword-2.rs
+++ b/src/test/compile-fail/self_type_keyword-2.rs
@@ -10,4 +10,14 @@
use self::Self as Foo; //~ ERROR unresolved import `self::Self`
-pub fn main() {}
+pub fn main() {
+ let Self = 5;
+ //~^ ERROR unresolved unit struct/variant or constant `Self`
+
+ match 15 {
+ Self => (),
+ //~^ ERROR unresolved unit struct/variant or constant `Self`
+ Foo { x: Self } => (),
+ //~^ ERROR unresolved unit struct/variant or constant `Self`
+ }
+}
diff --git a/src/test/compile-fail/self_type_keyword.rs b/src/test/compile-fail/self_type_keyword.rs
index 0f2a3f1..db6bcc6 100644
--- a/src/test/compile-fail/self_type_keyword.rs
+++ b/src/test/compile-fail/self_type_keyword.rs
@@ -17,12 +17,7 @@
//~^ ERROR lifetimes cannot use keyword names
pub fn main() {
- let Self = 5;
- //~^ ERROR expected identifier, found keyword `Self`
-
match 15 {
- Self => (),
- //~^ ERROR expected identifier, found keyword `Self`
ref Self => (),
//~^ ERROR expected identifier, found keyword `Self`
mut Self => (),
@@ -31,8 +26,6 @@
//~^ ERROR expected identifier, found keyword `Self`
Self!() => (),
//~^ ERROR macro undefined: 'Self!'
- Foo { x: Self } => (),
- //~^ ERROR expected identifier, found keyword `Self`
Foo { Self } => (),
//~^ ERROR expected identifier, found keyword `Self`
}
diff --git a/src/test/parse-fail/keyword-self-as-identifier.rs b/src/test/parse-fail/keyword-self-as-identifier.rs
deleted file mode 100644
index f8b93a1..0000000
--- a/src/test/parse-fail/keyword-self-as-identifier.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-fn main() {
- let Self = "foo"; //~ error: expected identifier, found keyword `Self`
-}
diff --git a/src/test/run-pass/union/union-backcomp.rs b/src/test/run-pass/union/union-backcomp.rs
index 9394b61..0f8c996 100644
--- a/src/test/run-pass/union/union-backcomp.rs
+++ b/src/test/run-pass/union/union-backcomp.rs
@@ -10,6 +10,12 @@
#![feature(untagged_unions)]
+macro_rules! union {
+ () => (struct S;)
+}
+
+union!();
+
fn union() {}
fn main() {