From 7d21f21f71b9b4a8a0662a223c20db7a789f5637 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 29 Jul 2017 04:47:12 +0300 Subject: [PATCH 1/2] syntax: Relax path grammar --- src/libsyntax/parse/parser.rs | 15 ++------------- src/test/compile-fail/issue-32995.rs | 8 ++------ src/test/compile-fail/issue-36116.rs | 15 +++++++++------ .../unboxed-closure-sugar-used-on-struct-3.rs | 12 +++++------- .../parse-fail/type-parameters-in-field-exprs.rs | 2 ++ 5 files changed, 20 insertions(+), 32 deletions(-) rename src/test/{parse-fail => compile-fail}/unboxed-closure-sugar-used-on-struct-3.rs (68%) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7bf4c6799b3cb..9e36adf3d3596 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -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` - unambiguously a path. - /// Paths with disambiguators are rejected for now, but may be allowed in the future. + /// Paths with disambiguators are still accepted, `x::` - unambiguously a path too. Type, /// A path with generic arguments disallowed, e.g. `foo::bar::Baz`, used in imports, /// visibilities or attributes. @@ -1835,18 +1835,7 @@ 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") - } - } + self.eat(&token::ModSep); let parameters = if self.eat_lt() { // `<'a, T, A = U>` diff --git a/src/test/compile-fail/issue-32995.rs b/src/test/compile-fail/issue-32995.rs index 4b7f82943bac1..ffbd0c0c22a7c 100644 --- a/src/test/compile-fail/issue-32995.rs +++ b/src/test/compile-fail/issue-32995.rs @@ -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 diff --git a/src/test/compile-fail/issue-36116.rs b/src/test/compile-fail/issue-36116.rs index 737955b2ff351..18a6e430b84de 100644 --- a/src/test/compile-fail/issue-36116.rs +++ b/src/test/compile-fail/issue-36116.rs @@ -8,16 +8,19 @@ // 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)] + struct Foo { _a: T, } -fn main() { +fn f() { let f = Some(Foo { _a: 42 }).map(|a| a as Foo::); - //~^ ERROR unnecessary path disambiguator - //~| NOTE try removing `::` - let g: Foo:: = Foo { _a: 42 }; - //~^ ERROR unnecessary path disambiguator - //~| NOTE try removing `::` } + +#[rustc_error] +fn main() {} //~ ERROR compilation successful diff --git a/src/test/parse-fail/unboxed-closure-sugar-used-on-struct-3.rs b/src/test/compile-fail/unboxed-closure-sugar-used-on-struct-3.rs similarity index 68% rename from src/test/parse-fail/unboxed-closure-sugar-used-on-struct-3.rs rename to src/test/compile-fail/unboxed-closure-sugar-used-on-struct-3.rs index 548a5078a747b..42fffe546c20c 100644 --- a/src/test/parse-fail/unboxed-closure-sugar-used-on-struct-3.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-used-on-struct-3.rs @@ -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 { f: A, r: R @@ -21,10 +19,10 @@ impl Bar { } fn bar() { - let b = Box::Bar::::new(); // OK + let b = Bar::::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() {} diff --git a/src/test/parse-fail/type-parameters-in-field-exprs.rs b/src/test/parse-fail/type-parameters-in-field-exprs.rs index 95c307c567099..cb018ff1bfa39 100644 --- a/src/test/parse-fail/type-parameters-in-field-exprs.rs +++ b/src/test/parse-fail/type-parameters-in-field-exprs.rs @@ -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 } From 804459bdca28010137990220e617a6b6cbab18d0 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 11 Aug 2017 02:30:08 +0300 Subject: [PATCH 2/2] Issue warnings for unnecessary path disambiguators --- src/libsyntax/ext/tt/macro_parser.rs | 4 +--- src/libsyntax/parse/parser.rs | 28 ++++++++++++++++++---------- src/test/compile-fail/issue-36116.rs | 15 +++++++++++++-- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 146bd5d985699..16a6a0717e0be 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -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 diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9e36adf3d3596..fbf7c4adf371a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -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) })) } @@ -1770,8 +1770,12 @@ impl<'a> Parser<'a> { /// `a::b::C::` (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); @@ -1779,7 +1783,7 @@ impl<'a> Parser<'a> { 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) }) } @@ -1804,10 +1808,10 @@ impl<'a> Parser<'a> { self.parse_path(style) } - fn parse_path_segments(&mut self, segments: &mut Vec, style: PathStyle) - -> PResult<'a, ()> { + fn parse_path_segments(&mut self, segments: &mut Vec, 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(()); @@ -1815,7 +1819,8 @@ impl<'a> Parser<'a> { } } - 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()?; @@ -1835,7 +1840,10 @@ impl<'a> Parser<'a> { && self.look_ahead(1, |t| is_args_start(t)) { // Generic arguments are found - `<`, `(`, `::<` or `::(`. let lo = self.span; - self.eat(&token::ModSep); + 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() { // `<'a, T, A = U>` @@ -2371,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, lo: Span) -> PResult<'a, P> { - 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()` diff --git a/src/test/compile-fail/issue-36116.rs b/src/test/compile-fail/issue-36116.rs index 18a6e430b84de..3afbfa61984b5 100644 --- a/src/test/compile-fail/issue-36116.rs +++ b/src/test/compile-fail/issue-36116.rs @@ -13,13 +13,24 @@ #![feature(rustc_attrs)] #![allow(unused)] +macro_rules! m { + ($p: path) => { + let _ = $p(0); + let _: $p; + } +} + struct Foo { _a: T, } +struct S(T); + fn f() { - let f = Some(Foo { _a: 42 }).map(|a| a as Foo::); - let g: Foo:: = Foo { _a: 42 }; + let f = Some(Foo { _a: 42 }).map(|a| a as Foo::); //~ WARN unnecessary path disambiguator + let g: Foo:: = Foo { _a: 42 }; //~ WARN unnecessary path disambiguator + + m!(S::); // OK, no warning } #[rustc_error]