Compress amount of hashed bytes for `isize` values in StableHasher
This is another attempt to land https://github.com/rust-lang/rust/pull/92103, this time hopefully with a correct implementation w.r.t. stable hashing guarantees. The previous PR was [reverted](https://github.com/rust-lang/rust/pull/93014) because it could produce the [same hash](https://github.com/rust-lang/rust/pull/92103#issuecomment-1014625442) for different values even in quite simple situations. I have since added a basic [test](https://github.com/rust-lang/rust/pull/93193) that should guard against that situation, I also added a new test in this PR, specialised for this optimization.
## Why this optimization helps
Since the original PR, I have tried to analyze why this optimization even helps (and why it especially helps for `clap`). I found that the vast majority of stable-hashing `i64` actually comes from hashing `isize` (which is converted to `i64` in the stable hasher). I only found a single place where is this datatype used directly in the compiler, and this place has also been showing up in traces that I used to find out when is `isize` being hashed. This place is `rustc_span::FileName::DocTest`, however, I suppose that isizes also come from other places, but they might not be so easy to find (there were some other entries in the trace). `clap` hashes about 8.5 million `isize`s, and all of them fit into a single byte, which is why this optimization has helped it [quite a lot](https://github.com/rust-lang/rust/pull/92103#issuecomment-1005711861).
Now, I'm not sure if special casing `isize` is the correct solution here, maybe something could be done with that `isize` inside `DocTest` or in other places, but that's for another discussion I suppose. In this PR, instead of hardcoding a special case inside `SipHasher128`, I instead put it into `StableHasher`, and only used it for `isize` (I tested that for `i64` it doesn't help, or at least not for `clap` and other few benchmarks that I was testing).
## New approach
Since the most common case is a single byte, I added a fast path for hashing `isize` values which positive value fits within a single byte, and a cold path for the rest of the values.
To avoid the previous correctness problem, we need to make sure that each unique `isize` value will produce a unique hash stream to the hasher. By hash stream I mean a sequence of bytes that will be hashed (a different sequence should produce a different hash, but that is of course not guaranteed).
We have to distinguish different values that produce the same bit pattern when we combine them. For example, if we just simply skipped the leading zero bytes for values that fit within a single byte, `(0xFF, 0xFFFFFFFFFFFFFFFF)` and `(0xFFFFFFFFFFFFFFFF, 0xFF)` would send the same hash stream to the hasher, which must not happen.
To avoid this situation, values `[0, 0xFE]` are hashed as a single byte. When we hash a larger (treating `isize` as `u64`) value, we first hash an additional byte `0xFF`. Since `0xFF` cannot occur when we apply the single byte optimization, we guarantee that the hash streams will be unique when hashing two values `(a, b)` and `(b, a)` if `a != b`:
1) When both `a` and `b` are within `[0, 0xFE]`, their hash streams will be different.
2) When neither `a` and `b` are within `[0, 0xFE]`, their hash streams will be different.
3) When `a` is within `[0, 0xFE]` and `b` isn't, when we hash `(a, b)`, the hash stream will definitely not begin with `0xFF`. When we hash `(b, a)`, the hash stream will definitely begin with `0xFF`. Therefore the hash streams will be different.
r? `@the8472`
Rollup of 8 pull requests
Successful merges:
- #92528 (Make `Fingerprint::combine_commutative` associative)
- #93221 ([borrowck] Fix help on mutating &self in async fns)
- #93542 (Prevent lifetime elision in type alias)
- #93546 (Validate that values in switch int terminator are unique)
- #93571 (better suggestion for duplicated `where` clause)
- #93574 (don't suggest adding `let` due to bad assignment expressions inside of `while` loop)
- #93590 (More let_else adoptions)
- #93592 (Remove unused dep from rustc_arena)
Failed merges:
r? `@ghost`
`@rustbot` modify labels: rollup
don't suggest adding `let` due to bad assignment expressions inside of `while` loop
adds a check that our `lhs` expression is actually within the conditional part of the `while` loop, instead of anywhere in the `while` body.
fixes#93486
[borrowck] Fix help on mutating &self in async fns
Previously, when rustc was provided an async function that tried to
mutate through a shared reference to an implicit self (as shown in the
ui test), rustc would suggest modifying the parameter signature
to `&mut` + the fully qualified name of the ty (in the case of the repro
`S`). If a user modified their code to match the suggestion, the
compiler would not accept it.
This commit modifies the suggestion so that when rustc is provided the
ui test that is also attached in this commit, it suggests (correctly)
`&mut self`. We try to be careful about distinguishing between implicit
and explicit self annotations, since the latter seem to be handled
correctly already.
This is my first PR here so I'm pretty sure I probably missed something/could use better terminology. I also didn't try to make the match exhaustive since implicit self is the only real special case that I need to handle (that I'm aware of), and I'm pretty sure there's a cleaner way to do this so any advice would be greatly appreciated! (I'm also not terribly confident about how I wrote the ui tests)
here is your cc as requested `@compiler-errors`
This is an attempt to fix#93093
Make `Fingerprint::combine_commutative` associative
The previous implementation swapped lower and upper 64-bits of a result
of modular addition, so the function was non-associative.
r? `@Aaron1011`
Return an indexmap in `all_local_trait_impls` query
The data structure previously used here required that `DefId` be `Ord`. As part of #90317, we do not want `DefId` to implement `Ord`.
debuginfo: Make sure that type names for closure and generator environments are unique in debuginfo.
Before this change, closure/generator environments coming from different instantiations of the same generic function were all assigned the same name even though they were distinct types with potentially different data layout. Now we append the generic arguments of the originating function to the type name.
This commit also emits `{closure_env#0}` as the name of these types in order to disambiguate them from the accompanying closure function (which keeps being called `{closure#0}`). Previously both were assigned the same name.
NOTE: Changing debuginfo names like this can break pretty printers and other debugger plugins. I think it's OK in this particular case because the names we are changing were ambiguous anyway. In general though it would be great to have a process for doing changes like these.
Fix two incorrect "it's" (typos in comments)
Found one of these while reading the documentation online. The other came up because it's in the same file.
Add missing | between print options
The help text for the newly stabilized print option is missing a | between stack-protector-strategies and link-args.
Make dead code check a query.
Dead code check is run for each invocation of the compiler, even if no modifications were involved.
This PR makes dead code check a query keyed on the module. This allows to skip the check when a module has not changed.
To perform this, a query `live_symbols_and_ignored_derived_traits` is introduced to encapsulate the global analysis of finding live symbols. The second query `check_mod_deathness` outputs diagnostics for each module based on this first query's results.
Continue work on associated const equality
This actually implements some more complex logic for assigning associated consts to values.
Inside of projection candidates, it now defers to a separate function for either consts or
types. To reduce amount of code, projections are now generic over T, where T is either a Type or
a Const. I can add some comments back later, but this was the fastest way to implement it.
It also now finds the correct type of consts in type_of.
---
The current main TODO is finding the const of the def id for the LeafDef.
Right now it works if the function isn't called, but once you use the trait impl with the bound it fails inside projection.
I was hoping to get some help in getting the `&'tcx ty::Const<'tcx>`, in addition to a bunch of other `todo!()`s which I think may not be hit.
r? `@oli-obk`
Updates #92827
Enable combining `+crt-static` and `relocation-model=pic` on `x86_64-unknown-linux-gnu`
Modern `gcc` versions support `-static-pie`, and `rustc` will already fall-back to `-static` if the local `gcc` is too old (and hence this change is optimistic rather than absolute). This brings the `-musl` and `-gnu` targets to feature compatibility (albeit with different default settings).
Of note a `-static` or `-static-pie` binary based on glibc that uses NSS-backed functions (`gethostbyname` or `getpwuid` etc.) need to have access to the `libnss_X.so.2` libraries and any of their dynamic dependencies.
I wasn't sure about the `# only`/`# ignore` changes (I've not got a `gnux32` toolchain to test with hence not also enabling `-static-pie` there).
Disable drop range analysis
The previous PR, #93165, still performed the drop range analysis despite ignoring the results. Unfortunately, there were ICEs in the analysis as well, so some packages failed to build (see the issue #93197 for an example). This change further disables the analysis and just provides dummy results in that case.
Before this change, closure/generator environments coming from different
instantiations of the same generic function were all assigned the same
name even though they were distinct types with potentially different data
layout. Now we append the generic arguments of the originating function
to the type name.
This commit also emits '{closure_env#0}' as the name of these types in
order to disambiguate them from the accompanying closure function
'{closure#0}'. Previously both were assigned the same name.
Rollup of 9 pull requests
Successful merges:
- #91343 (Fix suggestion to slice if scrutinee is a `Result` or `Option`)
- #93019 (If an integer is entered with an upper-case base prefix (0Xbeef, 0O755, 0B1010), suggest to make it lowercase)
- #93090 (`impl Display for io::ErrorKind`)
- #93456 (Remove an unnecessary transmute from opaque::Encoder)
- #93492 (Hide failed command unless in verbose mode)
- #93504 (kmc-solid: Increase the default stack size)
- #93513 (Allow any pretty printed line to have at least 60 chars)
- #93532 (Update books)
- #93533 (Update cargo)
Failed merges:
r? `@ghost`
`@rustbot` modify labels: rollup
Allow any pretty printed line to have at least 60 chars
Follow-up to #93155. The rustc AST pretty printer has a tendency to get stuck in "vertical smear mode" when formatting highly nested code, where it puts a linebreak at *every possible* linebreak opportunity once the indentation goes beyond the pretty printer's target line width:
```rust
...
((&([("test"
as
&str)]
as
[&str; 1])
as
&[&str; 1]),
(&([]
as
[ArgumentV1; 0])
as
&[ArgumentV1; 0]))
...
```
```rust
...
[(1
as
i32),
(2
as
i32),
(3
as
i32)]
as
[i32; 3]
...
```
This is less common after #93155 because that PR greatly reduced the total amount of indentation, but the "vertical smear mode" failure mode is still just as present when you have deeply nested modules, functions, or trait impls, such as in the case of macro-expanded code from `-Zunpretty=expanded`.
Vertical smear mode is never the best way to format highly indented code though. It does not prevent the target line width from being exceeded, and it produces output that is less readable than just a longer line.
This PR makes the pretty printing algorithm allow a minimum of 60 chars on every line independent of indentation. So as code gets more indented, the right margin eventually recedes to make room for formatting without vertical smear.
```console
├─────────────────────────────────────┤
├─────────────────────────────────────┤
├─────────────────────────────────────┤
├───────────────────────────────────┤
├─────────────────────────────────┤
├───────────────────────────────┤
├─────────────────────────────┤
├───────────────────────────┤
├───────────────────────────┤
├───────────────────────────┤
├───────────────────────────┤
├───────────────────────────┤
├─────────────────────────────┤
├───────────────────────────────┤
├─────────────────────────────────┤
├───────────────────────────────────┤
├─────────────────────────────────────┤
```
If an integer is entered with an upper-case base prefix (0Xbeef, 0O755, 0B1010), suggest to make it lowercase
The current error for this case isn't really great, it just complains about the whole thing past the `0` being an invalid suffix.
rustc_errors: only box the `diagnostic` field in `DiagnosticBuilder`.
I happened to need to do the first change (replacing `allow_suggestions` with equivalent functionality on `Diagnostic` itself) as part of a larger change, and noticed that there's only two fields left in `DiagnosticBuilderInner`.
So with this PR, instead of a single pointer, `DiagnosticBuilder` is two pointers, which should work just as well for passing *it* by value (and may even work better wrt some operations, though probably not by much).
But anything that was already taking advantage of `DiagnosticBuilder` being a single pointer, and wrapping it further (e.g. `Result<T, DiagnosticBuilder>` w/ non-ZST `T`), ~~will probably see a slowdown~~, so I want to do a perf run before even trying to propose this.
Check that `#[rustc_must_implement_one_of]` is applied to a trait
`#[rustc_must_implement_one_of]` only makes sense when applied to a trait, so it's sensible to emit an error otherwise.