tint: Fix RemovePhonies with @must_use fns

Fixed: tint:1873
Change-Id: I72b47d5d3e406345fee16073e612b0f0cf19798e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/124300
Commit-Queue: Ben Clayton <bclayton@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/tint/transform/remove_phonies.cc b/src/tint/transform/remove_phonies.cc
index b6d877d..e5aecd2 100644
--- a/src/tint/transform/remove_phonies.cc
+++ b/src/tint/transform/remove_phonies.cc
@@ -88,10 +88,22 @@
                     }
 
                     if (side_effects.size() == 1) {
-                        if (auto* call = side_effects[0]->As<ast::CallExpression>()) {
+                        if (auto* call_expr = side_effects[0]->As<ast::CallExpression>()) {
                             // Phony assignment with single call side effect.
-                            // Replace phony assignment with call.
-                            ctx.Replace(stmt, [&, call] { return b.CallStmt(ctx.Clone(call)); });
+                            auto* call = sem.Get(call_expr)->Unwrap()->As<sem::Call>();
+                            if (call->Target()->MustUse()) {
+                                // Replace phony assignment assignment to uniquely named let.
+                                ctx.Replace<ast::Statement>(stmt, [&, call_expr] {  //
+                                    auto name = b.Symbols().New("tint_phony");
+                                    auto* rhs = ctx.Clone(call_expr);
+                                    return b.Decl(b.Let(name, rhs));
+                                });
+                            } else {
+                                // Replace phony assignment with call statement.
+                                ctx.Replace(stmt, [&, call_expr] {  //
+                                    return b.CallStmt(ctx.Clone(call_expr));
+                                });
+                            }
                             return;
                         }
                     }
diff --git a/src/tint/transform/remove_phonies_test.cc b/src/tint/transform/remove_phonies_test.cc
index dc91b5a..60252a1 100644
--- a/src/tint/transform/remove_phonies_test.cc
+++ b/src/tint/transform/remove_phonies_test.cc
@@ -131,6 +131,60 @@
     EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RemovePhoniesTest, SingleSideEffectsMustUse) {
+    auto* src = R"(
+@must_use
+fn neg(a : i32) -> i32 {
+  return -(a);
+}
+
+@must_use
+fn add(a : i32, b : i32) -> i32 {
+  return (a + b);
+}
+
+fn f() {
+  let tint_phony = 42;
+  _ = neg(1);
+  _ = 100 + add(2, 3) + 200;
+  _ = add(neg(4), neg(5)) + 6;
+  _ = u32(neg(6));
+  _ = f32(add(7, 8));
+  _ = vec2<f32>(f32(neg(9)));
+  _ = vec3<i32>(1, neg(10), 3);
+  _ = mat2x2<f32>(1.0, f32(add(11, 12)), 3.0, 4.0);
+}
+)";
+
+    auto* expect = R"(
+@must_use
+fn neg(a : i32) -> i32 {
+  return -(a);
+}
+
+@must_use
+fn add(a : i32, b : i32) -> i32 {
+  return (a + b);
+}
+
+fn f() {
+  let tint_phony = 42;
+  let tint_phony_1 = neg(1);
+  let tint_phony_2 = add(2, 3);
+  let tint_phony_3 = add(neg(4), neg(5));
+  let tint_phony_4 = neg(6);
+  let tint_phony_5 = add(7, 8);
+  let tint_phony_6 = neg(9);
+  let tint_phony_7 = neg(10);
+  let tint_phony_8 = add(11, 12);
+}
+)";
+
+    auto got = Run<RemovePhonies>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RemovePhoniesTest, SingleSideEffects_OutOfOrder) {
     auto* src = R"(
 fn f() {
@@ -185,6 +239,7 @@
   return -(a);
 }
 
+@must_use
 fn add(a : i32, b : i32) -> i32 {
   return (a + b);
 }
@@ -206,6 +261,7 @@
   return -(a);
 }
 
+@must_use
 fn add(a : i32, b : i32) -> i32 {
   return (a + b);
 }