Nested Functions with GCC and Clang

matt_d1 pts0 comments

Martin Uecker

Blog

Contact/Impressum

Nested Functions with GCC and Clang

Martin Uecker, 2026-08-06

Introduction

Last time I discussed how one can use GCC's<br>nested functions for callbacks with requiring an executable stack. This will<br>be possible in GCC 17 with the help of two new built-in functions that provide<br>explicit access to the static chain and code pointer.

Today, I want to show two macros that I already use to implement nested functions<br>in a way that is portable across both GCC and Clang.

GCC 17: Nested Functions

To be able to use nested functions as callbacks without the need for trampolines or<br>executable stack, we used three macros to define a wide pointer<br>type and to wrap the new built-in functions.

#define wide(T) struct wide_##T { typeof(T) *code; void *chain; }<br>#define CALL(ptr, args) __builtin_call_with_static_chain(ptr.code(args), ptr.chain)<br>#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)<br>return CALL(p, (x));

int foo(int k)<br>int bar(int x) { return k + x; }<br>return baz(CLOSURE(cb_f, bar), 2 * k);

Somewhat Portable Nested Functions

We now add versions of the macros that allow us to compile the code using Clang's<br>Blocks extension and on older versions of GCC using trampolines (next time I will<br>explain a hack how trampolines can be avoided even on old versions of GCC).<br>As Blocks comes with a built-in wide pointer type with function call<br>semantics, the corresponding macros essentially become no-ops, while<br>a new NESTED macro which is a no-op on GCC defines a named wide pointer variable<br>on Clang using Blocks syntax.

#ifndef __clang__<br>#if __GNUC__<br>The following version compiles on both GCC and Clang<br>(Godbolt Example).<br>Note that an additional semicolon is required after the definition<br>of the nested function which luckily is ignored by GCC.

typedef int cb_f(int y);

int baz(wide(cb_f) p, int x)<br>return CALL(p, (x));

int foo(int k)<br>NESTED(int, bar, (int x))<br>return k + x;<br>};<br>return baz(CLOSURE(cb_f, bar), 2 * k);

Caveats for Clang

While this is quite nice, there are still some annoying limitations related<br>to the Blocks extension.

The most annoying limitation is that arrays in the parent function can not be<br>accessed when using Blocks (Godbolt Example).

Another limitation is that variables automatically become read-only if not<br>marked with the __block keyword (Godbolt Example).<br>This keyword then has to be hidden in a macro which expands to nothing on GCC.<br>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<br>defined for the function itself needs to be marked with __block<br>iself, otherwise the program will be silently miscompiled<br>(Godbolt Example).

Literature

GCC, Nested Functions

GCC, Constructing Function Calls

nested functions clang wide cb_f return

Related Articles