// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -parse-stdlib -Xllvm -sil-print-debuginfo -verify -swift-version 5 -primary-file %s %S/Inputs/errors_other.swift | %FileCheck %s import Swift class Cat {} enum HomeworkError : Error { case TooHard case TooMuch case CatAteIt(Cat) case CatHidIt(Cat) } func someValidPointer() -> UnsafePointer { fatalError() } func someValidPointer() -> UnsafeMutablePointer { fatalError() } // CHECK: sil hidden [ossa] @$s6errors10make_a_cat{{.*}}F : $@convention(thin) () -> (@owned Cat, @error any Error) { // CHECK: [[T1:%.*]] = metatype $@thick Cat.Type // CHECK: [[T0:%.*]] = function_ref @$s6errors3Cat{{.*}} : $@convention(method) (@thick Cat.Type) -> @owned Cat // CHECK-NEXT: [[T2:%.*]] = apply [[T0]]([[T1]]) // CHECK-NEXT: return [[T2]] : $Cat func make_a_cat() throws -> Cat { return Cat() } // CHECK: sil hidden [ossa] @$s6errors15dont_make_a_cat{{.*}}F : $@convention(thin) () -> (@owned Cat, @error any Error) { // CHECK: [[T0:%.*]] = metatype $@thin HomeworkError.Type // CHECK-NEXT: [[T1:%.*]] = enum $HomeworkError, #HomeworkError.TooHard!enumelt // CHECK-NEXT: [[BOX:%.*]] = alloc_existential_box $any Error, $HomeworkError // CHECK-NEXT: [[ADDR:%.*]] = project_existential_box $HomeworkError in [[BOX]] : $any Error // CHECK-NEXT: store [[BOX]] to [init] [[BOXBUF:%.*]] : // CHECK-NEXT: store [[T1]] to [init] [[ADDR]] // CHECK-NEXT: [[BOX2:%.*]] = load [take] [[BOXBUF]] // CHECK-NEXT: builtin "willThrow" // CHECK-NEXT: dealloc_stack [[BOXBUF]] // CHECK-NEXT: throw [[BOX2]] func dont_make_a_cat() throws -> Cat { throw HomeworkError.TooHard } // CHECK: sil hidden [ossa] @$s6errors11dont_return{{.*}}F : $@convention(thin) (@in_guaranteed T) -> (@out T, @error any Error) { // CHECK: [[T0:%.*]] = metatype $@thin HomeworkError.Type // CHECK-NEXT: [[T1:%.*]] = enum $HomeworkError, #HomeworkError.TooMuch!enumelt // CHECK-NEXT: [[BOX:%.*]] = alloc_existential_box $any Error, $HomeworkError // CHECK-NEXT: [[ADDR:%.*]] = project_existential_box $HomeworkError in [[BOX]] : $any Error // CHECK-NEXT: store [[BOX]] to [init] [[BOXBUF:%.*]] : // CHECK-NEXT: store [[T1]] to [init] [[ADDR]] // CHECK-NEXT: [[BOX2:%.*]] = load [take] [[BOXBUF]] // CHECK-NEXT: builtin "willThrow" // CHECK-NEXT: dealloc_stack [[BOXBUF]] // CHECK-NEXT: throw [[BOX2]] func dont_return(_ argument: T) throws -> T { throw HomeworkError.TooMuch } // CHECK: sil hidden [ossa] @$s6errors16all_together_nowyAA3CatCSbF : $@convention(thin) (Bool) -> @owned Cat { // CHECK: bb0(%0 : $Bool): // CHECK: [[RET_TEMP:%.*]] = alloc_stack $Cat // Branch on the flag. // CHECK: cond_br {{%.*}}, [[FLAG_TRUE:bb[0-9]+]], [[FLAG_FALSE:bb[0-9]+]] // In the true case, call make_a_cat(). // CHECK: [[FLAG_TRUE]]: // CHECK: [[MAC_FN:%.*]] = function_ref @$s6errors10make_a_catAA3CatCyKF : $@convention(thin) () -> (@owned Cat, @error any Error) // CHECK-NEXT: try_apply [[MAC_FN]]() : $@convention(thin) () -> (@owned Cat, @error any Error), normal [[MAC_NORMAL:bb[0-9]+]], error [[MAC_ERROR:bb[0-9]+]] // CHECK: [[MAC_NORMAL]]([[T0:%.*]] : @owned $Cat): // CHECK-NEXT: br [[TERNARY_CONT:bb[0-9]+]]([[T0]] : $Cat) // In the false case, call dont_make_a_cat(). // CHECK: [[FLAG_FALSE]]: // CHECK: [[DMAC_FN:%.*]] = function_ref @$s6errors15dont_make_a_catAA3CatCyKF : $@convention(thin) () -> (@owned Cat, @error any Error) // CHECK-NEXT: try_apply [[DMAC_FN]]() : $@convention(thin) () -> (@owned Cat, @error any Error), normal [[DMAC_NORMAL:bb[0-9]+]], error [[DMAC_ERROR:bb[0-9]+]] // CHECK: [[DMAC_NORMAL]]([[T0:%.*]] : @owned $Cat): // CHECK-NEXT: br [[TERNARY_CONT]]([[T0]] : $Cat) // Merge point for the ternary operator. Call dont_return with the result. // CHECK: [[TERNARY_CONT]]([[T0:%.*]] : @owned $Cat): // CHECK-NEXT: [[ARG_TEMP:%.*]] = alloc_stack $Cat // CHECK-NEXT: store [[T0]] to [init] [[ARG_TEMP]] // CHECK: [[DR_FN:%.*]] = function_ref @$s6errors11dont_return{{.*}} : // CHECK-NEXT: try_apply [[DR_FN]]([[RET_TEMP]], [[ARG_TEMP]]) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> (@out τ_0_0, @error any Error), normal [[DR_NORMAL:bb[0-9]+]], error [[DR_ERROR:bb[0-9]+]] // CHECK: [[DR_NORMAL]]({{%.*}} : $()): // CHECK-NEXT: destroy_addr [[ARG_TEMP]] // CHECK-NEXT: dealloc_stack [[ARG_TEMP]] // CHECK-NEXT: [[T0:%.*]] = load [take] [[RET_TEMP]] : $*Cat // CHECK-NEXT: dealloc_stack [[RET_TEMP]] // CHECK-NEXT: br [[RETURN:bb[0-9]+]]([[T0]] : $Cat) // Return block. // CHECK: [[RETURN]]([[T0:%.*]] : @owned $Cat): // CHECK-NEXT: return [[T0]] : $Cat // Catch dispatch block. // CHECK: [[CATCH:bb[0-9]+]]([[ERROR:%.*]] : @owned $any Error): // CHECK-NEXT: [[BORROWED_ERROR:%.*]] = begin_borrow [[ERROR]] // CHECK-NEXT: [[SRC_TEMP:%.*]] = alloc_stack $any Error // CHECK-NEXT: [[COPIED_BORROWED_ERROR:%.*]] = copy_value [[BORROWED_ERROR]] // CHECK-NEXT: store [[COPIED_BORROWED_ERROR]] to [init] [[SRC_TEMP]] // CHECK-NEXT: [[DEST_TEMP:%.*]] = alloc_stack $HomeworkError // CHECK-NEXT: checked_cast_addr_br copy_on_success any Error in [[SRC_TEMP]] : $*any Error to HomeworkError in [[DEST_TEMP]] : $*HomeworkError, [[IS_HWE:bb[0-9]+]], [[NOT_HWE:bb[0-9]+]] // Catch HomeworkError. // CHECK: [[IS_HWE]]: // CHECK-NEXT: [[T0_ORIG:%.*]] = load [take] [[DEST_TEMP]] : $*HomeworkError // CHECK-NEXT: switch_enum [[T0_ORIG]] : $HomeworkError, case #HomeworkError.CatAteIt!enumelt: [[MATCH:bb[0-9]+]], default [[NO_MATCH:bb[0-9]+]] // Catch HomeworkError.CatAteIt. // CHECK: [[MATCH]]([[T0:%.*]] : @owned $Cat): // CHECK-NEXT: [[MOVED_T0:%.*]] = move_value [lexical] [var_decl] [[T0]] // CHECK-NEXT: debug_value [[MOVED_T0]] : $Cat // CHECK-NEXT: [[BORROWED_T0:%.*]] = begin_borrow [[MOVED_T0]] // CHECK-NEXT: [[T0_COPY:%.*]] = copy_value [[BORROWED_T0]] // CHECK-NEXT: end_borrow [[BORROWED_T0]] // CHECK-NEXT: destroy_value [[MOVED_T0]] // CHECK-NEXT: dealloc_stack [[DEST_TEMP]] // CHECK-NEXT: destroy_addr [[SRC_TEMP]] // CHECK-NEXT: dealloc_stack [[SRC_TEMP]] // CHECK-NEXT: end_borrow [[BORROWED_ERROR]] // CHECK-NEXT: destroy_value [[ERROR]] // CHECK-NEXT: br [[RETURN]]([[T0_COPY]] : $Cat) // Catch other HomeworkErrors. // CHECK: [[NO_MATCH]]([[CATCHALL_ERROR:%.*]] : @owned $HomeworkError): // CHECK-NEXT: destroy_value [[CATCHALL_ERROR]] // CHECK-NEXT: dealloc_stack [[DEST_TEMP]] // CHECK-NEXT: destroy_addr [[SRC_TEMP]] // CHECK-NEXT: dealloc_stack [[SRC_TEMP]] // CHECK-NEXT: br [[CATCHALL:bb[0-9]+]] // Catch other types. // CHECK: [[NOT_HWE]]: // CHECK-NEXT: dealloc_stack [[DEST_TEMP]] // CHECK-NEXT: destroy_addr [[SRC_TEMP]] // CHECK-NEXT: dealloc_stack [[SRC_TEMP]] // CHECK-NEXT: br [[CATCHALL:bb[0-9]+]] // Catch all. // CHECK: [[CATCHALL]]: // CHECK-NEXT: [[T1:%.*]] = metatype $@thick Cat.Type // CHECK: [[T0:%.*]] = function_ref @$s6errors3Cat{{.*}} : $@convention(method) (@thick Cat.Type) -> @owned Cat // CHECK-NEXT: [[T2:%.*]] = apply [[T0]]([[T1]]) // CHECK-NEXT: end_borrow [[BORROWED_ERROR]] // CHECK-NEXT: destroy_value [[ERROR]] : $any Error // CHECK-NEXT: br [[RETURN]]([[T2]] : $Cat) // Landing pad. // CHECK: [[MAC_ERROR]]([[T0:%.*]] : @owned $any Error): // CHECK-NEXT: dealloc_stack [[RET_TEMP]] // CHECK-NEXT: br [[CATCH]]([[T0]] : $any Error) // CHECK: [[DMAC_ERROR]]([[T0:%.*]] : @owned $any Error): // CHECK-NEXT: dealloc_stack [[RET_TEMP]] // CHECK-NEXT: br [[CATCH]]([[T0]] : $any Error) // CHECK: [[DR_ERROR]]([[T0:%.*]] : @owned $any Error): // CHECK-NEXT: destroy_addr [[CAT:%.*]] : // CHECK-NEXT: dealloc_stack [[CAT]] // CHECK-NEXT: dealloc_stack // CHECK-NEXT: br [[CATCH]]([[T0]] : $any Error) func all_together_now(_ flag: Bool) -> Cat { do { return try dont_return(flag ? make_a_cat() : dont_make_a_cat()) } catch HomeworkError.CatAteIt(let cat) { return cat } catch _ { return Cat() } } // Make sure that if we catch an error in a throwing function we borrow the // error and only consume the error in the rethrow block. // // CHECK-LABEL: sil hidden [ossa] @$s6errors20all_together_now_twoyAA3CatCSgSbKF : $@convention(thin) (Bool) -> (@owned Optional, @error any Error) { // CHECK: bb0( // CHECK-NOT: bb1 // CHECK: try_apply {{.*}}, normal [[NORMAL_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]] // // CHECK: [[ERROR_BB]]([[ERROR:%.*]] : @owned $any Error): // CHECK: [[BORROWED_ERROR:%.*]] = begin_borrow [[ERROR]] // CHECK: [[COPIED_ERROR:%.*]] = copy_value [[BORROWED_ERROR]] // CHECK: store [[COPIED_ERROR]] to [init] [[CAST_INPUT_MEM:%.*]] : $*any Error // CHECK: checked_cast_addr_br copy_on_success any Error in [[CAST_INPUT_MEM]] : $*any Error to HomeworkError in [[CAST_OUTPUT_MEM:%.*]] : $*HomeworkError, [[CAST_YES_BB:bb[0-9]+]], [[CAST_NO_BB:bb[0-9]+]], // // CHECK: [[CAST_YES_BB]]: // CHECK: [[SUBERROR:%.*]] = load [take] [[CAST_OUTPUT_MEM]] // CHECK: switch_enum [[SUBERROR]] : $HomeworkError, case #HomeworkError.TooHard!enumelt: {{bb[0-9]+}}, default [[SWITCH_MATCH_FAIL_BB:bb[0-9]+]], // // CHECK: [[SWITCH_MATCH_FAIL_BB]]([[SUBERROR:%.*]] : @owned $HomeworkError): // CHECK: destroy_value [[SUBERROR]] // CHECK: end_borrow [[BORROWED_ERROR]] // CHECK: br [[RETHROW_BB:bb[0-9]+]]([[ERROR]] : $any Error) // // CHECK: [[CAST_NO_BB]]: // CHECK: end_borrow [[BORROWED_ERROR]] // CHECK: br [[RETHROW_BB]]([[ERROR]] : $any Error) // // CHECK: [[RETHROW_BB]]([[ERROR_FOR_RETHROW:%.*]] : @owned $any Error): // CHECK: throw [[ERROR_FOR_RETHROW]] // CHECK: } // end sil function '$s6errors20all_together_now_twoyAA3CatCSgSbKF' func all_together_now_two(_ flag: Bool) throws -> Cat? { do { return try dont_return(Cat()) } catch HomeworkError.TooHard { return nil } } // Same as the previous test, but with multiple cases instead of just one. // // CHECK-LABEL: sil hidden [ossa] @$s6errors22all_together_now_threeyAA3CatCSgSbKF : $@convention(thin) (Bool) -> (@owned Optional, @error any Error) { // CHECK: bb0( // CHECK-NOT: bb1 // CHECK: try_apply {{.*}}, normal [[NORMAL_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]] // // CHECK: [[ERROR_BB]]([[ERROR:%.*]] : @owned $any Error): // CHECK: [[BORROWED_ERROR:%.*]] = begin_borrow [[ERROR]] // CHECK: [[COPIED_ERROR:%.*]] = copy_value [[BORROWED_ERROR]] // CHECK: store [[COPIED_ERROR]] to [init] [[CAST_INPUT_MEM:%.*]] : $*any Error // CHECK: checked_cast_addr_br copy_on_success any Error in [[CAST_INPUT_MEM]] : $*any Error to HomeworkError in [[CAST_OUTPUT_MEM:%.*]] : $*HomeworkError, [[CAST_YES_BB:bb[0-9]+]], [[CAST_NO_BB:bb[0-9]+]], // // CHECK: [[CAST_YES_BB]]: // CHECK: [[SUBERROR:%.*]] = load [take] [[CAST_OUTPUT_MEM]] // CHECK: switch_enum [[SUBERROR]] : $HomeworkError, case #HomeworkError.TooHard!enumelt: {{bb[0-9]+}}, case #HomeworkError.TooMuch!enumelt: {{bb[0-9]+}}, default [[SWITCH_MATCH_FAIL_BB:bb[0-9]+]], // // CHECK: [[SWITCH_MATCH_FAIL_BB]]([[SUBERROR:%.*]] : @owned $HomeworkError): // CHECK: destroy_value [[SUBERROR]] // CHECK: end_borrow [[BORROWED_ERROR]] // CHECK: br [[RETHROW_BB:bb[0-9]+]]([[ERROR]] : $any Error) // // CHECK: [[CAST_NO_BB]]: // CHECK: end_borrow [[BORROWED_ERROR]] // CHECK: br [[RETHROW_BB]]([[ERROR]] : $any Error) // // CHECK: [[RETHROW_BB]]([[ERROR_FOR_RETHROW:%.*]] : @owned $any Error): // CHECK: throw [[ERROR_FOR_RETHROW]] // CHECK: } // end sil function '$s6errors22all_together_now_threeyAA3CatCSgSbKF' func all_together_now_three(_ flag: Bool) throws -> Cat? { do { return try dont_return(Cat()) } catch HomeworkError.TooHard { return nil } catch HomeworkError.TooMuch { return nil } } // Same as the previous test, but with a multi-pattern catch instead of two separate ones. // // CHECK-LABEL: sil hidden [ossa] @$s6errors21all_together_now_fouryAA3CatCSgSbKF : $@convention(thin) (Bool) -> (@owned Optional, @error any Error) { // CHECK: bb0( // CHECK-NOT: bb1 // CHECK: try_apply {{.*}}, normal [[NORMAL_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]] // // CHECK: [[ERROR_BB]]([[ERROR:%.*]] : @owned $any Error): // CHECK: [[BORROWED_ERROR:%.*]] = begin_borrow [[ERROR]] // CHECK: [[COPIED_ERROR:%.*]] = copy_value [[BORROWED_ERROR]] // CHECK: store [[COPIED_ERROR]] to [init] [[CAST_INPUT_MEM:%.*]] : $*any Error // CHECK: checked_cast_addr_br copy_on_success any Error in [[CAST_INPUT_MEM]] : $*any Error to HomeworkError in [[CAST_OUTPUT_MEM:%.*]] : $*HomeworkError, [[CAST_YES_BB:bb[0-9]+]], [[CAST_NO_BB:bb[0-9]+]], // // CHECK: [[CAST_YES_BB]]: // CHECK: [[SUBERROR:%.*]] = load [take] [[CAST_OUTPUT_MEM]] // CHECK: switch_enum [[SUBERROR]] : $HomeworkError, case #HomeworkError.TooHard!enumelt: [[TOO_HARD_BB:bb[0-9]+]], case #HomeworkError.TooMuch!enumelt: [[TOO_MUCH_BB:bb[0-9]+]], default [[SWITCH_MATCH_FAIL_BB:bb[0-9]+]], // // CHECK: [[TOO_HARD_BB]]: // CHECK: br [[CASE_BODY_BB:bb[0-9]+]] // // CHECK: [[TOO_MUCH_BB]]: // CHECK: br [[CASE_BODY_BB]] // // CHECK: [[CASE_BODY_BB]] // CHECK: [[RETVAL:%.*]] = enum $Optional // CHECK: destroy_value [[ERROR]] // CHECK: br bb2([[RETVAL]] : $Optional) // // CHECK: [[SWITCH_MATCH_FAIL_BB]]([[SUBERROR:%.*]] : @owned $HomeworkError): // CHECK: destroy_value [[SUBERROR]] // CHECK: end_borrow [[BORROWED_ERROR]] // CHECK: br [[RETHROW_BB:bb[0-9]+]]([[ERROR]] : $any Error) // // CHECK: [[CAST_NO_BB]]: // CHECK: end_borrow [[BORROWED_ERROR]] // CHECK: br [[RETHROW_BB]]([[ERROR]] : $any Error) // // CHECK: [[RETHROW_BB]]([[ERROR_FOR_RETHROW:%.*]] : @owned $any Error): // CHECK: throw [[ERROR_FOR_RETHROW]] // CHECK: } // end sil function '$s6errors21all_together_now_fouryAA3CatCSgSbKF' func all_together_now_four(_ flag: Bool) throws -> Cat? { do { return try dont_return(Cat()) } catch HomeworkError.TooHard, HomeworkError.TooMuch { return nil } } // A multi-pattern catch with associated value bindings. // // CHECK-LABEL: sil hidden [ossa] @$s6errors21all_together_now_fiveyAA3CatCSbKF : $@convention(thin) (Bool) -> (@owned Cat, @error any Error) { // Return block. // CHECK: [[RETURN:bb[0-9]+]]([[RETVAL:%.*]] : @owned $Cat): // CHECK-NEXT: return [[RETVAL]] : $Cat // Catch dispatch block. // CHECK: [[CATCH:bb[0-9]+]]([[ERROR:%.*]] : @owned $any Error): // CHECK: [[BORROWED_ERROR:%.*]] = begin_borrow [[ERROR]] // CHECK-NEXT: [[SRC_TEMP:%.*]] = alloc_stack $any Error // CHECK-NEXT: [[COPIED_BORROWED_ERROR:%.*]] = copy_value [[BORROWED_ERROR]] // CHECK-NEXT: store [[COPIED_BORROWED_ERROR]] to [init] [[SRC_TEMP]] // CHECK-NEXT: [[DEST_TEMP:%.*]] = alloc_stack $HomeworkError // CHECK-NEXT: checked_cast_addr_br copy_on_success any Error in [[SRC_TEMP]] : $*any Error to HomeworkError in [[DEST_TEMP]] : $*HomeworkError, [[IS_HWE:bb[0-9]+]], [[NOT_HWE:bb[0-9]+]] // Catch HomeworkError. // CHECK: [[IS_HWE]]: // CHECK-NEXT: [[T0_ORIG:%.*]] = load [take] [[DEST_TEMP]] : $*HomeworkError // CHECK-NEXT: switch_enum [[T0_ORIG]] : $HomeworkError, case #HomeworkError.CatAteIt!enumelt: [[MATCH_ATE:bb[0-9]+]], case #HomeworkError.CatHidIt!enumelt: [[MATCH_HID:bb[0-9]+]], default [[NO_MATCH:bb[0-9]+]] // Catch HomeworkError.CatAteIt. // CHECK: [[MATCH_ATE]]([[T0:%.*]] : @owned $Cat): // CHECK-NEXT: [[MOVED_T0:%.*]] = move_value [lexical] [var_decl] [[T0]] // CHECK-NEXT: [[T0_COPY:%.*]] = copy_value [[MOVED_T0]] // CHECK-NEXT: destroy_value [[MOVED_T0]] // CHECK-NEXT: dealloc_stack [[DEST_TEMP]] // CHECK-NEXT: destroy_addr [[SRC_TEMP]] // CHECK-NEXT: dealloc_stack [[SRC_TEMP]] // CHECK-NEXT: end_borrow [[BORROWED_ERROR]] // CHECK-NEXT: br [[EXTRACT:bb[0-9]+]]([[T0_COPY]] : $Cat) // Catch HomeworkError.CatHidIt. // CHECK: [[MATCH_HID]]([[T0:%.*]] : @owned $Cat): // CHECK-NEXT: [[MOVED_T0:%.*]] = move_value [lexical] [var_decl] [[T0]] // CHECK-NEXT: [[T0_COPY:%.*]] = copy_value [[MOVED_T0]] // CHECK-NEXT: destroy_value [[MOVED_T0]] // CHECK-NEXT: dealloc_stack [[DEST_TEMP]] // CHECK-NEXT: destroy_addr [[SRC_TEMP]] // CHECK-NEXT: dealloc_stack [[SRC_TEMP]] // CHECK-NEXT: end_borrow [[BORROWED_ERROR]] // CHECK-NEXT: br [[EXTRACT]]([[T0_COPY]] : $Cat) // CHECK: [[EXTRACT]]([[CAT:%.*]] : @owned $Cat): // CHECK-NEXT: debug_value [[CAT]] : $Cat, let, name "theCat" // CHECK-NEXT: [[BORROWED_CAT:%.*]] = begin_borrow [[CAT]] : $Cat // CHECK-NEXT: [[COPIED_CAT:%.*]] = copy_value [[BORROWED_CAT]] : $Cat // CHECK-NEXT: end_borrow [[BORROWED_CAT]] : $Cat // CHECK-NEXT: destroy_value [[CAT]] : $Cat // CHECK-NEXT: destroy_value [[ERROR]] : $any Error // CHECK-NEXT: br [[RETURN]]([[COPIED_CAT]] : $Cat) // Catch other HomeworkErrors. // CHECK: [[NO_MATCH]]([[CATCHALL_ERROR:%.*]] : @owned $HomeworkError): // CHECK-NEXT: destroy_value [[CATCHALL_ERROR]] // CHECK-NEXT: dealloc_stack [[DEST_TEMP]] // CHECK-NEXT: destroy_addr [[SRC_TEMP]] // CHECK-NEXT: dealloc_stack [[SRC_TEMP]] // CHECK-NEXT: end_borrow [[BORROWED_ERROR]] // CHECK-NEXT: br [[RETHROW:bb[0-9]+]] // Catch other types. // CHECK: [[NOT_HWE]]: // CHECK-NEXT: dealloc_stack [[DEST_TEMP]] // CHECK-NEXT: destroy_addr [[SRC_TEMP]] // CHECK-NEXT: dealloc_stack [[SRC_TEMP]] // CHECK-NEXT: end_borrow [[BORROWED_ERROR]] // CHECK-NEXT: br [[RETHROW]] // Rethrow // CHECK: [[RETHROW]]([[ERROR:%.*]] : @owned $any Error): // CHECK-NEXT: throw [[ERROR]] : $any Error func all_together_now_five(_ flag: Bool) throws -> Cat { do { return try dont_return(Cat()) } catch HomeworkError.CatAteIt(let theCat), HomeworkError.CatHidIt(let theCat) { return theCat } } // Catch in non-throwing context. // CHECK-LABEL: sil hidden [ossa] @$s6errors11catch_a_catAA3CatCyF : $@convention(thin) () -> @owned Cat // CHECK-NEXT: bb0: // CHECK-NEXT: [[M:%.*]] = metatype $@thick Cat.Type // CHECK: [[F:%.*]] = function_ref @$s6errors3Cat{{.*}} : $@convention(method) (@thick Cat.Type) -> @owned Cat // CHECK-NEXT: [[V:%.*]] = apply [[F]]([[M]]) // CHECK-NEXT: return [[V]] : $Cat func catch_a_cat() -> Cat { do { return Cat() } catch _ as HomeworkError {} // expected-warning {{'catch' block is unreachable because no errors are thrown in 'do' block}} } // Initializers. class HasThrowingInit { var field: Int init(value: Int) throws { field = value } } // CHECK-LABEL: sil hidden [exact_self_class] [ossa] @$s6errors15HasThrowingInit{{.*}} : $@convention(method) (Int, @thick HasThrowingInit.Type) -> (@owned HasThrowingInit, @error any Error) // CHECK: [[SELF:%.*]] = alloc_ref $HasThrowingInit // CHECK: [[T0:%.*]] = function_ref @$s6errors15HasThrowingInit{{.*}}c : $@convention(method) (Int, @owned HasThrowingInit) -> (@owned HasThrowingInit, @error any Error) // CHECK-NEXT: try_apply [[T0]](%0, [[SELF]]) : $@convention(method) (Int, @owned HasThrowingInit) -> (@owned HasThrowingInit, @error any Error), normal bb1, error bb2 // CHECK: bb1([[SELF:%.*]] : @owned $HasThrowingInit): // CHECK-NEXT: return [[SELF]] // CHECK: bb2([[ERROR:%.*]] : @owned $any Error): // CHECK-NEXT: throw [[ERROR]] // CHECK-LABEL: sil hidden [ossa] @$s6errors15HasThrowingInit{{.*}} : $@convention(method) (Int, @owned HasThrowingInit) -> (@owned HasThrowingInit, @error any Error) { // CHECK: [[T0:%.*]] = mark_uninitialized [rootself] %1 : $HasThrowingInit // CHECK-NEXT: [[BORROWED_T0:%.*]] = begin_borrow [[T0]] // CHECK-NEXT: [[T1:%.*]] = ref_element_addr [[BORROWED_T0]] : $HasThrowingInit // CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [dynamic] [[T1]] : $*Int // CHECK-NEXT: assign %0 to [[WRITE]] : $*Int // CHECK-NEXT: end_access [[WRITE]] // CHECK-NEXT: end_borrow [[BORROWED_T0]] // CHECK-NEXT: [[T0_RET:%.*]] = copy_value [[T0]] // CHECK-NEXT: destroy_value [[T0]] // CHECK-NEXT: return [[T0_RET]] : $HasThrowingInit enum ColorError : Error { case Red, Green, Blue } //CHECK-LABEL: sil hidden [ossa] @$s6errors6IThrows5Int32VyKF //CHECK: builtin "willThrow" //CHECK-NEXT: dealloc_stack //CHECK-NEXT: throw func IThrow() throws -> Int32 { throw ColorError.Red return 0 // expected-warning {{will never be executed}} } // Make sure that we are not emitting calls to 'willThrow' on rethrow sites. //CHECK-LABEL: sil hidden [ossa] @$s6errors12DoesNotThrows5Int32VyKF //CHECK-NOT: builtin "willThrow" //CHECK: return func DoesNotThrow() throws -> Int32 { _ = try IThrow() return 2 } // rdar://20782111 protocol Doomed { func check() throws } // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s6errors12DoomedStructVAA0B0A2aDP5checkyyKFTW : // CHECK: [[SELF:%.*]] = load [trivial] %0 : $*DoomedStruct // CHECK: [[T0:%.*]] = function_ref @$s6errors12DoomedStructV5checkyyKF : $@convention(method) (DoomedStruct) -> @error any Error // CHECK-NEXT: try_apply [[T0]]([[SELF]]) // CHECK: bb1([[T0:%.*]] : $()): // CHECK: [[T0:%.*]] = tuple () // CHECK: return [[T0]] : $() // CHECK: bb2([[T0:%.*]] : @owned $any Error): // CHECK: throw [[T0]] : $any Error struct DoomedStruct : Doomed { func check() throws {} } // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s6errors11DoomedClassCAA0B0A2aDP5checkyyKFTW : // CHECK: [[BORROWED_SELF:%.*]] = load_borrow %0 // CHECK: [[T0:%.*]] = class_method [[BORROWED_SELF]] : $DoomedClass, #DoomedClass.check : (DoomedClass) -> () throws -> (), $@convention(method) (@guaranteed DoomedClass) -> @error any Error // CHECK-NEXT: try_apply [[T0]]([[BORROWED_SELF]]) // CHECK: bb1([[T0:%.*]] : $()): // CHECK: [[T0:%.*]] = tuple () // CHECK: end_borrow [[BORROWED_SELF]] // CHECK: return [[T0]] : $() // CHECK: bb2([[T0:%.*]] : @owned $any Error): // CHECK: end_borrow [[BORROWED_SELF]] // CHECK: throw [[T0]] : $any Error class DoomedClass : Doomed { func check() throws {} } // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s6errors11HappyStructVAA6DoomedA2aDP5checkyyKFTW : // CHECK: [[T0:%.*]] = function_ref @$s6errors11HappyStructV5checkyyF : $@convention(method) (HappyStruct) -> () // CHECK: [[T1:%.*]] = apply [[T0]](%1) // CHECK: [[T1:%.*]] = tuple () // CHECK: return [[T1]] : $() struct HappyStruct : Doomed { func check() {} } // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s6errors10HappyClassCAA6DoomedA2aDP5checkyyKFTW : // CHECK: [[SELF:%.*]] = load_borrow %0 : $*HappyClass // CHECK: [[T0:%.*]] = class_method [[SELF]] : $HappyClass, #HappyClass.check : (HappyClass) -> () -> (), $@convention(method) (@guaranteed HappyClass) -> () // CHECK: [[T1:%.*]] = apply [[T0]]([[SELF]]) // CHECK: [[T1:%.*]] = tuple () // CHECK: end_borrow [[SELF]] // CHECK: return [[T1]] : $() class HappyClass : Doomed { func check() {} } func create(_ fn: () throws -> T) throws -> T { return try fn() } func testThunk(_ fn: () throws -> Int) throws -> Int { return try create(fn) } // CHECK-LABEL: sil shared [transparent] [serialized] [reabstraction_thunk] [ossa] @$sSis5Error_pIgdzo_SisAA_pIegrzo_TR : // CHECK: bb0(%0 : $*Int, %1 : @guaranteed $@noescape @callee_guaranteed () -> (Int, @error any Error)): // CHECK: try_apply %1() // CHECK: bb1([[T0:%.*]] : $Int): // CHECK: store [[T0]] to [trivial] %0 : $*Int // CHECK: [[T0:%.*]] = tuple () // CHECK: return [[T0]] // CHECK: bb2([[T0:%.*]] : @owned $any Error): // CHECK: throw [[T0]] : $any Error func createInt(_ fn: () -> Int) throws {} func testForceTry(_ fn: () -> Int) { try! createInt(fn) } // CHECK-LABEL: sil hidden [ossa] @$s6errors12testForceTryyySiyXEF : // CHECK: bb0([[ARG:%.*]] : @guaranteed $@noescape @callee_guaranteed () -> Int): // CHECK: [[FUNC:%.*]] = function_ref @$s6errors9createIntyySiyXEKF : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> Int) -> @error any Error // CHECK: try_apply [[FUNC]]([[ARG]]) // CHECK: return // CHECK: function_ref @swift_unexpectedError // CHECK: unreachable func testForceTryMultiple() { _ = try! (make_a_cat(), make_a_cat()) } // CHECK-LABEL: sil hidden [ossa] @$s6errors20testForceTryMultipleyyF // CHECK-NEXT: bb0: // CHECK: [[FN_1:%.+]] = function_ref @$s6errors10make_a_catAA3CatCyKF // CHECK-NEXT: try_apply [[FN_1]]() : $@convention(thin) () -> (@owned Cat, @error any Error), normal [[SUCCESS_1:[^ ]+]], error [[CLEANUPS_1:[^ ]+]], // CHECK: [[SUCCESS_1]]([[VALUE_1:%.+]] : @owned $Cat) // CHECK: [[FN_2:%.+]] = function_ref @$s6errors10make_a_catAA3CatCyKF // CHECK-NEXT: try_apply [[FN_2]]() : $@convention(thin) () -> (@owned Cat, @error any Error), normal [[SUCCESS_2:[^ ]+]], error [[CLEANUPS_2:[^ ]+]], // CHECK: [[SUCCESS_2]]([[VALUE_2:%.+]] : @owned $Cat) // CHECK-NEXT: ignored_use [[VALUE_1]] // CHECK-NEXT: ignored_use [[VALUE_2]] // CHECK-NEXT: destroy_value [[VALUE_2]] : $Cat // CHECK-NEXT: destroy_value [[VALUE_1]] : $Cat // CHECK-NEXT: [[VOID:%.+]] = tuple () // CHECK-NEXT: return [[VOID]] : $() // CHECK: [[FAILURE:.+]]([[ERROR:%.+]] : @owned $any Error): // CHECK: [[UNEXPECTED_ERROR:%.+]] = function_ref @swift_unexpectedError // CHECK-NEXT: apply [[UNEXPECTED_ERROR]]([[ERROR]] // CHECK-NEXT: unreachable // CHECK: [[CLEANUPS_1]]([[ERROR:%.+]] : @owned $any Error): // CHECK-NEXT: br [[FAILURE]]([[ERROR]] : $any Error) // CHECK: [[CLEANUPS_2]]([[ERROR:%.+]] : @owned $any Error): // CHECK-NEXT: destroy_value [[VALUE_1]] : $Cat // CHECK-NEXT: br [[FAILURE]]([[ERROR]] : $any Error) // CHECK: } // end sil function '$s6errors20testForceTryMultipleyyF' // Make sure we balance scopes correctly inside a switch. // enum CatFood { case Canned case Dry } // Something we can switch on that throws. func preferredFood() throws -> CatFood { return CatFood.Canned } func feedCat() throws -> Int { switch try preferredFood() { case .Canned: return 0 case .Dry: return 1 } } // CHECK-LABEL: sil hidden [ossa] @$s6errors7feedCatSiyKF : $@convention(thin) () -> (Int, @error any Error) // CHECK: debug_value undef : $any Error, var, name "$error", argno 1 // CHECK: %1 = function_ref @$s6errors13preferredFoodAA03CatC0OyKF : $@convention(thin) () -> (CatFood, @error any Error) // CHECK: try_apply %1() : $@convention(thin) () -> (CatFood, @error any Error), normal bb1, error bb5 // CHECK: bb1([[VAL:%.*]] : $CatFood): // CHECK: switch_enum [[VAL]] : $CatFood, case #CatFood.Canned!enumelt: bb2, case #CatFood.Dry!enumelt: bb3 // CHECK: bb5([[ERROR:%.*]] : @owned $any Error) // CHECK: throw [[ERROR]] : $any Error // Throwing statements inside cases. func getHungryCat(_ food: CatFood) throws -> Cat { switch food { case .Canned: return try make_a_cat() case .Dry: return try dont_make_a_cat() } } // errors.getHungryCat throws (errors.CatFood) -> errors.Cat // CHECK-LABEL: sil hidden [ossa] @$s6errors12getHungryCatyAA0D0CAA0D4FoodOKF : $@convention(thin) (CatFood) -> (@owned Cat, @error any Error) // CHECK: bb0(%0 : $CatFood): // CHECK: debug_value undef : $any Error, var, name "$error", argno 2 // CHECK: switch_enum %0 : $CatFood, case #CatFood.Canned!enumelt: bb1, case #CatFood.Dry!enumelt: bb3 // CHECK: bb1: // CHECK: [[FN:%.*]] = function_ref @$s6errors10make_a_catAA3CatCyKF : $@convention(thin) () -> (@owned Cat, @error any Error) // CHECK: try_apply [[FN]]() : $@convention(thin) () -> (@owned Cat, @error any Error), normal bb2, error bb6 // CHECK: bb3: // CHECK: [[FN:%.*]] = function_ref @$s6errors15dont_make_a_catAA3CatCyKF : $@convention(thin) () -> (@owned Cat, @error any Error) // CHECK: try_apply [[FN]]() : $@convention(thin) () -> (@owned Cat, @error any Error), normal bb4, error bb7 // CHECK: bb6([[ERROR:%.*]] : @owned $any Error): // CHECK: br bb8([[ERROR:%.*]] : $any Error) // CHECK: bb7([[ERROR:%.*]] : @owned $any Error): // CHECK: br bb8([[ERROR]] : $any Error) // CHECK: bb8([[ERROR:%.*]] : @owned $any Error): // CHECK: throw [[ERROR]] : $any Error func take_many_cats(_ cats: Cat...) throws {} func test_variadic(_ cat: Cat) throws { try take_many_cats(make_a_cat(), cat, make_a_cat(), make_a_cat()) } // CHECK-LABEL: sil hidden [ossa] @$s6errors13test_variadicyyAA3CatCKF : $@convention(thin) (@guaranteed Cat) -> @error any Error { // CHECK: bb0([[ARG:%.*]] : @guaranteed $Cat): // CHECK: debug_value undef : $any Error, var, name "$error", argno 2 // CHECK: [[N:%.*]] = integer_literal $Builtin.Word, 4 // CHECK: [[T0:%.*]] = function_ref @$ss27_allocateUninitializedArray{{.*}}F // CHECK: [[T1:%.*]] = apply [[T0]]([[N]]) // CHECK: ([[ARRAY:%.*]], [[T2:%.*]]) = destructure_tuple [[T1]] // CHECK: [[BB:%.*]] = begin_borrow [[ARRAY]] // CHECK: struct_extract [[BB]] // CHECK: [[ELT0:%.*]] = ref_tail_addr // Element 0. // CHECK: [[T0:%.*]] = function_ref @$s6errors10make_a_catAA3CatCyKF : $@convention(thin) () -> (@owned Cat, @error any Error) // CHECK: try_apply [[T0]]() : $@convention(thin) () -> (@owned Cat, @error any Error), normal [[NORM_0:bb[0-9]+]], error [[ERR_0:bb[0-9]+]] // CHECK: [[NORM_0]]([[CAT0:%.*]] : @owned $Cat): // CHECK-NEXT: store [[CAT0]] to [init] [[ELT0]] // Element 1. // CHECK-NEXT: [[T0:%.*]] = integer_literal $Builtin.Word, 1 // CHECK-NEXT: [[ELT1:%.*]] = index_addr [[ELT0]] : $*Cat, [[T0]] // CHECK-NEXT: [[ARG_COPY:%.*]] = copy_value [[ARG]] // CHECK-NEXT: store [[ARG_COPY]] to [init] [[ELT1]] // Element 2. // CHECK-NEXT: [[T0:%.*]] = integer_literal $Builtin.Word, 2 // CHECK-NEXT: [[ELT2:%.*]] = index_addr [[ELT0]] : $*Cat, [[T0]] // CHECK-NEXT: // function_ref // CHECK-NEXT: [[T0:%.*]] = function_ref @$s6errors10make_a_catAA3CatCyKF : $@convention(thin) () -> (@owned Cat, @error any Error) // CHECK-NEXT: try_apply [[T0]]() : $@convention(thin) () -> (@owned Cat, @error any Error), normal [[NORM_2:bb[0-9]+]], error [[ERR_2:bb[0-9]+]] // CHECK: [[NORM_2]]([[CAT2:%.*]] : @owned $Cat): // CHECK-NEXT: store [[CAT2]] to [init] [[ELT2]] // Element 3. // CHECK-NEXT: [[T0:%.*]] = integer_literal $Builtin.Word, 3 // CHECK-NEXT: [[ELT3:%.*]] = index_addr [[ELT0]] : $*Cat, [[T0]] // CHECK-NEXT: // function_ref // CHECK-NEXT: [[T0:%.*]] = function_ref @$s6errors10make_a_catAA3CatCyKF : $@convention(thin) () -> (@owned Cat, @error any Error) // CHECK-NEXT: try_apply [[T0]]() : $@convention(thin) () -> (@owned Cat, @error any Error), normal [[NORM_3:bb[0-9]+]], error [[ERR_3:bb[0-9]+]] // CHECK: [[NORM_3]]([[CAT3:%.*]] : @owned $Cat): // CHECK-NEXT: store [[CAT3]] to [init] [[ELT3]] // Complete the call and return. // CHECK: [[FIN_FN:%.*]] = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF // CHECK: [[FIN_ARRAY:%.*]] = apply [[FIN_FN]]([[ARRAY]]) // CHECK: [[TAKE_FN:%.*]] = function_ref @$s6errors14take_many_catsyyAA3CatCd_tKF : $@convention(thin) (@guaranteed Array) -> @error any Error // CHECK-NEXT: try_apply [[TAKE_FN]]([[FIN_ARRAY]]) : $@convention(thin) (@guaranteed Array) -> @error any Error, normal [[NORM_CALL:bb[0-9]+]], error [[ERR_CALL:bb[0-9]+]] // CHECK: [[NORM_CALL]]([[T0:%.*]] : $()): // CHECK-NEXT: destroy_value [[FIN_ARRAY]] // CHECK-NEXT: [[T0:%.*]] = tuple () // CHECK-NEXT: return // Failure from element 0. // CHECK: [[ERR_0]]([[ERROR:%.*]] : @owned $any Error): // CHECK: end_borrow [[BB]] // CHECK-NEXT: // function_ref // CHECK-NEXT: [[T0:%.*]] = function_ref @$ss29_deallocateUninitializedArray{{.*}}F // CHECK-NEXT: apply [[T0]]([[ARRAY]]) // CHECK-NEXT: br [[RETHROW:.*]]([[ERROR]] : $any Error) // Failure from element 2. // CHECK: [[ERR_2]]([[ERROR:%.*]] : @owned $any Error): // CHECK-NEXT: destroy_addr [[ELT1]] // CHECK-NEXT: destroy_addr [[ELT0]] // CHECK: end_borrow [[BB]] // CHECK-NEXT: // function_ref // CHECK-NEXT: [[T0:%.*]] = function_ref @$ss29_deallocateUninitializedArray{{.*}}F // CHECK-NEXT: apply [[T0]]([[ARRAY]]) // CHECK-NEXT: br [[RETHROW]]([[ERROR]] : $any Error) // Failure from element 3. // CHECK: [[ERR_3]]([[ERROR:%.*]] : @owned $any Error): // CHECK-NEXT: destroy_addr [[ELT2]] // CHECK-NEXT: destroy_addr [[ELT1]] // CHECK-NEXT: destroy_addr [[ELT0]] // CHECK-NEXT: end_borrow [[BB]] // CHECK-NEXT: // function_ref // CHECK-NEXT: [[T0:%.*]] = function_ref @$ss29_deallocateUninitializedArray{{.*}}F // CHECK-NEXT: apply [[T0]]([[ARRAY]]) // CHECK-NEXT: br [[RETHROW]]([[ERROR]] : $any Error) // Failure from call. // CHECK: [[ERR_CALL]]([[ERROR:%.*]] : @owned $any Error): // CHECK-NEXT: destroy_value [[FIN_ARRAY]] // CHECK-NEXT: br [[RETHROW]]([[ERROR]] : $any Error) // Rethrow. // CHECK: [[RETHROW]]([[ERROR:%.*]] : @owned $any Error): // CHECK-NEXT: throw [[ERROR]] // CHECK: } // end sil function '$s6errors13test_variadicyyAA3CatCKF' // rdar://20861374 // Clear out the self box before delegating. class BaseThrowingInit : HasThrowingInit { var subField: Int init(value: Int, subField: Int) throws { self.subField = subField try super.init(value: value) } } // CHECK: sil hidden [ossa] @$s6errors16BaseThrowingInit{{.*}}c : $@convention(method) (Int, Int, @owned BaseThrowingInit) -> (@owned BaseThrowingInit, @error any Error) // CHECK: [[BOX:%.*]] = alloc_box ${ var BaseThrowingInit } // CHECK: [[MARKED_BOX:%.*]] = mark_uninitialized [derivedself] [[BOX]] // CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [var_decl] [[MARKED_BOX]] // CHECK: [[PB:%.*]] = project_box [[BOX_LIFETIME]] // Initialize subField. // CHECK: [[T0:%.*]] = load_borrow [[PB]] // CHECK-NEXT: [[T1:%.*]] = ref_element_addr [[T0]] : $BaseThrowingInit, #BaseThrowingInit.subField // CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [dynamic] [[T1]] : $*Int // CHECK-NEXT: assign %1 to [[WRITE]] // CHECK-NEXT: end_access [[WRITE]] // CHECK-NEXT: end_borrow [[T0]] // Super delegation. // CHECK-NEXT: [[T0:%.*]] = load [take] [[PB]] // CHECK-NEXT: [[T2:%.*]] = upcast [[T0]] : $BaseThrowingInit to $HasThrowingInit // CHECK: [[T3:%[0-9]+]] = function_ref @$s6errors15HasThrowingInitC5valueACSi_tKcfc : $@convention(method) (Int, @owned HasThrowingInit) -> (@owned HasThrowingInit, @error any Error) // CHECK-NEXT: apply [[T3]](%0, [[T2]]) // Cleanups for writebacks. protocol Supportable { mutating func support() throws } protocol Buildable { associatedtype Structure : Supportable var firstStructure: Structure { get set } subscript(name: String) -> Structure { get set } } func supportFirstStructure(_ b: inout B) throws { try b.firstStructure.support() } // CHECK-LABEL: sil hidden [ossa] @$s6errors21supportFirstStructure{{.*}}F : $@convention(thin) (@inout B) -> @error any Error { // CHECK: [[MODIFY:%.*]] = witness_method $B, #Buildable.firstStructure!modify : // CHECK: ([[T1:%.*]], [[TOKEN:%.*]]) = begin_apply [[MODIFY]]([[BASE:%[0-9]*]]) // CHECK: [[SUPPORT:%.*]] = witness_method $B.Structure, #Supportable.support : // CHECK: try_apply [[SUPPORT]]([[T1]]) : {{.*}}, normal [[BB_NORMAL:bb[0-9]+]], error [[BB_ERROR:bb[0-9]+]] // CHECK: [[BB_NORMAL]] // CHECK: end_apply [[TOKEN]] // CHECK: return // CHECK: [[BB_ERROR]]([[ERROR:%.*]] : @owned $any Error): // CHECK: abort_apply [[TOKEN]] // CHECK: throw [[ERROR]] // CHECK: } // end sil function '$s6errors21supportFirstStructure{{.*}}F' func supportStructure(_ b: inout B, name: String) throws { try b[name].support() } // CHECK-LABEL: sil hidden [ossa] @$s6errors16supportStructure_4nameyxz_SStKAA9BuildableRzlF : $@convention(thin) (@inout B, @guaranteed String) -> @error any Error { // CHECK: bb0({{.*}}, [[INDEX:%.*]] : @guaranteed $String): // CHECK: [[INDEX_COPY:%.*]] = copy_value [[INDEX]] : $String // CHECK: [[BORROWED_INDEX_COPY:%.*]] = begin_borrow [[INDEX_COPY]] // CHECK: [[MODIFY:%.*]] = witness_method $B, #Buildable.subscript!modify : // CHECK: ([[T1:%.*]], [[TOKEN:%.*]]) = begin_apply [[MODIFY]]([[BORROWED_INDEX_COPY]], [[BASE:%[0-9]*]]) // CHECK: [[SUPPORT:%.*]] = witness_method $B.Structure, #Supportable.support : // CHECK: try_apply [[SUPPORT]]([[T1]]) : $@convention(witness_method: Supportable) <τ_0_0 where τ_0_0 : Supportable> (@inout τ_0_0) -> @error any Error, normal [[BB_NORMAL:bb[0-9]+]], error [[BB_ERROR:bb[0-9]+]] // CHECK: [[BB_NORMAL]] // CHECK: end_apply [[TOKEN]] // CHECK: end_borrow [[BORROWED_INDEX_COPY]] // CHECK: destroy_value [[INDEX_COPY]] : $String // CHECK: return // CHECK: [[BB_ERROR]]([[ERROR:%.*]] : @owned $any Error): // CHECK: abort_apply [[TOKEN]] // CHECK: end_borrow [[BORROWED_INDEX_COPY]] // CHECK: destroy_value [[INDEX_COPY]] : $String // CHECK: throw [[ERROR]] // CHECK: } // end sil function '$s6errors16supportStructure{{.*}}F' struct Pylon { var name: String mutating func support() throws {} } struct Bridge { var mainPylon : Pylon subscript(name: String) -> Pylon { get { return mainPylon } set {} } } func supportStructure(_ b: inout Bridge, name: String) throws { try b[name].support() } // CHECK: sil hidden [ossa] @$s6errors16supportStructure_4nameyAA6BridgeVz_SStKF : $@convention(thin) (@inout Bridge, @guaranteed String) -> @error any Error { // CHECK: bb0([[ARG1:%.*]] : $*Bridge, [[ARG2:%.*]] : @guaranteed $String): // CHECK: [[INDEX_COPY_1:%.*]] = copy_value [[ARG2]] : $String // CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [unknown] [[ARG1]] : $*Bridge // CHECK-NEXT: [[INDEX_COPY_2:%.*]] = copy_value [[INDEX_COPY_1]] : $String // CHECK-NEXT: [[TEMP:%.*]] = alloc_stack $Pylon // CHECK-NEXT: [[BASE:%.*]] = load_borrow [[WRITE]] : $*Bridge // CHECK-NEXT: // function_ref // CHECK-NEXT: [[GETTER:%.*]] = function_ref @$s6errors6BridgeVyAA5PylonVSScig : // CHECK-NEXT: [[T0:%.*]] = apply [[GETTER]]([[INDEX_COPY_1]], [[BASE]]) // CHECK-NEXT: store [[T0]] to [init] [[TEMP]] // CHECK-NEXT: end_borrow [[BASE]] // CHECK: [[SUPPORT:%.*]] = function_ref @$s6errors5PylonV7supportyyKF // CHECK-NEXT: try_apply [[SUPPORT]]([[TEMP]]) : {{.*}}, normal [[BB_NORMAL:bb[0-9]+]], error [[BB_ERROR:bb[0-9]+]] // CHECK: [[BB_NORMAL]] // CHECK-NEXT: [[T0:%.*]] = load [take] [[TEMP]] // CHECK-NEXT: // function_ref // CHECK-NEXT: [[SETTER:%.*]] = function_ref @$s6errors6BridgeVyAA5PylonVSScis : // CHECK-NEXT: apply [[SETTER]]([[T0]], [[INDEX_COPY_2]], [[WRITE]]) // CHECK-NEXT: end_access [[WRITE]] // CHECK-NEXT: dealloc_stack [[TEMP]] // CHECK-NEXT: destroy_value [[INDEX_COPY_1]] : $String // CHECK-NEXT: tuple () // CHECK-NEXT: return // We end up with ugly redundancy here because we don't want to // consume things during cleanup emission. It's questionable. // CHECK: [[BB_ERROR]]([[ERROR:%.*]] : @owned $any Error): // CHECK-NEXT: [[T0:%.*]] = load [copy] [[TEMP]] // CHECK-NEXT: [[INDEX_COPY_2_COPY:%.*]] = copy_value [[INDEX_COPY_2]] // CHECK-NEXT: // function_ref // CHECK-NEXT: [[SETTER:%.*]] = function_ref @$s6errors6BridgeVyAA5PylonVSScis : // CHECK-NEXT: apply [[SETTER]]([[T0]], [[INDEX_COPY_2_COPY]], [[WRITE]]) // CHECK-NEXT: destroy_addr [[TEMP]] // CHECK-NEXT: dealloc_stack [[TEMP]] // ==> SEMANTIC ARC TODO: INDEX_COPY_2 on the next line should be INDEX_COPY_2_COPY // CHECK-NEXT: destroy_value [[INDEX_COPY_2]] : $String // CHECK-NEXT: end_access [[WRITE]] // CHECK-NEXT: destroy_value [[INDEX_COPY_1]] : $String // CHECK-NEXT: throw [[ERROR]] // CHECK: } // end sil function '$s6errors16supportStructure_4nameyAA6BridgeVz_SStKF' // ! peepholes its argument with getSemanticsProvidingExpr(). // Test that doesn't look through try!. // rdar://21515402 func testForcePeephole(_ f: () throws -> Int?) -> Int { let x = (try! f())! return x } // CHECK-LABEL: sil hidden [ossa] @$s6errors15testOptionalTryyyF // CHECK-NEXT: bb0: // CHECK: [[FN:%.+]] = function_ref @$s6errors10make_a_catAA3CatCyKF // CHECK-NEXT: try_apply [[FN]]() : $@convention(thin) () -> (@owned Cat, @error any Error), normal [[SUCCESS:[^ ]+]], error [[CLEANUPS:[^ ]+]], // CHECK: [[SUCCESS]]([[VALUE:%.+]] : @owned $Cat) // CHECK-NEXT: [[WRAPPED:%.+]] = enum $Optional, #Optional.some!enumelt, [[VALUE]] // CHECK-NEXT: br [[DONE:[^ ]+]]([[WRAPPED]] : $Optional) // CHECK: [[DONE]]([[RESULT:%.+]] : @owned $Optional): // CHECK-NEXT: ignored_use [[RESULT]] // CHECK-NEXT: destroy_value [[RESULT]] : $Optional // CHECK-NEXT: [[VOID:%.+]] = tuple () // CHECK-NEXT: return [[VOID]] : $() // CHECK: [[CLEANUPS:.+]]([[ERROR:%.*]] : @owned $any Error): // CHECK-NEXT: destroy_value [[ERROR]] // CHECK-NEXT: [[NONE:%.+]] = enum $Optional, #Optional.none!enumelt // CHECK-NEXT: br [[DONE]]([[NONE]] : $Optional) // CHECK: } // end sil function '$s6errors15testOptionalTryyyF' func testOptionalTry() { _ = try? make_a_cat() } func sudo_make_a_cat() {} // CHECK-LABEL: sil hidden [ossa] @{{.*}}testOptionalTryThatNeverThrows func testOptionalTryThatNeverThrows() { guard let _ = try? sudo_make_a_cat() else { // expected-warning{{no calls to throwing}} return } } // CHECK-LABEL: sil hidden [ossa] @$s6errors18testOptionalTryVaryyF // CHECK-NEXT: bb0: // CHECK-NEXT: [[BOX:%.+]] = alloc_box ${ var Optional } // CHECK-NEXT: [[LIFETIME:%.+]] = begin_borrow [lexical] [var_decl] [[BOX]] // CHECK-NEXT: [[PB:%.*]] = project_box [[LIFETIME]] // CHECK: [[FN:%.+]] = function_ref @$s6errors10make_a_catAA3CatCyKF // CHECK-NEXT: try_apply [[FN]]() : $@convention(thin) () -> (@owned Cat, @error any Error), normal [[SUCCESS:[^ ]+]], error [[CLEANUPS:[^ ]+]], // CHECK: [[SUCCESS]]([[VALUE:%.+]] : @owned $Cat) // CHECK-NEXT: [[CAT_ENUM:%.+]] = enum $Optional, #Optional.some!enumelt // CHECK-NEXT: store [[CAT_ENUM]] to [init] [[PB]] : $*Optional // CHECK-NEXT: br [[DONE:[^ ]+]], // CHECK: [[DONE]]: // CHECK-NEXT: end_borrow [[LIFETIME]] // CHECK-NEXT: destroy_value [[BOX]] : ${ var Optional } // CHECK-NEXT: [[VOID:%.+]] = tuple () // CHECK-NEXT: return [[VOID]] : $() // CHECK: [[CLEANUPS:.+]]([[ERROR:%.*]] : @owned $any Error): // CHECK-NEXT: destroy_value [[ERROR]] // CHECK-NEXT: inject_enum_addr [[PB]] : $*Optional, #Optional.none!enumelt // CHECK-NEXT: br [[DONE]] // CHECK: } // end sil function '$s6errors18testOptionalTryVaryyF' func testOptionalTryVar() { var cat = try? make_a_cat() // expected-warning {{initialization of variable 'cat' was never used; consider replacing with assignment to '_' or removing it}} } // CHECK-LABEL: sil hidden [ossa] @$s6errors26testOptionalTryAddressOnly{{.*}}F // CHECK: bb0(%0 : $*T): // CHECK: [[BOX:%.+]] = alloc_stack $Optional // CHECK-NEXT: [[BOX_DATA:%.+]] = init_enum_data_addr [[BOX]] : $*Optional, #Optional.some!enumelt // CHECK: [[FN:%.+]] = function_ref @$s6errors11dont_return{{.*}}F // CHECK-NEXT: try_apply [[FN]]([[BOX_DATA]], %0) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> (@out τ_0_0, @error any Error), normal [[SUCCESS:[^ ]+]], error [[CLEANUPS:[^ ]+]], // CHECK: [[SUCCESS]]({{%.+}} : $()): // CHECK-NEXT: inject_enum_addr [[BOX]] : $*Optional, #Optional.some!enumelt // CHECK-NEXT: br [[DONE:[^ ]+]], // CHECK: [[DONE]]: // CHECK-NEXT: ignored_use [[BOX]] // CHECK-NEXT: destroy_addr [[BOX]] : $*Optional // CHECK-NEXT: dealloc_stack [[BOX]] : $*Optional // CHECK-NOT: destroy_addr %0 : $*T // CHECK-NEXT: [[VOID:%.+]] = tuple () // CHECK-NEXT: return [[VOID]] : $() // CHECK: [[CLEANUPS]]([[ERROR:%.+]] : @owned $any Error): // CHECK-NEXT: destroy_value [[ERROR]] // CHECK-NEXT: inject_enum_addr [[BOX]] : $*Optional, #Optional.none!enumelt // CHECK-NEXT: br [[DONE]] // CHECK: } // end sil function '$s6errors26testOptionalTryAddressOnlyyyxlF' func testOptionalTryAddressOnly(_ obj: T) { _ = try? dont_return(obj) } // CHECK-LABEL: sil hidden [ossa] @$s6errors29testOptionalTryAddressOnlyVar{{.*}}F // CHECK: bb0(%0 : $*T): // CHECK: [[BOX:%.+]] = alloc_box $<τ_0_0> { var Optional<τ_0_0> } // CHECK: [[LIFETIME:%.+]] = begin_borrow [lexical] [var_decl] [[BOX]] // CHECK-NEXT: [[PB:%.*]] = project_box [[LIFETIME]] // CHECK-NEXT: [[BOX_DATA:%.+]] = init_enum_data_addr [[PB]] : $*Optional, #Optional.some!enumelt // CHECK: [[FN:%.+]] = function_ref @$s6errors11dont_return{{.*}}F // CHECK-NEXT: try_apply [[FN]]([[BOX_DATA]], %0) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> (@out τ_0_0, @error any Error), normal [[SUCCESS:[^ ]+]], error [[CLEANUPS:[^ ]+]], // CHECK: [[SUCCESS]]({{%.+}} : $()): // CHECK-NEXT: inject_enum_addr [[PB]] : $*Optional, #Optional.some!enumelt // CHECK-NEXT: br [[DONE:[^ ]+]], // CHECK: [[DONE]]: // CHECK-NEXT: end_borrow [[LIFETIME]] // CHECK-NEXT: destroy_value [[BOX]] : $<τ_0_0> { var Optional<τ_0_0> } // CHECK-NOT: destroy_addr %0 : $*T // CHECK-NEXT: [[VOID:%.+]] = tuple () // CHECK-NEXT: return [[VOID]] : $() // CHECK: [[CLEANUPS]]([[ERROR:%.+]] : @owned $any Error): // CHECK-NEXT: destroy_value [[ERROR]] // CHECK-NEXT: inject_enum_addr [[PB]] : $*Optional, #Optional.none!enumelt // CHECK-NEXT: br [[DONE]] // CHECK: } // end sil function '$s6errors29testOptionalTryAddressOnlyVaryyxlF' func testOptionalTryAddressOnlyVar(_ obj: T) { var copy = try? dont_return(obj) // expected-warning {{initialization of variable 'copy' was never used; consider replacing with assignment to '_' or removing it}} } // CHECK-LABEL: sil hidden [ossa] @$s6errors23testOptionalTryMultipleyyF // CHECK: bb0: // CHECK: [[FN_1:%.+]] = function_ref @$s6errors10make_a_catAA3CatCyKF // CHECK-NEXT: try_apply [[FN_1]]() : $@convention(thin) () -> (@owned Cat, @error any Error), normal [[SUCCESS_1:[^ ]+]], error [[CLEANUPS_1:[^ ]+]], // CHECK: [[SUCCESS_1]]([[VALUE_1:%.+]] : @owned $Cat) // CHECK: [[FN_2:%.+]] = function_ref @$s6errors10make_a_catAA3CatCyKF // CHECK-NEXT: try_apply [[FN_2]]() : $@convention(thin) () -> (@owned Cat, @error any Error), normal [[SUCCESS_2:[^ ]+]], error [[CLEANUPS_2:[^ ]+]], // CHECK: [[SUCCESS_2]]([[VALUE_2:%.+]] : @owned $Cat) // CHECK-NEXT: [[TUPLE:%.+]] = tuple ([[VALUE_1]] : $Cat, [[VALUE_2]] : $Cat) // CHECK-NEXT: [[WRAPPED:%.+]] = enum $Optional<(Cat, Cat)>, #Optional.some!enumelt, [[TUPLE]] // CHECK-NEXT: br [[DONE:[^ ]+]]([[WRAPPED]] : $Optional<(Cat, Cat)>) // CHECK: [[DONE]]([[RESULT:%.+]] : @owned $Optional<(Cat, Cat)>): // CHECK-NEXT: ignored_use [[RESULT]] // CHECK-NEXT: destroy_value [[RESULT]] : $Optional<(Cat, Cat)> // CHECK-NEXT: [[VOID:%.+]] = tuple () // CHECK-NEXT: return [[VOID]] : $() // CHECK: [[FAILURE:.+]]([[ERROR:%.*]] : @owned $any Error): // CHECK-NEXT: destroy_value [[ERROR]] // CHECK-NEXT: [[NONE:%.+]] = enum $Optional<(Cat, Cat)>, #Optional.none!enumelt // CHECK-NEXT: br [[DONE]]([[NONE]] : $Optional<(Cat, Cat)>) // CHECK: [[CLEANUPS_1]]([[ERROR:%.+]] : @owned $any Error): // CHECK-NEXT: br [[FAILURE]]([[ERROR]] : $any Error) // CHECK: [[CLEANUPS_2]]([[ERROR:%.+]] : @owned $any Error): // CHECK-NEXT: destroy_value [[VALUE_1]] : $Cat // CHECK-NEXT: br [[FAILURE]]([[ERROR]] : $any Error) // CHECK: } // end sil function '$s6errors23testOptionalTryMultipleyyF' func testOptionalTryMultiple() { _ = try? (make_a_cat(), make_a_cat()) } // CHECK-LABEL: sil hidden [ossa] @$s6errors25testOptionalTryNeverFailsyyF // CHECK: bb0: // CHECK-NEXT: [[VALUE:%.+]] = tuple () // CHECK-NEXT: = enum $Optional<()>, #Optional.some!enumelt, [[VALUE]] // CHECK-NEXT: ignored_use // CHECK-NEXT: [[VOID:%.+]] = tuple () // CHECK-NEXT: return [[VOID]] : $() // CHECK: } // end sil function '$s6errors25testOptionalTryNeverFailsyyF' func testOptionalTryNeverFails() { _ = try? () // expected-warning {{no calls to throwing functions occur within 'try' expression}} } // CHECK-LABEL: sil hidden [ossa] @$s6errors28testOptionalTryNeverFailsVaryyF // CHECK: bb0: // CHECK-NEXT: [[BOX:%.+]] = alloc_box ${ var Optional<()> } // CHECK-NEXT: [[LIFETIME:%.*]] = begin_borrow [var_decl] [[BOX]] // CHECK-NEXT: [[PB:%.*]] = project_box [[LIFETIME]] // CHECK-NEXT: [[VALUE:%.+]] = tuple () // CHECK-NEXT: [[ENUM:%.+]] = enum $Optional<()>, #Optional.some!enumelt, [[VALUE]] // CHECK-NEXT: store [[ENUM]] to [trivial] [[PB]] : // CHECK-NEXT: end_borrow [[LIFETIME]] // CHECK-NEXT: destroy_value [[BOX]] : ${ var Optional<()> } // CHECK-NEXT: [[VOID:%.+]] = tuple () // CHECK-NEXT: return [[VOID]] : $() // CHECK-NEXT: } // end sil function '$s6errors28testOptionalTryNeverFailsVaryyF' func testOptionalTryNeverFailsVar() { var unit: ()? = try? () // expected-warning {{no calls to throwing functions occur within 'try' expression}} expected-warning {{variable 'unit' was never used; consider replacing with '_' or removing it}} } // CHECK-LABEL: sil hidden [ossa] @$s6errors36testOptionalTryNeverFailsAddressOnly{{.*}}F // CHECK: bb0(%0 : $*T): // CHECK: [[BOX:%.+]] = alloc_stack $Optional // CHECK-NEXT: [[BOX_DATA:%.+]] = init_enum_data_addr [[BOX]] : $*Optional, #Optional.some!enumelt // CHECK-NEXT: copy_addr %0 to [init] [[BOX_DATA]] : $*T // CHECK-NEXT: inject_enum_addr [[BOX]] : $*Optional, #Optional.some!enumelt // CHECK-NEXT: ignored_use [[BOX]] // CHECK-NEXT: destroy_addr [[BOX]] : $*Optional // CHECK-NEXT: dealloc_stack [[BOX]] : $*Optional // CHECK-NOT: destroy_addr %0 : $*T // CHECK-NEXT: [[VOID:%.+]] = tuple () // CHECK-NEXT: return [[VOID]] : $() // CHECK-NEXT: } // end sil function '$s6errors36testOptionalTryNeverFailsAddressOnlyyyxlF' func testOptionalTryNeverFailsAddressOnly(_ obj: T) { _ = try? obj // expected-warning {{no calls to throwing functions occur within 'try' expression}} } // CHECK-LABEL: sil hidden [ossa] @$s6errors39testOptionalTryNeverFailsAddressOnlyVar{{.*}}F // CHECK: bb0(%0 : $*T): // CHECK: [[BOX:%.+]] = alloc_box $<τ_0_0> { var Optional<τ_0_0> } // CHECK-NEXT: [[LIFETIME:%.+]] = begin_borrow [lexical] [var_decl] [[BOX]] // CHECK-NEXT: [[PB:%.*]] = project_box [[LIFETIME]] // CHECK-NEXT: [[BOX_DATA:%.+]] = init_enum_data_addr [[PB]] : $*Optional, #Optional.some!enumelt // CHECK-NEXT: copy_addr %0 to [init] [[BOX_DATA]] : $*T // CHECK-NEXT: inject_enum_addr [[PB]] : $*Optional, #Optional.some!enumelt // CHECK-NEXT: end_borrow [[LIFETIME]] // CHECK-NEXT: destroy_value [[BOX]] : $<τ_0_0> { var Optional<τ_0_0> } // CHECK-NEXT: [[VOID:%.+]] = tuple () // CHECK-NEXT: return [[VOID]] : $() // CHECK: } // end sil function '$s6errors13OtherErrorSubCACycfC' func testOptionalTryNeverFailsAddressOnlyVar(_ obj: T) { var copy = try? obj // expected-warning {{no calls to throwing functions occur within 'try' expression}} expected-warning {{initialization of variable 'copy' was never used; consider replacing with assignment to '_' or removing it}} } class SomeErrorClass : Error { } // CHECK-LABEL: sil_vtable SomeErrorClass // CHECK-NEXT: #SomeErrorClass.init!allocator: {{.*}} : @$s6errors14SomeErrorClassCACycfC // CHECK-NEXT: #SomeErrorClass.deinit!deallocator: @$s6errors14SomeErrorClassCfD // CHECK-NEXT: } class OtherErrorSub : OtherError { } // CHECK-LABEL: sil_vtable OtherErrorSub { // CHECK-NEXT: #OtherError.init!allocator: {{.*}} : @$s6errors13OtherErrorSubCACycfC [override] // CHECK-NEXT: #OtherErrorSub.deinit!deallocator: @$s6errors13OtherErrorSubCfD // OtherErrorSub.__deallocating_deinit // CHECK-NEXT:}