about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock4
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs11
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs15
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs6
-rw-r--r--compiler/rustc_errors/src/emitter.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs19
-rw-r--r--compiler/rustc_lint/src/late.rs6
-rw-r--r--compiler/rustc_middle/src/lint.rs3
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs58
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs18
-rw-r--r--compiler/rustc_resolve/Cargo.toml2
-rw-r--r--compiler/rustc_span/src/hygiene.rs4
-rw-r--r--compiler/rustc_span/src/lib.rs6
-rw-r--r--library/core/src/slice/mod.rs7
-rw-r--r--library/core/src/slice/select.rs302
-rw-r--r--library/core/src/slice/sort.rs142
-rw-r--r--src/doc/rustdoc/src/how-to-write-documentation.md6
-rw-r--r--src/tools/miri/tests/fail/terminate-terminator.rs2
-rw-r--r--src/tools/miri/tests/fail/terminate-terminator.stderr11
-rw-r--r--tests/rustdoc-gui/highlight-colors.goml84
-rw-r--r--tests/rustdoc-ui/unescaped_backticks.rs12
-rw-r--r--tests/rustdoc-ui/unescaped_backticks.stderr14
-rw-r--r--tests/rustdoc/strikethrough-in-summary.rs6
-rw-r--r--tests/rustdoc/test-strikethrough.rs13
-rw-r--r--tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs72
-rw-r--r--tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr209
-rw-r--r--tests/ui/impl-trait/arg-position-impl-trait-too-long.rs22
-rw-r--r--tests/ui/impl-trait/arg-position-impl-trait-too-long.stderr22
-rw-r--r--tests/ui/lint/lint-attr-everywhere-early.rs8
-rw-r--r--tests/ui/lint/lint-attr-everywhere-early.stderr48
-rw-r--r--tests/ui/lint/lint-attr-everywhere-late.rs5
-rw-r--r--tests/ui/lint/lint-attr-everywhere-late.stderr56
-rw-r--r--tests/ui/lint/lint-match-arms-2.rs24
-rw-r--r--tests/ui/lint/lint-match-arms-2.stderr29
37 files changed, 856 insertions, 411 deletions
diff --git a/Cargo.lock b/Cargo.lock
index c7f39357534..0369442f11c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2779,9 +2779,9 @@ dependencies = [
 
 [[package]]
 name = "pulldown-cmark"
-version = "0.9.2"
+version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63"
+checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998"
 dependencies = [
  "bitflags",
  "memchr",
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 211f5cb0a2a..8d4f96639ef 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1425,7 +1425,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             DefPathData::ImplTrait,
                             span,
                         );
-                        let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
+
+                        // HACK: pprust breaks strings with newlines when the type
+                        // gets too long. We don't want these to show up in compiler
+                        // output or built artifacts, so replace them here...
+                        // Perhaps we should instead format APITs more robustly.
+                        let ident = Ident::from_str_and_span(
+                            &pprust::ty_to_string(t).replace('\n', " "),
+                            span,
+                        );
+
                         let (param, bounds, path) = self.lower_universal_param_and_bounds(
                             *def_node_id,
                             span,
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index ccb3a0c4f27..5eaa988dd09 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -413,11 +413,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
 
     // Note: must be kept in sync with get_caller_location from cg_ssa
     pub(crate) fn get_caller_location(&mut self, mut source_info: mir::SourceInfo) -> CValue<'tcx> {
-        let span_to_caller_location = |fx: &mut FunctionCx<'_, '_, 'tcx>, mut span: Span| {
-            // Remove `Inlined` marks as they pollute `expansion_cause`.
-            while span.is_inlined() {
-                span.remove_mark();
-            }
+        let span_to_caller_location = |fx: &mut FunctionCx<'_, '_, 'tcx>, span: Span| {
             let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
             let caller = fx.tcx.sess.source_map().lookup_char_pos(topmost.lo());
             let const_loc = fx.tcx.const_caller_location((
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 1f5f5b69d4d..d516ac4ebb7 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -1450,11 +1450,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     ) -> OperandRef<'tcx, Bx::Value> {
         let tcx = bx.tcx();
 
-        let mut span_to_caller_location = |mut span: Span| {
-            // Remove `Inlined` marks as they pollute `expansion_cause`.
-            while span.is_inlined() {
-                span.remove_mark();
-            }
+        let mut span_to_caller_location = |span: Span| {
             let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
             let caller = tcx.sess.source_map().lookup_char_pos(topmost.lo());
             let const_loc = tcx.const_caller_location((
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 040eba10eb4..7e94578003e 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -949,7 +949,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // This deliberately does *not* honor `requires_caller_location` since it is used for much
         // more than just panics.
         for frame in stack.iter().rev() {
-            let span = frame.current_span();
+            let span = match frame.loc {
+                Left(loc) => {
+                    // If the stacktrace passes through MIR-inlined source scopes, add them.
+                    let mir::SourceInfo { mut span, scope } = *frame.body.source_info(loc);
+                    let mut scope_data = &frame.body.source_scopes[scope];
+                    while let Some((instance, call_span)) = scope_data.inlined {
+                        frames.push(FrameInfo { span, instance });
+                        span = call_span;
+                        scope_data = &frame.body.source_scopes[scope_data.parent_scope.unwrap()];
+                    }
+                    span
+                }
+                Right(span) => span,
+            };
             frames.push(FrameInfo { span, instance: frame.instance });
         }
         trace!("generate stacktrace: {:#?}", frames);
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
index 3701eb93ec8..df5b581000b 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
@@ -111,11 +111,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         location
     }
 
-    pub(crate) fn location_triple_for_span(&self, mut span: Span) -> (Symbol, u32, u32) {
-        // Remove `Inlined` marks as they pollute `expansion_cause`.
-        while span.is_inlined() {
-            span.remove_mark();
-        }
+    pub(crate) fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) {
         let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
         let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
         (
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 6d944e51314..e8cd7eaa60f 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -332,7 +332,7 @@ pub trait Emitter: Translate {
 
                     // Skip past non-macro entries, just in case there
                     // are some which do actually involve macros.
-                    ExpnKind::Inlined | ExpnKind::Desugaring(..) | ExpnKind::AstPass(..) => None,
+                    ExpnKind::Desugaring(..) | ExpnKind::AstPass(..) => None,
 
                     ExpnKind::Macro(macro_kind, name) => Some((macro_kind, name)),
                 }
@@ -403,7 +403,7 @@ pub trait Emitter: Translate {
                     continue;
                 }
 
-                if always_backtrace && !matches!(trace.kind, ExpnKind::Inlined) {
+                if always_backtrace {
                     new_labels.push((
                         trace.def_site,
                         format!(
@@ -442,7 +442,6 @@ pub trait Emitter: Translate {
                             "this derive macro expansion".into()
                         }
                         ExpnKind::Macro(MacroKind::Bang, _) => "this macro invocation".into(),
-                        ExpnKind::Inlined => "this inlined function call".into(),
                         ExpnKind::Root => "the crate root".into(),
                         ExpnKind::AstPass(kind) => kind.descr().into(),
                         ExpnKind::Desugaring(kind) => {
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 94b6a0f8f47..e14e8ac2ce0 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -438,12 +438,19 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                         // to borrow discr.
                         needs_to_be_read = true;
                     }
-                    PatKind::Or(_)
-                    | PatKind::Box(_)
-                    | PatKind::Slice(..)
-                    | PatKind::Ref(..)
-                    | PatKind::Wild => {
-                        // If the PatKind is Or, Box, Slice or Ref, the decision is made later
+                    PatKind::Slice(lhs, wild, rhs) => {
+                        // We don't need to test the length if the pattern is `[..]`
+                        if matches!((lhs, wild, rhs), (&[], Some(_), &[]))
+                            // Arrays have a statically known size, so
+                            // there is no need to read their length
+                            || discr_place.place.base_ty.is_array()
+                        {
+                        } else {
+                            needs_to_be_read = true;
+                        }
+                    }
+                    PatKind::Or(_) | PatKind::Box(_) | PatKind::Ref(..) | PatKind::Wild => {
+                        // If the PatKind is Or, Box, or Ref, the decision is made later
                         // as these patterns contains subpatterns
                         // If the PatKind is Wild, the decision is made based on the other patterns being
                         // examined
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index c9781a72704..8a4a451f8a8 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -240,8 +240,10 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
     }
 
     fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) {
-        lint_callback!(self, check_arm, a);
-        hir_visit::walk_arm(self, a);
+        self.with_lint_attrs(a.hir_id, |cx| {
+            lint_callback!(cx, check_arm, a);
+            hir_visit::walk_arm(cx, a);
+        })
     }
 
     fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index c266584ac28..14343ac1108 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -468,8 +468,7 @@ pub fn struct_lint_level(
 pub fn in_external_macro(sess: &Session, span: Span) -> bool {
     let expn_data = span.ctxt().outer_expn_data();
     match expn_data.kind {
-        ExpnKind::Inlined
-        | ExpnKind::Root
+        ExpnKind::Root
         | ExpnKind::Desugaring(
             DesugaringKind::ForLoop | DesugaringKind::WhileLoop | DesugaringKind::OpaqueTy,
         ) => false,
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 73f435d4840..a8d0dca37ff 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2488,9 +2488,7 @@ impl<'tcx> TyCtxt<'tcx> {
             && if self.features().collapse_debuginfo {
                 span.in_macro_expansion_with_collapse_debuginfo()
             } else {
-                // Inlined spans should not be collapsed as that leads to all of the
-                // inlined code being attributed to the inline callsite.
-                span.from_expansion() && !span.is_inlined()
+                span.from_expansion()
             }
     }
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 5559e8b3940..c11a4f7229d 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -90,35 +90,34 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> {
 
     #[instrument(level = "trace", skip(self))]
     fn visit_arm(&mut self, arm: &Arm<'tcx>) {
-        match arm.guard {
-            Some(Guard::If(expr)) => {
-                self.with_let_source(LetSource::IfLetGuard, |this| {
-                    this.visit_expr(&this.thir[expr])
-                });
-            }
-            Some(Guard::IfLet(ref pat, expr)) => {
-                self.with_let_source(LetSource::IfLetGuard, |this| {
-                    this.check_let(pat, expr, LetSource::IfLetGuard, pat.span);
-                    this.visit_pat(pat);
-                    this.visit_expr(&this.thir[expr]);
-                });
+        self.with_lint_level(arm.lint_level, |this| {
+            match arm.guard {
+                Some(Guard::If(expr)) => {
+                    this.with_let_source(LetSource::IfLetGuard, |this| {
+                        this.visit_expr(&this.thir[expr])
+                    });
+                }
+                Some(Guard::IfLet(ref pat, expr)) => {
+                    this.with_let_source(LetSource::IfLetGuard, |this| {
+                        this.check_let(pat, expr, LetSource::IfLetGuard, pat.span);
+                        this.visit_pat(pat);
+                        this.visit_expr(&this.thir[expr]);
+                    });
+                }
+                None => {}
             }
-            None => {}
-        }
-        self.visit_pat(&arm.pattern);
-        self.visit_expr(&self.thir[arm.body]);
+            this.visit_pat(&arm.pattern);
+            this.visit_expr(&self.thir[arm.body]);
+        });
     }
 
     #[instrument(level = "trace", skip(self))]
     fn visit_expr(&mut self, ex: &Expr<'tcx>) {
         match ex.kind {
             ExprKind::Scope { value, lint_level, .. } => {
-                let old_lint_level = self.lint_level;
-                if let LintLevel::Explicit(hir_id) = lint_level {
-                    self.lint_level = hir_id;
-                }
-                self.visit_expr(&self.thir[value]);
-                self.lint_level = old_lint_level;
+                self.with_lint_level(lint_level, |this| {
+                    this.visit_expr(&this.thir[value]);
+                });
                 return;
             }
             ExprKind::If { cond, then, else_opt, if_then_scope: _ } => {
@@ -190,6 +189,17 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
         self.let_source = old_let_source;
     }
 
+    fn with_lint_level(&mut self, new_lint_level: LintLevel, f: impl FnOnce(&mut Self)) {
+        if let LintLevel::Explicit(hir_id) = new_lint_level {
+            let old_lint_level = self.lint_level;
+            self.lint_level = hir_id;
+            f(self);
+            self.lint_level = old_lint_level;
+        } else {
+            f(self);
+        }
+    }
+
     fn check_patterns(&self, pat: &Pat<'tcx>, rf: RefutableFlag) {
         pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat));
         check_for_bindings_named_same_as_variants(self, pat, rf);
@@ -236,7 +246,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
         for &arm in arms {
             // Check the arm for some things unrelated to exhaustiveness.
             let arm = &self.thir.arms[arm];
-            self.check_patterns(&arm.pattern, Refutable);
+            self.with_lint_level(arm.lint_level, |this| {
+                this.check_patterns(&arm.pattern, Refutable);
+            });
         }
 
         let tarms: Vec<_> = arms
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 6c2e22a70b9..1748b1bf4a0 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -10,7 +10,6 @@ use rustc_middle::mir::*;
 use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
 use rustc_session::config::OptLevel;
-use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span};
 use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
 use rustc_target::spec::abi::Abi;
 
@@ -551,16 +550,6 @@ impl<'tcx> Inliner<'tcx> {
                 // Copy the arguments if needed.
                 let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, &callee_body);
 
-                let mut expn_data = ExpnData::default(
-                    ExpnKind::Inlined,
-                    callsite.source_info.span,
-                    self.tcx.sess.edition(),
-                    None,
-                    None,
-                );
-                expn_data.def_site = callee_body.span;
-                let expn_data =
-                    self.tcx.with_stable_hashing_context(|hcx| LocalExpnId::fresh(expn_data, hcx));
                 let mut integrator = Integrator {
                     args: &args,
                     new_locals: Local::new(caller_body.local_decls.len())..,
@@ -572,7 +561,6 @@ impl<'tcx> Inliner<'tcx> {
                     cleanup_block: unwind,
                     in_cleanup_block: false,
                     tcx: self.tcx,
-                    expn_data,
                     always_live_locals: BitSet::new_filled(callee_body.local_decls.len()),
                 };
 
@@ -956,7 +944,6 @@ struct Integrator<'a, 'tcx> {
     cleanup_block: UnwindAction,
     in_cleanup_block: bool,
     tcx: TyCtxt<'tcx>,
-    expn_data: LocalExpnId,
     always_live_locals: BitSet<Local>,
 }
 
@@ -1042,11 +1029,6 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
         *scope = self.map_scope(*scope);
     }
 
-    fn visit_span(&mut self, span: &mut Span) {
-        // Make sure that all spans track the fact that they were inlined.
-        *span = span.fresh_expansion(self.expn_data);
-    }
-
     fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
         self.in_cleanup_block = data.is_cleanup;
         self.super_basic_block_data(block, data);
diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml
index 1c16d85f1b9..46da0aa2853 100644
--- a/compiler/rustc_resolve/Cargo.toml
+++ b/compiler/rustc_resolve/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2021"
 
 [dependencies]
 bitflags = "1.2.1"
-pulldown-cmark = { version = "0.9.2", default-features = false }
+pulldown-cmark = { version = "0.9.3", default-features = false }
 rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index c669b64dd2c..6755657c727 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -320,7 +320,6 @@ impl ExpnId {
             // Stop going up the backtrace once include! is encountered
             if expn_data.is_root()
                 || expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include)
-                || expn_data.kind == ExpnKind::Inlined
             {
                 break;
             }
@@ -1058,8 +1057,6 @@ pub enum ExpnKind {
     AstPass(AstPass),
     /// Desugaring done by the compiler during HIR lowering.
     Desugaring(DesugaringKind),
-    /// MIR inlining
-    Inlined,
 }
 
 impl ExpnKind {
@@ -1073,7 +1070,6 @@ impl ExpnKind {
             },
             ExpnKind::AstPass(kind) => kind.descr().to_string(),
             ExpnKind::Desugaring(kind) => format!("desugaring of {}", kind.descr()),
-            ExpnKind::Inlined => "inlined source".to_string(),
         }
     }
 }
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 3d3833dfdab..eae3f0fa041 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -594,12 +594,6 @@ impl Span {
         matches!(outer_expn.kind, ExpnKind::Macro(..)) && outer_expn.collapse_debuginfo
     }
 
-    /// Returns `true` if this span comes from MIR inlining.
-    pub fn is_inlined(self) -> bool {
-        let outer_expn = self.ctxt().outer_expn_data();
-        matches!(outer_expn.kind, ExpnKind::Inlined)
-    }
-
     /// Returns `true` if `span` originates in a derive-macro's expansion.
     pub fn in_derive_expansion(self) -> bool {
         matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index c787b7288b0..bd1b16e8d73 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -42,6 +42,7 @@ mod index;
 mod iter;
 mod raw;
 mod rotate;
+mod select;
 mod specialize;
 
 #[unstable(feature = "str_internals", issue = "none")]
@@ -3034,7 +3035,7 @@ impl<T> [T] {
     where
         T: Ord,
     {
-        sort::partition_at_index(self, index, T::lt)
+        select::partition_at_index(self, index, T::lt)
     }
 
     /// Reorder the slice with a comparator function such that the element at `index` is at its
@@ -3089,7 +3090,7 @@ impl<T> [T] {
     where
         F: FnMut(&T, &T) -> Ordering,
     {
-        sort::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less)
+        select::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less)
     }
 
     /// Reorder the slice with a key extraction function such that the element at `index` is at its
@@ -3145,7 +3146,7 @@ impl<T> [T] {
         F: FnMut(&T) -> K,
         K: Ord,
     {
-        sort::partition_at_index(self, index, |a: &T, b: &T| f(a).lt(&f(b)))
+        select::partition_at_index(self, index, |a: &T, b: &T| f(a).lt(&f(b)))
     }
 
     /// Moves all consecutive repeated elements to the end of the slice according to the
diff --git a/library/core/src/slice/select.rs b/library/core/src/slice/select.rs
new file mode 100644
index 00000000000..ffc193578e0
--- /dev/null
+++ b/library/core/src/slice/select.rs
@@ -0,0 +1,302 @@
+//! Slice selection
+//!
+//! This module contains the implementation for `slice::select_nth_unstable`.
+//! It uses an introselect algorithm based on Orson Peters' pattern-defeating quicksort,
+//! published at: <https://github.com/orlp/pdqsort>
+//!
+//! The fallback algorithm used for introselect is Median of Medians using Tukey's Ninther
+//! for pivot selection. Using this as a fallback ensures O(n) worst case running time with
+//! better performance than one would get using heapsort as fallback.
+
+use crate::cmp;
+use crate::mem::{self, SizedTypeProperties};
+use crate::slice::sort::{
+    break_patterns, choose_pivot, insertion_sort_shift_left, partition, partition_equal,
+};
+
+// For slices of up to this length it's probably faster to simply sort them.
+// Defined at the module scope because it's used in multiple functions.
+const MAX_INSERTION: usize = 10;
+
+fn partition_at_index_loop<'a, T, F>(
+    mut v: &'a mut [T],
+    mut index: usize,
+    is_less: &mut F,
+    mut pred: Option<&'a T>,
+) where
+    F: FnMut(&T, &T) -> bool,
+{
+    // Limit the amount of iterations and fall back to fast deterministic selection
+    // to ensure O(n) worst case running time. This limit needs to be constant, because
+    // using `ilog2(len)` like in `sort` would result in O(n log n) time complexity.
+    // The exact value of the limit is chosen somewhat arbitrarily, but for most inputs bad pivot
+    // selections should be relatively rare, so the limit usually shouldn't be reached
+    // anyways.
+    let mut limit = 16;
+
+    // True if the last partitioning was reasonably balanced.
+    let mut was_balanced = true;
+
+    loop {
+        if v.len() <= MAX_INSERTION {
+            if v.len() > 1 {
+                insertion_sort_shift_left(v, 1, is_less);
+            }
+            return;
+        }
+
+        if limit == 0 {
+            median_of_medians(v, is_less, index);
+            return;
+        }
+
+        // If the last partitioning was imbalanced, try breaking patterns in the slice by shuffling
+        // some elements around. Hopefully we'll choose a better pivot this time.
+        if !was_balanced {
+            break_patterns(v);
+            limit -= 1;
+        }
+
+        // Choose a pivot
+        let (pivot, _) = choose_pivot(v, is_less);
+
+        // If the chosen pivot is equal to the predecessor, then it's the smallest element in the
+        // slice. Partition the slice into elements equal to and elements greater than the pivot.
+        // This case is usually hit when the slice contains many duplicate elements.
+        if let Some(p) = pred {
+            if !is_less(p, &v[pivot]) {
+                let mid = partition_equal(v, pivot, is_less);
+
+                // If we've passed our index, then we're good.
+                if mid > index {
+                    return;
+                }
+
+                // Otherwise, continue sorting elements greater than the pivot.
+                v = &mut v[mid..];
+                index = index - mid;
+                pred = None;
+                continue;
+            }
+        }
+
+        let (mid, _) = partition(v, pivot, is_less);
+        was_balanced = cmp::min(mid, v.len() - mid) >= v.len() / 8;
+
+        // Split the slice into `left`, `pivot`, and `right`.
+        let (left, right) = v.split_at_mut(mid);
+        let (pivot, right) = right.split_at_mut(1);
+        let pivot = &pivot[0];
+
+        if mid < index {
+            v = right;
+            index = index - mid - 1;
+            pred = Some(pivot);
+        } else if mid > index {
+            v = left;
+        } else {
+            // If mid == index, then we're done, since partition() guaranteed that all elements
+            // after mid are greater than or equal to mid.
+            return;
+        }
+    }
+}
+
+/// Helper function that returns the index of the minimum element in the slice using the given
+/// comparator function
+fn min_index<T, F: FnMut(&T, &T) -> bool>(slice: &[T], is_less: &mut F) -> Option<usize> {
+    slice
+        .iter()
+        .enumerate()
+        .reduce(|acc, t| if is_less(t.1, acc.1) { t } else { acc })
+        .map(|(i, _)| i)
+}
+
+/// Helper function that returns the index of the maximum element in the slice using the given
+/// comparator function
+fn max_index<T, F: FnMut(&T, &T) -> bool>(slice: &[T], is_less: &mut F) -> Option<usize> {
+    slice
+        .iter()
+        .enumerate()
+        .reduce(|acc, t| if is_less(acc.1, t.1) { t } else { acc })
+        .map(|(i, _)| i)
+}
+
+/// Reorder the slice such that the element at `index` is at its final sorted position.
+pub fn partition_at_index<T, F>(
+    v: &mut [T],
+    index: usize,
+    mut is_less: F,
+) -> (&mut [T], &mut T, &mut [T])
+where
+    F: FnMut(&T, &T) -> bool,
+{
+    if index >= v.len() {
+        panic!("partition_at_index index {} greater than length of slice {}", index, v.len());
+    }
+
+    if T::IS_ZST {
+        // Sorting has no meaningful behavior on zero-sized types. Do nothing.
+    } else if index == v.len() - 1 {
+        // Find max element and place it in the last position of the array. We're free to use
+        // `unwrap()` here because we know v must not be empty.
+        let max_idx = max_index(v, &mut is_less).unwrap();
+        v.swap(max_idx, index);
+    } else if index == 0 {
+        // Find min element and place it in the first position of the array. We're free to use
+        // `unwrap()` here because we know v must not be empty.
+        let min_idx = min_index(v, &mut is_less).unwrap();
+        v.swap(min_idx, index);
+    } else {
+        partition_at_index_loop(v, index, &mut is_less, None);
+    }
+
+    let (left, right) = v.split_at_mut(index);
+    let (pivot, right) = right.split_at_mut(1);
+    let pivot = &mut pivot[0];
+    (left, pivot, right)
+}
+
+/// Selection algorithm to select the k-th element from the slice in guaranteed O(n) time.
+/// This is essentially a quickselect that uses Tukey's Ninther for pivot selection
+fn median_of_medians<T, F: FnMut(&T, &T) -> bool>(mut v: &mut [T], is_less: &mut F, mut k: usize) {
+    // Since this function isn't public, it should never be called with an out-of-bounds index.
+    debug_assert!(k < v.len());
+
+    // If T is as ZST, `partition_at_index` will already return early.
+    debug_assert!(!T::IS_ZST);
+
+    // We now know that `k < v.len() <= isize::MAX`
+    loop {
+        if v.len() <= MAX_INSERTION {
+            if v.len() > 1 {
+                insertion_sort_shift_left(v, 1, is_less);
+            }
+            return;
+        }
+
+        // `median_of_{minima,maxima}` can't handle the extreme cases of the first/last element,
+        // so we catch them here and just do a linear search.
+        if k == v.len() - 1 {
+            // Find max element and place it in the last position of the array. We're free to use
+            // `unwrap()` here because we know v must not be empty.
+            let max_idx = max_index(v, is_less).unwrap();
+            v.swap(max_idx, k);
+            return;
+        } else if k == 0 {
+            // Find min element and place it in the first position of the array. We're free to use
+            // `unwrap()` here because we know v must not be empty.
+            let min_idx = min_index(v, is_less).unwrap();
+            v.swap(min_idx, k);
+            return;
+        }
+
+        let p = median_of_ninthers(v, is_less);
+
+        if p == k {
+            return;
+        } else if p > k {
+            v = &mut v[..p];
+        } else {
+            // Since `p < k < v.len()`, `p + 1` doesn't overflow and is
+            // a valid index into the slice.
+            v = &mut v[p + 1..];
+            k -= p + 1;
+        }
+    }
+}
+
+// Optimized for when `k` lies somewhere in the middle of the slice. Selects a pivot
+// as close as possible to the median of the slice. For more details on how the algorithm
+// operates, refer to the paper <https://drops.dagstuhl.de/opus/volltexte/2017/7612/pdf/LIPIcs-SEA-2017-24.pdf>.
+fn median_of_ninthers<T, F: FnMut(&T, &T) -> bool>(v: &mut [T], is_less: &mut F) -> usize {
+    // use `saturating_mul` so the multiplication doesn't overflow on 16-bit platforms.
+    let frac = if v.len() <= 1024 {
+        v.len() / 12
+    } else if v.len() <= 128_usize.saturating_mul(1024) {
+        v.len() / 64
+    } else {
+        v.len() / 1024
+    };
+
+    let pivot = frac / 2;
+    let lo = v.len() / 2 - pivot;
+    let hi = frac + lo;
+    let gap = (v.len() - 9 * frac) / 4;
+    let mut a = lo - 4 * frac - gap;
+    let mut b = hi + gap;
+    for i in lo..hi {
+        ninther(v, is_less, a, i - frac, b, a + 1, i, b + 1, a + 2, i + frac, b + 2);
+        a += 3;
+        b += 3;
+    }
+
+    median_of_medians(&mut v[lo..lo + frac], is_less, pivot);
+    partition(v, lo + pivot, is_less).0
+}
+
+/// Moves around the 9 elements at the indices a..i, such that
+/// `v[d]` contains the median of the 9 elements and the other
+/// elements are partitioned around it.
+fn ninther<T, F: FnMut(&T, &T) -> bool>(
+    v: &mut [T],
+    is_less: &mut F,
+    a: usize,
+    mut b: usize,
+    c: usize,
+    mut d: usize,
+    e: usize,
+    mut f: usize,
+    g: usize,
+    mut h: usize,
+    i: usize,
+) {
+    b = median_idx(v, is_less, a, b, c);
+    h = median_idx(v, is_less, g, h, i);
+    if is_less(&v[h], &v[b]) {
+        mem::swap(&mut b, &mut h);
+    }
+    if is_less(&v[f], &v[d]) {
+        mem::swap(&mut d, &mut f);
+    }
+    if is_less(&v[e], &v[d]) {
+        // do nothing
+    } else if is_less(&v[f], &v[e]) {
+        d = f;
+    } else {
+        if is_less(&v[e], &v[b]) {
+            v.swap(e, b);
+        } else if is_less(&v[h], &v[e]) {
+            v.swap(e, h);
+        }
+        return;
+    }
+    if is_less(&v[d], &v[b]) {
+        d = b;
+    } else if is_less(&v[h], &v[d]) {
+        d = h;
+    }
+
+    v.swap(d, e);
+}
+
+/// returns the index pointing to the median of the 3
+/// elements `v[a]`, `v[b]` and `v[c]`
+fn median_idx<T, F: FnMut(&T, &T) -> bool>(
+    v: &[T],
+    is_less: &mut F,
+    mut a: usize,
+    b: usize,
+    mut c: usize,
+) -> usize {
+    if is_less(&v[c], &v[a]) {
+        mem::swap(&mut a, &mut c);
+    }
+    if is_less(&v[c], &v[b]) {
+        return c;
+    }
+    if is_less(&v[b], &v[a]) {
+        return a;
+    }
+    b
+}
diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs
index eb8595ca90d..db76d26257a 100644
--- a/library/core/src/slice/sort.rs
+++ b/library/core/src/slice/sort.rs
@@ -145,7 +145,7 @@ where
 /// Never inline this function to avoid code bloat. It still optimizes nicely and has practically no
 /// performance impact. Even improving performance in some cases.
 #[inline(never)]
-fn insertion_sort_shift_left<T, F>(v: &mut [T], offset: usize, is_less: &mut F)
+pub(super) fn insertion_sort_shift_left<T, F>(v: &mut [T], offset: usize, is_less: &mut F)
 where
     F: FnMut(&T, &T) -> bool,
 {
@@ -557,7 +557,7 @@ where
 ///
 /// 1. Number of elements smaller than `v[pivot]`.
 /// 2. True if `v` was already partitioned.
-fn partition<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> (usize, bool)
+pub(super) fn partition<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> (usize, bool)
 where
     F: FnMut(&T, &T) -> bool,
 {
@@ -612,7 +612,7 @@ where
 ///
 /// Returns the number of elements equal to the pivot. It is assumed that `v` does not contain
 /// elements smaller than the pivot.
-fn partition_equal<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> usize
+pub(super) fn partition_equal<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> usize
 where
     F: FnMut(&T, &T) -> bool,
 {
@@ -670,7 +670,7 @@ where
 /// Scatters some elements around in an attempt to break patterns that might cause imbalanced
 /// partitions in quicksort.
 #[cold]
-fn break_patterns<T>(v: &mut [T]) {
+pub(super) fn break_patterns<T>(v: &mut [T]) {
     let len = v.len();
     if len >= 8 {
         let mut seed = len;
@@ -719,7 +719,7 @@ fn break_patterns<T>(v: &mut [T]) {
 /// Chooses a pivot in `v` and returns the index and `true` if the slice is likely already sorted.
 ///
 /// Elements in `v` might be reordered in the process.
-fn choose_pivot<T, F>(v: &mut [T], is_less: &mut F) -> (usize, bool)
+pub(super) fn choose_pivot<T, F>(v: &mut [T], is_less: &mut F) -> (usize, bool)
 where
     F: FnMut(&T, &T) -> bool,
 {
@@ -897,138 +897,6 @@ where
     recurse(v, &mut is_less, None, limit);
 }
 
-fn partition_at_index_loop<'a, T, F>(
-    mut v: &'a mut [T],
-    mut index: usize,
-    is_less: &mut F,
-    mut pred: Option<&'a T>,
-) where
-    F: FnMut(&T, &T) -> bool,
-{
-    // Limit the amount of iterations and fall back to heapsort, similarly to `slice::sort_unstable`.
-    // This lowers the worst case running time from O(n^2) to O(n log n).
-    // FIXME: Investigate whether it would be better to use something like Median of Medians
-    // or Fast Deterministic Selection to guarantee O(n) worst case.
-    let mut limit = usize::BITS - v.len().leading_zeros();
-
-    // True if the last partitioning was reasonably balanced.
-    let mut was_balanced = true;
-
-    loop {
-        let len = v.len();
-
-        // For slices of up to this length it's probably faster to simply sort them.
-        const MAX_INSERTION: usize = 10;
-        if len <= MAX_INSERTION {
-            if len >= 2 {
-                insertion_sort_shift_left(v, 1, is_less);
-            }
-            return;
-        }
-
-        if limit == 0 {
-            heapsort(v, is_less);
-            return;
-        }
-
-        // If the last partitioning was imbalanced, try breaking patterns in the slice by shuffling
-        // some elements around. Hopefully we'll choose a better pivot this time.
-        if !was_balanced {
-            break_patterns(v);
-            limit -= 1;
-        }
-
-        // Choose a pivot
-        let (pivot, _) = choose_pivot(v, is_less);
-
-        // If the chosen pivot is equal to the predecessor, then it's the smallest element in the
-        // slice. Partition the slice into elements equal to and elements greater than the pivot.
-        // This case is usually hit when the slice contains many duplicate elements.
-        if let Some(p) = pred {
-            if !is_less(p, &v[pivot]) {
-                let mid = partition_equal(v, pivot, is_less);
-
-                // If we've passed our index, then we're good.
-                if mid > index {
-                    return;
-                }
-
-                // Otherwise, continue sorting elements greater than the pivot.
-                v = &mut v[mid..];
-                index = index - mid;
-                pred = None;
-                continue;
-            }
-        }
-
-        let (mid, _) = partition(v, pivot, is_less);
-        was_balanced = cmp::min(mid, len - mid) >= len / 8;
-
-        // Split the slice into `left`, `pivot`, and `right`.
-        let (left, right) = v.split_at_mut(mid);
-        let (pivot, right) = right.split_at_mut(1);
-        let pivot = &pivot[0];
-
-        if mid < index {
-            v = right;
-            index = index - mid - 1;
-            pred = Some(pivot);
-        } else if mid > index {
-            v = left;
-        } else {
-            // If mid == index, then we're done, since partition() guaranteed that all elements
-            // after mid are greater than or equal to mid.
-            return;
-        }
-    }
-}
-
-/// Reorder the slice such that the element at `index` is at its final sorted position.
-pub fn partition_at_index<T, F>(
-    v: &mut [T],
-    index: usize,
-    mut is_less: F,
-) -> (&mut [T], &mut T, &mut [T])
-where
-    F: FnMut(&T, &T) -> bool,
-{
-    use cmp::Ordering::Greater;
-    use cmp::Ordering::Less;
-
-    if index >= v.len() {
-        panic!("partition_at_index index {} greater than length of slice {}", index, v.len());
-    }
-
-    if T::IS_ZST {
-        // Sorting has no meaningful behavior on zero-sized types. Do nothing.
-    } else if index == v.len() - 1 {
-        // Find max element and place it in the last position of the array. We're free to use
-        // `unwrap()` here because we know v must not be empty.
-        let (max_index, _) = v
-            .iter()
-            .enumerate()
-            .max_by(|&(_, x), &(_, y)| if is_less(x, y) { Less } else { Greater })
-            .unwrap();
-        v.swap(max_index, index);
-    } else if index == 0 {
-        // Find min element and place it in the first position of the array. We're free to use
-        // `unwrap()` here because we know v must not be empty.
-        let (min_index, _) = v
-            .iter()
-            .enumerate()
-            .min_by(|&(_, x), &(_, y)| if is_less(x, y) { Less } else { Greater })
-            .unwrap();
-        v.swap(min_index, index);
-    } else {
-        partition_at_index_loop(v, index, &mut is_less, None);
-    }
-
-    let (left, right) = v.split_at_mut(index);
-    let (pivot, right) = right.split_at_mut(1);
-    let pivot = &mut pivot[0];
-    (left, pivot, right)
-}
-
 /// Merges non-decreasing runs `v[..mid]` and `v[mid..]` using `buf` as temporary storage, and
 /// stores the result into `v[..]`.
 ///
diff --git a/src/doc/rustdoc/src/how-to-write-documentation.md b/src/doc/rustdoc/src/how-to-write-documentation.md
index 38fd1db5c21..1fa9f814476 100644
--- a/src/doc/rustdoc/src/how-to-write-documentation.md
+++ b/src/doc/rustdoc/src/how-to-write-documentation.md
@@ -165,15 +165,15 @@ extensions:
 ### Strikethrough
 
 Text may be rendered with a horizontal line through the center by wrapping the
-text with two tilde characters on each side:
+text with one or two tilde characters on each side:
 
 ```text
-An example of ~~strikethrough text~~.
+An example of ~~strikethrough text~~. You can also use ~single tildes~.
 ```
 
 This example will render as:
 
-> An example of ~~strikethrough text~~.
+> An example of ~~strikethrough text~~. You can also use ~single tildes~.
 
 This follows the [GitHub Strikethrough extension][strikethrough].
 
diff --git a/src/tools/miri/tests/fail/terminate-terminator.rs b/src/tools/miri/tests/fail/terminate-terminator.rs
index 22ffa1b2711..b9199cff079 100644
--- a/src/tools/miri/tests/fail/terminate-terminator.rs
+++ b/src/tools/miri/tests/fail/terminate-terminator.rs
@@ -12,13 +12,13 @@ impl Drop for Foo {
 
 #[inline(always)]
 fn has_cleanup() {
+    //~^ ERROR: panic in a function that cannot unwind
     let _f = Foo;
     panic!();
 }
 
 extern "C" fn panic_abort() {
     has_cleanup();
-    //~^ ERROR: panic in a function that cannot unwind
 }
 
 fn main() {
diff --git a/src/tools/miri/tests/fail/terminate-terminator.stderr b/src/tools/miri/tests/fail/terminate-terminator.stderr
index 8ce4bb7cbb5..d73e23a53d0 100644
--- a/src/tools/miri/tests/fail/terminate-terminator.stderr
+++ b/src/tools/miri/tests/fail/terminate-terminator.stderr
@@ -6,15 +6,18 @@ error: abnormal termination: panic in a function that cannot unwind
   --> $DIR/terminate-terminator.rs:LL:CC
    |
 LL | / fn has_cleanup() {
+LL | |
 LL | |     let _f = Foo;
 LL | |     panic!();
 LL | | }
    | |_^ panic in a function that cannot unwind
-...
-LL |       has_cleanup();
-   |       ------------- in this inlined function call
    |
-   = note: inside `panic_abort` at $DIR/terminate-terminator.rs:LL:CC
+   = note: inside `has_cleanup` at $DIR/terminate-terminator.rs:LL:CC
+note: inside `panic_abort`
+  --> $DIR/terminate-terminator.rs:LL:CC
+   |
+LL |     has_cleanup();
+   |     ^^^^^^^^^^^^^
 note: inside `main`
   --> $DIR/terminate-terminator.rs:LL:CC
    |
diff --git a/tests/rustdoc-gui/highlight-colors.goml b/tests/rustdoc-gui/highlight-colors.goml
index 4f5e1c110f2..d162674fa69 100644
--- a/tests/rustdoc-gui/highlight-colors.goml
+++ b/tests/rustdoc-gui/highlight-colors.goml
@@ -43,52 +43,52 @@ define-function: (
 
 call-function: ("check-colors", {
     "theme": "ayu",
-    "kw": "rgb(255, 119, 51)",
-    "kw2": "rgb(255, 119, 51)",
-    "prelude_ty": "rgb(105, 242, 223)",
-    "prelude_val": "rgb(255, 119, 51)",
-    "lifetime": "rgb(255, 119, 51)",
-    "number": "rgb(184, 204, 82)",
-    "string": "rgb(184, 204, 82)",
-    "bool_val": "rgb(255, 119, 51)",
-    "self": "rgb(54, 163, 217)",
-    "attr": "rgb(230, 225, 207)",
-    "macro": "rgb(163, 122, 204)",
-    "question_mark": "rgb(255, 144, 17)",
-    "comment": "rgb(120, 135, 151)",
-    "doc_comment": "rgb(161, 172, 136)",
+    "kw": "#ff7733",
+    "kw2": "#ff7733",
+    "prelude_ty": "#69f2df",
+    "prelude_val": "#ff7733",
+    "lifetime": "#ff7733",
+    "number": "#b8cc52",
+    "string": "#b8cc52",
+    "bool_val": "#ff7733",
+    "self": "#36a3d9",
+    "attr": "#e6e1cf",
+    "macro": "#a37acc",
+    "question_mark": "#ff9011",
+    "comment": "#788797",
+    "doc_comment": "#a1ac88",
 })
 call-function: ("check-colors", {
     "theme": "dark",
-    "kw": "rgb(171, 138, 193)",
-    "kw2": "rgb(118, 154, 203)",
-    "prelude_ty": "rgb(118, 154, 203)",
-    "prelude_val": "rgb(238, 104, 104)",
-    "lifetime": "rgb(217, 127, 38)",
-    "number": "rgb(131, 163, 0)",
-    "string": "rgb(131, 163, 0)",
-    "bool_val": "rgb(238, 104, 104)",
-    "self": "rgb(238, 104, 104)",
-    "attr": "rgb(238, 104, 104)",
-    "macro": "rgb(62, 153, 159)",
-    "question_mark": "rgb(255, 144, 17)",
-    "comment": "rgb(141, 141, 139)",
-    "doc_comment": "rgb(140, 163, 117)",
+    "kw": "#ab8ac1",
+    "kw2": "#769acb",
+    "prelude_ty": "#769acb",
+    "prelude_val": "#ee6868",
+    "lifetime": "#d97f26",
+    "number": "#83a300",
+    "string": "#83a300",
+    "bool_val": "#ee6868",
+    "self": "#ee6868",
+    "attr": "#ee6868",
+    "macro": "#3e999f",
+    "question_mark": "#ff9011",
+    "comment": "#8d8d8b",
+    "doc_comment": "#8ca375",
 })
 call-function: ("check-colors", {
     "theme": "light",
-    "kw": "rgb(137, 89, 168)",
-    "kw2": "rgb(66, 113, 174)",
-    "prelude_ty": "rgb(66, 113, 174)",
-    "prelude_val": "rgb(200, 40, 41)",
-    "lifetime": "rgb(183, 101, 20)",
-    "number": "rgb(113, 140, 0)",
-    "string": "rgb(113, 140, 0)",
-    "bool_val": "rgb(200, 40, 41)",
-    "self": "rgb(200, 40, 41)",
-    "attr": "rgb(200, 40, 41)",
-    "macro": "rgb(62, 153, 159)",
-    "question_mark": "rgb(255, 144, 17)",
-    "comment": "rgb(142, 144, 140)",
-    "doc_comment": "rgb(77, 77, 76)",
+    "kw": "#8959a8",
+    "kw2": "#4271ae",
+    "prelude_ty": "#4271ae",
+    "prelude_val": "#c82829",
+    "lifetime": "#b76514",
+    "number": "#718c00",
+    "string": "#718c00",
+    "bool_val": "#c82829",
+    "self": "#c82829",
+    "attr": "#c82829",
+    "macro": "#3e999f",
+    "question_mark": "#ff9011",
+    "comment": "#8e908c",
+    "doc_comment": "#4d4d4c",
 })
diff --git a/tests/rustdoc-ui/unescaped_backticks.rs b/tests/rustdoc-ui/unescaped_backticks.rs
index f1ad7c8d4c7..e99cd1f3d58 100644
--- a/tests/rustdoc-ui/unescaped_backticks.rs
+++ b/tests/rustdoc-ui/unescaped_backticks.rs
@@ -340,3 +340,15 @@ id! {
     /// level changes.
     pub mod tracing_macro {}
 }
+
+/// Regression test for <https://github.com/rust-lang/rust/issues/111117>
+pub mod trillium_server_common {
+    /// One-indexed, because the first CloneCounter is included. If you don't
+    /// want the original to count, construct a [``CloneCounterObserver`]
+    /// instead and use [`CloneCounterObserver::counter`] to increment.
+    //~^ ERROR unescaped backtick
+    pub struct CloneCounter;
+
+    /// This is used by the above.
+    pub struct CloneCounterObserver;
+}
diff --git a/tests/rustdoc-ui/unescaped_backticks.stderr b/tests/rustdoc-ui/unescaped_backticks.stderr
index e629dbc34e9..bf1f18889c4 100644
--- a/tests/rustdoc-ui/unescaped_backticks.stderr
+++ b/tests/rustdoc-ui/unescaped_backticks.stderr
@@ -342,6 +342,18 @@ LL | |     /// level changes.
            to this: [`rebuild_interest_cache\`][rebuild] is called after the value of the max
 
 error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:348:56
+   |
+LL |     /// instead and use [`CloneCounterObserver::counter`] to increment.
+   |                                                        ^
+   |
+   = help: the opening or closing backtick of an inline code may be missing
+help: if you meant to use a literal backtick, escape it
+   |
+LL |     /// instead and use [`CloneCounterObserver::counter\`] to increment.
+   |                                                        +
+
+error: unescaped backtick
   --> $DIR/unescaped_backticks.rs:11:5
    |
 LL | /// `
@@ -955,5 +967,5 @@ help: if you meant to use a literal backtick, escape it
 LL | /// | table`( | )\`body |
    |                  +
 
-error: aborting due to 63 previous errors
+error: aborting due to 64 previous errors
 
diff --git a/tests/rustdoc/strikethrough-in-summary.rs b/tests/rustdoc/strikethrough-in-summary.rs
deleted file mode 100644
index cb6cd0e7ba6..00000000000
--- a/tests/rustdoc/strikethrough-in-summary.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#![crate_name = "foo"]
-
-// @has foo/index.html '//del' 'strike'
-
-/// ~~strike~~
-pub fn strike() {}
diff --git a/tests/rustdoc/test-strikethrough.rs b/tests/rustdoc/test-strikethrough.rs
index c7855729a98..58162153b9e 100644
--- a/tests/rustdoc/test-strikethrough.rs
+++ b/tests/rustdoc/test-strikethrough.rs
@@ -1,6 +1,13 @@
 #![crate_name = "foo"]
 
-// @has foo/fn.f.html
-// @has - //del "Y"
-/// ~~Y~~
+// Test that strikethrough works with single and double tildes and that it shows up on
+// the item's dedicated page as well as the parent module's summary of items.
+
+// @has foo/index.html //del 'strike'
+// @has foo/index.html //del 'through'
+
+// @has foo/fn.f.html //del 'strike'
+// @has foo/fn.f.html //del 'through'
+
+/// ~~strike~~ ~through~
 pub fn f() {}
diff --git a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs
index 56f5ac44db0..41b09ba0370 100644
--- a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs
+++ b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs
@@ -1,6 +1,7 @@
 // edition:2021
 
 #![feature(rustc_attrs)]
+#![feature(stmt_expr_attributes)]
 
 // Should capture the discriminant since a variant of a multivariant enum is
 // mentioned in the match arm; the discriminant is captured by the closure regardless
@@ -8,9 +9,6 @@
 fn test_1_should_capture() {
     let variant = Some(2229);
     let c =  #[rustc_capture_analysis]
-    //~^ ERROR: attributes on expressions are experimental
-    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
-
     || {
     //~^ First Pass analysis includes:
     //~| Min Capture analysis includes:
@@ -29,8 +27,6 @@ fn test_1_should_capture() {
 fn test_2_should_not_capture() {
     let variant = Some(2229);
     let c =  #[rustc_capture_analysis]
-    //~^ ERROR: attributes on expressions are experimental
-    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
     || {
     //~^ First Pass analysis includes:
         match variant {
@@ -50,8 +46,6 @@ enum SingleVariant {
 fn test_3_should_not_capture_single_variant() {
     let variant = SingleVariant::Points(1);
     let c =  #[rustc_capture_analysis]
-    //~^ ERROR: attributes on expressions are experimental
-    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
     || {
     //~^ First Pass analysis includes:
         match variant {
@@ -66,8 +60,6 @@ fn test_3_should_not_capture_single_variant() {
 fn test_6_should_capture_single_variant() {
     let variant = SingleVariant::Points(1);
     let c =  #[rustc_capture_analysis]
-    //~^ ERROR: attributes on expressions are experimental
-    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
     || {
     //~^ First Pass analysis includes:
     //~| Min Capture analysis includes:
@@ -88,8 +80,6 @@ fn test_6_should_capture_single_variant() {
 fn test_4_should_not_capture_array() {
     let array: [i32; 3] = [0; 3];
     let c =  #[rustc_capture_analysis]
-    //~^ ERROR: attributes on expressions are experimental
-    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
     || {
     //~^ First Pass analysis includes:
         match array {
@@ -112,8 +102,6 @@ enum MVariant {
 fn test_5_should_capture_multi_variant() {
     let variant = MVariant::A;
     let c =  #[rustc_capture_analysis]
-    //~^ ERROR: attributes on expressions are experimental
-    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
     || {
     //~^ First Pass analysis includes:
     //~| Min Capture analysis includes:
@@ -127,6 +115,62 @@ fn test_5_should_capture_multi_variant() {
     c();
 }
 
+// Even though all patterns are wild, we need to read the discriminant
+// in order to test the slice length
+fn test_7_should_capture_slice_len() {
+    let slice: &[i32] = &[1, 2, 3];
+    let c =  #[rustc_capture_analysis]
+    || {
+    //~^ First Pass analysis includes:
+    //~| Min Capture analysis includes:
+        match slice {
+            //~^ NOTE: Capturing slice[] -> ImmBorrow
+            //~| NOTE: Min Capture slice[] -> ImmBorrow
+            [_,_,_] => {},
+            _ => {}
+        }
+    };
+    c();
+    let c =  #[rustc_capture_analysis]
+    || {
+    //~^ First Pass analysis includes:
+    //~| Min Capture analysis includes:
+        match slice {
+            //~^ NOTE: Capturing slice[] -> ImmBorrow
+            //~| NOTE: Min Capture slice[] -> ImmBorrow
+            [] => {},
+            _ => {}
+        }
+    };
+    c();
+    let c =  #[rustc_capture_analysis]
+    || {
+    //~^ First Pass analysis includes:
+    //~| Min Capture analysis includes:
+        match slice {
+            //~^ NOTE: Capturing slice[] -> ImmBorrow
+            //~| NOTE: Min Capture slice[] -> ImmBorrow
+            [_, .. ,_] => {},
+            _ => {}
+        }
+    };
+    c();
+}
+
+// Wild pattern that doesn't bind, so no capture
+fn test_8_capture_slice_wild() {
+    let slice: &[i32] = &[1, 2, 3];
+    let c =  #[rustc_capture_analysis]
+    || {
+    //~^ First Pass analysis includes:
+        match slice {
+            [..] => {},
+            _ => {}
+        }
+    };
+    c();
+}
+
 fn main() {
     test_1_should_capture();
     test_2_should_not_capture();
@@ -134,4 +178,6 @@ fn main() {
     test_6_should_capture_single_variant();
     test_4_should_not_capture_array();
     test_5_should_capture_multi_variant();
+    test_7_should_capture_slice_len();
+    test_8_capture_slice_wild();
 }
diff --git a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr
index 46081333395..e137af1a0bd 100644
--- a/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr
+++ b/tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.stderr
@@ -1,59 +1,5 @@
-error[E0658]: attributes on expressions are experimental
-  --> $DIR/patterns-capture-analysis.rs:10:14
-   |
-LL |     let c =  #[rustc_capture_analysis]
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
-   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
-
-error[E0658]: attributes on expressions are experimental
-  --> $DIR/patterns-capture-analysis.rs:31:14
-   |
-LL |     let c =  #[rustc_capture_analysis]
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
-   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
-
-error[E0658]: attributes on expressions are experimental
-  --> $DIR/patterns-capture-analysis.rs:52:14
-   |
-LL |     let c =  #[rustc_capture_analysis]
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
-   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
-
-error[E0658]: attributes on expressions are experimental
-  --> $DIR/patterns-capture-analysis.rs:68:14
-   |
-LL |     let c =  #[rustc_capture_analysis]
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
-   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
-
-error[E0658]: attributes on expressions are experimental
-  --> $DIR/patterns-capture-analysis.rs:90:14
-   |
-LL |     let c =  #[rustc_capture_analysis]
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
-   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
-
-error[E0658]: attributes on expressions are experimental
-  --> $DIR/patterns-capture-analysis.rs:114:14
-   |
-LL |     let c =  #[rustc_capture_analysis]
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
-   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
-
 error: First Pass analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:14:5
+  --> $DIR/patterns-capture-analysis.rs:12:5
    |
 LL | /     || {
 LL | |
@@ -65,13 +11,13 @@ LL | |     };
    | |_____^
    |
 note: Capturing variant[] -> ImmBorrow
-  --> $DIR/patterns-capture-analysis.rs:17:15
+  --> $DIR/patterns-capture-analysis.rs:15:15
    |
 LL |         match variant {
    |               ^^^^^^^
 
 error: Min Capture analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:14:5
+  --> $DIR/patterns-capture-analysis.rs:12:5
    |
 LL | /     || {
 LL | |
@@ -83,13 +29,13 @@ LL | |     };
    | |_____^
    |
 note: Min Capture variant[] -> ImmBorrow
-  --> $DIR/patterns-capture-analysis.rs:17:15
+  --> $DIR/patterns-capture-analysis.rs:15:15
    |
 LL |         match variant {
    |               ^^^^^^^
 
 error: First Pass analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:34:5
+  --> $DIR/patterns-capture-analysis.rs:30:5
    |
 LL | /     || {
 LL | |
@@ -100,7 +46,7 @@ LL | |     };
    | |_____^
 
 error: First Pass analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:55:5
+  --> $DIR/patterns-capture-analysis.rs:49:5
    |
 LL | /     || {
 LL | |
@@ -111,7 +57,7 @@ LL | |     };
    | |_____^
 
 error: First Pass analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:71:5
+  --> $DIR/patterns-capture-analysis.rs:63:5
    |
 LL | /     || {
 LL | |
@@ -123,18 +69,18 @@ LL | |     };
    | |_____^
    |
 note: Capturing variant[] -> ImmBorrow
-  --> $DIR/patterns-capture-analysis.rs:74:15
+  --> $DIR/patterns-capture-analysis.rs:66:15
    |
 LL |         match variant {
    |               ^^^^^^^
 note: Capturing variant[(0, 0)] -> ImmBorrow
-  --> $DIR/patterns-capture-analysis.rs:74:15
+  --> $DIR/patterns-capture-analysis.rs:66:15
    |
 LL |         match variant {
    |               ^^^^^^^
 
 error: Min Capture analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:71:5
+  --> $DIR/patterns-capture-analysis.rs:63:5
    |
 LL | /     || {
 LL | |
@@ -146,13 +92,13 @@ LL | |     };
    | |_____^
    |
 note: Min Capture variant[] -> ImmBorrow
-  --> $DIR/patterns-capture-analysis.rs:74:15
+  --> $DIR/patterns-capture-analysis.rs:66:15
    |
 LL |         match variant {
    |               ^^^^^^^
 
 error: First Pass analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:93:5
+  --> $DIR/patterns-capture-analysis.rs:83:5
    |
 LL | /     || {
 LL | |
@@ -163,7 +109,7 @@ LL | |     };
    | |_____^
 
 error: First Pass analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:117:5
+  --> $DIR/patterns-capture-analysis.rs:105:5
    |
 LL | /     || {
 LL | |
@@ -175,13 +121,13 @@ LL | |     };
    | |_____^
    |
 note: Capturing variant[] -> ImmBorrow
-  --> $DIR/patterns-capture-analysis.rs:120:15
+  --> $DIR/patterns-capture-analysis.rs:108:15
    |
 LL |         match variant {
    |               ^^^^^^^
 
 error: Min Capture analysis includes:
-  --> $DIR/patterns-capture-analysis.rs:117:5
+  --> $DIR/patterns-capture-analysis.rs:105:5
    |
 LL | /     || {
 LL | |
@@ -193,11 +139,130 @@ LL | |     };
    | |_____^
    |
 note: Min Capture variant[] -> ImmBorrow
-  --> $DIR/patterns-capture-analysis.rs:120:15
+  --> $DIR/patterns-capture-analysis.rs:108:15
    |
 LL |         match variant {
    |               ^^^^^^^
 
-error: aborting due to 15 previous errors
+error: First Pass analysis includes:
+  --> $DIR/patterns-capture-analysis.rs:123:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         match slice {
+...  |
+LL | |         }
+LL | |     };
+   | |_____^
+   |
+note: Capturing slice[] -> ImmBorrow
+  --> $DIR/patterns-capture-analysis.rs:126:15
+   |
+LL |         match slice {
+   |               ^^^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/patterns-capture-analysis.rs:123:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         match slice {
+...  |
+LL | |         }
+LL | |     };
+   | |_____^
+   |
+note: Min Capture slice[] -> ImmBorrow
+  --> $DIR/patterns-capture-analysis.rs:126:15
+   |
+LL |         match slice {
+   |               ^^^^^
+
+error: First Pass analysis includes:
+  --> $DIR/patterns-capture-analysis.rs:135:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         match slice {
+...  |
+LL | |         }
+LL | |     };
+   | |_____^
+   |
+note: Capturing slice[] -> ImmBorrow
+  --> $DIR/patterns-capture-analysis.rs:138:15
+   |
+LL |         match slice {
+   |               ^^^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/patterns-capture-analysis.rs:135:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         match slice {
+...  |
+LL | |         }
+LL | |     };
+   | |_____^
+   |
+note: Min Capture slice[] -> ImmBorrow
+  --> $DIR/patterns-capture-analysis.rs:138:15
+   |
+LL |         match slice {
+   |               ^^^^^
+
+error: First Pass analysis includes:
+  --> $DIR/patterns-capture-analysis.rs:147:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         match slice {
+...  |
+LL | |         }
+LL | |     };
+   | |_____^
+   |
+note: Capturing slice[] -> ImmBorrow
+  --> $DIR/patterns-capture-analysis.rs:150:15
+   |
+LL |         match slice {
+   |               ^^^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/patterns-capture-analysis.rs:147:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         match slice {
+...  |
+LL | |         }
+LL | |     };
+   | |_____^
+   |
+note: Min Capture slice[] -> ImmBorrow
+  --> $DIR/patterns-capture-analysis.rs:150:15
+   |
+LL |         match slice {
+   |               ^^^^^
+
+error: First Pass analysis includes:
+  --> $DIR/patterns-capture-analysis.rs:164:5
+   |
+LL | /     || {
+LL | |
+LL | |         match slice {
+LL | |             [..] => {},
+LL | |             _ => {}
+LL | |         }
+LL | |     };
+   | |_____^
+
+error: aborting due to 16 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/impl-trait/arg-position-impl-trait-too-long.rs b/tests/ui/impl-trait/arg-position-impl-trait-too-long.rs
new file mode 100644
index 00000000000..8ef9281c9d3
--- /dev/null
+++ b/tests/ui/impl-trait/arg-position-impl-trait-too-long.rs
@@ -0,0 +1,22 @@
+struct Header;
+struct EntryMetadata;
+struct Entry<A, B>(A, B);
+
+trait Tr {
+    type EncodedKey;
+    type EncodedValue;
+}
+
+fn test<C: Tr, R>(
+    // This APIT is long, however we shouldn't render the type name with a newline in it.
+    y: impl FnOnce(
+        &mut Header,
+        &mut [EntryMetadata],
+        &mut [Entry<C::EncodedKey, C::EncodedValue>]
+    ) -> R,
+) {
+    let () = y;
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/arg-position-impl-trait-too-long.stderr b/tests/ui/impl-trait/arg-position-impl-trait-too-long.stderr
new file mode 100644
index 00000000000..40446a3d339
--- /dev/null
+++ b/tests/ui/impl-trait/arg-position-impl-trait-too-long.stderr
@@ -0,0 +1,22 @@
+error[E0308]: mismatched types
+  --> $DIR/arg-position-impl-trait-too-long.rs:18:9
+   |
+LL |       y: impl FnOnce(
+   |  ________-
+LL | |         &mut Header,
+LL | |         &mut [EntryMetadata],
+LL | |         &mut [Entry<C::EncodedKey, C::EncodedValue>]
+LL | |     ) -> R,
+   | |__________- this type parameter
+LL |   ) {
+LL |       let () = y;
+   |           ^^   - this expression has type `impl FnOnce(&mut Header, &mut [EntryMetadata], &mut [Entry<C::EncodedKey, C::EncodedValue>]) -> R`
+   |           |
+   |           expected type parameter `impl FnOnce(&mut Header, &mut [EntryMetadata], &mut [Entry<C::EncodedKey, C::EncodedValue>]) -> R`, found `()`
+   |
+   = note: expected type parameter `impl FnOnce(&mut Header, &mut [EntryMetadata], &mut [Entry<C::EncodedKey, C::EncodedValue>]) -> R`
+                   found unit type `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/lint/lint-attr-everywhere-early.rs b/tests/ui/lint/lint-attr-everywhere-early.rs
index fd0c4b43e05..0c820ef9a29 100644
--- a/tests/ui/lint/lint-attr-everywhere-early.rs
+++ b/tests/ui/lint/lint-attr-everywhere-early.rs
@@ -134,6 +134,14 @@ fn expressions() {
         }
     }
 
+    match f {
+        #[deny(ellipsis_inclusive_range_patterns)]
+        Match{f1: 0...100} => {}
+        //~^ ERROR range patterns are deprecated
+        //~| WARNING this is accepted in the current edition
+        _ => {}
+    }
+
     // Statement Block
     {
         #![deny(unsafe_code)]
diff --git a/tests/ui/lint/lint-attr-everywhere-early.stderr b/tests/ui/lint/lint-attr-everywhere-early.stderr
index d6c6d5faef2..fac0eb4faff 100644
--- a/tests/ui/lint/lint-attr-everywhere-early.stderr
+++ b/tests/ui/lint/lint-attr-everywhere-early.stderr
@@ -384,92 +384,106 @@ note: the lint level is defined here
 LL |         #[deny(while_true)]
    |                ^^^^^^^^^^
 
+error: `...` range patterns are deprecated
+  --> $DIR/lint-attr-everywhere-early.rs:139:20
+   |
+LL |         Match{f1: 0...100} => {}
+   |                    ^^^ help: use `..=` for an inclusive range
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+note: the lint level is defined here
+  --> $DIR/lint-attr-everywhere-early.rs:138:16
+   |
+LL |         #[deny(ellipsis_inclusive_range_patterns)]
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: usage of an `unsafe` block
-  --> $DIR/lint-attr-everywhere-early.rs:140:9
+  --> $DIR/lint-attr-everywhere-early.rs:148:9
    |
 LL |         unsafe {}
    |         ^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/lint-attr-everywhere-early.rs:139:17
+  --> $DIR/lint-attr-everywhere-early.rs:147:17
    |
 LL |         #![deny(unsafe_code)]
    |                 ^^^^^^^^^^^
 
 error: usage of an `unsafe` block
-  --> $DIR/lint-attr-everywhere-early.rs:144:9
+  --> $DIR/lint-attr-everywhere-early.rs:152:9
    |
 LL |         unsafe {}
    |         ^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/lint-attr-everywhere-early.rs:143:16
+  --> $DIR/lint-attr-everywhere-early.rs:151:16
    |
 LL |         #[deny(unsafe_code)]
    |                ^^^^^^^^^^^
 
 error: usage of an `unsafe` block
-  --> $DIR/lint-attr-everywhere-early.rs:149:5
+  --> $DIR/lint-attr-everywhere-early.rs:157:5
    |
 LL |     unsafe {};
    |     ^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/lint-attr-everywhere-early.rs:148:12
+  --> $DIR/lint-attr-everywhere-early.rs:156:12
    |
 LL |     #[deny(unsafe_code)]
    |            ^^^^^^^^^^^
 
 error: usage of an `unsafe` block
-  --> $DIR/lint-attr-everywhere-early.rs:151:27
+  --> $DIR/lint-attr-everywhere-early.rs:159:27
    |
 LL |     [#[deny(unsafe_code)] unsafe {123}];
    |                           ^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/lint-attr-everywhere-early.rs:151:13
+  --> $DIR/lint-attr-everywhere-early.rs:159:13
    |
 LL |     [#[deny(unsafe_code)] unsafe {123}];
    |             ^^^^^^^^^^^
 
 error: usage of an `unsafe` block
-  --> $DIR/lint-attr-everywhere-early.rs:152:27
+  --> $DIR/lint-attr-everywhere-early.rs:160:27
    |
 LL |     (#[deny(unsafe_code)] unsafe {123},);
    |                           ^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/lint-attr-everywhere-early.rs:152:13
+  --> $DIR/lint-attr-everywhere-early.rs:160:13
    |
 LL |     (#[deny(unsafe_code)] unsafe {123},);
    |             ^^^^^^^^^^^
 
 error: usage of an `unsafe` block
-  --> $DIR/lint-attr-everywhere-early.rs:154:31
+  --> $DIR/lint-attr-everywhere-early.rs:162:31
    |
 LL |     call(#[deny(unsafe_code)] unsafe {123});
    |                               ^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/lint-attr-everywhere-early.rs:154:17
+  --> $DIR/lint-attr-everywhere-early.rs:162:17
    |
 LL |     call(#[deny(unsafe_code)] unsafe {123});
    |                 ^^^^^^^^^^^
 
 error: usage of an `unsafe` block
-  --> $DIR/lint-attr-everywhere-early.rs:156:38
+  --> $DIR/lint-attr-everywhere-early.rs:164:38
    |
 LL |     TupleStruct(#[deny(unsafe_code)] unsafe {123});
    |                                      ^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/lint-attr-everywhere-early.rs:156:24
+  --> $DIR/lint-attr-everywhere-early.rs:164:24
    |
 LL |     TupleStruct(#[deny(unsafe_code)] unsafe {123});
    |                        ^^^^^^^^^^^
 
 error: `...` range patterns are deprecated
-  --> $DIR/lint-attr-everywhere-early.rs:167:18
+  --> $DIR/lint-attr-everywhere-early.rs:175:18
    |
 LL |             f1: 0...100,
    |                  ^^^ help: use `..=` for an inclusive range
@@ -477,10 +491,10 @@ LL |             f1: 0...100,
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
 note: the lint level is defined here
-  --> $DIR/lint-attr-everywhere-early.rs:166:20
+  --> $DIR/lint-attr-everywhere-early.rs:174:20
    |
 LL |             #[deny(ellipsis_inclusive_range_patterns)]
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 36 previous errors
+error: aborting due to 37 previous errors
 
diff --git a/tests/ui/lint/lint-attr-everywhere-late.rs b/tests/ui/lint/lint-attr-everywhere-late.rs
index 1055157d602..a24355babb6 100644
--- a/tests/ui/lint/lint-attr-everywhere-late.rs
+++ b/tests/ui/lint/lint-attr-everywhere-late.rs
@@ -162,6 +162,11 @@ fn expressions() {
         }
     }
 
+    match 123 {
+        #[deny(non_snake_case)]
+        ARM_VAR => {} //~ ERROR variable `ARM_VAR` should have a snake case name
+    }
+
     // Statement Block
     {
         #![deny(enum_intrinsics_non_enums)]
diff --git a/tests/ui/lint/lint-attr-everywhere-late.stderr b/tests/ui/lint/lint-attr-everywhere-late.stderr
index a69c2e0ef2b..9587556b0c1 100644
--- a/tests/ui/lint/lint-attr-everywhere-late.stderr
+++ b/tests/ui/lint/lint-attr-everywhere-late.stderr
@@ -305,124 +305,136 @@ note: the lint level is defined here
 LL |         #[deny(enum_intrinsics_non_enums)]
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: variable `ARM_VAR` should have a snake case name
+  --> $DIR/lint-attr-everywhere-late.rs:167:9
+   |
+LL |         ARM_VAR => {}
+   |         ^^^^^^^ help: convert the identifier to snake case: `arm_var`
+   |
+note: the lint level is defined here
+  --> $DIR/lint-attr-everywhere-late.rs:166:16
+   |
+LL |         #[deny(non_snake_case)]
+   |                ^^^^^^^^^^^^^^
+
 error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
-  --> $DIR/lint-attr-everywhere-late.rs:168:9
+  --> $DIR/lint-attr-everywhere-late.rs:173:9
    |
 LL |         discriminant::<i32>(&123);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum.
-  --> $DIR/lint-attr-everywhere-late.rs:168:29
+  --> $DIR/lint-attr-everywhere-late.rs:173:29
    |
 LL |         discriminant::<i32>(&123);
    |                             ^^^^
 note: the lint level is defined here
-  --> $DIR/lint-attr-everywhere-late.rs:167:17
+  --> $DIR/lint-attr-everywhere-late.rs:172:17
    |
 LL |         #![deny(enum_intrinsics_non_enums)]
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
-  --> $DIR/lint-attr-everywhere-late.rs:172:9
+  --> $DIR/lint-attr-everywhere-late.rs:177:9
    |
 LL |         discriminant::<i32>(&123);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum.
-  --> $DIR/lint-attr-everywhere-late.rs:172:29
+  --> $DIR/lint-attr-everywhere-late.rs:177:29
    |
 LL |         discriminant::<i32>(&123);
    |                             ^^^^
 note: the lint level is defined here
-  --> $DIR/lint-attr-everywhere-late.rs:171:16
+  --> $DIR/lint-attr-everywhere-late.rs:176:16
    |
 LL |         #[deny(enum_intrinsics_non_enums)]
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
-  --> $DIR/lint-attr-everywhere-late.rs:177:5
+  --> $DIR/lint-attr-everywhere-late.rs:182:5
    |
 LL |     discriminant::<i32>(&123);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum.
-  --> $DIR/lint-attr-everywhere-late.rs:177:25
+  --> $DIR/lint-attr-everywhere-late.rs:182:25
    |
 LL |     discriminant::<i32>(&123);
    |                         ^^^^
 note: the lint level is defined here
-  --> $DIR/lint-attr-everywhere-late.rs:176:12
+  --> $DIR/lint-attr-everywhere-late.rs:181:12
    |
 LL |     #[deny(enum_intrinsics_non_enums)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
-  --> $DIR/lint-attr-everywhere-late.rs:179:41
+  --> $DIR/lint-attr-everywhere-late.rs:184:41
    |
 LL |     [#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123)];
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum.
-  --> $DIR/lint-attr-everywhere-late.rs:179:61
+  --> $DIR/lint-attr-everywhere-late.rs:184:61
    |
 LL |     [#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123)];
    |                                                             ^^^^
 note: the lint level is defined here
-  --> $DIR/lint-attr-everywhere-late.rs:179:13
+  --> $DIR/lint-attr-everywhere-late.rs:184:13
    |
 LL |     [#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123)];
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
-  --> $DIR/lint-attr-everywhere-late.rs:180:41
+  --> $DIR/lint-attr-everywhere-late.rs:185:41
    |
 LL |     (#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123),);
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum.
-  --> $DIR/lint-attr-everywhere-late.rs:180:61
+  --> $DIR/lint-attr-everywhere-late.rs:185:61
    |
 LL |     (#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123),);
    |                                                             ^^^^
 note: the lint level is defined here
-  --> $DIR/lint-attr-everywhere-late.rs:180:13
+  --> $DIR/lint-attr-everywhere-late.rs:185:13
    |
 LL |     (#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123),);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
-  --> $DIR/lint-attr-everywhere-late.rs:182:45
+  --> $DIR/lint-attr-everywhere-late.rs:187:45
    |
 LL |     call(#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123));
    |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum.
-  --> $DIR/lint-attr-everywhere-late.rs:182:65
+  --> $DIR/lint-attr-everywhere-late.rs:187:65
    |
 LL |     call(#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123));
    |                                                                 ^^^^
 note: the lint level is defined here
-  --> $DIR/lint-attr-everywhere-late.rs:182:17
+  --> $DIR/lint-attr-everywhere-late.rs:187:17
    |
 LL |     call(#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123));
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the return value of `mem::discriminant` is unspecified when called with a non-enum type
-  --> $DIR/lint-attr-everywhere-late.rs:184:52
+  --> $DIR/lint-attr-everywhere-late.rs:189:52
    |
 LL |     TupleStruct(#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123));
    |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `i32`, which is not an enum.
-  --> $DIR/lint-attr-everywhere-late.rs:184:72
+  --> $DIR/lint-attr-everywhere-late.rs:189:72
    |
 LL |     TupleStruct(#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123));
    |                                                                        ^^^^
 note: the lint level is defined here
-  --> $DIR/lint-attr-everywhere-late.rs:184:24
+  --> $DIR/lint-attr-everywhere-late.rs:189:24
    |
 LL |     TupleStruct(#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 31 previous errors
+error: aborting due to 32 previous errors
 
diff --git a/tests/ui/lint/lint-match-arms-2.rs b/tests/ui/lint/lint-match-arms-2.rs
new file mode 100644
index 00000000000..0c1146339c4
--- /dev/null
+++ b/tests/ui/lint/lint-match-arms-2.rs
@@ -0,0 +1,24 @@
+#![feature(if_let_guard)]
+#![allow(unused, non_snake_case)]
+
+enum E {
+    A,
+}
+
+#[allow(bindings_with_variant_name, irrefutable_let_patterns)]
+fn foo() {
+    match E::A {
+        #[deny(bindings_with_variant_name)]
+        A => {}
+    //~^ ERROR pattern binding `A` is named the same as one of the variants of the type `E`
+    }
+
+    match &E::A {
+        #[deny(irrefutable_let_patterns)]
+        a if let b = a => {}
+    //~^ ERROR irrefutable `if let` guard pattern
+        _ => {}
+    }
+}
+
+fn main() { }
diff --git a/tests/ui/lint/lint-match-arms-2.stderr b/tests/ui/lint/lint-match-arms-2.stderr
new file mode 100644
index 00000000000..062d5c12e96
--- /dev/null
+++ b/tests/ui/lint/lint-match-arms-2.stderr
@@ -0,0 +1,29 @@
+error[E0170]: pattern binding `A` is named the same as one of the variants of the type `E`
+  --> $DIR/lint-match-arms-2.rs:12:9
+   |
+LL |         A => {}
+   |         ^ help: to match on the variant, qualify the path: `E::A`
+   |
+note: the lint level is defined here
+  --> $DIR/lint-match-arms-2.rs:11:16
+   |
+LL |         #[deny(bindings_with_variant_name)]
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: irrefutable `if let` guard pattern
+  --> $DIR/lint-match-arms-2.rs:18:18
+   |
+LL |         a if let b = a => {}
+   |                  ^
+   |
+   = note: this pattern will always match, so the guard is useless
+   = help: consider removing the guard and adding a `let` inside the match arm
+note: the lint level is defined here
+  --> $DIR/lint-match-arms-2.rs:17:16
+   |
+LL |         #[deny(irrefutable_let_patterns)]
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0170`.