Errors in `DiagCtxtInner::emit_diagnostic` are never set to
`Level::Bug`, because the condition never succeeds, because
`self.treat_err_as_bug()` is called *before* the error counts are
incremented.
This commit switches to `self.treat_next_err_as_bug()`, fixing the
problem. This changes the error message output to actually say "internal
compiler error".
Of the error levels satisfying `is_error`, `Level::Error` is the only
one that can be a lint, so there's no need to check for it.
(And even if it wasn't, it would make more sense to include
non-`Error`-but-`is_error` lints under `lint_err_count` than under
`err_count`.)
There are four functions that adjust error and warning counts:
- `stash_diagnostic` (increment)
- `steal_diagnostic` (decrement)
- `emit_stashed_diagnostics) (decrement)
- `emit_diagnostic` (increment)
The first three all behave similarly, and only update `warn_count` for
forced warnings. But the last one updates `warn_count` for both forced
and non-forced warnings.
Seems like a bug. How should it be fixed? Well, `warn_count` is only
used in one place: `DiagCtxtInner::drop`, where it's part of the
condition relating to the printing of `good_path_delayed_bugs`. The
intention of that condition seems to be "have any errors been printed?"
so this commit replaces `warn_count` with `has_printed`, which is set
when printing occurs. This is simpler than all the ahead-of-time
incrementing and decrementing.
`is_force_warn` is only possible for diagnostics with `Level::Warning`,
but it is currently stored in `Diagnostic::code`, which every diagnostic
has.
This commit:
- removes the boolean `DiagnosticId::Lint::is_force_warn` field;
- adds a `ForceWarning` variant to `Level`.
Benefits:
- The common `Level::Warning` case now has no arguments, replacing
lots of `Warning(None)` occurrences.
- `rustc_session::lint::Level` and `rustc_errors::Level` are more
similar, both having `ForceWarning` and `Warning`.
This lets us avoid the use of `DiagnosticBuilder::into_diagnostic` in
miri, when then means that `DiagnosticBuilder::into_diagnostic` can
become private, being now only used by `stash` and `buffer`.
In #119606 I added them and used a `_mv` suffix, but that wasn't great.
A `with_` prefix has three different existing uses.
- Constructors, e.g. `Vec::with_capacity`.
- Wrappers that provide an environment to execute some code, e.g.
`with_session_globals`.
- Consuming chaining methods, e.g. `Span::with_{lo,hi,ctxt}`.
The third case is exactly what we want, so this commit changes
`DiagnosticBuilder::foo_mv` to `DiagnosticBuilder::with_foo`.
Thanks to @compiler-errors for the suggestion.
We have `span_delayed_bug` and often pass it a `DUMMY_SP`. This commit
adds `delayed_bug`, which matches pairs like `err`/`span_err` and
`warn`/`span_warn`.
Because it takes an error code after the span. This avoids the confusing
overlap with the `DiagCtxt::struct_span_err` method, which doesn't take
an error code.
It was added in #54232. It seems like it was aimed at NLL development,
which is well in the past. Also, it looks like `-Ztreat-err-as-bug` can
be used to achieve the same effect. So it doesn't seem necessary.
They are no longer used, because
`{DiagCtxt,DiagCtxtInner}::emit_diagnostic` are used everywhere instead.
This also means `track_diagnostic` can become consuming.
Currently it's used for two dynamic checks:
- When a diagnostic is emitted, has it been emitted before?
- When a diagnostic is dropped, has it been emitted/cancelled?
The first check is no longer need, because `emit` is consuming, so it's
impossible to emit a `DiagnosticBuilder` twice. The second check is
still needed.
This commit replaces `DiagnosticBuilderState` with a simpler
`Option<Box<Diagnostic>>`, which is enough for the second check:
functions like `emit` and `cancel` can take the `Diagnostic` and then
`drop` can check that the `Diagnostic` was taken.
The `DiagCtxt` reference from `DiagnosticBuilderState` is now stored as
its own field, removing the need for the `dcx` method.
As well as making the code shorter and simpler, the commit removes:
- One (deprecated) `ErrorGuaranteed::unchecked_claim_error_was_emitted`
call.
- Two `FIXME(eddyb)` comments that are no longer relevant.
- The use of a dummy `Diagnostic` in `into_diagnostic`.
Nice!
The existing uses are replaced in one of three ways.
- In a function that also has calls to `emit`, just rearrange the code
so that exactly one of `delay_as_bug` or `emit` is called on every
path.
- In a function returning a `DiagnosticBuilder`, use
`downgrade_to_delayed_bug`. That's good enough because it will get
emitted later anyway.
- In `unclosed_delim_err`, one set of errors is being replaced with
another set, so just cancel the original errors.
This works for most of its call sites. This is nice, because `emit` very
much makes sense as a consuming operation -- indeed,
`DiagnosticBuilderState` exists to ensure no diagnostic is emitted
twice, but it uses runtime checks.
For the small number of call sites where a consuming emit doesn't work,
the commit adds `DiagnosticBuilder::emit_without_consuming`. (This will
be removed in subsequent commits.)
Likewise, `emit_unless` becomes consuming. And `delay_as_bug` becomes
consuming, while `delay_as_bug_without_consuming` is added (which will
also be removed in subsequent commits.)
All this requires significant changes to `DiagnosticBuilder`'s chaining
methods. Currently `DiagnosticBuilder` method chaining uses a
non-consuming `&mut self -> &mut Self` style, which allows chaining to
be used when the chain ends in `emit()`, like so:
```
struct_err(msg).span(span).emit();
```
But it doesn't work when producing a `DiagnosticBuilder` value,
requiring this:
```
let mut err = self.struct_err(msg);
err.span(span);
err
```
This style of chaining won't work with consuming `emit` though. For
that, we need to use to a `self -> Self` style. That also would allow
`DiagnosticBuilder` production to be chained, e.g.:
```
self.struct_err(msg).span(span)
```
However, removing the `&mut self -> &mut Self` style would require that
individual modifications of a `DiagnosticBuilder` go from this:
```
err.span(span);
```
to this:
```
err = err.span(span);
```
There are *many* such places. I have a high tolerance for tedious
refactorings, but even I gave up after a long time trying to convert
them all.
Instead, this commit has it both ways: the existing `&mut self -> Self`
chaining methods are kept, and new `self -> Self` chaining methods are
added, all of which have a `_mv` suffix (short for "move"). Changes to
the existing `forward!` macro lets this happen with very little
additional boilerplate code. I chose to add the suffix to the new
chaining methods rather than the existing ones, because the number of
changes required is much smaller that way.
This doubled chainging is a bit clumsy, but I think it is worthwhile
because it allows a *lot* of good things to subsequently happen. In this
commit, there are many `mut` qualifiers removed in places where
diagnostics are emitted without being modified. In subsequent commits:
- chaining can be used more, making the code more concise;
- more use of chaining also permits the removal of redundant diagnostic
APIs like `struct_err_with_code`, which can be replaced easily with
`struct_err` + `code_mv`;
- `emit_without_diagnostic` can be removed, which simplifies a lot of
machinery, removing the need for `DiagnosticBuilderState`.
Remove `-Zreport-delayed-bugs`.
It's not used within the repository in any way (e.g. in tests), and doesn't seem useful.
It was added in #52568.
r? ````@oli-obk````
Because it's redundant w.r.t. `Diagnostic::is_lint`, which is present
for every diagnostic level.
`struct_lint_level_impl` was the only place that set the `Error` field
to `true`, and it's also the only place that calls
`Diagnostic::is_lint()` to set the `is_lint` field.
It's not used, and doesn't quite fit the general pattern.
Also, `Diagnostic::downgrade_to_delayed_bug` doesn't need to return
`&mut Self` for the same reason.
`Diagnostic` has 40 methods that return `&mut Self` and could be
considered setters. Four of them have a `set_` prefix. This doesn't seem
necessary for a type that implements the builder pattern. This commit
removes the `set_` prefixes on those four methods.
Lots of vectors of messages called `message` or `msg`. This commit
pluralizes them.
Note that `emit_message_default` and `emit_messages_default` both
already existed, and both process a vector, so I renamed the former
`emit_messages_default_inner` because it's called by the latter.
`DiagCtxt::span_bug` is different to the other `DiagCtxt::span_*`
methods. This commit makes it the same, which requires changing
`DiagCtxt::span_delayed_bug` to not do everything within the
`inner.borrow_mut()`.
- Take a `Vec` instead of an iterator, because that's all that is
needed.
- Do an early return for the "no bugs" case.
- Use `enumerate` and an `i == 0` test to identify the first bug.
Those changes mean the `no_bug` variable can be removed, which I found
hard to read.
`IntoDiagnostic` defaults to `ErrorGuaranteed`, because errors are the
most common diagnostic level. It makes sense to do likewise for the
closely-related (and much more widely used) `DiagnosticBuilder` type,
letting us write `DiagnosticBuilder<'a, ErrorGuaranteed>` as just
`DiagnosticBuilder<'a>`. This cuts over 200 lines of code due to many
multi-line things becoming single line things.
We can just get the error level in the `match` and then use
`DiagnosticBuilder::new`. This then means a number of `DiagCtxt`
functions are no longer needed, because this was the one place that used
them.
Note: the commit changes the treatment of spans for `Expect`, which was
different to all the other cases, but this has no apparent effect.
The easter egg ICE on `break rust` is weird: it's the one ICE in the
entire compiler that doesn't immediately abort, which makes it
annoyingly inconsistent.
This commit changes it to abort. As part of this, the extra notes are
now appended onto the bug dignostic, rather than being printed as
individual note diagnostics, which changes the output format a bit.
These changes don't interferes with the joke, but they do help with my
ongoing cleanups to error handling.
This lets different error levels share the same return type from
`emit_*`.
- A lot of inconsistencies in the `DiagCtxt` API are removed.
- `Noted` is removed.
- `FatalAbort` is introduced for fatal errors (abort via `raise`),
replacing the `EmissionGuarantee` impl for `!`.
- `Bug` is renamed `BugAbort` (to avoid clashing with `Level::Bug` and
to mirror `FatalAbort`), and modified to work in the new way with bug
errors (abort via panic).
- Various diagnostic creators and emitters updated to the new, better
signatures. Note that `DiagCtxt::bug` no longer needs to call
`panic_any`, because `emit` handles that.
Also shorten the obnoxiously long
`diagnostic_builder_emit_producing_guarantee` name.
And make all hand-written `IntoDiagnostic` impls generic, by using
`DiagnosticBuilder::new(dcx, level, ...)` instead of e.g.
`dcx.struct_err(...)`.
This means the `create_*` functions are the source of the error level.
This change will let us remove `struct_diagnostic`.
Note: `#[rustc_lint_diagnostics]` is added to `DiagnosticBuilder::new`,
it's necessary to pass diagnostics tests now that it's used in
`into_diagnostic` functions.
This commit replaces this pattern:
```
err.into_diagnostic(dcx)
```
with this pattern:
```
dcx.create_err(err)
```
in a lot of places.
It's a little shorter, makes the error level explicit, avoids some
`IntoDiagnostic` imports, and is a necessary prerequisite for the next
commit which will add a `level` arg to `into_diagnostic`.
This requires adding `track_caller` on `create_err` to avoid mucking up
the output of `tests/ui/track-diagnostics/track4.rs`. It probably should
have been there already.
Uplift `TypeAndMut` and `ClosureKind` to `rustc_type_ir`
Uplifts `TypeAndMut` and `ClosureKind`
I know I said I was just going to get rid of `TypeAndMut` (https://github.com/rust-lang/types-team/issues/124) but I think this is much simpler, lol
r? `@jackh726` or `@lcnr`
Currently, `emit_diagnostic` takes `&mut self`.
This commit changes it so `emit_diagnostic` takes `self` and the new
`emit_diagnostic_without_consuming` function takes `&mut self`.
I find the distinction useful. The former case is much more common, and
avoids a bunch of `mut` and `&mut` occurrences. We can also restrict the
latter with `pub(crate)` which is nice.
Compare `Handler::warn` and `Handler::span_warn`. Conceptually they are
almost identical. But their implementations are weirdly different.
`warn`:
- calls `DiagnosticBuilder::<()>::new(self, Warning(None), msg)`, then `emit()`
- which calls `G::diagnostic_builder_emit_producing_guarantee(self)`
- which calls `handler.emit_diagnostic(&mut db.inner.diagnostic)`
`span_warn`:
- calls `self.emit_diag_at_span(Diagnostic::new(Warning(None), msg), span)`
- which calls `self.emit_diagnostic(diag.set_span(sp))`
I.e. they both end up at `emit_diagnostic`, but take very different
routes to get there.
This commit changes `span_*` and similar ones to not use
`emit_diag_at_span`. Instead they just call `struct_span_*` + `emit`.
Some nice side-effects of this:
- `span_fatal` and `span_fatal_with_code` don't need
`FatalError.raise()`, because `emit` does that.
- `span_err` and `span_err_with_code` doesn't need `unwrap`.
- `struct_span_note`'s `span` arg type is changed from `Span` to
`impl Into<MultiSpan>` like all the other functions.
The `Handler` functions that directly emit diagnostics can be more
easily implemented using `struct_foo(msg).emit()`. This mirrors
`Handler::emit_err` which just does `create_err(err).emit()`.
`Handler::bug` is not converted because of weirdness involving
conflation bugs and fatal errors with `EmissionGuarantee`. I'll fix that
later.
It's necessary for `derive(Diagnostic)`, but is best avoided elsewhere
because there are clearer alternatives.
This required adding `Handler::struct_almost_fatal`.
detects redundant imports that can be eliminated.
for #117772 :
In order to facilitate review and modification, split the checking code and
removing redundant imports code into two PR.
according to a poll of gay people in my phone, purple is the most popular color to use for highlighting
| color | percentage |
| ---------- | ---------- |
| bold white | 6% |
| blue | 14% |
| cyan | 26% |
| purple | 37% |
| magenta | 17% |
unfortunately, purple is not supported by 16-color terminals, which rustc apparently wants to support for some reason.
until we require support for full 256-color terms (e.g. by doing the same feature detection as we currently do for urls), we can't use it.
instead, i have collapsed the purple votes into magenta on the theory that they're close, and also because magenta is pretty.
This is weird: `HandlerInner::emit` calls
`HandlerInner::emit_diagnostic`, but only after doing a
`treat-err-as-bug` check. Which is fine, *except* that there are
multiple others paths for an `Error` or `Fatal` diagnostic to be passed
to `HandlerInner::emit_diagnostic` without going through
`HandlerInner::emit`, e.g. `Handler::span_err` call
`Handler::emit_diag_at_span`, which calls `emit_diagnostic`.
So that suggests that the coverage for `treat-err-as-bug` is incomplete.
This commit removes `HandlerInner::emit` and moves the
`treat-err-as-bug` check to `HandlerInner::emit_diagnostic`, so it
cannot by bypassed.
`Handler` is a wrapper around `HanderInner`. Some functions on
on `Handler` just forward to the samed-named functions on
`HandlerInner`.
This commit removes as many of those as possible, implementing functions
on `Handler` where possible, to avoid the boilerplate required for
forwarding. The commit is moderately large but it's very mechanical.