From 492826ac144666c75d68bc0a0121453ecc08561f Mon Sep 17 00:00:00 2001
From: Alexis Bourget <alexis.bourget@gmail.com>
Date: Sat, 5 Sep 2020 22:37:36 +0200
Subject: [PATCH 01/19] Add a note about the panic behavior of math operations
 on time objects

---
 library/std/src/time.rs | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index 73c0a7b403a7b..42f1cde3e1c8f 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -100,6 +100,11 @@ pub use core::time::Duration;
 /// [clock_time_get (Monotonic Clock)]: https://nuxi.nl/cloudabi/#clock_time_get
 ///
 /// **Disclaimer:** These system calls might change over time.
+///
+/// > Note: mathematical operations like [`add`] may panic if the underlying
+/// > structure cannot represent the new point in time.
+///
+/// [`add`]: Instant::add
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[stable(feature = "time2", since = "1.8.0")]
 pub struct Instant(time::Instant);
@@ -174,6 +179,11 @@ pub struct Instant(time::Instant);
 /// [GetSystemTimeAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime
 ///
 /// **Disclaimer:** These system calls might change over time.
+///
+/// > Note: mathematical operations like [`add`] may panic if the underlying
+/// > structure cannot represent the new point in time.
+///
+/// [`add`]: SystemTime::add
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[stable(feature = "time2", since = "1.8.0")]
 pub struct SystemTime(time::SystemTime);

From a6ff925f8b5598a1f6d84964525baa1d4a08fd63 Mon Sep 17 00:00:00 2001
From: LingMan <LingMan@users.noreply.github.com>
Date: Mon, 21 Sep 2020 04:53:44 +0200
Subject: [PATCH 02/19] Reduce boilerplate with the matches! macro

Replaces simple bool `match`es of the form

    match $expr {
        $pattern => true
        _ => false
    }

and their inverse with invocations of the matches! macro.
---
 compiler/rustc_middle/src/hir/map/mod.rs      |  16 +-
 .../rustc_middle/src/mir/interpret/mod.rs     |   8 +-
 .../rustc_middle/src/mir/interpret/value.rs   |  10 +-
 compiler/rustc_middle/src/mir/mod.rs          |  73 ++++-----
 compiler/rustc_middle/src/mir/visit.rs        |  63 +++-----
 .../src/traits/specialization_graph.rs        |   5 +-
 compiler/rustc_middle/src/ty/adjustment.rs    |   5 +-
 compiler/rustc_middle/src/ty/context.rs       |   5 +-
 compiler/rustc_middle/src/ty/diagnostics.rs   |  32 ++--
 compiler/rustc_middle/src/ty/instance.rs      |   8 +-
 compiler/rustc_middle/src/ty/layout.rs        |   5 +-
 compiler/rustc_middle/src/ty/mod.rs           |  34 ++--
 compiler/rustc_middle/src/ty/sty.rs           | 145 ++++--------------
 13 files changed, 140 insertions(+), 269 deletions(-)

diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 1e57411f9c54f..9ef1dd038d170 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -535,15 +535,15 @@ impl<'hir> Map<'hir> {
             Some(Node::Binding(_)) => (),
             _ => return false,
         }
-        match self.find(self.get_parent_node(id)) {
+        matches!(
+            self.find(self.get_parent_node(id)),
             Some(
                 Node::Item(_)
                 | Node::TraitItem(_)
                 | Node::ImplItem(_)
                 | Node::Expr(Expr { kind: ExprKind::Closure(..), .. }),
-            ) => true,
-            _ => false,
-        }
+            )
+        )
     }
 
     /// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context.
@@ -554,10 +554,10 @@ impl<'hir> Map<'hir> {
 
     /// Whether `hir_id` corresponds to a `mod` or a crate.
     pub fn is_hir_id_module(&self, hir_id: HirId) -> bool {
-        match self.get_entry(hir_id).node {
-            Node::Item(Item { kind: ItemKind::Mod(_), .. }) | Node::Crate(..) => true,
-            _ => false,
-        }
+        matches!(
+            self.get_entry(hir_id).node,
+            Node::Item(Item { kind: ItemKind::Mod(_), .. }) | Node::Crate(..)
+        )
     }
 
     /// Retrieves the `HirId` for `id`'s enclosing method, unless there's a
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 20363625e42b6..b5beb3babe239 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -486,10 +486,10 @@ impl<'tcx> TyCtxt<'tcx> {
         // `main as fn() == main as fn()` is false, while `let x = main as fn(); x == x` is true.
         // However, formatting code relies on function identity (see #58320), so we only do
         // this for generic functions.  Lifetime parameters are ignored.
-        let is_generic = instance.substs.into_iter().any(|kind| match kind.unpack() {
-            GenericArgKind::Lifetime(_) => false,
-            _ => true,
-        });
+        let is_generic = instance
+            .substs
+            .into_iter()
+            .any(|kind| !matches!(kind.unpack(), GenericArgKind::Lifetime(_)));
         if is_generic {
             // Get a fresh ID.
             let mut alloc_map = self.alloc_map.lock();
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index 1f547d9dc3a43..e5c7d496bacad 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -445,19 +445,13 @@ impl<'tcx, Tag> Scalar<Tag> {
     /// Do not call this method!  Dispatch based on the type instead.
     #[inline]
     pub fn is_bits(self) -> bool {
-        match self {
-            Scalar::Raw { .. } => true,
-            _ => false,
-        }
+        matches!(self, Scalar::Raw { .. })
     }
 
     /// Do not call this method!  Dispatch based on the type instead.
     #[inline]
     pub fn is_ptr(self) -> bool {
-        match self {
-            Scalar::Ptr(_) => true,
-            _ => false,
-        }
+        matches!(self, Scalar::Ptr(_))
     }
 
     pub fn to_bool(self) -> InterpResult<'tcx, bool> {
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 8ff75bf392e69..03071e716e8f2 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -935,67 +935,59 @@ impl<'tcx> LocalDecl<'tcx> {
     /// - `let x = ...`,
     /// - or `match ... { C(x) => ... }`
     pub fn can_be_made_mutable(&self) -> bool {
-        match self.local_info {
-            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
-                binding_mode: ty::BindingMode::BindByValue(_),
-                opt_ty_info: _,
-                opt_match_place: _,
-                pat_span: _,
-            })))) => true,
-
-            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
-                ImplicitSelfKind::Imm,
-            )))) => true,
-
-            _ => false,
-        }
+        matches!(
+            self.local_info,
+            Some(box LocalInfo::User(ClearCrossCrate::Set(
+                BindingForm::Var(VarBindingForm {
+                    binding_mode: ty::BindingMode::BindByValue(_),
+                    opt_ty_info: _,
+                    opt_match_place: _,
+                    pat_span: _,
+                })
+                | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm),
+            )))
+        )
     }
 
     /// Returns `true` if local is definitely not a `ref ident` or
     /// `ref mut ident` binding. (Such bindings cannot be made into
     /// mutable bindings, but the inverse does not necessarily hold).
     pub fn is_nonref_binding(&self) -> bool {
-        match self.local_info {
-            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
-                binding_mode: ty::BindingMode::BindByValue(_),
-                opt_ty_info: _,
-                opt_match_place: _,
-                pat_span: _,
-            })))) => true,
-
-            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_)))) => true,
-
-            _ => false,
-        }
+        matches!(
+            self.local_info,
+            Some(box LocalInfo::User(ClearCrossCrate::Set(
+                BindingForm::Var(VarBindingForm {
+                    binding_mode: ty::BindingMode::BindByValue(_),
+                    opt_ty_info: _,
+                    opt_match_place: _,
+                    pat_span: _,
+                })
+                | BindingForm::ImplicitSelf(_),
+            )))
+        )
     }
 
     /// Returns `true` if this variable is a named variable or function
     /// parameter declared by the user.
     #[inline]
     pub fn is_user_variable(&self) -> bool {
-        match self.local_info {
-            Some(box LocalInfo::User(_)) => true,
-            _ => false,
-        }
+        matches!(self.local_info, Some(box LocalInfo::User(_)))
     }
 
     /// Returns `true` if this is a reference to a variable bound in a `match`
     /// expression that is used to access said variable for the guard of the
     /// match arm.
     pub fn is_ref_for_guard(&self) -> bool {
-        match self.local_info {
-            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard))) => true,
-            _ => false,
-        }
+        matches!(
+            self.local_info,
+            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)))
+        )
     }
 
     /// Returns `Some` if this is a reference to a static item that is used to
     /// access that static
     pub fn is_ref_to_static(&self) -> bool {
-        match self.local_info {
-            Some(box LocalInfo::StaticRef { .. }) => true,
-            _ => false,
-        }
+        matches!(self.local_info, Some(box LocalInfo::StaticRef { .. }))
     }
 
     /// Returns `Some` if this is a reference to a static item that is used to
@@ -2124,10 +2116,7 @@ pub enum BinOp {
 impl BinOp {
     pub fn is_checkable(self) -> bool {
         use self::BinOp::*;
-        match self {
-            Add | Sub | Mul | Shl | Shr => true,
-            _ => false,
-        }
+        matches!(self, Add | Sub | Mul | Shl | Shr)
     }
 }
 
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index a008bd5f75fa0..f4d57dffacf0c 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -1164,82 +1164,63 @@ pub enum PlaceContext {
 impl PlaceContext {
     /// Returns `true` if this place context represents a drop.
     pub fn is_drop(&self) -> bool {
-        match *self {
-            PlaceContext::MutatingUse(MutatingUseContext::Drop) => true,
-            _ => false,
-        }
+        matches!(self, PlaceContext::MutatingUse(MutatingUseContext::Drop))
     }
 
     /// Returns `true` if this place context represents a borrow.
     pub fn is_borrow(&self) -> bool {
-        match *self {
+        matches!(
+            self,
             PlaceContext::NonMutatingUse(
                 NonMutatingUseContext::SharedBorrow
-                | NonMutatingUseContext::ShallowBorrow
-                | NonMutatingUseContext::UniqueBorrow,
-            )
-            | PlaceContext::MutatingUse(MutatingUseContext::Borrow) => true,
-            _ => false,
-        }
+                    | NonMutatingUseContext::ShallowBorrow
+                    | NonMutatingUseContext::UniqueBorrow
+            ) | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
+        )
     }
 
     /// Returns `true` if this place context represents a storage live or storage dead marker.
     pub fn is_storage_marker(&self) -> bool {
-        match *self {
-            PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead) => true,
-            _ => false,
-        }
+        matches!(
+            self,
+            PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead)
+        )
     }
 
     /// Returns `true` if this place context represents a storage live marker.
     pub fn is_storage_live_marker(&self) -> bool {
-        match *self {
-            PlaceContext::NonUse(NonUseContext::StorageLive) => true,
-            _ => false,
-        }
+        matches!(self, PlaceContext::NonUse(NonUseContext::StorageLive))
     }
 
     /// Returns `true` if this place context represents a storage dead marker.
     pub fn is_storage_dead_marker(&self) -> bool {
-        match *self {
-            PlaceContext::NonUse(NonUseContext::StorageDead) => true,
-            _ => false,
-        }
+        matches!(self, PlaceContext::NonUse(NonUseContext::StorageDead))
     }
 
     /// Returns `true` if this place context represents a use that potentially changes the value.
     pub fn is_mutating_use(&self) -> bool {
-        match *self {
-            PlaceContext::MutatingUse(..) => true,
-            _ => false,
-        }
+        matches!(self, PlaceContext::MutatingUse(..))
     }
 
     /// Returns `true` if this place context represents a use that does not change the value.
     pub fn is_nonmutating_use(&self) -> bool {
-        match *self {
-            PlaceContext::NonMutatingUse(..) => true,
-            _ => false,
-        }
+        matches!(self, PlaceContext::NonMutatingUse(..))
     }
 
     /// Returns `true` if this place context represents a use.
     pub fn is_use(&self) -> bool {
-        match *self {
-            PlaceContext::NonUse(..) => false,
-            _ => true,
-        }
+        !matches!(self, PlaceContext::NonUse(..))
     }
 
     /// Returns `true` if this place context represents an assignment statement.
     pub fn is_place_assignment(&self) -> bool {
-        match *self {
+        matches!(
+            self,
             PlaceContext::MutatingUse(
                 MutatingUseContext::Store
-                | MutatingUseContext::Call
-                | MutatingUseContext::AsmOutput,
-            ) => true,
-            _ => false,
-        }
+                    | MutatingUseContext::Call
+                    | MutatingUseContext::AsmOutput,
+            )
+        )
     }
 }
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
index 969404c68cab7..ec6010e6eecf4 100644
--- a/compiler/rustc_middle/src/traits/specialization_graph.rs
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -79,10 +79,7 @@ pub enum Node {
 
 impl<'tcx> Node {
     pub fn is_from_trait(&self) -> bool {
-        match *self {
-            Node::Trait(..) => true,
-            _ => false,
-        }
+        matches!(self, Node::Trait(..))
     }
 
     /// Iterate over the items defined directly by the given (impl or trait) node.
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index 46ef5ff7dd8c5..89d0e13955122 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -85,10 +85,7 @@ pub struct Adjustment<'tcx> {
 
 impl Adjustment<'tcx> {
     pub fn is_region_borrow(&self) -> bool {
-        match self.kind {
-            Adjust::Borrow(AutoBorrow::Ref(..)) => true,
-            _ => false,
-        }
+        matches!(self.kind, Adjust::Borrow(AutoBorrow::Ref(..)))
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index cd8f12a4f3576..d2c7d6e328f71 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -588,10 +588,7 @@ impl<'tcx> TypeckResults<'tcx> {
             return false;
         }
 
-        match self.type_dependent_defs().get(expr.hir_id) {
-            Some(Ok((DefKind::AssocFn, _))) => true,
-            _ => false,
-        }
+        matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _))))
     }
 
     pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option<BindingMode> {
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 715319747e390..65703d04c7040 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -11,21 +11,16 @@ use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate};
 impl<'tcx> TyS<'tcx> {
     /// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive.
     pub fn is_primitive_ty(&self) -> bool {
-        match self.kind() {
-            Bool
-            | Char
-            | Str
-            | Int(_)
-            | Uint(_)
-            | Float(_)
+        matches!(
+            self.kind(),
+            Bool | Char | Str | Int(_) | Uint(_) | Float(_)
             | Infer(
                 InferTy::IntVar(_)
                 | InferTy::FloatVar(_)
                 | InferTy::FreshIntTy(_)
-                | InferTy::FreshFloatTy(_),
-            ) => true,
-            _ => false,
-        }
+                | InferTy::FreshFloatTy(_)
+            )
+        )
     }
 
     /// Whether the type is succinctly representable as a type instead of just referred to with a
@@ -64,11 +59,16 @@ impl<'tcx> TyS<'tcx> {
 
     /// Whether the type can be safely suggested during error recovery.
     pub fn is_suggestable(&self) -> bool {
-        match self.kind() {
-            Opaque(..) | FnDef(..) | FnPtr(..) | Dynamic(..) | Closure(..) | Infer(..)
-            | Projection(..) => false,
-            _ => true,
-        }
+        !matches!(
+            self.kind(),
+            Opaque(..)
+                | FnDef(..)
+                | FnPtr(..)
+                | Dynamic(..)
+                | Closure(..)
+                | Infer(..)
+                | Projection(..)
+        )
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index a6b62097d5b18..e527d6dc34cf1 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -183,10 +183,10 @@ impl<'tcx> InstanceDef<'tcx> {
             ty::InstanceDef::DropGlue(_, Some(_)) => return false,
             _ => return true,
         };
-        match tcx.def_key(def_id).disambiguated_data.data {
-            DefPathData::Ctor | DefPathData::ClosureExpr => true,
-            _ => false,
-        }
+        matches!(
+            tcx.def_key(def_id).disambiguated_data.data,
+            DefPathData::Ctor | DefPathData::ClosureExpr
+        )
     }
 
     /// Returns `true` if the machine code for this instance is instantiated in
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index b0a1413a9d62f..4e2dac0fd8c9c 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -2628,10 +2628,7 @@ where
             target.target_os == "linux" && target.arch == "sparc64" && target_env_gnu_like;
         let linux_powerpc_gnu_like =
             target.target_os == "linux" && target.arch == "powerpc" && target_env_gnu_like;
-        let rust_abi = match sig.abi {
-            RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true,
-            _ => false,
-        };
+        let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall);
 
         // Handle safe Rust thin and fat pointers.
         let adjust_for_rust_scalar = |attrs: &mut ArgAttributes,
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index f23d666cfcfdd..eaf8037d6099e 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2675,15 +2675,15 @@ impl<'tcx> ClosureKind {
     /// Returns `true` if this a type that impls this closure kind
     /// must also implement `other`.
     pub fn extends(self, other: ty::ClosureKind) -> bool {
-        match (self, other) {
-            (ClosureKind::Fn, ClosureKind::Fn) => true,
-            (ClosureKind::Fn, ClosureKind::FnMut) => true,
-            (ClosureKind::Fn, ClosureKind::FnOnce) => true,
-            (ClosureKind::FnMut, ClosureKind::FnMut) => true,
-            (ClosureKind::FnMut, ClosureKind::FnOnce) => true,
-            (ClosureKind::FnOnce, ClosureKind::FnOnce) => true,
-            _ => false,
-        }
+        matches!(
+            (self, other),
+            (ClosureKind::Fn, ClosureKind::Fn)
+                | (ClosureKind::Fn, ClosureKind::FnMut)
+                | (ClosureKind::Fn, ClosureKind::FnOnce)
+                | (ClosureKind::FnMut, ClosureKind::FnMut)
+                | (ClosureKind::FnMut, ClosureKind::FnOnce)
+                | (ClosureKind::FnOnce, ClosureKind::FnOnce)
+        )
     }
 
     /// Returns the representative scalar type for this closure kind.
@@ -2809,15 +2809,15 @@ impl<'tcx> TyCtxt<'tcx> {
 
     pub fn opt_associated_item(self, def_id: DefId) -> Option<&'tcx AssocItem> {
         let is_associated_item = if let Some(def_id) = def_id.as_local() {
-            match self.hir().get(self.hir().local_def_id_to_hir_id(def_id)) {
-                Node::TraitItem(_) | Node::ImplItem(_) => true,
-                _ => false,
-            }
+            matches!(
+                self.hir().get(self.hir().local_def_id_to_hir_id(def_id)),
+                Node::TraitItem(_) | Node::ImplItem(_)
+            )
         } else {
-            match self.def_kind(def_id) {
-                DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy => true,
-                _ => false,
-            }
+            matches!(
+                self.def_kind(def_id),
+                DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy
+            )
         };
 
         is_associated_item.then(|| self.associated_item(def_id))
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 724ec101b23b7..5cba451ea6e3c 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1763,10 +1763,7 @@ impl<'tcx> TyS<'tcx> {
 
     #[inline]
     pub fn is_never(&self) -> bool {
-        match self.kind() {
-            Never => true,
-            _ => false,
-        }
+        matches!(self.kind(), Never)
     }
 
     /// Checks whether a type is definitely uninhabited. This is
@@ -1823,34 +1820,22 @@ impl<'tcx> TyS<'tcx> {
 
     #[inline]
     pub fn is_adt(&self) -> bool {
-        match self.kind() {
-            Adt(..) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Adt(..))
     }
 
     #[inline]
     pub fn is_ref(&self) -> bool {
-        match self.kind() {
-            Ref(..) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Ref(..))
     }
 
     #[inline]
     pub fn is_ty_var(&self) -> bool {
-        match self.kind() {
-            Infer(TyVar(_)) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Infer(TyVar(_)))
     }
 
     #[inline]
     pub fn is_ty_infer(&self) -> bool {
-        match self.kind() {
-            Infer(_) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Infer(_))
     }
 
     #[inline]
@@ -1880,20 +1865,14 @@ impl<'tcx> TyS<'tcx> {
     #[inline]
     pub fn is_slice(&self) -> bool {
         match self.kind() {
-            RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => match ty.kind() {
-                Slice(_) | Str => true,
-                _ => false,
-            },
+            RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => matches!(ty.kind(), Slice(_) | Str),
             _ => false,
         }
     }
 
     #[inline]
     pub fn is_array(&self) -> bool {
-        match self.kind() {
-            Array(..) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Array(..))
     }
 
     #[inline]
@@ -1940,27 +1919,21 @@ impl<'tcx> TyS<'tcx> {
 
     #[inline]
     pub fn is_region_ptr(&self) -> bool {
-        match self.kind() {
-            Ref(..) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Ref(..))
     }
 
     #[inline]
     pub fn is_mutable_ptr(&self) -> bool {
-        match self.kind() {
+        matches!(
+            self.kind(),
             RawPtr(TypeAndMut { mutbl: hir::Mutability::Mut, .. })
-            | Ref(_, _, hir::Mutability::Mut) => true,
-            _ => false,
-        }
+                | Ref(_, _, hir::Mutability::Mut)
+        )
     }
 
     #[inline]
     pub fn is_unsafe_ptr(&self) -> bool {
-        match self.kind() {
-            RawPtr(_) => true,
-            _ => false,
-        }
+        matches!(self.kind(), RawPtr(_))
     }
 
     /// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer).
@@ -1990,35 +1963,22 @@ impl<'tcx> TyS<'tcx> {
     /// contents are abstract to rustc.)
     #[inline]
     pub fn is_scalar(&self) -> bool {
-        match self.kind() {
-            Bool
-            | Char
-            | Int(_)
-            | Float(_)
-            | Uint(_)
+        matches!(
+            self.kind(),
+            Bool | Char | Int(_) | Float(_) | Uint(_) | FnDef(..) | FnPtr(_) | RawPtr(_)
             | Infer(IntVar(_) | FloatVar(_))
-            | FnDef(..)
-            | FnPtr(_)
-            | RawPtr(_) => true,
-            _ => false,
-        }
+        )
     }
 
     /// Returns `true` if this type is a floating point type.
     #[inline]
     pub fn is_floating_point(&self) -> bool {
-        match self.kind() {
-            Float(_) | Infer(FloatVar(_)) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Float(_) | Infer(FloatVar(_)))
     }
 
     #[inline]
     pub fn is_trait(&self) -> bool {
-        match self.kind() {
-            Dynamic(..) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Dynamic(..))
     }
 
     #[inline]
@@ -2031,52 +1991,32 @@ impl<'tcx> TyS<'tcx> {
 
     #[inline]
     pub fn is_closure(&self) -> bool {
-        match self.kind() {
-            Closure(..) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Closure(..))
     }
 
     #[inline]
     pub fn is_generator(&self) -> bool {
-        match self.kind() {
-            Generator(..) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Generator(..))
     }
 
     #[inline]
     pub fn is_integral(&self) -> bool {
-        match self.kind() {
-            Infer(IntVar(_)) | Int(_) | Uint(_) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Infer(IntVar(_)) | Int(_) | Uint(_))
     }
 
     #[inline]
     pub fn is_fresh_ty(&self) -> bool {
-        match self.kind() {
-            Infer(FreshTy(_)) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Infer(FreshTy(_)))
     }
 
     #[inline]
     pub fn is_fresh(&self) -> bool {
-        match self.kind() {
-            Infer(FreshTy(_)) => true,
-            Infer(FreshIntTy(_)) => true,
-            Infer(FreshFloatTy(_)) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Infer(FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_)))
     }
 
     #[inline]
     pub fn is_char(&self) -> bool {
-        match self.kind() {
-            Char => true,
-            _ => false,
-        }
+        matches!(self.kind(), Char)
     }
 
     #[inline]
@@ -2086,34 +2026,22 @@ impl<'tcx> TyS<'tcx> {
 
     #[inline]
     pub fn is_signed(&self) -> bool {
-        match self.kind() {
-            Int(_) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Int(_))
     }
 
     #[inline]
     pub fn is_ptr_sized_integral(&self) -> bool {
-        match self.kind() {
-            Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize))
     }
 
     #[inline]
     pub fn is_machine(&self) -> bool {
-        match self.kind() {
-            Int(..) | Uint(..) | Float(..) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Int(..) | Uint(..) | Float(..))
     }
 
     #[inline]
     pub fn has_concrete_skeleton(&self) -> bool {
-        match self.kind() {
-            Param(_) | Infer(_) | Error(_) => false,
-            _ => true,
-        }
+        !matches!(self.kind(), Param(_) | Infer(_) | Error(_))
     }
 
     /// Returns the type and mutability of `*ty`.
@@ -2156,26 +2084,17 @@ impl<'tcx> TyS<'tcx> {
 
     #[inline]
     pub fn is_fn(&self) -> bool {
-        match self.kind() {
-            FnDef(..) | FnPtr(_) => true,
-            _ => false,
-        }
+        matches!(self.kind(), FnDef(..) | FnPtr(_))
     }
 
     #[inline]
     pub fn is_fn_ptr(&self) -> bool {
-        match self.kind() {
-            FnPtr(_) => true,
-            _ => false,
-        }
+        matches!(self.kind(), FnPtr(_))
     }
 
     #[inline]
     pub fn is_impl_trait(&self) -> bool {
-        match self.kind() {
-            Opaque(..) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Opaque(..))
     }
 
     #[inline]

From b4e77d21bcf8b15ef7d873005382ba8ca309faf5 Mon Sep 17 00:00:00 2001
From: "Felix S. Klock II" <pnkfelix@pnkfx.org>
Date: Mon, 15 Jun 2020 11:50:58 -0400
Subject: [PATCH 03/19] rewrite old test so that its attributes are consistent
 with what we want in the language.

(Note that the fact this test existed is a slight sign that we may need a crater
run on this bugfix...)
---
 .../ui/rfc-2565-param-attrs/param-attrs-allowed.rs   | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs b/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs
index 1217f89cb3168..a547d09d04822 100644
--- a/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs
+++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs
@@ -8,8 +8,8 @@ extern "C" {
         #[allow(unused_mut)] a: i32,
         #[cfg(something)] b: i32,
         #[cfg_attr(something, cfg(nothing))] c: i32,
-        #[deny(unused_mut)] d: i32,
-        #[forbid(unused_mut)] #[warn(unused_mut)] ...
+        #[forbid(unused_mut)] d: i32,
+        #[deny(unused_mut)] #[warn(unused_mut)] ...
     );
 }
 
@@ -17,16 +17,16 @@ type FnType = fn(
     #[allow(unused_mut)] a: i32,
     #[cfg(something)] b: i32,
     #[cfg_attr(something, cfg(nothing))] c: i32,
-    #[deny(unused_mut)] d: i32,
-    #[forbid(unused_mut)] #[warn(unused_mut)] e: i32
+    #[forbid(unused_mut)] d: i32,
+    #[deny(unused_mut)] #[warn(unused_mut)] e: i32
 );
 
 pub fn foo(
     #[allow(unused_mut)] a: i32,
     #[cfg(something)] b: i32,
     #[cfg_attr(something, cfg(nothing))] c: i32,
-    #[deny(unused_mut)] d: i32,
-    #[forbid(unused_mut)] #[warn(unused_mut)] _e: i32
+    #[forbid(unused_mut)] d: i32,
+    #[deny(unused_mut)] #[warn(unused_mut)] _e: i32
 ) {}
 
 // self

From 9601724b11bbd9081b1bee6f7e478a5d2b9ace41 Mon Sep 17 00:00:00 2001
From: Tamir Duberstein <tamird@google.com>
Date: Sun, 4 Oct 2020 12:39:39 +0000
Subject: [PATCH 04/19] Avoid unchecked casts in net parser

---
 library/std/src/net/parser.rs | 69 +++++++++++++++++++++++------------
 1 file changed, 46 insertions(+), 23 deletions(-)

diff --git a/library/std/src/net/parser.rs b/library/std/src/net/parser.rs
index 0570a7c41bfe6..da94a5735034f 100644
--- a/library/std/src/net/parser.rs
+++ b/library/std/src/net/parser.rs
@@ -6,11 +6,34 @@
 #[cfg(test)]
 mod tests;
 
+use crate::convert::TryInto as _;
 use crate::error::Error;
 use crate::fmt;
 use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
 use crate::str::FromStr;
 
+trait ReadNumberHelper: crate::marker::Sized {
+    const ZERO: Self;
+    fn checked_mul(&self, other: u32) -> Option<Self>;
+    fn checked_add(&self, other: u32) -> Option<Self>;
+}
+
+macro_rules! impl_helper {
+    ($($t:ty)*) => ($(impl ReadNumberHelper for $t {
+        const ZERO: Self = 0;
+        #[inline]
+        fn checked_mul(&self, other: u32) -> Option<Self> {
+            Self::checked_mul(*self, other.try_into().ok()?)
+        }
+        #[inline]
+        fn checked_add(&self, other: u32) -> Option<Self> {
+            Self::checked_add(*self, other.try_into().ok()?)
+        }
+    })*)
+}
+
+impl_helper! { u8 u16 }
+
 struct Parser<'a> {
     // parsing as ASCII, so can use byte array
     state: &'a [u8],
@@ -59,7 +82,7 @@ impl<'a> Parser<'a> {
     fn read_char(&mut self) -> Option<char> {
         self.state.split_first().map(|(&b, tail)| {
             self.state = tail;
-            b as char
+            char::from(b)
         })
     }
 
@@ -84,25 +107,26 @@ impl<'a> Parser<'a> {
         })
     }
 
-    // Read a single digit in the given radix. For instance, 0-9 in radix 10;
-    // 0-9A-F in radix 16.
-    fn read_digit(&mut self, radix: u32) -> Option<u32> {
-        self.read_atomically(move |p| p.read_char()?.to_digit(radix))
-    }
-
     // Read a number off the front of the input in the given radix, stopping
     // at the first non-digit character or eof. Fails if the number has more
-    // digits than max_digits, or the value is >= upto, or if there is no number.
-    fn read_number(&mut self, radix: u32, max_digits: u32, upto: u32) -> Option<u32> {
+    // digits than max_digits or if there is no number.
+    fn read_number<T: ReadNumberHelper>(
+        &mut self,
+        radix: u32,
+        max_digits: Option<usize>,
+    ) -> Option<T> {
         self.read_atomically(move |p| {
-            let mut result = 0;
+            let mut result = T::ZERO;
             let mut digit_count = 0;
 
-            while let Some(digit) = p.read_digit(radix) {
-                result = (result * radix) + digit;
+            while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) {
+                result = result.checked_mul(radix)?;
+                result = result.checked_add(digit)?;
                 digit_count += 1;
-                if digit_count > max_digits || result >= upto {
-                    return None;
+                if let Some(max_digits) = max_digits {
+                    if digit_count > max_digits {
+                        return None;
+                    }
                 }
             }
 
@@ -116,7 +140,7 @@ impl<'a> Parser<'a> {
             let mut groups = [0; 4];
 
             for (i, slot) in groups.iter_mut().enumerate() {
-                *slot = p.read_separator('.', i, |p| p.read_number(10, 3, 0x100))? as u8;
+                *slot = p.read_separator('.', i, |p| p.read_number(10, None))?;
             }
 
             Some(groups.into())
@@ -140,17 +164,17 @@ impl<'a> Parser<'a> {
                     let ipv4 = p.read_separator(':', i, |p| p.read_ipv4_addr());
 
                     if let Some(v4_addr) = ipv4 {
-                        let octets = v4_addr.octets();
-                        groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16);
-                        groups[i + 1] = ((octets[2] as u16) << 8) | (octets[3] as u16);
+                        let [one, two, three, four] = v4_addr.octets();
+                        groups[i + 0] = u16::from_be_bytes([one, two]);
+                        groups[i + 1] = u16::from_be_bytes([three, four]);
                         return (i + 2, true);
                     }
                 }
 
-                let group = p.read_separator(':', i, |p| p.read_number(16, 4, 0x10000));
+                let group = p.read_separator(':', i, |p| p.read_number(16, Some(4)));
 
                 match group {
-                    Some(g) => *slot = g as u16,
+                    Some(g) => *slot = g,
                     None => return (i, false),
                 }
             }
@@ -195,12 +219,11 @@ impl<'a> Parser<'a> {
         self.read_ipv4_addr().map(IpAddr::V4).or_else(move || self.read_ipv6_addr().map(IpAddr::V6))
     }
 
-    /// Read a : followed by a port in base 10
+    /// Read a : followed by a port in base 10.
     fn read_port(&mut self) -> Option<u16> {
         self.read_atomically(|p| {
             let _ = p.read_given_char(':')?;
-            let port = p.read_number(10, 5, 0x10000)?;
-            Some(port as u16)
+            p.read_number(10, None)
         })
     }
 

From f78a7ade61c1c218eead76854abb7d83bb6c6f75 Mon Sep 17 00:00:00 2001
From: Tamir Duberstein <tamird@google.com>
Date: Sun, 4 Oct 2020 17:07:30 +0000
Subject: [PATCH 05/19] Inline "eof" methods

---
 library/std/src/net/parser.rs | 15 ++-------------
 1 file changed, 2 insertions(+), 13 deletions(-)

diff --git a/library/std/src/net/parser.rs b/library/std/src/net/parser.rs
index da94a5735034f..3a5fd8f6f5d0e 100644
--- a/library/std/src/net/parser.rs
+++ b/library/std/src/net/parser.rs
@@ -44,10 +44,6 @@ impl<'a> Parser<'a> {
         Parser { state: input.as_bytes() }
     }
 
-    fn is_eof(&self) -> bool {
-        self.state.is_empty()
-    }
-
     /// Run a parser, and restore the pre-parse state if it fails
     fn read_atomically<T, F>(&mut self, inner: F) -> Option<T>
     where
@@ -63,19 +59,12 @@ impl<'a> Parser<'a> {
 
     /// Run a parser, but fail if the entire input wasn't consumed.
     /// Doesn't run atomically.
-    fn read_till_eof<T, F>(&mut self, inner: F) -> Option<T>
-    where
-        F: FnOnce(&mut Parser<'_>) -> Option<T>,
-    {
-        inner(self).filter(|_| self.is_eof())
-    }
-
-    /// Same as read_till_eof, but returns a Result<AddrParseError> on failure
     fn parse_with<T, F>(&mut self, inner: F) -> Result<T, AddrParseError>
     where
         F: FnOnce(&mut Parser<'_>) -> Option<T>,
     {
-        self.read_till_eof(inner).ok_or(AddrParseError(()))
+        let result = inner(self);
+        if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(()))
     }
 
     /// Read the next character from the input

From afa2a675453091773eb9dd1b19389725526224b9 Mon Sep 17 00:00:00 2001
From: "Felix S. Klock II" <pnkfelix@pnkfx.org>
Date: Mon, 15 Jun 2020 14:17:35 -0400
Subject: [PATCH 06/19] Prevent forbid from being ignored if overriden at the
 same level.

That is, this changes `#[forbid(foo)] #[allow(foo)]` from allowing foo to
forbidding foo.
---
 compiler/rustc_lint/src/levels.rs             | 47 ++++++++++++++++--
 compiler/rustc_middle/src/lint.rs             | 20 +++++++-
 ...0819-dont-override-forbid-in-same-scope.rs | 49 +++++++++++++++++++
 ...-dont-override-forbid-in-same-scope.stderr | 29 +++++++++++
 src/tools/clippy/tests/ui/attrs.rs            |  1 -
 src/tools/clippy/tests/ui/attrs.stderr        | 16 ++----
 6 files changed, 144 insertions(+), 18 deletions(-)
 create mode 100644 src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs
 create mode 100644 src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr

diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 48254dcee82fe..222333a578b7d 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -10,6 +10,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_hir::{intravisit, HirId};
 use rustc_middle::hir::map::Map;
+use rustc_middle::lint::LevelSource;
 use rustc_middle::lint::LintDiagnosticBuilder;
 use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource};
 use rustc_middle::ty::query::Providers;
@@ -95,6 +96,44 @@ impl<'s> LintLevelsBuilder<'s> {
         self.sets.list.push(LintSet::CommandLine { specs });
     }
 
+    /// Attempts to insert the `id` to `level_src` map entry. If unsuccessful
+    /// (e.g. if a forbid was already inserted on the same scope), then emits a
+    /// diagnostic with no change to `specs`.
+    fn insert_spec(
+        &mut self,
+        specs: &mut FxHashMap<LintId, LevelSource>,
+        id: LintId,
+        (level, src): LevelSource,
+    ) {
+        if let Some((old_level, old_src)) = specs.get(&id) {
+            if old_level == &Level::Forbid && level != Level::Forbid {
+                let mut diag_builder = struct_span_err!(
+                    self.sess,
+                    src.span(),
+                    E0453,
+                    "{}({}) incompatible with previous forbid in same scope",
+                    level.as_str(),
+                    src.name(),
+                );
+                match *old_src {
+                    LintSource::Default => {}
+                    LintSource::Node(_, forbid_source_span, reason) => {
+                        diag_builder.span_label(forbid_source_span, "`forbid` level set here");
+                        if let Some(rationale) = reason {
+                            diag_builder.note(&rationale.as_str());
+                        }
+                    }
+                    LintSource::CommandLine(_) => {
+                        diag_builder.note("`forbid` lint level was set on command line");
+                    }
+                }
+                diag_builder.emit();
+                return;
+            }
+        }
+        specs.insert(id, (level, src));
+    }
+
     /// Pushes a list of AST lint attributes onto this context.
     ///
     /// This function will return a `BuilderPush` object which should be passed
@@ -109,7 +148,7 @@ impl<'s> LintLevelsBuilder<'s> {
     ///   `#[allow]`
     ///
     /// Don't forget to call `pop`!
-    pub fn push(
+    pub(crate) fn push(
         &mut self,
         attrs: &[ast::Attribute],
         store: &LintStore,
@@ -221,7 +260,7 @@ impl<'s> LintLevelsBuilder<'s> {
                         let src = LintSource::Node(name, li.span(), reason);
                         for &id in ids {
                             self.check_gated_lint(id, attr.span);
-                            specs.insert(id, (level, src));
+                            self.insert_spec(&mut specs, id, (level, src));
                         }
                     }
 
@@ -235,7 +274,7 @@ impl<'s> LintLevelsBuilder<'s> {
                                     reason,
                                 );
                                 for id in ids {
-                                    specs.insert(*id, (level, src));
+                                    self.insert_spec(&mut specs, *id, (level, src));
                                 }
                             }
                             Err((Some(ids), new_lint_name)) => {
@@ -272,7 +311,7 @@ impl<'s> LintLevelsBuilder<'s> {
                                     reason,
                                 );
                                 for id in ids {
-                                    specs.insert(*id, (level, src));
+                                    self.insert_spec(&mut specs, *id, (level, src));
                                 }
                             }
                             Err((None, _)) => {
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 25e5379881e70..91e1d6e0b0b72 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -9,7 +9,7 @@ use rustc_session::lint::{builtin, Level, Lint, LintId};
 use rustc_session::{DiagnosticMessageId, Session};
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
-use rustc_span::{Span, Symbol};
+use rustc_span::{symbol, Span, Symbol, DUMMY_SP};
 
 /// How a lint level was set.
 #[derive(Clone, Copy, PartialEq, Eq, HashStable)]
@@ -25,6 +25,24 @@ pub enum LintSource {
     CommandLine(Symbol),
 }
 
+impl LintSource {
+    pub fn name(&self) -> Symbol {
+        match *self {
+            LintSource::Default => symbol::kw::Default,
+            LintSource::Node(name, _, _) => name,
+            LintSource::CommandLine(name) => name,
+        }
+    }
+
+    pub fn span(&self) -> Span {
+        match *self {
+            LintSource::Default => DUMMY_SP,
+            LintSource::Node(_, span, _) => span,
+            LintSource::CommandLine(_) => DUMMY_SP,
+        }
+    }
+}
+
 pub type LevelSource = (Level, LintSource);
 
 pub struct LintLevelSets {
diff --git a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs
new file mode 100644
index 0000000000000..8e25227b59e63
--- /dev/null
+++ b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs
@@ -0,0 +1,49 @@
+// This test is checking that you cannot override a `forbid` by adding in other
+// attributes later in the same scope. (We already ensure that you cannot
+// override it in nested scopes).
+
+// If you turn off deduplicate diagnostics (which rustc turns on by default but
+// compiletest turns off when it runs ui tests), then the errors are
+// (unfortunately) repeated here because the checking is done as we read in the
+// errors, and curretly that happens two or three different times, depending on
+// compiler flags.
+//
+// I decided avoiding the redundant output was not worth the time in engineering
+// effort for bug like this, which 1. end users are unlikely to run into in the
+// first place, and 2. they won't see the redundant output anyway.
+
+// compile-flags: -Z deduplicate-diagnostics=yes
+
+fn forbid_first(num: i32) -> i32 {
+    #![forbid(unused)]
+    #![deny(unused)]
+    //~^ ERROR: deny(unused) incompatible with previous forbid in same scope [E0453]
+    #![warn(unused)]
+    //~^ ERROR: warn(unused) incompatible with previous forbid in same scope [E0453]
+    #![allow(unused)]
+    //~^ ERROR: allow(unused) incompatible with previous forbid in same scope [E0453]
+
+    num * num
+}
+
+fn forbid_last(num: i32) -> i32 {
+    #![deny(unused)]
+    #![warn(unused)]
+    #![allow(unused)]
+    #![forbid(unused)]
+
+    num * num
+}
+
+fn forbid_multiple(num: i32) -> i32 {
+    #![forbid(unused)]
+    #![forbid(unused)]
+
+    num * num
+}
+
+fn main() {
+    forbid_first(10);
+    forbid_last(10);
+    forbid_multiple(10);
+}
diff --git a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr
new file mode 100644
index 0000000000000..3951c511bf432
--- /dev/null
+++ b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr
@@ -0,0 +1,29 @@
+error[E0453]: deny(unused) incompatible with previous forbid in same scope
+  --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:19:13
+   |
+LL |     #![forbid(unused)]
+   |               ------ `forbid` level set here
+LL |     #![deny(unused)]
+   |             ^^^^^^
+
+error[E0453]: warn(unused) incompatible with previous forbid in same scope
+  --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:21:13
+   |
+LL |     #![forbid(unused)]
+   |               ------ `forbid` level set here
+...
+LL |     #![warn(unused)]
+   |             ^^^^^^
+
+error[E0453]: allow(unused) incompatible with previous forbid in same scope
+  --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:23:14
+   |
+LL |     #![forbid(unused)]
+   |               ------ `forbid` level set here
+...
+LL |     #![allow(unused)]
+   |              ^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0453`.
diff --git a/src/tools/clippy/tests/ui/attrs.rs b/src/tools/clippy/tests/ui/attrs.rs
index 908d063729f45..32685038067d6 100644
--- a/src/tools/clippy/tests/ui/attrs.rs
+++ b/src/tools/clippy/tests/ui/attrs.rs
@@ -3,7 +3,6 @@
 // Test that the whole restriction group is not enabled
 #![warn(clippy::restriction)]
 #![deny(clippy::restriction)]
-#![forbid(clippy::restriction)]
 #![allow(clippy::missing_docs_in_private_items, clippy::panic, clippy::unreachable)]
 
 #[inline(always)]
diff --git a/src/tools/clippy/tests/ui/attrs.stderr b/src/tools/clippy/tests/ui/attrs.stderr
index ef4b89eaa6dee..4324984dd60eb 100644
--- a/src/tools/clippy/tests/ui/attrs.stderr
+++ b/src/tools/clippy/tests/ui/attrs.stderr
@@ -1,5 +1,5 @@
 error: you have declared `#[inline(always)]` on `test_attr_lint`. This is usually a bad idea
-  --> $DIR/attrs.rs:9:1
+  --> $DIR/attrs.rs:8:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | #[inline(always)]
    = note: `-D clippy::inline-always` implied by `-D warnings`
 
 error: the since field must contain a semver-compliant version
-  --> $DIR/attrs.rs:29:14
+  --> $DIR/attrs.rs:28:14
    |
 LL | #[deprecated(since = "forever")]
    |              ^^^^^^^^^^^^^^^^^
@@ -15,7 +15,7 @@ LL | #[deprecated(since = "forever")]
    = note: `-D clippy::deprecated-semver` implied by `-D warnings`
 
 error: the since field must contain a semver-compliant version
-  --> $DIR/attrs.rs:32:14
+  --> $DIR/attrs.rs:31:14
    |
 LL | #[deprecated(since = "1")]
    |              ^^^^^^^^^^^
@@ -37,13 +37,5 @@ LL | #![deny(clippy::restriction)]
    |
    = help: try enabling only the lints you really need
 
-error: restriction lints are not meant to be all enabled
-  --> $DIR/attrs.rs:6:11
-   |
-LL | #![forbid(clippy::restriction)]
-   |           ^^^^^^^^^^^^^^^^^^^
-   |
-   = help: try enabling only the lints you really need
-
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 

From 5ab19676ed25ce52769b06a2fc7319b93d6c64dd Mon Sep 17 00:00:00 2001
From: Robin Schoonover <robin@cornhooves.org>
Date: Wed, 16 Sep 2020 19:41:22 -0600
Subject: [PATCH 07/19] Remove extra indirection in LitKind::ByteStr

---
 compiler/rustc_ast/src/ast.rs                    | 2 +-
 compiler/rustc_ast/src/util/literal.rs           | 5 ++---
 compiler/rustc_builtin_macros/src/source_util.rs | 4 +---
 compiler/rustc_mir_build/src/thir/constant.rs    | 2 +-
 4 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 95abf55291506..492d5788fc04f 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1606,7 +1606,7 @@ pub enum LitKind {
     /// A string literal (`"foo"`).
     Str(Symbol, StrStyle),
     /// A byte string (`b"foo"`).
-    ByteStr(Lrc<Vec<u8>>),
+    ByteStr(Lrc<[u8]>),
     /// A byte char (`b'f'`).
     Byte(u8),
     /// A character literal (`'a'`).
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index 597e5b437fcb1..f6f1ad0a9c3f2 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -4,7 +4,6 @@ use crate::ast::{self, Lit, LitKind};
 use crate::token::{self, Token};
 use crate::tokenstream::TokenTree;
 
-use rustc_data_structures::sync::Lrc;
 use rustc_lexer::unescape::{unescape_byte, unescape_char};
 use rustc_lexer::unescape::{unescape_byte_literal, unescape_literal, Mode};
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -108,7 +107,7 @@ impl LitKind {
                 });
                 error?;
                 buf.shrink_to_fit();
-                LitKind::ByteStr(Lrc::new(buf))
+                LitKind::ByteStr(buf.into())
             }
             token::ByteStrRaw(_) => {
                 let s = symbol.as_str();
@@ -128,7 +127,7 @@ impl LitKind {
                     symbol.to_string().into_bytes()
                 };
 
-                LitKind::ByteStr(Lrc::new(bytes))
+                LitKind::ByteStr(bytes.into())
             }
             token::Err => LitKind::Err(symbol),
         })
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index 70753208af310..f76bbd8381940 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -13,8 +13,6 @@ use rustc_span::{self, Pos, Span};
 use smallvec::SmallVec;
 use std::rc::Rc;
 
-use rustc_data_structures::sync::Lrc;
-
 // These macros all relate to the file system; they either return
 // the column/row/filename of the expression, or they include
 // a given file into the current one.
@@ -216,7 +214,7 @@ pub fn expand_include_bytes(
         }
     };
     match cx.source_map().load_binary_file(&file) {
-        Ok(bytes) => base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Lrc::new(bytes)))),
+        Ok(bytes) => base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(bytes.into()))),
         Err(e) => {
             cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e));
             DummyResult::any(sp)
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index a7bb2864dafa0..b71ff6e755749 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -31,7 +31,7 @@ crate fn lit_to_const<'tcx>(
         (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
             if matches!(inner_ty.kind(), ty::Slice(_)) =>
         {
-            let allocation = Allocation::from_byte_aligned_bytes(data as &Vec<u8>);
+            let allocation = Allocation::from_byte_aligned_bytes(data as &[u8]);
             let allocation = tcx.intern_const_alloc(allocation);
             ConstValue::Slice { data: allocation, start: 0, end: data.len() }
         }

From 62f7712a1fd500604f76442f627ea35ce7217177 Mon Sep 17 00:00:00 2001
From: Robin Schoonover <robin@cornhooves.org>
Date: Sun, 4 Oct 2020 15:53:37 -0600
Subject: [PATCH 08/19] Change clippy's Constant back to refcount clone byte
 strings

---
 src/tools/clippy/clippy_lints/src/consts.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tools/clippy/clippy_lints/src/consts.rs b/src/tools/clippy/clippy_lints/src/consts.rs
index 0000d39263ed3..062c9bd2d9e6c 100644
--- a/src/tools/clippy/clippy_lints/src/consts.rs
+++ b/src/tools/clippy/clippy_lints/src/consts.rs
@@ -155,7 +155,7 @@ pub fn lit_to_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
     match *lit {
         LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
         LitKind::Byte(b) => Constant::Int(u128::from(b)),
-        LitKind::ByteStr(ref s) => Constant::Binary(Lrc::from(s.as_slice())),
+        LitKind::ByteStr(ref s) => Constant::Binary(Lrc::clone(s)),
         LitKind::Char(c) => Constant::Char(c),
         LitKind::Int(n, _) => Constant::Int(n),
         LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {

From b205436ff66db720cb4b0c503d14ff0a571b14c7 Mon Sep 17 00:00:00 2001
From: Camelid <37223377+camelid@users.noreply.github.com>
Date: Sun, 4 Oct 2020 16:57:32 -0700
Subject: [PATCH 09/19] Allow anyone to set regression labels

---
 triagebot.toml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/triagebot.toml b/triagebot.toml
index bcdc40017b526..8b7b536bcbf3c 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -3,6 +3,7 @@ allow-unauthenticated = [
     "C-*", "A-*", "E-*", "NLL-*", "O-*", "S-*", "T-*", "WG-*", "F-*",
     "D-*",
     "requires-nightly",
+    "regression-*",
     # I-* without I-nominated
     "I-*", "!I-nominated",
     "AsyncAwait-OnDeck",

From afe83d4c1ca70149b463ac7548cf5d204d3d5844 Mon Sep 17 00:00:00 2001
From: Thom Chiovoloni <chiovolonit@gmail.com>
Date: Sun, 4 Oct 2020 18:35:16 -0700
Subject: [PATCH 10/19] Rename bootstrap/defaults/{config.toml.PROFILE =>
 config.PROFILE.toml}

---
 src/bootstrap/config.rs                                       | 2 +-
 .../defaults/{config.toml.codegen => config.codegen.toml}     | 0
 .../defaults/{config.toml.compiler => config.compiler.toml}   | 0
 .../defaults/{config.toml.library => config.library.toml}     | 0
 src/bootstrap/defaults/{config.toml.user => config.user.toml} | 0
 src/bootstrap/setup.rs                                        | 4 ++--
 6 files changed, 3 insertions(+), 3 deletions(-)
 rename src/bootstrap/defaults/{config.toml.codegen => config.codegen.toml} (100%)
 rename src/bootstrap/defaults/{config.toml.compiler => config.compiler.toml} (100%)
 rename src/bootstrap/defaults/{config.toml.library => config.library.toml} (100%)
 rename src/bootstrap/defaults/{config.toml.user => config.user.toml} (100%)

diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 5314398ce9a22..6265bbaf5c22c 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -574,7 +574,7 @@ impl Config {
             include_path.push("src");
             include_path.push("bootstrap");
             include_path.push("defaults");
-            include_path.push(format!("config.toml.{}", include));
+            include_path.push(format!("config.{}.toml", include));
             let included_toml = get_toml(&include_path);
             toml.merge(included_toml);
         }
diff --git a/src/bootstrap/defaults/config.toml.codegen b/src/bootstrap/defaults/config.codegen.toml
similarity index 100%
rename from src/bootstrap/defaults/config.toml.codegen
rename to src/bootstrap/defaults/config.codegen.toml
diff --git a/src/bootstrap/defaults/config.toml.compiler b/src/bootstrap/defaults/config.compiler.toml
similarity index 100%
rename from src/bootstrap/defaults/config.toml.compiler
rename to src/bootstrap/defaults/config.compiler.toml
diff --git a/src/bootstrap/defaults/config.toml.library b/src/bootstrap/defaults/config.library.toml
similarity index 100%
rename from src/bootstrap/defaults/config.toml.library
rename to src/bootstrap/defaults/config.library.toml
diff --git a/src/bootstrap/defaults/config.toml.user b/src/bootstrap/defaults/config.user.toml
similarity index 100%
rename from src/bootstrap/defaults/config.toml.user
rename to src/bootstrap/defaults/config.user.toml
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs
index 9d3a889aa008e..8a77641fbfefb 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/setup.rs
@@ -20,7 +20,7 @@ pub fn setup(src_path: &Path, include_name: &str) {
             file.display()
         );
         println!(
-            "note: this will use the configuration in {}/src/bootstrap/defaults/config.toml.{}",
+            "note: this will use the configuration in {}/src/bootstrap/defaults/config.{}.toml",
             src_path.display(),
             include_name
         );
@@ -36,7 +36,7 @@ pub fn setup(src_path: &Path, include_name: &str) {
     t!(fs::write(path, settings));
 
     let include_path =
-        format!("{}/src/bootstrap/defaults/config.toml.{}", src_path.display(), include_name);
+        format!("{}/src/bootstrap/defaults/config.{}.toml", src_path.display(), include_name);
     println!("`x.py` will now use the configuration at {}", include_path);
 
     let suggestions = match include_name {

From 5388eb41e940cddaf8ae4ea812c4e04a3e9d9401 Mon Sep 17 00:00:00 2001
From: Thom Chiovoloni <chiovolonit@gmail.com>
Date: Sun, 4 Oct 2020 18:39:59 -0700
Subject: [PATCH 11/19] Add changelog entry mentioning the renamed profile
 files

---
 src/bootstrap/CHANGELOG.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/bootstrap/CHANGELOG.md b/src/bootstrap/CHANGELOG.md
index d8c704f451bfc..7c12642da3551 100644
--- a/src/bootstrap/CHANGELOG.md
+++ b/src/bootstrap/CHANGELOG.md
@@ -7,6 +7,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 ## [Non-breaking changes since the last major version]
 
 - `x.py check` needs opt-in to check tests (--all-targets) [#77473](https://github.com/rust-lang/rust/pull/77473)
+- The default bootstrap profiles are now located at `bootstrap/defaults/config.$PROFILE.toml` (previously they were located at `bootstrap/defaults/config.toml.$PROFILE`) [#77558](https://github.com/rust-lang/rust/pull/77558)
+
 
 ## [Version 2] - 2020-09-25
 

From c877ff3664abea60d69b8acf8e7dce85c2ffd859 Mon Sep 17 00:00:00 2001
From: Camelid <camelidcamel@gmail.com>
Date: Sun, 4 Oct 2020 19:08:40 -0700
Subject: [PATCH 12/19] Fix rustdoc warnings about invalid Rust syntax

---
 compiler/rustc_mir/src/borrow_check/region_infer/mod.rs | 4 +++-
 compiler/rustc_mir/src/util/pretty.rs                   | 3 ++-
 compiler/rustc_trait_selection/src/opaque_types.rs      | 7 +++++--
 compiler/rustc_typeck/src/check/expr.rs                 | 4 ++--
 compiler/rustc_typeck/src/check/pat.rs                  | 4 ++--
 5 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
index 3dc082a4413b3..053ca7c23d26e 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
@@ -1225,7 +1225,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// it. However, it works pretty well in practice. In particular,
     /// this is needed to deal with projection outlives bounds like
     ///
-    ///     <T as Foo<'0>>::Item: '1
+    /// ```ignore (MIR syntax)
+    /// <T as Foo<'0>>::Item: '1
+    /// ```
     ///
     /// In particular, this routine winds up being important when
     /// there are bounds like `where <T as Foo<'a>>::Item: 'b` in the
diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs
index 49c644a20bf82..67bc886b9380a 100644
--- a/compiler/rustc_mir/src/util/pretty.rs
+++ b/compiler/rustc_mir/src/util/pretty.rs
@@ -659,7 +659,8 @@ pub fn write_allocations<'tcx>(
 /// Dumps the size and metadata and content of an allocation to the given writer.
 /// The expectation is that the caller first prints other relevant metadata, so the exact
 /// format of this function is (*without* leading or trailing newline):
-/// ```
+///
+/// ```text
 /// size: {}, align: {}) {
 ///     <bytes>
 /// }
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 28697ec4e3b9f..4f351ab176d41 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -38,13 +38,16 @@ pub struct OpaqueTypeDecl<'tcx> {
     /// then `substs` would be `['a, T]`.
     pub substs: SubstsRef<'tcx>,
 
-    /// The span of this particular definition of the opaque type.  So
+    /// The span of this particular definition of the opaque type. So
     /// for example:
     ///
     /// ```
     /// type Foo = impl Baz;
     /// fn bar() -> Foo {
-    ///             ^^^ This is the span we are looking for!
+    /// //          ^^^ This is the span we are looking for!
+    /// // ...
+    /// # unimplemented!()
+    /// }
     /// ```
     ///
     /// In cases where the fn returns `(impl Trait, impl Trait)` or
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index af800eab67a5e..179e383be2e2b 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1275,7 +1275,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     /// Report an error for a struct field expression when there are fields which aren't provided.
     ///
-    /// ```ignore (diagnostic)
+    /// ```text
     /// error: missing field `you_can_use_this_field` in initializer of `foo::Foo`
     ///  --> src/main.rs:8:5
     ///   |
@@ -1327,7 +1327,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     /// Report an error for a struct field expression when there are no visible fields.
     ///
-    /// ```ignore (diagnostic)
+    /// ```text
     /// error: cannot construct `Foo` with struct literal syntax due to inaccessible fields
     ///  --> src/main.rs:8:5
     ///   |
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 3e431a9c00090..53bc2069b76ce 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -1381,7 +1381,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Returns a diagnostic reporting a struct pattern which is missing an `..` due to
     /// inaccessible fields.
     ///
-    /// ```ignore (diagnostic)
+    /// ```text
     /// error: pattern requires `..` due to inaccessible fields
     ///   --> src/main.rs:10:9
     ///    |
@@ -1431,7 +1431,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     /// Returns a diagnostic reporting a struct pattern which does not mention some fields.
     ///
-    /// ```ignore (diagnostic)
+    /// ```text
     /// error[E0027]: pattern does not mention field `you_cant_use_this_field`
     ///   --> src/main.rs:15:9
     ///    |

From b1ce6190ae4cb412c21207932924889e7201d4df Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Sat, 26 Sep 2020 15:31:30 +0200
Subject: [PATCH 13/19] Add missing examples for MaybeUninit

---
 library/core/src/mem/maybe_uninit.rs | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index e629d28eae163..862c452a43480 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -246,6 +246,14 @@ impl<T> MaybeUninit<T> {
     /// Note that dropping a `MaybeUninit<T>` will never call `T`'s drop code.
     /// It is your responsibility to make sure `T` gets dropped if it got initialized.
     ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let v: MaybeUninit<Vec<u8>> = MaybeUninit::new(vec![42]);
+    /// ```
+    ///
     /// [`assume_init`]: MaybeUninit::assume_init
     #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[rustc_const_stable(feature = "const_maybe_uninit", since = "1.36.0")]
@@ -259,9 +267,15 @@ impl<T> MaybeUninit<T> {
     /// Note that dropping a `MaybeUninit<T>` will never call `T`'s drop code.
     /// It is your responsibility to make sure `T` gets dropped if it got initialized.
     ///
-    /// See the [type-level documentation][type] for some examples.
+    /// See the [type-level documentation][MaybeUninit] for some examples.
     ///
-    /// [type]: union.MaybeUninit.html
+    /// # Example
+    ///
+    /// ```
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let v: MaybeUninit<String> = MaybeUninit::uninit();
+    /// ```
     #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[rustc_const_stable(feature = "const_maybe_uninit", since = "1.36.0")]
     #[inline(always)]

From 554145609484d111f6ca3acaca644ae881c20a10 Mon Sep 17 00:00:00 2001
From: Ivan Tham <pickfire@riseup.net>
Date: Mon, 5 Oct 2020 22:47:52 +0800
Subject: [PATCH 14/19] Hint doc use convert::identity relative link

---
 library/core/src/hint.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 4eb47dd1378c5..5d8137f91ee06 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -98,8 +98,6 @@ pub fn spin_loop() {
 /// An identity function that *__hints__* to the compiler to be maximally pessimistic about what
 /// `black_box` could do.
 ///
-/// [`std::convert::identity`]: https://doc.rust-lang.org/core/convert/fn.identity.html
-///
 /// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can
 /// use `dummy` in any possible valid way that Rust code is allowed to without introducing undefined
 /// behavior in the calling code. This property makes `black_box` useful for writing code in which
@@ -108,6 +106,8 @@ pub fn spin_loop() {
 /// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The
 /// extent to which it can block optimisations may vary depending upon the platform and code-gen
 /// backend used. Programs cannot rely on `black_box` for *correctness* in any way.
+///
+/// [`std::convert::identity`]: ../convert/fn.identity.html
 #[cfg_attr(not(miri), inline)]
 #[cfg_attr(miri, inline(never))]
 #[unstable(feature = "test", issue = "50297")]

From cb881d36ae0060e1dc6815e7caefe4e8df79dc09 Mon Sep 17 00:00:00 2001
From: Ivan Tham <pickfire@riseup.net>
Date: Mon, 5 Oct 2020 23:29:43 +0800
Subject: [PATCH 15/19] hint doc use intra-doc links

Co-authored-by: Joshua Nelson <joshua@yottadb.com>
---
 library/core/src/hint.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 5d8137f91ee06..454fb34e77e49 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -107,7 +107,7 @@ pub fn spin_loop() {
 /// extent to which it can block optimisations may vary depending upon the platform and code-gen
 /// backend used. Programs cannot rely on `black_box` for *correctness* in any way.
 ///
-/// [`std::convert::identity`]: ../convert/fn.identity.html
+/// [`std::convert::identity`]: crate::convert::identity
 #[cfg_attr(not(miri), inline)]
 #[cfg_attr(miri, inline(never))]
 #[unstable(feature = "test", issue = "50297")]

From 35192ff574c3706646e2f4be16d5c22c4f8b60b1 Mon Sep 17 00:00:00 2001
From: Eric Huss <eric@huss.org>
Date: Mon, 5 Oct 2020 11:19:08 -0700
Subject: [PATCH 16/19] Fix span for unicode escape suggestion.

---
 compiler/rustc_parse/src/lexer/unescape_error_reporting.rs | 5 ++---
 src/test/ui/fmt/format-string-error-2.stderr               | 4 +---
 src/test/ui/parser/issue-23620-invalid-escapes.stderr      | 6 +++---
 3 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index 6f249f491a647..47d317f918865 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -181,10 +181,9 @@ pub(crate) fn emit_unescape_error(
 
             if suggestion_len > 0 {
                 suggestion.push('}');
-                let lo = char_span.lo();
-                let hi = lo + BytePos(suggestion_len as u32);
+                let hi = char_span.lo() + BytePos(suggestion_len as u32);
                 diag.span_suggestion(
-                    span.with_lo(lo).with_hi(hi),
+                    span.with_hi(hi),
                     "format of unicode escape sequences uses braces",
                     suggestion,
                     Applicability::MaybeIncorrect,
diff --git a/src/test/ui/fmt/format-string-error-2.stderr b/src/test/ui/fmt/format-string-error-2.stderr
index d202044a2bb97..c421fe49ef0a4 100644
--- a/src/test/ui/fmt/format-string-error-2.stderr
+++ b/src/test/ui/fmt/format-string-error-2.stderr
@@ -2,9 +2,7 @@ error: incorrect unicode escape sequence
   --> $DIR/format-string-error-2.rs:77:20
    |
 LL |     println!("\x7B}\u8 {", 1);
-   |                    ^^-
-   |                      |
-   |                      help: format of unicode escape sequences uses braces: `\u{8}`
+   |                    ^^^ help: format of unicode escape sequences uses braces: `\u{8}`
 
 error: invalid format string: expected `'}'`, found `'a'`
   --> $DIR/format-string-error-2.rs:5:5
diff --git a/src/test/ui/parser/issue-23620-invalid-escapes.stderr b/src/test/ui/parser/issue-23620-invalid-escapes.stderr
index b391ac75bf8d1..8c924ad0330e9 100644
--- a/src/test/ui/parser/issue-23620-invalid-escapes.stderr
+++ b/src/test/ui/parser/issue-23620-invalid-escapes.stderr
@@ -80,9 +80,9 @@ error: incorrect unicode escape sequence
   --> $DIR/issue-23620-invalid-escapes.rs:32:14
    |
 LL |     let _ = "\u8f";
-   |              ^^--
-   |                |
-   |                help: format of unicode escape sequences uses braces: `\u{8f}`
+   |              ^^^-
+   |              |
+   |              help: format of unicode escape sequences uses braces: `\u{8f}`
 
 error: aborting due to 13 previous errors
 

From 8d11f90a16fb374d68b4aae5486c3e12c74c63b7 Mon Sep 17 00:00:00 2001
From: Aaron Hill <aa1ronham@gmail.com>
Date: Mon, 5 Oct 2020 15:32:25 -0400
Subject: [PATCH 17/19] Record `expansion_that_defined` into crate metadata

Fixes #77523

Now that hygiene serialization is implemented, we also need to record
`expansion_that_defined` so that we properly handle a foreign
`SyntaxContext`.
---
 compiler/rustc_metadata/src/rmeta/decoder.rs  |  4 ++++
 .../src/rmeta/decoder/cstore_impl.rs          |  1 +
 compiler/rustc_metadata/src/rmeta/encoder.rs  |  4 ++++
 compiler/rustc_metadata/src/rmeta/mod.rs      |  1 +
 compiler/rustc_middle/src/query/mod.rs        |  5 +++++
 compiler/rustc_middle/src/ty/mod.rs           |  6 ++++--
 .../hygiene/auxiliary/def-site-async-await.rs |  7 +++++++
 .../ui/hygiene/auxiliary/opaque-hygiene.rs    | 21 +++++++++++++++++++
 .../issue-77523-def-site-async-await.rs       | 19 +++++++++++++++++
 9 files changed, 66 insertions(+), 2 deletions(-)
 create mode 100644 src/test/ui/hygiene/auxiliary/def-site-async-await.rs
 create mode 100644 src/test/ui/hygiene/auxiliary/opaque-hygiene.rs
 create mode 100644 src/test/ui/hygiene/issue-77523-def-site-async-await.rs

diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index c31e941b3ffc6..8b11d2c913ac2 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1011,6 +1011,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         self.root.tables.impl_trait_ref.get(self, id).map(|tr| tr.decode((self, tcx)))
     }
 
+    fn get_expn_that_defined(&self, id: DefIndex, sess: &Session) -> ExpnId {
+        self.root.tables.expn_that_defined.get(self, id).unwrap().decode((self, sess))
+    }
+
     /// Iterates over all the stability attributes in the given crate.
     fn get_lib_features(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Option<Symbol>)] {
         // FIXME: For a proc macro crate, not sure whether we should return the "host"
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 4102cf84a6775..578ce382912f0 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -238,6 +238,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     }
 
     crate_extern_paths => { cdata.source().paths().cloned().collect() }
+    expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) }
 }
 
 pub fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index f58a792ef585e..4350ac5c27a88 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -747,6 +747,7 @@ impl EncodeContext<'a, 'tcx> {
             ty::Visibility::from_hir(enum_vis, enum_id, self.tcx));
         record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
         record!(self.tables.attributes[def_id] <- &self.tcx.get_attrs(def_id)[..]);
+        record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
         record!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
             assert!(f.did.is_local());
             f.did.index
@@ -883,6 +884,7 @@ impl EncodeContext<'a, 'tcx> {
         record!(self.tables.visibility[def_id] <- field.vis);
         record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
         record!(self.tables.attributes[def_id] <- variant_data.fields()[field_index].attrs);
+        record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
         self.encode_ident_span(def_id, field.ident);
         self.encode_stability(def_id);
         self.encode_deprecation(def_id);
@@ -924,6 +926,7 @@ impl EncodeContext<'a, 'tcx> {
         record!(self.tables.kind[def_id] <- EntryKind::Struct(self.lazy(data), adt_def.repr));
         record!(self.tables.visibility[def_id] <- ctor_vis);
         record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
+        record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
         self.encode_stability(def_id);
         self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
@@ -1339,6 +1342,7 @@ impl EncodeContext<'a, 'tcx> {
             ty::Visibility::from_hir(&item.vis, item.hir_id, tcx));
         record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
         record!(self.tables.attributes[def_id] <- item.attrs);
+        record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
         // FIXME(eddyb) there should be a nicer way to do this.
         match item.kind {
             hir::ItemKind::ForeignMod(ref fm) => record!(self.tables.children[def_id] <-
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 1a127035d4ff7..9e26d02e4e16d 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -294,6 +294,7 @@ define_tables! {
     variances: Table<DefIndex, Lazy<[ty::Variance]>>,
     generics: Table<DefIndex, Lazy<ty::Generics>>,
     explicit_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
+    expn_that_defined: Table<DefIndex, Lazy<ExpnId>>,
     // FIXME(eddyb) this would ideally be `Lazy<[...]>` but `ty::Predicate`
     // doesn't handle shorthands in its own (de)serialization impls,
     // as it's an `enum` for which we want to derive (de)serialization,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index d5b99ea4d288d..fe115bbb9c334 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -191,6 +191,11 @@ rustc_queries! {
             eval_always
             desc { |tcx| "parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
         }
+
+        /// Internal helper query. Use `tcx.expansion_that_defined` instead
+        query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
+            desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) }
+        }
     }
 
     Codegen {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index b7530c077ccd1..7f77334acee75 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -3034,10 +3034,12 @@ impl<'tcx> TyCtxt<'tcx> {
                 .hygienic_eq(def_name.span.ctxt(), self.expansion_that_defined(def_parent_def_id))
     }
 
-    fn expansion_that_defined(self, scope: DefId) -> ExpnId {
+    pub fn expansion_that_defined(self, scope: DefId) -> ExpnId {
         match scope.as_local() {
+            // Parsing and expansion aren't incremental, so we don't
+            // need to go through a query for the same-crate case.
             Some(scope) => self.hir().definitions().expansion_that_defined(scope),
-            None => ExpnId::root(),
+            None => self.expn_that_defined(scope),
         }
     }
 
diff --git a/src/test/ui/hygiene/auxiliary/def-site-async-await.rs b/src/test/ui/hygiene/auxiliary/def-site-async-await.rs
new file mode 100644
index 0000000000000..f7e9b80131885
--- /dev/null
+++ b/src/test/ui/hygiene/auxiliary/def-site-async-await.rs
@@ -0,0 +1,7 @@
+// edition:2018
+
+extern crate opaque_hygiene;
+
+pub async fn serve() {
+    opaque_hygiene::make_it!();
+}
diff --git a/src/test/ui/hygiene/auxiliary/opaque-hygiene.rs b/src/test/ui/hygiene/auxiliary/opaque-hygiene.rs
new file mode 100644
index 0000000000000..7730f91bd6a03
--- /dev/null
+++ b/src/test/ui/hygiene/auxiliary/opaque-hygiene.rs
@@ -0,0 +1,21 @@
+// force-host
+// no-prefer-dynamic
+
+#![feature(proc_macro_quote)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::{TokenStream, quote};
+
+#[proc_macro]
+pub fn make_it(input: TokenStream) -> TokenStream {
+    // `quote!` applies def-site hygiene
+    quote! {
+        trait Foo {
+            fn my_fn(&self) {}
+        }
+
+        impl<T> Foo for T {}
+        "a".my_fn();
+    }
+}
diff --git a/src/test/ui/hygiene/issue-77523-def-site-async-await.rs b/src/test/ui/hygiene/issue-77523-def-site-async-await.rs
new file mode 100644
index 0000000000000..2af60ff6f53b6
--- /dev/null
+++ b/src/test/ui/hygiene/issue-77523-def-site-async-await.rs
@@ -0,0 +1,19 @@
+// build-pass
+// aux-build:opaque-hygiene.rs
+// aux-build:def-site-async-await.rs
+
+// Regression test for issue #77523
+// Tests that we don't ICE when an unusual combination
+// of def-site hygiene and cross-crate monomorphization occurs.
+
+extern crate def_site_async_await;
+
+use std::future::Future;
+
+fn mk_ctxt() -> std::task::Context<'static> {
+    panic!()
+}
+
+fn main() {
+    Box::pin(def_site_async_await::serve()).as_mut().poll(&mut mk_ctxt());
+}

From c8d25af6985c2c6be388fc198c2c7d50eb553fc4 Mon Sep 17 00:00:00 2001
From: Camelid <camelidcamel@gmail.com>
Date: Mon, 5 Oct 2020 15:07:27 -0700
Subject: [PATCH 18/19] Fixup

---
 compiler/rustc_mir/src/borrow_check/region_infer/mod.rs | 2 +-
 compiler/rustc_trait_selection/src/opaque_types.rs      | 5 +----
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
index 053ca7c23d26e..6264f521c62bf 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
@@ -1225,7 +1225,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// it. However, it works pretty well in practice. In particular,
     /// this is needed to deal with projection outlives bounds like
     ///
-    /// ```ignore (MIR syntax)
+    /// ```ignore (internal compiler representation so lifetime syntax is invalid)
     /// <T as Foo<'0>>::Item: '1
     /// ```
     ///
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 4f351ab176d41..618f3e045e712 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -41,13 +41,10 @@ pub struct OpaqueTypeDecl<'tcx> {
     /// The span of this particular definition of the opaque type. So
     /// for example:
     ///
-    /// ```
+    /// ```ignore (incomplete snippet)
     /// type Foo = impl Baz;
     /// fn bar() -> Foo {
     /// //          ^^^ This is the span we are looking for!
-    /// // ...
-    /// # unimplemented!()
-    /// }
     /// ```
     ///
     /// In cases where the fn returns `(impl Trait, impl Trait)` or

From dc5a000d794329c1cac5dc94871329fcb8b30123 Mon Sep 17 00:00:00 2001
From: Joshua Nelson <jyn514@gmail.com>
Date: Thu, 17 Sep 2020 18:05:56 -0400
Subject: [PATCH 19/19] Revamp rustdoc docs about documentation using `cfg`

- Move `cfg(doc)` out of `unstable-features`. It's not unstable.
- Remove outdated reference to `everybody_loops`.
- Improve wording in various places
- Give an example of code this allows (and does not allow)
- Link to `cfg(doc)` in `doc(cfg)` documentation. Since one is stable
and the other is not, don't combine them.
- Cleanup wording for `doc(cfg)`
- Incorporate changes from #76849
- Mention that `doc(cfg)` is also for features
---
 src/doc/rustdoc/src/advanced-features.md | 38 ++++++++++++++++++++++--
 src/doc/rustdoc/src/unstable-features.md | 33 +++++++++-----------
 2 files changed, 50 insertions(+), 21 deletions(-)

diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md
index c9a0dff5ab303..cad5648be48c9 100644
--- a/src/doc/rustdoc/src/advanced-features.md
+++ b/src/doc/rustdoc/src/advanced-features.md
@@ -2,7 +2,7 @@
 
 The features listed on this page fall outside the rest of the main categories.
 
-## `#[cfg(doc)]`: Documenting platform-/feature-specific information
+## `#[cfg(doc)]`: Documenting platform-specific or feature-specific information
 
 For conditional compilation, Rustdoc treats your crate the same way the compiler does. Only things
 from the host target are available (or from the given `--target` if present), and everything else is
@@ -17,7 +17,7 @@ with other `#[cfg]` filters on it, you can write something like `#[cfg(any(windo
 This will preserve the item either when built normally on Windows, or when being documented
 anywhere.
 
-Please note that this feature is not passed to doctests.
+Please note that this `cfg` is not passed to doctests.
 
 Example:
 
@@ -33,6 +33,40 @@ pub struct UnixToken;
 Here, the respective tokens can only be used by dependent crates on their respective platforms, but
 they will both appear in documentation.
 
+### Interactions between platform-specific docs
+
+Rustdoc does not have a magic way to compile documentation 'as-if' you'd run it once for each
+platform (such a magic wand has been called the ['holy grail of rustdoc'][#1998]). Instead,
+it sees *all* of your code at once, the same way the Rust compiler would if you passed it
+`--cfg doc`. However, Rustdoc has a trick up its sleeve to handle platform-specific code if it
+*does* receive it.
+
+To document your crate, Rustdoc only needs to know the public signature of your functions.
+In particular, it doesn't have to know how any of your functions are implemented, so it ignores
+all type errors and name resolution errors with function bodies. Note that this does *not*
+work for anything outside a function body: since Rustdoc documents your types, it has to
+know what those types are! For example, this code will work regardless of the platform:
+
+<!-- `ignore` because doc-tests are run with `rustc`, not `rustdoc` -->
+```ignore
+pub fn f() {
+    use std::os::windows::ffi::OsStrExt;
+}
+```
+
+but this will not, because the unknown type is part of the function signature:
+
+```ignore
+pub fn f() -> std::os::windows::ffi::EncodeWide<'static> {
+    unimplemented!()
+}
+```
+
+For a more realistic example of code this allows, see [the rustdoc test suite][realistic-async].
+
+[#1998]: https://github.com/rust-lang/rust/issues/1998
+[realistic-async]: https://github.com/rust-lang/rust/blob/b146000e910ccd60bdcde89363cb6aa14ecc0d95/src/test/rustdoc-ui/error-in-impl-trait/realistic-async.rs
+
 ## Add aliases for an item in documentation search
 
 This feature allows you to add alias(es) to an item when using the `rustdoc` search through the
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index e4d8818b56cad..16157a4b080f1 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -43,28 +43,16 @@ plain text.
 These features operate by extending the `#[doc]` attribute, and thus can be caught by the compiler
 and enabled with a `#![feature(...)]` attribute in your crate.
 
-### Documenting platform-/feature-specific information
+### `#[doc(cfg)]`: Recording what platforms or features are required for code to be present
 
-Because of the way Rustdoc documents a crate, the documentation it creates is specific to the target
-rustc compiles for. Anything that's specific to any other target is dropped via `#[cfg]` attribute
-processing early in the compilation process. However, Rustdoc has a trick up its sleeve to handle
-platform-specific code if it *does* receive it.
+You can use `#[doc(cfg(...))]` to tell Rustdoc exactly which platform items appear on.
+This has two effects:
 
-Because Rustdoc doesn't need to fully compile a crate to binary, it replaces function bodies with
-`loop {}` to prevent having to process more than necessary. This means that any code within a
-function that requires platform-specific pieces is ignored. Combined with a special attribute,
-`#[doc(cfg(...))]`, you can tell Rustdoc exactly which platform something is supposed to run on,
-ensuring that doctests are only run on the appropriate platforms.
-
-The `#[doc(cfg(...))]` attribute has another effect: When Rustdoc renders documentation for that
-item, it will be accompanied by a banner explaining that the item is only available on certain
-platforms.
-
-For Rustdoc to document an item, it needs to see it, regardless of what platform it's currently
-running on. To aid this, Rustdoc sets the flag `#[cfg(doc)]` when running on your crate.
-Combining this with the target platform of a given item allows it to appear when building your crate
-normally on that platform, as well as when building documentation anywhere.
+1. doctests will only run on the appropriate platforms, and
+2. When Rustdoc renders documentation for that item, it will be accompanied by a banner explaining
+   that the item is only available on certain platforms.
 
+`#[doc(cfg)]` is intended to be used alongside [`#[cfg(doc)]`][cfg-doc].
 For example, `#[cfg(any(windows, doc))]` will preserve the item either on Windows or during the
 documentation process. Then, adding a new attribute `#[doc(cfg(windows))]` will tell Rustdoc that
 the item is supposed to be used on Windows. For example:
@@ -81,6 +69,12 @@ pub struct WindowsToken;
 #[cfg(any(unix, doc))]
 #[doc(cfg(unix))]
 pub struct UnixToken;
+
+/// Token struct that is only available with the `serde` feature
+#[cfg(feature = "serde")]
+#[doc(cfg(feature = "serde"))]
+#[derive(serde::Deserialize)]
+pub struct SerdeToken;
 ```
 
 In this sample, the tokens will only appear on their respective platforms, but they will both appear
@@ -90,6 +84,7 @@ in documentation.
 `#![feature(doc_cfg)]` feature gate. For more information, see [its chapter in the Unstable
 Book][unstable-doc-cfg] and [its tracking issue][issue-doc-cfg].
 
+[cfg-doc]: ./advanced-features.md
 [unstable-doc-cfg]: ../unstable-book/language-features/doc-cfg.html
 [issue-doc-cfg]: https://github.com/rust-lang/rust/issues/43781