about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs27
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs7
-rw-r--r--tests/ui/binop/false-binop-caused-by-missing-semi.fixed10
-rw-r--r--tests/ui/binop/false-binop-caused-by-missing-semi.rs10
-rw-r--r--tests/ui/binop/false-binop-caused-by-missing-semi.stderr17
5 files changed, 71 insertions, 0 deletions
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 8bcec3273d8..bb21b027cc9 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -959,12 +959,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Applicability::MachineApplicable,
             );
         });
+        self.check_for_missing_semi(lhs, &mut err);
 
         adjust_err(&mut err);
 
         err.emit();
     }
 
+    /// Check if the expression that could not be assigned to was a typoed expression that
+    pub fn check_for_missing_semi(
+        &self,
+        expr: &'tcx hir::Expr<'tcx>,
+        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+    ) -> bool {
+        if let hir::ExprKind::Binary(binop, lhs, rhs) = expr.kind
+            && let hir::BinOpKind::Mul = binop.node
+            && self.tcx.sess.source_map().is_multiline(lhs.span.between(rhs.span))
+            && rhs.is_syntactic_place_expr()
+        {
+            //      v missing semicolon here
+            // foo()
+            // *bar = baz;
+            // (#80446).
+            err.span_suggestion_verbose(
+                lhs.span.shrink_to_hi(),
+                "you might have meant to write a semicolon here",
+                ";".to_string(),
+                Applicability::MachineApplicable,
+            );
+            return true;
+        }
+        false
+    }
+
     // Check if an expression `original_expr_id` comes from the condition of a while loop,
     /// as opposed from the body of a while loop, which we can naively check by iterating
     /// parents until we find a loop...
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index d0d3b0e5b73..f40406c6726 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -379,6 +379,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         (err, output_def_id)
                     }
                 };
+                if self.check_for_missing_semi(expr, &mut err)
+                    && let hir::Node::Expr(expr) = self.tcx.hir().get_parent(expr.hir_id)
+                    && let hir::ExprKind::Assign(..) = expr.kind
+                {
+                    // We defer to the later error produced by `check_lhs_assignable`.
+                    err.delay_as_bug();
+                }
 
                 let suggest_deref_binop =
                     |err: &mut DiagnosticBuilder<'_, _>, lhs_deref_ty: Ty<'tcx>| {
diff --git a/tests/ui/binop/false-binop-caused-by-missing-semi.fixed b/tests/ui/binop/false-binop-caused-by-missing-semi.fixed
new file mode 100644
index 00000000000..b47372c9064
--- /dev/null
+++ b/tests/ui/binop/false-binop-caused-by-missing-semi.fixed
@@ -0,0 +1,10 @@
+// run-rustfix
+fn foo() {}
+fn main() {
+    let mut y = 42;
+    let x = &mut y;
+    foo();
+    *x = 0;  //~ ERROR invalid left-hand side of assignment
+    let _ = x;
+    println!("{y}");
+}
diff --git a/tests/ui/binop/false-binop-caused-by-missing-semi.rs b/tests/ui/binop/false-binop-caused-by-missing-semi.rs
new file mode 100644
index 00000000000..14671de7e51
--- /dev/null
+++ b/tests/ui/binop/false-binop-caused-by-missing-semi.rs
@@ -0,0 +1,10 @@
+// run-rustfix
+fn foo() {}
+fn main() {
+    let mut y = 42;
+    let x = &mut y;
+    foo()
+    *x = 0;  //~ ERROR invalid left-hand side of assignment
+    let _ = x;
+    println!("{y}");
+}
diff --git a/tests/ui/binop/false-binop-caused-by-missing-semi.stderr b/tests/ui/binop/false-binop-caused-by-missing-semi.stderr
new file mode 100644
index 00000000000..fca042b1c57
--- /dev/null
+++ b/tests/ui/binop/false-binop-caused-by-missing-semi.stderr
@@ -0,0 +1,17 @@
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/false-binop-caused-by-missing-semi.rs:7:8
+   |
+LL | /     foo()
+LL | |     *x = 0;
+   | |      - ^
+   | |______|
+   |        cannot assign to this expression
+   |
+help: you might have meant to write a semicolon here
+   |
+LL |     foo();
+   |          +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0070`.