In lower level languages there are also a bunch of other issues:
- RAII can easily make functions that appear in a tail position not actually tail calls, due to destructors implicitly running after the call;
- there can be issues when reusing the stack frame of the caller, especially with caller-cleanup calling conventions;
- the compiler needs to prove that no pointers to the stack frame of the function being optimized have escaped, otherwise it would be reusing the memory of live variables which is illegal.