From df8ab6ee0bb76d872ef6b666ce871b0d8829b24b Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Fri, 12 Sep 2025 11:20:57 -0700 Subject: [PATCH] SILGen: Don't copy_addr [take] trivial address-only values. This is a new case that comes up with `InlineArray`, since an `InlineArray` with unknown count but known trivial element type is trivial but still address-only due to its unknown size. We are inconsistent about whether we emit formal copies or not of these values; they should generally be unnecessary as long as the memory location of a value is sufficiently long-lived, but the SIL verifier still reasonably considers a `[take]` as an invalidation of the memory, even though at runtime a take is a no-op. Since the take is unnecessary, we can just not take when we copy out of a trivial address location. Fixes #84141 | rdar://160007939. --- lib/SILGen/SILGenLValue.cpp | 4 +++- test/SILGen/trivial_address_only_switch.swift | 15 +++++++++++++++ test/SILGen/variadic-generic-tuples.swift | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 test/SILGen/trivial_address_only_switch.swift diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index 2c906ddb64c..23df4448b9f 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -5234,7 +5234,9 @@ void SILGenFunction::emitSemanticStore(SILLocation loc, assert(!silConv.useLoweredAddresses() || (dest->getType().isAddressOnly(F) == rvalue->getType().isAddress())); if (rvalue->getType().isAddress()) { - B.createCopyAddr(loc, rvalue, dest, IsTake, isInit); + B.createCopyAddr(loc, rvalue, dest, + rvalue->getType().isTrivial(F) ? IsNotTake : IsTake, + isInit); } else { emitUnloweredStoreOfCopy(B, loc, rvalue, dest, isInit); } diff --git a/test/SILGen/trivial_address_only_switch.swift b/test/SILGen/trivial_address_only_switch.swift new file mode 100644 index 00000000000..8a272250b80 --- /dev/null +++ b/test/SILGen/trivial_address_only_switch.swift @@ -0,0 +1,15 @@ +// RUN: %target-swift-emit-silgen -verify -disable-availability-checking %s + +public enum StreamYieldResult: Sendable { + case literal(buffer: InlineArray) + case end(buffer: InlineArray, endIndex: Int) + + public func buffer() -> InlineArray { + switch self { + case .literal(let b): + return b + case .end(let b, _): + return b + } + } +} diff --git a/test/SILGen/variadic-generic-tuples.swift b/test/SILGen/variadic-generic-tuples.swift index 6c63a488110..007253c2be7 100644 --- a/test/SILGen/variadic-generic-tuples.swift +++ b/test/SILGen/variadic-generic-tuples.swift @@ -102,7 +102,7 @@ public struct Container { // Finally, the actual assignment. // CHECK-NEXT: [[ACCESS:%.*]] = begin_access [modify] [unknown] %1 : // CHECK-NEXT: [[FIELD:%.*]] = struct_element_addr [[ACCESS]] : $*Container, #Container.storage -// CHECK-NEXT: copy_addr [take] [[COPY2]] to [[FIELD]] : $*(repeat Stored) +// CHECK-NEXT: copy_addr [[COPY2]] to [[FIELD]] : $*(repeat Stored) // CHECK-NEXT: end_access [[ACCESS]] // Clean up. // CHECK-NEXT: dealloc_stack [[COPY2]]