`check_scope_decls` iterates a scope's entity map while
`check_entity_decl` can insert into that same scope: a procedure alias
(`f :: e`) goes through `override_entity_in_scope`, which calls
`scope_map_insert`. The map grows at 75% load (12 of 16 slots, then 24
of 32), and `scope_map_insert` grows before it probes for the key, so
even an alias that only replaces an existing value rehashes and
reallocates the table in the middle of the iteration.
`ScopeMapIterator` re-read its map on every step while `end` had
captured the capacity at loop start, so the walk continued over the new
table under the old sentinel: it ran past the end of the reallocated
table and dereferenced whatever followed it as an `Entity *` - a nullptr
dereference for a procedure scope holding exactly 12 or 24 entities - or
it stopped at the stale end index and silently skipped every declaration
that the rehash had moved behind it, which left unused declarations
without any diagnostic at all.
The iterator now snapshots the table pointer and capacity when it is
constructed, so iteration is invariant under any insert or grow and
cannot leave the table it began on. A scope that does not grow behaves
exactly as before: the snapshot points at the same table.
Refs #7598
PR #6476 "fixed" an issue that didn't exist because it misunderstood this allocator's semantics. What it conluded was an edge case was in fact entirely predictable and desireable behavior for this allocator.
In "fixing" this edge case, it prevented the exact scratch mechanics that sets this allocator apart for its use case.
Reverted.
Tagless switch cases are ordered predicates, so distinct constant conditions may fold to the same Boolean value. Restrict duplicate-case tracking to explicitly tagged switches and add positive and negative regression coverage for issue #7421.