From 8dac2b156617bb21dcd732ac1939cb10e3abc53d Mon Sep 17 00:00:00 2001
From: Joe Groff <jgroff@apple.com>
Date: Fri, 11 Apr 2025 12:21:54 -0700
Subject: [PATCH] SILGen: Emit `copy x` on a trivial value as a trivial copy.

Avoids an assertion failure emitting an `explicit_copy_value` on the trivial
value, which is unsupported. This allows `copy x` to compile, albeit with
no effect (which is not ideal, but also not a regression, since no-implicit-copy
controls still don't fully work on trivial values). Fixes #80573 and rdar://148712387.
---
 lib/SILGen/SILGenExpr.cpp   | 8 ++++++++
 test/SILGen/copy_expr.swift | 6 ++++++
 2 files changed, 14 insertions(+)

diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index 4341c4d024efd..b1c1ac1e1a010 100644
--- a/lib/SILGen/SILGenExpr.cpp
+++ b/lib/SILGen/SILGenExpr.cpp
@@ -7178,6 +7178,14 @@ RValue RValueEmitter::visitCopyExpr(CopyExpr *E, SGFContext C) {
     auto address = SGF.emitAddressOfLValue(subExpr, std::move(lv));
 
     if (subType.isLoadable(SGF.F)) {
+      // Trivial types don't undergo any lifetime analysis, so simply load
+      // the value.
+      if (subType.isTrivial(SGF.F)
+          && !address.getType().isMoveOnlyWrapped()) {
+        return RValue(SGF, {SGF.B.createLoadCopy(E, address)},
+                      subType.getASTType());
+      }
+
       // Use a formal access load borrow so this closes in the writeback scope
       // above.
       ManagedValue value = SGF.B.createFormalAccessLoadBorrow(E, address);
diff --git a/test/SILGen/copy_expr.swift b/test/SILGen/copy_expr.swift
index 1cb51175f879e..2469df79f25c5 100644
--- a/test/SILGen/copy_expr.swift
+++ b/test/SILGen/copy_expr.swift
@@ -439,3 +439,9 @@ func testCallMethodOnAddressOnlyInOutCopy<T : P>(_ x: inout T) {
   _ = (copy x).computedK
   _ = (copy x).consumingComputedK
 }
+
+struct Trivial: BitwiseCopyable { var x: Int }
+
+func copyTrivial(x: inout Trivial) -> Trivial {
+    return copy x
+}