about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-06-28 13:46:43 +0000
committerbors <bors@rust-lang.org>2022-06-28 13:46:43 +0000
commit00ebeb87ac87a492bd59ace6bd43d6ad1629ca4e (patch)
tree08462526fb5f69acea449b972d435d0ebed03906
parentbaf382e63c023259fa1f9042f8f479f183ca6ed3 (diff)
parent66b806084ec50917ab6cb87c3774facfdf3038fa (diff)
downloadrust-00ebeb87ac87a492bd59ace6bd43d6ad1629ca4e.tar.gz
rust-00ebeb87ac87a492bd59ace6bd43d6ad1629ca4e.zip
Auto merge of #98612 - Dylan-DPC:rollup-7tasikc, r=Dylan-DPC
Rollup of 9 pull requests

Successful merges:

 - #97346 (Remove a back-compat hack on lazy TAIT)
 - #98261 (Remove `MAX_SUGGESTION_HIGHLIGHT_LINES`)
 - #98337 ([RFC 2011] Optimize non-consuming operators)
 - #98384 (Fix RSS reporting on macOS)
 - #98420 (translation: lint fix + more migration)
 - #98430 (Refactor iter adapters with less macros)
 - #98555 (Hermit: Fix initializing lazy locks)
 - #98595 (Implement `Send` and `Sync` for `ThinBox<T>`)
 - #98597 (Remove unstable CStr/CString change from 1.62 release note)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock1
-rw-r--r--RELEASES.md2
-rw-r--r--compiler/rustc_borrowck/src/borrowck_errors.rs7
-rw-r--r--compiler/rustc_borrowck/src/lib.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs96
-rw-r--r--compiler/rustc_data_structures/src/profiling.rs18
-rw-r--r--compiler/rustc_error_messages/locales/en-US/privacy.ftl12
-rw-r--r--compiler/rustc_error_messages/src/lib.rs1
-rw-r--r--compiler/rustc_errors/src/emitter.rs5
-rw-r--r--compiler/rustc_expand/src/base.rs3
-rw-r--r--compiler/rustc_expand/src/lib.rs1
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs14
-rw-r--r--compiler/rustc_lint/src/internal.rs9
-rw-r--r--compiler/rustc_parse/src/lib.rs1
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs2
-rw-r--r--compiler/rustc_privacy/Cargo.toml7
-rw-r--r--compiler/rustc_privacy/src/errors.rs75
-rw-r--r--compiler/rustc_privacy/src/lib.rs92
-rw-r--r--compiler/rustc_session/src/session.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs21
-rw-r--r--library/alloc/src/boxed/thin.rs8
-rw-r--r--library/core/src/iter/adapters/chain.rs72
-rw-r--r--library/core/src/iter/adapters/flatten.rs41
-rw-r--r--library/core/src/iter/adapters/fuse.rs60
-rw-r--r--library/std/src/sys/hermit/condvar.rs19
-rw-r--r--library/std/src/sys/hermit/mutex.rs4
-rw-r--r--library/std/src/sys/hermit/rwlock.rs11
-rw-r--r--src/test/ui/impl-trait/nested-return-type2.rs8
-rw-r--r--src/test/ui/impl-trait/nested-return-type2.stderr16
-rw-r--r--src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.rs9
-rw-r--r--src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.stdout29
-rw-r--r--src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs32
-rw-r--r--src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout147
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_flatten.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/diagnostics.rs91
-rw-r--r--src/tools/clippy/tests/ui/map_flatten.stderr25
-rw-r--r--src/tools/clippy/tests/ui/map_flatten_fixable.fixed2
-rw-r--r--src/tools/clippy/tests/ui/map_flatten_fixable.stderr54
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.fixed6
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.stderr46
42 files changed, 651 insertions, 445 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 347341b5ff7..96d9449db57 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4280,6 +4280,7 @@ dependencies = [
  "rustc_data_structures",
  "rustc_errors",
  "rustc_hir",
+ "rustc_macros",
  "rustc_middle",
  "rustc_session",
  "rustc_span",
diff --git a/RELEASES.md b/RELEASES.md
index 3d88891ad21..7479735012c 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -29,7 +29,6 @@ Compiler
 Libraries
 ---------
 
-- [Move `CStr` to libcore, and `CString` to liballoc][94079]
 - [Windows: Use a pipe relay for chaining pipes][95841]
 - [Replace Linux Mutex and Condvar with futex based ones.][95035]
 - [Replace RwLock by a futex based one on Linux][95801]
@@ -90,7 +89,6 @@ and related tools.
 
 [93313]: https://github.com/rust-lang/rust/pull/93313/
 [93969]: https://github.com/rust-lang/rust/pull/93969/
-[94079]: https://github.com/rust-lang/rust/pull/94079/
 [94206]: https://github.com/rust-lang/rust/pull/94206/
 [94457]: https://github.com/rust-lang/rust/pull/94457/
 [94775]: https://github.com/rust-lang/rust/pull/94775/
diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs
index a1233d62cb0..708fe8719a1 100644
--- a/compiler/rustc_borrowck/src/borrowck_errors.rs
+++ b/compiler/rustc_borrowck/src/borrowck_errors.rs
@@ -1,4 +1,6 @@
-use rustc_errors::{struct_span_err, DiagnosticBuilder, DiagnosticId, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{
+    struct_span_err, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
+};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
 
@@ -476,10 +478,11 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         struct_span_err!(self, span, E0716, "temporary value dropped while borrowed",)
     }
 
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     fn struct_span_err_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
-        msg: &str,
+        msg: impl Into<DiagnosticMessage>,
         code: DiagnosticId,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         self.infcx.tcx.sess.struct_span_err_with_code(sp, msg, code)
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 8ef2974c372..a2df072aa31 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -6,6 +6,7 @@
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(never_type)]
+#![feature(rustc_attrs)]
 #![feature(stmt_expr_attributes)]
 #![feature(trusted_step)]
 #![feature(try_blocks)]
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index cad30181212..9e50d33486c 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -1,11 +1,10 @@
-use crate::assert::expr_if_not;
 use rustc_ast::{
     attr,
     ptr::P,
     token,
     tokenstream::{DelimSpan, TokenStream, TokenTree},
-    BorrowKind, Expr, ExprKind, ItemKind, MacArgs, MacCall, MacDelimiter, Mutability, Path,
-    PathSegment, Stmt, StructRest, UseTree, UseTreeKind, DUMMY_NODE_ID,
+    BinOpKind, BorrowKind, Expr, ExprKind, ItemKind, MacArgs, MacCall, MacDelimiter, Mutability,
+    Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID,
 };
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
@@ -16,11 +15,19 @@ use rustc_span::{
 };
 
 pub(super) struct Context<'cx, 'a> {
+    // An optimization.
+    //
+    // Elements that aren't consumed (PartialEq, PartialOrd, ...) can be copied **after** the
+    // `assert!` expression fails rather than copied on-the-fly.
+    best_case_captures: Vec<Stmt>,
     // Top-level `let captureN = Capture::new()` statements
     capture_decls: Vec<Capture>,
     cx: &'cx ExtCtxt<'a>,
     // Formatting string used for debugging
     fmt_string: String,
+    // If the current expression being visited consumes itself. Used to construct
+    // `best_case_captures`.
+    is_consumed: bool,
     // Top-level `let __local_bindN = &expr` statements
     local_bind_decls: Vec<Stmt>,
     // Used to avoid capturing duplicated paths
@@ -36,9 +43,11 @@ pub(super) struct Context<'cx, 'a> {
 impl<'cx, 'a> Context<'cx, 'a> {
     pub(super) fn new(cx: &'cx ExtCtxt<'a>, span: Span) -> Self {
         Self {
+            best_case_captures: <_>::default(),
             capture_decls: <_>::default(),
             cx,
             fmt_string: <_>::default(),
+            is_consumed: true,
             local_bind_decls: <_>::default(),
             paths: <_>::default(),
             span,
@@ -69,14 +78,22 @@ impl<'cx, 'a> Context<'cx, 'a> {
         self.manage_cond_expr(&mut cond_expr);
         let initial_imports = self.build_initial_imports();
         let panic = self.build_panic(&expr_str, panic_path);
+        let cond_expr_with_unlikely = self.build_unlikely(cond_expr);
+
+        let Self { best_case_captures, capture_decls, cx, local_bind_decls, span, .. } = self;
 
-        let Self { capture_decls, cx, local_bind_decls, span, .. } = self;
+        let mut assert_then_stmts = Vec::with_capacity(2);
+        assert_then_stmts.extend(best_case_captures);
+        assert_then_stmts.push(self.cx.stmt_expr(panic));
+        let assert_then = self.cx.block(span, assert_then_stmts);
 
         let mut stmts = Vec::with_capacity(4);
         stmts.push(initial_imports);
         stmts.extend(capture_decls.into_iter().map(|c| c.decl));
         stmts.extend(local_bind_decls);
-        stmts.push(cx.stmt_expr(expr_if_not(cx, span, cond_expr, panic, None)));
+        stmts.push(
+            cx.stmt_expr(cx.expr(span, ExprKind::If(cond_expr_with_unlikely, assert_then, None))),
+        );
         cx.expr_block(cx.block(span, stmts))
     }
 
@@ -115,6 +132,16 @@ impl<'cx, 'a> Context<'cx, 'a> {
         )
     }
 
+    /// Takes the conditional expression of `assert!` and then wraps it inside `unlikely`
+    fn build_unlikely(&self, cond_expr: P<Expr>) -> P<Expr> {
+        let unlikely_path = self.cx.std_path(&[sym::intrinsics, sym::unlikely]);
+        self.cx.expr_call(
+            self.span,
+            self.cx.expr_path(self.cx.path(self.span, unlikely_path)),
+            vec![self.cx.expr(self.span, ExprKind::Unary(UnOp::Not, cond_expr))],
+        )
+    }
+
     /// The necessary custom `panic!(...)` expression.
     ///
     /// panic!(
@@ -167,17 +194,39 @@ impl<'cx, 'a> Context<'cx, 'a> {
     /// See [Self::manage_initial_capture] and [Self::manage_try_capture]
     fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
         match (*expr).kind {
-            ExprKind::AddrOf(_, _, ref mut local_expr) => {
-                self.manage_cond_expr(local_expr);
+            ExprKind::AddrOf(_, mutability, ref mut local_expr) => {
+                self.with_is_consumed_management(
+                    matches!(mutability, Mutability::Mut),
+                    |this| this.manage_cond_expr(local_expr)
+                );
             }
             ExprKind::Array(ref mut local_exprs) => {
                 for local_expr in local_exprs {
                     self.manage_cond_expr(local_expr);
                 }
             }
-            ExprKind::Binary(_, ref mut lhs, ref mut rhs) => {
-                self.manage_cond_expr(lhs);
-                self.manage_cond_expr(rhs);
+            ExprKind::Binary(ref op, ref mut lhs, ref mut rhs) => {
+                self.with_is_consumed_management(
+                    matches!(
+                        op.node,
+                        BinOpKind::Add
+                            | BinOpKind::And
+                            | BinOpKind::BitAnd
+                            | BinOpKind::BitOr
+                            | BinOpKind::BitXor
+                            | BinOpKind::Div
+                            | BinOpKind::Mul
+                            | BinOpKind::Or
+                            | BinOpKind::Rem
+                            | BinOpKind::Shl
+                            | BinOpKind::Shr
+                            | BinOpKind::Sub
+                    ),
+                    |this| {
+                        this.manage_cond_expr(lhs);
+                        this.manage_cond_expr(rhs);
+                    }
+                );
             }
             ExprKind::Call(_, ref mut local_exprs) => {
                 for local_expr in local_exprs {
@@ -228,8 +277,11 @@ impl<'cx, 'a> Context<'cx, 'a> {
                     self.manage_cond_expr(local_expr);
                 }
             }
-            ExprKind::Unary(_, ref mut local_expr) => {
-                self.manage_cond_expr(local_expr);
+            ExprKind::Unary(un_op, ref mut local_expr) => {
+                self.with_is_consumed_management(
+                    matches!(un_op, UnOp::Neg | UnOp::Not),
+                    |this| this.manage_cond_expr(local_expr)
+                );
             }
             // Expressions that are not worth or can not be captured.
             //
@@ -337,9 +389,23 @@ impl<'cx, 'a> Context<'cx, 'a> {
             ))
             .add_trailing_semicolon();
         let local_bind_path = self.cx.expr_path(Path::from_ident(local_bind));
-        let ret = self.cx.stmt_expr(local_bind_path);
-        let block = self.cx.expr_block(self.cx.block(self.span, vec![try_capture_call, ret]));
-        *expr = self.cx.expr_deref(self.span, block);
+        let rslt = if self.is_consumed {
+            let ret = self.cx.stmt_expr(local_bind_path);
+            self.cx.expr_block(self.cx.block(self.span, vec![try_capture_call, ret]))
+        } else {
+            self.best_case_captures.push(try_capture_call);
+            local_bind_path
+        };
+        *expr = self.cx.expr_deref(self.span, rslt);
+    }
+
+    // Calls `f` with the internal `is_consumed` set to `curr_is_consumed` and then
+    // sets the internal `is_consumed` back to its original value.
+    fn with_is_consumed_management(&mut self, curr_is_consumed: bool, f: impl FnOnce(&mut Self)) {
+        let prev_is_consumed = self.is_consumed;
+        self.is_consumed = curr_is_consumed;
+        f(self);
+        self.is_consumed = prev_is_consumed;
     }
 }
 
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index 88ff33b4d09..d8b26f9840b 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -826,6 +826,24 @@ cfg_if! {
                 }
             }
         }
+    } else if #[cfg(target_os = "macos")] {
+        pub fn get_resident_set_size() -> Option<usize> {
+            use libc::{c_int, c_void, getpid, proc_pidinfo, proc_taskinfo, PROC_PIDTASKINFO};
+            use std::mem;
+            const PROC_TASKINFO_SIZE: c_int = mem::size_of::<proc_taskinfo>() as c_int;
+
+            unsafe {
+                let mut info: proc_taskinfo = mem::zeroed();
+                let info_ptr = &mut info as *mut proc_taskinfo as *mut c_void;
+                let pid = getpid() as c_int;
+                let ret = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, info_ptr, PROC_TASKINFO_SIZE);
+                if ret == PROC_TASKINFO_SIZE {
+                    Some(info.pti_resident_size as usize)
+                } else {
+                    None
+                }
+            }
+        }
     } else if #[cfg(unix)] {
         pub fn get_resident_set_size() -> Option<usize> {
             let field = 1;
diff --git a/compiler/rustc_error_messages/locales/en-US/privacy.ftl b/compiler/rustc_error_messages/locales/en-US/privacy.ftl
new file mode 100644
index 00000000000..2b0778f48ca
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/privacy.ftl
@@ -0,0 +1,12 @@
+privacy-field-is-private = field `{$field_name}` of {$variant_descr} `{$def_path_str}` is private
+privacy-field-is-private-is-update-syntax-label = field `{$field_name}` is private
+privacy-field-is-private-label = private field
+
+privacy-item-is-private = {$kind} `{$descr}` is private
+    .label = private {$kind}
+privacy-unnamed-item-is-private = {$kind} is private
+    .label = private {$kind}
+
+privacy-in-public-interface = {$vis_descr} {$kind} `{$descr}` in public interface
+    .label = can't leak {$vis_descr} {$kind}
+    .visibility-label = `{$descr}` declared as {$vis_descr}
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 673e160cc1e..90eb5ef5446 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -32,6 +32,7 @@ pub use unic_langid::{langid, LanguageIdentifier};
 // Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
 fluent_messages! {
     parser => "../locales/en-US/parser.ftl",
+    privacy => "../locales/en-US/privacy.ftl",
     typeck => "../locales/en-US/typeck.ftl",
     builtin_macros => "../locales/en-US/builtin_macros.ftl",
 }
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index a4cbc73978d..8b2a995f1c5 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -656,11 +656,6 @@ impl Emitter for SilentEmitter {
     }
 }
 
-/// Maximum number of lines we will print for a multiline suggestion; arbitrary.
-///
-/// This should be replaced with a more involved mechanism to output multiline suggestions that
-/// more closely mimics the regular diagnostic output, where irrelevant code lines are elided.
-pub const MAX_SUGGESTION_HIGHLIGHT_LINES: usize = 6;
 /// Maximum number of suggestions to be shown
 ///
 /// Arbitrary, but taken from trait import suggestion limit
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 245719bff12..1e57d66dd9f 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1077,6 +1077,7 @@ impl<'a> ExtCtxt<'a> {
         self.current_expansion.id.expansion_cause()
     }
 
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_span_err<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -1101,9 +1102,11 @@ impl<'a> ExtCtxt<'a> {
     ///
     /// Compilation will be stopped in the near future (at the end of
     /// the macro expansion phase).
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
         self.sess.parse_sess.span_diagnostic.span_err(sp, msg);
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
         self.sess.parse_sess.span_diagnostic.span_warn(sp, msg);
     }
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 86ff110eec1..c18147592dc 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -9,6 +9,7 @@
 #![feature(proc_macro_diagnostic)]
 #![feature(proc_macro_internals)]
 #![feature(proc_macro_span)]
+#![feature(rustc_attrs)]
 #![feature(try_blocks)]
 #![recursion_limit = "256"]
 
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 7684d861f3c..ebb8d443421 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -39,21 +39,19 @@ pub struct OpaqueTypeDecl<'tcx> {
 }
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
-    /// This is a backwards compatibility hack to prevent breaking changes from
-    /// lazy TAIT around RPIT handling.
-    pub fn replace_opaque_types_with_inference_vars<T: TypeFoldable<'tcx>>(
+    pub fn replace_opaque_types_with_inference_vars(
         &self,
-        value: T,
+        ty: Ty<'tcx>,
         body_id: HirId,
         span: Span,
         code: ObligationCauseCode<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-    ) -> InferOk<'tcx, T> {
-        if !value.has_opaque_types() {
-            return InferOk { value, obligations: vec![] };
+    ) -> InferOk<'tcx, Ty<'tcx>> {
+        if !ty.has_opaque_types() {
+            return InferOk { value: ty, obligations: vec![] };
         }
         let mut obligations = vec![];
-        let value = value.fold_with(&mut ty::fold::BottomUpFolder {
+        let value = ty.fold_with(&mut ty::fold::BottomUpFolder {
             tcx: self.tcx,
             lt_op: |lt| lt,
             ct_op: |ct| ct,
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index fadb1c87933..56c8635a189 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -406,9 +406,12 @@ impl LateLintPass<'_> for Diagnostics {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         let Some((span, def_id, substs)) = typeck_results_of_method_fn(cx, expr) else { return };
         debug!(?span, ?def_id, ?substs);
-        if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) &&
-            !cx.tcx.has_attr(instance.def_id(), sym::rustc_lint_diagnostics)
-        {
+        let has_attr = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs)
+            .ok()
+            .and_then(|inst| inst)
+            .map(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics))
+            .unwrap_or(false);
+        if !has_attr {
             return;
         }
 
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index f3bdd63ee6d..113af328a91 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -6,6 +6,7 @@
 #![feature(let_chains)]
 #![feature(let_else)]
 #![feature(never_type)]
+#![feature(rustc_attrs)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 58d5d43cfbf..0869ed65ad2 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -357,6 +357,7 @@ impl<'a> DerefMut for SnapshotParser<'a> {
 }
 
 impl<'a> Parser<'a> {
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub(super) fn span_err<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -365,6 +366,7 @@ impl<'a> Parser<'a> {
         err.span_err(sp, self.diagnostic())
     }
 
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_span_err<S: Into<MultiSpan>>(
         &self,
         sp: S,
diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml
index d952e288a64..5785921fb1e 100644
--- a/compiler/rustc_privacy/Cargo.toml
+++ b/compiler/rustc_privacy/Cargo.toml
@@ -4,14 +4,15 @@ version = "0.0.0"
 edition = "2021"
 
 [dependencies]
-rustc_middle = { path = "../rustc_middle" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_attr = { path = "../rustc_attr" }
+rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_hir = { path = "../rustc_hir" }
-rustc_typeck = { path = "../rustc_typeck" }
+rustc_macros = { path = "../rustc_macros" }
+rustc_middle = { path = "../rustc_middle" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
-rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
+rustc_typeck = { path = "../rustc_typeck" }
 tracing = "0.1"
diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs
new file mode 100644
index 00000000000..482721d373a
--- /dev/null
+++ b/compiler/rustc_privacy/src/errors.rs
@@ -0,0 +1,75 @@
+use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
+use rustc_span::{Span, Symbol};
+
+#[derive(SessionDiagnostic)]
+#[error(privacy::field_is_private, code = "E0451")]
+pub struct FieldIsPrivate {
+    #[primary_span]
+    pub span: Span,
+    pub field_name: Symbol,
+    pub variant_descr: &'static str,
+    pub def_path_str: String,
+    #[subdiagnostic]
+    pub label: FieldIsPrivateLabel,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub enum FieldIsPrivateLabel {
+    #[label(privacy::field_is_private_is_update_syntax_label)]
+    IsUpdateSyntax {
+        #[primary_span]
+        span: Span,
+        field_name: Symbol,
+    },
+    #[label(privacy::field_is_private_label)]
+    Other {
+        #[primary_span]
+        span: Span,
+    },
+}
+
+#[derive(SessionDiagnostic)]
+#[error(privacy::item_is_private)]
+pub struct ItemIsPrivate<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub kind: &'a str,
+    pub descr: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(privacy::unnamed_item_is_private)]
+pub struct UnnamedItemIsPrivate {
+    #[primary_span]
+    pub span: Span,
+    pub kind: &'static str,
+}
+
+// Duplicate of `InPublicInterface` but with a different error code, shares the same slug.
+#[derive(SessionDiagnostic)]
+#[error(privacy::in_public_interface, code = "E0445")]
+pub struct InPublicInterfaceTraits<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub vis_descr: &'static str,
+    pub kind: &'a str,
+    pub descr: String,
+    #[label(privacy::visibility_label)]
+    pub vis_span: Span,
+}
+
+// Duplicate of `InPublicInterfaceTraits` but with a different error code, shares the same slug.
+#[derive(SessionDiagnostic)]
+#[error(privacy::in_public_interface, code = "E0446")]
+pub struct InPublicInterface<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub vis_descr: &'static str,
+    pub kind: &'a str,
+    pub descr: String,
+    #[label(privacy::visibility_label)]
+    pub vis_span: Span,
+}
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index b27c986d0f9..238c917bbc3 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1,15 +1,19 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(associated_type_defaults)]
 #![feature(control_flow_enum)]
+#![feature(rustc_private)]
 #![feature(try_blocks)]
-#![feature(associated_type_defaults)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
+#![cfg_attr(not(bootstrap), deny(rustc::untranslatable_diagnostic))]
+#![cfg_attr(not(bootstrap), deny(rustc::diagnostic_outside_of_impl))]
+
+mod errors;
 
 use rustc_ast::MacroDef;
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::intern::Interned;
-use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
@@ -34,6 +38,11 @@ use std::marker::PhantomData;
 use std::ops::ControlFlow;
 use std::{cmp, fmt, mem};
 
+use errors::{
+    FieldIsPrivate, FieldIsPrivateLabel, InPublicInterface, InPublicInterfaceTraits, ItemIsPrivate,
+    UnnamedItemIsPrivate,
+};
+
 ////////////////////////////////////////////////////////////////////////////////
 /// Generic infrastructure used to implement specific visitors below.
 ////////////////////////////////////////////////////////////////////////////////
@@ -935,23 +944,17 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
         let hir_id = self.tcx.hir().local_def_id_to_hir_id(self.current_item);
         let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id).1;
         if !field.vis.is_accessible_from(def_id, self.tcx) {
-            let label = if in_update_syntax {
-                format!("field `{}` is private", field.name)
-            } else {
-                "private field".to_string()
-            };
-
-            struct_span_err!(
-                self.tcx.sess,
+            self.tcx.sess.emit_err(FieldIsPrivate {
                 span,
-                E0451,
-                "field `{}` of {} `{}` is private",
-                field.name,
-                def.variant_descr(),
-                self.tcx.def_path_str(def.did())
-            )
-            .span_label(span, label)
-            .emit();
+                field_name: field.name,
+                variant_descr: def.variant_descr(),
+                def_path_str: self.tcx.def_path_str(def.did()),
+                label: if in_update_syntax {
+                    FieldIsPrivateLabel::IsUpdateSyntax { span, field_name: field.name }
+                } else {
+                    FieldIsPrivateLabel::Other { span }
+                },
+            });
         }
     }
 }
@@ -1075,11 +1078,11 @@ impl<'tcx> TypePrivacyVisitor<'tcx> {
     fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
         let is_error = !self.item_is_accessible(def_id);
         if is_error {
-            self.tcx
-                .sess
-                .struct_span_err(self.span, &format!("{} `{}` is private", kind, descr))
-                .span_label(self.span, &format!("private {}", kind))
-                .emit();
+            self.tcx.sess.emit_err(ItemIsPrivate {
+                span: self.span,
+                kind,
+                descr: descr.to_string(),
+            });
         }
         is_error
     }
@@ -1250,13 +1253,10 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
                     hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()),
                 };
                 let kind = kind.descr(def_id);
-                let msg = match name {
-                    Some(name) => format!("{} `{}` is private", kind, name),
-                    None => format!("{} is private", kind),
+                let _ = match name {
+                    Some(name) => sess.emit_err(ItemIsPrivate { span, kind, descr: name }),
+                    None => sess.emit_err(UnnamedItemIsPrivate { span, kind }),
                 };
-                sess.struct_span_err(span, &msg)
-                    .span_label(span, &format!("private {}", kind))
-                    .emit();
                 return;
             }
         }
@@ -1753,22 +1753,31 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
                     }
                 }
             };
-            let make_msg = || format!("{} {} `{}` in public interface", vis_descr, kind, descr);
             let span = self.tcx.def_span(self.item_def_id.to_def_id());
             if self.has_old_errors
                 || self.in_assoc_ty
                 || self.tcx.resolutions(()).has_pub_restricted
             {
-                let mut err = if kind == "trait" {
-                    struct_span_err!(self.tcx.sess, span, E0445, "{}", make_msg())
-                } else {
-                    struct_span_err!(self.tcx.sess, span, E0446, "{}", make_msg())
-                };
+                let descr = descr.to_string();
                 let vis_span =
                     self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id));
-                err.span_label(span, format!("can't leak {} {}", vis_descr, kind));
-                err.span_label(vis_span, format!("`{}` declared as {}", descr, vis_descr));
-                err.emit();
+                if kind == "trait" {
+                    self.tcx.sess.emit_err(InPublicInterfaceTraits {
+                        span,
+                        vis_descr,
+                        kind,
+                        descr,
+                        vis_span,
+                    });
+                } else {
+                    self.tcx.sess.emit_err(InPublicInterface {
+                        span,
+                        vis_descr,
+                        kind,
+                        descr,
+                        vis_span,
+                    });
+                }
             } else {
                 let err_code = if kind == "trait" { "E0445" } else { "E0446" };
                 self.tcx.struct_span_lint_hir(
@@ -1776,7 +1785,12 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
                     hir_id,
                     span,
                     |lint| {
-                        lint.build(&format!("{} (error {})", make_msg(), err_code)).emit();
+                        lint.build(&format!(
+                            "{} (error {})",
+                            format!("{} {} `{}` in public interface", vis_descr, kind, descr),
+                            err_code
+                        ))
+                        .emit();
                     },
                 );
             }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index f1814eebfa6..b5058fd699a 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -280,6 +280,7 @@ impl Session {
         self.crate_types.set(crate_types).expect("`crate_types` was initialized twice")
     }
 
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_span_warn<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -287,6 +288,7 @@ impl Session {
     ) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_span_warn(sp, msg)
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_span_warn_with_expectation<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -295,6 +297,7 @@ impl Session {
     ) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_span_warn_with_expectation(sp, msg, id)
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_span_warn_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -303,9 +306,11 @@ impl Session {
     ) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_span_warn_with_code(sp, msg, code)
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_warn(msg)
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_warn_with_expectation(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -313,6 +318,7 @@ impl Session {
     ) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_warn_with_expectation(msg, id)
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_span_allow<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -320,9 +326,11 @@ impl Session {
     ) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_span_allow(sp, msg)
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_allow(msg)
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_expect(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -330,6 +338,7 @@ impl Session {
     ) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_expect(msg, id)
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_span_err<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -337,6 +346,7 @@ impl Session {
     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
         self.diagnostic().struct_span_err(sp, msg)
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_span_err_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -346,12 +356,14 @@ impl Session {
         self.diagnostic().struct_span_err_with_code(sp, msg, code)
     }
     // FIXME: This method should be removed (every error should have an associated error code).
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_err(
         &self,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
         self.parse_sess.struct_err(msg)
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_err_with_code(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -359,6 +371,7 @@ impl Session {
     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
         self.diagnostic().struct_err_with_code(msg, code)
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_warn_with_code(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -366,6 +379,7 @@ impl Session {
     ) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_warn_with_code(msg, code)
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_span_fatal<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -373,6 +387,7 @@ impl Session {
     ) -> DiagnosticBuilder<'_, !> {
         self.diagnostic().struct_span_fatal(sp, msg)
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -381,13 +396,16 @@ impl Session {
     ) -> DiagnosticBuilder<'_, !> {
         self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
         self.diagnostic().struct_fatal(msg)
     }
 
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
         self.diagnostic().span_fatal(sp, msg)
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn span_fatal_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -396,9 +414,11 @@ impl Session {
     ) -> ! {
         self.diagnostic().span_fatal_with_code(sp, msg, code)
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
         self.diagnostic().fatal(msg).raise()
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn span_err_or_warn<S: Into<MultiSpan>>(
         &self,
         is_warning: bool,
@@ -411,6 +431,7 @@ impl Session {
             self.span_err(sp, msg);
         }
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn span_err<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -418,6 +439,7 @@ impl Session {
     ) -> ErrorGuaranteed {
         self.diagnostic().span_err(sp, msg)
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn span_err_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -426,6 +448,7 @@ impl Session {
     ) {
         self.diagnostic().span_err_with_code(sp, msg, code)
     }
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
         self.diagnostic().err(msg)
     }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 82c54291a5d..aba4f144d4b 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -28,7 +28,6 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
-use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::fold::{MaxUniverse, TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::subst::Subst;
@@ -252,22 +251,10 @@ fn project_and_unify_type<'cx, 'tcx>(
         Err(InProgress) => return ProjectAndUnifyResult::Recursive,
     };
     debug!(?normalized, ?obligations, "project_and_unify_type result");
-    let actual = obligation.predicate.term;
-    // HACK: lazy TAIT would regress src/test/ui/impl-trait/nested-return-type2.rs, so we add
-    // a back-compat hack hat converts the RPITs into inference vars, just like they were before
-    // lazy TAIT.
-    // This does not affect TAITs in general, as tested in the nested-return-type-tait* tests.
-    let InferOk { value: actual, obligations: new } =
-        selcx.infcx().replace_opaque_types_with_inference_vars(
-            actual,
-            obligation.cause.body_id,
-            obligation.cause.span,
-            ObligationCauseCode::MiscObligation,
-            obligation.param_env,
-        );
-    obligations.extend(new);
-
-    match infcx.at(&obligation.cause, obligation.param_env).eq(normalized, actual) {
+    match infcx
+        .at(&obligation.cause, obligation.param_env)
+        .eq(normalized, obligation.predicate.term)
+    {
         Ok(InferOk { obligations: inferred_obligations, value: () }) => {
             obligations.extend(inferred_obligations);
             ProjectAndUnifyResult::Holds(obligations)
diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs
index 807c035fdbd..203e5dff0c7 100644
--- a/library/alloc/src/boxed/thin.rs
+++ b/library/alloc/src/boxed/thin.rs
@@ -33,6 +33,14 @@ pub struct ThinBox<T: ?Sized> {
     _marker: PhantomData<T>,
 }
 
+/// `ThinBox<T>` is `Send` if `T` is `Send` because the data is owned.
+#[unstable(feature = "thin_box", issue = "92791")]
+unsafe impl<T: ?Sized + Send> Send for ThinBox<T> {}
+
+/// `ThinBox<T>` is `Sync` if `T` is `Sync` because the data is owned.
+#[unstable(feature = "thin_box", issue = "92791")]
+unsafe impl<T: ?Sized + Sync> Sync for ThinBox<T> {}
+
 #[unstable(feature = "thin_box", issue = "92791")]
 impl<T> ThinBox<T> {
     /// Moves a type to the heap with its `Metadata` stored in the heap allocation instead of on
diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs
index 53e48500e3b..60eb3a6da3a 100644
--- a/library/core/src/iter/adapters/chain.rs
+++ b/library/core/src/iter/adapters/chain.rs
@@ -37,33 +37,6 @@ impl<A, B> Chain<A, B> {
     }
 }
 
-/// Fuse the iterator if the expression is `None`.
-macro_rules! fuse {
-    ($self:ident . $iter:ident . $($call:tt)+) => {
-        match $self.$iter {
-            Some(ref mut iter) => match iter.$($call)+ {
-                None => {
-                    $self.$iter = None;
-                    None
-                }
-                item => item,
-            },
-            None => None,
-        }
-    };
-}
-
-/// Try an iterator method without fusing,
-/// like an inline `.as_mut().and_then(...)`
-macro_rules! maybe {
-    ($self:ident . $iter:ident . $($call:tt)+) => {
-        match $self.$iter {
-            Some(ref mut iter) => iter.$($call)+,
-            None => None,
-        }
-    };
-}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A, B> Iterator for Chain<A, B>
 where
@@ -74,10 +47,7 @@ where
 
     #[inline]
     fn next(&mut self) -> Option<A::Item> {
-        match fuse!(self.a.next()) {
-            None => maybe!(self.b.next()),
-            item => item,
-        }
+        and_then_or_clear(&mut self.a, Iterator::next).or_else(|| self.b.as_mut()?.next())
     }
 
     #[inline]
@@ -161,7 +131,7 @@ where
             self.a = None;
         }
 
-        maybe!(self.b.nth(n))
+        self.b.as_mut()?.nth(n)
     }
 
     #[inline]
@@ -169,23 +139,15 @@ where
     where
         P: FnMut(&Self::Item) -> bool,
     {
-        match fuse!(self.a.find(&mut predicate)) {
-            None => maybe!(self.b.find(predicate)),
-            item => item,
-        }
+        and_then_or_clear(&mut self.a, |a| a.find(&mut predicate))
+            .or_else(|| self.b.as_mut()?.find(predicate))
     }
 
     #[inline]
     fn last(self) -> Option<A::Item> {
         // Must exhaust a before b.
-        let a_last = match self.a {
-            Some(a) => a.last(),
-            None => None,
-        };
-        let b_last = match self.b {
-            Some(b) => b.last(),
-            None => None,
-        };
+        let a_last = self.a.and_then(Iterator::last);
+        let b_last = self.b.and_then(Iterator::last);
         b_last.or(a_last)
     }
 
@@ -220,10 +182,7 @@ where
 {
     #[inline]
     fn next_back(&mut self) -> Option<A::Item> {
-        match fuse!(self.b.next_back()) {
-            None => maybe!(self.a.next_back()),
-            item => item,
-        }
+        and_then_or_clear(&mut self.b, |b| b.next_back()).or_else(|| self.a.as_mut()?.next_back())
     }
 
     #[inline]
@@ -263,7 +222,7 @@ where
             self.b = None;
         }
 
-        maybe!(self.a.nth_back(n))
+        self.a.as_mut()?.nth_back(n)
     }
 
     #[inline]
@@ -271,10 +230,8 @@ where
     where
         P: FnMut(&Self::Item) -> bool,
     {
-        match fuse!(self.b.rfind(&mut predicate)) {
-            None => maybe!(self.a.rfind(predicate)),
-            item => item,
-        }
+        and_then_or_clear(&mut self.b, |b| b.rfind(&mut predicate))
+            .or_else(|| self.a.as_mut()?.rfind(predicate))
     }
 
     fn try_rfold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
@@ -324,3 +281,12 @@ where
     B: TrustedLen<Item = A::Item>,
 {
 }
+
+#[inline]
+fn and_then_or_clear<T, U>(opt: &mut Option<T>, f: impl FnOnce(&mut T) -> Option<U>) -> Option<U> {
+    let x = f(opt.as_mut()?);
+    if x.is_none() {
+        *opt = None;
+    }
+    x
+}
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index 351fd569d8a..15a120e35a2 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -290,20 +290,11 @@ where
     #[inline]
     fn next(&mut self) -> Option<U::Item> {
         loop {
-            if let Some(ref mut inner) = self.frontiter {
-                match inner.next() {
-                    None => self.frontiter = None,
-                    elt @ Some(_) => return elt,
-                }
+            if let elt @ Some(_) = and_then_or_clear(&mut self.frontiter, Iterator::next) {
+                return elt;
             }
             match self.iter.next() {
-                None => match self.backiter.as_mut()?.next() {
-                    None => {
-                        self.backiter = None;
-                        return None;
-                    }
-                    elt @ Some(_) => return elt,
-                },
+                None => return and_then_or_clear(&mut self.backiter, Iterator::next),
                 Some(inner) => self.frontiter = Some(inner.into_iter()),
             }
         }
@@ -436,21 +427,12 @@ where
     #[inline]
     fn next_back(&mut self) -> Option<U::Item> {
         loop {
-            if let Some(ref mut inner) = self.backiter {
-                match inner.next_back() {
-                    None => self.backiter = None,
-                    elt @ Some(_) => return elt,
-                }
+            if let elt @ Some(_) = and_then_or_clear(&mut self.backiter, |b| b.next_back()) {
+                return elt;
             }
             match self.iter.next_back() {
-                None => match self.frontiter.as_mut()?.next_back() {
-                    None => {
-                        self.frontiter = None;
-                        return None;
-                    }
-                    elt @ Some(_) => return elt,
-                },
-                next => self.backiter = next.map(IntoIterator::into_iter),
+                None => return and_then_or_clear(&mut self.frontiter, |f| f.next_back()),
+                Some(inner) => self.backiter = Some(inner.into_iter()),
             }
         }
     }
@@ -606,3 +588,12 @@ unsafe impl<T, const N: usize> TrustedConstSize for [T; N] {}
 unsafe impl<T, const N: usize> TrustedConstSize for &'_ [T; N] {}
 #[unstable(feature = "std_internals", issue = "none")]
 unsafe impl<T, const N: usize> TrustedConstSize for &'_ mut [T; N] {}
+
+#[inline]
+fn and_then_or_clear<T, U>(opt: &mut Option<T>, f: impl FnOnce(&mut T) -> Option<U>) -> Option<U> {
+    let x = f(opt.as_mut()?);
+    if x.is_none() {
+        *opt = None;
+    }
+    x
+}
diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs
index 8adb53c6714..c9314454203 100644
--- a/library/core/src/iter/adapters/fuse.rs
+++ b/library/core/src/iter/adapters/fuse.rs
@@ -29,33 +29,6 @@ impl<I> Fuse<I> {
 #[stable(feature = "fused", since = "1.26.0")]
 impl<I> FusedIterator for Fuse<I> where I: Iterator {}
 
-/// Fuse the iterator if the expression is `None`.
-macro_rules! fuse {
-    ($self:ident . iter . $($call:tt)+) => {
-        match $self.iter {
-            Some(ref mut iter) => match iter.$($call)+ {
-                None => {
-                    $self.iter = None;
-                    None
-                }
-                item => item,
-            },
-            None => None,
-        }
-    };
-}
-
-/// Specialized macro that doesn't check if the expression is `None`.
-/// (We trust that a `FusedIterator` will fuse itself.)
-macro_rules! spec {
-    ($self:ident . iter . $($call:tt)+) => {
-        match $self.iter {
-            Some(ref mut iter) => iter.$($call)+,
-            None => None,
-        }
-    };
-}
-
 // Any specialized implementation here is made internal
 // to avoid exposing default fns outside this trait.
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -281,12 +254,12 @@ where
 
     #[inline]
     default fn next(&mut self) -> Option<<I as Iterator>::Item> {
-        fuse!(self.iter.next())
+        and_then_or_clear(&mut self.iter, Iterator::next)
     }
 
     #[inline]
     default fn nth(&mut self, n: usize) -> Option<I::Item> {
-        fuse!(self.iter.nth(n))
+        and_then_or_clear(&mut self.iter, |iter| iter.nth(n))
     }
 
     #[inline]
@@ -308,7 +281,7 @@ where
     where
         P: FnMut(&Self::Item) -> bool,
     {
-        fuse!(self.iter.find(predicate))
+        and_then_or_clear(&mut self.iter, |iter| iter.find(predicate))
     }
 
     #[inline]
@@ -316,7 +289,7 @@ where
     where
         I: DoubleEndedIterator,
     {
-        fuse!(self.iter.next_back())
+        and_then_or_clear(&mut self.iter, |iter| iter.next_back())
     }
 
     #[inline]
@@ -324,7 +297,7 @@ where
     where
         I: DoubleEndedIterator,
     {
-        fuse!(self.iter.nth_back(n))
+        and_then_or_clear(&mut self.iter, |iter| iter.nth_back(n))
     }
 
     #[inline]
@@ -348,7 +321,7 @@ where
         P: FnMut(&Self::Item) -> bool,
         I: DoubleEndedIterator,
     {
-        fuse!(self.iter.rfind(predicate))
+        and_then_or_clear(&mut self.iter, |iter| iter.rfind(predicate))
     }
 }
 
@@ -361,12 +334,12 @@ where
 {
     #[inline]
     fn next(&mut self) -> Option<<I as Iterator>::Item> {
-        spec!(self.iter.next())
+        self.iter.as_mut()?.next()
     }
 
     #[inline]
     fn nth(&mut self, n: usize) -> Option<I::Item> {
-        spec!(self.iter.nth(n))
+        self.iter.as_mut()?.nth(n)
     }
 
     #[inline]
@@ -387,7 +360,7 @@ where
     where
         P: FnMut(&Self::Item) -> bool,
     {
-        spec!(self.iter.find(predicate))
+        self.iter.as_mut()?.find(predicate)
     }
 
     #[inline]
@@ -395,7 +368,7 @@ where
     where
         I: DoubleEndedIterator,
     {
-        spec!(self.iter.next_back())
+        self.iter.as_mut()?.next_back()
     }
 
     #[inline]
@@ -403,7 +376,7 @@ where
     where
         I: DoubleEndedIterator,
     {
-        spec!(self.iter.nth_back(n))
+        self.iter.as_mut()?.nth_back(n)
     }
 
     #[inline]
@@ -426,6 +399,15 @@ where
         P: FnMut(&Self::Item) -> bool,
         I: DoubleEndedIterator,
     {
-        spec!(self.iter.rfind(predicate))
+        self.iter.as_mut()?.rfind(predicate)
+    }
+}
+
+#[inline]
+fn and_then_or_clear<T, U>(opt: &mut Option<T>, f: impl FnOnce(&mut T) -> Option<U>) -> Option<U> {
+    let x = f(opt.as_mut()?);
+    if x.is_none() {
+        *opt = None;
     }
+    x
 }
diff --git a/library/std/src/sys/hermit/condvar.rs b/library/std/src/sys/hermit/condvar.rs
index 3f00160e55a..22059ca0dbe 100644
--- a/library/std/src/sys/hermit/condvar.rs
+++ b/library/std/src/sys/hermit/condvar.rs
@@ -3,6 +3,7 @@ use crate::ptr;
 use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
 use crate::sys::hermit::abi;
 use crate::sys::locks::Mutex;
+use crate::sys_common::lazy_box::{LazyBox, LazyInit};
 use crate::time::Duration;
 
 // The implementation is inspired by Andrew D. Birrell's paper
@@ -14,14 +15,26 @@ pub struct Condvar {
     sem2: *const c_void,
 }
 
-pub type MovableCondvar = Condvar;
+pub(crate) type MovableCondvar = LazyBox<Condvar>;
+
+impl LazyInit for Condvar {
+    fn init() -> Box<Self> {
+        Box::new(Self::new())
+    }
+}
 
 unsafe impl Send for Condvar {}
 unsafe impl Sync for Condvar {}
 
 impl Condvar {
-    pub const fn new() -> Condvar {
-        Condvar { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() }
+    pub fn new() -> Self {
+        let mut condvar =
+            Self { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() };
+        unsafe {
+            let _ = abi::sem_init(&mut condvar.sem1, 0);
+            let _ = abi::sem_init(&mut condvar.sem2, 0);
+        }
+        condvar
     }
 
     pub unsafe fn notify_one(&self) {
diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs
index ef44bf411fb..eb15a04ffcf 100644
--- a/library/std/src/sys/hermit/mutex.rs
+++ b/library/std/src/sys/hermit/mutex.rs
@@ -175,9 +175,7 @@ impl Mutex {
     }
 
     #[inline]
-    pub unsafe fn init(&mut self) {
-        self.inner = Spinlock::new(MutexInner::new());
-    }
+    pub unsafe fn init(&mut self) {}
 
     #[inline]
     pub unsafe fn lock(&self) {
diff --git a/library/std/src/sys/hermit/rwlock.rs b/library/std/src/sys/hermit/rwlock.rs
index d43fa08a171..9701bab1f66 100644
--- a/library/std/src/sys/hermit/rwlock.rs
+++ b/library/std/src/sys/hermit/rwlock.rs
@@ -1,9 +1,10 @@
 use crate::cell::UnsafeCell;
-use crate::sys::locks::{Condvar, Mutex};
+use crate::sys::locks::{MovableCondvar, Mutex};
+use crate::sys_common::lazy_box::{LazyBox, LazyInit};
 
 pub struct RwLock {
     lock: Mutex,
-    cond: Condvar,
+    cond: MovableCondvar,
     state: UnsafeCell<State>,
 }
 
@@ -28,7 +29,11 @@ unsafe impl Sync for RwLock {}
 
 impl RwLock {
     pub const fn new() -> RwLock {
-        RwLock { lock: Mutex::new(), cond: Condvar::new(), state: UnsafeCell::new(State::Unlocked) }
+        RwLock {
+            lock: Mutex::new(),
+            cond: MovableCondvar::new(),
+            state: UnsafeCell::new(State::Unlocked),
+        }
     }
 
     #[inline]
diff --git a/src/test/ui/impl-trait/nested-return-type2.rs b/src/test/ui/impl-trait/nested-return-type2.rs
index 39928d543e1..279641a46c3 100644
--- a/src/test/ui/impl-trait/nested-return-type2.rs
+++ b/src/test/ui/impl-trait/nested-return-type2.rs
@@ -1,5 +1,3 @@
-// check-pass
-
 trait Duh {}
 
 impl Duh for i32 {}
@@ -20,11 +18,9 @@ impl<R: Duh, F: FnMut() -> R> Trait for F {
 // the hidden type. We already have obligations registered on the inference
 // var to make it uphold the `: Duh` bound on `Trait::Assoc`. The opaque
 // type does not implement `Duh`, even if its hidden type does.
-// Lazy TAIT would error out, but we inserted a hack to make it work again,
-// keeping backwards compatibility.
 fn foo() -> impl Trait<Assoc = impl Send> {
+    //~^ ERROR `impl Send: Duh` is not satisfied
     || 42
 }
 
-fn main() {
-}
+fn main() {}
diff --git a/src/test/ui/impl-trait/nested-return-type2.stderr b/src/test/ui/impl-trait/nested-return-type2.stderr
new file mode 100644
index 00000000000..f996e99de07
--- /dev/null
+++ b/src/test/ui/impl-trait/nested-return-type2.stderr
@@ -0,0 +1,16 @@
+error[E0277]: the trait bound `impl Send: Duh` is not satisfied
+  --> $DIR/nested-return-type2.rs:21:13
+   |
+LL | fn foo() -> impl Trait<Assoc = impl Send> {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Duh` is not implemented for `impl Send`
+   |
+   = help: the trait `Duh` is implemented for `i32`
+note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2.rs:23:5: 23:10]`
+  --> $DIR/nested-return-type2.rs:12:31
+   |
+LL | impl<R: Duh, F: FnMut() -> R> Trait for F {
+   |                               ^^^^^     ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.rs b/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.rs
deleted file mode 100644
index 1db9d33c72a..00000000000
--- a/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-// check-pass
-// compile-flags: -Z unpretty=expanded
-
-#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
-
-fn main() {
-    let elem = 1i32;
-    assert!(elem == 1);
-}
diff --git a/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.stdout b/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.stdout
deleted file mode 100644
index a590eb32232..00000000000
--- a/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.stdout
+++ /dev/null
@@ -1,29 +0,0 @@
-#![feature(prelude_import)]
-#![no_std]
-// check-pass
-// compile-flags: -Z unpretty=expanded
-
-#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
-#[macro_use]
-extern crate std;
-
-fn main() {
-    let elem = 1i32;
-    {
-        #[allow(unused_imports)]
-        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
-        let mut __capture0 = ::core::asserting::Capture::new();
-        let __local_bind0 = &elem;
-        if !(*{
-                                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
-                                __local_bind0
-                            } == 1) {
-                {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem == 1\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
-                }
-            }
-    };
-}
diff --git a/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs b/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs
new file mode 100644
index 00000000000..5ec84b08ff8
--- /dev/null
+++ b/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs
@@ -0,0 +1,32 @@
+// check-pass
+// compile-flags: -Z unpretty=expanded
+
+#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+
+fn arbitrary_consuming_method_for_demonstration_purposes() {
+    let elem = 1i32;
+    assert!(elem as usize);
+}
+
+fn addr_of() {
+    let elem = 1i32;
+    assert!(&elem);
+}
+
+fn binary() {
+    let elem = 1i32;
+    assert!(elem == 1);
+    assert!(elem >= 1);
+    assert!(elem > 0);
+    assert!(elem < 3);
+    assert!(elem <= 3);
+    assert!(elem != 3);
+}
+
+fn unary() {
+    let elem = &1i32;
+    assert!(*elem);
+}
+
+fn main() {
+}
diff --git a/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout b/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout
new file mode 100644
index 00000000000..90f858f80e6
--- /dev/null
+++ b/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout
@@ -0,0 +1,147 @@
+#![feature(prelude_import)]
+#![no_std]
+// check-pass
+// compile-flags: -Z unpretty=expanded
+
+#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+
+fn arbitrary_consuming_method_for_demonstration_purposes() {
+    let elem = 1i32;
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*{
+                                    (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                                    __local_bind0
+                                } as usize)) {
+
+
+
+
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem as usize\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+}
+fn addr_of() {
+    let elem = 1i32;
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!&*__local_bind0) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: &elem\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+}
+fn binary() {
+    let elem = 1i32;
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*__local_bind0 == 1)) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem == 1\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*__local_bind0 >= 1)) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem >= 1\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*__local_bind0 > 0)) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem > 0\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*__local_bind0 < 3)) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem < 3\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*__local_bind0 <= 3)) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem <= 3\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*__local_bind0 != 3)) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem != 3\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+}
+fn unary() {
+    let elem = &1i32;
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!**__local_bind0) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: *elem\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+}
+fn main() {}
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
index f447940ea3b..8ae84dbb3dc 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg_for_edges;
+use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::is_trait_method;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
@@ -14,17 +14,14 @@ use super::MAP_FLATTEN;
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_arg: &Expr<'_>, map_span: Span) {
     if let Some((caller_ty_name, method_to_use)) = try_get_caller_ty_name_and_method_name(cx, expr, recv, map_arg) {
         let mut applicability = Applicability::MachineApplicable;
-        let help_msgs = [
-            &format!("try replacing `map` with `{}`", method_to_use),
-            "and remove the `.flatten()`",
-        ];
+        
         let closure_snippet = snippet_with_applicability(cx, map_arg.span, "..", &mut applicability);
-        span_lint_and_sugg_for_edges(
+        span_lint_and_sugg(
             cx,
             MAP_FLATTEN,
             expr.span.with_lo(map_span.lo()),
             &format!("called `map(..).flatten()` on `{}`", caller_ty_name),
-            &help_msgs,
+            &format!("try replacing `map` with `{}` and remove the `.flatten()`", method_to_use),
             format!("{}({})", method_to_use, closure_snippet),
             applicability,
         );
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index 448dc4e6147..3d1208824fa 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -4,7 +4,6 @@ use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_mac
 use clippy_utils::ty::{implements_trait, match_type};
 use clippy_utils::{contains_return, is_trait_item, last_path_segment, paths};
 use if_chain::if_chain;
-use rustc_errors::emitter::MAX_SUGGESTION_HIGHLIGHT_LINES;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -33,7 +32,6 @@ pub(super) fn check<'tcx>(
         arg: &hir::Expr<'_>,
         or_has_args: bool,
         span: Span,
-        method_span: Span,
     ) -> bool {
         let is_default_default = || is_trait_item(cx, fun, sym::Default);
 
@@ -56,19 +54,14 @@ pub(super) fn check<'tcx>(
             then {
                 let mut applicability = Applicability::MachineApplicable;
                 let hint = "unwrap_or_default()";
-                let mut sugg_span = span;
+                let sugg_span = span;
 
-                let mut sugg: String = format!(
+                let sugg: String = format!(
                     "{}.{}",
                     snippet_with_applicability(cx, self_expr.span, "..", &mut applicability),
                     hint
                 );
 
-                if sugg.lines().count() > MAX_SUGGESTION_HIGHLIGHT_LINES {
-                    sugg_span = method_span.with_hi(span.hi());
-                    sugg = hint.to_string();
-                }
-
                 span_lint_and_sugg(
                     cx,
                     OR_FUN_CALL,
@@ -178,7 +171,7 @@ pub(super) fn check<'tcx>(
         match inner_arg.kind {
             hir::ExprKind::Call(fun, or_args) => {
                 let or_has_args = !or_args.is_empty();
-                if !check_unwrap_or_default(cx, name, fun, self_arg, arg, or_has_args, expr.span, method_span) {
+                if !check_unwrap_or_default(cx, name, fun, self_arg, arg, or_has_args, expr.span) {
                     let fun_span = if or_has_args { None } else { Some(fun.span) };
                     check_general_case(cx, name, method_span, self_arg, arg, expr.span, fun_span);
                 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index 99e9e3275ab..2564099f4db 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -112,7 +112,6 @@ const LINT_EMISSION_FUNCTIONS: [&[&str]; 8] = [
     &["clippy_utils", "diagnostics", "span_lint_and_sugg"],
     &["clippy_utils", "diagnostics", "span_lint_and_then"],
     &["clippy_utils", "diagnostics", "span_lint_hir_and_then"],
-    &["clippy_utils", "diagnostics", "span_lint_and_sugg_for_edges"],
 ];
 const SUGGESTION_DIAGNOSTIC_BUILDER_METHODS: [(&str, bool); 9] = [
     ("span_suggestion", false),
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index 39595f589c7..7f55db3b31f 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -8,7 +8,7 @@
 //! Thank you!
 //! ~The `INTERNAL_METADATA_COLLECTOR` lint
 
-use rustc_errors::{emitter::MAX_SUGGESTION_HIGHLIGHT_LINES, Applicability, Diagnostic, MultiSpan};
+use rustc_errors::{Applicability, Diagnostic, MultiSpan};
 use rustc_hir::HirId;
 use rustc_lint::{LateContext, Lint, LintContext};
 use rustc_span::source_map::Span;
@@ -219,95 +219,6 @@ pub fn span_lint_and_sugg<'a, T: LintContext>(
     });
 }
 
-/// Like [`span_lint_and_sugg`] with a focus on the edges. The output will either
-/// emit single span or multispan suggestion depending on the number of its lines.
-///
-/// If the given suggestion string has more lines than the maximum display length defined by
-/// [`MAX_SUGGESTION_HIGHLIGHT_LINES`][`rustc_errors::emitter::MAX_SUGGESTION_HIGHLIGHT_LINES`],
-/// this function will split the suggestion and span to showcase the change for the top and
-/// bottom edge of the code. For normal suggestions, in one display window, the help message
-/// will be combined with a colon.
-///
-/// Multipart suggestions like the one being created here currently cannot be
-/// applied by rustfix (See [rustfix#141](https://github.com/rust-lang/rustfix/issues/141)).
-/// Testing rustfix with this lint emission function might require a file with
-/// suggestions that can be fixed and those that can't. See
-/// [clippy#8520](https://github.com/rust-lang/rust-clippy/pull/8520/files) for
-/// an example and of this.
-///
-/// # Example for a long suggestion
-///
-/// ```text
-/// error: called `map(..).flatten()` on `Option`
-///   --> $DIR/map_flatten.rs:8:10
-///    |
-/// LL |           .map(|x| {
-///    |  __________^
-/// LL | |             if x <= 5 {
-/// LL | |                 Some(x)
-/// LL | |             } else {
-/// ...  |
-/// LL | |         })
-/// LL | |         .flatten();
-///    | |__________________^
-///    |
-///   = note: `-D clippy::map-flatten` implied by `-D warnings`
-/// help: try replacing `map` with `and_then`
-///    |
-/// LL ~         .and_then(|x| {
-/// LL +             if x <= 5 {
-/// LL +                 Some(x)
-///    |
-/// help: and remove the `.flatten()`
-///    |
-/// LL +                 None
-/// LL +             }
-/// LL ~         });
-///    |
-/// ```
-pub fn span_lint_and_sugg_for_edges(
-    cx: &LateContext<'_>,
-    lint: &'static Lint,
-    sp: Span,
-    msg: &str,
-    helps: &[&str; 2],
-    sugg: String,
-    applicability: Applicability,
-) {
-    span_lint_and_then(cx, lint, sp, msg, |diag| {
-        let sugg_lines_count = sugg.lines().count();
-        if sugg_lines_count > MAX_SUGGESTION_HIGHLIGHT_LINES {
-            let sm = cx.sess().source_map();
-            if let (Ok(line_upper), Ok(line_bottom)) =
-                (sm.lookup_line(sp.lo()), sm.lookup_line(sp.hi()))
-            {
-                let split_idx = MAX_SUGGESTION_HIGHLIGHT_LINES / 2;
-                let span_upper = sm.span_until_char(
-                    sp.with_hi(line_upper.sf.lines(|lines| lines[line_upper.line + split_idx])),
-                    '\n',
-                );
-                let span_bottom = sp.with_lo(line_bottom.sf.lines(|lines| lines[line_bottom.line - split_idx]));
-
-                let sugg_lines_vec = sugg.lines().collect::<Vec<&str>>();
-                let sugg_upper = sugg_lines_vec[..split_idx].join("\n");
-                let sugg_bottom = sugg_lines_vec[sugg_lines_count - split_idx..].join("\n");
-
-                diag.span_suggestion(span_upper, helps[0], sugg_upper, applicability);
-                diag.span_suggestion(span_bottom, helps[1], sugg_bottom, applicability);
-
-                return;
-            }
-        }
-        diag.span_suggestion_with_style(
-            sp,
-            &helps.join(", "),
-            sugg,
-            applicability,
-            rustc_errors::SuggestionStyle::ShowAlways,
-        );
-    });
-}
-
 /// Create a suggestion made from several `span → replacement`.
 ///
 /// Note: in the JSON format (used by `compiletest_rs`), the help message will
diff --git a/src/tools/clippy/tests/ui/map_flatten.stderr b/src/tools/clippy/tests/ui/map_flatten.stderr
index c9c60df838f..4b2630d6858 100644
--- a/src/tools/clippy/tests/ui/map_flatten.stderr
+++ b/src/tools/clippy/tests/ui/map_flatten.stderr
@@ -12,14 +12,12 @@ LL | |         .flatten();
    | |__________________^
    |
    = note: `-D clippy::map-flatten` implied by `-D warnings`
-help: try replacing `map` with `and_then`
+help: try replacing `map` with `and_then` and remove the `.flatten()`
    |
 LL ~         .and_then(|x| {
 LL +             if x <= 5 {
 LL +                 Some(x)
-   |
-help: and remove the `.flatten()`
-   |
+LL +             } else {
 LL +                 None
 LL +             }
 LL ~         });
@@ -38,14 +36,12 @@ LL | |         })
 LL | |         .flatten();
    | |__________________^
    |
-help: try replacing `map` with `and_then`
+help: try replacing `map` with `and_then` and remove the `.flatten()`
    |
 LL ~         .and_then(|x| {
 LL +             if x == 1 {
 LL +                 Ok(x)
-   |
-help: and remove the `.flatten()`
-   |
+LL +             } else {
 LL +                 Err(0)
 LL +             }
 LL ~         });
@@ -64,14 +60,13 @@ LL | |         })
 LL | |         .flatten();
    | |__________________^
    |
-help: try replacing `map` with `and_then`
+help: try replacing `map` with `and_then` and remove the `.flatten()`
    |
 LL ~         .and_then(|res| {
 LL +             if res > 0 {
 LL +                 do_something();
-   |
-help: and remove the `.flatten()`
-   |
+LL +                 Ok(res)
+LL +             } else {
 LL +                 Err(0)
 LL +             }
 LL ~         });
@@ -90,14 +85,12 @@ LL | |         })
 LL | |         .flatten()
    | |__________________^
    |
-help: try replacing `map` with `filter_map`
+help: try replacing `map` with `filter_map` and remove the `.flatten()`
    |
 LL ~         .filter_map(|some_value| {
 LL +             if some_value > 3 {
 LL +                 Some(some_value)
-   |
-help: and remove the `.flatten()`
-   |
+LL +             } else {
 LL +                 None
 LL +             }
 LL +         })
diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed
index 928e5bd509c..e9b41354c58 100644
--- a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed
+++ b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed
@@ -59,8 +59,6 @@ fn issue8878() {
         .and_then(|_| {
 // we need some newlines
 // so that the span is big enough
-// we need some newlines
-// so that the span is big enough
 // for a splitted output of the diagnostic
             Some("")
  // whitespace beforehand is important as well
diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr
index 828e24acaad..f3b82ad08d0 100644
--- a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr
+++ b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr
@@ -2,79 +2,45 @@ error: called `map(..).flatten()` on `Iterator`
   --> $DIR/map_flatten_fixable.rs:18:47
    |
 LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect();
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id)`
    |
    = note: `-D clippy::map-flatten` implied by `-D warnings`
-help: try replacing `map` with `filter_map`, and remove the `.flatten()`
-   |
-LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id).collect();
-   |                                               ~~~~~~~~~~~~~~~~~~~~~
 
 error: called `map(..).flatten()` on `Iterator`
   --> $DIR/map_flatten_fixable.rs:19:47
    |
 LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect();
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: try replacing `map` with `filter_map`, and remove the `.flatten()`
-   |
-LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_ref).collect();
-   |                                               ~~~~~~~~~~~~~~~~~~~~~~~~~
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_ref)`
 
 error: called `map(..).flatten()` on `Iterator`
   --> $DIR/map_flatten_fixable.rs:20:47
    |
 LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect();
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: try replacing `map` with `filter_map`, and remove the `.flatten()`
-   |
-LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_closure).collect();
-   |                                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_closure)`
 
 error: called `map(..).flatten()` on `Iterator`
   --> $DIR/map_flatten_fixable.rs:21:47
    |
 LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect();
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: try replacing `map` with `filter_map`, and remove the `.flatten()`
-   |
-LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(|x| x.checked_add(1)).collect();
-   |                                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(|x| x.checked_add(1))`
 
 error: called `map(..).flatten()` on `Iterator`
   --> $DIR/map_flatten_fixable.rs:24:47
    |
 LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: try replacing `map` with `flat_map`, and remove the `.flatten()`
-   |
-LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().flat_map(|x| 0..x).collect();
-   |                                               ~~~~~~~~~~~~~~~~~~
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `flat_map` and remove the `.flatten()`: `flat_map(|x| 0..x)`
 
 error: called `map(..).flatten()` on `Option`
   --> $DIR/map_flatten_fixable.rs:27:40
    |
 LL |     let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
-   |                                        ^^^^^^^^^^^^^^^^^^^^
-   |
-help: try replacing `map` with `and_then`, and remove the `.flatten()`
-   |
-LL |     let _: Option<_> = (Some(Some(1))).and_then(|x| x);
-   |                                        ~~~~~~~~~~~~~~~
+   |                                        ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)`
 
 error: called `map(..).flatten()` on `Result`
   --> $DIR/map_flatten_fixable.rs:30:42
    |
 LL |     let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten();
-   |                                          ^^^^^^^^^^^^^^^^^^^^
-   |
-help: try replacing `map` with `and_then`, and remove the `.flatten()`
-   |
-LL |     let _: Result<_, &str> = (Ok(Ok(1))).and_then(|x| x);
-   |                                          ~~~~~~~~~~~~~~~
+   |                                          ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)`
 
 error: called `map(..).flatten()` on `Option`
   --> $DIR/map_flatten_fixable.rs:59:10
@@ -89,14 +55,12 @@ LL | |         })
 LL | |         .flatten();
    | |__________________^
    |
-help: try replacing `map` with `and_then`
+help: try replacing `map` with `and_then` and remove the `.flatten()`
    |
 LL ~         .and_then(|_| {
 LL + // we need some newlines
 LL + // so that the span is big enough
-   |
-help: and remove the `.flatten()`
-   |
+LL + // for a splitted output of the diagnostic
 LL +             Some("")
 LL +  // whitespace beforehand is important as well
 LL ~         });
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index 3208048e0d5..123aed40251 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -185,8 +185,7 @@ mod issue8239 {
             .reduce(|mut acc, f| {
                 acc.push_str(&f);
                 acc
-            })
-            .unwrap_or_default();
+            }).unwrap_or_default();
     }
 
     fn more_to_max_suggestion_highest_lines_1() {
@@ -198,8 +197,7 @@ mod issue8239 {
                 let _ = "";
                 acc.push_str(&f);
                 acc
-            })
-            .unwrap_or_default();
+            }).unwrap_or_default();
     }
 
     fn equal_to_max_suggestion_highest_lines() {
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index 549b00ae3c4..dfe15654bc3 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -109,16 +109,50 @@ LL |         None.unwrap_or( unsafe { ptr_to_ref(s) }    );
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
 
 error: use of `unwrap_or` followed by a call to `new`
-  --> $DIR/or_fun_call.rs:189:14
+  --> $DIR/or_fun_call.rs:182:9
+   |
+LL | /         frames
+LL | |             .iter()
+LL | |             .map(|f: &String| f.to_lowercase())
+LL | |             .reduce(|mut acc, f| {
+...  |
+LL | |             })
+LL | |             .unwrap_or(String::new());
+   | |_____________________________________^
+   |
+help: try this
+   |
+LL ~         frames
+LL +             .iter()
+LL +             .map(|f: &String| f.to_lowercase())
+LL +             .reduce(|mut acc, f| {
+LL +                 acc.push_str(&f);
+LL +                 acc
+LL ~             }).unwrap_or_default();
    |
-LL |             .unwrap_or(String::new());
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
 
 error: use of `unwrap_or` followed by a call to `new`
-  --> $DIR/or_fun_call.rs:202:14
+  --> $DIR/or_fun_call.rs:195:9
+   |
+LL | /         iter.map(|f: &String| f.to_lowercase())
+LL | |             .reduce(|mut acc, f| {
+LL | |                 let _ = "";
+LL | |                 let _ = "";
+...  |
+LL | |             })
+LL | |             .unwrap_or(String::new());
+   | |_____________________________________^
+   |
+help: try this
+   |
+LL ~         iter.map(|f: &String| f.to_lowercase())
+LL +             .reduce(|mut acc, f| {
+LL +                 let _ = "";
+LL +                 let _ = "";
+LL +                 acc.push_str(&f);
+LL +                 acc
+LL ~             }).unwrap_or_default();
    |
-LL |             .unwrap_or(String::new());
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
 
 error: use of `unwrap_or` followed by a call to `new`
   --> $DIR/or_fun_call.rs:208:9