Prevent multiple 'ignored unless specified at crate level' lints. The
multiplication happens because we run the same lint three times:
* In BuiltinCombinedEarlyLintPass
* In BuiltinCombinedPreExpansionLintPass
* In shallow_lint_levels_on
Only run the lint one time by checking the `lint_added_lints` bool.
Rollup of 5 pull requests
Successful merges:
- #119331 (rustdoc-search: count path edits with separate edit limit)
- #119359 (Simplify Parser::ident_or_error)
- #119376 (Add regression test for #106630)
- #119379 (Update `parse_seq` doc)
- #119380 (Don't suggest writing a bodyless arm if the pattern can never be a never pattern)
r? `@ghost`
`@rustbot` modify labels: rollup
Don't suggest writing a bodyless arm if the pattern can never be a never pattern
#118527 enabled arms to be bodyless for never patterns ; this PR removes the `,` and `}` suggestions for patterns that could never be never patterns.
Add regression test for #106630
This PR adds a regression test for #106630. I was unsure where exactly to place the test or how to test it locally so please let me know if I should change something.
rustdoc-search: count path edits with separate edit limit
Avoids strange-looking results like this one, where the path component seems to be ignored:
![image](https://github.com/rust-lang/rust/assets/1593513/f0ef077a-6e09-4d67-a29d-8cabc1495f66)
Since the two are counted separately elsewhere, they should get their own limits, too. The biggest problem with combining them is that paths are loosely checked by not requiring every component to match, which means that if they are short and matched loosely, they can easily find "drunk typist" matches that make no sense, like this old result:
std::collections::btree_map::itermut matching slice::itermut
maxEditDistance = ("slice::itermut".length) / 3 = 14 / 3 = 4
editDistance("std", "slice") = 4
editDistance("itermut", "itermut") = 0
4 + 0 <= 4 PASS
Of course, `slice::itermut` should not match stuff from btreemap. `slice` should not match `std`.
The new result counts them separately:
maxPathEditDistance = "slice".length / 3 = 5 / 3 = 1
maxEditDistance = "itermut".length / 3 = 7 / 3 = 2
editDistance("std", "slice") = 4
4 <= 1 FAIL
Effectively, this makes path queries less "typo-resistant". It's not zero, but it means `vec` won't match the `v1` prelude.
This commit also adds substring matching to paths. It's stricter than the substring matching in the main part, but loose enough that what I expect to match does.
Queries without parent paths are unchanged.
This field was not functioning as described in its comment in `config.example.toml`.
Also, updated the default value to `true` to keep the bootstrapping behavior as it was before.
Signed-off-by: onur-ozkan <work@onurozkan.dev>
coverage: Unexpand spans with `find_ancestor_inside_same_ctxt`
Back in https://github.com/rust-lang/rust/pull/118525#discussion_r1412877621 it was observed that our `unexpand_into_body_span` now looks very similar to `Span::find_ancestor_inside`.
At the time I tried switching over, but doing so resulted in incorrect coverage mappings (or assertion failures), so I left a `FIXME` comment instead.
After some investigation, I identified the two problems with my original approach:
- I should have been using `find_ancestor_inside_same_ctxt` instead, since we want a span that's inside the body and has the same context as the body.
- For async functions, we were actually using the post-expansion body span, which is why we needed to forcibly set the unexpanded span's context to match the body span. For body spans produced by macro-expansion, we already have special-case code to detect this and use the pre-expansion call site as the body span. By making this code also detect async desugaring, I was able to end up with a body span that works properly with `find_ancestor_inside_same_ctxt`, avoiding the need to forcibly change the span context.
Fix parenthesization of subexprs containing statement boundary
This PR fixes a multitude of false negatives and false positives in the AST pretty printer's parenthesis insertion related to statement boundaries — statements which terminate unexpectedly early if there aren't parentheses.
Without this fix, the AST pretty printer (including both `stringify!` and `rustc -Zunpretty=expanded`) is prone to producing output which is not syntactically valid Rust. Invalid output is problematic because it means Rustfmt is unable to parse the output of `cargo expand`, for example, causing friction by forcing someone trying to debug a macro into reading poorly formatted code.
I believe the set of bugs fixed in this PR account for the most prevalent reason that `cargo expand` produces invalid output in real-world usage.
Fixes#98790.
## False negatives
The following is a correct program — `cargo check` succeeds.
```rust
macro_rules! m {
($e:expr) => {
match () { _ => $e }
};
}
fn main() {
m!({ 1 } - 1);
}
```
But `rustc -Zunpretty=expanded main.rs` produces output that is invalid Rust syntax, because parenthesization is needed and not being done by the pretty printer.
```rust
fn main() { match () { _ => { 1 } - 1, }; }
```
Piping this expanded code to rustfmt, it fails to parse.
```console
error: unexpected `,` in pattern
--> <stdin>:1:38
|
1 | fn main() { match () { _ => { 1 } - 1, }; }
| ^
|
help: try adding parentheses to match on a tuple...
|
1 | fn main() { match () { _ => { 1 } (- 1,) }; }
| + +
help: ...or a vertical bar to match on multiple alternatives
|
1 | fn main() { match () { _ => { 1 } - 1 | }; }
| ~~~~~
```
Fixed output after this PR:
```rust
fn main() { match () { _ => ({ 1 }) - 1, }; }
```
## False positives
Less problematic, but worth fixing (just like #118726).
```rust
fn main() {
let _ = match () { _ => 1 } - 1;
}
```
Output of `rustc -Zunpretty=expanded lib.rs` before this PR. There is no reason parentheses would need to be inserted there.
```rust
fn main() { let _ = (match () { _ => 1, }) - 1; }
```
After this PR:
```rust
fn main() { let _ = match () { _ => 1, } - 1; }
```
## Alternatives considered
In this PR I opted to parenthesize only the leading subexpression causing the statement boundary, rather than the entire statement. Example:
```rust
macro_rules! m {
($e:expr) => {
$e
};
}
fn main() {
m!(loop { break [1]; }[0] - 1);
}
```
This PR produces the following pretty-printed contents for fn main:
```rust
(loop { break [1]; })[0] - 1;
```
A different equally correct output would be:
```rust
(loop { break [1]; }[0] - 1);
```
I chose the one I did because it is the *only* approach used by handwritten code in the standard library and compiler. There are 4 places where parenthesization is being used to prevent a statement boundary, and in all 4, the developer has chosen to parenthesize the smallest subexpression rather than the whole statement:
b37d43efd9/compiler/rustc_codegen_cranelift/example/alloc_system.rs (L102)b37d43efd9/compiler/rustc_parse/src/errors.rs (L1021-L1029)b37d43efd9/library/core/src/future/poll_fn.rs (L151)b37d43efd9/library/core/src/ops/range.rs (L824-L828)
6459: Check for redundant `matches!` with `Ready`, `Pending`, `V4`, `V6`
Fixes#6459.
```
changelog: [`redundant_pattern_matching`]: Add checks for `Poll::{Ready,Pending}` and `IpAddr::{V4,V6}` in `matches!`
```
Introduce `const Trait` (always-const trait bounds)
Feature `const_trait_impl` currently lacks a way to express “always const” trait bounds. This makes it impossible to define generic items like fns or structs which contain types that depend on const method calls (\*). While the final design and esp. the syntax of effects / keyword generics isn't set in stone, some version of “always const” trait bounds will very likely form a part of it. Further, their implementation is trivial thanks to the `effects` backbone.
Not sure if this needs t-lang sign-off though.
(\*):
```rs
#![feature(const_trait_impl, effects, generic_const_exprs)]
fn compute<T: const Trait>() -> Type<{ T::generate() }> { /*…*/ }
struct Store<T: const Trait>
where
Type<{ T::generate() }>:,
{
field: Type<{ T::generate() }>,
}
```
Lastly, “always const” trait bounds are a perfect fit for `generic_const_items`.
```rs
#![feature(const_trait_impl, effects, generic_const_items)]
const DEFAULT<T: const Default>: T = T::default();
```
Previously, we (oli, fee1-dead and I) wanted to reinterpret `~const Trait` as `const Trait` in generic const items which would've been quite surprising and not very generalizable.
Supersedes #117530.
---
cc `@oli-obk`
As discussed
r? fee1-dead (or compiler)
new lint: `eager_transmute`
A small but still hopefully useful lint that looks for patterns such as `(x < 5).then_some(transmute(x))`.
This is almost certainly wrong because it evaluates the transmute eagerly and can lead to surprises such as the check being completely removed and always evaluating to `Some` no matter what `x` is (it is UB after all when the integer is not a valid bitpattern for the transmuted-to type). [Example](https://godbolt.org/z/xoY34fPzh).
The user most likely meant to use `then` instead.
I can't remember where I saw this but this is inspired by a real bug that happened in practice.
This could probably be a correctness lint?
changelog: new lint: [`eager_int_transmute`]
Support encoding spans with relative offsets
The relative offset is often smaller than the absolute offset, and with
the LEB128 encoding, this ends up cutting the overall metadata size
considerably (~1.5 megabytes on libcore). We can support both relative
and absolute encodings essentially for free since we already take a full
byte to differentiate between direct and indirect encodings (so an extra
variant is quite cheap).
The relative offset is often smaller than the absolute offset, and with
the LEB128 encoding, this ends up cutting the overall metadata size
considerably (~1.5 megabytes on libcore). We can support both relative
and absolute encodings essentially for free since we already take a full
byte to differentiate between direct and indirect encodings (so an extra
variant is quite cheap).