Martin Uecker, 2026-08-06
Last time I discussed how one can use GCC's nested functions for callbacks with requiring an executable stack. This will be possible in GCC 17 with the help of two new built-in functions that provide explicit access to the static chain and code pointer.
Today, I want to show two macros that I already use to implement nested functions in a way that is portable across both GCC and Clang.
To be able to use nested functions as callbacks without the need for trampolines or executable stack, we used three macros to define a wide pointer type and to wrap the new built-in functions.
#define wide(T) struct wide_##T { typeof(T) *code; void *chain; }
#define CALL(ptr, args) __builtin_call_with_static_chain(ptr.code(args), ptr.chain)
#define CLOSURE(T, x) (wide(T)){ __builtin_call_code_address(x), __builtin_call_static_chain(x) }
Our toy example then looks quite nice.
typedef int cb_f(int y);
int baz(wide(cb_f) p, int x)
{
return CALL(p, (x));
}
int foo(int k)
{
int bar(int x) { return k + x; }
return baz(CLOSURE(cb_f, bar), 2 * k);
}
We now add versions of the macros that allow us to compile the code using Clang's Blocks extension and on older versions of GCC using trampolines (next time I will explain a hack how trampolines can be avoided even on old versions of GCC). As Blocks comes with a built-in wide pointer type with function call semantics, the corresponding macros essentially become no-ops, while a new NESTED macro which is a no-op on GCC defines a named wide pointer variable on Clang using Blocks syntax.
#ifndef __clang__
#if __GNUC__ < 17
// GCC using trampolines
#define wide(T) typeof(T*)
#define CALL(ptr, args) (ptr(args))
#define CLOSURE(T, x) (x)
#else
// GCC 17 using wide function pointer
#define wide(T) struct wide_##T { typeof(T) *code; void *chain; }
#define CALL(ptr, args) __builtin_call_with_static_chain(ptr.code(args), ptr.chain)
#define CLOSURE(T, x) (wide(T)){ __builtin_call_code_address(x), __builtin_call_static_chain(x) }
#endif
#define NESTED(ret, name, args) ret name args
#else
// Clang Blocks extension
#define wide(T) typeof(T^)
#define CALL(ptr, args) (ptr(args))
#define CLOSURE(T, x) (x)
#define NESTED(ret, name, args) ret (^name) args = ^ret args
#endif
The following version compiles on both GCC and Clang (Godbolt Example). Note that an additional semicolon is required after the definition of the nested function which luckily is ignored by GCC.
typedef int cb_f(int y);
int baz(wide(cb_f) p, int x)
{
return CALL(p, (x));
}
int foo(int k)
{
NESTED(int, bar, (int x))
{
return k + x;
};
return baz(CLOSURE(cb_f, bar), 2 * k);
}
While this is quite nice, there are still some annoying limitations related to the Blocks extension.
The most annoying limitation is that arrays in the parent function can not be accessed when using Blocks (Godbolt Example).
Another limitation is that variables automatically become read-only if not
marked with the __block keyword (Godbolt Example).
This keyword then has to be hidden in a macro which expands to nothing on GCC.
Also note that despite being read-only the type of the variable does not become const-qualified.
Finally, to be able to invoke a nested function recursively, the variable
defined for the function itself needs to be marked with __block
iself, otherwise the program will be silently miscompiled
(Godbolt Example).