commit 0dcc91b39522fbc9557618c46bf4d193aa40bba9
parent 10edd3fecf8e36b56b5b8b41b653755dd44de48c
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Thu, 7 May 2026 13:14:35 -0700
setjmp.h
Diffstat:
3 files changed, 40 insertions(+), 0 deletions(-)
diff --git a/doc/builtins.md b/doc/builtins.md
@@ -149,6 +149,10 @@ Always:
- Float → float: `__extendsfdf2`, `__extendsftf2`, `__extenddftf2`, `__truncdfsf2`, `__trunctfsf2`, `__trunctfdf2`
- Compare: `__eq`, `__ne`, `__lt`, `__le`, `__gt`, `__ge`, `__unord` × `sf2`/`df2`/`tf2`
+### Nonlocal jumps (always shipped)
+- `setjmp`, `longjmp` — target-specific assembly. The `jmp_buf` layout is
+ internal to these two functions; `<setjmp.h>` only fixes the array size.
+
### Atomic fallbacks (only when target lacks native atomics for that width)
- Generic: `__atomic_load`, `__atomic_store`, `__atomic_exchange`, `__atomic_compare_exchange`
- Sized N ∈ {1,2,4,8,16}: `__atomic_load_N`, `__atomic_store_N`, `__atomic_exchange_N`, `__atomic_compare_exchange_N`, `__atomic_fetch_{add,sub,and,or,xor,nand}_N`
diff --git a/include/setjmp.h b/include/setjmp.h
@@ -0,0 +1,23 @@
+/* setjmp.h -- C11 7.13 -- Nonlocal jumps
+ *
+ * setjmp.h is *not* part of the C11 freestanding subset (C11 4p6); cfree
+ * provides it as an extension for code that wants nonlocal control flow
+ * without a hosted libc. The setjmp/longjmp pair is target-specific
+ * assembly and lives in libcfree_rt.a -- see doc/builtins.md.
+ *
+ * jmp_buf is an array type (C11 7.13p2). Its layout is internal to the
+ * runtime; the size below is conservative -- large enough to hold every
+ * cfree target's callee-saved GPRs + callee-saved FPRs + sp + return
+ * address. C11 7.13 explicitly excludes the floating-point status flags,
+ * the state of open files, and any other component of the abstract
+ * machine, so no signal-mask slot is reserved.
+ */
+#ifndef CFREE_SETJMP_H
+#define CFREE_SETJMP_H
+
+typedef long jmp_buf[32];
+
+int setjmp(jmp_buf env);
+_Noreturn void longjmp(jmp_buf env, int val);
+
+#endif
diff --git a/test/smoke.c b/test/smoke.c
@@ -29,6 +29,7 @@
#include <float.h>
#include <iso646.h>
#include <limits.h>
+#include <setjmp.h>
#include <stdalign.h>
#include <stdarg.h>
#include <stdatomic.h>
@@ -131,6 +132,17 @@ static int sum_n(int n, ...) {
/* stdnoreturn: macro must expand to a usable function specifier. */
static noreturn void cfree_trap(void) { for (;;) {} }
+/* setjmp: jmp_buf is an array type, setjmp is callable in the contexts
+ permitted by C11 7.13.1.1p4, longjmp is _Noreturn. Compile-only --
+ smoke.c never links against a setjmp implementation. */
+_Static_assert(sizeof(jmp_buf) >= sizeof(void *) * 8, "jmp_buf room for regs");
+static jmp_buf cfree_jb;
+static int cfree_setjmp_compiles(int x) {
+ if (setjmp(cfree_jb) != 0) return 1; /* allowed context */
+ if (x) longjmp(cfree_jb, 42);
+ return 0;
+}
+
/* stdatomic: types, memory_order, lock-free macros, plus a runtime
exercise of load, store, exchange, CAS, fetch ops, and atomic_flag. */
_Static_assert(sizeof(atomic_int) == sizeof(int), "atomic_int matches int");
@@ -172,5 +184,6 @@ static int cfree_atomic_ok(void) {
int cfree_smoke_ok(void) {
(void)aligned_buf;
if (0) cfree_trap();
+ if (0) (void)cfree_setjmp_compiles(0);
return sum_n(3, 1, 2, 3) == 6 && cfree_atomic_ok();
}