about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-11-17 16:24:54 +0000
committerbors <bors@rust-lang.org>2024-11-17 16:24:54 +0000
commita8e75c53d0036b5d012cbc0ee5de17f8991fe60c (patch)
treebb4be0dcd1f6f02bd5d244beb6d1b6161f85392b
parent23e7ecb34962ecd069cf28ae7db585e92ca2ee63 (diff)
parentdefc8666a38c115fa46ab4ddb4e3d2eeca3c206c (diff)
downloadrust-a8e75c53d0036b5d012cbc0ee5de17f8991fe60c.tar.gz
rust-a8e75c53d0036b5d012cbc0ee5de17f8991fe60c.zip
Auto merge of #133135 - jieyouxu:rollup-4q1wbyq, r=jieyouxu
Rollup of 6 pull requests

Successful merges:

 - #133029 (ABI checks: add support for some tier3 arches, warn on others.)
 - #133051 (Increase accuracy of `if` condition misparse suggestion)
 - #133060 (Trim whitespace in RemoveLet primary span)
 - #133093 (Let chains tests)
 - #133116 (stabilize const_ptr_is_null)
 - #133126 (alloc: fix `String`'s doc)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs6
-rw-r--r--compiler/rustc_monomorphize/src/mono_checks/abi_check.rs4
-rw-r--r--compiler/rustc_parse/src/errors.rs3
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs11
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs2
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs109
-rw-r--r--compiler/rustc_target/src/target_features.rs37
-rw-r--r--library/alloc/src/string.rs2
-rw-r--r--library/core/src/intrinsics/mod.rs16
-rw-r--r--library/core/src/lib.rs3
-rw-r--r--library/core/src/ptr/const_ptr.rs8
-rw-r--r--library/core/src/ptr/mod.rs16
-rw-r--r--library/core/src/ptr/mut_ptr.rs6
-rw-r--r--library/core/src/slice/raw.rs4
-rw-r--r--library/core/src/ub_checks.rs16
-rw-r--r--tests/ui/consts/const-ptr-is-null.rs1
-rw-r--r--tests/ui/consts/const-ptr-is-null.stderr2
-rw-r--r--tests/ui/consts/ptr_is_null.rs1
-rw-r--r--tests/ui/issues/issue-39848.stderr6
-rw-r--r--tests/ui/let-else/let-else-if.stderr2
-rw-r--r--tests/ui/lint/issue-104392.stderr2
-rw-r--r--tests/ui/missing/missing-block-hint.stderr2
-rw-r--r--tests/ui/parser/bad-if-statements.stderr4
-rw-r--r--tests/ui/parser/block-no-opening-brace.stderr6
-rw-r--r--tests/ui/parser/closure-return-syntax.stderr2
-rw-r--r--tests/ui/parser/else-no-if.stderr18
-rw-r--r--tests/ui/parser/label-after-block-like.stderr14
-rw-r--r--tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.fixed39
-rw-r--r--tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.rs39
-rw-r--r--tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.stderr57
-rw-r--r--tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs57
-rw-r--r--tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr101
-rw-r--r--tests/ui/parser/unnecessary-let.fixed13
-rw-r--r--tests/ui/parser/unnecessary-let.rs4
-rw-r--r--tests/ui/parser/unnecessary-let.stderr24
-rw-r--r--tests/ui/pattern/usefulness/conflicting_bindings.rs2
-rw-r--r--tests/ui/pattern/usefulness/conflicting_bindings.stderr18
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs11
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr18
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs25
-rw-r--r--tests/ui/unsafe/unsafe-block-without-braces.stderr2
41 files changed, 602 insertions, 111 deletions
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 62115aef4a7..f12320cb851 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -263,6 +263,12 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
     }
 
     /// See documentation on the `ptr_guaranteed_cmp` intrinsic.
+    /// Returns `2` if the result is unknown.
+    /// Returns `1` if the pointers are guaranteed equal.
+    /// Returns `0` if the pointers are guaranteed inequal.
+    ///
+    /// Note that this intrinsic is exposed on stable for comparison with null. In other words, any
+    /// change to this function that affects comparison with null is insta-stable!
     fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8> {
         interp_ok(match (a, b) {
             // Comparisons between integers are always known.
diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
index d53595929e7..02b361456e4 100644
--- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
+++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
@@ -36,9 +36,7 @@ fn do_check_abi<'tcx>(
     target_feature_def: DefId,
     mut emit_err: impl FnMut(Option<&'static str>),
 ) {
-    let Some(feature_def) = tcx.sess.target.features_for_correct_vector_abi() else {
-        return;
-    };
+    let feature_def = tcx.sess.target.features_for_correct_vector_abi();
     let codegen_attrs = tcx.codegen_fn_attrs(target_feature_def);
     for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) {
         let size = arg_abi.layout.size;
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 7ec4ad6dc35..37eb463cba6 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -650,8 +650,9 @@ pub(crate) struct LeftArrowOperator {
 #[diag(parse_remove_let)]
 pub(crate) struct RemoveLet {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")]
     pub span: Span,
+    #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")]
+    pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 0ac6133e828..0012db471ef 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -2683,6 +2683,13 @@ impl<'a> Parser<'a> {
                 //            ^^
                 //     }
                 //
+                // We account for macro calls that were meant as conditions as well.
+                //
+                //     if ... {
+                //     } else if macro! { foo bar } {
+                //            ^^
+                //     }
+                //
                 // If $cond is "statement-like" such as ExprKind::While then we
                 // want to suggest wrapping in braces.
                 //
@@ -2693,7 +2700,9 @@ impl<'a> Parser<'a> {
                 //     }
                 //     ^
                     if self.check(&TokenKind::OpenDelim(Delimiter::Brace))
-                        && classify::expr_requires_semi_to_be_stmt(&cond) =>
+                        && (classify::expr_requires_semi_to_be_stmt(&cond)
+                            || matches!(cond.kind, ExprKind::MacCall(..)))
+                    =>
                 {
                     self.dcx().emit_err(errors::ExpectedElseBlock {
                         first_tok_span,
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 3546e5b0f04..c4326427f67 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -685,7 +685,7 @@ impl<'a> Parser<'a> {
             self.bump();
             // Trim extra space after the `let`
             let span = lo.with_hi(self.token.span.lo());
-            self.dcx().emit_err(RemoveLet { span });
+            self.dcx().emit_err(RemoveLet { span: lo, suggestion: span });
             lo = self.token.span;
         }
 
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index b7cdae3e3e1..190cd9ed061 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -475,6 +475,7 @@ impl<'a> Parser<'a> {
     }
 
     fn error_block_no_opening_brace_msg(&mut self, msg: Cow<'static, str>) -> Diag<'a> {
+        let prev = self.prev_token.span;
         let sp = self.token.span;
         let mut e = self.dcx().struct_span_err(sp, msg);
         let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon;
@@ -514,8 +515,97 @@ impl<'a> Parser<'a> {
                 } else {
                     stmt.span
                 };
+                self.suggest_fixes_misparsed_for_loop_head(
+                    &mut e,
+                    prev.between(sp),
+                    stmt_span,
+                    &stmt.kind,
+                );
+            }
+            Err(e) => {
+                self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
+                e.cancel();
+            }
+            _ => {}
+        }
+        e.span_label(sp, "expected `{`");
+        e
+    }
+
+    fn suggest_fixes_misparsed_for_loop_head(
+        &self,
+        e: &mut Diag<'_>,
+        between: Span,
+        stmt_span: Span,
+        stmt_kind: &StmtKind,
+    ) {
+        match (&self.token.kind, &stmt_kind) {
+            (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
+                if let ExprKind::Call(..) = expr.kind =>
+            {
+                // for _ in x y() {}
+                e.span_suggestion_verbose(
+                    between,
+                    "you might have meant to write a method call",
+                    ".".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
+                if let ExprKind::Field(..) = expr.kind =>
+            {
+                // for _ in x y.z {}
+                e.span_suggestion_verbose(
+                    between,
+                    "you might have meant to write a field access",
+                    ".".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            (token::CloseDelim(Delimiter::Brace), StmtKind::Expr(expr))
+                if let ExprKind::Struct(expr) = &expr.kind
+                    && let None = expr.qself
+                    && expr.path.segments.len() == 1 =>
+            {
+                // This is specific to "mistyped `if` condition followed by empty body"
+                //
+                // for _ in x y {}
+                e.span_suggestion_verbose(
+                    between,
+                    "you might have meant to write a field access",
+                    ".".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
+                if let ExprKind::Lit(lit) = expr.kind
+                    && let None = lit.suffix
+                    && let token::LitKind::Integer | token::LitKind::Float = lit.kind =>
+            {
+                // for _ in x 0 {}
+                // for _ in x 0.0 {}
+                e.span_suggestion_verbose(
+                    between,
+                    format!("you might have meant to write a field access"),
+                    ".".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
+                if let ExprKind::Loop(..)
+                | ExprKind::If(..)
+                | ExprKind::While(..)
+                | ExprKind::Match(..)
+                | ExprKind::ForLoop { .. }
+                | ExprKind::TryBlock(..)
+                | ExprKind::Ret(..)
+                | ExprKind::Closure(..)
+                | ExprKind::Struct(..)
+                | ExprKind::Try(..) = expr.kind =>
+            {
+                // These are more likely to have been meant as a block body.
                 e.multipart_suggestion(
-                    "try placing this code inside a block",
+                    "you might have meant to write this as part of a block",
                     vec![
                         (stmt_span.shrink_to_lo(), "{ ".to_string()),
                         (stmt_span.shrink_to_hi(), " }".to_string()),
@@ -524,14 +614,19 @@ impl<'a> Parser<'a> {
                     Applicability::MaybeIncorrect,
                 );
             }
-            Err(e) => {
-                self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
-                e.cancel();
+            (token::OpenDelim(Delimiter::Brace), _) => {}
+            (_, _) => {
+                e.multipart_suggestion(
+                    "you might have meant to write this as part of a block",
+                    vec![
+                        (stmt_span.shrink_to_lo(), "{ ".to_string()),
+                        (stmt_span.shrink_to_hi(), " }".to_string()),
+                    ],
+                    // Speculative; has been misleading in the past (#46836).
+                    Applicability::MaybeIncorrect,
+                );
             }
-            _ => {}
         }
-        e.span_label(sp, "expected `{`");
-        e
     }
 
     fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 88536926b11..112eb862663 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -598,7 +598,12 @@ const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[
 const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
     &[/*(64, "zvl64b"), */ (128, "v")];
 // Always warn on SPARC, as the necessary target features cannot be enabled in Rust at the moment.
-const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(128, "vis")*/];
+const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(64, "vis")*/];
+
+const HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
+    &[/*(512, "hvx-length64b"),*/ (1024, "hvx-length128b")];
+const MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "msa")];
+const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vdspv1")];
 
 impl super::spec::Target {
     pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
@@ -620,20 +625,24 @@ impl super::spec::Target {
         }
     }
 
-    // Returns None if we do not support ABI checks on the given target yet.
-    pub fn features_for_correct_vector_abi(&self) -> Option<&'static [(u64, &'static str)]> {
+    pub fn features_for_correct_vector_abi(&self) -> &'static [(u64, &'static str)] {
         match &*self.arch {
-            "x86" | "x86_64" => Some(X86_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "aarch64" | "arm64ec" => Some(AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "arm" => Some(ARM_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "powerpc" | "powerpc64" => Some(POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "loongarch64" => Some(&[]), // on-stack ABI, so we complain about all by-val vectors
-            "riscv32" | "riscv64" => Some(RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "wasm32" | "wasm64" => Some(WASM_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "s390x" => Some(S390X_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "sparc" | "sparc64" => Some(SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            // FIXME: add support for non-tier2 architectures
-            _ => None,
+            "x86" | "x86_64" => X86_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "aarch64" | "arm64ec" => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "arm" => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "powerpc" | "powerpc64" => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "loongarch64" => &[], // on-stack ABI, so we complain about all by-val vectors
+            "riscv32" | "riscv64" => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "wasm32" | "wasm64" => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "s390x" => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "sparc" | "sparc64" => SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "hexagon" => HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "bpf" => &[], // no vector ABI
+            "csky" => CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            // FIXME: for some tier3 targets, we are overly cautious and always give warnings
+            // when passing args in vector registers.
+            _ => &[],
         }
     }
 
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index b042720933b..e0576c25515 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -116,7 +116,7 @@ use crate::vec::Vec;
 /// `String`s are always valid UTF-8. If you need a non-UTF-8 string, consider
 /// [`OsString`]. It is similar, but without the UTF-8 constraint. Because UTF-8
 /// is a variable width encoding, `String`s are typically smaller than an array of
-/// the same `chars`:
+/// the same `char`s:
 ///
 /// ```
 /// use std::mem;
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index c87a6439ec3..6a37c60d9c9 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -3292,8 +3292,8 @@ pub const unsafe fn ptr_offset_from_unsigned<T>(_ptr: *const T, _base: *const T)
 
 /// See documentation of `<*const T>::guaranteed_eq` for details.
 /// Returns `2` if the result is unknown.
-/// Returns `1` if the pointers are guaranteed equal
-/// Returns `0` if the pointers are guaranteed inequal
+/// Returns `1` if the pointers are guaranteed equal.
+/// Returns `0` if the pointers are guaranteed inequal.
 #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020"))]
 #[rustc_intrinsic]
 #[rustc_nounwind]
@@ -4014,9 +4014,9 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
             count: usize = count,
         ) => {
             let zero_size = count == 0 || size == 0;
-            ub_checks::is_aligned_and_not_null(src, align, zero_size)
-                && ub_checks::is_aligned_and_not_null(dst, align, zero_size)
-                && ub_checks::is_nonoverlapping(src, dst, size, count)
+            ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size)
+                && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size)
+                && ub_checks::maybe_is_nonoverlapping(src, dst, size, count)
         }
     );
 
@@ -4120,8 +4120,8 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
                 align: usize = align_of::<T>(),
                 zero_size: bool = T::IS_ZST || count == 0,
             ) =>
-            ub_checks::is_aligned_and_not_null(src, align, zero_size)
-                && ub_checks::is_aligned_and_not_null(dst, align, zero_size)
+            ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size)
+                && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size)
         );
         copy(src, dst, count)
     }
@@ -4202,7 +4202,7 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
                 addr: *const () = dst as *const (),
                 align: usize = align_of::<T>(),
                 zero_size: bool = T::IS_ZST || count == 0,
-            ) => ub_checks::is_aligned_and_not_null(addr, align, zero_size)
+            ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, zero_size)
         );
         write_bytes(dst, val, count)
     }
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 0ce33958941..3b8ac20e527 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -109,6 +109,7 @@
 // tidy-alphabetical-start
 #![cfg_attr(bootstrap, feature(const_exact_div))]
 #![cfg_attr(bootstrap, feature(const_fmt_arguments_new))]
+#![cfg_attr(bootstrap, feature(const_ub_checks))]
 #![feature(array_ptr_get)]
 #![feature(asm_experimental_arch)]
 #![feature(const_align_of_val)]
@@ -121,7 +122,6 @@
 #![feature(const_heap)]
 #![feature(const_nonnull_new)]
 #![feature(const_pin_2)]
-#![feature(const_ptr_is_null)]
 #![feature(const_ptr_sub_ptr)]
 #![feature(const_raw_ptr_comparison)]
 #![feature(const_size_of_val)]
@@ -132,7 +132,6 @@
 #![feature(const_type_id)]
 #![feature(const_type_name)]
 #![feature(const_typed_swap)]
-#![feature(const_ub_checks)]
 #![feature(core_intrinsics)]
 #![feature(coverage_attribute)]
 #![feature(do_not_recommend)]
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 2d7507e2d53..0dbe819acb1 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -29,16 +29,18 @@ impl<T: ?Sized> *const T {
     /// assert!(!ptr.is_null());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
+    #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_diagnostic_item = "ptr_const_is_null"]
     #[inline]
+    #[rustc_allow_const_fn_unstable(const_eval_select)]
     pub const fn is_null(self) -> bool {
         // Compare via a cast to a thin pointer, so fat pointers are only
         // considering their "data" part for null-ness.
         let ptr = self as *const u8;
         const_eval_select!(
             @capture { ptr: *const u8 } -> bool:
-            if const #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] {
+            // This use of `const_raw_ptr_comparison` has been explicitly blessed by t-lang.
+            if const #[rustc_allow_const_fn_unstable(const_raw_ptr_comparison)] {
                 match (ptr).guaranteed_eq(null_mut()) {
                     Some(res) => res,
                     // To remain maximally convervative, we stop execution when we don't
@@ -280,7 +282,7 @@ impl<T: ?Sized> *const T {
     /// }
     /// ```
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
-    #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
+    #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const unsafe fn as_ref<'a>(self) -> Option<&'a T> {
         // SAFETY: the caller must guarantee that `self` is valid
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 603e9044217..805edddfe63 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -1103,9 +1103,9 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
             count: usize = count,
         ) => {
             let zero_size = size == 0 || count == 0;
-            ub_checks::is_aligned_and_not_null(x, align, zero_size)
-                && ub_checks::is_aligned_and_not_null(y, align, zero_size)
-                && ub_checks::is_nonoverlapping(x, y, size, count)
+            ub_checks::maybe_is_aligned_and_not_null(x, align, zero_size)
+                && ub_checks::maybe_is_aligned_and_not_null(y, align, zero_size)
+                && ub_checks::maybe_is_nonoverlapping(x, y, size, count)
         }
     );
 
@@ -1216,7 +1216,7 @@ pub const unsafe fn replace<T>(dst: *mut T, src: T) -> T {
                 addr: *const () = dst as *const (),
                 align: usize = align_of::<T>(),
                 is_zst: bool = T::IS_ZST,
-            ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
+            ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
         );
         mem::replace(&mut *dst, src)
     }
@@ -1369,7 +1369,7 @@ pub const unsafe fn read<T>(src: *const T) -> T {
                 addr: *const () = src as *const (),
                 align: usize = align_of::<T>(),
                 is_zst: bool = T::IS_ZST,
-            ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
+            ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
         );
         crate::intrinsics::read_via_copy(src)
     }
@@ -1573,7 +1573,7 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
                 addr: *mut () = dst as *mut (),
                 align: usize = align_of::<T>(),
                 is_zst: bool = T::IS_ZST,
-            ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
+            ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
         );
         intrinsics::write_via_move(dst, src)
     }
@@ -1745,7 +1745,7 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
                 addr: *const () = src as *const (),
                 align: usize = align_of::<T>(),
                 is_zst: bool = T::IS_ZST,
-            ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
+            ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
         );
         intrinsics::volatile_load(src)
     }
@@ -1825,7 +1825,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
                 addr: *mut () = dst as *mut (),
                 align: usize = align_of::<T>(),
                 is_zst: bool = T::IS_ZST,
-            ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
+            ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
         );
         intrinsics::volatile_store(dst, src);
     }
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 344ba46a50e..f0204bd0f77 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -29,7 +29,7 @@ impl<T: ?Sized> *mut T {
     /// assert!(!ptr.is_null());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
+    #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_diagnostic_item = "ptr_is_null"]
     #[inline]
     pub const fn is_null(self) -> bool {
@@ -271,7 +271,7 @@ impl<T: ?Sized> *mut T {
     /// }
     /// ```
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
-    #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
+    #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const unsafe fn as_ref<'a>(self) -> Option<&'a T> {
         // SAFETY: the caller must guarantee that `self` is valid for a
@@ -619,7 +619,7 @@ impl<T: ?Sized> *mut T {
     /// println!("{s:?}"); // It'll print: "[4, 2, 3]".
     /// ```
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
-    #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
+    #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
         // SAFETY: the caller must guarantee that `self` is be valid for
diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs
index 89840881c4d..319b76899bf 100644
--- a/library/core/src/slice/raw.rs
+++ b/library/core/src/slice/raw.rs
@@ -132,7 +132,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
                 align: usize = align_of::<T>(),
                 len: usize = len,
             ) =>
-            ub_checks::is_aligned_and_not_null(data, align, false)
+            ub_checks::maybe_is_aligned_and_not_null(data, align, false)
                 && ub_checks::is_valid_allocation_size(size, len)
         );
         &*ptr::slice_from_raw_parts(data, len)
@@ -186,7 +186,7 @@ pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a m
                 align: usize = align_of::<T>(),
                 len: usize = len,
             ) =>
-            ub_checks::is_aligned_and_not_null(data, align, false)
+            ub_checks::maybe_is_aligned_and_not_null(data, align, false)
                 && ub_checks::is_valid_allocation_size(size, len)
         );
         &mut *ptr::slice_from_raw_parts_mut(data, len)
diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs
index 8fcbda141da..3e6110c9c88 100644
--- a/library/core/src/ub_checks.rs
+++ b/library/core/src/ub_checks.rs
@@ -64,8 +64,6 @@ macro_rules! assert_unsafe_precondition {
             #[rustc_no_mir_inline]
             #[inline]
             #[rustc_nounwind]
-            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))]
-            #[rustc_allow_const_fn_unstable(const_ptr_is_null, const_ub_checks)] // only for UB checks
             const fn precondition_check($($name:$ty),*) {
                 if !$e {
                     ::core::panicking::panic_nounwind(
@@ -116,12 +114,16 @@ pub(crate) const fn check_language_ub() -> bool {
 /// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the
 /// check is anyway not executed in `const`.
 #[inline]
-#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
-pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize, is_zst: bool) -> bool {
+#[rustc_allow_const_fn_unstable(const_eval_select)]
+pub(crate) const fn maybe_is_aligned_and_not_null(
+    ptr: *const (),
+    align: usize,
+    is_zst: bool,
+) -> bool {
     // This is just for safety checks so we can const_eval_select.
     const_eval_select!(
         @capture { ptr: *const (), align: usize, is_zst: bool } -> bool:
-        if const #[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] {
+        if const {
             is_zst || !ptr.is_null()
         } else {
             ptr.is_aligned_to(align) && (is_zst || !ptr.is_null())
@@ -141,8 +143,8 @@ pub(crate) const fn is_valid_allocation_size(size: usize, len: usize) -> bool {
 /// Note that in const-eval this function just returns `true` and therefore must
 /// only be used with `assert_unsafe_precondition!`, similar to `is_aligned_and_not_null`.
 #[inline]
-#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
-pub(crate) const fn is_nonoverlapping(
+#[rustc_allow_const_fn_unstable(const_eval_select)]
+pub(crate) const fn maybe_is_nonoverlapping(
     src: *const (),
     dst: *const (),
     size: usize,
diff --git a/tests/ui/consts/const-ptr-is-null.rs b/tests/ui/consts/const-ptr-is-null.rs
index 82c293c0ad6..92cf87a9782 100644
--- a/tests/ui/consts/const-ptr-is-null.rs
+++ b/tests/ui/consts/const-ptr-is-null.rs
@@ -1,4 +1,3 @@
-#![feature(const_ptr_is_null)]
 use std::ptr;
 
 const IS_NULL: () = {
diff --git a/tests/ui/consts/const-ptr-is-null.stderr b/tests/ui/consts/const-ptr-is-null.stderr
index 5fd35142818..f71b3752772 100644
--- a/tests/ui/consts/const-ptr-is-null.stderr
+++ b/tests/ui/consts/const-ptr-is-null.stderr
@@ -8,7 +8,7 @@ note: inside `std::ptr::const_ptr::<impl *const T>::is_null::compiletime`
 note: inside `std::ptr::const_ptr::<impl *const i32>::is_null`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 note: inside `MAYBE_NULL`
-  --> $DIR/const-ptr-is-null.rs:17:14
+  --> $DIR/const-ptr-is-null.rs:16:14
    |
 LL |     assert!(!ptr.wrapping_sub(512).is_null());
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/consts/ptr_is_null.rs b/tests/ui/consts/ptr_is_null.rs
index bbf13802312..8b41f5718e8 100644
--- a/tests/ui/consts/ptr_is_null.rs
+++ b/tests/ui/consts/ptr_is_null.rs
@@ -1,7 +1,6 @@
 //@ compile-flags: --crate-type=lib
 //@ check-pass
 
-#![feature(const_ptr_is_null)]
 #![allow(useless_ptr_null_checks)]
 
 const FOO: &usize = &42;
diff --git a/tests/ui/issues/issue-39848.stderr b/tests/ui/issues/issue-39848.stderr
index a6c6c61f170..1ffed2d4a1d 100644
--- a/tests/ui/issues/issue-39848.stderr
+++ b/tests/ui/issues/issue-39848.stderr
@@ -16,10 +16,10 @@ LL |         if $tgt.has_$field() {}
 LL |     get_opt!(bar, foo);
    |     ------------------ in this macro invocation
    = note: this error originates in the macro `get_opt` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: try placing this code inside a block
+help: you might have meant to write a method call
    |
-LL |         if $tgt.has_{ $field() } {}
-   |                     +          +
+LL |         if $tgt.has_.$field() {}
+   |                     +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/let-else/let-else-if.stderr b/tests/ui/let-else/let-else-if.stderr
index 7e2215c8c05..ad36b423150 100644
--- a/tests/ui/let-else/let-else-if.stderr
+++ b/tests/ui/let-else/let-else-if.stderr
@@ -4,7 +4,7 @@ error: conditional `else if` is not supported for `let...else`
 LL |     let Some(_) = Some(()) else if true {
    |                                 ^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL ~     let Some(_) = Some(()) else { if true {
 LL |
diff --git a/tests/ui/lint/issue-104392.stderr b/tests/ui/lint/issue-104392.stderr
index 8e466439ae6..4d8d8c56d41 100644
--- a/tests/ui/lint/issue-104392.stderr
+++ b/tests/ui/lint/issue-104392.stderr
@@ -6,7 +6,7 @@ LL |     { unsafe 92 }
    |       |
    |       while parsing this `unsafe` expression
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     { unsafe { 92 } }
    |              +    +
diff --git a/tests/ui/missing/missing-block-hint.stderr b/tests/ui/missing/missing-block-hint.stderr
index 18719289abd..7a08d70d0ce 100644
--- a/tests/ui/missing/missing-block-hint.stderr
+++ b/tests/ui/missing/missing-block-hint.stderr
@@ -25,7 +25,7 @@ note: the `if` expression is missing a block after this condition
    |
 LL |         if (foo)
    |            ^^^^^
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |             { bar; }
    |             +      +
diff --git a/tests/ui/parser/bad-if-statements.stderr b/tests/ui/parser/bad-if-statements.stderr
index ee839db6455..320b1176993 100644
--- a/tests/ui/parser/bad-if-statements.stderr
+++ b/tests/ui/parser/bad-if-statements.stderr
@@ -29,7 +29,7 @@ note: the `if` expression is missing a block after this condition
    |
 LL |     if true x
    |        ^^^^
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     if true { x }
    |             +   +
@@ -65,7 +65,7 @@ note: the `if` expression is missing a block after this condition
    |
 LL |     if true x else {}
    |        ^^^^
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     if true { x } else {}
    |             +   +
diff --git a/tests/ui/parser/block-no-opening-brace.stderr b/tests/ui/parser/block-no-opening-brace.stderr
index 83360944ed5..b65de4eac3f 100644
--- a/tests/ui/parser/block-no-opening-brace.stderr
+++ b/tests/ui/parser/block-no-opening-brace.stderr
@@ -6,7 +6,7 @@ LL |     loop
 LL |         let x = 0;
    |         ^^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |         { let x = 0; }
    |         +            +
@@ -21,7 +21,7 @@ LL |     while true
 LL |         let x = 0;
    |         ^^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |         { let x = 0; }
    |         +            +
@@ -32,7 +32,7 @@ error: expected `{`, found keyword `let`
 LL |         let x = 0;
    |         ^^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |         { let x = 0; }
    |         +            +
diff --git a/tests/ui/parser/closure-return-syntax.stderr b/tests/ui/parser/closure-return-syntax.stderr
index eb8428854af..aacc31ed871 100644
--- a/tests/ui/parser/closure-return-syntax.stderr
+++ b/tests/ui/parser/closure-return-syntax.stderr
@@ -4,7 +4,7 @@ error: expected `{`, found `22`
 LL |     let x = || -> i32 22;
    |                       ^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     let x = || -> i32 { 22 };
    |                       +    +
diff --git a/tests/ui/parser/else-no-if.stderr b/tests/ui/parser/else-no-if.stderr
index 2e3e8f6b50e..eec64b0f4bc 100644
--- a/tests/ui/parser/else-no-if.stderr
+++ b/tests/ui/parser/else-no-if.stderr
@@ -30,7 +30,7 @@ error: expected `{`, found `falsy`
 LL |     } else falsy();
    |            ^^^^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     } else { falsy() };
    |            +         +
@@ -41,7 +41,7 @@ error: expected `{`, found keyword `loop`
 LL |     } else loop{}
    |            ^^^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     } else { loop{} }
    |            +        +
@@ -65,7 +65,7 @@ error: expected `{`, found `falsy`
 LL |     } else falsy!();
    |            ^^^^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     } else { falsy!() };
    |            +          +
@@ -74,12 +74,14 @@ error: expected `{`, found `falsy`
   --> $DIR/else-no-if.rs:47:12
    |
 LL |     } else falsy! {} {
-   |            ^^^^^ expected `{`
+   |       ---- ^^^^^
+   |       |
+   |       expected an `if` or a block after this `else`
    |
-help: try placing this code inside a block
+help: add an `if` if this is the condition of a chained `else if` statement
    |
-LL |     } else { falsy! {} } {
-   |            +           +
+LL |     } else if falsy! {} {
+   |            ++
 
 error: expected `{`, found `falsy`
   --> $DIR/else-no-if.rs:54:12
@@ -87,7 +89,7 @@ error: expected `{`, found `falsy`
 LL |     } else falsy! {};
    |            ^^^^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     } else { falsy! {} };
    |            +           +
diff --git a/tests/ui/parser/label-after-block-like.stderr b/tests/ui/parser/label-after-block-like.stderr
index be8c679d8ce..4dea225e3f3 100644
--- a/tests/ui/parser/label-after-block-like.stderr
+++ b/tests/ui/parser/label-after-block-like.stderr
@@ -23,7 +23,7 @@ note: the `if` expression is missing a block after this condition
    |
 LL |     if let () = () 'a {}
    |        ^^^^^^^^^^^
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     if let () = () { 'a {} }
    |                    +       +
@@ -53,7 +53,7 @@ note: the `if` expression is missing a block after this condition
    |
 LL |     if true 'a {}
    |        ^^^^
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     if true { 'a {} }
    |             +       +
@@ -80,7 +80,7 @@ LL |     loop 'a {}
    |     |
    |     while parsing this `loop` expression
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     loop { 'a {} }
    |          +       +
@@ -108,7 +108,7 @@ LL |     while true 'a {}
    |     |     this `while` condition successfully parsed
    |     while parsing the body of this `while` expression
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     while true { 'a {} }
    |                +       +
@@ -136,7 +136,7 @@ LL |     while let () = () 'a {}
    |     |     this `while` condition successfully parsed
    |     while parsing the body of this `while` expression
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     while let () = () { 'a {} }
    |                       +       +
@@ -161,7 +161,7 @@ error: expected `{`, found `'a`
 LL |     for _ in 0..0 'a {}
    |                   ^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     for _ in 0..0 { 'a {} }
    |                   +       +
@@ -188,7 +188,7 @@ LL |     unsafe 'a {}
    |     |
    |     while parsing this `unsafe` expression
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     unsafe { 'a {} }
    |            +       +
diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.fixed b/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.fixed
new file mode 100644
index 00000000000..ea9dc4cf6cc
--- /dev/null
+++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.fixed
@@ -0,0 +1,39 @@
+//@ run-rustfix
+#![allow(dead_code)]
+fn main() {
+    for _ in [1, 2, 3].iter().map(|x| x) {}
+    //~^ ERROR expected `{`, found `map`
+    //~| HELP you might have meant to write a method call
+}
+fn foo5() {
+    let x = (vec![1, 2, 3],);
+    for _ in x.0 {}
+    //~^ ERROR expected `{`, found `0`
+    //~| HELP you might have meant to write a field access
+}
+fn foo6() {
+    let x = ((vec![1, 2, 3],),);
+    for _ in x.0.0 {}
+    //~^ ERROR expected `{`, found `0.0`
+    //~| HELP you might have meant to write a field access
+}
+fn foo7() {
+    let x = Some(vec![1, 2, 3]);
+    for _ in x.unwrap() {}
+    //~^ ERROR expected `{`, found `unwrap`
+    //~| HELP you might have meant to write a method call
+}
+fn foo8() {
+    let x = S { a: A { b: vec![1, 2, 3] } };
+    for _ in x.a.b {}
+    //~^ ERROR expected `{`, found `a`
+    //~| HELP you might have meant to write a field access
+}
+
+struct S {
+    a: A,
+}
+
+struct A {
+    b: Vec<i32>,
+}
diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.rs b/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.rs
new file mode 100644
index 00000000000..1833f458a8a
--- /dev/null
+++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.rs
@@ -0,0 +1,39 @@
+//@ run-rustfix
+#![allow(dead_code)]
+fn main() {
+    for _ in [1, 2, 3].iter()map(|x| x) {}
+    //~^ ERROR expected `{`, found `map`
+    //~| HELP you might have meant to write a method call
+}
+fn foo5() {
+    let x = (vec![1, 2, 3],);
+    for _ in x 0 {}
+    //~^ ERROR expected `{`, found `0`
+    //~| HELP you might have meant to write a field access
+}
+fn foo6() {
+    let x = ((vec![1, 2, 3],),);
+    for _ in x 0.0 {}
+    //~^ ERROR expected `{`, found `0.0`
+    //~| HELP you might have meant to write a field access
+}
+fn foo7() {
+    let x = Some(vec![1, 2, 3]);
+    for _ in x unwrap() {}
+    //~^ ERROR expected `{`, found `unwrap`
+    //~| HELP you might have meant to write a method call
+}
+fn foo8() {
+    let x = S { a: A { b: vec![1, 2, 3] } };
+    for _ in x a.b {}
+    //~^ ERROR expected `{`, found `a`
+    //~| HELP you might have meant to write a field access
+}
+
+struct S {
+    a: A,
+}
+
+struct A {
+    b: Vec<i32>,
+}
diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.stderr b/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.stderr
new file mode 100644
index 00000000000..87f76efffa6
--- /dev/null
+++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.stderr
@@ -0,0 +1,57 @@
+error: expected `{`, found `map`
+  --> $DIR/missing-dot-on-if-condition-expression-fixable.rs:4:30
+   |
+LL |     for _ in [1, 2, 3].iter()map(|x| x) {}
+   |                              ^^^ expected `{`
+   |
+help: you might have meant to write a method call
+   |
+LL |     for _ in [1, 2, 3].iter().map(|x| x) {}
+   |                              +
+
+error: expected `{`, found `0`
+  --> $DIR/missing-dot-on-if-condition-expression-fixable.rs:10:16
+   |
+LL |     for _ in x 0 {}
+   |                ^ expected `{`
+   |
+help: you might have meant to write a field access
+   |
+LL |     for _ in x.0 {}
+   |               +
+
+error: expected `{`, found `0.0`
+  --> $DIR/missing-dot-on-if-condition-expression-fixable.rs:16:16
+   |
+LL |     for _ in x 0.0 {}
+   |                ^^^ expected `{`
+   |
+help: you might have meant to write a field access
+   |
+LL |     for _ in x.0.0 {}
+   |               +
+
+error: expected `{`, found `unwrap`
+  --> $DIR/missing-dot-on-if-condition-expression-fixable.rs:22:16
+   |
+LL |     for _ in x unwrap() {}
+   |                ^^^^^^ expected `{`
+   |
+help: you might have meant to write a method call
+   |
+LL |     for _ in x.unwrap() {}
+   |               +
+
+error: expected `{`, found `a`
+  --> $DIR/missing-dot-on-if-condition-expression-fixable.rs:28:16
+   |
+LL |     for _ in x a.b {}
+   |                ^ expected `{`
+   |
+help: you might have meant to write a field access
+   |
+LL |     for _ in x.a.b {}
+   |               +
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs
new file mode 100644
index 00000000000..c4a9ed66a83
--- /dev/null
+++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs
@@ -0,0 +1,57 @@
+fn main() {
+    for _ in [1, 2, 3].iter()map(|x| x) {}
+    //~^ ERROR expected `{`, found `map`
+    //~| HELP you might have meant to write a method call
+}
+fn foo1() {
+    for _ in 1.3f64 cos() {}
+    //~^ ERROR expected `{`, found `cos`
+    //~| HELP you might have meant to write a method call
+}
+fn foo2() {
+    for _ in 1.3 cos {}
+    //~^ ERROR expected `{`, found `cos`
+    //~| HELP you might have meant to write a field access
+}
+fn foo3() {
+    for _ in 1 cos() {}
+    //~^ ERROR expected `{`, found `cos`
+    //~| HELP you might have meant to write a method call
+}
+fn foo4() {
+    for _ in 1 cos {}
+    //~^ ERROR expected `{`, found `cos`
+    //~| HELP you might have meant to write a field access
+}
+fn foo5() {
+    let x = (vec![1, 2, 3],);
+    for _ in x 0 {}
+    //~^ ERROR expected `{`, found `0`
+    //~| HELP you might have meant to write a field access
+}
+fn foo6() {
+    let x = ((vec![1, 2, 3],),);
+    for _ in x 0.0 {}
+    //~^ ERROR expected `{`, found `0.0`
+    //~| HELP you might have meant to write a field access
+}
+fn foo7() {
+    let x = Some(vec![1, 2, 3]);
+    for _ in x unwrap() {}
+    //~^ ERROR expected `{`, found `unwrap`
+    //~| HELP you might have meant to write a method call
+}
+fn foo8() {
+    let x = S { a: A { b: vec![1, 2, 3] } };
+    for _ in x a.b {}
+    //~^ ERROR expected `{`, found `a`
+    //~| HELP you might have meant to write a field access
+}
+
+struct S {
+    a: A,
+}
+
+struct A {
+    b: Vec<i32>,
+}
diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr
new file mode 100644
index 00000000000..bfb72b95682
--- /dev/null
+++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr
@@ -0,0 +1,101 @@
+error: expected `{`, found `map`
+  --> $DIR/missing-dot-on-if-condition-expression.rs:2:30
+   |
+LL |     for _ in [1, 2, 3].iter()map(|x| x) {}
+   |                              ^^^ expected `{`
+   |
+help: you might have meant to write a method call
+   |
+LL |     for _ in [1, 2, 3].iter().map(|x| x) {}
+   |                              +
+
+error: expected `{`, found `cos`
+  --> $DIR/missing-dot-on-if-condition-expression.rs:7:21
+   |
+LL |     for _ in 1.3f64 cos() {}
+   |                     ^^^ expected `{`
+   |
+help: you might have meant to write a method call
+   |
+LL |     for _ in 1.3f64.cos() {}
+   |                    +
+
+error: expected `{`, found `cos`
+  --> $DIR/missing-dot-on-if-condition-expression.rs:12:18
+   |
+LL |     for _ in 1.3 cos {}
+   |                  ^^^ expected `{`
+   |
+help: you might have meant to write a field access
+   |
+LL |     for _ in 1.3.cos {}
+   |                 +
+
+error: expected `{`, found `cos`
+  --> $DIR/missing-dot-on-if-condition-expression.rs:17:16
+   |
+LL |     for _ in 1 cos() {}
+   |                ^^^ expected `{`
+   |
+help: you might have meant to write a method call
+   |
+LL |     for _ in 1.cos() {}
+   |               +
+
+error: expected `{`, found `cos`
+  --> $DIR/missing-dot-on-if-condition-expression.rs:22:16
+   |
+LL |     for _ in 1 cos {}
+   |                ^^^ expected `{`
+   |
+help: you might have meant to write a field access
+   |
+LL |     for _ in 1.cos {}
+   |               +
+
+error: expected `{`, found `0`
+  --> $DIR/missing-dot-on-if-condition-expression.rs:28:16
+   |
+LL |     for _ in x 0 {}
+   |                ^ expected `{`
+   |
+help: you might have meant to write a field access
+   |
+LL |     for _ in x.0 {}
+   |               +
+
+error: expected `{`, found `0.0`
+  --> $DIR/missing-dot-on-if-condition-expression.rs:34:16
+   |
+LL |     for _ in x 0.0 {}
+   |                ^^^ expected `{`
+   |
+help: you might have meant to write a field access
+   |
+LL |     for _ in x.0.0 {}
+   |               +
+
+error: expected `{`, found `unwrap`
+  --> $DIR/missing-dot-on-if-condition-expression.rs:40:16
+   |
+LL |     for _ in x unwrap() {}
+   |                ^^^^^^ expected `{`
+   |
+help: you might have meant to write a method call
+   |
+LL |     for _ in x.unwrap() {}
+   |               +
+
+error: expected `{`, found `a`
+  --> $DIR/missing-dot-on-if-condition-expression.rs:46:16
+   |
+LL |     for _ in x a.b {}
+   |                ^ expected `{`
+   |
+help: you might have meant to write a field access
+   |
+LL |     for _ in x.a.b {}
+   |               +
+
+error: aborting due to 9 previous errors
+
diff --git a/tests/ui/parser/unnecessary-let.fixed b/tests/ui/parser/unnecessary-let.fixed
new file mode 100644
index 00000000000..bdee07e76aa
--- /dev/null
+++ b/tests/ui/parser/unnecessary-let.fixed
@@ -0,0 +1,13 @@
+//@ run-rustfix
+
+fn main() {
+    for _x in [1, 2, 3] {}
+    //~^ ERROR expected pattern, found `let`
+    //~| ERROR missing `in` in `for` loop
+
+    match 1 {
+        1 => {}
+        //~^ ERROR expected pattern, found `let`
+        _ => {}
+    }
+}
diff --git a/tests/ui/parser/unnecessary-let.rs b/tests/ui/parser/unnecessary-let.rs
index 6279109621d..a889d9f7789 100644
--- a/tests/ui/parser/unnecessary-let.rs
+++ b/tests/ui/parser/unnecessary-let.rs
@@ -1,5 +1,7 @@
+//@ run-rustfix
+
 fn main() {
-    for let x of [1, 2, 3] {}
+    for let _x of [1, 2, 3] {}
     //~^ ERROR expected pattern, found `let`
     //~| ERROR missing `in` in `for` loop
 
diff --git a/tests/ui/parser/unnecessary-let.stderr b/tests/ui/parser/unnecessary-let.stderr
index 05ac1faafd4..0b28123747a 100644
--- a/tests/ui/parser/unnecessary-let.stderr
+++ b/tests/ui/parser/unnecessary-let.stderr
@@ -1,31 +1,31 @@
 error: expected pattern, found `let`
-  --> $DIR/unnecessary-let.rs:2:9
+  --> $DIR/unnecessary-let.rs:4:9
    |
-LL |     for let x of [1, 2, 3] {}
-   |         ^^^^
+LL |     for let _x of [1, 2, 3] {}
+   |         ^^^
    |
 help: remove the unnecessary `let` keyword
    |
-LL -     for let x of [1, 2, 3] {}
-LL +     for x of [1, 2, 3] {}
+LL -     for let _x of [1, 2, 3] {}
+LL +     for _x of [1, 2, 3] {}
    |
 
 error: missing `in` in `for` loop
-  --> $DIR/unnecessary-let.rs:2:15
+  --> $DIR/unnecessary-let.rs:4:16
    |
-LL |     for let x of [1, 2, 3] {}
-   |               ^^
+LL |     for let _x of [1, 2, 3] {}
+   |                ^^
    |
 help: try using `in` here instead
    |
-LL |     for let x in [1, 2, 3] {}
-   |               ~~
+LL |     for let _x in [1, 2, 3] {}
+   |                ~~
 
 error: expected pattern, found `let`
-  --> $DIR/unnecessary-let.rs:7:9
+  --> $DIR/unnecessary-let.rs:9:9
    |
 LL |         let 1 => {}
-   |         ^^^^
+   |         ^^^
    |
 help: remove the unnecessary `let` keyword
    |
diff --git a/tests/ui/pattern/usefulness/conflicting_bindings.rs b/tests/ui/pattern/usefulness/conflicting_bindings.rs
index 0b3e7ce9e9a..16737e0a894 100644
--- a/tests/ui/pattern/usefulness/conflicting_bindings.rs
+++ b/tests/ui/pattern/usefulness/conflicting_bindings.rs
@@ -10,6 +10,8 @@ fn main() {
     //~^ ERROR: mutable more than once
     if let Some(ref mut y @ ref mut z) = x && true {}
     //~^ ERROR: mutable more than once
+    if let Some(_) = Some(()) && let Some(ref mut y @ ref mut z) = x && true {}
+    //~^ ERROR: mutable more than once
     while let Some(ref mut y @ ref mut z) = x {}
     //~^ ERROR: mutable more than once
     while let Some(ref mut y @ ref mut z) = x && true {}
diff --git a/tests/ui/pattern/usefulness/conflicting_bindings.stderr b/tests/ui/pattern/usefulness/conflicting_bindings.stderr
index 679fc83e7f5..6f6504e6f64 100644
--- a/tests/ui/pattern/usefulness/conflicting_bindings.stderr
+++ b/tests/ui/pattern/usefulness/conflicting_bindings.stderr
@@ -31,7 +31,15 @@ LL |     if let Some(ref mut y @ ref mut z) = x && true {}
    |                 value is mutably borrowed by `y` here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/conflicting_bindings.rs:13:20
+  --> $DIR/conflicting_bindings.rs:13:43
+   |
+LL |     if let Some(_) = Some(()) && let Some(ref mut y @ ref mut z) = x && true {}
+   |                                           ^^^^^^^^^   --------- value is mutably borrowed by `z` here
+   |                                           |
+   |                                           value is mutably borrowed by `y` here
+
+error: cannot borrow value as mutable more than once at a time
+  --> $DIR/conflicting_bindings.rs:15:20
    |
 LL |     while let Some(ref mut y @ ref mut z) = x {}
    |                    ^^^^^^^^^   --------- value is mutably borrowed by `z` here
@@ -39,7 +47,7 @@ LL |     while let Some(ref mut y @ ref mut z) = x {}
    |                    value is mutably borrowed by `y` here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/conflicting_bindings.rs:15:20
+  --> $DIR/conflicting_bindings.rs:17:20
    |
 LL |     while let Some(ref mut y @ ref mut z) = x && true {}
    |                    ^^^^^^^^^   --------- value is mutably borrowed by `z` here
@@ -47,7 +55,7 @@ LL |     while let Some(ref mut y @ ref mut z) = x && true {}
    |                    value is mutably borrowed by `y` here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/conflicting_bindings.rs:18:9
+  --> $DIR/conflicting_bindings.rs:20:9
    |
 LL |         ref mut y @ ref mut z => {}
    |         ^^^^^^^^^   --------- value is mutably borrowed by `z` here
@@ -55,12 +63,12 @@ LL |         ref mut y @ ref mut z => {}
    |         value is mutably borrowed by `y` here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/conflicting_bindings.rs:21:24
+  --> $DIR/conflicting_bindings.rs:23:24
    |
 LL |         () if let Some(ref mut y @ ref mut z) = x => {}
    |                        ^^^^^^^^^   --------- value is mutably borrowed by `z` here
    |                        |
    |                        value is mutably borrowed by `y` here
 
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs
index 5c333cd7795..47653efffb7 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs
@@ -94,4 +94,15 @@ fn use_in_arm_ok(c: bool) {
     };
 }
 
+fn use_in_same_chain(c: bool) {
+    let x: Box<_> = Box::new(1);
+
+    let v = (1, 2);
+
+    match v {
+        (1, 2) if let y = x && c && let z = x => false, //~ ERROR use of moved value: `x`
+        _ => true,
+    };
+}
+
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr
index 087e54244b3..123c5f19430 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr
@@ -60,6 +60,22 @@ help: borrow this binding in the pattern to avoid moving the value
 LL |         (1, 2) if let ref y = x && c => false,
    |                       +++
 
-error: aborting due to 4 previous errors
+error[E0382]: use of moved value: `x`
+  --> $DIR/move-guard-if-let-chain.rs:103:41
+   |
+LL |     let x: Box<_> = Box::new(1);
+   |         - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+...
+LL |         (1, 2) if let y = x && c && let z = x => false,
+   |                       -                 ^ value used here after move
+   |                       |
+   |                       value moved here
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         (1, 2) if let ref y = x && c && let z = x => false,
+   |                       +++
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs
new file mode 100644
index 00000000000..389c76337f0
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs
@@ -0,0 +1,25 @@
+// issue-103476
+//@ compile-flags: -Zlint-mir -Zunstable-options
+//@ edition: 2024
+//@ check-pass
+
+#![feature(let_chains)]
+#![allow(irrefutable_let_patterns)]
+
+struct Pd;
+
+impl Pd {
+    fn it(&self) -> It {
+        todo!()
+    }
+}
+
+pub struct It<'a>(Box<dyn Tr<'a>>);
+
+trait Tr<'a> {}
+
+fn f(m: Option<Pd>) {
+    if let Some(n) = m && let it = n.it() {};
+}
+
+fn main() {}
diff --git a/tests/ui/unsafe/unsafe-block-without-braces.stderr b/tests/ui/unsafe/unsafe-block-without-braces.stderr
index d29e49d73a6..3d8234c15e7 100644
--- a/tests/ui/unsafe/unsafe-block-without-braces.stderr
+++ b/tests/ui/unsafe/unsafe-block-without-braces.stderr
@@ -6,7 +6,7 @@ LL |     unsafe //{
 LL |         std::mem::transmute::<f32, u32>(1.0);
    |         ^^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |         { std::mem::transmute::<f32, u32>(1.0); }
    |         +                                       +