From 75d5f107ddbac9e0872f1551e70dfbf5d441f3e0 Mon Sep 17 00:00:00 2001
From: Morten Lohne <lohnemorten@gmail.com>
Date: Thu, 10 Aug 2023 01:14:19 +0200
Subject: [PATCH] Bugfix: 'can_have_side_effects()' would return 'false' for
 struct/enum/array/tuple literals unless *all* sub-expressions had side
 effects. This would easily allow side effects to slip through, and also
 wrongly label empty literals as having side effects. Add some tests for the
 last point

---
 compiler/rustc_hir/src/hir.rs                 |  4 +--
 .../in-trait/return-type-suggestion.rs        |  1 -
 .../in-trait/return-type-suggestion.stderr    |  4 +--
 tests/ui/return/return-struct.rs              | 24 +++++++++++++
 tests/ui/return/return-struct.stderr          | 35 +++++++++++++++++++
 5 files changed, 62 insertions(+), 6 deletions(-)
 create mode 100644 tests/ui/return/return-struct.rs
 create mode 100644 tests/ui/return/return-struct.stderr

diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 92a91766d91..6340f1dcca1 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1843,7 +1843,7 @@ impl Expr<'_> {
                 .iter()
                 .map(|field| field.expr)
                 .chain(init.into_iter())
-                .all(|e| e.can_have_side_effects()),
+                .any(|e| e.can_have_side_effects()),
 
             ExprKind::Array(args)
             | ExprKind::Tup(args)
@@ -1857,7 +1857,7 @@ impl Expr<'_> {
                     ..
                 },
                 args,
-            ) => args.iter().all(|arg| arg.can_have_side_effects()),
+            ) => args.iter().any(|arg| arg.can_have_side_effects()),
             ExprKind::If(..)
             | ExprKind::Match(..)
             | ExprKind::MethodCall(..)
diff --git a/tests/ui/async-await/in-trait/return-type-suggestion.rs b/tests/ui/async-await/in-trait/return-type-suggestion.rs
index 92a9e035e89..cdab4ea0f37 100644
--- a/tests/ui/async-await/in-trait/return-type-suggestion.rs
+++ b/tests/ui/async-await/in-trait/return-type-suggestion.rs
@@ -6,7 +6,6 @@ trait A {
     async fn e() {
         Ok(())
         //~^ ERROR mismatched types
-        //~| HELP consider using a semicolon here
     }
 }
 
diff --git a/tests/ui/async-await/in-trait/return-type-suggestion.stderr b/tests/ui/async-await/in-trait/return-type-suggestion.stderr
index d9309459812..179c9ed93db 100644
--- a/tests/ui/async-await/in-trait/return-type-suggestion.stderr
+++ b/tests/ui/async-await/in-trait/return-type-suggestion.stderr
@@ -2,9 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/return-type-suggestion.rs:7:9
    |
 LL |         Ok(())
-   |         ^^^^^^- help: consider using a semicolon here: `;`
-   |         |
-   |         expected `()`, found `Result<(), _>`
+   |         ^^^^^^ expected `()`, found `Result<(), _>`
    |
    = note: expected unit type `()`
                    found enum `Result<(), _>`
diff --git a/tests/ui/return/return-struct.rs b/tests/ui/return/return-struct.rs
new file mode 100644
index 00000000000..446445c17ba
--- /dev/null
+++ b/tests/ui/return/return-struct.rs
@@ -0,0 +1,24 @@
+struct S;
+
+enum Age {
+    Years(i64, i64)
+}
+
+fn foo() {
+    let mut age = 29;
+    Age::Years({age += 1; age}, 55)
+    //~^ ERROR mismatched types
+}
+
+fn bar() {
+    let mut age = 29;
+    Age::Years(age, 55)
+    //~^ ERROR mismatched types
+}
+
+fn baz() {
+    S
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/return/return-struct.stderr b/tests/ui/return/return-struct.stderr
new file mode 100644
index 00000000000..e6c0363e363
--- /dev/null
+++ b/tests/ui/return/return-struct.stderr
@@ -0,0 +1,35 @@
+error[E0308]: mismatched types
+  --> $DIR/return-struct.rs:9:5
+   |
+LL |     Age::Years({age += 1; age}, 55)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Age`
+   |
+help: consider using a semicolon here
+   |
+LL |     Age::Years({age += 1; age}, 55);
+   |                                    +
+help: try adding a return type
+   |
+LL | fn foo() -> Age {
+   |          ++++++
+
+error[E0308]: mismatched types
+  --> $DIR/return-struct.rs:15:5
+   |
+LL | fn bar() {
+   |          - help: try adding a return type: `-> Age`
+LL |     let mut age = 29;
+LL |     Age::Years(age, 55)
+   |     ^^^^^^^^^^^^^^^^^^^ expected `()`, found `Age`
+
+error[E0308]: mismatched types
+  --> $DIR/return-struct.rs:20:5
+   |
+LL | fn baz() {
+   |          - help: try adding a return type: `-> S`
+LL |     S
+   |     ^ expected `()`, found `S`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.