AFAIK it's fine to use the value of private_constant even outside its lifetime (or at least that's the intent). See [conv.lval]/2.
Though if private_constant is passed by reference (and accessed through the reference), then [conv.lval]/2 is no help.
Ah, thanks for the correction! That significantly reduces the scope of the problem. But how can a function like the following be fixed?
// Contract:
// - returns ref to a single POD object (address-stable)
// - can be called during std::exit() without UB
// - the object can be read during std::exit() without UB
// - thread-safety is a bonus but not required
const info& get_info()
{
static const info i = /*...*/; // oops!
return i;
}
Depending on destruction order, the static local i can be destroyed before the last time it is read and/or before the last time get_info() is called. Either case triggers UB. I literally do not know how to fix this function's implementation without also changing its contract and without resorting to non-portable techniques! ("Construct with new" you might say, but then where are you going to stash the pointer? "Easy, a static local... oh")
The issue resolution appears to take away a tool in our toolbox: storage at a statically-known location that lasts until termination.