diff --git a/examples/basic/expected/0031-basic-local-fn-return.ir b/examples/basic/expected/0031-basic-local-fn-return.ir index 78ab51e9..d6832a0c 100644 --- a/examples/basic/expected/0031-basic-local-fn-return.ir +++ b/examples/basic/expected/0031-basic-local-fn-return.ir @@ -4470,6 +4470,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/basic/expected/0032-basic-ufcs-return-type.ir b/examples/basic/expected/0032-basic-ufcs-return-type.ir index 6204648f..cfb0c72e 100644 --- a/examples/basic/expected/0032-basic-ufcs-return-type.ir +++ b/examples/basic/expected/0032-basic-ufcs-return-type.ir @@ -4392,6 +4392,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/basic/expected/0044-basic-default-arg-expansion.ir b/examples/basic/expected/0044-basic-default-arg-expansion.ir index 65c8cc6f..08100e24 100644 --- a/examples/basic/expected/0044-basic-default-arg-expansion.ir +++ b/examples/basic/expected/0044-basic-default-arg-expansion.ir @@ -4308,6 +4308,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/closures/expected/0301-closures-fn-pointers.ir b/examples/closures/expected/0301-closures-fn-pointers.ir index 2f97a891..df24af13 100644 --- a/examples/closures/expected/0301-closures-fn-pointers.ir +++ b/examples/closures/expected/0301-closures-fn-pointers.ir @@ -4317,6 +4317,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/concurrency/expected/1807-concurrency-fiber-context-switch.ir b/examples/concurrency/expected/1807-concurrency-fiber-context-switch.ir index e5acebeb..eb102c18 100644 --- a/examples/concurrency/expected/1807-concurrency-fiber-context-switch.ir +++ b/examples/concurrency/expected/1807-concurrency-fiber-context-switch.ir @@ -4469,6 +4469,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/concurrency/expected/1808-concurrency-fiber-switch-stress.ir b/examples/concurrency/expected/1808-concurrency-fiber-switch-stress.ir index 8b3db9ed..1b63ca4d 100644 --- a/examples/concurrency/expected/1808-concurrency-fiber-switch-stress.ir +++ b/examples/concurrency/expected/1808-concurrency-fiber-switch-stress.ir @@ -4445,6 +4445,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/concurrency/expected/1809-concurrency-fiber-guard-stack.ir b/examples/concurrency/expected/1809-concurrency-fiber-guard-stack.ir index 08e71fef..10be516d 100644 --- a/examples/concurrency/expected/1809-concurrency-fiber-guard-stack.ir +++ b/examples/concurrency/expected/1809-concurrency-fiber-guard-stack.ir @@ -4444,6 +4444,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/errors/expected/1004-errors-try.ir b/examples/errors/expected/1004-errors-try.ir index 9ebed7fc..50b5b69c 100644 --- a/examples/errors/expected/1004-errors-try.ir +++ b/examples/errors/expected/1004-errors-try.ir @@ -4321,6 +4321,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/errors/expected/1006-errors-inferred-error-sets.ir b/examples/errors/expected/1006-errors-inferred-error-sets.ir index b6519917..34135e78 100644 --- a/examples/errors/expected/1006-errors-inferred-error-sets.ir +++ b/examples/errors/expected/1006-errors-inferred-error-sets.ir @@ -4326,6 +4326,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/errors/expected/1009-errors-catch.ir b/examples/errors/expected/1009-errors-catch.ir index 4c473d27..50751996 100644 --- a/examples/errors/expected/1009-errors-catch.ir +++ b/examples/errors/expected/1009-errors-catch.ir @@ -4323,6 +4323,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/ffi-jni/expected/1402-ffi-jni-call-03-methodid-sharing.ir b/examples/ffi-jni/expected/1402-ffi-jni-call-03-methodid-sharing.ir index d78d87f6..4830e254 100644 --- a/examples/ffi-jni/expected/1402-ffi-jni-call-03-methodid-sharing.ir +++ b/examples/ffi-jni/expected/1402-ffi-jni-call-03-methodid-sharing.ir @@ -4277,6 +4277,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/ffi-jni/expected/1403-ffi-jni-call-04-jint-return.ir b/examples/ffi-jni/expected/1403-ffi-jni-call-04-jint-return.ir index 469f3453..fa322916 100644 --- a/examples/ffi-jni/expected/1403-ffi-jni-call-04-jint-return.ir +++ b/examples/ffi-jni/expected/1403-ffi-jni-call-04-jint-return.ir @@ -4275,6 +4275,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/ffi-jni/expected/1404-ffi-jni-call-05-jlong-return.ir b/examples/ffi-jni/expected/1404-ffi-jni-call-05-jlong-return.ir index c70ed569..2045aabf 100644 --- a/examples/ffi-jni/expected/1404-ffi-jni-call-05-jlong-return.ir +++ b/examples/ffi-jni/expected/1404-ffi-jni-call-05-jlong-return.ir @@ -4275,6 +4275,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/ffi-jni/expected/1405-ffi-jni-call-06-jdouble-return.ir b/examples/ffi-jni/expected/1405-ffi-jni-call-06-jdouble-return.ir index 53e05a5b..251c59d2 100644 --- a/examples/ffi-jni/expected/1405-ffi-jni-call-06-jdouble-return.ir +++ b/examples/ffi-jni/expected/1405-ffi-jni-call-06-jdouble-return.ir @@ -4288,6 +4288,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/ffi-jni/expected/1406-ffi-jni-call-07-jboolean-return.ir b/examples/ffi-jni/expected/1406-ffi-jni-call-07-jboolean-return.ir index c9e9de7a..c53fab8b 100644 --- a/examples/ffi-jni/expected/1406-ffi-jni-call-07-jboolean-return.ir +++ b/examples/ffi-jni/expected/1406-ffi-jni-call-07-jboolean-return.ir @@ -4275,6 +4275,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/ffi-jni/expected/1407-ffi-jni-call-08-jobject-return.ir b/examples/ffi-jni/expected/1407-ffi-jni-call-08-jobject-return.ir index 7e77eef3..58dfc3b9 100644 --- a/examples/ffi-jni/expected/1407-ffi-jni-call-08-jobject-return.ir +++ b/examples/ffi-jni/expected/1407-ffi-jni-call-08-jobject-return.ir @@ -4275,6 +4275,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/ffi-jni/expected/1408-ffi-jni-call-09-static.ir b/examples/ffi-jni/expected/1408-ffi-jni-call-09-static.ir index 1f374d48..4387456d 100644 --- a/examples/ffi-jni/expected/1408-ffi-jni-call-09-static.ir +++ b/examples/ffi-jni/expected/1408-ffi-jni-call-09-static.ir @@ -4275,6 +4275,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/ffi-jni/expected/1418-ffi-jni-class-08-call.ir b/examples/ffi-jni/expected/1418-ffi-jni-class-08-call.ir index f46e39d8..5da930c8 100644 --- a/examples/ffi-jni/expected/1418-ffi-jni-class-08-call.ir +++ b/examples/ffi-jni/expected/1418-ffi-jni-class-08-call.ir @@ -4319,6 +4319,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/ffi-jni/expected/1421-ffi-jni-env-02-lexical-direct.ir b/examples/ffi-jni/expected/1421-ffi-jni-env-02-lexical-direct.ir index 7dc50eef..11ff568d 100644 --- a/examples/ffi-jni/expected/1421-ffi-jni-env-02-lexical-direct.ir +++ b/examples/ffi-jni/expected/1421-ffi-jni-env-02-lexical-direct.ir @@ -4275,6 +4275,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/ffi-jni/expected/1425-ffi-jni-main-03-ctor.ir b/examples/ffi-jni/expected/1425-ffi-jni-main-03-ctor.ir index ade4a918..88eb0b3e 100644 --- a/examples/ffi-jni/expected/1425-ffi-jni-main-03-ctor.ir +++ b/examples/ffi-jni/expected/1425-ffi-jni-main-03-ctor.ir @@ -4283,6 +4283,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/ffi-objc/expected/1309-ffi-objc-class-method-lowering.ir b/examples/ffi-objc/expected/1309-ffi-objc-class-method-lowering.ir index 86270e17..a9db4ddd 100644 --- a/examples/ffi-objc/expected/1309-ffi-objc-class-method-lowering.ir +++ b/examples/ffi-objc/expected/1309-ffi-objc-class-method-lowering.ir @@ -4318,6 +4318,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/ffi-objc/expected/1314-ffi-objc-class-dealloc-roundtrip.ir b/examples/ffi-objc/expected/1314-ffi-objc-class-dealloc-roundtrip.ir index 6692741c..30efc8d9 100644 --- a/examples/ffi-objc/expected/1314-ffi-objc-class-dealloc-roundtrip.ir +++ b/examples/ffi-objc/expected/1314-ffi-objc-class-dealloc-roundtrip.ir @@ -4395,6 +4395,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/ffi-objc/expected/1319-ffi-objc-property-sx-defined.ir b/examples/ffi-objc/expected/1319-ffi-objc-property-sx-defined.ir index 4f98ed79..12911b8b 100644 --- a/examples/ffi-objc/expected/1319-ffi-objc-property-sx-defined.ir +++ b/examples/ffi-objc/expected/1319-ffi-objc-property-sx-defined.ir @@ -4443,6 +4443,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/ffi-objc/expected/1329-ffi-objc-call-03-selector-sharing.ir b/examples/ffi-objc/expected/1329-ffi-objc-call-03-selector-sharing.ir index 05285f3f..cb1916d2 100644 --- a/examples/ffi-objc/expected/1329-ffi-objc-call-03-selector-sharing.ir +++ b/examples/ffi-objc/expected/1329-ffi-objc-call-03-selector-sharing.ir @@ -4275,6 +4275,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/ffi-objc/expected/1332-ffi-objc-call-06-sret-return.ir b/examples/ffi-objc/expected/1332-ffi-objc-call-06-sret-return.ir index 1de05c2c..6f3eb002 100644 --- a/examples/ffi-objc/expected/1332-ffi-objc-call-06-sret-return.ir +++ b/examples/ffi-objc/expected/1332-ffi-objc-call-06-sret-return.ir @@ -4371,6 +4371,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/ffi-objc/expected/1347-ffi-objc-dsl-07-mangling-table.ir b/examples/ffi-objc/expected/1347-ffi-objc-dsl-07-mangling-table.ir index 083518ca..746d2af0 100644 --- a/examples/ffi-objc/expected/1347-ffi-objc-dsl-07-mangling-table.ir +++ b/examples/ffi-objc/expected/1347-ffi-objc-dsl-07-mangling-table.ir @@ -4376,6 +4376,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/ffi/expected/1202-ffi-cc-c-large-aggregate.ir b/examples/ffi/expected/1202-ffi-cc-c-large-aggregate.ir index 0b59f7e6..2b615a04 100644 --- a/examples/ffi/expected/1202-ffi-cc-c-large-aggregate.ir +++ b/examples/ffi/expected/1202-ffi-cc-c-large-aggregate.ir @@ -4302,6 +4302,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/generics/expected/0200-generics-generic.ir b/examples/generics/expected/0200-generics-generic.ir index 39983c0e..55fffdf3 100644 --- a/examples/generics/expected/0200-generics-generic.ir +++ b/examples/generics/expected/0200-generics-generic.ir @@ -4312,6 +4312,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/generics/expected/0201-generics-generic-struct.ir b/examples/generics/expected/0201-generics-generic-struct.ir index 97424ed8..1072e9b8 100644 --- a/examples/generics/expected/0201-generics-generic-struct.ir +++ b/examples/generics/expected/0201-generics-generic-struct.ir @@ -4616,6 +4616,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/optionals/expected/0903-optionals-optional-roundtrip.ir b/examples/optionals/expected/0903-optionals-optional-roundtrip.ir index 80d26fc1..44d25cb9 100644 --- a/examples/optionals/expected/0903-optionals-optional-roundtrip.ir +++ b/examples/optionals/expected/0903-optionals-optional-roundtrip.ir @@ -4506,6 +4506,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/optionals/expected/0904-optionals-any-to-string-optional.ir b/examples/optionals/expected/0904-optionals-any-to-string-optional.ir index 21542b6d..7c8f1693 100644 --- a/examples/optionals/expected/0904-optionals-any-to-string-optional.ir +++ b/examples/optionals/expected/0904-optionals-any-to-string-optional.ir @@ -4357,6 +4357,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/packs/expected/0507-packs-pack-mono-dedup.ir b/examples/packs/expected/0507-packs-pack-mono-dedup.ir index 83d0eb8a..954f5e33 100644 --- a/examples/packs/expected/0507-packs-pack-mono-dedup.ir +++ b/examples/packs/expected/0507-packs-pack-mono-dedup.ir @@ -4323,6 +4323,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/packs/expected/0513-packs-pack-mixed-comptime.ir b/examples/packs/expected/0513-packs-pack-mixed-comptime.ir index 3b3fa530..11953f8f 100644 --- a/examples/packs/expected/0513-packs-pack-mixed-comptime.ir +++ b/examples/packs/expected/0513-packs-pack-mixed-comptime.ir @@ -4296,6 +4296,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/packs/expected/0518-packs-pack-value-dispatch.ir b/examples/packs/expected/0518-packs-pack-value-dispatch.ir index 41e5679f..5874a678 100644 --- a/examples/packs/expected/0518-packs-pack-value-dispatch.ir +++ b/examples/packs/expected/0518-packs-pack-value-dispatch.ir @@ -4318,6 +4318,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/packs/expected/0528-packs-protocol-pack-methods.ir b/examples/packs/expected/0528-packs-protocol-pack-methods.ir index 93664598..edf4b8c6 100644 --- a/examples/packs/expected/0528-packs-protocol-pack-methods.ir +++ b/examples/packs/expected/0528-packs-protocol-pack-methods.ir @@ -4472,6 +4472,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/protocols/expected/0400-protocols-impl-for-builtin.ir b/examples/protocols/expected/0400-protocols-impl-for-builtin.ir index 369aea53..a9a0dac7 100644 --- a/examples/protocols/expected/0400-protocols-impl-for-builtin.ir +++ b/examples/protocols/expected/0400-protocols-impl-for-builtin.ir @@ -4425,6 +4425,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/protocols/expected/0413-protocols-parameterized-protocol-value.ir b/examples/protocols/expected/0413-protocols-parameterized-protocol-value.ir index 4d77e214..93152ff3 100644 --- a/examples/protocols/expected/0413-protocols-parameterized-protocol-value.ir +++ b/examples/protocols/expected/0413-protocols-parameterized-protocol-value.ir @@ -4522,6 +4522,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/protocols/expected/0414-protocols-generic-struct-protocol-erase.ir b/examples/protocols/expected/0414-protocols-generic-struct-protocol-erase.ir index c1c3da8a..2df51921 100644 --- a/examples/protocols/expected/0414-protocols-generic-struct-protocol-erase.ir +++ b/examples/protocols/expected/0414-protocols-generic-struct-protocol-erase.ir @@ -4538,6 +4538,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/protocols/expected/0416-protocols-auto-type-erasure.ir b/examples/protocols/expected/0416-protocols-auto-type-erasure.ir index c861c4cf..c780dab8 100644 --- a/examples/protocols/expected/0416-protocols-auto-type-erasure.ir +++ b/examples/protocols/expected/0416-protocols-auto-type-erasure.ir @@ -4631,6 +4631,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/examples/types/expected/0107-types-int-cmp-in-float-ternary.ir b/examples/types/expected/0107-types-int-cmp-in-float-ternary.ir index 78ec7ce5..678520b0 100644 --- a/examples/types/expected/0107-types-int-cmp-in-float-ternary.ir +++ b/examples/types/expected/0107-types-int-cmp-in-float-ternary.ir @@ -4311,6 +4311,9 @@ declare i64 @now_secs(ptr) #0 ; Function Attrs: nounwind declare i64 @mono_ms(ptr) #0 +; Function Attrs: nounwind +declare void @abort() #0 + ; Function Attrs: nounwind define internal ptr @CBlockingIo.spawn_raw(ptr %0, ptr %1, ptr %2, ptr %3, { i64 } %4) #0 { entry: diff --git a/library/modules/std/io.sx b/library/modules/std/io.sx index af9e64ef..9c40f9dd 100644 --- a/library/modules/std/io.sx +++ b/library/modules/std/io.sx @@ -26,6 +26,9 @@ #import "modules/std/atomic.sx"; time :: #import "modules/std/time.sx"; +// Loud-bail for the one-awaiter-per-future invariant (mirrors sched.sx). +io_abort :: () -> noreturn extern libc "abort"; + // --- IoErr: the error channel async rides (cancellation = model (a)) --- // // A canceled future raises `.Canceled` out of `await`; a failed task @@ -125,17 +128,28 @@ sx_run_boxed_closure :: (arg: *void) { // (issue 0156 Part 2) — so any inputs are captured at the CALL SITE in the lambda // (`context.io.async(() -> i64 => compute(a, b))`), exactly like `sched.go`. // -// The Future is HEAP-allocated (not returned by value): under the fiber impl the -// worker fills it AFTER `async` returns, so the awaiter and the worker must share -// one stable object. Like `sched.go`'s Task, it currently leaks (bounded by the -// async count; invisible under the default GPA). Freeing it needs join-point -// ownership — deferred. +// The Future (and the completion-closure `ThunkBox`) are HEAP-allocated (not +// returned by value): under the fiber impl the worker fills the Future AFTER +// `async` returns, so the awaiter and the worker must share one stable object. +// Like `sched.go`'s Task, they currently leak (bounded by the async count; +// invisible under the default GPA). Freeing them needs join-point ownership — +// deferred. +// +// ALLOCATOR-LIFETIME CONTRACT: both are allocated from the `context.allocator` +// in force at the `async` CALL, and that allocator MUST outlive the future — +// i.e. survive until the worker has run and the result is consumed. This is the +// long-lived-container rule (CLAUDE.md): calling `async` inside a transient +// `push Context { allocator = arena }` that is torn down before `run()`/`await` +// drives the worker frees the Future while it is still live (use-after-free). +// The common case (the program-stable default GPA, or a scheduler set up under a +// long-lived allocator) is safe. A deeper fix — `async` capturing the scheduler's +// own long-lived allocator the way `sched.go` does — needs a protocol affordance +// to reach it and is deferred to the convergence phase. async :: ufcs (io: Io, worker: Closure() -> $R) -> *Future($R) { raw := context.allocator.alloc_bytes(size_of(Future($R))); f : *Future($R) = xx raw; f.state = .pending; f.park = .{ handle = null }; - f.task = null; f.canceled = Atomic(bool).init(false); // The completion closure: run the worker, publish the result, wake any parked // awaiter. Heap-boxed so it survives until the worker actually runs (deferred @@ -161,6 +175,17 @@ async :: ufcs (io: Io, worker: Closure() -> $R) -> *Future($R) { await :: ufcs (f: *Future($R)) -> $R !IoErr { if f.canceled.load(.acquire) { raise error.Canceled; } if f.state == .pending { + // ONE awaiter per future (M:1): the single `park` slot records one parked + // fiber, so a second concurrent `await` on the same pending future would + // OVERWRITE the first awaiter's handle and orphan it forever (the worker's + // single `ready(f.park)` wakes only the last). Enforce loudly here, exactly + // as `sched.Task.wait` does — a non-null handle on a still-pending future + // means another fiber is already parked on it. (Fan-in over many futures — + // `race` — registers ONE awaiter across SEPARATE futures, so it is fine.) + if f.park.handle != null { + out("io: await — future already has an awaiter (one awaiter per future in the M:1 model)\n"); + io_abort(); + } context.io.suspend_raw(@f.park) catch {}; // Phase 3 propagates Canceled } if f.canceled.load(.acquire) { raise error.Canceled; } @@ -169,10 +194,14 @@ await :: ufcs (f: *Future($R)) -> $R !IoErr { return f.value; } -// `cancel(f)` — request cancellation. Sets the per-future cancel flag + -// marks the state so a subsequent `await` raises `.Canceled`. (In the -// blocking model the task already ran; cancel still rides the `!` -// channel — model (a).) +// `cancel(f)` — request cancellation. Sets the per-future cancel flag + marks the +// state so a subsequent `await` raises `.Canceled` (model (a) — cancel rides the +// `!` channel). DOES NOT STOP AN ALREADY-SPAWNED WORKER: under the fiber impl the +// worker fiber is already queued, so `run()` still executes it to completion (its +// side effects happen; it flips `.canceled -> .ready`). The sticky `canceled` +// atomic is the source of truth — subsequent awaits keep raising regardless of +// the state field. True work-cancellation (the worker's next suspend raising +// `Canceled` so it abandons its body) is Phase 3. cancel :: ufcs (f: *Future($R)) { f.canceled.store(true, .release); f.state = .canceled;