Well I'm not sure about forbidding heap allocations, that would severely limit what you can do with a function. In low level languages like Rust or C it would be difficult to keep track of the total size of heap allocations in a performant way, but in e.g. Python it should be possible to add some tracing so that a function can only allocate X bytes, and beyond that throw an error or log a warning.
It would be great if we can mark some functions as non-Turing-complete, and avoid recursion. Would make it easier to reason about them.