miri: make vtable addresses not globally unique
Miri currently gives vtables a unique global address. That's not actually matching reality though. So this PR enables Miri to generate different addresses for the same type-trait pair.
To avoid generating an unbounded number of `AllocId` (and consuming unbounded amounts of memory), we use the "salt" technique that we also already use for giving constants non-unique addresses: the cache is keyed on a "salt" value n top of the actually relevant key, and Miri picks a random salt (currently in the range `0..16`) each time it needs to choose an `AllocId` for one of these globals -- that means we'll get up to 16 different addresses for each vtable. The salt scheme is integrated into the global allocation deduplication logic in `tcx`, and also used for functions and string literals. (So this also fixes the problem that casting the same function to a fn ptr over and over will consume unbounded memory.)
r? `@saethlin`
Fixes https://github.com/rust-lang/miri/issues/3737
Use more slice patterns inside the compiler
Nothing super noteworthy. Just replacing the common 'fragile' pattern of "length check followed by indexing or unwrap" with slice patterns for legibility and 'robustness'.
r? ghost
match lowering: Hide `Candidate` from outside the lowering algorithm
The internals of `Candidate` are tricky and a source of confusion. This PR makes it so we don't expose `Candidate`s outside the lowering algorithm. Now:
- false edges are handled in `lower_match_tree`;
- `lower_match_tree` takes a list of patterns as input;
- `lower_match_tree` returns a flat datastructure that contains only the necessary information.
r? ```@matthewjasper```
Isolate the diagnostic code that expects `thir::Pat` to be printable
Currently, `thir::Pat` implements `fmt::Display` (and `IntoDiagArg`) directly, for use by a few diagnostics.
That makes it tricky to experiment with alternate representations for THIR patterns, because the patterns currently need to be printable on their own. That immediately rules out possibilities like storing subpatterns as a `PatId` index into a central list (instead of the current directly-owned `Box<Pat>`).
This PR therefore takes an incremental step away from that obstacle, by removing `thir::Pat` from diagnostic structs in `rustc_pattern_analysis`, and hiding the pattern-printing process behind a single public `Pat::to_string` method. Doing so makes it easier to identify and update the code that wants to print patterns, and gives a place to pass in additional context in the future if necessary.
---
I'm currently not sure whether switching over to `PatId` is actually desirable or not, but I think this change makes sense on its own merits, by reducing the coupling between `thir::Pat` and the pattern-analysis error types.
exhaustiveness: Explain why a given pattern is considered unreachable
This PR tells the user why a given pattern is considered unreachable. I reused the intersection information we were already computing; even though it's incomplete I convinced myself that it is sufficient to always get a set of patterns that cover the unreachable one.
I'm not a fan of the diagnostic messages I came up with, I'm open to suggestions.
Fixes https://github.com/rust-lang/rust/issues/127870. This is also the other one of the two diagnostic improvements I wanted to do before https://github.com/rust-lang/rust/pull/122792.
Note: the first commit is an unrelated drive-by tweak.
r? `@compiler-errors`
Various notes on match lowering
This is an assortment of comments for things that I found unclear or confusing when I was learning how match lowering works.
This PR only adds/modifies comments, so there are no functional changes.
I have tried to avoid touching code that would conflict with #127159.
r? `@Nadrieril`
treat `&raw (const|mut) UNSAFE_STATIC` implied deref as safe
Fixesrust-lang/rust#125833
As reported in that and related issues, `static mut STATIC_MUT: T` is very often used in embedded code, and is in many ways equivalent to `static STATIC_CELL: SyncUnsafeCell<T>`. The Rust expression of `&raw mut STATIC_MUT` and `SyncUnsafeCell::get(&STATIC_CELL)` are approximately equal, and both evaluate to `*mut T`. The library function is safe because it has *declared itself* to be safe. However, the raw ref operator is unsafe because all uses of `static mut` are considered unsafe, even though the static's value is not used by this expression (unlike, for example, `&STATIC_MUT`).
We can fix this unnatural difference by simply adding the proper exclusion for the safety check inside the THIR unsafeck, so that we do not declare it unsafe if it is not.
While the primary concern here is `static mut`, this change is made for all instances of an "unsafe static", which includes a static declared inside `extern "abi" {}`. Hypothetically, we could go as far as generalizing this to all instances of `&raw (const|mut) *ptr`, but today we do not, as we have not actually considered the range of possible expressions that use a similar encoding. We do not even extend this to thread-local equivalents, because they have less clear semantics.
The implied deref to statics introduced by HIR->THIR lowering is only
used to create place expressions, it lacks unsafe semantics.
It is also confusing, as there is no visible `*ident` in the source.
For both classes of "unsafe static" (extern static and static mut)
allow this operation.
We lack a clear story around `thread_local! { static mut }`, which
is actually its own category of item that reuses the static syntax but
has its own rules. It's possible they should be similarly included, but
in the absence of a good reason one way or another, we do not bless it.
Explain why we require `_` for empty patterns
This adds a note to the "non-exhaustive patterns" diagnostic to explain why we sometimes require extra `_` patterns on empty types. This is one of the two diagnostic improvements I wanted to do before [stabilizing `min_exhaustive_patterns`](https://github.com/rust-lang/rust/pull/122792).
r? ``@compiler-errors``
match lowering: Split `finalize_or_candidate` into more coherent methods
I noticed that `finalize_or_candidate` was responsible for several different postprocessing tasks, making it difficult to understand.
This PR aims to clean up some of the confusion by:
- Extracting `remove_never_subcandidates` from `merge_trivial_subcandidates`
- Extracting `test_remaining_match_pairs_after_or` from `finalize_or_candidate`
- Taking what remains of `finalize_or_candidate`, and inlining it into its caller
---
Reviewing individual commits and ignoring whitespace is recommended.
Most of the large-looking changes are just moving existing code around, mostly unaltered.
r? ``@Nadrieril``
Replace a long inline "autoref" comment with method docs
This comment has two problems:
- It is very long, making the flow of the enclosing method hard to follow.
- It starts by talking about an `autoref` flag that hasn't existed since #59114.
- This makes it hard to trust that the information in the comment is accurate or relevant, even though much of it still seems to be true.
This PR therefore replaces the long inline comment with a revised doc comment on `bind_matched_candidate_for_guard`, and some shorter inline comments.
For readers who want more historical context, we also link to the PR that added the old comment, and the PR that removed the `autoref` flag.
match lowering: Rename `MatchPair` to `MatchPairTree`
In #120904, `MatchPair` became able to store other match pairs as children, forming a tree. That has made the old name confusing, so this patch renames the type to `MatchPairTree`.
This PR also includes a patch renaming the `test` method to `pick_test_for_match_pair`, since it would conflict with the main change.
r? `@Nadrieril`
MIR building: Stop using `unpack!` for `BlockAnd<()>`
This is a subset of #127416, containing only the parts related to `BlockAnd<()>`.
The first patch removes the non-assigning form of the `unpack!` macro, because it is frustratingly inconsistent with the main form. We can replace it with an ordinary method that discards the `()` and returns the block.
The second patch then finds all of the remaining code that was using `unpack!` with `BlockAnd<()>`, and updates it to use that new method instead.
---
Changes since original review of #127416:
- Renamed `fn unpack_block` → `fn into_block`
- Removed `fn unpack_discard`, replacing it with `let _: BlockAnd<()> = ...` (2 occurrences)
- Tweaked `arm_end_blocks` to unpack earlier and build `Vec<BasicBlock>` instead of `Vec<BlockAnd<()>>`