]> git.proxmox.com Git - rustc.git/blobdiff - src/doc/rustc-dev-guide/src/diagnostics.md
New upstream version 1.63.0+dfsg1
[rustc.git] / src / doc / rustc-dev-guide / src / diagnostics.md
index b6752042852c6bf72bef094428b3a9145fb69fd8..0f0bfd895a40345d971ed5132aba7a5c2cbd1ed9 100644 (file)
@@ -139,10 +139,11 @@ use an error-level lint instead of a fixed error.
   flag. That said, don't make it so terse that it's hard to understand.
 - The word "illegal" is illegal. Prefer "invalid" or a more specific word
   instead.
-- Errors should document the span of code where they occur – the
-  [`rustc_errors::diagnostic_builder::DiagnosticBuilder`][diagbuild]  `span_*`
-  methods allow to easily do this. Also `note` other spans that have
-  contributed to the error if the span isn't too large.
+- Errors should document the span of code where they occur (use
+  [`rustc_errors::diagnostic_builder::DiagnosticBuilder`][diagbuild]'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.
 - When emitting a message with span, try to reduce the span to the smallest
   amount possible that still signifies the issue
 - Try not to emit multiple error messages for the same error. This may require
@@ -272,19 +273,20 @@ There are two main ways to find where a given error is emitted:
 
 - `grep` for either a sub-part of the error message/label or error code. This
   usually works well and is straightforward, but there are some cases where
-  the error emitting code is removed from the code where the error is
+  the code emitting the error is removed from the code where the error is
   constructed behind a relatively deep call-stack. Even then, it is a good way
   to get your bearings.
-- Invoking `rustc` with the nightly-only flag `-Z treat-err-as-bug=1`, which
+- Invoking `rustc` with the nightly-only flag `-Z treat-err-as-bug=1`
   will treat the first error being emitted as an Internal Compiler Error, which
-  allows you to use the environment variable `RUST_BACKTRACE=full` to get a
+  allows you to get a
   stack trace at the point the error has been emitted. Change the `1` to
-  something else if you whish to trigger on a later error. Some limitations
-  with this approach is that some calls get elided from the stack trace because
-  they get inlined in the compiled `rustc`, and the same problem we faced with
-  the prior approach, where the _construction_ of the error is far away from
-  where it is _emitted_. In some cases we buffer multiple errors in order to
-  emit them in order.
+  something else if you wish to trigger on a later error.
+
+  There are limitations with this approach:
+  - Some calls get elided from the stack trace because they get inlined in the compiled `rustc`.
+  - The _construction_ of the error is far away from where it is _emitted_,
+    a problem similar to the one we faced with the `grep` approach.
+    In some cases, we buffer multiple errors in order to emit them in order.
 
 The regular development practices apply: judicious use of `debug!()` statements
 and use of a debugger to trigger break points in order to figure out in what
@@ -312,6 +314,15 @@ reporting errors.
 
 [errors]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/index.html
 
+Diagnostics can be implemented as types which implement the `SessionDiagnostic`
+trait. This is preferred for new diagnostics as it enforces a separation
+between diagnostic emitting logic and the main code paths. For less-complex
+diagnostics, the `SessionDiagnostic` trait can be derived -- see [Diagnostic
+structs][diagnostic-structs]. Within the trait implementation, the APIs
+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
 usually have names like `span_err` or `struct_span_err` or `span_warn`, etc...
@@ -327,6 +338,12 @@ directly and ones that allow finer control over what to emit. For example,
 [`struct_span_err`][strspanerr] instead returns a
 [`DiagnosticBuilder`][diagbuild].
 
+Most of these methods will accept strings, but it is recommended that typed
+identifiers for translatable diagnostics be used for new diagnostics (see
+[Translation][translation]).
+
+[translation]: ./diagnostics/translation.md
+
 `DiagnosticBuilder` allows you to add related notes and suggestions to an error
 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
@@ -340,30 +357,30 @@ emit or [cancel][cancel] a `DiagnosticBuilder` will result in an ICE.) See the
 
 ```rust,ignore
 // Get a DiagnosticBuilder. This does _not_ emit an error yet.
-let mut err = sess.struct_span_err(sp, "oh no! this is an error!");
+let mut err = sess.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.
 
 if let Ok(snippet) = sess.source_map().span_to_snippet(sp) {
     // Use the snippet to generate a suggested fix
-    err.span_suggestion(suggestion_sp, "try using a qux here", format!("qux {}", snippet));
+    err.span_suggestion(suggestion_sp, fluent::example::try_qux_suggestion, format!("qux {}", snippet));
 } else {
     // If we weren't able to generate a snippet, then emit a "help" message
     // instead of a concrete "suggestion". In practice this is unlikely to be
     // reached.
-    err.span_help(suggestion_sp, "you could use a qux here instead");
+    err.span_help(suggestion_sp, fluent::example::qux_suggestion);
 }
 
 // emit the error
 err.emit();
 ```
 
-Alternatively, for less-complex diagnostics, the `SessionDiagnostic` derive
-macro can be used -- see [Creating Errors With SessionDiagnostic][sessiondiagnostic].
-
-[sessiondiagnostic]: ./diagnostics/sessiondiagnostic.md
-
+```fluent
+example-example-error = oh no! this is an error!
+  .try-qux-suggestion = try using a qux here
+  .qux-suggestion = you could use a qux here instead
+```
 
 ## Suggestions
 
@@ -405,17 +422,17 @@ apply them)
 For example, to make our `qux` suggestion machine-applicable, we would do:
 
 ```rust,ignore
-let mut err = sess.struct_span_err(sp, "oh no! this is an error!");
+let mut err = sess.struct_span_err(sp, fluent::example::message);
 
 if let Ok(snippet) = sess.source_map().span_to_snippet(sp) {
     err.span_suggestion(
         suggestion_sp,
-        "try using a qux here",
+        fluent::example::try_qux_suggestion,
         format!("qux {}", snippet),
         Applicability::MachineApplicable,
     );
 } else {
-    err.span_help(suggestion_sp, "you could use a qux here instead");
+    err.span_help(suggestion_sp, fluent::example::qux_suggestion);
 }
 
 err.emit();
@@ -504,9 +521,9 @@ much faster to work on.
 
 Every lint is implemented via a `struct` that implements the `LintPass` `trait`
 (you can also implement one of the more specific lint pass traits, either
-`EarlyLintPass` or `LateLintPass` depending on when is best for your lint to run). 
-The trait implementation allows you to check certain syntactic constructs 
-as the linter walks the AST. You can then choose to emit lints in a 
+`EarlyLintPass` or `LateLintPass` depending on when is best for your lint to run).
+The trait implementation allows you to check certain syntactic constructs
+as the linter walks the AST. You can then choose to emit lints in a
 very similar way to compile errors.
 
 You also declare the metadata of a particular lint via the `declare_lint!`
@@ -557,13 +574,12 @@ impl EarlyLintPass for WhileTrue {
             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 msg = "denote infinite loops with `loop { ... }`";
                         let condition_span = cx.sess.source_map().guess_head_span(e.span);
                         cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
-                            lint.build(msg)
+                            lint.build(fluent::example::use_loop)
                                 .span_suggestion_short(
                                     condition_span,
-                                    "use `loop`",
+                                    fluent::example::suggestion,
                                     "loop".to_owned(),
                                     Applicability::MachineApplicable,
                                 )
@@ -577,6 +593,11 @@ impl EarlyLintPass for WhileTrue {
 }
 ```
 
+```fluent
+example-use-loop = denote infinite loops with `loop {"{"} ... {"}"}`
+  .suggestion = use `loop`
+```
+
 ### Edition-gated lints
 
 Sometimes we want to change the behavior of a lint in a new edition. To do this,
@@ -613,15 +634,15 @@ declare_lint! {
 The use of the term `future-incompatible` within the compiler has a slightly
 broader meaning than what rustc exposes to users of the compiler.
 
-Inside rustc, future-incompatible lints are for signalling to the user that code they have 
+Inside rustc, future-incompatible lints are for signalling to the user that code they have
 written may not compile in the future. In general, future-incompatible code
 exists for two reasons:
-* the user has written unsound code that the compiler mistakenly accepted. While 
-it is within Rust's backwards compatibility guarantees to fix the soundness hole 
-(breaking the user's code), the lint is there to warn the user that this will happen 
-in some upcoming version of rustc *regardless of which edition the code uses*. This is the 
+* the user has written unsound code that the compiler mistakenly accepted. While
+it is within Rust's backwards compatibility guarantees to fix the soundness hole
+(breaking the user's code), the lint is there to warn the user that this will happen
+in some upcoming version of rustc *regardless of which edition the code uses*. This is the
 meaning that rustc exclusively exposes to users as "future incompatible".
-* the user has written code that will either no longer compiler *or* will change 
+* the user has written code that will either no longer compiler *or* will change
 meaning in an upcoming *edition*. These are often called "edition lints" and can be
 typically seen in the various "edition compatibility" lint groups (e.g., `rust_2021_compatibility`)
 that are used to lint against code that will break if the user updates the crate's edition.
@@ -644,11 +665,11 @@ declare_lint! {
 Notice the `reason` field which describes why the future incompatible change is happening.
 This will change the diagnostic message the user receives as well as determine which
 lint groups the lint is added to. In the example above, the lint is an "edition lint"
-(since it's "reason" is `EditionError`) signifying to the user that the use of anonymous 
+(since it's "reason" is `EditionError`) signifying to the user that the use of anonymous
 parameters will no longer compile in Rust 2018 and beyond.
 
-Inside [LintStore::register_lints][fi-lint-groupings], lints with `future_incompatible` 
-fields get placed into either edition-based lint groups (if their `reason` is tied to 
+Inside [LintStore::register_lints][fi-lint-groupings], lints with `future_incompatible`
+fields get placed into either edition-based lint groups (if their `reason` is tied to
 an edition) or into the `future_incompatibility` lint group.
 
 [fi-lint-groupings]: https://github.com/rust-lang/rust/blob/51fd129ac12d5bfeca7d216c47b0e337bf13e0c2/compiler/rustc_lint/src/context.rs#L212-L237
@@ -659,7 +680,7 @@ to support this.
 
 ### Renaming or removing a lint
 
-If it is determined that a lint is either improperly named or no longer needed, 
+If it is determined that a lint is either improperly named or no longer needed,
 the lint must be registered for renaming or removal, which will trigger a warning if a user tries
 to use the old lint name. To declare a rename/remove, add a line with
 [`store.register_renamed`] or [`store.register_removed`] to the code of the
@@ -695,11 +716,11 @@ This defines the `nonstandard_style` group which turns on the listed lints. A
 user can turn on these lints with a `!#[warn(nonstandard_style)]` attribute in
 the source code, or by passing `-W nonstandard-style` on the command line.
 
-Some lint groups are created automatically in `LintStore::register_lints`. For instance, 
-any lint declared with `FutureIncompatibleInfo` where the reason is 
-`FutureIncompatibilityReason::FutureReleaseError` (the default when 
+Some lint groups are created automatically in `LintStore::register_lints`. For instance,
+any lint declared with `FutureIncompatibleInfo` where the reason is
+`FutureIncompatibilityReason::FutureReleaseError` (the default when
 `@future_incompatible` is used in `declare_lint!`), will be added to
-the `future_incompatible` lint group. Editions also have their own lint groups 
+the `future_incompatible` lint group. Editions also have their own lint groups
 (e.g., `rust_2021_compatibility`) automatically generated for any lints signaling
 future-incompatible code that will break in the specified edition.
 
@@ -868,7 +889,7 @@ For example, the `Iterator` trait can be annotated in the following way:
 #[rustc_on_unimplemented(
     on(
         _Self="&str",
-        note="call `.chars()` or `.as_bytes()` on `{Self}"
+        note="call `.chars()` or `.as_bytes()` on `{Self}`"
     ),
     message="`{Self}` is not an iterator",
     label="`{Self}` is not an iterator",