Interesting options there.
For many projects I have worked on over the years, embedded systems, safety critical systems, etc, the last three cases would have been considered unacceptably bad design or implementation and rejected immediately.
If you don't know the scope, be that actual syntactic scope in the language or where your data is via some smart pointer, and where it is no longer required to exist then you are opening up to memory leaks and or dangling pointers.
If you don't know the size you are opening yourself up to stack overflow or memory exhaustion.
Now, as you correctly imply, many programmers in many situations, "don't know of care to figure out" these things. They assume they have infinite stack and heap. They assume that if there is a problem with either it's not a big deal, the OS will kill it, the OS or user will restart it. It does not happen so often as to have to worry about it, right?
Kind of appalling really.
Last week one of our servers in the cloud when down. Could not even log in. Turned out my colleague, a Python head, had a Python service running there for many weeks just fine. Until one day it decided to eat all memory and fill up temp file space. He is still trying to find out where and why that might happen.
To your question:
Rust works like pretty much every other language in common use.
If data only comes into existence in a function and is only needed in that function then it is local variables or perhaps passed in as a parameter. All happening on the stack.
If data needs to live longer than a function, or function call chain if passing reference down, then it needs to be allocated on the heap. Rust has "smart pointers" like Rc and Arc to take care of that. Or just "move" ownership around.
Except if "local data" is actually going to be huge put it on the heap so as not to blow the stack space.