Even after the fix for PR96630, GCC still accepts this invalid code that accesses a variable outside its lifetime: constexpr int f() { const int *p = 0; for (int i = 0; i != 2; ++i) { if (i == 1) { return *p; } const int n = 0; p = &n; } } static_assert(f() == 0); (Live: https://godbolt.org/z/3fEEoq3T6) Even though `*p` denotes `n`, which is usable in constant expressions, the evaluation of `*p` still has undefined behavior because `n` is not within its lifetime, so this is non-constant by [expr.const]/10.8. Note in particular that the special provision in [expr.const]/17 that effectively says we get to ignore the lifetime rules in some cases does not apply to variables whose lifetime started within the evaluation. So this is valid: void g() { const int n = 0; static_assert([] { return n; }() == 0); } ... because we get to assume that n is alive throughout the evaluation, but the same doesn't apply in the testcase above, because the lifetime of the variable started within the evaluation of `f() == 0`.
See also PR118462 -- I'm not sure if these are duplicates or not; this one requires the variable to be declared `const`. However, GCC does reject this simplified testcase with a lifetime error: constexpr int f() { const int *p = 0; { const int n = 0; p = &n; } return *p; } static_assert(f() == 0); ... suggesting that reentering the scope where `n` was declared is relevant.
We don't yet handle other ways of accessing values outside their lifetime (e.g. following explicit destructor calls).
*** Bug 118462 has been marked as a duplicate of this bug. ***
.