The following code doesn't work with @safe -dip1000: int* p; int i; p = &i;
i has a shorter lifetime than p, the compiler complains. But this code does: int i; int* p; p = &i; In both cases, p can't point to i before i exists, and p ceases to exist when i ceases to exist. I believe this is because the first option would let me write: struct Foo { bool exists = true; ~this() { exists = false; } void doStuff() { assert(exists); } } Foo* p; scope(exit) (*p).doStuff; Foo f; scope(exit) destroy(f); p = &f; And this will run into the assert when -dip1000 should ensure it can't. The compiler does this even in the absence of scope guards and destructors because simple, obvious rules will be easier to understand and implement than nuanced ones, even if it makes you reorder declarations sometimes. Is this right?