about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-10-04 04:33:28 +0000
committerbors <bors@rust-lang.org>2020-10-04 04:33:28 +0000
commit2251766944f355a039e67aeb13ab630b2d46bf9b (patch)
tree255a2666dc4671287f122208c30df66693e17855
parent4cf3dc19a1e59ffdebe3d8ca106e5b7f2d6d212e (diff)
parentf5db16639713a9a3e6730a59c5a03007557df057 (diff)
downloadrust-2251766944f355a039e67aeb13ab630b2d46bf9b.tar.gz
rust-2251766944f355a039e67aeb13ab630b2d46bf9b.zip
Auto merge of #77517 - JohnTitor:rollup-msbd49e, r=JohnTitor
Rollup of 11 pull requests

Successful merges:

 - #75143 (Use `tracing` spans to trace the entire MIR interp stack)
 - #75699 (Uplift drop-bounds lint from clippy)
 - #76768 (Test and reject out-of-bounds shuffle vectors)
 - #77190 (updated p! macro to accept literals)
 - #77388 (Add some regression tests)
 - #77419 (Create E0777 error code for invalid argument in derive)
 - #77447 (BTreeMap: document DrainFilterInner better)
 - #77468 (Fix test name)
 - #77469 (Improve rustdoc error for failed intra-doc link resolution)
 - #77473 (Make --all-targets in x.py check opt-in)
 - #77508 (Fix capitalization in blog post name)

Failed merges:

r? `@ghost`
-rw-r--r--Cargo.lock15
-rw-r--r--RELEASES.md2
-rw-r--r--compiler/rustc_driver/Cargo.toml1
-rw-r--r--compiler/rustc_driver/src/lib.rs20
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs1
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0777.md19
-rw-r--r--compiler/rustc_expand/src/expand.rs4
-rw-r--r--compiler/rustc_expand/src/proc_macro.rs22
-rw-r--r--compiler/rustc_lint/src/lib.rs3
-rw-r--r--compiler/rustc_lint/src/traits.rs79
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs185
-rw-r--r--compiler/rustc_mir/Cargo.toml1
-rw-r--r--compiler/rustc_mir/src/interpret/eval_context.rs78
-rw-r--r--library/alloc/src/collections/btree/map.rs8
-rw-r--r--library/core/src/mem/mod.rs1
-rw-r--r--src/bootstrap/CHANGELOG.md2
-rw-r--r--src/bootstrap/builder.rs2
-rw-r--r--src/bootstrap/check.rs69
-rw-r--r--src/bootstrap/flags.rs10
-rw-r--r--src/ci/docker/host-x86_64/mingw-check/Dockerfile2
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs15
-rw-r--r--src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr2
-rw-r--r--src/test/rustdoc-ui/intra-link-errors.rs10
-rw-r--r--src/test/rustdoc-ui/intra-link-errors.stderr10
-rw-r--r--src/test/rustdoc-ui/intra-link-span-ice-55723.stderr2
-rw-r--r--src/test/rustdoc-ui/intra-links-warning-crlf.stderr8
-rw-r--r--src/test/rustdoc-ui/intra-links-warning.stderr36
-rw-r--r--src/test/rustdoc-ui/lint-group.stderr2
-rw-r--r--src/test/ui/const-generics/issues/issue-75299.rs11
-rw-r--r--src/test/ui/drop-bounds/drop-bounds-impl-drop.rs14
-rw-r--r--src/test/ui/drop-bounds/drop-bounds.rs19
-rw-r--r--src/test/ui/drop-bounds/drop-bounds.stderr50
-rw-r--r--src/test/ui/error-codes/E0777.rs7
-rw-r--r--src/test/ui/error-codes/E0777.stderr21
-rw-r--r--src/test/ui/issues/issue-68951.rs9
-rw-r--r--src/test/ui/mir/issue-77359-simplify-arm-identity.rs (renamed from src/test/ui/mir/issue-77359-simplify-arm-identity-.rs)0
-rw-r--r--src/test/ui/pattern/issue-66501.rs12
-rw-r--r--src/test/ui/pattern/issue-72565.rs8
-rw-r--r--src/test/ui/pattern/issue-72565.stderr8
-rw-r--r--src/test/ui/simd/shuffle-not-out-of-bounds.rs191
-rw-r--r--src/test/ui/simd/shuffle-not-out-of-bounds.stderr76
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-74244.rs20
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-74244.stderr9
-rw-r--r--src/tools/clippy/clippy_lints/src/deprecated_lints.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/drop_bounds.rs73
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/paths.rs1
-rw-r--r--src/tools/clippy/src/lintlist/mod.rs7
-rw-r--r--src/tools/clippy/tests/ui/deprecated.rs1
-rw-r--r--src/tools/clippy/tests/ui/deprecated.stderr8
-rw-r--r--src/tools/clippy/tests/ui/drop_bounds.rs8
-rw-r--r--src/tools/clippy/tests/ui/drop_bounds.stderr16
-rw-r--r--src/tools/tidy/src/deps.rs1
53 files changed, 866 insertions, 331 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 28bd57ef673..fb7d2a4ac2f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1727,15 +1727,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "log_settings"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19af41f0565d7c19b2058153ad0b42d4d5ce89ec4dbf06ed6741114a8b63e7cd"
-dependencies = [
- "lazy_static",
-]
-
-[[package]]
 name = "lsp-codec"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3523,6 +3514,7 @@ dependencies = [
  "rustc_target",
  "tracing",
  "tracing-subscriber",
+ "tracing-tree",
  "winapi 0.3.9",
 ]
 
@@ -3810,7 +3802,6 @@ version = "0.0.0"
 dependencies = [
  "either",
  "itertools 0.9.0",
- "log_settings",
  "polonius-engine",
  "regex",
  "rustc_apfloat",
@@ -5105,9 +5096,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-tree"
-version = "0.1.5"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1a3dc4774db3a6b2d66a4f8d8de670e874ec3ed55615860c994927419b32c5f"
+checksum = "43aac8afb493b08e1e1904956f7407c1e671b9c83b26a17e1bd83d6a3520e350"
 dependencies = [
  "ansi_term 0.12.1",
  "atty",
diff --git a/RELEASES.md b/RELEASES.md
index 62d30842b23..ce11a74b71f 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -90,7 +90,7 @@ Compatibility Notes
 
 Internal Only
 --------
-- [Improved default settings for bootstrapping in `x.py`.][73964] You can read details about this change in the ["Changes To `x.py` Defaults"](https://blog.rust-lang.org/inside-rust/2020/08/30/changes-to-x-py-defaults.html) post on the Inside Rust blog.
+- [Improved default settings for bootstrapping in `x.py`.][73964] You can read details about this change in the ["Changes to `x.py` defaults"](https://blog.rust-lang.org/inside-rust/2020/08/30/changes-to-x-py-defaults.html) post on the Inside Rust blog.
 
 [1.47.0-cfg]: https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard
 [75048]: https://github.com/rust-lang/rust/pull/75048/
diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml
index adfce1008e1..f610e88b7fc 100644
--- a/compiler/rustc_driver/Cargo.toml
+++ b/compiler/rustc_driver/Cargo.toml
@@ -11,6 +11,7 @@ crate-type = ["dylib"]
 libc = "0.2"
 tracing = { version = "0.1.18" }
 tracing-subscriber = { version = "0.2.10", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
+tracing-tree = "0.1.6"
 rustc_middle = { path = "../rustc_middle" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 544efc124e1..3f50c68e3eb 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -1251,11 +1251,21 @@ pub fn init_env_logger(env: &str) {
         Ok(s) if s.is_empty() => return,
         Ok(_) => {}
     }
-    let builder = tracing_subscriber::FmtSubscriber::builder();
-
-    let builder = builder.with_env_filter(tracing_subscriber::EnvFilter::from_env(env));
-
-    builder.init()
+    let filter = tracing_subscriber::EnvFilter::from_env(env);
+    let layer = tracing_tree::HierarchicalLayer::default()
+        .with_indent_lines(true)
+        .with_ansi(true)
+        .with_targets(true)
+        .with_thread_ids(true)
+        .with_thread_names(true)
+        .with_wraparound(10)
+        .with_verbose_exit(true)
+        .with_verbose_entry(true)
+        .with_indent_amount(2);
+
+    use tracing_subscriber::layer::SubscriberExt;
+    let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
+    tracing::subscriber::set_global_default(subscriber).unwrap();
 }
 
 pub fn main() -> ! {
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 81f65ac8690..981b5bb8ba7 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -459,6 +459,7 @@ E0773: include_str!("./error_codes/E0773.md"),
 E0774: include_str!("./error_codes/E0774.md"),
 E0775: include_str!("./error_codes/E0775.md"),
 E0776: include_str!("./error_codes/E0776.md"),
+E0777: include_str!("./error_codes/E0777.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
diff --git a/compiler/rustc_error_codes/src/error_codes/E0777.md b/compiler/rustc_error_codes/src/error_codes/E0777.md
new file mode 100644
index 00000000000..8c5c6e28b65
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0777.md
@@ -0,0 +1,19 @@
+A literal value was used inside `#[derive]`.
+
+Erroneous code example:
+
+```compile_fail,E0777
+#[derive("Clone")] // error!
+struct Foo;
+```
+
+Only paths to traits are allowed as argument inside `#[derive]`. You can find
+more information about the `#[derive]` attribute in the [Rust Book].
+
+
+```
+#[derive(Clone)] // ok!
+struct Foo;
+```
+
+[Rust Book]: https://doc.rust-lang.org/book/appendix-03-derivable-traits.html
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index e5cfb866938..c6287693dc9 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -18,7 +18,7 @@ use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
 use rustc_data_structures::map_in_place::MapInPlace;
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_errors::{Applicability, PResult};
+use rustc_errors::{struct_span_err, Applicability, PResult};
 use rustc_feature::Features;
 use rustc_parse::parser::Parser;
 use rustc_parse::validate_attr;
@@ -542,7 +542,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     fn error_derive_forbidden_on_non_adt(&self, derives: &[Path], item: &Annotatable) {
         let attr = self.cx.sess.find_by_name(item.attrs(), sym::derive);
         let span = attr.map_or(item.span(), |attr| attr.span);
-        let mut err = rustc_errors::struct_span_err!(
+        let mut err = struct_span_err!(
             self.cx.sess,
             span,
             E0774,
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 94b3fcf2850..4c95f19b96d 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -5,7 +5,8 @@ use rustc_ast::token;
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::{self as ast, *};
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{Applicability, ErrorReported};
+use rustc_errors::{struct_span_err, Applicability, ErrorReported};
+use rustc_lexer::is_ident;
 use rustc_parse::nt_to_tokenstream;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, DUMMY_SP};
@@ -182,9 +183,22 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>)
             .filter_map(|nmi| match nmi {
                 NestedMetaItem::Literal(lit) => {
                     error_reported_filter_map = true;
-                    cx.struct_span_err(lit.span, "expected path to a trait, found literal")
-                        .help("for example, write `#[derive(Debug)]` for `Debug`")
-                        .emit();
+                    let mut err = struct_span_err!(
+                        cx.sess,
+                        lit.span,
+                        E0777,
+                        "expected path to a trait, found literal",
+                    );
+                    let token = lit.token.to_string();
+                    if token.starts_with('"')
+                        && token.len() > 2
+                        && is_ident(&token[1..token.len() - 1])
+                    {
+                        err.help(&format!("try using `#[derive({})]`", &token[1..token.len() - 1]));
+                    } else {
+                        err.help("for example, write `#[derive(Debug)]` for `Debug`");
+                    }
+                    err.emit();
                     None
                 }
                 NestedMetaItem::MetaItem(mi) => Some(mi),
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 33caedfc198..49e80f9d8a5 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -53,6 +53,7 @@ mod non_ascii_idents;
 mod nonstandard_style;
 mod passes;
 mod redundant_semicolon;
+mod traits;
 mod types;
 mod unused;
 
@@ -75,6 +76,7 @@ use internal::*;
 use non_ascii_idents::*;
 use nonstandard_style::*;
 use redundant_semicolon::*;
+use traits::*;
 use types::*;
 use unused::*;
 
@@ -157,6 +159,7 @@ macro_rules! late_lint_passes {
                 MissingDebugImplementations: MissingDebugImplementations::default(),
                 ArrayIntoIter: ArrayIntoIter,
                 ClashingExternDeclarations: ClashingExternDeclarations::new(),
+                DropTraitConstraints: DropTraitConstraints,
             ]
         );
     };
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
new file mode 100644
index 00000000000..d4f79036e5a
--- /dev/null
+++ b/compiler/rustc_lint/src/traits.rs
@@ -0,0 +1,79 @@
+use crate::LateContext;
+use crate::LateLintPass;
+use crate::LintContext;
+use rustc_hir as hir;
+use rustc_span::symbol::sym;
+
+declare_lint! {
+    /// The `drop_bounds` lint checks for generics with `std::ops::Drop` as
+    /// bounds.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// fn foo<T: Drop>() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// `Drop` bounds do not really accomplish anything. A type may have
+    /// compiler-generated drop glue without implementing the `Drop` trait
+    /// itself. The `Drop` trait also only has one method, `Drop::drop`, and
+    /// that function is by fiat not callable in user code. So there is really
+    /// no use case for using `Drop` in trait bounds.
+    ///
+    /// The most likely use case of a drop bound is to distinguish between
+    /// types that have destructors and types that don't. Combined with
+    /// specialization, a naive coder would write an implementation that
+    /// assumed a type could be trivially dropped, then write a specialization
+    /// for `T: Drop` that actually calls the destructor. Except that doing so
+    /// is not correct; String, for example, doesn't actually implement Drop,
+    /// but because String contains a Vec, assuming it can be trivially dropped
+    /// will leak memory.
+    pub DROP_BOUNDS,
+    Warn,
+    "bounds of the form `T: Drop` are useless"
+}
+
+declare_lint_pass!(
+    /// Lint for bounds of the form `T: Drop`, which usually
+    /// indicate an attempt to emulate `std::mem::needs_drop`.
+    DropTraitConstraints => [DROP_BOUNDS]
+);
+
+impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
+        use rustc_middle::ty::PredicateAtom::*;
+
+        let def_id = cx.tcx.hir().local_def_id(item.hir_id);
+        let predicates = cx.tcx.explicit_predicates_of(def_id);
+        for &(predicate, span) in predicates.predicates {
+            let trait_predicate = match predicate.skip_binders() {
+                Trait(trait_predicate, _constness) => trait_predicate,
+                _ => continue,
+            };
+            let def_id = trait_predicate.trait_ref.def_id;
+            if cx.tcx.lang_items().drop_trait() == Some(def_id) {
+                // Explicitly allow `impl Drop`, a drop-guards-as-Voldemort-type pattern.
+                if trait_predicate.trait_ref.self_ty().is_impl_trait() {
+                    continue;
+                }
+                cx.struct_span_lint(DROP_BOUNDS, span, |lint| {
+                    let needs_drop = match cx.tcx.get_diagnostic_item(sym::needs_drop) {
+                        Some(needs_drop) => needs_drop,
+                        None => return,
+                    };
+                    let msg = format!(
+                        "bounds on `{}` are useless, consider instead \
+                         using `{}` to detect if a type has a destructor",
+                        predicate,
+                        cx.tcx.def_path_str(needs_drop)
+                    );
+                    lint.build(&msg).emit()
+                });
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 7b5cf681f38..238bce94cf5 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -28,6 +28,9 @@ use std::ops::{Deref, DerefMut};
 use super::*;
 
 macro_rules! p {
+    (@$lit:literal) => {
+        write!(scoped_cx!(), $lit)?
+    };
     (@write($($data:expr),+)) => {
         write!(scoped_cx!(), $($data),+)?
     };
@@ -37,8 +40,8 @@ macro_rules! p {
     (@$method:ident($($arg:expr),*)) => {
         scoped_cx!() = scoped_cx!().$method($($arg),*)?
     };
-    ($($kind:ident $data:tt),+) => {{
-        $(p!(@$kind $data);)+
+    ($($elem:tt $(($($args:tt)*))?),+) => {{
+        $(p!(@ $elem $(($($args)*))?);)+
     }};
 }
 macro_rules! define_scoped_cx {
@@ -478,7 +481,7 @@ pub trait PrettyPrinter<'tcx>:
 
             p!(print(self_ty));
             if let Some(trait_ref) = trait_ref {
-                p!(write(" as "), print(trait_ref.print_only_trait_path()));
+                p!(" as ", print(trait_ref.print_only_trait_path()));
             }
             Ok(cx)
         })
@@ -495,9 +498,9 @@ pub trait PrettyPrinter<'tcx>:
         self.generic_delimiters(|mut cx| {
             define_scoped_cx!(cx);
 
-            p!(write("impl "));
+            p!("impl ");
             if let Some(trait_ref) = trait_ref {
-                p!(print(trait_ref.print_only_trait_path()), write(" for "));
+                p!(print(trait_ref.print_only_trait_path()), " for ");
             }
             p!(print(self_ty));
 
@@ -509,8 +512,8 @@ pub trait PrettyPrinter<'tcx>:
         define_scoped_cx!(self);
 
         match *ty.kind() {
-            ty::Bool => p!(write("bool")),
-            ty::Char => p!(write("char")),
+            ty::Bool => p!("bool"),
+            ty::Char => p!("char"),
             ty::Int(t) => p!(write("{}", t.name_str())),
             ty::Uint(t) => p!(write("{}", t.name_str())),
             ty::Float(t) => p!(write("{}", t.name_str())),
@@ -525,23 +528,23 @@ pub trait PrettyPrinter<'tcx>:
                 p!(print(tm.ty))
             }
             ty::Ref(r, ty, mutbl) => {
-                p!(write("&"));
+                p!("&");
                 if self.region_should_not_be_omitted(r) {
-                    p!(print(r), write(" "));
+                    p!(print(r), " ");
                 }
                 p!(print(ty::TypeAndMut { ty, mutbl }))
             }
-            ty::Never => p!(write("!")),
+            ty::Never => p!("!"),
             ty::Tuple(ref tys) => {
-                p!(write("("), comma_sep(tys.iter()));
+                p!("(", comma_sep(tys.iter()));
                 if tys.len() == 1 {
-                    p!(write(","));
+                    p!(",");
                 }
-                p!(write(")"))
+                p!(")")
             }
             ty::FnDef(def_id, substs) => {
                 let sig = self.tcx().fn_sig(def_id).subst(self.tcx(), substs);
-                p!(print(sig), write(" {{"), print_value_path(def_id, substs), write("}}"));
+                p!(print(sig), " {{", print_value_path(def_id, substs), "}}");
             }
             ty::FnPtr(ref bare_fn) => p!(print(bare_fn)),
             ty::Infer(infer_ty) => {
@@ -555,7 +558,7 @@ pub trait PrettyPrinter<'tcx>:
                     p!(write("{}", infer_ty))
                 }
             }
-            ty::Error(_) => p!(write("[type error]")),
+            ty::Error(_) => p!("[type error]"),
             ty::Param(ref param_ty) => p!(write("{}", param_ty)),
             ty::Bound(debruijn, bound_ty) => match bound_ty.kind {
                 ty::BoundTyKind::Anon => self.pretty_print_bound_var(debruijn, bound_ty.var)?,
@@ -567,11 +570,11 @@ pub trait PrettyPrinter<'tcx>:
             ty::Dynamic(data, r) => {
                 let print_r = self.region_should_not_be_omitted(r);
                 if print_r {
-                    p!(write("("));
+                    p!("(");
                 }
-                p!(write("dyn "), print(data));
+                p!("dyn ", print(data));
                 if print_r {
-                    p!(write(" + "), print(r), write(")"));
+                    p!(" + ", print(r), ")");
                 }
             }
             ty::Foreign(def_id) => {
@@ -597,7 +600,7 @@ pub trait PrettyPrinter<'tcx>:
                         p!(write("{}", name));
                         // FIXME(eddyb) print this with `print_def_path`.
                         if !substs.is_empty() {
-                            p!(write("::"));
+                            p!("::");
                             p!(generic_delimiters(|cx| cx.comma_sep(substs.iter())));
                         }
                         return Ok(self);
@@ -608,7 +611,7 @@ pub trait PrettyPrinter<'tcx>:
 
                     let mut first = true;
                     let mut is_sized = false;
-                    p!(write("impl"));
+                    p!("impl");
                     for predicate in bounds.predicates {
                         // Note: We can't use `to_opt_poly_trait_ref` here as `predicate`
                         // may contain unbound variables. We therefore do this manually.
@@ -634,21 +637,21 @@ pub trait PrettyPrinter<'tcx>:
                     if !is_sized {
                         p!(write("{}?Sized", if first { " " } else { "+" }));
                     } else if first {
-                        p!(write(" Sized"));
+                        p!(" Sized");
                     }
                     Ok(self)
                 })?);
             }
-            ty::Str => p!(write("str")),
+            ty::Str => p!("str"),
             ty::Generator(did, substs, movability) => {
                 p!(write("["));
                 match movability {
                     hir::Movability::Movable => {}
-                    hir::Movability::Static => p!(write("static ")),
+                    hir::Movability::Static => p!("static "),
                 }
 
                 if !self.tcx().sess.verbose() {
-                    p!(write("generator"));
+                    p!("generator");
                     // FIXME(eddyb) should use `def_span`.
                     if let Some(did) = did.as_local() {
                         let hir_id = self.tcx().hir().local_def_id_to_hir_id(did);
@@ -661,7 +664,7 @@ pub trait PrettyPrinter<'tcx>:
                     p!(print_def_path(did, substs));
                     if substs.as_generator().is_valid() {
                         // Search for the first inference variable
-                        p!(write(" upvar_tys=("));
+                        p!(" upvar_tys=(");
                         let mut uninferred_ty =
                             substs.as_generator().upvar_tys().filter(|ty| ty.is_ty_infer());
                         if uninferred_ty.next().is_some() {
@@ -669,15 +672,15 @@ pub trait PrettyPrinter<'tcx>:
                         } else {
                             self = self.comma_sep(substs.as_generator().upvar_tys())?;
                         }
-                        p!(write(")"));
+                        p!(")");
                     }
                 }
 
                 if substs.as_generator().is_valid() {
-                    p!(write(" "), print(substs.as_generator().witness()));
+                    p!(" ", print(substs.as_generator().witness()));
                 }
 
-                p!(write("]"));
+                p!("]")
             }
             ty::GeneratorWitness(types) => {
                 p!(in_binder(&types));
@@ -690,7 +693,7 @@ pub trait PrettyPrinter<'tcx>:
                     if let Some(did) = did.as_local() {
                         let hir_id = self.tcx().hir().local_def_id_to_hir_id(did);
                         if self.tcx().sess.opts.debugging_opts.span_free_formats {
-                            p!(write("@"), print_def_path(did.to_def_id(), substs));
+                            p!("@", print_def_path(did.to_def_id(), substs));
                         } else {
                             let span = self.tcx().hir().span(hir_id);
                             p!(write("@{}", self.tcx().sess.source_map().span_to_string(span)));
@@ -707,40 +710,40 @@ pub trait PrettyPrinter<'tcx>:
                         if uninferred_ty.next().is_some() {
                             // If the upvar substs contain an inference variable we haven't
                             // finished capture analysis.
-                            p!(write(" closure_substs=(unavailable)"));
+                            p!(" closure_substs=(unavailable)");
                         } else {
-                            p!(write(" closure_kind_ty="), print(substs.as_closure().kind_ty()));
+                            p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
                             p!(
-                                write(" closure_sig_as_fn_ptr_ty="),
+                                " closure_sig_as_fn_ptr_ty=",
                                 print(substs.as_closure().sig_as_fn_ptr_ty())
                             );
-                            p!(write(" upvar_tys=("));
+                            p!(" upvar_tys=(");
                             self = self.comma_sep(substs.as_closure().upvar_tys())?;
-                            p!(write(")"));
+                            p!(")");
                         }
                     }
                 }
-                p!(write("]"));
+                p!("]");
             }
             ty::Array(ty, sz) => {
-                p!(write("["), print(ty), write("; "));
+                p!("[", print(ty), "; ");
                 if self.tcx().sess.verbose() {
                     p!(write("{:?}", sz));
                 } else if let ty::ConstKind::Unevaluated(..) = sz.val {
                     // Do not try to evaluate unevaluated constants. If we are const evaluating an
                     // array length anon const, rustc will (with debug assertions) print the
                     // constant's path. Which will end up here again.
-                    p!(write("_"));
+                    p!("_");
                 } else if let Some(n) = sz.val.try_to_bits(self.tcx().data_layout.pointer_size) {
                     p!(write("{}", n));
                 } else if let ty::ConstKind::Param(param) = sz.val {
                     p!(write("{}", param));
                 } else {
-                    p!(write("_"));
+                    p!("_");
                 }
-                p!(write("]"))
+                p!("]")
             }
-            ty::Slice(ty) => p!(write("["), print(ty), write("]")),
+            ty::Slice(ty) => p!("[", print(ty), "]"),
         }
 
         Ok(self)
@@ -847,7 +850,7 @@ pub trait PrettyPrinter<'tcx>:
 
         for (_, def_id) in auto_traits {
             if !first {
-                p!(write(" + "));
+                p!(" + ");
             }
             first = false;
 
@@ -865,16 +868,16 @@ pub trait PrettyPrinter<'tcx>:
     ) -> Result<Self, Self::Error> {
         define_scoped_cx!(self);
 
-        p!(write("("), comma_sep(inputs.iter().copied()));
+        p!("(", comma_sep(inputs.iter().copied()));
         if c_variadic {
             if !inputs.is_empty() {
-                p!(write(", "));
+                p!(", ");
             }
-            p!(write("..."));
+            p!("...");
         }
-        p!(write(")"));
+        p!(")");
         if !output.is_unit() {
-            p!(write(" -> "), print(output));
+            p!(" -> ", print(output));
         }
 
         Ok(self)
@@ -945,7 +948,7 @@ pub trait PrettyPrinter<'tcx>:
                 self.pretty_print_bound_var(debruijn, bound_var)?
             }
             ty::ConstKind::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
-            ty::ConstKind::Error(_) => p!(write("[const error]")),
+            ty::ConstKind::Error(_) => p!("[const error]"),
         };
         Ok(self)
     }
@@ -987,17 +990,17 @@ pub trait PrettyPrinter<'tcx>:
                     {
                         p!(pretty_print_byte_str(byte_str))
                     } else {
-                        p!(write("<too short allocation>"))
+                        p!("<too short allocation>")
                     }
                 }
                 // FIXME: for statics and functions, we could in principle print more detail.
                 Some(GlobalAlloc::Static(def_id)) => p!(write("<static({:?})>", def_id)),
-                Some(GlobalAlloc::Function(_)) => p!(write("<function>")),
-                None => p!(write("<dangling pointer>")),
+                Some(GlobalAlloc::Function(_)) => p!("<function>"),
+                None => p!("<dangling pointer>"),
             },
             // Bool
-            (Scalar::Raw { data: 0, .. }, ty::Bool) => p!(write("false")),
-            (Scalar::Raw { data: 1, .. }, ty::Bool) => p!(write("true")),
+            (Scalar::Raw { data: 0, .. }, ty::Bool) => p!("false"),
+            (Scalar::Raw { data: 1, .. }, ty::Bool) => p!("true"),
             // Float
             (Scalar::Raw { data, .. }, ty::Float(ast::FloatTy::F32)) => {
                 p!(write("{}f32", Single::from_bits(data)))
@@ -1093,13 +1096,13 @@ pub trait PrettyPrinter<'tcx>:
 
     fn pretty_print_byte_str(mut self, byte_str: &'tcx [u8]) -> Result<Self::Const, Self::Error> {
         define_scoped_cx!(self);
-        p!(write("b\""));
+        p!("b\"");
         for &c in byte_str {
             for e in std::ascii::escape_default(c) {
                 self.write_char(e as char)?;
             }
         }
-        p!(write("\""));
+        p!("\"");
         Ok(self)
     }
 
@@ -1112,7 +1115,7 @@ pub trait PrettyPrinter<'tcx>:
         define_scoped_cx!(self);
 
         if self.tcx().sess.verbose() {
-            p!(write("ConstValue({:?}: ", ct), print(ty), write(")"));
+            p!(write("ConstValue({:?}: ", ct), print(ty), ")");
             return Ok(self);
         }
 
@@ -1149,7 +1152,7 @@ pub trait PrettyPrinter<'tcx>:
                 let ptr = Pointer::new(AllocId(0), offset);
 
                 let byte_str = alloc.get_bytes(&self.tcx(), ptr, n).unwrap();
-                p!(write("*"));
+                p!("*");
                 p!(pretty_print_byte_str(byte_str));
                 Ok(self)
             }
@@ -1173,14 +1176,14 @@ pub trait PrettyPrinter<'tcx>:
 
                 match *ty.kind() {
                     ty::Array(..) => {
-                        p!(write("["), comma_sep(fields), write("]"));
+                        p!("[", comma_sep(fields), "]");
                     }
                     ty::Tuple(..) => {
-                        p!(write("("), comma_sep(fields));
+                        p!("(", comma_sep(fields));
                         if contents.fields.len() == 1 {
-                            p!(write(","));
+                            p!(",");
                         }
-                        p!(write(")"));
+                        p!(")");
                     }
                     ty::Adt(def, substs) if def.variants.is_empty() => {
                         p!(print_value_path(def.did, substs));
@@ -1194,19 +1197,19 @@ pub trait PrettyPrinter<'tcx>:
                         match variant_def.ctor_kind {
                             CtorKind::Const => {}
                             CtorKind::Fn => {
-                                p!(write("("), comma_sep(fields), write(")"));
+                                p!("(", comma_sep(fields), ")");
                             }
                             CtorKind::Fictive => {
-                                p!(write(" {{ "));
+                                p!(" {{ ");
                                 let mut first = true;
                                 for (field_def, field) in variant_def.fields.iter().zip(fields) {
                                     if !first {
-                                        p!(write(", "));
+                                        p!(", ");
                                     }
                                     p!(write("{}: ", field_def.ident), print(field));
                                     first = false;
                                 }
-                                p!(write(" }}"));
+                                p!(" }}");
                             }
                         }
                     }
@@ -1224,7 +1227,7 @@ pub trait PrettyPrinter<'tcx>:
                 // fallback
                 p!(write("{:?}", ct));
                 if print_ty {
-                    p!(write(": "), print(ty));
+                    p!(": ", print(ty));
                 }
                 Ok(self)
             }
@@ -1637,7 +1640,7 @@ impl<F: fmt::Write> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> {
             if this.print_alloc_ids {
                 p!(write("{:?}", p));
             } else {
-                p!(write("&_"));
+                p!("&_");
             }
             Ok(this)
         };
@@ -1703,11 +1706,11 @@ impl<F: fmt::Write> FmtPrinter<'_, '_, F> {
             ty::ReVar(_) => {}
             ty::ReErased => {}
             ty::ReStatic => {
-                p!(write("'static"));
+                p!("'static");
                 return Ok(self);
             }
             ty::ReEmpty(ty::UniverseIndex::ROOT) => {
-                p!(write("'<empty>"));
+                p!("'<empty>");
                 return Ok(self);
             }
             ty::ReEmpty(ui) => {
@@ -1716,7 +1719,7 @@ impl<F: fmt::Write> FmtPrinter<'_, '_, F> {
             }
         }
 
-        p!(write("'_"));
+        p!("'_");
 
         Ok(self)
     }
@@ -1847,7 +1850,7 @@ where
     type Error = P::Error;
     fn print(&self, mut cx: P) -> Result<Self::Output, Self::Error> {
         define_scoped_cx!(cx);
-        p!(print(self.0), write(": "), print(self.1));
+        p!(print(self.0), ": ", print(self.1));
         Ok(cx)
     }
 }
@@ -1945,7 +1948,7 @@ define_print_and_forward_display! {
     (self, cx):
 
     &'tcx ty::List<Ty<'tcx>> {
-        p!(write("{{"), comma_sep(self.iter()), write("}}"))
+        p!("{{", comma_sep(self.iter()), "}}")
     }
 
     ty::TypeAndMut<'tcx> {
@@ -1981,7 +1984,7 @@ define_print_and_forward_display! {
             p!(write("extern {} ", self.abi));
         }
 
-        p!(write("fn"), pretty_fn_sig(self.inputs(), self.c_variadic, self.output()));
+        p!("fn", pretty_fn_sig(self.inputs(), self.c_variadic, self.output()));
     }
 
     ty::InferTy {
@@ -1990,7 +1993,7 @@ define_print_and_forward_display! {
             return Ok(cx);
         }
         match *self {
-            ty::TyVar(_) => p!(write("_")),
+            ty::TyVar(_) => p!("_"),
             ty::IntVar(_) => p!(write("{}", "{integer}")),
             ty::FloatVar(_) => p!(write("{}", "{float}")),
             ty::FreshTy(v) => p!(write("FreshTy({})", v)),
@@ -2016,16 +2019,16 @@ define_print_and_forward_display! {
     }
 
     ty::SubtypePredicate<'tcx> {
-        p!(print(self.a), write(" <: "), print(self.b))
+        p!(print(self.a), " <: ", print(self.b))
     }
 
     ty::TraitPredicate<'tcx> {
-        p!(print(self.trait_ref.self_ty()), write(": "),
+        p!(print(self.trait_ref.self_ty()), ": ",
            print(self.trait_ref.print_only_trait_path()))
     }
 
     ty::ProjectionPredicate<'tcx> {
-        p!(print(self.projection_ty), write(" == "), print(self.ty))
+        p!(print(self.projection_ty), " == ", print(self.ty))
     }
 
     ty::ProjectionTy<'tcx> {
@@ -2034,9 +2037,9 @@ define_print_and_forward_display! {
 
     ty::ClosureKind {
         match *self {
-            ty::ClosureKind::Fn => p!(write("Fn")),
-            ty::ClosureKind::FnMut => p!(write("FnMut")),
-            ty::ClosureKind::FnOnce => p!(write("FnOnce")),
+            ty::ClosureKind::Fn => p!("Fn"),
+            ty::ClosureKind::FnMut => p!("FnMut"),
+            ty::ClosureKind::FnOnce => p!("FnOnce"),
         }
     }
 
@@ -2051,7 +2054,7 @@ define_print_and_forward_display! {
         match *self {
             ty::PredicateAtom::Trait(ref data, constness) => {
                 if let hir::Constness::Const = constness {
-                    p!(write("const "));
+                    p!("const ");
                 }
                 p!(print(data))
             }
@@ -2059,33 +2062,23 @@ define_print_and_forward_display! {
             ty::PredicateAtom::RegionOutlives(predicate) => p!(print(predicate)),
             ty::PredicateAtom::TypeOutlives(predicate) => p!(print(predicate)),
             ty::PredicateAtom::Projection(predicate) => p!(print(predicate)),
-            ty::PredicateAtom::WellFormed(arg) => p!(print(arg), write(" well-formed")),
+            ty::PredicateAtom::WellFormed(arg) => p!(print(arg), " well-formed"),
             ty::PredicateAtom::ObjectSafe(trait_def_id) => {
-                p!(write("the trait `"),
-                print_def_path(trait_def_id, &[]),
-                write("` is object-safe"))
+                p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe")
             }
             ty::PredicateAtom::ClosureKind(closure_def_id, _closure_substs, kind) => {
-                p!(write("the closure `"),
+                p!("the closure `",
                 print_value_path(closure_def_id, &[]),
                 write("` implements the trait `{}`", kind))
             }
             ty::PredicateAtom::ConstEvaluatable(def, substs) => {
-                p!(write("the constant `"),
-                print_value_path(def.did, substs),
-                write("` can be evaluated"))
+                p!("the constant `", print_value_path(def.did, substs), "` can be evaluated")
             }
             ty::PredicateAtom::ConstEquate(c1, c2) => {
-                p!(write("the constant `"),
-                print(c1),
-                write("` equals `"),
-                print(c2),
-                write("`"))
+                p!("the constant `", print(c1), "` equals `", print(c2), "`")
             }
             ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
-                p!(write("the type `"),
-                print(ty),
-                write("` is found in the environment"))
+                p!("the type `", print(ty), "` is found in the environment")
             }
         }
     }
diff --git a/compiler/rustc_mir/Cargo.toml b/compiler/rustc_mir/Cargo.toml
index a6d22243d6d..487668cfa11 100644
--- a/compiler/rustc_mir/Cargo.toml
+++ b/compiler/rustc_mir/Cargo.toml
@@ -12,7 +12,6 @@ either = "1.5.0"
 rustc_graphviz = { path = "../rustc_graphviz" }
 itertools = "0.9"
 tracing = "0.1"
-log_settings = "0.1.1"
 polonius-engine = "0.12.0"
 regex = "1"
 rustc_middle = { path = "../rustc_middle" }
diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs
index f97096984fa..93da6e3d38a 100644
--- a/compiler/rustc_mir/src/interpret/eval_context.rs
+++ b/compiler/rustc_mir/src/interpret/eval_context.rs
@@ -48,8 +48,41 @@ pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
         FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), Pointer<M::PointerTag>>,
 }
 
+// The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread
+// boundary and dropped in the other thread, it would exit the span in the other thread.
+struct SpanGuard(tracing::Span, std::marker::PhantomData<*const u8>);
+
+impl SpanGuard {
+    /// By default a `SpanGuard` does nothing.
+    fn new() -> Self {
+        Self(tracing::Span::none(), std::marker::PhantomData)
+    }
+
+    /// If a span is entered, we exit the previous span (if any, normally none) and enter the
+    /// new span. This is mainly so we don't have to use `Option` for the `tracing_span` field of
+    /// `Frame` by creating a dummy span to being with and then entering it once the frame has
+    /// been pushed.
+    fn enter(&mut self, span: tracing::Span) {
+        // This executes the destructor on the previous instance of `SpanGuard`, ensuring that
+        // we never enter or exit more spans than vice versa. Unless you `mem::leak`, then we
+        // can't protect the tracing stack, but that'll just lead to weird logging, no actual
+        // problems.
+        *self = Self(span, std::marker::PhantomData);
+        self.0.with_subscriber(|(id, dispatch)| {
+            dispatch.enter(id);
+        });
+    }
+}
+
+impl Drop for SpanGuard {
+    fn drop(&mut self) {
+        self.0.with_subscriber(|(id, dispatch)| {
+            dispatch.exit(id);
+        });
+    }
+}
+
 /// A stack frame.
-#[derive(Clone)]
 pub struct Frame<'mir, 'tcx, Tag = (), Extra = ()> {
     ////////////////////////////////////////////////////////////////////////////////
     // Function and callsite information
@@ -80,6 +113,11 @@ pub struct Frame<'mir, 'tcx, Tag = (), Extra = ()> {
     /// can either directly contain `Scalar` or refer to some part of an `Allocation`.
     pub locals: IndexVec<mir::Local, LocalState<'tcx, Tag>>,
 
+    /// The span of the `tracing` crate is stored here.
+    /// When the guard is dropped, the span is exited. This gives us
+    /// a full stack trace on all tracing statements.
+    tracing_span: SpanGuard,
+
     ////////////////////////////////////////////////////////////////////////////////
     // Current position within the function
     ////////////////////////////////////////////////////////////////////////////////
@@ -184,6 +222,7 @@ impl<'mir, 'tcx, Tag> Frame<'mir, 'tcx, Tag> {
             locals: self.locals,
             loc: self.loc,
             extra,
+            tracing_span: self.tracing_span,
         }
     }
 }
@@ -637,11 +676,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         return_place: Option<PlaceTy<'tcx, M::PointerTag>>,
         return_to_block: StackPopCleanup,
     ) -> InterpResult<'tcx> {
-        if !self.stack().is_empty() {
-            info!("PAUSING({}) {}", self.frame_idx(), self.frame().instance);
-        }
-        ::log_settings::settings().indentation += 1;
-
         // first push a stack frame so we have access to the local substs
         let pre_frame = Frame {
             body,
@@ -652,6 +686,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             // all methods actually know about the frame
             locals: IndexVec::new(),
             instance,
+            tracing_span: SpanGuard::new(),
             extra: (),
         };
         let frame = M::init_frame_extra(self, pre_frame)?;
@@ -696,7 +731,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         self.frame_mut().locals = locals;
         M::after_stack_push(self)?;
         self.frame_mut().loc = Ok(mir::Location::START);
-        info!("ENTERING({}) {}", self.frame_idx(), self.frame().instance);
+
+        let span = info_span!("frame", "{}", instance);
+        self.frame_mut().tracing_span.enter(span);
 
         Ok(())
     }
@@ -747,10 +784,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// cause us to continue unwinding.
     pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx> {
         info!(
-            "LEAVING({}) {} (unwinding = {})",
-            self.frame_idx(),
-            self.frame().instance,
-            unwinding
+            "popping stack frame ({})",
+            if unwinding { "during unwinding" } else { "returning from function" }
         );
 
         // Sanity check `unwinding`.
@@ -766,7 +801,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             throw_ub_format!("unwinding past the topmost frame of the stack");
         }
 
-        ::log_settings::settings().indentation -= 1;
         let frame =
             self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
 
@@ -823,15 +857,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
         }
 
-        if !self.stack().is_empty() {
-            info!(
-                "CONTINUING({}) {} (unwinding = {})",
-                self.frame_idx(),
-                self.frame().instance,
-                unwinding
-            );
-        }
-
         Ok(())
     }
 
@@ -995,7 +1020,16 @@ where
 {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'ctx>, hasher: &mut StableHasher) {
         // Exhaustive match on fields to make sure we forget no field.
-        let Frame { body, instance, return_to_block, return_place, locals, loc, extra } = self;
+        let Frame {
+            body,
+            instance,
+            return_to_block,
+            return_place,
+            locals,
+            loc,
+            extra,
+            tracing_span: _,
+        } = self;
         body.hash_stable(hcx, hasher);
         instance.hash_stable(hcx, hasher);
         return_to_block.hash_stable(hcx, hasher);
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 2b244a04d22..04f317401f1 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -1701,10 +1701,14 @@ where
 /// Most of the implementation of DrainFilter, independent of the type
 /// of the predicate, thus also serving for BTreeSet::DrainFilter.
 pub(super) struct DrainFilterInner<'a, K: 'a, V: 'a> {
+    /// Reference to the length field in the borrowed map, updated live.
     length: &'a mut usize,
-    // dormant_root is wrapped in an Option to be able to `take` it.
+    /// Burried reference to the root field in the borrowed map.
+    /// Wrapped in `Option` to allow drop handler to `take` it.
     dormant_root: Option<DormantMutRef<'a, node::Root<K, V>>>,
-    // cur_leaf_edge is wrapped in an Option because maps without root lack a leaf edge.
+    /// Contains a leaf edge preceding the next element to be returned, or the last leaf edge.
+    /// Empty if the map has no root, if iteration went beyond the last leaf edge,
+    /// or if a panic occurred in the predicate.
     cur_leaf_edge: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>,
 }
 
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index aa1b5529df2..a2c7da6e695 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -568,6 +568,7 @@ pub unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize {
 #[inline]
 #[stable(feature = "needs_drop", since = "1.21.0")]
 #[rustc_const_stable(feature = "const_needs_drop", since = "1.36.0")]
+#[rustc_diagnostic_item = "needs_drop"]
 pub const fn needs_drop<T>() -> bool {
     intrinsics::needs_drop::<T>()
 }
diff --git a/src/bootstrap/CHANGELOG.md b/src/bootstrap/CHANGELOG.md
index fe426c4cec7..d8c704f451b 100644
--- a/src/bootstrap/CHANGELOG.md
+++ b/src/bootstrap/CHANGELOG.md
@@ -6,7 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
 ## [Non-breaking changes since the last major version]
 
-None.
+- `x.py check` needs opt-in to check tests (--all-targets) [#77473](https://github.com/rust-lang/rust/pull/77473)
 
 ## [Version 2] - 2020-09-25
 
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 4beeb9c87c4..6856cd338cf 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -532,7 +532,7 @@ impl<'a> Builder<'a> {
     pub fn new(build: &Build) -> Builder<'_> {
         let (kind, paths) = match build.config.cmd {
             Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
-            Subcommand::Check { ref paths } => (Kind::Check, &paths[..]),
+            Subcommand::Check { ref paths, all_targets: _ } => (Kind::Check, &paths[..]),
             Subcommand::Clippy { ref paths } => (Kind::Clippy, &paths[..]),
             Subcommand::Fix { ref paths } => (Kind::Fix, &paths[..]),
             Subcommand::Doc { ref paths, .. } => (Kind::Doc, &paths[..]),
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index ead0bd0413b..371631154f7 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -1,9 +1,12 @@
 //! Implementation of compiling the compiler and standard library, in "check"-based modes.
 
-use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, std_cargo};
 use crate::config::TargetSelection;
 use crate::tool::{prepare_tool_cargo, SourceType};
+use crate::{
+    builder::{Builder, Kind, RunConfig, ShouldRun, Step},
+    Subcommand,
+};
 use crate::{Compiler, Mode};
 use std::path::PathBuf;
 
@@ -74,35 +77,37 @@ impl Step for Std {
         //
         // Currently only the "libtest" tree of crates does this.
 
-        let mut cargo = builder.cargo(
-            compiler,
-            Mode::Std,
-            SourceType::InTree,
-            target,
-            cargo_subcommand(builder.kind),
-        );
-        std_cargo(builder, target, compiler.stage, &mut cargo);
-        cargo.arg("--all-targets");
+        if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
+            let mut cargo = builder.cargo(
+                compiler,
+                Mode::Std,
+                SourceType::InTree,
+                target,
+                cargo_subcommand(builder.kind),
+            );
+            std_cargo(builder, target, compiler.stage, &mut cargo);
+            cargo.arg("--all-targets");
+
+            // Explicitly pass -p for all dependencies krates -- this will force cargo
+            // to also check the tests/benches/examples for these crates, rather
+            // than just the leaf crate.
+            for krate in builder.in_tree_crates("test") {
+                cargo.arg("-p").arg(krate.name);
+            }
 
-        // Explicitly pass -p for all dependencies krates -- this will force cargo
-        // to also check the tests/benches/examples for these crates, rather
-        // than just the leaf crate.
-        for krate in builder.in_tree_crates("test") {
-            cargo.arg("-p").arg(krate.name);
+            builder.info(&format!(
+                "Checking std test/bench/example targets ({} -> {})",
+                &compiler.host, target
+            ));
+            run_cargo(
+                builder,
+                cargo,
+                args(builder.kind),
+                &libstd_test_stamp(builder, compiler, target),
+                vec![],
+                true,
+            );
         }
-
-        builder.info(&format!(
-            "Checking std test/bench/example targets ({} -> {})",
-            &compiler.host, target
-        ));
-        run_cargo(
-            builder,
-            cargo,
-            args(builder.kind),
-            &libstd_test_stamp(builder, compiler, target),
-            vec![],
-            true,
-        );
     }
 }
 
@@ -143,7 +148,9 @@ impl Step for Rustc {
             cargo_subcommand(builder.kind),
         );
         rustc_cargo(builder, &mut cargo, target);
-        cargo.arg("--all-targets");
+        if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
+            cargo.arg("--all-targets");
+        }
 
         // Explicitly pass -p for all compiler krates -- this will force cargo
         // to also check the tests/benches/examples for these crates, rather
@@ -205,7 +212,9 @@ macro_rules! tool_check_step {
                     &[],
                 );
 
-                cargo.arg("--all-targets");
+                if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
+                    cargo.arg("--all-targets");
+                }
 
                 builder.info(&format!(
                     "Checking {} artifacts ({} -> {})",
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 795244e7cd4..c1a9d4fcd23 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -47,6 +47,9 @@ pub enum Subcommand {
         paths: Vec<PathBuf>,
     },
     Check {
+        // Whether to run checking over all targets (e.g., unit / integration
+        // tests).
+        all_targets: bool,
         paths: Vec<PathBuf>,
     },
     Clippy {
@@ -250,6 +253,9 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
                         `/<build_base>/rustfix_missing_coverage.txt`",
                 );
             }
+            "check" => {
+                opts.optflag("", "all-targets", "Check all targets");
+            }
             "bench" => {
                 opts.optmulti("", "test-args", "extra arguments", "ARGS");
             }
@@ -484,7 +490,9 @@ Arguments:
 
         let cmd = match subcommand.as_str() {
             "build" | "b" => Subcommand::Build { paths },
-            "check" | "c" => Subcommand::Check { paths },
+            "check" | "c" => {
+                Subcommand::Check { paths, all_targets: matches.opt_present("all-targets") }
+            }
             "clippy" => Subcommand::Clippy { paths },
             "fix" => Subcommand::Fix { paths },
             "test" | "t" => Subcommand::Test {
diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
index 8fc9a009dce..b2aa5844e47 100644
--- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
@@ -24,7 +24,7 @@ COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
 
 ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
 ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \
-           python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \
+           python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu --all-targets && \
            python3 ../x.py build --stage 0 src/tools/build-manifest && \
            python3 ../x.py test --stage 0 src/tools/compiletest && \
            python3 ../x.py test --stage 2 src/tools/tidy && \
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index cf94ea384fd..f234dc5c03b 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -1576,22 +1576,27 @@ fn resolution_failure(
                     };
                     // See if this was a module: `[path]` or `[std::io::nope]`
                     if let Some(module) = last_found_module {
-                        let module_name = collector.cx.tcx.item_name(module);
-                        let note = format!(
-                            "the module `{}` contains no item named `{}`",
-                            module_name, unresolved
-                        );
+                        let note = if partial_res.is_some() {
+                            // Part of the link resolved; e.g. `std::io::nonexistent`
+                            let module_name = collector.cx.tcx.item_name(module);
+                            format!("no item named `{}` in module `{}`", unresolved, module_name)
+                        } else {
+                            // None of the link resolved; e.g. `Notimported`
+                            format!("no item named `{}` in scope", unresolved)
+                        };
                         if let Some(span) = sp {
                             diag.span_label(span, &note);
                         } else {
                             diag.note(&note);
                         }
+
                         // If the link has `::` in it, assume it was meant to be an intra-doc link.
                         // Otherwise, the `[]` might be unrelated.
                         // FIXME: don't show this for autolinks (`<>`), `()` style links, or reference links
                         if !path_str.contains("::") {
                             diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#);
                         }
+
                         continue;
                     }
 
diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr
index 33260fa0e1e..9ec9dd4bc9a 100644
--- a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr
+++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr
@@ -2,7 +2,7 @@ error: unresolved link to `v2`
   --> $DIR/deny-intra-link-resolution-failure.rs:3:6
    |
 LL | /// [v2]
-   |      ^^ the module `deny_intra_link_resolution_failure` contains no item named `v2`
+   |      ^^ no item named `v2` in scope
    |
 note: the lint level is defined here
   --> $DIR/deny-intra-link-resolution-failure.rs:1:9
diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs
index 0278caf3087..ef928ae02f3 100644
--- a/src/test/rustdoc-ui/intra-link-errors.rs
+++ b/src/test/rustdoc-ui/intra-link-errors.rs
@@ -6,23 +6,23 @@
 
 /// [path::to::nonexistent::module]
 //~^ ERROR unresolved link
-//~| NOTE `intra_link_errors` contains no item named `path`
+//~| NOTE no item named `path` in scope
 
 /// [path::to::nonexistent::macro!]
 //~^ ERROR unresolved link
-//~| NOTE `intra_link_errors` contains no item named `path`
+//~| NOTE no item named `path` in scope
 
 /// [type@path::to::nonexistent::type]
 //~^ ERROR unresolved link
-//~| NOTE `intra_link_errors` contains no item named `path`
+//~| NOTE no item named `path` in scope
 
 /// [std::io::not::here]
 //~^ ERROR unresolved link
-//~| NOTE `io` contains no item named `not`
+//~| NOTE no item named `not` in module `io`
 
 /// [type@std::io::not::here]
 //~^ ERROR unresolved link
-//~| NOTE `io` contains no item named `not`
+//~| NOTE no item named `not` in module `io`
 
 /// [std::io::Error::x]
 //~^ ERROR unresolved link
diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr
index b63f799535a..31e7fc48afd 100644
--- a/src/test/rustdoc-ui/intra-link-errors.stderr
+++ b/src/test/rustdoc-ui/intra-link-errors.stderr
@@ -2,7 +2,7 @@ error: unresolved link to `path::to::nonexistent::module`
   --> $DIR/intra-link-errors.rs:7:6
    |
 LL | /// [path::to::nonexistent::module]
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path`
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in scope
    |
 note: the lint level is defined here
   --> $DIR/intra-link-errors.rs:1:9
@@ -14,25 +14,25 @@ error: unresolved link to `path::to::nonexistent::macro`
   --> $DIR/intra-link-errors.rs:11:6
    |
 LL | /// [path::to::nonexistent::macro!]
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path`
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in scope
 
 error: unresolved link to `path::to::nonexistent::type`
   --> $DIR/intra-link-errors.rs:15:6
    |
 LL | /// [type@path::to::nonexistent::type]
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path`
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in scope
 
 error: unresolved link to `std::io::not::here`
   --> $DIR/intra-link-errors.rs:19:6
    |
 LL | /// [std::io::not::here]
-   |      ^^^^^^^^^^^^^^^^^^ the module `io` contains no item named `not`
+   |      ^^^^^^^^^^^^^^^^^^ no item named `not` in module `io`
 
 error: unresolved link to `std::io::not::here`
   --> $DIR/intra-link-errors.rs:23:6
    |
 LL | /// [type@std::io::not::here]
-   |      ^^^^^^^^^^^^^^^^^^^^^^^ the module `io` contains no item named `not`
+   |      ^^^^^^^^^^^^^^^^^^^^^^^ no item named `not` in module `io`
 
 error: unresolved link to `std::io::Error::x`
   --> $DIR/intra-link-errors.rs:27:6
diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr
index d946aa93980..d8afa9e7efd 100644
--- a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr
+++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr
@@ -2,7 +2,7 @@ error: unresolved link to `i`
   --> $DIR/intra-link-span-ice-55723.rs:9:10
    |
 LL | /// (arr[i])
-   |           ^ the module `intra_link_span_ice_55723` contains no item named `i`
+   |           ^ no item named `i` in scope
    |
 note: the lint level is defined here
   --> $DIR/intra-link-span-ice-55723.rs:1:9
diff --git a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr
index 76a2ac0c8cf..67c48378fd2 100644
--- a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr
+++ b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr
@@ -2,7 +2,7 @@ warning: unresolved link to `error`
   --> $DIR/intra-links-warning-crlf.rs:7:6
    |
 LL | /// [error]
-   |      ^^^^^ the module `intra_links_warning_crlf` contains no item named `error`
+   |      ^^^^^ no item named `error` in scope
    |
    = note: `#[warn(broken_intra_doc_links)]` on by default
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
@@ -11,7 +11,7 @@ warning: unresolved link to `error1`
   --> $DIR/intra-links-warning-crlf.rs:12:11
    |
 LL | /// docs [error1]
-   |           ^^^^^^ the module `intra_links_warning_crlf` contains no item named `error1`
+   |           ^^^^^^ no item named `error1` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -19,7 +19,7 @@ warning: unresolved link to `error2`
   --> $DIR/intra-links-warning-crlf.rs:15:11
    |
 LL | /// docs [error2]
-   |           ^^^^^^ the module `intra_links_warning_crlf` contains no item named `error2`
+   |           ^^^^^^ no item named `error2` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -27,7 +27,7 @@ warning: unresolved link to `error`
   --> $DIR/intra-links-warning-crlf.rs:23:20
    |
 LL |  * It also has an [error].
-   |                    ^^^^^ the module `intra_links_warning_crlf` contains no item named `error`
+   |                    ^^^^^ no item named `error` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr
index 09db465df59..4cdb8bbdde7 100644
--- a/src/test/rustdoc-ui/intra-links-warning.stderr
+++ b/src/test/rustdoc-ui/intra-links-warning.stderr
@@ -10,37 +10,37 @@ warning: unresolved link to `Bar::foo`
   --> $DIR/intra-links-warning.rs:3:35
    |
 LL |        //! Test with [Foo::baz], [Bar::foo], ...
-   |                                   ^^^^^^^^ the module `intra_links_warning` contains no item named `Bar`
+   |                                   ^^^^^^^^ no item named `Bar` in scope
 
 warning: unresolved link to `Uniooon::X`
   --> $DIR/intra-links-warning.rs:6:13
    |
 LL |      //! , [Uniooon::X] and [Qux::Z].
-   |             ^^^^^^^^^^ the module `intra_links_warning` contains no item named `Uniooon`
+   |             ^^^^^^^^^^ no item named `Uniooon` in scope
 
 warning: unresolved link to `Qux::Z`
   --> $DIR/intra-links-warning.rs:6:30
    |
 LL |      //! , [Uniooon::X] and [Qux::Z].
-   |                              ^^^^^^ the module `intra_links_warning` contains no item named `Qux`
+   |                              ^^^^^^ no item named `Qux` in scope
 
 warning: unresolved link to `Uniooon::X`
   --> $DIR/intra-links-warning.rs:10:14
    |
 LL |       //! , [Uniooon::X] and [Qux::Z].
-   |              ^^^^^^^^^^ the module `intra_links_warning` contains no item named `Uniooon`
+   |              ^^^^^^^^^^ no item named `Uniooon` in scope
 
 warning: unresolved link to `Qux::Z`
   --> $DIR/intra-links-warning.rs:10:31
    |
 LL |       //! , [Uniooon::X] and [Qux::Z].
-   |                               ^^^^^^ the module `intra_links_warning` contains no item named `Qux`
+   |                               ^^^^^^ no item named `Qux` in scope
 
 warning: unresolved link to `Qux:Y`
   --> $DIR/intra-links-warning.rs:14:13
    |
 LL |        /// [Qux:Y]
-   |             ^^^^^ the module `intra_links_warning` contains no item named `Qux:Y`
+   |             ^^^^^ no item named `Qux:Y` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -48,7 +48,7 @@ warning: unresolved link to `error`
   --> $DIR/intra-links-warning.rs:58:30
    |
 LL |  * time to introduce a link [error]*/
-   |                              ^^^^^ the module `intra_links_warning` contains no item named `error`
+   |                              ^^^^^ no item named `error` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -56,7 +56,7 @@ warning: unresolved link to `error`
   --> $DIR/intra-links-warning.rs:64:30
    |
 LL |  * time to introduce a link [error]
-   |                              ^^^^^ the module `intra_links_warning` contains no item named `error`
+   |                              ^^^^^ no item named `error` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -70,7 +70,7 @@ LL | #[doc = "single line [error]"]
            
            single line [error]
                         ^^^^^
-   = note: the module `intra_links_warning` contains no item named `error`
+   = note: no item named `error` in scope
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error`
@@ -83,7 +83,7 @@ LL | #[doc = "single line with \"escaping\" [error]"]
            
            single line with "escaping" [error]
                                         ^^^^^
-   = note: the module `intra_links_warning` contains no item named `error`
+   = note: no item named `error` in scope
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error`
@@ -98,14 +98,14 @@ LL | | /// [error]
            
            [error]
             ^^^^^
-   = note: the module `intra_links_warning` contains no item named `error`
+   = note: no item named `error` in scope
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error1`
   --> $DIR/intra-links-warning.rs:80:11
    |
 LL | /// docs [error1]
-   |           ^^^^^^ the module `intra_links_warning` contains no item named `error1`
+   |           ^^^^^^ no item named `error1` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -113,7 +113,7 @@ warning: unresolved link to `error2`
   --> $DIR/intra-links-warning.rs:82:11
    |
 LL | /// docs [error2]
-   |           ^^^^^^ the module `intra_links_warning` contains no item named `error2`
+   |           ^^^^^^ no item named `error2` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -121,7 +121,7 @@ warning: unresolved link to `BarA`
   --> $DIR/intra-links-warning.rs:21:10
    |
 LL | /// bar [BarA] bar
-   |          ^^^^ the module `intra_links_warning` contains no item named `BarA`
+   |          ^^^^ no item named `BarA` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -129,7 +129,7 @@ warning: unresolved link to `BarB`
   --> $DIR/intra-links-warning.rs:27:9
    |
 LL |  * bar [BarB] bar
-   |         ^^^^ the module `intra_links_warning` contains no item named `BarB`
+   |         ^^^^ no item named `BarB` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -137,7 +137,7 @@ warning: unresolved link to `BarC`
   --> $DIR/intra-links-warning.rs:34:6
    |
 LL | bar [BarC] bar
-   |      ^^^^ the module `intra_links_warning` contains no item named `BarC`
+   |      ^^^^ no item named `BarC` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -151,7 +151,7 @@ LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
            
            bar [BarD] bar
                 ^^^^
-   = note: the module `intra_links_warning` contains no item named `BarD`
+   = note: no item named `BarD` in scope
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `BarF`
@@ -167,7 +167,7 @@ LL | f!("Foo\nbar [BarF] bar\nbaz");
            
            bar [BarF] bar
                 ^^^^
-   = note: the module `intra_links_warning` contains no item named `BarF`
+   = note: no item named `BarF` in scope
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
    = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr
index 4e9134ea469..32be90193fe 100644
--- a/src/test/rustdoc-ui/lint-group.stderr
+++ b/src/test/rustdoc-ui/lint-group.stderr
@@ -32,7 +32,7 @@ error: unresolved link to `error`
   --> $DIR/lint-group.rs:9:29
    |
 LL | /// what up, let's make an [error]
-   |                             ^^^^^ the module `lint_group` contains no item named `error`
+   |                             ^^^^^ no item named `error` in scope
    |
 note: the lint level is defined here
   --> $DIR/lint-group.rs:7:9
diff --git a/src/test/ui/const-generics/issues/issue-75299.rs b/src/test/ui/const-generics/issues/issue-75299.rs
new file mode 100644
index 00000000000..23f30a1eea0
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-75299.rs
@@ -0,0 +1,11 @@
+// compile-flags: -Zmir-opt-level=3
+// run-pass
+
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+fn main() {
+    fn foo<const N: usize>() -> [u8; N] {
+        [0; N]
+    }
+    let _x = foo::<1>();
+}
diff --git a/src/test/ui/drop-bounds/drop-bounds-impl-drop.rs b/src/test/ui/drop-bounds/drop-bounds-impl-drop.rs
new file mode 100644
index 00000000000..063efc7b31a
--- /dev/null
+++ b/src/test/ui/drop-bounds/drop-bounds-impl-drop.rs
@@ -0,0 +1,14 @@
+// run-pass
+#![deny(drop_bounds)]
+// As a special exemption, `impl Drop` in the return position raises no error.
+// This allows a convenient way to return an unnamed drop guard.
+fn voldemort_type() -> impl Drop {
+  struct Voldemort;
+  impl Drop for Voldemort {
+    fn drop(&mut self) {}
+  }
+  Voldemort
+}
+fn main() {
+  let _ = voldemort_type();
+}
diff --git a/src/test/ui/drop-bounds/drop-bounds.rs b/src/test/ui/drop-bounds/drop-bounds.rs
new file mode 100644
index 00000000000..c73538278d3
--- /dev/null
+++ b/src/test/ui/drop-bounds/drop-bounds.rs
@@ -0,0 +1,19 @@
+#![deny(drop_bounds)]
+fn foo<T: Drop>() {} //~ ERROR
+fn bar<U>()
+where
+    U: Drop, //~ ERROR
+{
+}
+fn baz(_x: impl Drop) {} //~ ERROR
+struct Foo<T: Drop> { //~ ERROR
+  _x: T
+}
+struct Bar<U> where U: Drop { //~ ERROR
+  _x: U
+}
+trait Baz: Drop { //~ ERROR
+}
+impl<T: Drop> Baz for T { //~ ERROR
+}
+fn main() {}
diff --git a/src/test/ui/drop-bounds/drop-bounds.stderr b/src/test/ui/drop-bounds/drop-bounds.stderr
new file mode 100644
index 00000000000..15ba4c9a649
--- /dev/null
+++ b/src/test/ui/drop-bounds/drop-bounds.stderr
@@ -0,0 +1,50 @@
+error: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+  --> $DIR/drop-bounds.rs:2:11
+   |
+LL | fn foo<T: Drop>() {}
+   |           ^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/drop-bounds.rs:1:9
+   |
+LL | #![deny(drop_bounds)]
+   |         ^^^^^^^^^^^
+
+error: bounds on `U: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+  --> $DIR/drop-bounds.rs:5:8
+   |
+LL |     U: Drop,
+   |        ^^^^
+
+error: bounds on `impl Drop: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+  --> $DIR/drop-bounds.rs:8:17
+   |
+LL | fn baz(_x: impl Drop) {}
+   |                 ^^^^
+
+error: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+  --> $DIR/drop-bounds.rs:9:15
+   |
+LL | struct Foo<T: Drop> {
+   |               ^^^^
+
+error: bounds on `U: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+  --> $DIR/drop-bounds.rs:12:24
+   |
+LL | struct Bar<U> where U: Drop {
+   |                        ^^^^
+
+error: bounds on `Self: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+  --> $DIR/drop-bounds.rs:15:12
+   |
+LL | trait Baz: Drop {
+   |            ^^^^
+
+error: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+  --> $DIR/drop-bounds.rs:17:9
+   |
+LL | impl<T: Drop> Baz for T {
+   |         ^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/test/ui/error-codes/E0777.rs b/src/test/ui/error-codes/E0777.rs
new file mode 100644
index 00000000000..ff70f736866
--- /dev/null
+++ b/src/test/ui/error-codes/E0777.rs
@@ -0,0 +1,7 @@
+#[derive("Clone")] //~ ERROR E0777
+#[derive("Clone
+")]
+//~^^ ERROR E0777
+struct Foo;
+
+fn main() {}
diff --git a/src/test/ui/error-codes/E0777.stderr b/src/test/ui/error-codes/E0777.stderr
new file mode 100644
index 00000000000..ea73c58993e
--- /dev/null
+++ b/src/test/ui/error-codes/E0777.stderr
@@ -0,0 +1,21 @@
+error[E0777]: expected path to a trait, found literal
+  --> $DIR/E0777.rs:1:10
+   |
+LL | #[derive("Clone")]
+   |          ^^^^^^^
+   |
+   = help: try using `#[derive(Clone)]`
+
+error[E0777]: expected path to a trait, found literal
+  --> $DIR/E0777.rs:2:10
+   |
+LL |   #[derive("Clone
+   |  __________^
+LL | | ")]
+   | |_^
+   |
+   = help: for example, write `#[derive(Debug)]` for `Debug`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0777`.
diff --git a/src/test/ui/issues/issue-68951.rs b/src/test/ui/issues/issue-68951.rs
new file mode 100644
index 00000000000..1c1e92c5bbc
--- /dev/null
+++ b/src/test/ui/issues/issue-68951.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+fn main() {
+    let array = [0x42u8; 10];
+    for b in &array {
+        let lo = b & 0xf;
+        let hi = (b >> 4) & 0xf;
+    }
+}
diff --git a/src/test/ui/mir/issue-77359-simplify-arm-identity-.rs b/src/test/ui/mir/issue-77359-simplify-arm-identity.rs
index e58ba50a9e5..e58ba50a9e5 100644
--- a/src/test/ui/mir/issue-77359-simplify-arm-identity-.rs
+++ b/src/test/ui/mir/issue-77359-simplify-arm-identity.rs
diff --git a/src/test/ui/pattern/issue-66501.rs b/src/test/ui/pattern/issue-66501.rs
new file mode 100644
index 00000000000..ffcfd4ad83e
--- /dev/null
+++ b/src/test/ui/pattern/issue-66501.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![allow(unreachable_patterns)]
+
+fn main() {
+    const CONST: &[Option<()>; 1] = &[Some(())];
+    match &[Some(())] {
+        &[None] => {}
+        CONST => {}
+        &[Some(())] => {}
+    }
+}
diff --git a/src/test/ui/pattern/issue-72565.rs b/src/test/ui/pattern/issue-72565.rs
new file mode 100644
index 00000000000..1e262fd5067
--- /dev/null
+++ b/src/test/ui/pattern/issue-72565.rs
@@ -0,0 +1,8 @@
+const F: &'static dyn PartialEq<u32> = &7u32;
+
+fn main() {
+    let a: &dyn PartialEq<u32> = &7u32;
+    match a {
+        F => panic!(), //~ ERROR: `&dyn PartialEq<u32>` cannot be used in patterns
+    }
+}
diff --git a/src/test/ui/pattern/issue-72565.stderr b/src/test/ui/pattern/issue-72565.stderr
new file mode 100644
index 00000000000..2f82616b277
--- /dev/null
+++ b/src/test/ui/pattern/issue-72565.stderr
@@ -0,0 +1,8 @@
+error: `&dyn PartialEq<u32>` cannot be used in patterns
+  --> $DIR/issue-72565.rs:6:9
+   |
+LL |         F => panic!(),
+   |         ^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/simd/shuffle-not-out-of-bounds.rs b/src/test/ui/simd/shuffle-not-out-of-bounds.rs
new file mode 100644
index 00000000000..8a533453e75
--- /dev/null
+++ b/src/test/ui/simd/shuffle-not-out-of-bounds.rs
@@ -0,0 +1,191 @@
+// build-fail
+#![allow(non_camel_case_types)]
+#![feature(repr_simd, platform_intrinsics)]
+
+// Test for #73542 to verify out-of-bounds shuffle vectors do not compile.
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct u8x2(u8, u8);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct u8x4(u8, u8, u8, u8);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct u8x8(u8, u8, u8, u8, u8, u8, u8, u8);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct u8x16(
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct u8x32(
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct u8x64(
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+);
+
+// Test vectors by lane size. Since LLVM does not distinguish between a shuffle
+// over two f32s and a shuffle over two u64s, or any other such combination,
+// it is not necessary to test every possible vector, only lane counts.
+macro_rules! test_shuffle_lanes {
+    ($n:literal, $x:ident, $y:ident, $t:tt) => {
+        unsafe {
+                let shuffle: $x = {
+                    const ARR: [u32; $n] = {
+                        let mut arr = [0; $n];
+                        arr[0] = $n * 2;
+                        arr
+                    };
+                    extern "platform-intrinsic" {
+                        pub fn $y<T, U>(x: T, y: T, idx: [u32; $n]) -> U;
+                    }
+                    let vec1 = $x$t;
+                    let vec2 = $x$t;
+                    $y(vec1, vec2, ARR)
+                };
+        }
+    }
+}
+//~^^^^^ ERROR: invalid monomorphization of `simd_shuffle2` intrinsic
+//~| ERROR: invalid monomorphization of `simd_shuffle4` intrinsic
+//~| ERROR: invalid monomorphization of `simd_shuffle8` intrinsic
+//~| ERROR: invalid monomorphization of `simd_shuffle16` intrinsic
+//~| ERROR: invalid monomorphization of `simd_shuffle32` intrinsic
+//~| ERROR: invalid monomorphization of `simd_shuffle64` intrinsic
+// Because the test is mostly embedded in a macro, all the errors have the same origin point.
+// And unfortunately, standard comments, as in the UI test harness, disappear in macros!
+
+fn main() {
+    test_shuffle_lanes!(2, u8x2, simd_shuffle2, (2, 1));
+    test_shuffle_lanes!(4, u8x4, simd_shuffle4, (4, 3, 2, 1));
+    test_shuffle_lanes!(8, u8x8, simd_shuffle8, (8, 7, 6, 5, 4, 3, 2, 1));
+    test_shuffle_lanes!(16, u8x16, simd_shuffle16,
+        (16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
+    test_shuffle_lanes!(32, u8x32, simd_shuffle32,
+        (32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
+         15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
+    test_shuffle_lanes!(64, u8x64, simd_shuffle64,
+        (64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49,
+         48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33,
+         32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17,
+         16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
+}
diff --git a/src/test/ui/simd/shuffle-not-out-of-bounds.stderr b/src/test/ui/simd/shuffle-not-out-of-bounds.stderr
new file mode 100644
index 00000000000..4806f2ca27b
--- /dev/null
+++ b/src/test/ui/simd/shuffle-not-out-of-bounds.stderr
@@ -0,0 +1,76 @@
+error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: shuffle index #0 is out of bounds (limit 4)
+  --> $DIR/shuffle-not-out-of-bounds.rs:163:21
+   |
+LL |                     $y(vec1, vec2, ARR)
+   |                     ^^^^^^^^^^^^^^^^^^^
+...
+LL |     test_shuffle_lanes!(2, u8x2, simd_shuffle2, (2, 1));
+   |     ---------------------------------------------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: shuffle index #0 is out of bounds (limit 8)
+  --> $DIR/shuffle-not-out-of-bounds.rs:163:21
+   |
+LL |                     $y(vec1, vec2, ARR)
+   |                     ^^^^^^^^^^^^^^^^^^^
+...
+LL |     test_shuffle_lanes!(4, u8x4, simd_shuffle4, (4, 3, 2, 1));
+   |     ---------------------------------------------------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: shuffle index #0 is out of bounds (limit 16)
+  --> $DIR/shuffle-not-out-of-bounds.rs:163:21
+   |
+LL |                     $y(vec1, vec2, ARR)
+   |                     ^^^^^^^^^^^^^^^^^^^
+...
+LL |     test_shuffle_lanes!(8, u8x8, simd_shuffle8, (8, 7, 6, 5, 4, 3, 2, 1));
+   |     ---------------------------------------------------------------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0511]: invalid monomorphization of `simd_shuffle16` intrinsic: shuffle index #0 is out of bounds (limit 32)
+  --> $DIR/shuffle-not-out-of-bounds.rs:163:21
+   |
+LL |                       $y(vec1, vec2, ARR)
+   |                       ^^^^^^^^^^^^^^^^^^^
+...
+LL | /     test_shuffle_lanes!(16, u8x16, simd_shuffle16,
+LL | |         (16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
+   | |_________________________________________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0511]: invalid monomorphization of `simd_shuffle32` intrinsic: shuffle index #0 is out of bounds (limit 64)
+  --> $DIR/shuffle-not-out-of-bounds.rs:163:21
+   |
+LL |                       $y(vec1, vec2, ARR)
+   |                       ^^^^^^^^^^^^^^^^^^^
+...
+LL | /     test_shuffle_lanes!(32, u8x32, simd_shuffle32,
+LL | |         (32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
+LL | |          15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
+   | |_____________________________________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0511]: invalid monomorphization of `simd_shuffle64` intrinsic: shuffle index #0 is out of bounds (limit 128)
+  --> $DIR/shuffle-not-out-of-bounds.rs:163:21
+   |
+LL |                       $y(vec1, vec2, ARR)
+   |                       ^^^^^^^^^^^^^^^^^^^
+...
+LL | /     test_shuffle_lanes!(64, u8x64, simd_shuffle64,
+LL | |         (64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49,
+LL | |          48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33,
+LL | |          32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17,
+LL | |          16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
+   | |_________________________________________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0511`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-74244.rs b/src/test/ui/type-alias-impl-trait/issue-74244.rs
new file mode 100644
index 00000000000..bb4104b3d25
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-74244.rs
@@ -0,0 +1,20 @@
+#![feature(type_alias_impl_trait)]
+
+trait Allocator {
+    type Buffer;
+}
+
+struct DefaultAllocator;
+
+impl<T> Allocator for DefaultAllocator {
+    //~^ ERROR: the type parameter `T` is not constrained
+    type Buffer = ();
+}
+
+type A = impl Fn(<DefaultAllocator as Allocator>::Buffer);
+
+fn foo() -> A {
+    |_| ()
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-74244.stderr b/src/test/ui/type-alias-impl-trait/issue-74244.stderr
new file mode 100644
index 00000000000..ff6bacd277e
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-74244.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/issue-74244.rs:9:6
+   |
+LL | impl<T> Allocator for DefaultAllocator {
+   |      ^ unconstrained type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index c17a0e83330..c5884361dff 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -163,3 +163,12 @@ declare_deprecated_lint! {
     pub REGEX_MACRO,
     "the regex! macro has been removed from the regex crate in 2018"
 }
+
+declare_deprecated_lint! {
+    /// **What it does:** Nothing. This lint has been deprecated.
+    ///
+    /// **Deprecation reason:** This lint has been uplifted to rustc and is now called
+    /// `drop_bounds`.
+    pub DROP_BOUNDS,
+    "this lint has been uplifted to rustc and is now called `drop_bounds`"
+}
diff --git a/src/tools/clippy/clippy_lints/src/drop_bounds.rs b/src/tools/clippy/clippy_lints/src/drop_bounds.rs
deleted file mode 100644
index ec3b6afa630..00000000000
--- a/src/tools/clippy/clippy_lints/src/drop_bounds.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-use crate::utils::{match_def_path, paths, span_lint};
-use if_chain::if_chain;
-use rustc_hir::{GenericBound, GenericParam, WhereBoundPredicate, WherePredicate};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
-    /// **What it does:** Checks for generics with `std::ops::Drop` as bounds.
-    ///
-    /// **Why is this bad?** `Drop` bounds do not really accomplish anything.
-    /// A type may have compiler-generated drop glue without implementing the
-    /// `Drop` trait itself. The `Drop` trait also only has one method,
-    /// `Drop::drop`, and that function is by fiat not callable in user code.
-    /// So there is really no use case for using `Drop` in trait bounds.
-    ///
-    /// The most likely use case of a drop bound is to distinguish between types
-    /// that have destructors and types that don't. Combined with specialization,
-    /// a naive coder would write an implementation that assumed a type could be
-    /// trivially dropped, then write a specialization for `T: Drop` that actually
-    /// calls the destructor. Except that doing so is not correct; String, for
-    /// example, doesn't actually implement Drop, but because String contains a
-    /// Vec, assuming it can be trivially dropped will leak memory.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// fn foo<T: Drop>() {}
-    /// ```
-    /// Could be written as:
-    /// ```rust
-    /// fn foo<T>() {}
-    /// ```
-    pub DROP_BOUNDS,
-    correctness,
-    "bounds of the form `T: Drop` are useless"
-}
-
-const DROP_BOUNDS_SUMMARY: &str = "bounds of the form `T: Drop` are useless, \
-                                   use `std::mem::needs_drop` to detect if a type has drop glue";
-
-declare_lint_pass!(DropBounds => [DROP_BOUNDS]);
-
-impl<'tcx> LateLintPass<'tcx> for DropBounds {
-    fn check_generic_param(&mut self, cx: &LateContext<'tcx>, p: &'tcx GenericParam<'_>) {
-        for bound in p.bounds.iter() {
-            lint_bound(cx, bound);
-        }
-    }
-    fn check_where_predicate(&mut self, cx: &LateContext<'tcx>, p: &'tcx WherePredicate<'_>) {
-        if let WherePredicate::BoundPredicate(WhereBoundPredicate { bounds, .. }) = p {
-            for bound in *bounds {
-                lint_bound(cx, bound);
-            }
-        }
-    }
-}
-
-fn lint_bound<'tcx>(cx: &LateContext<'tcx>, bound: &'tcx GenericBound<'_>) {
-    if_chain! {
-        if let GenericBound::Trait(t, _) = bound;
-        if let Some(def_id) = t.trait_ref.path.res.opt_def_id();
-        if match_def_path(cx, def_id, &paths::DROP_TRAIT);
-        then {
-            span_lint(
-                cx,
-                DROP_BOUNDS,
-                t.span,
-                DROP_BOUNDS_SUMMARY
-            );
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index c3ff34e6e1e..70efdaeb9c6 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -179,7 +179,6 @@ mod derive;
 mod doc;
 mod double_comparison;
 mod double_parens;
-mod drop_bounds;
 mod drop_forget_ref;
 mod duration_subsec;
 mod else_if_without_else;
@@ -478,6 +477,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         "clippy::regex_macro",
         "the regex! macro has been removed from the regex crate in 2018",
     );
+    store.register_removed(
+        "clippy::drop_bounds",
+        "this lint has been uplifted to rustc and is now called `drop_bounds`",
+    );
     // end deprecated lints, do not remove this comment, it’s used in `update_lints`
 
     // begin register lints, do not remove this comment, it’s used in `update_lints`
@@ -532,7 +535,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &doc::NEEDLESS_DOCTEST_MAIN,
         &double_comparison::DOUBLE_COMPARISONS,
         &double_parens::DOUBLE_PARENS,
-        &drop_bounds::DROP_BOUNDS,
         &drop_forget_ref::DROP_COPY,
         &drop_forget_ref::DROP_REF,
         &drop_forget_ref::FORGET_COPY,
@@ -959,7 +961,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box strings::StringLitAsBytes);
     store.register_late_pass(|| box derive::Derive);
     store.register_late_pass(|| box types::CharLitAsU8);
-    store.register_late_pass(|| box drop_bounds::DropBounds);
     store.register_late_pass(|| box get_last_with_len::GetLastWithLen);
     store.register_late_pass(|| box drop_forget_ref::DropForgetRef);
     store.register_late_pass(|| box empty_enum::EmptyEnum);
@@ -1282,7 +1283,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&doc::NEEDLESS_DOCTEST_MAIN),
         LintId::of(&double_comparison::DOUBLE_COMPARISONS),
         LintId::of(&double_parens::DOUBLE_PARENS),
-        LintId::of(&drop_bounds::DROP_BOUNDS),
         LintId::of(&drop_forget_ref::DROP_COPY),
         LintId::of(&drop_forget_ref::DROP_REF),
         LintId::of(&drop_forget_ref::FORGET_COPY),
@@ -1714,7 +1714,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&copies::IF_SAME_THEN_ELSE),
         LintId::of(&derive::DERIVE_HASH_XOR_EQ),
         LintId::of(&derive::DERIVE_ORD_XOR_PARTIAL_ORD),
-        LintId::of(&drop_bounds::DROP_BOUNDS),
         LintId::of(&drop_forget_ref::DROP_COPY),
         LintId::of(&drop_forget_ref::DROP_REF),
         LintId::of(&drop_forget_ref::FORGET_COPY),
diff --git a/src/tools/clippy/clippy_lints/src/utils/paths.rs b/src/tools/clippy/clippy_lints/src/utils/paths.rs
index 1583afad208..be837a61dc0 100644
--- a/src/tools/clippy/clippy_lints/src/utils/paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/paths.rs
@@ -31,7 +31,6 @@ pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"];
 pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"];
 pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"];
 pub const DROP: [&str; 3] = ["core", "mem", "drop"];
-pub const DROP_TRAIT: [&str; 4] = ["core", "ops", "drop", "Drop"];
 pub const DURATION: [&str; 3] = ["core", "time", "Duration"];
 pub const EARLY_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "EarlyContext"];
 pub const EXIT: [&str; 3] = ["std", "process", "exit"];
diff --git a/src/tools/clippy/src/lintlist/mod.rs b/src/tools/clippy/src/lintlist/mod.rs
index 9603023ed06..f6d529de9a3 100644
--- a/src/tools/clippy/src/lintlist/mod.rs
+++ b/src/tools/clippy/src/lintlist/mod.rs
@@ -424,13 +424,6 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "double_parens",
     },
     Lint {
-        name: "drop_bounds",
-        group: "correctness",
-        desc: "bounds of the form `T: Drop` are useless",
-        deprecation: None,
-        module: "drop_bounds",
-    },
-    Lint {
         name: "drop_copy",
         group: "correctness",
         desc: "calls to `std::mem::drop` with a value that implements Copy",
diff --git a/src/tools/clippy/tests/ui/deprecated.rs b/src/tools/clippy/tests/ui/deprecated.rs
index 3eefb232780..9e32fe36ece 100644
--- a/src/tools/clippy/tests/ui/deprecated.rs
+++ b/src/tools/clippy/tests/ui/deprecated.rs
@@ -8,5 +8,6 @@
 #[warn(clippy::into_iter_on_array)]
 #[warn(clippy::unused_label)]
 #[warn(clippy::regex_macro)]
+#[warn(clippy::drop_bounds)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr
index a80e2bf31fe..d3400a7be09 100644
--- a/src/tools/clippy/tests/ui/deprecated.stderr
+++ b/src/tools/clippy/tests/ui/deprecated.stderr
@@ -60,11 +60,17 @@ error: lint `clippy::regex_macro` has been removed: `the regex! macro has been r
 LL | #[warn(clippy::regex_macro)]
    |        ^^^^^^^^^^^^^^^^^^^
 
+error: lint `clippy::drop_bounds` has been removed: `this lint has been uplifted to rustc and is now called `drop_bounds``
+  --> $DIR/deprecated.rs:11:8
+   |
+LL | #[warn(clippy::drop_bounds)]
+   |        ^^^^^^^^^^^^^^^^^^^
+
 error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon`
   --> $DIR/deprecated.rs:1:8
    |
 LL | #[warn(clippy::str_to_string)]
    |        ^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 11 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/drop_bounds.rs b/src/tools/clippy/tests/ui/drop_bounds.rs
deleted file mode 100644
index 6d6a9dc0783..00000000000
--- a/src/tools/clippy/tests/ui/drop_bounds.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#![allow(unused)]
-fn foo<T: Drop>() {}
-fn bar<T>()
-where
-    T: Drop,
-{
-}
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/drop_bounds.stderr b/src/tools/clippy/tests/ui/drop_bounds.stderr
deleted file mode 100644
index 8208c0ed7e3..00000000000
--- a/src/tools/clippy/tests/ui/drop_bounds.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error: bounds of the form `T: Drop` are useless, use `std::mem::needs_drop` to detect if a type has drop glue
-  --> $DIR/drop_bounds.rs:2:11
-   |
-LL | fn foo<T: Drop>() {}
-   |           ^^^^
-   |
-   = note: `#[deny(clippy::drop_bounds)]` on by default
-
-error: bounds of the form `T: Drop` are useless, use `std::mem::needs_drop` to detect if a type has drop glue
-  --> $DIR/drop_bounds.rs:5:8
-   |
-LL |     T: Drop,
-   |        ^^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 356705305d7..0c52fee68a9 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -116,7 +116,6 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
     "libz-sys",
     "lock_api",
     "log",
-    "log_settings",
     "maybe-uninit",
     "md-5",
     "measureme",