various clippy fixes
We need to keep the order of the given clippy lint rules before passing them.
Since clap doesn't offer any useful interface for this purpose out of the box,
we have to handle it manually.
Additionally, this PR makes `-D` rules work as expected. Previously, lint rules were limited to `-W`. By enabling `-D`, clippy began to complain numerous lines in the tree, all of which have been resolved in this PR as well.
Fixes#121481
cc `@matthiaskrgr`
Stabilize associated type bounds (RFC 2289)
This PR stabilizes associated type bounds, which were laid out in [RFC 2289]. This gives us a shorthand to express nested type bounds that would otherwise need to be expressed with nested `impl Trait` or broken into several `where` clauses.
### What are we stabilizing?
We're stabilizing the associated item bounds syntax, which allows us to put bounds in associated type position within other bounds, i.e. `T: Trait<Assoc: Bounds...>`. See [RFC 2289] for motivation.
In all position, the associated type bound syntax expands into a set of two (or more) bounds, and never anything else (see "How does this differ[...]" section for more info).
Associated type bounds are stabilized in four positions:
* **`where` clauses (and APIT)** - This is equivalent to breaking up the bound into two (or more) `where` clauses. For example, `where T: Trait<Assoc: Bound>` is equivalent to `where T: Trait, <T as Trait>::Assoc: Bound`.
* **Supertraits** - Similar to above, `trait CopyIterator: Iterator<Item: Copy> {}`. This is almost equivalent to breaking up the bound into two (or more) `where` clauses; however, the bound on the associated item is implied whenever the trait is used. See #112573/#112629.
* **Associated type item bounds** - This allows constraining the *nested* rigid projections that are associated with a trait's associated types. e.g. `trait Trait { type Assoc: Trait2<Assoc2: Copy>; }`.
* **opaque item bounds (RPIT, TAIT)** - This allows constraining associated types that are associated with the opaque without having to *name* the opaque. For example, `impl Iterator<Item: Copy>` defines an iterator whose item is `Copy` without having to actually name that item bound.
The latter three are not expressible in surface Rust (though for associated type item bounds, this will change in #120752, which I don't believe should block this PR), so this does represent a slight expansion of what can be expressed in trait bounds.
### How does this differ from the RFC?
Compared to the RFC, the current implementation *always* desugars associated type bounds to sets of `ty::Clause`s internally. Specifically, it does *not* introduce a position-dependent desugaring as laid out in [RFC 2289], and in particular:
* It does *not* desugar to anonymous associated items in associated type item bounds.
* It does *not* desugar to nested RPITs in RPIT bounds, nor nested TAITs in TAIT bounds.
This position-dependent desugaring laid out in the RFC existed simply to side-step limitations of the trait solver, which have mostly been fixed in #120584. The desugaring laid out in the RFC also added unnecessary complication to the design of the feature, and introduces its own limitations to, for example:
* Conditionally lowering to nested `impl Trait` in certain positions such as RPIT and TAIT means that we inherit the limitations of RPIT/TAIT, namely lack of support for higher-ranked opaque inference. See this code example: https://github.com/rust-lang/rust/pull/120752#issuecomment-1979412531.
* Introducing anonymous associated types makes traits no longer object safe, since anonymous associated types are not nameable, and all associated types must be named in `dyn` types.
This last point motivates why this PR is *not* stabilizing support for associated type bounds in `dyn` types, e.g, `dyn Assoc<Item: Bound>`. Why? Because `dyn` types need to have *concrete* types for all associated items, this would necessitate a distinct lowering for associated type bounds, which seems both complicated and unnecessary compared to just requiring the user to write `impl Trait` themselves. See #120719.
### Implementation history:
Limited to the significant behavioral changes and fixes and relevant PRs, ping me if I left something out--
* #57428
* #108063
* #110512
* #112629
* #120719
* #120584Closes#52662
[RFC 2289]: https://rust-lang.github.io/rfcs/2289-associated-type-bounds.html
never patterns: suggest `!` patterns on non-exhaustive matches
When a match is non-exhaustive we now suggest never patterns whenever it makes sense.
r? ``@compiler-errors``
`f16` and `f128` step 3: compiler support & feature gate
Continuation of https://github.com/rust-lang/rust/pull/121841, another portion of https://github.com/rust-lang/rust/pull/114607
This PR exposes the new types to the world and adds a feature gate. Marking this as a draft because I need some feedback on where I did the feature gate check. It also does not yet catch type via suffixed literals (so the feature gate test will fail, probably some others too because I haven't belssed).
If there is a better place to check all types after resolution, I can do that. If not, I figure maybe I can add a second gate location in AST when it checks numeric suffixes.
Unfortunately I still don't think there is much testing to be done for correctness (codegen tests or parsed value checks) until we have basic library support. I think that will be the next step.
Tracking issue: https://github.com/rust-lang/rust/issues/116909
r? `@compiler-errors`
cc `@Nilstrieb`
`@rustbot` label +F-f16_and_f128
Detect calls to .clone() on T: !Clone types on borrowck errors
When encountering a lifetime error on a type that *holds* a type that doesn't implement `Clone`, explore the item's body for potential calls to `.clone()` that are only cloning the reference `&T` instead of `T` because `T: !Clone`. If we find this, suggest `T: Clone`.
```
error[E0502]: cannot borrow `*list` as mutable because it is also borrowed as immutable
--> $DIR/clone-on-ref.rs:7:5
|
LL | for v in list.iter() {
| ---- immutable borrow occurs here
LL | cloned_items.push(v.clone())
| ------- this call doesn't do anything, the result is still `&T` because `T` doesn't implement `Clone`
LL | }
LL | list.push(T::default());
| ^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
LL |
LL | drop(cloned_items);
| ------------ immutable borrow later used here
|
help: consider further restricting this bound
|
LL | fn foo<T: Default + Clone>(list: &mut Vec<T>) {
| +++++++
```
```
error[E0505]: cannot move out of `x` because it is borrowed
--> $DIR/clone-on-ref.rs:23:10
|
LL | fn qux(x: A) {
| - binding `x` declared here
LL | let a = &x;
| -- borrow of `x` occurs here
LL | let b = a.clone();
| ------- this call doesn't do anything, the result is still `&A` because `A` doesn't implement `Clone`
LL | drop(x);
| ^ move out of `x` occurs here
LL |
LL | println!("{b:?}");
| ----- borrow later used here
|
help: consider annotating `A` with `#[derive(Clone)]`
|
LL + #[derive(Clone)]
LL | struct A;
|
```
Fix#48677.
coverage: Initial support for branch coverage instrumentation
(This is a review-ready version of the changes that were drafted in #118305.)
This PR adds support for branch coverage instrumentation, gated behind the unstable flag value `-Zcoverage-options=branch`. (Coverage instrumentation must also be enabled with `-Cinstrument-coverage`.)
During THIR-to-MIR lowering (MIR building), if branch coverage is enabled, we collect additional information about branch conditions and their corresponding then/else blocks. We inject special marker statements into those blocks, so that the `InstrumentCoverage` MIR pass can reliably identify them even after the initially-built MIR has been simplified and renumbered.
The rest of the changes are mostly just plumbing needed to gather up the information that was collected during MIR building, and include it in the coverage metadata that we embed in the final binary.
Note that `llvm-cov show` doesn't print branch coverage information in its source views by default; that needs to be explicitly enabled with `--show-branches=count` or similar.
---
The current implementation doesn't have any support for instrumenting `if let` or let-chains. I think it's still useful without that, and adding it would be non-trivial, so I'm happy to leave that for future work.
match lowering: don't collect test alternatives ahead of time
I'm very happy with this one. Before this, when sorting candidates into the possible test branches, we manually computed `usize` indices to determine in which branch each candidate goes. To make this work we had a first pass that collected the possible alternatives we'd have to deal with, and a second pass that actually sorts the candidates.
In this PR, I replace `usize` indices with a dedicated enum. This makes `sort_candidates` easier to follow, and we don't need the first pass anymore.
r? ``@matthewjasper``
pattern analysis: Store field indices in `DeconstructedPat` to avoid virtual wildcards
For a pattern like `Struct { field3: true, .. }`, in pattern analysis we represent it as `Struct { field1: _, field2: _, field3: true, field4: _ }`. This PR makes it so we store `Struct { field3: true, .. }` instead. This means we never have to create fake `_` patterns during lowering.
r? ``@compiler-errors``
Clarity improvements to `DropTree`
These changes are based on some points of confusion I had when initially trying to understand this code.
The only “functional” change is an additional assertion in `<ExitScopes as DropTreeBuilder>::link_entry_point`, checking that the dummy terminator is `TerminatorKind::UnwindResume` as expected.
match lowering: define a convenient struct
Small refactor PR: `bindings` and `ascriptions` always come together so I made a struct for them. I'll have one or two fields to add to it in a later PR as well.
Add asm goto support to `asm!`
Tracking issue: #119364
This PR implements asm-goto support, using the syntax described in "future possibilities" section of [RFC2873](https://rust-lang.github.io/rfcs/2873-inline-asm.html#asm-goto).
Currently I have only implemented the `label` part, not the `fallthrough` part (i.e. fallthrough is implicit). This doesn't reduce the expressive though, since you can use label-break to get arbitrary control flow or simply set a value and rely on jump threading optimisation to get the desired control flow. I can add that later if deemed necessary.
r? ``@Amanieu``
cc ``@ojeda``
This method would previously take a target scope, and then verify that it
was equal to the scope on top of the if-then scope stack.
In practice, this means that callers have to go out of their way to pass around
redundant scope information that's already on the if-then stack.
So it's easier to just retrieve the correct scope directly from the if-then
stack, and simplify the other code that was passing it around.
This allows us to use real field names instead of tuple element numbers.
Renaming `previous_drops` to `existing_drops_map` clarifies that "previous" was
unrelated to drop order.
This makes it easier to see that the call to `in_scope` returns both the then
block and the else block. The rather confusing `unpack!` step is confined to
its own separate line.
(This patch reindents several lines, so using "ignore whitespace" is
recommended in order to focus on the actual changes.)
Extract an arguments struct for `Builder::then_else_break`
Most of this method's arguments are usually or always forwarded as-is to recursive invocations.
Wrapping them in a dedicated struct allows us to document each struct field, and lets us use struct-update syntax to indicate which arguments are being modified when making a recursive call.
---
While trying to understand the lowering of `if` expressions, I found it difficult to keep track of the half-dozen arguments passed through to every call to `then_else_break`. I tried switching over to an arguments struct, and I found that it really helps to make sense of what each argument does, and how each call is modifying the arguments.
I have some further ideas for how to streamline these recursive calls, but I've kept those out of this PR so that it's a pure refactoring with no behavioural changes.
Most of this method's arguments are usually or always forwarded as-is to
recursive invocations.
Wrapping them in a dedicated struct allows us to document each struct field,
and lets us use struct-update syntax to indicate which arguments are being
modified when making a recursive call.
Add new `pattern_complexity` attribute to add possibility to limit and check recursion in pattern matching
Needed for https://github.com/rust-lang/rust-analyzer/issues/9528.
This PR adds a new attribute only available when running rust testsuite called `pattern_complexity` which allows to set the maximum recursion for the pattern matching. It is quite useful to ensure the complexity doesn't grow, like in `tests/ui/pattern/usefulness/issue-118437-exponential-time-on-diagonal-match.rs`.
r? `@Nadrieril`
Rollup of 5 pull requests
Successful merges:
- #120761 (Add initial support for DataFlowSanitizer)
- #121622 (Preserve same vtable pointer when cloning raw waker, to fix Waker::will_wake)
- #121716 (match lowering: Lower bindings in a predictable order)
- #121731 (Now that inlining, mir validation and const eval all use reveal-all, we won't be constraining hidden types here anymore)
- #121841 (`f16` and `f128` step 2: intrinsics)
r? `@ghost`
`@rustbot` modify labels: rollup
match lowering: Lower bindings in a predictable order
After the recent refactorings, we can now lower bindings in a truly predictable order. The order in https://github.com/rust-lang/rust/pull/120214 was an improvement but not very clear. With this PR, we lower bindings from left to right, with the special case that `x @ pat` is traversed as `pat @ x` (i.e. `x` is lowered after any bindings in `pat`).
This description only applies in the absence of or-patterns. Or-patterns make everything complicated, because the binding place depends on the subpattern. Until I have a better idea I leave them to be handled in whatever weird order arises from today's code.
r? `@matthewjasper`
Before, the SwitchInt cases were computed in two passes: if the first
pass accepted e.g. 0..=5 and then 1, the second pass would not accept
0..=5 anymore because 1 would be listed in the SwitchInt options.
Now there's a single pass, so if we sort 0..=5 we must take care to not
sort a subsequent 1.
The ordinary lowering of `thir::ExprKind::Let` is unreachable
After desugaring, `let` expressions should only appear inside `if` expressions or `match` guards, possibly nested within a let-chain. In both cases they are specifically handled by the lowerings of those expressions, so this case is currently unreachable.
---
Context: https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/Lowering.20of.20.60thir.3A.3AExprKind.3A.3ALet.60.20is.20unreachable
My conclusions are partly based on the observation that stubbing out this match arm doesn't cause any test failures. So either this really is unreachable, or it can be reached in some obscure circumstances that our test suite doesn't cover.
If we end up needing this code (or something like it) for an implementation of https://github.com/rust-lang/rfcs/pull/3573, it should be easy enough to pull it back out of version control history.
I looked into having the `if`/`match` lowerings call back into `expr_into_dest`, but from what I can tell that won't work well, because there are extra scoping considerations that require some awareness of the enclosing if/match.
r? ```@Nadrieril```
After desugaring, `let` expressions should only appear inside `if` expressions
or `match` guards, possibly nested within a let-chain. In both cases they are
specifically handled by the lowerings of those expressions, so this case is
currently unreachable.
match lowering: pre-simplify or-patterns too
This is the final part of my work to simplify match pairs early: now we do it for or-patterns too. This makes it possible to collect fake borrows separately from the main match lowering algorithm. That'll enable more simplifications of or-pattern handling.
Note: I was tempted to have `Candidate` contain a `FlatPat`, but there are so many places that use `candidate.match_pairs` etc directly that I chose not to.
r? `@matthewjasper`
match lowering: Separate the `bool` case from other integers in `TestKind`
`TestKind::SwitchInt` had a special case for `bool` essentially everywhere it's used, so I made `TestKind::If` to handle the bool case on its own.
r? `@matthewjasper`
match lowering: Remove hacky branch in sort_candidate
Reusing `self.test()` there wasn't actually pulling a lot of weight. In particular the `TestKind::Len` cases were all already correctly handled.
r? `@matthewjasper`
Make the success arms of `if lhs || rhs` meet up in a separate block
Extracted from #118305, where this is necessary to avoid introducing a bug when injecting marker statements into the then/else arms.
---
In the previous code (#111752), the success block of `lhs` would jump directly to the success block of `rhs`. However, `rhs_success_block` could already contain statements that are specific to the RHS, and the direct goto causes them to be executed in the LHS success path as well.
This patch therefore creates a fresh block that the LHS and RHS success blocks can both jump to.
---
I think the reason we currently get away with this is that `rhs_success_block` usually doesn't contain anything other than StorageDead statements for locals used by the RHS, and those statements don't seem to cause problems in the LHS success path (which never makes those locals live).
But if we start adding meaningful statements for branch coverage (or MC/DC coverage), it's important to keep the LHS and RHS blocks separate.
Add stubs in IR and ABI for `f16` and `f128`
This is the very first step toward the changes in https://github.com/rust-lang/rust/pull/114607 and the [`f16` and `f128` RFC](https://rust-lang.github.io/rfcs/3453-f16-and-f128.html). It adds the types to `rustc_type_ir::FloatTy` and `rustc_abi::Primitive`, and just propagates those out as `unimplemented!` stubs where necessary.
These types do not parse yet so there is no feature gate, and it should be okay to use `unimplemented!`.
The next steps will probably be AST support with parsing and the feature gate.
r? `@compiler-errors`
cc `@Nilstrieb` suggested breaking the PR up in https://github.com/rust-lang/rust/pull/120645#issuecomment-1925900572
Skip unnecessary comparison with half-open range patterns
This is the last remaining detail in the implementation of half-open range patterns. Until now, a half-open range pattern like `10..` was converted to `10..T::MAX` before lowering to MIR, which generated an extra pointless comparison. With this PR we don't generate it.
In the previous code, the success block of `lhs` would jump directly to the
success block of `rhs`. However, `rhs_success_block` could already contain
statements that are specific to the RHS, and the direct goto causes them to be
executed in the LHS success path as well.
This patch therefore creates a fresh block that the LHS and RHS success blocks
can both jump to.
match lowering: Split off `test_candidates` into several functions and improve comments
The logic of `test_candidates` has three steps: pick a test, sort the candidates, and generate code for everything. So I split it off into three methods.
I also ended up reworking the comments that explain the algorithm. In particular I added detailed examples. I removed the digression about https://github.com/rust-lang/rust/issues/29740 because it's no longer relevant to how the code is structured today.
r? ``@matthewjasper``
PR #119097 made the decision to make all `IntoDiagnostic` impls generic,
because this allowed a bunch of nice cleanups. But four hand-written
impls were unintentionally overlooked. This commit makes them generic.
match lowering: test one or pattern at a time
This is a bit more opinionated than the previous PRs. On the face of it this is less efficient and more complex than before, but I personally found the loop that digs into `leaf_candidates` on each iteration very confusing. Instead this does "generate code for this or-pattern" then "generate further code for each branch if needed" in two steps.
Incidentally this way we don't _require_ or patterns to be sorted at the end. It's still an important optimization but I find it clearer to not rely on it for correctness.
r? `@matthewjasper`