From 7c11a53f9ccb4040995b9e054b093a47fef29cc1 Mon Sep 17 00:00:00 2001 From: yukang Date: Fri, 25 Nov 2022 17:11:47 +0800 Subject: fix #104867, Properly handle postfix inc/dec in standalone and subexpr scenarios --- compiler/rustc_parse/src/parser/expr.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'compiler/rustc_parse/src/parser/expr.rs') diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 9f2267efb82..b98372d0f28 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -292,7 +292,15 @@ impl<'a> Parser<'a> { let op_span = self.prev_token.span.to(self.token.span); // Eat the second `+` self.bump(); - lhs = self.recover_from_postfix_increment(lhs, op_span)?; + let prev_is_semi = { + if let Ok(prev_code) = self.sess.source_map().span_to_prev_source(lhs.span) && + prev_code.trim_end().ends_with(";") { + true + } else { + false + } + }; + lhs = self.recover_from_postfix_increment(lhs, op_span, prev_is_semi)?; continue; } -- cgit 1.4.1-3-g733a5 From dee85a391f091f314a24fb5a090f2e528f4eb81c Mon Sep 17 00:00:00 2001 From: yukang Date: Sat, 26 Nov 2022 05:33:13 +0800 Subject: add start_stmt to handle postfix increment --- compiler/rustc_parse/src/parser/diagnostics.rs | 29 ++++---- compiler/rustc_parse/src/parser/expr.rs | 23 +++--- compiler/rustc_parse/src/parser/stmt.rs | 4 +- src/test/ui/parser/increment-autofix-2.fixed | 63 +++++++++++++++++ src/test/ui/parser/increment-autofix-2.rs | 63 +++++++++++++++++ src/test/ui/parser/increment-autofix-2.stderr | 84 ++++++++++++++++++++++ src/test/ui/parser/increment-notfixed.fixed | 63 ----------------- src/test/ui/parser/increment-notfixed.rs | 63 ----------------- src/test/ui/parser/increment-notfixed.stderr | 84 ---------------------- src/test/ui/parser/issue-104867-inc-dec-2.rs | 41 +++++++++++ src/test/ui/parser/issue-104867-inc-dec-2.stderr | 90 ++++++++++++++++++++++++ src/test/ui/parser/issue-104867-inc-dec.rs | 15 ++++ src/test/ui/parser/issue-104867-inc-dec.stderr | 25 ++++++- 13 files changed, 406 insertions(+), 241 deletions(-) create mode 100644 src/test/ui/parser/increment-autofix-2.fixed create mode 100644 src/test/ui/parser/increment-autofix-2.rs create mode 100644 src/test/ui/parser/increment-autofix-2.stderr delete mode 100644 src/test/ui/parser/increment-notfixed.fixed delete mode 100644 src/test/ui/parser/increment-notfixed.rs delete mode 100644 src/test/ui/parser/increment-notfixed.stderr create mode 100644 src/test/ui/parser/issue-104867-inc-dec-2.rs create mode 100644 src/test/ui/parser/issue-104867-inc-dec-2.stderr (limited to 'compiler/rustc_parse/src/parser/expr.rs') diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index eba0f22f37f..f8c6ff994c4 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1259,10 +1259,9 @@ impl<'a> Parser<'a> { &mut self, operand_expr: P, op_span: Span, - prev_is_semi: bool, + start_stmt: bool, ) -> PResult<'a, P> { - let standalone = - if prev_is_semi { IsStandalone::Standalone } else { IsStandalone::Subexpr }; + let standalone = if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr }; let kind = IncDecRecovery { standalone, op: IncOrDec::Inc, fixity: UnaryFixity::Pre }; self.recover_from_inc_dec(operand_expr, kind, op_span) } @@ -1271,10 +1270,10 @@ impl<'a> Parser<'a> { &mut self, operand_expr: P, op_span: Span, - prev_is_semi: bool, + start_stmt: bool, ) -> PResult<'a, P> { let kind = IncDecRecovery { - standalone: if prev_is_semi { IsStandalone::Standalone } else { IsStandalone::Subexpr }, + standalone: if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr }, op: IncOrDec::Inc, fixity: UnaryFixity::Post, }; @@ -1305,20 +1304,22 @@ impl<'a> Parser<'a> { UnaryFixity::Post => (base.span.shrink_to_lo(), op_span), }; - let Ok(base_src) = self.span_to_snippet(base.span) - else { return help_base_case(err, base) }; match kind.standalone { IsStandalone::Standalone => { self.inc_dec_standalone_suggest(kind, spans).emit_verbose(&mut err) } - IsStandalone::Subexpr => match kind.fixity { - UnaryFixity::Pre => { - self.prefix_inc_dec_suggest(base_src, kind, spans).emit(&mut err) - } - UnaryFixity::Post => { - self.postfix_inc_dec_suggest(base_src, kind, spans).emit(&mut err) + IsStandalone::Subexpr => { + let Ok(base_src) = self.span_to_snippet(base.span) + else { return help_base_case(err, base) }; + match kind.fixity { + UnaryFixity::Pre => { + self.prefix_inc_dec_suggest(base_src, kind, spans).emit(&mut err) + } + UnaryFixity::Post => { + self.postfix_inc_dec_suggest(base_src, kind, spans).emit(&mut err) + } } - }, + } } Err(err) } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index b98372d0f28..36fe328cb19 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -83,7 +83,7 @@ macro_rules! maybe_whole_expr { pub(super) enum LhsExpr { NotYetParsed, AttributesParsed(AttrWrapper), - AlreadyParsed(P), + AlreadyParsed(P, bool), // (expr, starts_statement) } impl From> for LhsExpr { @@ -101,7 +101,7 @@ impl From> for LhsExpr { /// /// This conversion does not allocate. fn from(expr: P) -> Self { - LhsExpr::AlreadyParsed(expr) + LhsExpr::AlreadyParsed(expr, false) } } @@ -173,7 +173,9 @@ impl<'a> Parser<'a> { min_prec: usize, lhs: LhsExpr, ) -> PResult<'a, P> { - let mut lhs = if let LhsExpr::AlreadyParsed(expr) = lhs { + let mut starts_stmt = false; + let mut lhs = if let LhsExpr::AlreadyParsed(expr, starts_statement) = lhs { + starts_stmt = starts_statement; expr } else { let attrs = match lhs { @@ -292,15 +294,7 @@ impl<'a> Parser<'a> { let op_span = self.prev_token.span.to(self.token.span); // Eat the second `+` self.bump(); - let prev_is_semi = { - if let Ok(prev_code) = self.sess.source_map().span_to_prev_source(lhs.span) && - prev_code.trim_end().ends_with(";") { - true - } else { - false - } - }; - lhs = self.recover_from_postfix_increment(lhs, op_span, prev_is_semi)?; + lhs = self.recover_from_postfix_increment(lhs, op_span, starts_stmt)?; continue; } @@ -607,14 +601,15 @@ impl<'a> Parser<'a> { token::BinOp(token::Plus) if this.look_ahead(1, |t| *t == token::BinOp(token::Plus)) => { - let prev_is_semi = this.prev_token == token::Semi; + let starts_stmt = this.prev_token == token::Semi + || this.prev_token == token::CloseDelim(Delimiter::Brace); let pre_span = this.token.span.to(this.look_ahead(1, |t| t.span)); // Eat both `+`s. this.bump(); this.bump(); let operand_expr = this.parse_dot_or_call_expr(Default::default())?; - this.recover_from_prefix_increment(operand_expr, pre_span, prev_is_semi) + this.recover_from_prefix_increment(operand_expr, pre_span, starts_stmt) } token::Ident(..) if this.token.is_keyword(kw::Box) => { make_it!(this, attrs, |this, _| this.parse_box_expr(lo)) diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 1b56cd72db0..53aa0315151 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -156,7 +156,7 @@ impl<'a> Parser<'a> { // Perform this outside of the `collect_tokens_trailing_token` closure, // since our outer attributes do not apply to this part of the expression let expr = self.with_res(Restrictions::STMT_EXPR, |this| { - this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) + this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr, true)) })?; Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr))) } else { @@ -190,7 +190,7 @@ impl<'a> Parser<'a> { let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac)); let e = self.maybe_recover_from_bad_qpath(e)?; let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?; - let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; + let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e, false))?; StmtKind::Expr(e) }; Ok(self.mk_stmt(lo.to(hi), kind)) diff --git a/src/test/ui/parser/increment-autofix-2.fixed b/src/test/ui/parser/increment-autofix-2.fixed new file mode 100644 index 00000000000..580ebaf5dbb --- /dev/null +++ b/src/test/ui/parser/increment-autofix-2.fixed @@ -0,0 +1,63 @@ +// run-rustfix + +struct Foo { + bar: Bar, +} + +struct Bar { + qux: i32, +} + +pub fn post_regular() { + let mut i = 0; + i += 1; //~ ERROR Rust has no postfix increment operator + println!("{}", i); +} + +pub fn post_while() { + let mut i = 0; + while { let tmp = i; i += 1; tmp } < 5 { + //~^ ERROR Rust has no postfix increment operator + println!("{}", i); + } +} + +pub fn post_regular_tmp() { + let mut tmp = 0; + tmp += 1; //~ ERROR Rust has no postfix increment operator + println!("{}", tmp); +} + +pub fn post_while_tmp() { + let mut tmp = 0; + while { let tmp_ = tmp; tmp += 1; tmp_ } < 5 { + //~^ ERROR Rust has no postfix increment operator + println!("{}", tmp); + } +} + +pub fn post_field() { + let mut foo = Foo { bar: Bar { qux: 0 } }; + foo.bar.qux += 1; + //~^ ERROR Rust has no postfix increment operator + println!("{}", foo.bar.qux); +} + +pub fn post_field_tmp() { + struct S { + tmp: i32 + } + let mut s = S { tmp: 0 }; + s.tmp += 1; + //~^ ERROR Rust has no postfix increment operator + println!("{}", s.tmp); +} + +pub fn pre_field() { + let mut foo = Foo { bar: Bar { qux: 0 } }; + foo.bar.qux += 1; + //~^ ERROR Rust has no prefix increment operator + println!("{}", foo.bar.qux); +} + +fn main() {} diff --git a/src/test/ui/parser/increment-autofix-2.rs b/src/test/ui/parser/increment-autofix-2.rs new file mode 100644 index 00000000000..ebe5fa6ca1e --- /dev/null +++ b/src/test/ui/parser/increment-autofix-2.rs @@ -0,0 +1,63 @@ +// run-rustfix + +struct Foo { + bar: Bar, +} + +struct Bar { + qux: i32, +} + +pub fn post_regular() { + let mut i = 0; + i++; //~ ERROR Rust has no postfix increment operator + println!("{}", i); +} + +pub fn post_while() { + let mut i = 0; + while i++ < 5 { + //~^ ERROR Rust has no postfix increment operator + println!("{}", i); + } +} + +pub fn post_regular_tmp() { + let mut tmp = 0; + tmp++; //~ ERROR Rust has no postfix increment operator + println!("{}", tmp); +} + +pub fn post_while_tmp() { + let mut tmp = 0; + while tmp++ < 5 { + //~^ ERROR Rust has no postfix increment operator + println!("{}", tmp); + } +} + +pub fn post_field() { + let mut foo = Foo { bar: Bar { qux: 0 } }; + foo.bar.qux++; + //~^ ERROR Rust has no postfix increment operator + println!("{}", foo.bar.qux); +} + +pub fn post_field_tmp() { + struct S { + tmp: i32 + } + let mut s = S { tmp: 0 }; + s.tmp++; + //~^ ERROR Rust has no postfix increment operator + println!("{}", s.tmp); +} + +pub fn pre_field() { + let mut foo = Foo { bar: Bar { qux: 0 } }; + ++foo.bar.qux; + //~^ ERROR Rust has no prefix increment operator + println!("{}", foo.bar.qux); +} + +fn main() {} diff --git a/src/test/ui/parser/increment-autofix-2.stderr b/src/test/ui/parser/increment-autofix-2.stderr new file mode 100644 index 00000000000..11e985480d6 --- /dev/null +++ b/src/test/ui/parser/increment-autofix-2.stderr @@ -0,0 +1,84 @@ +error: Rust has no postfix increment operator + --> $DIR/increment-autofix-2.rs:13:6 + | +LL | i++; + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL | i += 1; + | ~~~~ + +error: Rust has no postfix increment operator + --> $DIR/increment-autofix-2.rs:19:12 + | +LL | while i++ < 5 { + | ----- ^^ not a valid postfix operator + | | + | while parsing the condition of this `while` expression + | +help: use `+= 1` instead + | +LL | while { let tmp = i; i += 1; tmp } < 5 { + | +++++++++++ ~~~~~~~~~~~~~~~ + +error: Rust has no postfix increment operator + --> $DIR/increment-autofix-2.rs:27:8 + | +LL | tmp++; + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL | tmp += 1; + | ~~~~ + +error: Rust has no postfix increment operator + --> $DIR/increment-autofix-2.rs:33:14 + | +LL | while tmp++ < 5 { + | ----- ^^ not a valid postfix operator + | | + | while parsing the condition of this `while` expression + | +help: use `+= 1` instead + | +LL | while { let tmp_ = tmp; tmp += 1; tmp_ } < 5 { + | ++++++++++++ ~~~~~~~~~~~~~~~~~~ + +error: Rust has no postfix increment operator + --> $DIR/increment-autofix-2.rs:41:16 + | +LL | foo.bar.qux++; + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL | foo.bar.qux += 1; + | ~~~~ + +error: Rust has no postfix increment operator + --> $DIR/increment-autofix-2.rs:51:10 + | +LL | s.tmp++; + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL | s.tmp += 1; + | ~~~~ + +error: Rust has no prefix increment operator + --> $DIR/increment-autofix-2.rs:58:5 + | +LL | ++foo.bar.qux; + | ^^ not a valid prefix operator + | +help: use `+= 1` instead + | +LL - ++foo.bar.qux; +LL + foo.bar.qux += 1; + | + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/parser/increment-notfixed.fixed b/src/test/ui/parser/increment-notfixed.fixed deleted file mode 100644 index 580ebaf5dbb..00000000000 --- a/src/test/ui/parser/increment-notfixed.fixed +++ /dev/null @@ -1,63 +0,0 @@ -// run-rustfix - -struct Foo { - bar: Bar, -} - -struct Bar { - qux: i32, -} - -pub fn post_regular() { - let mut i = 0; - i += 1; //~ ERROR Rust has no postfix increment operator - println!("{}", i); -} - -pub fn post_while() { - let mut i = 0; - while { let tmp = i; i += 1; tmp } < 5 { - //~^ ERROR Rust has no postfix increment operator - println!("{}", i); - } -} - -pub fn post_regular_tmp() { - let mut tmp = 0; - tmp += 1; //~ ERROR Rust has no postfix increment operator - println!("{}", tmp); -} - -pub fn post_while_tmp() { - let mut tmp = 0; - while { let tmp_ = tmp; tmp += 1; tmp_ } < 5 { - //~^ ERROR Rust has no postfix increment operator - println!("{}", tmp); - } -} - -pub fn post_field() { - let mut foo = Foo { bar: Bar { qux: 0 } }; - foo.bar.qux += 1; - //~^ ERROR Rust has no postfix increment operator - println!("{}", foo.bar.qux); -} - -pub fn post_field_tmp() { - struct S { - tmp: i32 - } - let mut s = S { tmp: 0 }; - s.tmp += 1; - //~^ ERROR Rust has no postfix increment operator - println!("{}", s.tmp); -} - -pub fn pre_field() { - let mut foo = Foo { bar: Bar { qux: 0 } }; - foo.bar.qux += 1; - //~^ ERROR Rust has no prefix increment operator - println!("{}", foo.bar.qux); -} - -fn main() {} diff --git a/src/test/ui/parser/increment-notfixed.rs b/src/test/ui/parser/increment-notfixed.rs deleted file mode 100644 index ebe5fa6ca1e..00000000000 --- a/src/test/ui/parser/increment-notfixed.rs +++ /dev/null @@ -1,63 +0,0 @@ -// run-rustfix - -struct Foo { - bar: Bar, -} - -struct Bar { - qux: i32, -} - -pub fn post_regular() { - let mut i = 0; - i++; //~ ERROR Rust has no postfix increment operator - println!("{}", i); -} - -pub fn post_while() { - let mut i = 0; - while i++ < 5 { - //~^ ERROR Rust has no postfix increment operator - println!("{}", i); - } -} - -pub fn post_regular_tmp() { - let mut tmp = 0; - tmp++; //~ ERROR Rust has no postfix increment operator - println!("{}", tmp); -} - -pub fn post_while_tmp() { - let mut tmp = 0; - while tmp++ < 5 { - //~^ ERROR Rust has no postfix increment operator - println!("{}", tmp); - } -} - -pub fn post_field() { - let mut foo = Foo { bar: Bar { qux: 0 } }; - foo.bar.qux++; - //~^ ERROR Rust has no postfix increment operator - println!("{}", foo.bar.qux); -} - -pub fn post_field_tmp() { - struct S { - tmp: i32 - } - let mut s = S { tmp: 0 }; - s.tmp++; - //~^ ERROR Rust has no postfix increment operator - println!("{}", s.tmp); -} - -pub fn pre_field() { - let mut foo = Foo { bar: Bar { qux: 0 } }; - ++foo.bar.qux; - //~^ ERROR Rust has no prefix increment operator - println!("{}", foo.bar.qux); -} - -fn main() {} diff --git a/src/test/ui/parser/increment-notfixed.stderr b/src/test/ui/parser/increment-notfixed.stderr deleted file mode 100644 index ffee8b64637..00000000000 --- a/src/test/ui/parser/increment-notfixed.stderr +++ /dev/null @@ -1,84 +0,0 @@ -error: Rust has no postfix increment operator - --> $DIR/increment-notfixed.rs:13:6 - | -LL | i++; - | ^^ not a valid postfix operator - | -help: use `+= 1` instead - | -LL | i += 1; - | ~~~~ - -error: Rust has no postfix increment operator - --> $DIR/increment-notfixed.rs:19:12 - | -LL | while i++ < 5 { - | ----- ^^ not a valid postfix operator - | | - | while parsing the condition of this `while` expression - | -help: use `+= 1` instead - | -LL | while { let tmp = i; i += 1; tmp } < 5 { - | +++++++++++ ~~~~~~~~~~~~~~~ - -error: Rust has no postfix increment operator - --> $DIR/increment-notfixed.rs:27:8 - | -LL | tmp++; - | ^^ not a valid postfix operator - | -help: use `+= 1` instead - | -LL | tmp += 1; - | ~~~~ - -error: Rust has no postfix increment operator - --> $DIR/increment-notfixed.rs:33:14 - | -LL | while tmp++ < 5 { - | ----- ^^ not a valid postfix operator - | | - | while parsing the condition of this `while` expression - | -help: use `+= 1` instead - | -LL | while { let tmp_ = tmp; tmp += 1; tmp_ } < 5 { - | ++++++++++++ ~~~~~~~~~~~~~~~~~~ - -error: Rust has no postfix increment operator - --> $DIR/increment-notfixed.rs:41:16 - | -LL | foo.bar.qux++; - | ^^ not a valid postfix operator - | -help: use `+= 1` instead - | -LL | foo.bar.qux += 1; - | ~~~~ - -error: Rust has no postfix increment operator - --> $DIR/increment-notfixed.rs:51:10 - | -LL | s.tmp++; - | ^^ not a valid postfix operator - | -help: use `+= 1` instead - | -LL | s.tmp += 1; - | ~~~~ - -error: Rust has no prefix increment operator - --> $DIR/increment-notfixed.rs:58:5 - | -LL | ++foo.bar.qux; - | ^^ not a valid prefix operator - | -help: use `+= 1` instead - | -LL - ++foo.bar.qux; -LL + foo.bar.qux += 1; - | - -error: aborting due to 7 previous errors - diff --git a/src/test/ui/parser/issue-104867-inc-dec-2.rs b/src/test/ui/parser/issue-104867-inc-dec-2.rs new file mode 100644 index 00000000000..e64dfbcdc28 --- /dev/null +++ b/src/test/ui/parser/issue-104867-inc-dec-2.rs @@ -0,0 +1,41 @@ +fn test1() { + let mut i = 0; + let _ = i + ++i; //~ ERROR Rust has no prefix increment operator +} + +fn test2() { + let mut i = 0; + let _ = ++i + i; //~ ERROR Rust has no prefix increment operator +} + +fn test3() { + let mut i = 0; + let _ = ++i + ++i; //~ ERROR Rust has no prefix increment operator +} + +fn test4() { + let mut i = 0; + let _ = i + i++; //~ ERROR Rust has no postfix increment operator +} + +fn test5() { + let mut i = 0; + let _ = i++ + i; //~ ERROR Rust has no postfix increment operator +} + +fn test6() { + let mut i = 0; + let _ = i++ + i++; //~ ERROR Rust has no postfix increment operator +} + +fn test7() { + let mut i = 0; + let _ = ++i + i++; //~ ERROR Rust has no prefix increment operator +} + +fn test8() { + let mut i = 0; + let _ = i++ + ++i; //~ ERROR Rust has no postfix increment operator +} + +fn main() { } diff --git a/src/test/ui/parser/issue-104867-inc-dec-2.stderr b/src/test/ui/parser/issue-104867-inc-dec-2.stderr new file mode 100644 index 00000000000..21cfa4e8b78 --- /dev/null +++ b/src/test/ui/parser/issue-104867-inc-dec-2.stderr @@ -0,0 +1,90 @@ +error: Rust has no prefix increment operator + --> $DIR/issue-104867-inc-dec-2.rs:3:17 + | +LL | let _ = i + ++i; + | ^^ not a valid prefix operator + | +help: use `+= 1` instead + | +LL | let _ = i + { i += 1; i }; + | ~ +++++++++ + +error: Rust has no prefix increment operator + --> $DIR/issue-104867-inc-dec-2.rs:8:13 + | +LL | let _ = ++i + i; + | ^^ not a valid prefix operator + | +help: use `+= 1` instead + | +LL | let _ = { i += 1; i } + i; + | ~ +++++++++ + +error: Rust has no prefix increment operator + --> $DIR/issue-104867-inc-dec-2.rs:13:13 + | +LL | let _ = ++i + ++i; + | ^^ not a valid prefix operator + | +help: use `+= 1` instead + | +LL | let _ = { i += 1; i } + ++i; + | ~ +++++++++ + +error: Rust has no postfix increment operator + --> $DIR/issue-104867-inc-dec-2.rs:18:18 + | +LL | let _ = i + i++; + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL | let _ = { let tmp = i + i; i + i += 1; tmp }; + | +++++++++++ ~~~~~~~~~~~~~~~~~~~ + +error: Rust has no postfix increment operator + --> $DIR/issue-104867-inc-dec-2.rs:23:14 + | +LL | let _ = i++ + i; + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL | let _ = { let tmp = i; i += 1; tmp } + i; + | +++++++++++ ~~~~~~~~~~~~~~~ + +error: Rust has no postfix increment operator + --> $DIR/issue-104867-inc-dec-2.rs:28:14 + | +LL | let _ = i++ + i++; + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL | let _ = { let tmp = i; i += 1; tmp } + i++; + | +++++++++++ ~~~~~~~~~~~~~~~ + +error: Rust has no prefix increment operator + --> $DIR/issue-104867-inc-dec-2.rs:33:13 + | +LL | let _ = ++i + i++; + | ^^ not a valid prefix operator + | +help: use `+= 1` instead + | +LL | let _ = { i += 1; i } + i++; + | ~ +++++++++ + +error: Rust has no postfix increment operator + --> $DIR/issue-104867-inc-dec-2.rs:38:14 + | +LL | let _ = i++ + ++i; + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL | let _ = { let tmp = i; i += 1; tmp } + ++i; + | +++++++++++ ~~~~~~~~~~~~~~~ + +error: aborting due to 8 previous errors + diff --git a/src/test/ui/parser/issue-104867-inc-dec.rs b/src/test/ui/parser/issue-104867-inc-dec.rs index d08d74ec1f9..760c67b4bed 100644 --- a/src/test/ui/parser/issue-104867-inc-dec.rs +++ b/src/test/ui/parser/issue-104867-inc-dec.rs @@ -27,4 +27,19 @@ fn test5() { if ++i == 1 { } //~ ERROR Rust has no prefix increment operator } +fn test6() { + let mut i = 0; + loop { break; } + i++; //~ ERROR Rust has no postfix increment operator + loop { break; } + ++i; +} + +fn test7() { + let mut i = 0; + loop { break; } + ++i; //~ ERROR Rust has no prefix increment operator +} + + fn main() {} diff --git a/src/test/ui/parser/issue-104867-inc-dec.stderr b/src/test/ui/parser/issue-104867-inc-dec.stderr index d45b92bf899..78bfd3e82f0 100644 --- a/src/test/ui/parser/issue-104867-inc-dec.stderr +++ b/src/test/ui/parser/issue-104867-inc-dec.stderr @@ -54,5 +54,28 @@ help: use `+= 1` instead LL | if { i += 1; i } == 1 { } | ~ +++++++++ -error: aborting due to 5 previous errors +error: Rust has no postfix increment operator + --> $DIR/issue-104867-inc-dec.rs:33:6 + | +LL | i++; + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL | i += 1; + | ~~~~ + +error: Rust has no prefix increment operator + --> $DIR/issue-104867-inc-dec.rs:41:5 + | +LL | ++i; + | ^^ not a valid prefix operator + | +help: use `+= 1` instead + | +LL - ++i; +LL + i += 1; + | + +error: aborting due to 7 previous errors -- cgit 1.4.1-3-g733a5 From 2fd364acff5f962b0ce4f4dffb5ae085d5f2b67a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 29 Nov 2022 13:36:00 +1100 Subject: Remove `token::Lit` from `ast::MetaItemLit`. `token::Lit` contains a `kind` field that indicates what kind of literal it is. `ast::MetaItemLit` currently wraps a `token::Lit` but also has its own `kind` field. This means that `ast::MetaItemLit` encodes the literal kind in two different ways. This commit changes `ast::MetaItemLit` so it no longer wraps `token::Lit`. It now contains the `symbol` and `suffix` fields from `token::Lit`, but not the `kind` field, eliminating the redundancy. --- compiler/rustc_ast/src/ast.rs | 8 +++++--- compiler/rustc_ast/src/attr/mod.rs | 4 +++- compiler/rustc_ast/src/util/literal.rs | 27 +++++++++++++++++++++++++-- compiler/rustc_ast_lowering/src/lib.rs | 3 ++- compiler/rustc_ast_pretty/src/pprust/state.rs | 2 +- compiler/rustc_builtin_macros/src/derive.rs | 10 ++++++---- compiler/rustc_parse/src/parser/expr.rs | 11 ++++++----- compiler/rustc_parse/src/parser/pat.rs | 2 +- src/tools/rustfmt/src/attr.rs | 12 +++++++----- 9 files changed, 56 insertions(+), 23 deletions(-) (limited to 'compiler/rustc_parse/src/parser/expr.rs') diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b869b2f8af9..c1795be2290 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1733,8 +1733,10 @@ pub enum StrStyle { /// A literal in a meta item. #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub struct MetaItemLit { - /// The original literal token as written in source code. - pub token_lit: token::Lit, + /// The original literal as written in the source code. + pub symbol: Symbol, + /// The original suffix as written in the source code. + pub suffix: Option, /// The "semantic" representation of the literal lowered from the original tokens. /// Strings are unescaped, hexadecimal forms are eliminated, etc. pub kind: LitKind, @@ -3103,7 +3105,7 @@ mod size_asserts { static_assert_size!(ItemKind, 112); static_assert_size!(LitKind, 24); static_assert_size!(Local, 72); - static_assert_size!(MetaItemLit, 48); + static_assert_size!(MetaItemLit, 40); static_assert_size!(Param, 40); static_assert_size!(Pat, 88); static_assert_size!(Path, 24); diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 1ba46914675..2ec126715e7 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -328,7 +328,9 @@ pub fn mk_name_value_item_str(ident: Ident, str: Symbol, str_span: Span) -> Meta } pub fn mk_name_value_item(ident: Ident, kind: LitKind, lit_span: Span) -> MetaItem { - let lit = MetaItemLit { token_lit: kind.synthesize_token_lit(), kind, span: lit_span }; + let token_lit = kind.synthesize_token_lit(); + let lit = + MetaItemLit { symbol: token_lit.symbol, suffix: token_lit.suffix, kind, span: lit_span }; let span = ident.span.to(lit_span); MetaItem { path: Path::from_ident(ident), kind: MetaItemKind::NameValue(lit), span } } diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 9f6fdf44ac0..a0a925d4700 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -202,9 +202,32 @@ impl LitKind { } impl MetaItemLit { - /// Converts token literal into a meta item literal. + /// Converts a token literal into a meta item literal. pub fn from_token_lit(token_lit: token::Lit, span: Span) -> Result { - Ok(MetaItemLit { token_lit, kind: LitKind::from_token_lit(token_lit)?, span }) + Ok(MetaItemLit { + symbol: token_lit.symbol, + suffix: token_lit.suffix, + kind: LitKind::from_token_lit(token_lit)?, + span, + }) + } + + /// Cheaply converts a meta item literal into a token literal. + pub fn as_token_lit(&self) -> token::Lit { + let kind = match self.kind { + LitKind::Bool(_) => token::Bool, + LitKind::Str(_, ast::StrStyle::Cooked) => token::Str, + LitKind::Str(_, ast::StrStyle::Raw(n)) => token::StrRaw(n), + LitKind::ByteStr(_, ast::StrStyle::Cooked) => token::ByteStr, + LitKind::ByteStr(_, ast::StrStyle::Raw(n)) => token::ByteStrRaw(n), + LitKind::Byte(_) => token::Byte, + LitKind::Char(_) => token::Char, + LitKind::Int(..) => token::Integer, + LitKind::Float(..) => token::Float, + LitKind::Err => token::Err, + }; + + token::Lit::new(kind, self.symbol, self.suffix) } /// Converts an arbitrary token into meta item literal. diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1d279706278..8e4bfb71336 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -954,7 +954,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { lit } else { MetaItemLit { - token_lit: token::Lit::new(token::LitKind::Err, kw::Empty, None), + symbol: kw::Empty, + suffix: None, kind: LitKind::Err, span: DUMMY_SP, } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index ebe55a4b771..d555cf48730 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -376,7 +376,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere } fn print_meta_item_lit(&mut self, lit: &ast::MetaItemLit) { - self.print_token_literal(lit.token_lit, lit.span) + self.print_token_literal(lit.as_token_lit(), lit.span) } fn print_token_literal(&mut self, token_lit: token::Lit, span: Span) { diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index fa5a45730ac..2a8dc02849e 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -1,7 +1,7 @@ use crate::cfg_eval::cfg_eval; use rustc_ast as ast; -use rustc_ast::{token, GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; +use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; use rustc_errors::{struct_span_err, Applicability}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; use rustc_feature::AttributeTemplate; @@ -130,9 +130,11 @@ fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool { } fn report_unexpected_meta_item_lit(sess: &Session, lit: &ast::MetaItemLit) { - let help_msg = match lit.token_lit.kind { - token::Str if rustc_lexer::is_ident(lit.token_lit.symbol.as_str()) => { - format!("try using `#[derive({})]`", lit.token_lit.symbol) + let help_msg = match lit.kind { + ast::LitKind::Str(_, ast::StrStyle::Cooked) + if rustc_lexer::is_ident(lit.symbol.as_str()) => + { + format!("try using `#[derive({})]`", lit.symbol) } _ => "for example, write `#[derive(Debug)]` for `Debug`".to_string(), }; diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index e0443a697b5..1c773bea000 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1551,7 +1551,7 @@ impl<'a> Parser<'a> { }) }); consume_colon = false; - Ok(self.mk_expr(lo, ExprKind::Lit(lit.token_lit))) + Ok(self.mk_expr(lo, ExprKind::Lit(lit.as_token_lit()))) } else if !ate_colon && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt)) { @@ -1654,7 +1654,8 @@ impl<'a> Parser<'a> { } let name = lifetime.without_first_quote().name; ast::MetaItemLit { - token_lit: token::Lit::new(token::LitKind::Char, name, None), + symbol: name, + suffix: None, kind: ast::LitKind::Char(name.as_str().chars().next().unwrap_or('_')), span: lifetime.span, } @@ -1773,8 +1774,8 @@ impl<'a> Parser<'a> { Some(lit) => match lit.kind { ast::LitKind::Str(symbol_unescaped, style) => Ok(ast::StrLit { style, - symbol: lit.token_lit.symbol, - suffix: lit.token_lit.suffix, + symbol: lit.symbol, + suffix: lit.suffix, span: lit.span, symbol_unescaped, }), @@ -1817,7 +1818,7 @@ impl<'a> Parser<'a> { pub(super) fn parse_token_lit(&mut self) -> PResult<'a, (token::Lit, Span)> { self.parse_opt_token_lit() .ok_or(()) - .or_else(|()| self.handle_missing_lit().map(|lit| (lit.token_lit, lit.span))) + .or_else(|()| self.handle_missing_lit().map(|lit| (lit.as_token_lit(), lit.span))) } pub(super) fn parse_meta_item_lit(&mut self) -> PResult<'a, MetaItemLit> { diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index cbeec951e2d..b5147158f70 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -420,7 +420,7 @@ impl<'a> Parser<'a> { err.span_label(self_.token.span, format!("expected {}", expected)); err }); - PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit.token_lit))) + PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit.as_token_lit()))) } else { // Try to parse everything else as literal with optional minus match self.parse_literal_maybe_minus() { diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs index 2ac703b957b..c503eeeb9b3 100644 --- a/src/tools/rustfmt/src/attr.rs +++ b/src/tools/rustfmt/src/attr.rs @@ -260,7 +260,9 @@ impl Rewrite for ast::NestedMetaItem { fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { match self { ast::NestedMetaItem::MetaItem(ref meta_item) => meta_item.rewrite(context, shape), - ast::NestedMetaItem::Lit(ref l) => rewrite_literal(context, l.token_lit, l.span, shape), + ast::NestedMetaItem::Lit(ref l) => { + rewrite_literal(context, l.as_token_lit(), l.span, shape) + } } } } @@ -308,18 +310,18 @@ impl Rewrite for ast::MetaItem { }), )? } - ast::MetaItemKind::NameValue(ref literal) => { + ast::MetaItemKind::NameValue(ref lit) => { let path = rewrite_path(context, PathContext::Type, &None, &self.path, shape)?; // 3 = ` = ` let lit_shape = shape.shrink_left(path.len() + 3)?; - // `rewrite_literal` returns `None` when `literal` exceeds max + // `rewrite_literal` returns `None` when `lit` exceeds max // width. Since a literal is basically unformattable unless it // is a string literal (and only if `format_strings` is set), // we might be better off ignoring the fact that the attribute // is longer than the max width and continue on formatting. // See #2479 for example. - let value = rewrite_literal(context, literal.token_lit, literal.span, lit_shape) - .unwrap_or_else(|| context.snippet(literal.span).to_owned()); + let value = rewrite_literal(context, lit.as_token_lit(), lit.span, lit_shape) + .unwrap_or_else(|| context.snippet(lit.span).to_owned()); format!("{} = {}", path, value) } }) -- cgit 1.4.1-3-g733a5 From d887615b4c83d856cd3e40000968c047f2ff4019 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 5 Dec 2022 14:39:56 +1100 Subject: Parameterise `Parser::{recover_unclosed_char,handle_missing_lit}`. These two methods both produce a `MetaItemLit`, and then some of the call sites convert the `MetaItemLit` to a `token::Lit` with `as_token_lit`. This commit parameterises these two methods with a `mk_lit_char` closure, which can be used to produce either `MetaItemLit` or `token::Lit` directly as necessary. --- compiler/rustc_parse/src/parser/expr.rs | 57 +++++++++++++++++++++------------ compiler/rustc_parse/src/parser/pat.rs | 22 +++++++------ 2 files changed, 49 insertions(+), 30 deletions(-) (limited to 'compiler/rustc_parse/src/parser/expr.rs') diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 1c773bea000..07f03e0d582 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1543,15 +1543,16 @@ impl<'a> Parser<'a> { && (matches!(self.token.kind, token::CloseDelim(_) | token::Comma) || self.token.is_op()) { - let lit = self.recover_unclosed_char(label_.ident, |self_| { - self_.sess.create_err(UnexpectedTokenAfterLabel { - span: self_.token.span, - remove_label: None, - enclose_in_block: None, - }) - }); + let (lit, _) = + self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| { + self_.sess.create_err(UnexpectedTokenAfterLabel { + span: self_.token.span, + remove_label: None, + enclose_in_block: None, + }) + }); consume_colon = false; - Ok(self.mk_expr(lo, ExprKind::Lit(lit.as_token_lit()))) + Ok(self.mk_expr(lo, ExprKind::Lit(lit))) } else if !ate_colon && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt)) { @@ -1626,12 +1627,13 @@ impl<'a> Parser<'a> { Ok(expr) } - /// Emit an error when a char is parsed as a lifetime because of a missing quote - pub(super) fn recover_unclosed_char( + /// Emit an error when a char is parsed as a lifetime because of a missing quote. + pub(super) fn recover_unclosed_char( &self, lifetime: Ident, + mk_lit_char: impl FnOnce(Symbol, Span) -> L, err: impl FnOnce(&Self) -> DiagnosticBuilder<'a, ErrorGuaranteed>, - ) -> ast::MetaItemLit { + ) -> L { if let Some(mut diag) = self.sess.span_diagnostic.steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar) { @@ -1653,12 +1655,7 @@ impl<'a> Parser<'a> { .emit(); } let name = lifetime.without_first_quote().name; - ast::MetaItemLit { - symbol: name, - suffix: None, - kind: ast::LitKind::Char(name.as_str().chars().next().unwrap_or('_')), - span: lifetime.span, - } + mk_lit_char(name, lifetime.span) } /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead. @@ -1785,7 +1782,23 @@ impl<'a> Parser<'a> { } } - fn handle_missing_lit(&mut self) -> PResult<'a, MetaItemLit> { + pub(crate) fn mk_token_lit_char(name: Symbol, span: Span) -> (token::Lit, Span) { + (token::Lit { symbol: name, suffix: None, kind: token::Char }, span) + } + + fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit { + ast::MetaItemLit { + symbol: name, + suffix: None, + kind: ast::LitKind::Char(name.as_str().chars().next().unwrap_or('_')), + span, + } + } + + fn handle_missing_lit( + &mut self, + mk_lit_char: impl FnOnce(Symbol, Span) -> L, + ) -> PResult<'a, L> { if let token::Interpolated(inner) = &self.token.kind { let expr = match inner.as_ref() { token::NtExpr(expr) => Some(expr), @@ -1809,7 +1822,7 @@ impl<'a> Parser<'a> { // On an error path, eagerly consider a lifetime to be an unclosed character lit if self.token.is_lifetime() { let lt = self.expect_lifetime(); - Ok(self.recover_unclosed_char(lt.ident, err)) + Ok(self.recover_unclosed_char(lt.ident, mk_lit_char, err)) } else { Err(err(self)) } @@ -1818,11 +1831,13 @@ impl<'a> Parser<'a> { pub(super) fn parse_token_lit(&mut self) -> PResult<'a, (token::Lit, Span)> { self.parse_opt_token_lit() .ok_or(()) - .or_else(|()| self.handle_missing_lit().map(|lit| (lit.as_token_lit(), lit.span))) + .or_else(|()| self.handle_missing_lit(Parser::mk_token_lit_char)) } pub(super) fn parse_meta_item_lit(&mut self) -> PResult<'a, MetaItemLit> { - self.parse_opt_meta_item_lit().ok_or(()).or_else(|()| self.handle_missing_lit()) + self.parse_opt_meta_item_lit() + .ok_or(()) + .or_else(|()| self.handle_missing_lit(Parser::mk_meta_item_lit_char)) } fn recover_after_dot(&mut self) -> Option { diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index b5147158f70..a1981e11477 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -411,16 +411,20 @@ impl<'a> Parser<'a> { { // Recover a `'a` as a `'a'` literal let lt = self.expect_lifetime(); - let lit = self.recover_unclosed_char(lt.ident, |self_| { - let expected = expected.unwrap_or("pattern"); - let msg = - format!("expected {}, found {}", expected, super::token_descr(&self_.token)); + let (lit, _) = + self.recover_unclosed_char(lt.ident, Parser::mk_token_lit_char, |self_| { + let expected = expected.unwrap_or("pattern"); + let msg = format!( + "expected {}, found {}", + expected, + super::token_descr(&self_.token) + ); - let mut err = self_.struct_span_err(self_.token.span, &msg); - err.span_label(self_.token.span, format!("expected {}", expected)); - err - }); - PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit.as_token_lit()))) + let mut err = self_.struct_span_err(self_.token.span, &msg); + err.span_label(self_.token.span, format!("expected {}", expected)); + err + }); + PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit))) } else { // Try to parse everything else as literal with optional minus match self.parse_literal_maybe_minus() { -- cgit 1.4.1-3-g733a5