Optimize `delayed_bug` handling.
Once we have emitted at least one error, delayed bugs won't be used. So we can (a) we can (a) discard any existing delayed bugs, and (b) stop recording any new delayed bugs.
This eliminates a longstanding `FIXME` comment. There should be no soundness issues because it's not possible to un-emit an error.
r? `@oli-obk`
`cargo update`
Run `cargo update`, with some pinning and fixes necessitated by that. This *should* unblock #112865
There's a couple of places where I only pinned a dependency in one location - this seems like a bit of a hack, but better than duplicating the FIXME across all `Cargo.toml` where a dependency is introduced.
cc `@Nilstrieb`
Once we have emitted at least one error, delayed bugs won't be used. So
we can (a) we can (a) discard any existing delayed bugs, and (b) stop
recording any new delayed bugs.
This eliminates a longstanding `FIXME` comment. There should be no
soundness issues because it's not possible to un-emit an error.
There are a couple of places where we call
`inner.emitter.emit_diagnostic` directly rather than going through
`inner.emit_diagnostic`, to guarantee the diagnostic is printed. This
feels dubious to me, particularly the bypassing of `TRACK_DIAGNOSTIC`.
This commit removes those.
- In `print_error_count`, it uses `ForceWarning` instead of `Warning`.
- It removes `DiagCtxtInner::failure_note`, because it only has three
uses and direct use of `emit_diagnostic` is consistent with other
similar locations.
- It removes `force_print_diagnostic`, and adds `struct_failure_note`,
and updates `print_query_stack` accordingly, which makes it more
normal. That location doesn't seem to need forced printing anyway.
It's only has a single remaining purpose: to ensure that a diagnostic is
printed when `trimmed_def_paths` is used. It's an annoying mechanism:
weak, with odd semantics, badly named, and gets in the way of other
changes.
This commit replaces it with a simpler `must_produce_diag` mechanism,
getting rid of a diagnostic `Level` along the way.
Now that error counts can't go up and down due to stashing/stealing, we
have a nice property:
(err_count > 0) iff (an ErrorGuaranteed has been produced)
So we can now record `ErrorGuaranteed`s within `DiagCtxt` and use that
in methods like `has_error`, instead of checking that the count is
greater than 0 and calling `unchecked_error_guaranteed` to create the
`ErrorGuaranteed`.
In fact, we can record a `Vec<ErrorGuaranteed>` and use its length to
count the number, instead of maintaining a separate count.
- Remove low-value comments about functionality that is obvious.
- Add missing `track_caller` attributes -- every method should have one.
- Adjust `rustc_lint_diagnostic` attributes. Every method involving a
`impl Into<DiagnosticMessage>` or `impl Into<SubdiangnosticMessage>`
argument should have one, except for those producing bugs, which
aren't user-facing.
The current order is almost perfectly random. This commit puts them into
a predictable order in their own impl block, going from the highest
level (`Block`) to the lowest (`Expect`). Within each level this is the
order:
- struct_err, err
- struct_span_err, span_err
- create_err, emit_err
The first one in each pair creates a diagnostic, the second one creates
*and* emits a diagnostic. Not every method is present for every level.
The diff is messy, but other than moving methods around, the only thing
it does is create the new `impl DiagCtxt` block with its own comment.
Suppress suggestions in derive macro
close#118809
I suppress warnings inside derive macros.
For example, the compiler emits following error by a program described in https://github.com/rust-lang/rust/issues/118809#issuecomment-1852256687 with a suggestion that indicates invalid syntax.
```
error[E0308]: `?` operator has incompatible types
--> src/main.rs:3:17
|
3 | #[derive(Debug, Deserialize)]
| ^^^^^^^^^^^ expected `u32`, found `u64`
|
= note: `?` operator cannot convert from `u64` to `u32`
= note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
help: you can convert a `u64` to a `u32` and panic if the converted value doesn't fit
|
3 | #[derive(Debug, Deserialize.try_into().unwrap())]
| ++++++++++++++++++++
For more information about this error, try `rustc --explain E0308`.
error: could not compile `serde_test` (bin "serde_test") due to 2 previous errors
```
In this PR, suggestions to cast are suppressed.
```
error[E0308]: `?` operator has incompatible types
--> src/main.rs:3:17
|
3 | #[derive(Debug, Deserialize)]
| ^^^^^^^^^^^ expected `u32`, found `u64`
|
= note: `?` operator cannot convert from `u64` to `u32`
= note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0308`.
error: could not compile `serde_test` (bin "serde_test") due to 2 previous errors
```
These crates all needed specialization for `newtype_index!`, which will no
longer be necessary when the current nightly eventually becomes the next
bootstrap compiler.
Fix `ErrorGuaranteed` unsoundness with stash/steal.
When you stash an error, the error count is incremented. You can then use the non-zero error count to get an `ErrorGuaranteed`. You can then steal the error, which decrements the error count. You can then cancel the error.
Example code:
```
fn unsound(dcx: &DiagCtxt) -> ErrorGuaranteed {
let sp = rustc_span::DUMMY_SP;
let k = rustc_errors::StashKey::Cycle;
dcx.struct_err("bogus").stash(sp, k); // increment error count on stash
let guar = dcx.has_errors().unwrap(); // ErrorGuaranteed from error count > 0
let err = dcx.steal_diagnostic(sp, k).unwrap(); // decrement error count on steal
err.cancel(); // cancel error
guar // ErrorGuaranteed with no error emitted!
}
```
This commit fixes the problem in the simplest way: by not counting stashed errors in `DiagCtxt::{err_count,has_errors}`.
However, just doing this without any other changes leads to over 40 ui test failures. Mostly because of uninteresting extra errors (many saying "type annotations needed" when type inference fails), and in a few cases, due to delayed bugs causing ICEs when no normal errors are printed.
To fix these, this commit adds `DiagCtxt::stashed_err_count`, and uses it in three places alongside `DiagCtxt::{has_errors,err_count}`. It's dodgy to rely on it, because unlike `DiagCtxt::err_count` it can go up and down. But it's needed to preserve existing behaviour, and at least the three places that need it are now obvious.
r? oli-obk
Invert diagnostic lints.
That is, change `diagnostic_outside_of_impl` and `untranslatable_diagnostic` from `allow` to `deny`, because more than half of the compiler has been converted to use translated diagnostics.
This commit removes more `deny` attributes than it adds `allow` attributes, which proves that this change is warranted.
r? ````@davidtwco````
When you stash an error, the error count is incremented. You can then
use the non-zero error count to get an `ErrorGuaranteed`. You can then
steal the error, which decrements the error count. You can then cancel
the error.
Example code:
```
fn unsound(dcx: &DiagCtxt) -> ErrorGuaranteed {
let sp = rustc_span::DUMMY_SP;
let k = rustc_errors::StashKey::Cycle;
dcx.struct_err("bogus").stash(sp, k); // increment error count on stash
let guar = dcx.has_errors().unwrap(); // ErrorGuaranteed from error count > 0
let err = dcx.steal_diagnostic(sp, k).unwrap(); // decrement error count on steal
err.cancel(); // cancel error
guar // ErrorGuaranteed with no error emitted!
}
```
This commit fixes the problem in the simplest way: by not counting
stashed errors in `DiagCtxt::{err_count,has_errors}`.
However, just doing this without any other changes leads to over 40 ui
test failures. Mostly because of uninteresting extra errors (many saying
"type annotations needed" when type inference fails), and in a few
cases, due to delayed bugs causing ICEs when no normal errors are
printed.
To fix these, this commit adds `DiagCtxt::stashed_err_count`, and uses
it in three places alongside `DiagCtxt::{has_errors,err_count}`. It's
dodgy to rely on it, because unlike `DiagCtxt::err_count` it can go up
and down. But it's needed to preserve existing behaviour, and at least
the three places that need it are now obvious.
- In `emit_producing_error_guaranteed`, only allow `Level::Error`.
- In `emit_diagnostic`, only produce `ErrorGuaranteed` for `Level` and
`DelayedBug`. (Not `Bug` or `Fatal`. They don't need it, because the
relevant `emit` methods abort.)
- Add/update various comments.
Some cleanups around diagnostic levels.
Plus some refactoring in and around diagnostic levels and emission. Details in the individual commit logs.
r? ````@oli-obk````
That is, change `diagnostic_outside_of_impl` and
`untranslatable_diagnostic` from `allow` to `deny`, because more than
half of the compiler has be converted to use translated diagnostics.
This commit removes more `deny` attributes than it adds `allow`
attributes, which proves that this change is warranted.
All the other `emit`/`emit_diagnostic` methods were recently made
consuming (e.g. #119606), but this one wasn't. But it makes sense to.
Much of this is straightforward, and lots of `clone` calls are avoided.
There are a couple of tricky bits.
- `Emitter::primary_span_formatted` no longer takes a `Diagnostic` and
returns a pair. Instead it takes the two fields from `Diagnostic` that
it used (`span` and `suggestions`) as `&mut`, and modifies them. This
is necessary to avoid the cloning of `diag.children` in two emitters.
- `from_errors_diagnostic` is rearranged so various uses of `diag` occur
before the consuming `emit_diagnostic` call.
The two kinds of delayed bug have quite different semantics so a
stronger conceptual separation is nice. (`is_error` is a good example,
because the two kinds have different behaviour.)
The commit also moves the `DelayedBug` variant after `Error` in `Level`,
to reflect the fact that it's weaker than `Error` -- it might trigger an
error but also might not. (The pre-existing `downgrade_to_delayed_bug`
function also reflects the notion that delayed bugs are lower/after
normal errors.)
Plus it condenses some of the comments on `Level` into a table, for
easier reading, and introduces `can_be_top_or_sub` to indicate which
levels can be used in top-level diagnostics vs. subdiagnostics.
Finally, it renames `DiagCtxtInner::span_delayed_bugs` as
`DiagCtxtInner::delayed_bugs`. The `span_` prefix is unnecessary because
some delayed bugs don't have a span.
- Combine two different blocks involving
`diagnostic.level.get_expectation_id()` into one.
- Combine several `if`s involving `diagnostic.level` into a single
`match`.
This requires reordering some of the operations, but this has no
functional effect.
It doesn't affect behaviour, but makes sense with (a) `FailureNote` having
`()` as its emission guarantee, and (b) in `Level` the `is_error` levels
now are all listed before the non-`is_error` levels.
Remove `BorrowckErrors::tainted_by_errors`
This PR removes one of the `tainted_by_errors` occurrences, replacing it with direct use of `ErrorGuaranteed`.
r? `@oli-obk`
`emit_future_breakage` calls
`self.dcx().take_future_breakage_diagnostics()` and then passes the
result to `self.dcx().emit_future_breakage_report(diags)`. This commit
removes the first of these and lets `emit_future_breakage_report` do the
taking.
It also inlines and removes what is left of `emit_future_breakage`,
which has a single call site.
- `emitted_at` isn't used outside the crate.
- `code` and `messages` are public fields, so there's no point have
trivial getters/setters for them.
- `suggestions` is public, so the comment about "functionality on
`Diagnostic`" isn't needed.
When there are two possibilities, both of which use a `String`, it's
nicer to use a struct than an enum. Especially when mapping the contents
into a tuple.
It contains an `i128`, but when creating them we convert any number
outside the range -100..100 to a string, because Fluent uses an `f64`.
It's all a bit strange.
This commit changes the `i128` to an `i32`, which fits safely in
Fluent's `f64`, and removes the -100..100 range check. This means that
only integers outside the range of `i32` will be converted to strings.