# "Copy of noncopyable typed value" bug

**URL:** <https://forums.swift.org/t/copy-of-noncopyable-typed-value-bug/84873>\
**Category:** Compiler\
**Tags:** bug, noncopyable, ~copyable\
**Created:** [February 21, 2026, 12:35pm UTC](https://forums.swift.org/t/copy-of-noncopyable-typed-value-bug/84873 "2026-02-21T12:35:30Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![jeremyabannister](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jeremyabannister/32/10143_2.png) [@jeremyabannister](https://forums.swift.org/u/jeremyabannister)\
**Post date:** [February 21, 2026, 12:35pm UTC](https://forums.swift.org/t/copy-of-noncopyable-typed-value-bug/84873/1 "2026-02-21T12:35:30Z")

</div>

The following code hits a compiler bug:

```swift
struct A: ~Copyable {}

struct B: ~Copyable {
    var a: A?
}

func make() -> sending B {
    B(a: nil)
}

func f() {
    let b = make().a // Error: Copy of noncopyable typed value. This is a compiler bug. Please file a bug with a small example of the bug
    _ = b
}

```

I've filed an [issue](https://github.com/swiftlang/swift/issues/87396), but I like to also post these things here out of curiosity to hear a bit about what's going on under the hood.

---

<div class="post-metadata">

**Author:** ![ramonasuncion](https://avatars.discourse-cdn.com/v4/letter/r/6a8cbe/32.png) [@ramonasuncion](https://forums.swift.org/u/ramonasuncion)\
**Post date:** [February 21, 2026, 2:37pm UTC](https://forums.swift.org/t/copy-of-noncopyable-typed-value-bug/84873/2 "2026-02-21T14:37:37Z")

</div>

Yeah, if anyone wants to contribute, this seems to belong to the same compiler bug family as [#85576](https://github.com/swiftlang/swift/issues/85576), [#87141](https://github.com/swiftlang/swift/issues/87141), [#73156](https://github.com/swiftlang/swift/issues/73156), [#80724](https://github.com/swiftlang/swift/issues/80724), [#82261](https://github.com/swiftlang/swift/issues/82261), [#76775](https://github.com/swiftlang/swift/issues/76775), and [#72651](https://github.com/swiftlang/swift/issues/72651)

---

<div class="post-metadata">

**Author:** ![ben-lev](https://avatars.discourse-cdn.com/v4/letter/b/90ced4/32.png) [@ben-lev](https://forums.swift.org/u/ben-lev)\
**Post date:** [February 21, 2026, 9:57pm UTC](https://forums.swift.org/t/copy-of-noncopyable-typed-value-bug/84873/3 "2026-02-21T21:57:07Z")

</div>

> curiosity to hear a bit about what's going on under the hood.

I’m not at all an expert on this, but curious too so we can take a peek at the SIL in a similar passing case, then compare:

If it’s written to make the ‘`consuming` nature’ of the situation clear, it seems to compile fine:

```swift
struct A: ~Copyable {}

struct B: ~Copyable {
  var a: A?
  
  consuming func takeA() -> A? { a }
}

func make() -> sending B {
    B(a: nil)
}

func f() {
  let b = make().takeA()
  _ = b
}

```

In the above version the core SILGen emitted for `f`:

```swift
   %0 = alloc_box ${ let Optional<A> }, let, name "b" // users: %13, %1
   %1 = begin_borrow [lexical] [var_decl] %0 // users: %12, %2
   %2 = project_box %1, 0 // users: %8, %7
   // function_ref make()
   %3 = function_ref @$s8snippet24makeAA1BVyF : $@convention(thin) () -> @sil_sending @owned B // user: %4
   %4 = apply %3() : $@convention(thin) () -> @sil_sending @owned B // user: %6
   // function_ref B.takeA()
   %5 = function_ref @$s8snippet21BV5takeAAA1AVSgyF : $@convention(method) (@owned B) -> @owned Optional<A> // user: %6
   %6 = apply %5(%4) : $@convention(method) (@owned B) -> @owned Optional<A> // user: %7
   store %6 to [init] %2 // id: %7
   %8 = mark_unresolved_non_copyable_value [no_consume_or_assign] %2 // user: %9
   %9 = load_borrow %8 // users: %11, %10
   ignored_use %9 // id: %10
   end_borrow %9 // id: %11
   end_borrow %1 // id: %12
   destroy_value %0 // id: %13

```

Note here there’s no explicit copies in the IR. We make a stack slot for the `Optional<A>`, invoke `make() -> B`, then call `takeA() → A?` on the returned value, and `store` it into that original stack slot (`store %6 to [init] %2`). That is a pretty direct “ **move** `make().takeA() into b`” I assume.

One more maybe relevant passing case to compare to:

```swift
func f() {
  let b = make()
  let a = b.a
  _ = a
}

```

This one works and is semantically almost identical to what you wrote. The SILGen is:

```swift
  %0 = alloc_stack [lexical] [var_decl] $B, let, name "b", type $B // users: %3, %5, %13
  // function_ref make()
  %1 = function_ref @$s8snippet34makeAA1BVyF : $@convention(thin) () -> @sil_sending @owned B // user: %2
  %2 = apply %1() : $@convention(thin) () -> @sil_sending @owned B // user: %3
  store %2 to %0 // id: %3
  %4 = alloc_stack [lexical] [var_decl] $Optional<A>, let, name "a", type $Optional<A> // users: %9, %8, %11, %12
  %5 = struct_element_addr %0, #B.a // user: %6
  %6 = load %5 // user: %8
  debug_value undef : $*B, let, name "b" // id: %7
  store %6 to %4 // id: %8
  %9 = load %4
  debug_value undef : $*Optional<A>, let, name "a" // id: %10
  destroy_addr %4 // id: %11
  dealloc_stack %4 // id: %12
  dealloc_stack %0 // id: %13

```

In this one again no explicit copy. It puts `b` on the stack, grabs the address of `b.a` , loads it (not sure how the compiler thinks about this in terms of whether or not it constitutes a ‘copy’, but it’s not a literal `copy_value`), and then stores it to `a`.

Now in the failing source (so `make().a` instead of `make().takeA()`), SILGen emits:

```swift
   %0 = alloc_box ${ let Optional<A> }, let, name "b" // users: %16, %1
   %1 = begin_borrow [lexical] [var_decl] %0 // users: %15, %2
   %2 = project_box %1, 0 // users: %11, %10
   // function_ref make()
   %3 = function_ref @$s8snippet14makeAA1BVyF : $@convention(thin) () -> @sil_sending @owned B // user: %4
   %4 = apply %3() : $@convention(thin) () -> @sil_sending @owned B // users: %9, %5
   %5 = begin_borrow %4 // users: %8, %6
   %6 = struct_extract %5, #B.a // user: %7
   %7 = copy_value %6 // user: %10
   end_borrow %5 // id: %8
   destroy_value %4 // id: %9
   store %7 to [init] %2 // id: %10
   %11 = mark_unresolved_non_copyable_value [no_consume_or_assign] %2 // user: %12
   %12 = load_borrow %11 // users: %14, %13
   ignored_use %12 // id: %13
   end_borrow %12 // id: %14
   end_borrow %1 // id: %15
   destroy_value %0 // id: %16

```

The IR is pretty similar here, except now to extract the `a` from the returned `B` it does:

```swift
   %4 = apply %3() : $@convention(thin) () -> @sil_sending @owned B // users: %9, %5
   %5 = begin_borrow %4 // users: %8, %6
   %6 = struct_extract %5, #B.a // user: %7
   %7 = copy_value %6 // user: %10
   end_borrow %5 // id: %8
   destroy_value %4 // id: %9
   store %7 to [init] %2 // id: %10

```

It does an explicit copy of `make().a` with the `copy_value`, then stores the copy into the original stack slot. I’m assuming that is (part of?) the issue.

As someone with very little knowledge on the compiler architecture, I can’t comment on whether it’s that SILGen shouldn’t have emitted the copy, or some downstream pass should realize it can eliminate the copy to make it legal, or some other option altogether. But anyway there’s some of the IR out of interest 😃

---

<div class="post-metadata">

**Author:** ![ibex](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ibex/32/30439_2.png) [@ibex](https://forums.swift.org/u/ibex)\
**Post date:** [February 21, 2026, 11:15pm UTC](https://forums.swift.org/t/copy-of-noncopyable-typed-value-bug/84873/4 "2026-02-21T23:15:12Z")

</div>

> [@jeremyabannister](#):
>
> ```swift
> struct A: ~Copyable {}
> 
> struct B: ~Copyable {
> var a: A?
> }
> 
> func make() -> sending B {
> B(a: nil)
> }
> 
> func f() {
> let b = make().a // Error: Copy of noncopyable typed value. This is a compiler bug. Please file a bug with a small example of the bug
> _ = b
> }
> 
> ```

This compiles:

```swift
struct A: ~Copyable {}

struct B: ~Copyable {
    var a: A?
}

func make() -> sending B {
    B(a: nil)
}

func g() {
    let b = make()
    _ = b.a
}

```

What is the difference?

---

<div class="post-metadata">

**Author:** ![jamieQ](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jamieq/32/5117_2.png) [@jamieQ](https://forums.swift.org/u/jamieQ)\
**Post date:** [February 22, 2026, 1:10am UTC](https://forums.swift.org/t/copy-of-noncopyable-typed-value-bug/84873/5 "2026-02-22T01:10:05Z")

</div>

one difference i think is that in your case the '`B`' variable is an l-value and in the original example it's an r-value. perhaps that has something to do with it? as Ben pointed out though, if you make the 'consumingness' explicit the r-value version also works.
