about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-12-14 04:00:05 +0000
committerbors <bors@rust-lang.org>2022-12-14 04:00:05 +0000
commit309c469eece74cd9b83328d18302f1a177d0df7f (patch)
tree41237410c23162187258a755970f79bfdce983ed
parent918d0ac38e8c3bcf4fb5ee2241fb14979c73c312 (diff)
parentded10a13d2a0ccb4475cb7a330179a1f39e2b4ff (diff)
downloadrust-309c469eece74cd9b83328d18302f1a177d0df7f.tar.gz
rust-309c469eece74cd9b83328d18302f1a177d0df7f.zip
Auto merge of #104875 - chenyukang:yukang/fix-104867-inc, r=estebank
Properly handle postfix inc/dec in standalone and subexpr scenarios

Fixes #104867
r? `@estebank`
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs50
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs15
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs4
-rw-r--r--src/test/ui/parser/increment-autofix-2.fixed63
-rw-r--r--src/test/ui/parser/increment-autofix-2.rs (renamed from src/test/ui/parser/increment-notfixed.rs)8
-rw-r--r--src/test/ui/parser/increment-autofix-2.stderr (renamed from src/test/ui/parser/increment-notfixed.stderr)26
-rw-r--r--src/test/ui/parser/issue-104867-inc-dec-2.rs52
-rw-r--r--src/test/ui/parser/issue-104867-inc-dec-2.stderr107
-rw-r--r--src/test/ui/parser/issue-104867-inc-dec.rs45
-rw-r--r--src/test/ui/parser/issue-104867-inc-dec.stderr81
10 files changed, 386 insertions, 65 deletions
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index c316a4dd6b4..0191ab730c8 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -159,8 +159,6 @@ enum IsStandalone {
     Standalone,
     /// It's a subexpression, i.e., *not* standalone.
     Subexpr,
-    /// It's maybe standalone; we're not sure.
-    Maybe,
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -213,14 +211,8 @@ impl MultiSugg {
         err.multipart_suggestion(&self.msg, self.patches, self.applicability);
     }
 
-    /// Overrides individual messages and applicabilities.
-    fn emit_many(
-        err: &mut Diagnostic,
-        msg: &str,
-        applicability: Applicability,
-        suggestions: impl Iterator<Item = Self>,
-    ) {
-        err.multipart_suggestions(msg, suggestions.map(|s| s.patches), applicability);
+    fn emit_verbose(self, err: &mut Diagnostic) {
+        err.multipart_suggestion_verbose(&self.msg, self.patches, self.applicability);
     }
 }
 
@@ -1267,12 +1259,10 @@ impl<'a> Parser<'a> {
         &mut self,
         operand_expr: P<Expr>,
         op_span: Span,
-        prev_is_semi: bool,
+        start_stmt: bool,
     ) -> PResult<'a, P<Expr>> {
-        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)
     }
 
@@ -1280,13 +1270,13 @@ impl<'a> Parser<'a> {
         &mut self,
         operand_expr: P<Expr>,
         op_span: Span,
+        start_stmt: bool,
     ) -> PResult<'a, P<Expr>> {
         let kind = IncDecRecovery {
-            standalone: IsStandalone::Maybe,
+            standalone: if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr },
             op: IncOrDec::Inc,
             fixity: UnaryFixity::Post,
         };
-
         self.recover_from_inc_dec(operand_expr, kind, op_span)
     }
 
@@ -1315,34 +1305,25 @@ impl<'a> Parser<'a> {
         };
 
         match kind.standalone {
-            IsStandalone::Standalone => self.inc_dec_standalone_suggest(kind, spans).emit(&mut err),
+            IsStandalone::Standalone => {
+                self.inc_dec_standalone_suggest(kind, spans).emit_verbose(&mut err)
+            }
             IsStandalone::Subexpr => {
                 let Ok(base_src) = self.span_to_snippet(base.span)
-                    else { return help_base_case(err, base) };
+                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)
+                        // won't suggest since we can not handle the precedences
+                        // for example: `a + b++` has been parsed (a + b)++ and we can not suggest here
+                        if !matches!(base.kind, ExprKind::Binary(_, _, _)) {
+                            self.postfix_inc_dec_suggest(base_src, kind, spans).emit(&mut err)
+                        }
                     }
                 }
             }
-            IsStandalone::Maybe => {
-                let Ok(base_src) = self.span_to_snippet(base.span)
-                    else { return help_base_case(err, base) };
-                let sugg1 = match kind.fixity {
-                    UnaryFixity::Pre => self.prefix_inc_dec_suggest(base_src, kind, spans),
-                    UnaryFixity::Post => self.postfix_inc_dec_suggest(base_src, kind, spans),
-                };
-                let sugg2 = self.inc_dec_standalone_suggest(kind, spans);
-                MultiSugg::emit_many(
-                    &mut err,
-                    "use `+= 1` instead",
-                    Applicability::Unspecified,
-                    [sugg1, sugg2].into_iter(),
-                )
-            }
         }
         Err(err)
     }
@@ -1392,7 +1373,6 @@ impl<'a> Parser<'a> {
         }
 
         patches.push((post_span, format!(" {}= 1", kind.op.chr())));
-
         MultiSugg {
             msg: format!("use `{}= 1` instead", kind.op.chr()),
             patches,
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 8a3545eb3be..c0ed450b985 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<Expr>),
+    AlreadyParsed(P<Expr>, bool), // (expr, starts_statement)
 }
 
 impl From<Option<AttrWrapper>> for LhsExpr {
@@ -101,7 +101,7 @@ impl From<P<Expr>> for LhsExpr {
     ///
     /// This conversion does not allocate.
     fn from(expr: P<Expr>) -> Self {
-        LhsExpr::AlreadyParsed(expr)
+        LhsExpr::AlreadyParsed(expr, false)
     }
 }
 
@@ -173,7 +173,9 @@ impl<'a> Parser<'a> {
         min_prec: usize,
         lhs: LhsExpr,
     ) -> PResult<'a, P<Expr>> {
-        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,7 +294,7 @@ 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)?;
+                lhs = self.recover_from_postfix_increment(lhs, op_span, starts_stmt)?;
                 continue;
             }
 
@@ -590,14 +592,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 42197e63797..bae7f2670cb 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -164,7 +164,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 {
@@ -198,7 +198,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-notfixed.rs b/src/test/ui/parser/increment-autofix-2.rs
index 15f159e53d2..ebe5fa6ca1e 100644
--- a/src/test/ui/parser/increment-notfixed.rs
+++ b/src/test/ui/parser/increment-autofix-2.rs
@@ -1,3 +1,5 @@
+// run-rustfix
+
 struct Foo {
     bar: Bar,
 }
@@ -35,7 +37,7 @@ pub fn post_while_tmp() {
 }
 
 pub fn post_field() {
-    let foo = Foo { bar: Bar { qux: 0 } };
+    let mut foo = Foo { bar: Bar { qux: 0 } };
     foo.bar.qux++;
     //~^ ERROR Rust has no postfix increment operator
     println!("{}", foo.bar.qux);
@@ -45,14 +47,14 @@ pub fn post_field_tmp() {
     struct S {
         tmp: i32
     }
-    let s = S { tmp: 0 };
+    let mut s = S { tmp: 0 };
     s.tmp++;
     //~^ ERROR Rust has no postfix increment operator
     println!("{}", s.tmp);
 }
 
 pub fn pre_field() {
-    let foo = Foo { bar: Bar { qux: 0 } };
+    let mut foo = Foo { bar: Bar { qux: 0 } };
     ++foo.bar.qux;
     //~^ ERROR Rust has no prefix increment operator
     println!("{}", foo.bar.qux);
diff --git a/src/test/ui/parser/increment-notfixed.stderr b/src/test/ui/parser/increment-autofix-2.stderr
index ae55ae06714..11e985480d6 100644
--- a/src/test/ui/parser/increment-notfixed.stderr
+++ b/src/test/ui/parser/increment-autofix-2.stderr
@@ -1,18 +1,16 @@
 error: Rust has no postfix increment operator
-  --> $DIR/increment-notfixed.rs:11:6
+  --> $DIR/increment-autofix-2.rs:13:6
    |
 LL |     i++;
    |      ^^ not a valid postfix operator
    |
 help: use `+= 1` instead
    |
-LL |     { let tmp = i; i += 1; tmp };
-   |     +++++++++++  ~~~~~~~~~~~~~~~
 LL |     i += 1;
    |       ~~~~
 
 error: Rust has no postfix increment operator
-  --> $DIR/increment-notfixed.rs:17:12
+  --> $DIR/increment-autofix-2.rs:19:12
    |
 LL |     while i++ < 5 {
    |     -----  ^^ not a valid postfix operator
@@ -23,24 +21,20 @@ help: use `+= 1` instead
    |
 LL |     while { let tmp = i; i += 1; tmp } < 5 {
    |           +++++++++++  ~~~~~~~~~~~~~~~
-LL |     while i += 1 < 5 {
-   |             ~~~~
 
 error: Rust has no postfix increment operator
-  --> $DIR/increment-notfixed.rs:25:8
+  --> $DIR/increment-autofix-2.rs:27:8
    |
 LL |     tmp++;
    |        ^^ not a valid postfix operator
    |
 help: use `+= 1` instead
    |
-LL |     { let tmp_ = tmp; tmp += 1; tmp_ };
-   |     ++++++++++++    ~~~~~~~~~~~~~~~~~~
 LL |     tmp += 1;
    |         ~~~~
 
 error: Rust has no postfix increment operator
-  --> $DIR/increment-notfixed.rs:31:14
+  --> $DIR/increment-autofix-2.rs:33:14
    |
 LL |     while tmp++ < 5 {
    |     -----    ^^ not a valid postfix operator
@@ -51,37 +45,31 @@ help: use `+= 1` instead
    |
 LL |     while { let tmp_ = tmp; tmp += 1; tmp_ } < 5 {
    |           ++++++++++++    ~~~~~~~~~~~~~~~~~~
-LL |     while tmp += 1 < 5 {
-   |               ~~~~
 
 error: Rust has no postfix increment operator
-  --> $DIR/increment-notfixed.rs:39:16
+  --> $DIR/increment-autofix-2.rs:41:16
    |
 LL |     foo.bar.qux++;
    |                ^^ not a valid postfix operator
    |
 help: use `+= 1` instead
    |
-LL |     { let tmp = foo.bar.qux; foo.bar.qux += 1; tmp };
-   |     +++++++++++            ~~~~~~~~~~~~~~~~~~~~~~~~~
 LL |     foo.bar.qux += 1;
    |                 ~~~~
 
 error: Rust has no postfix increment operator
-  --> $DIR/increment-notfixed.rs:49:10
+  --> $DIR/increment-autofix-2.rs:51:10
    |
 LL |     s.tmp++;
    |          ^^ not a valid postfix operator
    |
 help: use `+= 1` instead
    |
-LL |     { let tmp = s.tmp; s.tmp += 1; tmp };
-   |     +++++++++++      ~~~~~~~~~~~~~~~~~~~
 LL |     s.tmp += 1;
    |           ~~~~
 
 error: Rust has no prefix increment operator
-  --> $DIR/increment-notfixed.rs:56:5
+  --> $DIR/increment-autofix-2.rs:58:5
    |
 LL |     ++foo.bar.qux;
    |     ^^ not a valid prefix operator
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..a006421a975
--- /dev/null
+++ b/src/test/ui/parser/issue-104867-inc-dec-2.rs
@@ -0,0 +1,52 @@
+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
+    // won't suggest since we can not handle the precedences
+}
+
+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 test9() {
+    let mut i = 0;
+    let _ = (1 + 2 + i)++; //~ ERROR Rust has no postfix increment operator
+}
+
+fn test10() {
+    let mut i = 0;
+    let _ = (i++ + 1) + 2; //~ 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..4e2d0546851
--- /dev/null
+++ b/src/test/ui/parser/issue-104867-inc-dec-2.stderr
@@ -0,0 +1,107 @@
+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
+
+error: Rust has no postfix increment operator
+  --> $DIR/issue-104867-inc-dec-2.rs:24: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:29: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:34: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:39: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:44:24
+   |
+LL |     let _ = (1 + 2 + i)++;
+   |                        ^^ not a valid postfix operator
+   |
+help: use `+= 1` instead
+   |
+LL |     let _ = { let tmp = (1 + 2 + i); (1 + 2 + i) += 1; tmp };
+   |             +++++++++++            ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: Rust has no postfix increment operator
+  --> $DIR/issue-104867-inc-dec-2.rs:49:15
+   |
+LL |     let _ = (i++ + 1) + 2;
+   |               ^^ not a valid postfix operator
+   |
+help: use `+= 1` instead
+   |
+LL |     let _ = ({ let tmp = i; i += 1; tmp } + 1) + 2;
+   |              +++++++++++  ~~~~~~~~~~~~~~~
+
+error: aborting due to 10 previous errors
+
diff --git a/src/test/ui/parser/issue-104867-inc-dec.rs b/src/test/ui/parser/issue-104867-inc-dec.rs
new file mode 100644
index 00000000000..760c67b4bed
--- /dev/null
+++ b/src/test/ui/parser/issue-104867-inc-dec.rs
@@ -0,0 +1,45 @@
+struct S {
+    x: i32,
+}
+
+fn test1() {
+    let mut i = 0;
+    i++; //~ ERROR Rust has no postfix increment operator
+}
+
+fn test2() {
+    let s = S { x: 0 };
+    s.x++; //~ ERROR Rust has no postfix increment operator
+}
+
+fn test3() {
+    let mut i = 0;
+    if i++ == 1 {} //~ ERROR Rust has no postfix increment operator
+}
+
+fn test4() {
+    let mut i = 0;
+    ++i; //~ ERROR Rust has no prefix increment operator
+}
+
+fn test5() {
+    let mut i = 0;
+    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
new file mode 100644
index 00000000000..78bfd3e82f0
--- /dev/null
+++ b/src/test/ui/parser/issue-104867-inc-dec.stderr
@@ -0,0 +1,81 @@
+error: Rust has no postfix increment operator
+  --> $DIR/issue-104867-inc-dec.rs:7:6
+   |
+LL |     i++;
+   |      ^^ not a valid postfix operator
+   |
+help: use `+= 1` instead
+   |
+LL |     i += 1;
+   |       ~~~~
+
+error: Rust has no postfix increment operator
+  --> $DIR/issue-104867-inc-dec.rs:12:8
+   |
+LL |     s.x++;
+   |        ^^ not a valid postfix operator
+   |
+help: use `+= 1` instead
+   |
+LL |     s.x += 1;
+   |         ~~~~
+
+error: Rust has no postfix increment operator
+  --> $DIR/issue-104867-inc-dec.rs:17:9
+   |
+LL |     if i++ == 1 {}
+   |         ^^ not a valid postfix operator
+   |
+help: use `+= 1` instead
+   |
+LL |     if { let tmp = i; i += 1; tmp } == 1 {}
+   |        +++++++++++  ~~~~~~~~~~~~~~~
+
+error: Rust has no prefix increment operator
+  --> $DIR/issue-104867-inc-dec.rs:22:5
+   |
+LL |     ++i;
+   |     ^^ not a valid prefix operator
+   |
+help: use `+= 1` instead
+   |
+LL -     ++i;
+LL +     i += 1;
+   |
+
+error: Rust has no prefix increment operator
+  --> $DIR/issue-104867-inc-dec.rs:27:8
+   |
+LL |     if ++i == 1 { }
+   |        ^^ not a valid prefix operator
+   |
+help: use `+= 1` instead
+   |
+LL |     if { i += 1; i } == 1 { }
+   |        ~   +++++++++
+
+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
+