From 5af861cf7b4a87857ca6aa9dab2ad277ea8c059b Mon Sep 17 00:00:00 2001 From: Dominik Stolz Date: Wed, 17 Apr 2024 23:40:03 +0200 Subject: Disallow ambiguous attributes on expressions --- compiler/rustc_parse/src/parser/expr.rs | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 00947a4c585..1625173970a 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -327,7 +327,9 @@ impl<'a> Parser<'a> { this.parse_expr_assoc_with(prec + prec_adjustment, LhsExpr::NotYetParsed) })?; - let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span); + self.error_ambiguous_outer_attrs(&lhs, lhs_span, rhs.span); + let span = lhs_span.to(rhs.span); + lhs = match op { AssocOp::Add | AssocOp::Subtract @@ -426,6 +428,18 @@ impl<'a> Parser<'a> { }); } + fn error_ambiguous_outer_attrs(&self, lhs: &P, lhs_span: Span, rhs_span: Span) { + if let Some(attr) = lhs.attrs.iter().find(|a| a.style == AttrStyle::Outer) { + self.dcx().emit_err(errors::AmbiguousOuterAttributes { + span: attr.span.to(rhs_span), + sugg: errors::WrapInParentheses::Expression { + left: attr.span.shrink_to_lo(), + right: lhs_span.shrink_to_hi(), + }, + }); + } + } + /// Possibly translate the current token to an associative operator. /// The method does not advance the current token. /// @@ -506,7 +520,8 @@ impl<'a> Parser<'a> { None }; let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span); - let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span); + self.error_ambiguous_outer_attrs(&lhs, lhs.span, rhs_span); + let span = lhs.span.to(rhs_span); let limits = if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed }; let range = self.mk_range(Some(lhs), rhs, limits); @@ -722,7 +737,8 @@ impl<'a> Parser<'a> { expr_kind: fn(P, P) -> ExprKind, ) -> PResult<'a, P> { let mk_expr = |this: &mut Self, lhs: P, rhs: P| { - this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, rhs.span), expr_kind(lhs, rhs)) + this.error_ambiguous_outer_attrs(&lhs, lhs_span, rhs.span); + this.mk_expr(lhs_span.to(rhs.span), expr_kind(lhs, rhs)) }; // Save the state of the parser before parsing type normally, in case there is a @@ -3807,16 +3823,6 @@ impl<'a> Parser<'a> { self.mk_expr(span, ExprKind::Err(guar)) } - /// Create expression span ensuring the span of the parent node - /// is larger than the span of lhs and rhs, including the attributes. - fn mk_expr_sp(&self, lhs: &P, lhs_span: Span, rhs_span: Span) -> Span { - lhs.attrs - .iter() - .find(|a| a.style == AttrStyle::Outer) - .map_or(lhs_span, |a| a.span) - .to(rhs_span) - } - fn collect_tokens_for_expr( &mut self, attrs: AttrWrapper, -- cgit 1.4.1-3-g733a5 From 2ef15523c15758ae00aa192de7077fd36fa61315 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 19 Apr 2024 13:12:12 -0400 Subject: Don't fatal when calling expect_one_of when recovering arg in parse_seq --- compiler/rustc_parse/src/parser/mod.rs | 1 + .../ui/impl-trait/precise-capturing/unexpected-token.rs | 9 +++++++++ .../impl-trait/precise-capturing/unexpected-token.stderr | 16 ++++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 tests/ui/impl-trait/precise-capturing/unexpected-token.rs create mode 100644 tests/ui/impl-trait/precise-capturing/unexpected-token.stderr (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 4a996f89a9a..33efdc84417 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -898,6 +898,7 @@ impl<'a> Parser<'a> { } // Attempt to keep parsing if it was an omitted separator. + self.last_unexpected_token_span = None; match f(self) { Ok(t) => { // Parsed successfully, therefore most probably the code only diff --git a/tests/ui/impl-trait/precise-capturing/unexpected-token.rs b/tests/ui/impl-trait/precise-capturing/unexpected-token.rs new file mode 100644 index 00000000000..39c8c0def6b --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/unexpected-token.rs @@ -0,0 +1,9 @@ +// We used to fatal error without any useful diagnostic when we had an unexpected +// token due to a strange interaction between the sequence parsing code and the +// param/lifetime parsing code. + +fn hello() -> impl use<'a {}> Sized {} +//~^ ERROR expected one of `,` or `>`, found `{` +//~| ERROR expected item, found `>` + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr b/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr new file mode 100644 index 00000000000..989c479b248 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr @@ -0,0 +1,16 @@ +error: expected one of `,` or `>`, found `{` + --> $DIR/unexpected-token.rs:5:27 + | +LL | fn hello() -> impl use<'a {}> Sized {} + | ^ expected one of `,` or `>` + +error: expected item, found `>` + --> $DIR/unexpected-token.rs:5:29 + | +LL | fn hello() -> impl use<'a {}> Sized {} + | ^ expected item + | + = note: for a full list of items that can appear in modules, see + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 98332c108b8074954203fa4b0c82fbab876d3059 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Sat, 20 Apr 2024 15:52:22 +0200 Subject: Improve handling of expr->field errors The current message for "`->` used for field access" is the following: ```rust error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `->` --> src/main.rs:2:6 | 2 | a->b; | ^^ expected one of 8 possible tokens ``` (playground link[1]) This PR tries to address this by adding a dedicated error message and recovery. The proposed error message is: ``` error: `->` used for field access or method call --> ./tiny_test.rs:2:6 | 2 | a->b; | ^^ help: try using `.` instead | = help: the `.` operator will dereference the value if needed ``` (feel free to bikeshed it as much as necessary) [1]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7f8b6f4433aa7866124123575456f54e Signed-off-by: Sasha Pourcelot --- compiler/rustc_parse/messages.ftl | 4 +++ compiler/rustc_parse/src/errors.rs | 9 ++++++ compiler/rustc_parse/src/parser/expr.rs | 6 ++++ tests/ui/parser/expr-rarrow-call.fixed | 33 ++++++++++++++++++++ tests/ui/parser/expr-rarrow-call.rs | 33 ++++++++++++++++++++ tests/ui/parser/expr-rarrow-call.stderr | 42 ++++++++++++++++++++++++++ tests/ui/parser/issues/issue-118530-ice.rs | 3 +- tests/ui/parser/issues/issue-118530-ice.stderr | 14 +++++++-- 8 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 tests/ui/parser/expr-rarrow-call.fixed create mode 100644 tests/ui/parser/expr-rarrow-call.rs create mode 100644 tests/ui/parser/expr-rarrow-call.stderr (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index e2436759c22..32a0df2f619 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -230,6 +230,10 @@ parse_expected_struct_field = expected one of `,`, `:`, or `{"}"}`, found `{$tok parse_expected_trait_in_trait_impl_found_type = expected a trait, found type +parse_expr_rarrow_call = `->` used for field access or method call + .suggestion = try using `.` instead + .help = the `.` operator will dereference the value if needed + parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements .label = dash-separated idents are not valid .suggestion = if the original crate name uses dashes you need to use underscores in the code diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index eae2d904c35..ca8de4240f4 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2988,3 +2988,12 @@ pub(crate) struct AsyncImpl { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(parse_expr_rarrow_call)] +#[help] +pub(crate) struct ExprRArrowCall { + #[primary_span] + #[suggestion(style = "short", applicability = "machine-applicable", code = ".")] + pub span: Span, +} diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 00947a4c585..8a454610718 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -979,6 +979,12 @@ impl<'a> Parser<'a> { // we are using noexpect here because we don't expect a `.` directly after a `return` // which could be suggested otherwise self.eat_noexpect(&token::Dot) + } else if self.token.kind == TokenKind::RArrow && self.may_recover() { + // Recovery for `expr->suffix`. + self.bump(); + let span = self.prev_token.span; + self.dcx().emit_err(errors::ExprRArrowCall { span }); + true } else { self.eat(&token::Dot) }; diff --git a/tests/ui/parser/expr-rarrow-call.fixed b/tests/ui/parser/expr-rarrow-call.fixed new file mode 100644 index 00000000000..9a05e20092d --- /dev/null +++ b/tests/ui/parser/expr-rarrow-call.fixed @@ -0,0 +1,33 @@ +//@ run-rustfix +#![allow( + dead_code, + unused_must_use +)] + +struct Named { + foo: usize +} + +struct Unnamed(usize); + +fn named_struct_field_access(named: &Named) { + named.foo; //~ ERROR `->` used for field access or method call +} + +fn unnamed_struct_field_access(unnamed: &Unnamed) { + unnamed.0; //~ ERROR `->` used for field access or method call +} + +fn tuple_field_access(t: &(u8, u8)) { + t.0; //~ ERROR `->` used for field access or method call + t.1; //~ ERROR `->` used for field access or method call +} + +#[derive(Clone)] +struct Foo; + +fn method_call(foo: &Foo) { + foo.clone(); //~ ERROR `->` used for field access or method call +} + +fn main() {} diff --git a/tests/ui/parser/expr-rarrow-call.rs b/tests/ui/parser/expr-rarrow-call.rs new file mode 100644 index 00000000000..760b0f6f345 --- /dev/null +++ b/tests/ui/parser/expr-rarrow-call.rs @@ -0,0 +1,33 @@ +//@ run-rustfix +#![allow( + dead_code, + unused_must_use +)] + +struct Named { + foo: usize +} + +struct Unnamed(usize); + +fn named_struct_field_access(named: &Named) { + named->foo; //~ ERROR `->` used for field access or method call +} + +fn unnamed_struct_field_access(unnamed: &Unnamed) { + unnamed->0; //~ ERROR `->` used for field access or method call +} + +fn tuple_field_access(t: &(u8, u8)) { + t->0; //~ ERROR `->` used for field access or method call + t->1; //~ ERROR `->` used for field access or method call +} + +#[derive(Clone)] +struct Foo; + +fn method_call(foo: &Foo) { + foo->clone(); //~ ERROR `->` used for field access or method call +} + +fn main() {} diff --git a/tests/ui/parser/expr-rarrow-call.stderr b/tests/ui/parser/expr-rarrow-call.stderr new file mode 100644 index 00000000000..90082f98cb5 --- /dev/null +++ b/tests/ui/parser/expr-rarrow-call.stderr @@ -0,0 +1,42 @@ +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:14:10 + | +LL | named->foo; + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:18:12 + | +LL | unnamed->0; + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:22:6 + | +LL | t->0; + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:23:6 + | +LL | t->1; + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: `->` used for field access or method call + --> $DIR/expr-rarrow-call.rs:30:8 + | +LL | foo->clone(); + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: aborting due to 5 previous errors + diff --git a/tests/ui/parser/issues/issue-118530-ice.rs b/tests/ui/parser/issues/issue-118530-ice.rs index e758e5af4d9..cf14eebec2b 100644 --- a/tests/ui/parser/issues/issue-118530-ice.rs +++ b/tests/ui/parser/issues/issue-118530-ice.rs @@ -3,8 +3,9 @@ fn bar() -> String { [1, 2, 3].iter() //~ ERROR expected `;`, found `#` #[feature] attr::fn bar() -> String { //~ ERROR expected identifier, found keyword `fn` - //~^ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `->` + //~^ ERROR expected one of `(`, `.`, `::`, `;`, `?`, `}`, or an operator, found `{` //~| ERROR expected `;`, found `bar` + //~| ERROR `->` used for field access or method call #[attr] [1, 2, 3].iter().map().collect::() #[attr] diff --git a/tests/ui/parser/issues/issue-118530-ice.stderr b/tests/ui/parser/issues/issue-118530-ice.stderr index ef573fb7ba3..75c6a40c744 100644 --- a/tests/ui/parser/issues/issue-118530-ice.stderr +++ b/tests/ui/parser/issues/issue-118530-ice.stderr @@ -33,11 +33,19 @@ LL | attr::fn bar() -> String { | | | help: add `;` here -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `->` +error: `->` used for field access or method call --> $DIR/issue-118530-ice.rs:5:20 | LL | attr::fn bar() -> String { - | ^^ expected one of `.`, `;`, `?`, `}`, or an operator + | ^^ help: try using `.` instead + | + = help: the `.` operator will dereference the value if needed + +error: expected one of `(`, `.`, `::`, `;`, `?`, `}`, or an operator, found `{` + --> $DIR/issue-118530-ice.rs:5:30 + | +LL | attr::fn bar() -> String { + | ^ expected one of 7 possible tokens -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors -- cgit 1.4.1-3-g733a5 From 9bd175c8a206cabbca2818d9cf509939b95301a8 Mon Sep 17 00:00:00 2001 From: klensy Date: Tue, 23 Apr 2024 11:23:20 +0300 Subject: parser: remove ununsed(no reads) max_angle_bracket_count field --- compiler/rustc_parse/src/parser/mod.rs | 3 --- compiler/rustc_parse/src/parser/path.rs | 1 - 2 files changed, 4 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 4a996f89a9a..cd8a5600c73 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -162,7 +162,6 @@ pub struct Parser<'a> { /// /// See the comments in the `parse_path_segment` function for more details. unmatched_angle_bracket_count: u16, - max_angle_bracket_count: u16, angle_bracket_nesting: u16, last_unexpected_token_span: Option, @@ -430,7 +429,6 @@ impl<'a> Parser<'a> { num_bump_calls: 0, break_last_token: false, unmatched_angle_bracket_count: 0, - max_angle_bracket_count: 0, angle_bracket_nesting: 0, last_unexpected_token_span: None, subparser_name, @@ -778,7 +776,6 @@ impl<'a> Parser<'a> { if ate { // See doc comment for `unmatched_angle_bracket_count`. self.unmatched_angle_bracket_count += 1; - self.max_angle_bracket_count += 1; debug!("eat_lt: (increment) count={:?}", self.unmatched_angle_bracket_count); } ate diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 0f410772dd9..b97ec8c613d 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -299,7 +299,6 @@ impl<'a> Parser<'a> { // parsing a new path. if style == PathStyle::Expr { self.unmatched_angle_bracket_count = 0; - self.max_angle_bracket_count = 0; } // Generic arguments are found - `<`, `(`, `::<` or `::(`. -- cgit 1.4.1-3-g733a5