The report is narrow and serious.
Rust issue 164250 reports that a generic struct declared with a 'static bound can accept a reference to a local value through field assignment. The attached program compiles, then keeps that reference during Drop. Its ordinary run prints data from reused stack storage. The AddressSanitizer run reports a stack use after scope.[1]
The issue was open when this dispatch was written. The Rust project labels it as a soundness bug in the borrow checker, lifetime, variance, destructor, and types areas. Its current priority label is high. Comments trace variants back to old compiler releases, but the issue does not yet provide a released fix or a complete impact census.[1]
The compiler accepted the program. The runtime witness showed why acceptance was wrong.
Variance is the lane change.
The Rust Reference says lifetime subtyping can occur during type checking. A reference with a longer lifetime can be used where a shorter lifetime is expected. Variance controls whether that relation passes through a generic type.[2]
That machinery is useful. It lets references fit the lifetime a caller needs. It also means a field update cannot be checked as a local syntax event. The compiler must preserve every bound that the enclosing type and its destructor will rely on later.
struct Q<T: 'static>(Option<T>);
let local = String::from("short life");
let mut q = Q(None);
q.0 = Some(&local); // reported as accepted
// q is dropped after local leaves its valid scope
Drop turns the bound into behavior.
The Rustonomicon explains why generic destructors receive stricter lifetime checks. A Drop implementation can read borrowed data during destruction. Its generic arguments must outlive the value when the destructor can observe them.[3]
The reported example makes that ability concrete. The type declaration says T: 'static. The field assignment installs a shorter reference. The destructor moves the value into longer-lived storage. The stale reference is then read after its source scope ended.[1]
Do not reduce this to "Rust is unsafe" or "the borrow checker is broken." The useful engineering question is whether your compiler accepted this shape, which versions did so, and what changed after a fix lands.
Build the regression record before the fix arrives.
Save the exact source, compiler identity, command, acceptance result, and runtime witness. Run the same fixture against the version you ship and the candidate fixed version. Keep the compile result separate from the sanitizer result. A new rejection proves the compiler closed this reproducer. It does not prove that every related path is closed.
The Rust compiler guide describes variance as a query that computes how generic parameters may vary. That is the implementation layer maintainers will inspect. Application teams do not need to guess the patch. They need a small fixture and a versioned before-and-after record.[4]
If you maintain generic types with custom destructors, add nearby tests for constructor use, field assignment, mutation through references, and drop order. Keep each test small enough that a changed compiler verdict has one readable cause.