Most fundamentally, Vec is and always will be a (pointer, capacity, length) triplet. No more, no less.
and
If a Vec has allocated memory, then the memory it points to is on the heap (as defined by the allocator Rust is configured to use by default), and its pointer points to len() initialized elements in order (what you would see if you coerced it to a slice), followed by capacity() - len() logically uninitialized elements.
I hope this answers the question.
Although you should really read the docs linked above as there is a lot of different behaviour when e.g. using ZSTs.
I hope a future escape analysis pass of Rustc will stack-allocate small Vecs that don't escape. Nailing down a semantics that is sub-optimal is... suboptimal.
In C++, std::vec<int> v { 1, 2, 3 }; still allocates its storage on the heap because the std::vec constructor runs in its own stack frame --- and because of the way stack frames (typically) work, function-call semantics usually deny the possibility of use a helper function for stack allocation.
But if have allocated a struct on the heap (with box or something) smallvec doesn't help you... So, can Clippy perform escape analysis on a whole Crate and warn me where I can avoid a Box/Vec? It's worse than having this pass in Rustc, but better than having nothing.