[...]
It only need to 'see' inside the std::vector and find the call
to 'new' and the companion call to 'delete'.
And verify, of course, that no other function called modifies
the pointer. Except, of course, that in most uses, the call to
new isn't in the constructor. The real optimization problem
with std::vector is to make a sequence of successive push_back
rapid.
It only need builtin knowledge of memory allocation primitives
(something I'm sure most compilers already have).
It needs to ensure that no other functions modify the pointer.
A lot do, and there are generally a lot of indirections involved
in calling them.
If by static analysis it can prove that a memory allocation is
always freed at the end of scope and it can prove that the
allocation size cannot exceed a certain value (or has a
fallback mechanism for that), then it can convert a call to
new in the equivalent of alloca+placement new.
The key here (and with std::vector) is, first, proving that
allocation size cannot exceed a certain value, and second, that
doing just one allocation with this value, rather than the
allocation/copy/free which occurs when the capacity is increased
doesn't change the guaranteed semantics, is what requires
internal knowledge: the user may have replaced to global
operator new (making calls to the function "observable
behavior"), and in the case of std::vector, the copy
constructors may have side effects. The transformation is never
the less legal, because the standard explicitly allows
std::string and std::vector to have any capacity they want after
construction, but there's nothing in the code that indicates
this.
The problem with std::string is simpler, because the compiler
knows that copying char or wchar_t has no observable side
effects, so one part of the problem is solved. And I'm sure
that an optimization which ignored possible "observable
behavior" in operator new would be acceptable (although it
should be documented as "not strictly conforming").
Of course, this is why you need escape analysis.
Which generally means intermodule analysis; most people pass
strings and vectors by reference, and not by value. (And even
if the reference is const, if the original object is non-const,
the called function may legally cast away const and modify the
object anyway.)