Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

syntax: Relax path grammar #43540

Merged
merged 2 commits into from
Aug 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/libsyntax/ext/tt/macro_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,9 +599,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
panic!(FatalError)
}
},
"path" => {
token::NtPath(panictry!(p.parse_path(PathStyle::Type)))
},
"path" => token::NtPath(panictry!(p.parse_path_common(PathStyle::Type, false))),
"meta" => token::NtMeta(panictry!(p.parse_meta_item())),
"vis" => token::NtVis(panictry!(p.parse_visibility(true))),
// this is not supposed to happen, since it has been checked
Expand Down
39 changes: 18 additions & 21 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ pub enum PathStyle {
Expr,
/// In other contexts, notably in types, no ambiguity exists and paths can be written
/// without the disambiguator, e.g. `x<y>` - unambiguously a path.
/// Paths with disambiguators are rejected for now, but may be allowed in the future.
/// Paths with disambiguators are still accepted, `x::<Y>` - unambiguously a path too.
Type,
/// A path with generic arguments disallowed, e.g. `foo::bar::Baz`, used in imports,
/// visibilities or attributes.
Expand Down Expand Up @@ -1755,7 +1755,7 @@ impl<'a> Parser<'a> {
self.expect(&token::ModSep)?;

let qself = QSelf { ty, position: path.segments.len() };
self.parse_path_segments(&mut path.segments, style)?;
self.parse_path_segments(&mut path.segments, style, true)?;

Ok((qself, ast::Path { segments: path.segments, span: lo.to(self.prev_span) }))
}
Expand All @@ -1770,16 +1770,20 @@ impl<'a> Parser<'a> {
/// `a::b::C::<D>` (with disambiguator)
/// `Fn(Args)` (without disambiguator)
/// `Fn::(Args)` (with disambiguator)
pub fn parse_path(&mut self, style: PathStyle) -> PResult<'a, ast::Path>
{
pub fn parse_path(&mut self, style: PathStyle) -> PResult<'a, ast::Path> {
self.parse_path_common(style, true)
}

pub fn parse_path_common(&mut self, style: PathStyle, enable_warning: bool)
-> PResult<'a, ast::Path> {
maybe_whole!(self, NtPath, |x| x);

let lo = self.meta_var_span.unwrap_or(self.span);
let mut segments = Vec::new();
if self.eat(&token::ModSep) {
segments.push(PathSegment::crate_root(lo));
}
self.parse_path_segments(&mut segments, style)?;
self.parse_path_segments(&mut segments, style, enable_warning)?;

Ok(ast::Path { segments, span: lo.to(self.prev_span) })
}
Expand All @@ -1804,18 +1808,19 @@ impl<'a> Parser<'a> {
self.parse_path(style)
}

fn parse_path_segments(&mut self, segments: &mut Vec<PathSegment>, style: PathStyle)
-> PResult<'a, ()> {
fn parse_path_segments(&mut self, segments: &mut Vec<PathSegment>, style: PathStyle,
enable_warning: bool) -> PResult<'a, ()> {
loop {
segments.push(self.parse_path_segment(style)?);
segments.push(self.parse_path_segment(style, enable_warning)?);

if self.is_import_coupler() || !self.eat(&token::ModSep) {
return Ok(());
}
}
}

fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> {
fn parse_path_segment(&mut self, style: PathStyle, enable_warning: bool)
-> PResult<'a, PathSegment> {
let ident_span = self.span;
let ident = self.parse_path_segment_ident()?;

Expand All @@ -1835,17 +1840,9 @@ impl<'a> Parser<'a> {
&& self.look_ahead(1, |t| is_args_start(t)) {
// Generic arguments are found - `<`, `(`, `::<` or `::(`.
let lo = self.span;
if self.eat(&token::ModSep) {
// These errors are not strictly necessary and may be removed in the future.
if style == PathStyle::Type {
let mut err = self.diagnostic().struct_span_err(self.prev_span,
"unnecessary path disambiguator");
err.span_label(self.prev_span, "try removing `::`");
err.emit();
} else if self.token == token::OpenDelim(token::Paren) {
self.diagnostic().span_err(self.prev_span,
"`::` is not supported before parenthesized generic arguments")
}
if self.eat(&token::ModSep) && style == PathStyle::Type && enable_warning {
self.diagnostic().struct_span_warn(self.prev_span, "unnecessary path disambiguator")
.span_label(self.prev_span, "try removing `::`").emit();
}

let parameters = if self.eat_lt() {
Expand Down Expand Up @@ -2382,7 +2379,7 @@ impl<'a> Parser<'a> {

// Assuming we have just parsed `.`, continue parsing into an expression.
fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
let segment = self.parse_path_segment(PathStyle::Expr)?;
let segment = self.parse_path_segment(PathStyle::Expr, true)?;
Ok(match self.token {
token::OpenDelim(token::Paren) => {
// Method call `expr.f()`
Expand Down
8 changes: 2 additions & 6 deletions src/test/compile-fail/issue-32995.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,11 @@ fn main() {
//~^ ERROR parenthesized parameters may only be used with a trait
//~| WARN previously accepted

macro_rules! pathexpr {
($p:path) => { $p }
}

let p = pathexpr!(::std::str()::from_utf8)(b"foo").unwrap();
let p = ::std::str::()::from_utf8(b"foo").unwrap();
//~^ ERROR parenthesized parameters may only be used with a trait
//~| WARN previously accepted

let p = pathexpr!(::std::str::from_utf8())(b"foo").unwrap();
let p = ::std::str::from_utf8::()(b"foo").unwrap();
//~^ ERROR parenthesized parameters may only be used with a trait
//~| WARN previously accepted

Expand Down
28 changes: 21 additions & 7 deletions src/test/compile-fail/issue-36116.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,30 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Unnecessary path disambiguator is ok

#![feature(rustc_attrs)]
#![allow(unused)]

macro_rules! m {
($p: path) => {
let _ = $p(0);
let _: $p;
}
}

struct Foo<T> {
_a: T,
}

fn main() {
let f = Some(Foo { _a: 42 }).map(|a| a as Foo::<i32>);
//~^ ERROR unnecessary path disambiguator
//~| NOTE try removing `::`
struct S<T>(T);

fn f() {
let f = Some(Foo { _a: 42 }).map(|a| a as Foo::<i32>); //~ WARN unnecessary path disambiguator
let g: Foo::<i32> = Foo { _a: 42 }; //~ WARN unnecessary path disambiguator

let g: Foo::<i32> = Foo { _a: 42 };
//~^ ERROR unnecessary path disambiguator
//~| NOTE try removing `::`
m!(S::<u8>); // OK, no warning
}

#[rustc_error]
fn main() {} //~ ERROR compilation successful
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: -Z parse-only

// Test that parentheses form doesn't work in expression paths.
// Test that parentheses form parses in expression paths.

struct Bar<A,R> {
f: A, r: R
Expand All @@ -21,10 +19,10 @@ impl<A,B> Bar<A,B> {
}

fn bar() {
let b = Box::Bar::<isize,usize>::new(); // OK
let b = Bar::<isize, usize>::new(); // OK

let b = Box::Bar::()::new();
//~^ ERROR `::` is not supported before parenthesized generic arguments
let b = Bar::(isize, usize)::new(); // OK too (for the parser)
//~^ ERROR parenthesized parameters may only be used with a trait
}

fn main() { }
fn main() {}
2 changes: 2 additions & 0 deletions src/test/parse-fail/type-parameters-in-field-exprs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ fn main() {
//~^ ERROR field expressions may not have generic arguments
f.x::<>;
//~^ ERROR field expressions may not have generic arguments
f.x::();
//~^ ERROR field expressions may not have generic arguments
}