Are D's nested functions truly functions - for example are they ABI-compatible with a top-level function? If so, how do they get access to the stack frame?
gcc has this feature, it is implemented by constructing a trampoline-style function on the stack. This requires an executable stack, so isn't really a thing any more.
> for example are they ABI-compatible with a top-level function?
If they are annotated with `static`, yes. If they are not so annotated, they are ABI-compatible with non-static member functions. In fact, in D, a pointer to a non-static member is interchangeable with a pointer to a non-static nested function. This makes for much convenience when dealing with algorithms that accept such pointers (called "delegates" in D):
> how do they get access to the stack frame?
And extra argument is passed to the function which is the frame pointer to the calling function. (This is called a "static link". The "dynamic link" is the return address.) This can be thought of as the "this" pointer to the "struct" that represents the caller's stack frame, hence the binary compatibility with member functions.
To go back to the enclosing enclosing enclosing function's stack frame, you dereference the static link 3 times.
The tricky part is optimizing these dereferences away when there are no captured variables in a stack frame.
D has native support for 'delegates'; closures, essentially. Function literals that reference objects from an outer scope are delegates, and ABI-compatible with other delegates. Regular function pointers can trivially be converted to delegates, so if you want to store function pointers, you should store delegates instead and convert transparently as needed. You can't pass delegates into C functions (because they're only in the D abi, not the C abi), though most C libraries that take a callback also take a 'state' pointer that you can use instead.
Tl;dr: it's a bit complicated, especially wrt communication with c libraries, but in general they're interchangeable with other functions.
gcc has this feature, it is implemented by constructing a trampoline-style function on the stack. This requires an executable stack, so isn't really a thing any more.