From 00e57afd2729a68401b0e252cbbbeb5c1b5d1a6f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 9 Feb 2024 14:41:58 +1100 Subject: [PATCH] Some updates for recent diagnostics changes. --- src/bug-fix-procedure.md | 2 +- src/compiler-debugging.md | 15 ++++--- src/diagnostics.md | 58 +++++++++++++-------------- src/diagnostics/diagnostic-structs.md | 27 +++++++------ src/diagnostics/error-codes.md | 6 +-- src/diagnostics/error-guaranteed.md | 4 +- src/diagnostics/lintstore.md | 2 +- src/diagnostics/translation.md | 6 +-- src/ty.md | 20 ++++----- 9 files changed, 71 insertions(+), 69 deletions(-) diff --git a/src/bug-fix-procedure.md b/src/bug-fix-procedure.md index 388e39b93a..70ccc93e05 100644 --- a/src/bug-fix-procedure.md +++ b/src/bug-fix-procedure.md @@ -313,7 +313,7 @@ Let's say that we've adopted `E0592` as our code. Then we can change the `add_lint()` call above to something like: ```rust -struct_span_err!(self.tcx.sess, self.tcx.span_of_impl(item1).unwrap(), msg) +struct_span_code_err!(self.dcx(), self.tcx.span_of_impl(item1).unwrap(), msg) .emit(); ``` diff --git a/src/compiler-debugging.md b/src/compiler-debugging.md index 2d2dd3f15e..c7f799a03c 100644 --- a/src/compiler-debugging.md +++ b/src/compiler-debugging.md @@ -108,12 +108,8 @@ stack backtrace: If you want to get a backtrace to the point where the compiler emits an error message, you can pass the `-Z treat-err-as-bug=n`, which will make -the compiler panic on the `nth` error on `span_delayed_bug`. If you leave -off `=n`, the compiler will assume `1` for `n` and thus panic on the -first error it encounters. - -This can also help when debugging `span_delayed_bug` calls - it will make -the first `span_delayed_bug` call panic, which will give you a useful backtrace. +the compiler panic on the `nth` error. If you leave off `=n`, the compiler will +assume `1` for `n` and thus panic on the first error it encounters. For example: @@ -184,6 +180,13 @@ stack backtrace: Cool, now I have a backtrace for the error! +## Debugging delayed bugs + +The `-Z eagerly-emit-delayed-bugs` option makes it easy to debug delayed bugs. +It turns them into normal errors, i.e. makes them visible. This can be used in +combination with `-Z treat-err-as-bug` to stop at a particular delayed bug and +get a backtrace. + ## Getting the error creation location `-Z track-diagnostics` can help figure out where errors are emitted. It uses `#[track_caller]` diff --git a/src/diagnostics.md b/src/diagnostics.md index 553f1312db..39c6c8aa52 100644 --- a/src/diagnostics.md +++ b/src/diagnostics.md @@ -30,8 +30,8 @@ LL | more code (See [diagnostic levels](#diagnostic-levels)) - Code (for example, for "mismatched types", it is `E0308`). It helps users get more information about the current error through an extended - description of the problem in the error code index. Diagnostics created - by lints don't have a code in the emitted message. + description of the problem in the error code index. Not all diagnostic have a + code. For example, diagnostics created by lints don't have one. - Message. It is the main description of the problem. It should be general and able to stand on its own, so that it can make sense even in isolation. - Diagnostic window. This contains several things: @@ -116,7 +116,7 @@ Here are a few examples: so warnings are instead emitted, and will eventually be turned into fixed (hard) errors. -Hard-coded warnings (those using the `span_warn` methods) should be avoided +Hard-coded warnings (those using methods like `span_warn`) should be avoided for normal code, preferring to use lints instead. Some cases, such as warnings with CLI flags, will require the use of hard-coded warnings. @@ -139,7 +139,7 @@ use an error-level lint instead of a fixed error. - The word "illegal" is illegal. Prefer "invalid" or a more specific word instead. - Errors should document the span of code where they occur (use - [`rustc_errors::diagnostic_builder::DiagnosticBuilder`][diagbuild]'s + [`rustc_errors::DiagCtxt`][DiagCtxt]'s `span_*` methods or a diagnostic struct's `#[primary_span]` to easily do this). Also `note` other spans that have contributed to the error if the span isn't too large. @@ -324,14 +324,12 @@ described below can be used as normal. [diagnostic-structs]: ./diagnostics/diagnostic-structs.md -[`Session`][session] and [`ParseSess`][parsesses] have -methods (or fields with methods) that allow reporting errors. These methods +[`DiagCtxt`][DiagCtxt] has methods that create and emit errors. These methods usually have names like `span_err` or `struct_span_err` or `span_warn`, etc... There are lots of them; they emit different types of "errors", such as warnings, errors, fatal errors, suggestions, etc. -[parsesses]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/parse/struct.ParseSess.html -[session]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/struct.Session.html +[DiagCtxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.DiagCtxt.html In general, there are two classes of such methods: ones that emit an error directly and ones that allow finer control over what to emit. For example, @@ -350,15 +348,15 @@ before emitting it by calling the [`emit`][emit] method. (Failing to either emit or [cancel][cancel] a `DiagnosticBuilder` will result in an ICE.) See the [docs][diagbuild] for more info on what you can do. -[spanerr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/struct.Session.html#method.span_err -[strspanerr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/struct.Session.html#method.struct_span_err +[spanerr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.DiagCtxt.html#method.span_err +[strspanerr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.DiagCtxt.html#method.struct_span_err [diagbuild]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/diagnostic_builder/struct.DiagnosticBuilder.html [emit]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/diagnostic_builder/struct.DiagnosticBuilder.html#method.emit -[cancel]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.Diagnostic.html#method.cancel +[cancel]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/diagnostic_builder/struct.DiagnosticBuilder.html#method.cancel ```rust,ignore // Get a DiagnosticBuilder. This does _not_ emit an error yet. -let mut err = sess.struct_span_err(sp, fluent::example::example_error); +let mut err = sess.dcx.struct_span_err(sp, fluent::example::example_error); // In some cases, you might need to check if `sp` is generated by a macro to // avoid printing weird errors about macro-generated code. @@ -421,7 +419,7 @@ apply them) For example, to make our `qux` suggestion machine-applicable, we would do: ```rust,ignore -let mut err = sess.struct_span_err(sp, fluent::example::message); +let mut err = sess.dcx.struct_span_err(sp, fluent::example::message); if let Ok(snippet) = sess.source_map().span_to_snippet(sp) { err.span_suggestion( @@ -644,24 +642,22 @@ fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr { // list of methods. impl EarlyLintPass for WhileTrue { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - if let ast::ExprKind::While(cond, ..) = &e.kind { - if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind { - if let ast::LitKind::Bool(true) = lit.kind { - if !lit.span.from_expansion() { - let condition_span = cx.sess.source_map().guess_head_span(e.span); - cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| { - lint.build(fluent::example::use_loop) - .span_suggestion_short( - condition_span, - fluent::example::suggestion, - "loop".to_owned(), - Applicability::MachineApplicable, - ) - .emit(); - }) - } - } - } + if let ast::ExprKind::While(cond, ..) = &e.kind + && let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind + && let ast::LitKind::Bool(true) = lit.kind + && !lit.span.from_expansion() + { + let condition_span = cx.sess.source_map().guess_head_span(e.span); + cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| { + lint.build(fluent::example::use_loop) + .span_suggestion_short( + condition_span, + fluent::example::suggestion, + "loop".to_owned(), + Applicability::MachineApplicable, + ) + .emit(); + }) } } } diff --git a/src/diagnostics/diagnostic-structs.md b/src/diagnostics/diagnostic-structs.md index 6d698e3f30..b6ee5aba68 100644 --- a/src/diagnostics/diagnostic-structs.md +++ b/src/diagnostics/diagnostic-structs.md @@ -1,23 +1,23 @@ # Diagnostic and subdiagnostic structs -rustc has two diagnostic derives that can be used to create simple diagnostics, +rustc has three diagnostic derives that can be used to create simple diagnostics, which are recommended to be used when they are applicable: -`#[derive(Diagnostic)]` and `#[derive(Subdiagnostic)]`. +`#[derive(Diagnostic)]`, #[derive(LintDiagnostic)], and `#[derive(Subdiagnostic)]`. Diagnostics created with the derive macros can be translated into different languages and each has a slug that uniquely identifies the diagnostic. -## `#[derive(Diagnostic)]` +## `#[derive(Diagnostic)]` and `#[derive(LintDiagnostic)]` Instead of using the `DiagnosticBuilder` API to create and emit diagnostics, -the `Diagnostic` derive can be used. `#[derive(Diagnostic)]` is -only applicable for simple diagnostics that don't require much logic in -deciding whether or not to add additional subdiagnostics. +these derives can be used. They are only applicable for simple diagnostics that +don't require much logic in deciding whether or not to add additional +subdiagnostics. Consider the [definition][defn] of the "field already declared" diagnostic shown below: ```rust,ignore #[derive(Diagnostic)] -#[diag(hir_analysis_field_already_declared, code = "E0124")] +#[diag(hir_analysis_field_already_declared, code = E0124)] pub struct FieldAlreadyDeclared { pub field_name: Ident, #[primary_span] @@ -113,17 +113,18 @@ In the end, the `Diagnostic` derive will generate an implementation of `IntoDiagnostic` that looks like the following: ```rust,ignore -impl IntoDiagnostic<'_> for FieldAlreadyDeclared { - fn into_diagnostic(self, handler: &'_ rustc_errors::Handler) -> DiagnosticBuilder<'_> { - let mut diag = handler.struct_err(rustc_errors::fluent::hir_analysis_field_already_declared); +impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a> for FieldAlreadyDeclared { + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { + let mut diag = + DiagnosticBuilder::new(dcx, level, fluent::hir_analysis_field_already_declared); diag.set_span(self.span); diag.span_label( self.span, - rustc_errors::fluent::hir_analysis_label + fluent::hir_analysis_label ); diag.span_label( self.prev_span, - rustc_errors::fluent::hir_analysis_previous_decl_label + fluent::hir_analysis_previous_decl_label ); diag } @@ -135,7 +136,7 @@ straightforward, just create an instance of the struct and pass it to `emit_err` (or `emit_warning`): ```rust,ignore -tcx.sess.emit_err(FieldAlreadyDeclared { +tcx.dcx().emit_err(FieldAlreadyDeclared { field_name: f.ident, span: f.span, prev_span, diff --git a/src/diagnostics/error-codes.md b/src/diagnostics/error-codes.md index 7cdf5ebca3..81abd62c8f 100644 --- a/src/diagnostics/error-codes.md +++ b/src/diagnostics/error-codes.md @@ -70,10 +70,10 @@ register_diagnostics! { } ``` -To actually issue the error, you can use the `struct_span_err!` macro: +To actually issue the error, you can use the `struct_span_code_err!` macro: ```rust -struct_span_err!(self.tcx.sess, // some path to the session here +struct_span_code_err!(self.dcx(), // some path to the `DiagCtxt` here span, // whatever span in the source you want E0592, // your new error code fluent::example::an_error_message) @@ -84,7 +84,7 @@ If you want to add notes or other snippets, you can invoke methods before you call `.emit()`: ```rust -struct_span_err!(...) +struct_span_code_err!(...) .span_label(another_span, fluent::example::example_label) .span_note(another_span, fluent::example::separate_note) .emit() diff --git a/src/diagnostics/error-guaranteed.md b/src/diagnostics/error-guaranteed.md index ce1456cfcc..4d4ffdb60b 100644 --- a/src/diagnostics/error-guaranteed.md +++ b/src/diagnostics/error-guaranteed.md @@ -14,7 +14,7 @@ error code path leads to a failure. There are some important considerations about the usage of `ErrorGuaranteed`: * It does _not_ convey information about the _kind_ of error. For example, the - error may be due (indirectly) to a `span_delayed_bug` or other compiler error. + error may be due (indirectly) to a delayed bug or other compiler error. Thus, you should not rely on `ErrorGuaranteed` when deciding whether to emit an error, or what kind of error to emit. @@ -23,7 +23,7 @@ There are some important considerations about the usage of `ErrorGuaranteed`: _has already been_ emitted -- that is, the [`emit()`][emit] function has already been called. For example, if we detect that a future part of the compiler will error, we _cannot_ use `ErrorGuaranteed` unless we first emit - an error ourselves. + an error or delayed bug ourselves. Thankfully, in most cases, it should be statically impossible to abuse `ErrorGuaranteed`. diff --git a/src/diagnostics/lintstore.md b/src/diagnostics/lintstore.md index 54dd841ad2..bd2b025294 100644 --- a/src/diagnostics/lintstore.md +++ b/src/diagnostics/lintstore.md @@ -76,7 +76,7 @@ Registration of these lints happens in the [`rustc_lint::register_internals`] function which is called when constructing a new lint store inside [`rustc_lint::new_lint_store`]. -### Builtin Lints +#### Builtin Lints These are primarily described in two places, `rustc_lint_defs::builtin` and `rustc_lint::builtin`. diff --git a/src/diagnostics/translation.md b/src/diagnostics/translation.md index 5e04e701e4..57a92b1409 100644 --- a/src/diagnostics/translation.md +++ b/src/diagnostics/translation.md @@ -7,13 +7,13 @@ rustc's diagnostic infrastructure supports translatable diagnostics using There are two ways of writing translatable diagnostics: -1. For simple diagnostics, using a diagnostic (or subdiagnostic) derive - ("simple" diagnostics being those that don't require a lot of logic in +1. For simple diagnostics, using a diagnostic (or subdiagnostic) derive. + ("Simple" diagnostics being those that don't require a lot of logic in deciding to emit subdiagnostics and can therefore be represented as diagnostic structs). See [the diagnostic and subdiagnostic structs documentation](./diagnostic-structs.md). 2. Using typed identifiers with `DiagnosticBuilder` APIs (in - `Diagnostic` implementations). + `IntoDiagnostic` or `AddToDiagnostic` or `DecorateLint` implementations). When adding or changing a translatable diagnostic, you don't need to worry about the translations. diff --git a/src/ty.md b/src/ty.md index 044ca6ad91..43e62e116f 100644 --- a/src/ty.md +++ b/src/ty.md @@ -342,24 +342,26 @@ emitting an error to the user, then this could cause later errors to be suppress compilation might inadvertently succeed! Sometimes there is a third case. You believe that an error has been reported, but you believe it -would've been reported earlier in the compilation, not locally. In that case, you can invoke -[`span_delayed_bug`] This will make a note that you expect compilation to yield an error -- if -however compilation should succeed, then it will trigger a compiler bug report. +would've been reported earlier in the compilation, not locally. In that case, you can create a +"delayed bug" with [`delayed_bug`] or [`span_delayed_bug`] This will make a note that you expect +compilation to yield an error -- if however compilation should succeed, then it will trigger a +compiler bug report. +[`delayed_bug`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.DiagCtxt.html#method.delayed_bug [`span_delayed_bug`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.DiagCtxt.html#method.span_delayed_bug For added safety, it's not actually possible to produce a `TyKind::Error` value outside of [`rustc_middle::ty`][ty]; there is a private member of `TyKind::Error` that prevents it from being constructable elsewhere. Instead, -one should use the [`TyCtxt::ty_error`][terr] or -[`TyCtxt::ty_error_with_message`][terrmsg] methods. These methods automatically -call `span_delayed_bug` before returning an interned `Ty` of kind `Error`. If you +one should use the [`Ty::new_error`][terr] or +[`Ty::new_error_with_message`][terrmsg] methods. These methods either take an `ErrorGuaranteed` +or call `span_delayed_bug` before returning an interned `Ty` of kind `Error`. If you were already planning to use [`span_delayed_bug`], then you can just pass the span and message to [`ty_error_with_message`][terrmsg] instead to avoid -delaying a redundant span bug. +a redundant delayed bug. -[terr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.ty_error -[terrmsg]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.ty_error_with_message +[terr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.new_error +[terrmsg]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.new_error_with_message ## Question: Why not substitute “inside” the `AdtDef`?