Skip to content

SIL verification failed: result of struct_element_addr does not match type of field #85474

@clackary

Description

@clackary

Description

We ran into a crash while building a project in release mode.

Isolating it as best I can, it seems to happen when specializing a function that applies a stored closure returning a generic existential type.

Reproduction

// Minimal protocol with associated type
protocol P<Shape> {
    associatedtype Shape
}

// Builder stores a closure returning the constrained existential
struct Builder<A> {
    let f: () -> any P<A> // Dropping the constraint on P avoids the crash
                          // i.e. `let f: () -> any P`
}

// Array helper
extension Array {
    func resolve<A>() -> [any P]
        where Element == Builder<A>
    {
        map { $0.f() }
    }
}

// Concrete witness and concrete type to specialize
struct Concrete<S>: P { typealias Shape = S }
struct X {}

_ = [
    Builder<X>.init { Concrete<X>() }
].resolve()

I've minimized down to the above code in a single file, compiling with optimizations: swiftc -O repro.swift

Note that it compiles successfully without optimizations, so -O is required.

As I was working to minimize the reproducer, I noticed that dropping the constraint on the existential P in Builder's f return type caused compilation to succeed, so that seems like a clue as to where the bug is.

Stack dump

SIL verification failed: result of struct_element_addr does not match type of field
  $*@callee_guaranteed () -> @out any P<X>
  $*@callee_guaranteed @substituted <τ_0_0> () -> @out any P<τ_0_0> for <X>
Verifying instruction:
     %56 = store_borrow %54 to %55 : $*Builder<X> // users: %62, %57
->   %57 = struct_element_addr %56 : $*Builder<X>, #Builder.f // user: %58
     %58 = load_borrow %57 : $*@callee_guaranteed @substituted <τ_0_0> () -> @out any P<τ_0_0> for <X> // users: %61, %60
In function:
// specialized Array.resolve<A>()
sil shared [ossa] @$sSa4mainE7resolveSayAA1P_pGyAA7BuilderVyqd__GRszlFAA1XV_Tg5 : $@convention(method) (@guaranteed Array<Builder<X>>) -> @owned Array<any P> {
// %0 "self"                                      // users: %53, %51, %3, %1
bb0(%0 : @guaranteed $Array<Builder<X>>):
  debug_value %0, let, name "self", argno 1       // id: %1
  // function_ref specialized Array.count.getter
  %2 = function_ref @$sSa5countSivg4main7BuilderVyAB1XVG_Tg5 : $@convention(method) (@guaranteed Array<Builder<X>>) -> Int // user: %3
  %3 = apply %2(%0) : $@convention(method) (@guaranteed Array<Builder<X>>) -> Int // users: %19, %5
  %4 = integer_literal $Builtin.Int64, 0          // users: %33, %37, %41, %20, %8, %6
  %5 = struct_extract %3, #Int._value             // users: %33, %84, %43, %20, %6
  %6 = builtin "cmp_eq_Int64"(%5, %4) : $Builtin.Int1 // user: %7
  cond_br %6, bb1, bb2                            // id: %7

bb1:                                              // Preds: bb0
  %8 = struct $Int (%4)                           // user: %10
  // function_ref specialized static Array._allocateUninitialized(_:)
  %9 = function_ref @$sSa22_allocateUninitializedySayxG_SpyxGtSiFZ4main1P_p_Tt0g5 : $@convention(thin) (Int) -> (@owned Array<any P>, UnsafeMutablePointer<any P>) // user: %10
  %10 = apply %9(%8) : $@convention(thin) (Int) -> (@owned Array<any P>, UnsafeMutablePointer<any P>) // user: %11
  (%11, %12) = destructure_tuple %10              // user: %13
  br bb3(%11)                                     // id: %13

bb2:                                              // Preds: bb0
  %14 = alloc_stack [var_decl] $ContiguousArray<any P> // users: %93, %86, %82, %81, %80, %28, %70, %19, %17
  // function_ref specialized ContiguousArray.init()
  %15 = function_ref @$ss15ContiguousArrayVAByxGycfC4main1P_p_Ttg5 : $@convention(thin) () -> @owned ContiguousArray<any P> // user: %16
  %16 = apply %15() : $@convention(thin) () -> @owned ContiguousArray<any P> // user: %17
  store %16 to [init] %14                         // id: %17
  // function_ref specialized ContiguousArray.reserveCapacity(_:)
  %18 = function_ref @$ss15ContiguousArrayV15reserveCapacityyySiF4main1P_p_Tg5 : $@convention(method) (Int, @inout ContiguousArray<any P>) -> () // user: %19
  %19 = apply %18(%3, %14) : $@convention(method) (Int, @inout ContiguousArray<any P>) -> ()
  %20 = builtin "cmp_slt_Int64"(%5, %4) : $Builtin.Int1 // user: %21
  cond_fail %20, "Range requires lowerBound <= upperBound" // id: %21
  %22 = integer_literal $Builtin.Int1, -1         // users: %46, %44
  %23 = integer_literal $Builtin.Int64, 1         // user: %46
  // function_ref specialized Array._hoistableIsNativeTypeChecked()
  %24 = function_ref @$sSa29_hoistableIsNativeTypeCheckedSbyF4main7BuilderVyAB1XVG_Tg5 : $@convention(method) (@guaranteed Array<Builder<X>>) -> Bool // user: %51
  // function_ref specialized Array._checkSubscript(_:wasNativeTypeChecked:)
  %25 = function_ref @$sSa15_checkSubscript_20wasNativeTypeCheckeds16_DependenceTokenVSi_SbtF4main7BuilderVyAE1XVG_Tg5 : $@convention(method) (Int, Bool, @guaranteed Array<Builder<X>>) -> _DependenceToken
  // function_ref specialized Array._getElement(_:wasNativeTypeChecked:matchingSubscriptCheck:)
  %26 = function_ref @$sSa11_getElement_20wasNativeTypeChecked22matchingSubscriptCheckxSi_Sbs16_DependenceTokenVtF4main7BuilderVyAF1XVG_Tg5 : $@convention(method) (Int, Bool, _DependenceToken, @guaranteed Array<Builder<X>>) -> @owned Builder<X> // user: %53
  // function_ref specialized ContiguousArray._makeUniqueAndReserveCapacityIfNotUnique()
  %27 = function_ref @$ss15ContiguousArrayV034_makeUniqueAndReserveCapacityIfNotD0yyF4main1P_p_Tg5 : $@convention(method) (@inout ContiguousArray<any P>) -> () // user: %70
  %28 = struct_element_addr %14, #ContiguousArray._buffer // user: %29
  %29 = struct_element_addr %28, #_ContiguousArrayBuffer._storage // user: %71
  // function_ref specialized ContiguousArray._reserveCapacityAssumingUniqueBuffer(oldCount:)
  %30 = function_ref @$ss15ContiguousArrayV36_reserveCapacityAssumingUniqueBuffer8oldCountySi_tF4main1P_p_Tg5 : $@convention(method) (Int, @inout ContiguousArray<any P>) -> () // user: %80
  // function_ref specialized ContiguousArray._appendElementAssumeUniqueAndCapacity(_:newElement:)
  %31 = function_ref @$ss15ContiguousArrayV37_appendElementAssumeUniqueAndCapacity_03newD0ySi_xntF4main1P_p_Tg5 : $@convention(method) (Int, @in any P, @inout ContiguousArray<any P>) -> () // user: %81
  // function_ref specialized ContiguousArray._endMutation()
  %32 = function_ref @$ss15ContiguousArrayV12_endMutationyyF4main1P_p_Tg5 : $@convention(method) (@inout ContiguousArray<any P>) -> () // user: %82
  %33 = builtin "cmp_sge_Int64"(%4, %5) : $Builtin.Int1 // user: %34
  cond_fail %33, "loop induction variable overflowed" // id: %34
  %35 = integer_literal $Builtin.Int1, 0          // user: %42
  %36 = integer_literal $Builtin.Int1, -1         // user: %44
  br bb4(%4)                                      // id: %37

// %38                                            // user: %39
bb3(%38 : @owned $Array<any P>):                  // Preds: bb5 bb1
  return %38                                      // id: %39

// %40                                            // users: %50, %46, %43, %41
bb4(%40 : $Builtin.Int64):                        // Preds: bb6 bb2
  %41 = builtin "cmp_slt_Int64"(%40, %4) : $Builtin.Int1
  cond_fail %35, "Index out of bounds"            // id: %42
  %43 = builtin "cmp_slt_Int64"(%40, %5) : $Builtin.Int1
  %44 = builtin "xor_Int1"(%36, %22) : $Builtin.Int1 // user: %45
  cond_fail %44, "Index out of bounds"            // id: %45
  %46 = builtin "sadd_with_overflow_Int64"(%40, %23, %22) : $(Builtin.Int64, Builtin.Int1) // users: %48, %47
  %47 = tuple_extract %46, 0                      // users: %95, %84
  %48 = tuple_extract %46, 1
  %49 = alloc_stack [lexical] $any P              // users: %64, %83, %81
  %50 = struct $Int (%40)                         // user: %53
  %51 = apply %24(%0) : $@convention(method) (@guaranteed Array<Builder<X>>) -> Bool // user: %53
  %52 = struct $_DependenceToken ()               // user: %53
  %53 = apply %26(%50, %51, %52, %0) : $@convention(method) (Int, Bool, _DependenceToken, @guaranteed Array<Builder<X>>) -> @owned Builder<X> // user: %54
  %54 = move_value [lexical] %53                  // users: %66, %56
  %55 = alloc_stack $Builder<X>                   // users: %69, %56
  %56 = store_borrow %54 to %55                   // users: %62, %57
  %57 = struct_element_addr %56, #Builder.f       // user: %58
  %58 = load_borrow %57                           // users: %61, %60
  %59 = alloc_stack $any P<X>                     // users: %68, %67, %63, %60
  %60 = apply %58(%59) : $@callee_guaranteed @substituted <τ_0_0> () -> @out any P<τ_0_0> for <X>
  end_borrow %58                                  // id: %61
  end_borrow %56                                  // id: %62
  %63 = open_existential_addr immutable_access %59 to $*@opened("49D17B98-C03C-11F0-A3D3-066CDC995E31", any P<X>) Self // users: %65, %64
  %64 = init_existential_addr %49, $@opened("49D17B98-C03C-11F0-A3D3-066CDC995E31", any P<X>) Self // type-defs: %63; user: %65
  copy_addr %63 to [init] %64                     // id: %65
  destroy_value %54                               // id: %66
  destroy_addr %59                                // id: %67
  dealloc_stack %59                               // id: %68
  dealloc_stack %55                               // id: %69
  %70 = apply %27(%14) : $@convention(method) (@inout ContiguousArray<any P>) -> ()
  %71 = load_borrow %29                           // users: %79, %72
  %72 = ref_element_addr %71, #__ContiguousArrayStorageBase.countAndCapacity // user: %73
  %73 = struct_element_addr %72, #_ArrayBody._storage // user: %74
  %74 = struct_element_addr %73, #_SwiftArrayBodyStorage.count // user: %75
  %75 = struct_element_addr %74, #Int._value      // user: %76
  %76 = load [trivial] %75                        // user: %77
  %77 = builtin "assumeNonNegative_Int64"(%76) : $Builtin.Int64 // user: %78
  %78 = struct $Int (%77)                         // users: %81, %80
  end_borrow %71                                  // id: %79
  %80 = apply %30(%78, %14) : $@convention(method) (Int, @inout ContiguousArray<any P>) -> ()
  %81 = apply %31(%78, %49, %14) : $@convention(method) (Int, @in any P, @inout ContiguousArray<any P>) -> ()
  %82 = apply %32(%14) : $@convention(method) (@inout ContiguousArray<any P>) -> ()
  dealloc_stack %49                               // id: %83
  %84 = builtin "cmp_eq_Int64"(%47, %5) : $Builtin.Int1 // user: %85
  cond_br %84, bb5, bb6                           // id: %85

bb5:                                              // Preds: bb4
  %86 = load [take] %14                           // user: %87
  %87 = destructure_struct %86                    // user: %88
  %88 = destructure_struct %87                    // user: %89
  %89 = unchecked_ref_cast %88 to $Builtin.BridgeObject // user: %90
  %90 = struct $_BridgeStorage<__ContiguousArrayStorageBase> (%89) // user: %91
  %91 = struct $_ArrayBuffer<any P> (%90)         // user: %92
  %92 = struct $Array<any P> (%91)                // user: %94
  dealloc_stack %14                               // id: %93
  br bb3(%92)                                     // id: %94

bb6:                                              // Preds: bb4
  br bb4(%47)                                     // id: %95
} // end sil function '$sSa4mainE7resolveSayAA1P_pGyAA7BuilderVyqd__GRszlFAA1XV_Tg5'

Please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the crash backtrace.
Stack dump:
0.	Program arguments: ~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend -frontend -c -primary-file repro.swift -target arm64-apple-macosx26.0 -Xllvm -aarch64-use-tbi -enable-objc-interop -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -color-diagnostics -Xcc -fcolor-diagnostics -O -empty-abi-descriptor -no-auto-bridging-header-chaining -module-name main -in-process-plugin-server-path ~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/lib/swift/host/libSwiftInProcPluginServer.dylib -plugin-path ~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/lib/swift/host/plugins -plugin-path ~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/local/lib/swift/host/plugins -target-sdk-version 26.1 -target-sdk-name macosx26.1 -external-plugin-path /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/lib/swift/host/plugins#/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/bin/swift-plugin-server -external-plugin-path /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/local/lib/swift/host/plugins#/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/bin/swift-plugin-server -enable-default-cmo -o /var/folders/4v/lbp_rtss3q1fwqdfv5y4d0wh0000gp/T/TemporaryDirectory.ZQgaPV/sil-verification-crash_5-1.o
1.	Apple Swift version 6.2.1 (swift-6.2.1-RELEASE)
2.	Compiling with effective version 5.10
3.	While evaluating request ExecuteSILPipelineRequest(Run pipelines { PrepareOptimizationPasses, EarlyModulePasses, HighLevel,Function+EarlyLoopOpt, HighLevel,Module+StackPromote, MidLevel,Function, ClosureSpecialize, LowLevel,Function, LateLoopOpt, SIL Debug Info Generator } on SIL for main)
4.	While running pass #3657 SILFunctionTransform "BoundsCheckOpts" on SILFunction "@$sSa4mainE7resolveSayAA1P_pGyAA7BuilderVyqd__GRszlFAA1XV_Tg5".
 for 'resolve()' (at repro.swift:13:5)
5.	While verifying SIL function "@$sSa4mainE7resolveSayAA1P_pGyAA7BuilderVyqd__GRszlFAA1XV_Tg5".
 for 'resolve()' (at repro.swift:13:5)
 #0 0x000000010a0bcb6c (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x1059dcb6c)
 #1 0x000000010a0bb298 (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x1059db298)
 #2 0x000000010a0bd1b4 (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x1059dd1b4)
 #3 0x000000019f492744 (/usr/lib/system/libsystem_platform.dylib+0x1804d6744)
 #4 0x000000019f488888 (/usr/lib/system/libsystem_pthread.dylib+0x1804cc888)
 #5 0x000000019f38e808 (/usr/lib/system/libsystem_c.dylib+0x1803d2808)
 #6 0x000000010581cb1c (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x10113cb1c)
 #7 0x0000000105834df8 (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x101154df8)
 #8 0x00000001058249d0 (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x1011449d0)
 #9 0x0000000105823258 (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x101143258)
#10 0x000000010581d534 (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x10113d534)
#11 0x00000001051cac00 (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x100aeac00)
#12 0x000000010530a0cc (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x100c2a0cc)
#13 0x000000010530adf0 (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x100c2adf0)
#14 0x0000000105307ffc (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x100c27ffc)
#15 0x0000000105307f7c (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x100c27f7c)
#16 0x000000010532d7bc (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x100c4d7bc)
#17 0x000000010530f1c8 (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x100c2f1c8)
#18 0x00000001053081ec (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x100c281ec)
#19 0x0000000105310950 (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x100c30950)
#20 0x0000000104bb59ac (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x1004d59ac)
#21 0x0000000104974c48 (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x100294c48)
#22 0x00000001049742a8 (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x1002942a8)
#23 0x0000000104980a6c (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x1002a0a6c)
#24 0x00000001049760a0 (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x1002960a0)
#25 0x000000010497585c (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x10029585c)
#26 0x0000000104718d48 (~/Library/Developer/Toolchains/swift-6.2.1-RELEASE.xctoolchain/usr/bin/swift-frontend+0x100038d48)
#27 0x000000019f0c9d54

Expected behavior

The provided code should compile successfully with optimizations enabled.

Environment

macOS: 26.0.1
Xcode: 26.1
swift: Reproduced with both the open source 6.2.1 release, as well as the latest main snapshot (2025-11-03).

Note that this does not reproduce in a linux container.

Additional information

No response

Metadata

Metadata

Assignees

Labels

SILOptimizerArea → compiler: SIL optimization passescrashBug: A crash, i.e., an abnormal termination of software

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions