]> git.proxmox.com Git - rustc.git/blobdiff - src/doc/rustc-dev-guide/src/diagnostics.md
New upstream version 1.55.0+dfsg1
[rustc.git] / src / doc / rustc-dev-guide / src / diagnostics.md
index 50da15c220d986f35adb113a20fe3a24486df30d..385d7db60fd8c118a7348cb526a5cb5dbbcfe8ac 100644 (file)
@@ -1,8 +1,285 @@
-# Emitting Errors and other Diagnostics
+# Errors and Lints
+
+<!-- toc -->
 
 A lot of effort has been put into making `rustc` have great error messages.
 This chapter is about how to emit compile errors and lints from the compiler.
 
+## Diagnostic structure
+
+The main parts of a diagnostic error are the following:
+
+```
+error[E0000]: main error message
+  --> file.rs:LL:CC
+   |
+LL | <code>
+   | -^^^^- secondary label
+   |  |
+   |  primary label
+   |
+   = note: note without a `Span`, created with `.note`
+note: sub-diagnostic message for `.span_note`
+  --> file.rs:LL:CC
+   |
+LL | more code
+   |      ^^^^
+```
+
+- Description (`error`, `warning`, etc.).
+- 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.
+- 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:
+  - The path, line number and column of the beginning of the primary span.
+  - The users' affected code and its surroundings.
+  - Primary and secondary spans underlying the users' code. These spans can
+    optionally contain one or more labels.
+    - Primary spans should have enough text to describe the problem in such a
+      way that if it where the only thing being displayed (for example, in an
+      IDE) it would still make sense. Because it is "spatially aware" (it
+      points at the code), it can generally be more succinct than the error
+      message.
+    - If cluttered output can be foreseen in cases when multiple span labels
+      overlap, it is a good idea to tweak the output appropriately. For
+      example, the `if/else arms have incompatible types` error uses different
+      spans depending on whether the arms are all in the same line, if one of
+      the arms is empty and if none of those cases applies.
+- Sub-diagnostics. Any error can have multiple sub-diagnostics that look
+  similar to the main part of the error. These are used for cases where the
+  order of the explanation might not correspond with the order of the code. If
+  the order of the explanation can be "order free", leveraging secondary labels
+  in the main diagnostic is preferred, as it is typically less verbose.
+
+The text should be matter of fact and avoid capitalization and periods, unless
+multiple sentences are _needed_:
+
+```txt
+error: the fobrulator needs to be krontrificated
+```
+
+When code or an identifier must appear in a message or label, it should be
+surrounded with single acute accents \`.
+
+### Error explanations
+
+Some errors include long form descriptions. They may be viewed with the
+`--explain` flag, or via the [error index]. Each explanation comes with an
+example of how to trigger it and advice on how to fix it.
+
+Please read [RFC 1567] for details on how to format and write long error
+codes.
+
+The descriptions are written in Markdown, and all of them are linked in the
+[`rustc_error_codes`] crate.
+
+As a general rule, give an error a code (with an associated explanation) if the
+explanation would give more information than the error itself. A lot of the time
+it's better to put all the information in the emitted error itself. However,
+sometimes that would make the error verbose or there are too many possible
+triggers to include useful information for all cases in the error, in which case
+it's a good idea to add an explanation.[^estebank]
+As always, if you are not sure, just ask your reviewer!
+
+[^estebank]: This rule of thumb was suggested by **@estebank** [here][estebank-comment].
+
+[`rustc_error_codes`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_error_codes/error_codes/index.html
+[error index]: https://doc.rust-lang.org/error-index.html
+[RFC 1567]: https://github.com/rust-lang/rfcs/blob/master/text/1567-long-error-codes-explanation-normalization.md
+[estebank-comment]: https://github.com/rust-lang/rustc-dev-guide/pull/967#issuecomment-733218283
+
+### Lints versus fixed diagnostics
+
+Some messages are emitted via [lints](#lints), where the user can control the
+level. Most diagnostics are hard-coded such that the user cannot control the
+level.
+
+Usually it is obvious whether a diagnostic should be "fixed" or a lint, but
+there are some grey areas.
+
+Here are a few examples:
+
+- Borrow checker errors: these are fixed errors. The user cannot adjust the
+  level of these diagnostics to silence the borrow checker.
+- Dead code: this is a lint. While the user probably doesn't want dead code in
+  their crate, making this a hard error would make refactoring and development
+  very painful.
+- [safe_packed_borrows future compatibility warning][safe_packed_borrows]:
+  this is a silencable lint related to safety. It was judged that the making
+  this a hard (fixed) error would cause too much breakage, so instead a
+  warning is emitted that eventually will be turned into a hard error.
+
+Hard-coded warnings (those using the `span_warn` methods) 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.
+
+See the `deny` [lint level](#diagnostic-levels) below for guidelines when to
+use an error-level lint instead of a fixed error.
+
+[safe_packed_borrows]: https://github.com/rust-lang/rust/issues/46043
+
+## Diagnostic output style guide
+
+- Write in plain simple English. If your message, when shown on a – possibly
+  small – screen (which hasn't been cleaned for a while), cannot be understood
+  by a normal programmer, who just came out of bed after a night partying,
+  it's too complex.
+- `Error`, `Warning`, `Note`, and `Help` messages start with a lowercase
+  letter and do not end with punctuation.
+- Error messages should be succinct. Users will see these error messages many
+  times, and more verbose descriptions can be viewed with the `--explain`
+  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.
+- 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
+  detecting duplicates.
+- When the compiler has too little information for a specific error message,
+  consult with the compiler team to add new attributes for library code that
+  allow adding more information. For example see
+  [`#[rustc_on_unimplemented]`](#rustc_on_unimplemented). Use these
+  annotations when available!
+- Keep in mind that Rust's learning curve is rather steep, and that the
+  compiler messages are an important learning tool.
+- When talking about the compiler, call it `the compiler`, not `Rust` or
+  `rustc`.
+
+### Lint naming
+
+From [RFC 0344], lint names should be consistent, with the following
+guidelines:
+
+The basic rule is: the lint name should make sense when read as "allow
+*lint-name*" or "allow *lint-name* items". For example, "allow
+`deprecated` items" and "allow `dead_code`" makes sense, while "allow
+`unsafe_block`" is ungrammatical (should be plural).
+
+- Lint names should state the bad thing being checked for, e.g. `deprecated`,
+  so that `#[allow(deprecated)]` (items) reads correctly. Thus `ctypes` is not
+  an appropriate name; `improper_ctypes` is.
+
+- Lints that apply to arbitrary items (like the stability lints) should just
+  mention what they check for: use `deprecated` rather than
+  `deprecated_items`. This keeps lint names short. (Again, think "allow
+  *lint-name* items".)
+
+- If a lint applies to a specific grammatical class, mention that class and
+  use the plural form: use `unused_variables` rather than `unused_variable`.
+  This makes `#[allow(unused_variables)]` read correctly.
+
+- Lints that catch unnecessary, unused, or useless aspects of code should use
+  the term `unused`, e.g. `unused_imports`, `unused_typecasts`.
+
+- Use snake case in the same way you would for function names.
+
+[RFC 0344]: https://github.com/rust-lang/rfcs/blob/master/text/0344-conventions-galore.md#lints
+
+### Diagnostic levels
+
+Guidelines for different diagnostic levels:
+
+- `error`: emitted when the compiler detects a problem that makes it unable to
+  compile the program, either because the program is invalid or the programmer
+  has decided to make a specific `warning` into an error.
+
+- `warning`: emitted when the compiler detects something odd about a program.
+  Care should be taken when adding warnings to avoid warning fatigue, and
+  avoid false-positives where there really isn't a problem with the code. Some
+  examples of when it is appropriate to issue a warning:
+
+  - A situation where the user *should* take action, such as swap out a
+    deprecated item, or use a `Result`, but otherwise doesn't prevent
+    compilation.
+  - Unnecessary syntax that can be removed without affecting the semantics of
+    the code. For example, unused code, or unnecessary `unsafe`.
+  - Code that is very likely to be incorrect, dangerous, or confusing, but the
+    language technically allows, and is not ready or confident enough to make
+    an error. For example `unused_comparisons` (out of bounds comparisons) or
+    `bindings_with_variant_name` (the user likely did not intend to create a
+    binding in a pattern).
+  - [Future-incompatible lints](#future-incompatible), where something was
+    accidentally or erroneously accepted in the past, but rejecting would
+    cause excessive breakage in the ecosystem.
+  - Stylistic choices. For example, camel or snake case, or the `dyn` trait
+    warning in the 2018 edition. These have a high bar to be added, and should
+    only be used in exceptional circumstances. Other stylistic choices should
+    either be allow-by-default lints, or part of other tools like Clippy or
+    rustfmt.
+
+- `help`: emitted following an `error` or `warning` to give additional
+  information to the user about how to solve their problem. These messages
+  often include a suggestion string and [`rustc_errors::Applicability`]
+  confidence level to guide automated source fixes by tools. See the
+  [Suggestions](#suggestions) section for more details.
+
+  The error or warning portion should *not* suggest how to fix the problem,
+  only the "help" sub-diagnostic should.
+
+- `note`: emitted to identify additional circumstances and parts of the code
+  that caused the warning or error. For example, the borrow checker will note
+  any previous conflicting borrows.
+
+Not to be confused with *lint levels*, whose guidelines are:
+
+- `forbid`: Lints should never default to `forbid`.
+- `deny`: Equivalent to `error` diagnostic level. Some examples:
+
+  - A future-incompatible or edition-based lint that has graduated from the
+    warning level.
+  - Something that has an extremely high confidence that is incorrect, but
+    still want an escape hatch to allow it to pass.
+
+- `warn`: Equivalent to the `warning` diagnostic level. See `warning` above
+  for guidelines.
+- `allow`: Examples of the kinds of lints that should default to `allow`:
+
+  - The lint has a too high false positive rate.
+  - The lint is too opinionated.
+  - The lint is experimental.
+  - The lint is used for enforcing something that is not normally enforced.
+    For example, the `unsafe_code` lint can be used to prevent usage of unsafe
+    code.
+
+More information about lint levels can be found in the [rustc
+book][rustc-lint-levels] and the [reference][reference-diagnostics].
+
+[`rustc_errors::Applicability`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/enum.Applicability.html
+[reference-diagnostics]: https://doc.rust-lang.org/nightly/reference/attributes/diagnostics.html#lint-check-attributes
+[rustc-lint-levels]: https://doc.rust-lang.org/nightly/rustc/lints/levels.html
+
+## Helpful tips and options
+
+### Finding the source of errors
+
+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
+  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
+  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
+  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.
+
+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
+order things are happening.
+
 ## `Span`
 
 [`Span`][span] is the primary data structure in `rustc` used to represent a
@@ -72,6 +349,12 @@ if let Ok(snippet) = sess.source_map().span_to_snippet(sp) {
 err.emit();
 ```
 
+Alternatively, for less-complex diagnostics, the `SessionDiagnostic` derive
+macro can be used -- see [Creating Errors With SessionDiagnostic][sessiondiagnostic].
+
+[sessiondiagnostic]: ./diagnostics/sessiondiagnostic.md
+
+
 ## Suggestions
 
 In addition to telling the user exactly _why_ their code is wrong, it's
@@ -84,11 +367,29 @@ Server][rls] and [`rustfix`][rustfix].
 [rls]: https://github.com/rust-lang/rls
 [rustfix]: https://github.com/rust-lang/rustfix
 
-Not all suggestions should be applied mechanically. Use the
+Not all suggestions should be applied mechanically, they have a degree of
+confidence in the suggested code, from high
+(`Applicability::MachineApplicable`) to low (`Applicability::MaybeIncorrect`).
+Be conservative when choosing the level. Use the
 [`span_suggestion`][span_suggestion] method of `DiagnosticBuilder` to
 make a suggestion. The last argument provides a hint to tools whether
 the suggestion is mechanically applicable or not.
 
+Suggestions point to one or more spans with corresponding code that will
+replace their current content.
+
+The message that accompanies them should be understandable in the following
+contexts:
+
+- shown as an independent sub-diagnostic (this is the default output)
+- shown as a label pointing at the affected span (this is done automatically if
+some heuristics for verbosity are met)
+- shown as a `help` sub-diagnostic with no content (used for cases where the
+suggestion is obvious from the text, but we still want to let tools to apply
+them))
+- not shown (used for _very_ obvious cases, but we still want to allow tools to
+apply them)
+
 [span_suggestion]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.DiagnosticBuilder.html#method.span_suggestion
 
 For example, to make our `qux` suggestion machine-applicable, we would do:
@@ -157,9 +458,25 @@ The possible values of [`Applicability`][appl] are:
 
 [appl]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/enum.Applicability.html
 
+### Suggestion Style Guide
+
+- Suggestions should not be a question. In particular, language like "did you
+  mean" should be avoided. Sometimes, it's unclear why a particular suggestion
+  is being made. In these cases, it's better to be upfront about what the
+  suggestion is.
+
+  Compare "did you mean: `Foo`" vs. "there is a struct with a similar name: `Foo`".
+
+- The message should not contain any phrases like "the following", "as shown",
+  etc. Use the span to convey what is being talked about.
+- The message may contain further instruction such as "to do xyz, use" or "to do
+  xyz, use abc".
+- The message may contain a name of a function, variable, or type, but avoid
+  whole expressions.
+
 ## Lints
 
-The compiler linting infrastructure is defined in the [`rustc::lint`][rlint]
+The compiler linting infrastructure is defined in the [`rustc_middle::lint`][rlint]
 module.
 
 [rlint]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/lint/index.html
@@ -167,15 +484,20 @@ module.
 ### Declaring a lint
 
 The built-in compiler lints are defined in the [`rustc_lint`][builtin]
-crate.
+crate. Lints that need to be implemented in other crates are defined in
+[`rustc_lint_defs`]. You should prefer to place lints in `rustc_lint` if
+possible. One benefit is that it is close to the dependency root, so it can be
+much faster to work on.
 
 [builtin]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/index.html
+[`rustc_lint_defs`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/index.html
 
 Every lint is implemented via a `struct` that implements the `LintPass` `trait`
-(you also implement one of the more specific lint pass traits, either
-`EarlyLintPass` or `LateLintPass`).  The trait implementation allows you to
-check certain syntactic constructs as the linter walks the source code. You can
-then choose to emit lints in a very similar way to compile errors.
+(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 
+very similar way to compile errors.
 
 You also declare the metadata of a particular lint via the `declare_lint!`
 macro. This includes the name, the default level, a short description, and some
@@ -198,35 +520,45 @@ declare_lint! {
     "suggest using `loop { }` instead of `while true { }`"
 }
 
-// Define a struct and `impl LintPass` for it.
-#[derive(Copy, Clone)]
-pub struct WhileTrue;
-
-// This declares a lint pass, providing a list of associated lints.  The
+// This declares a struct and a lint pass, providing a list of associated lints. The
 // compiler currently doesn't use the associated lints directly (e.g., to not
 // run the pass or otherwise check that the pass emits the appropriate set of
 // lints). However, it's good to be accurate here as it's possible that we're
 // going to register the lints via the get_lints method on our lint pass (that
 // this macro generates).
-impl_lint_pass!(
-    WhileTrue => [WHILE_TRUE],
-);
+declare_lint_pass!(WhileTrue => [WHILE_TRUE]);
 
-// LateLintPass has lots of methods. We only override the definition of
+// Helper function for `WhileTrue` lint.
+// Traverse through any amount of parenthesis and return the first non-parens expression.
+fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
+    while let ast::ExprKind::Paren(sub) = &expr.kind {
+        expr = sub;
+    }
+    expr
+}
+
+// `EarlyLintPass` has lots of methods. We only override the definition of
 // `check_expr` for this lint because that's all we need, but you could
 // override other methods for your own lint. See the rustc docs for a full
 // list of methods.
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for WhileTrue {
-    fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
-        if let hir::ExprWhile(ref cond, ..) = e.node {
-            if let hir::ExprLit(ref lit) = cond.node {
-                if let ast::LitKind::Bool(true) = lit.node {
-                    if lit.span.ctxt() == SyntaxContext::empty() {
+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 msg = "denote infinite loops with `loop { ... }`";
-                        let condition_span = cx.tcx.sess.source_map().def_span(e.span);
-                        let mut err = cx.struct_span_lint(WHILE_TRUE, condition_span, msg);
-                        err.span_suggestion_short(condition_span, "use `loop`", "loop".to_owned());
-                        err.emit();
+                        let condition_span = cx.sess.source_map().guess_head_span(e.span);
+                        cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
+                            lint.build(msg)
+                                .span_suggestion_short(
+                                    condition_span,
+                                    "use `loop`",
+                                    "loop".to_owned(),
+                                    Applicability::MachineApplicable,
+                                )
+                                .emit();
+                        })
                     }
                 }
             }
@@ -235,7 +567,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for WhileTrue {
 }
 ```
 
-### Edition-gated Lints
+### Edition-gated lints
 
 Sometimes we want to change the behavior of a lint in a new edition. To do this,
 we just add the transition to our invocation of `declare_lint!`:
@@ -252,6 +584,24 @@ declare_lint! {
 This makes the `ANONYMOUS_PARAMETERS` lint allow-by-default in the 2015 edition
 but warn-by-default in the 2018 edition.
 
+### Future-incompatible lints
+
+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 
+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 
+meaning that rustc exclusively exposes to users as "future incompatible".
+* 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.
+
 A future-incompatible lint should be declared with the `@future_incompatible`
 additional "field":
 
@@ -262,23 +612,42 @@ declare_lint! {
     "detects anonymous parameters",
     @future_incompatible = FutureIncompatibleInfo {
         reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
-        edition: Some(Edition::Edition2018),
+        reason: FutureIncompatibilityReason::EditionError(Edition::Edition2018),
     };
 }
 ```
 
+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 
+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 
+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
+
 If you need a combination of options that's not supported by the
-`declare_lint!` macro, you can always define your own static with a type of
-`&Lint` but this is currently linted against in the compiler tree.
+`declare_lint!` macro, you can always change the `declare_lint!` macro
+to support this.
 
-####  Guidelines for creating a future incompatibility lint
+### Renaming or removing a lint
 
-- Create a lint defaulting to warn as normal, with ideally the same error
-  message you would normally give.
-- Add a suitable reference, typically an RFC or tracking issue. Go ahead
-  and include the full URL, sort items in ascending order of issue numbers.
-- Later, change lint to error.
-- Eventually, remove lint.
+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
+[`rustc_lint::register_builtins`] function.
+
+```rust,ignore
+store.register_renamed("single_use_lifetime", "single_use_lifetimes");
+```
+
+[`store.register_renamed`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html#method.register_renamed
+[`store.register_removed`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html#method.register_removed
+[`rustc_lint::register_builtins`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/fn.register_builtins.html
 
 ### Lint Groups
 
@@ -302,6 +671,14 @@ 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 
+`@future_incompatible` is used in `declare_lint!`), will be added to
+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.
+
 ### Linting early in the compiler
 
 On occasion, you may need to define a lint that runs before the linting system
@@ -322,12 +699,12 @@ like normal but invokes the lint with `buffer_lint`.
 
 #### Linting even earlier in the compiler
 
-The parser (`librustc_ast`) is interesting in that it cannot have dependencies on
-any of the other `librustc*` crates. In particular, it cannot depend on
-`librustc_middle::lint` or `librustc_lint`, where all of the compiler linting
+The parser (`rustc_ast`) is interesting in that it cannot have dependencies on
+any of the other `rustc*` crates. In particular, it cannot depend on
+`rustc_middle::lint` or `rustc_lint`, where all of the compiler linting
 infrastructure is defined. That's troublesome!
 
-To solve this, `librustc_ast` defines its own buffered lint type, which
+To solve this, `rustc_ast` defines its own buffered lint type, which
 `ParseSess::buffer_lint` uses. After macro expansion, these buffered lints are
 then dumped into the `Session::buffered_lints` used by the rest of the compiler.
 
@@ -335,7 +712,7 @@ then dumped into the `Session::buffered_lints` used by the rest of the compiler.
 
 The compiler accepts an `--error-format json` flag to output
 diagnostics as JSON objects (for the benefit of tools such as `cargo
-fix` or the RLS). It looks like this
+fix` or the RLS). It looks like this:
 
 ```console
 $ rustc json_error_demo.rs --error-format json
@@ -358,8 +735,8 @@ the structured JSON and see the "human" output (well, _sans_ colors)
 without having to compile everything twice.
 
 The "human" readable and the json format emitter can be found under
-librustc_errors, both were moved from the `librustc_ast` crate to the
-[librustc_errors crate](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/index.html).
+`rustc_errors`, both were moved from the `rustc_ast` crate to the
+[rustc_errors crate](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/index.html).
 
 The JSON emitter defines [its own `Diagnostic`
 struct](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/json/struct.Diagnostic.html)