diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 049940d19a651..a153997599aba 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -993,20 +993,33 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 ));
 
                 let msg = "use `.addr()` to obtain the address of a pointer";
-                if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) {
-                    let scalar_cast = match t_c {
-                        ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(),
-                        _ => format!(" as {}", self.cast_ty),
-                    };
+
+                let expr_prec = self.expr.precedence().order();
+                let needs_parens = expr_prec < rustc_ast::util::parser::PREC_POSTFIX;
+
+                let scalar_cast = match t_c {
+                    ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(),
+                    _ => format!(" as {}", self.cast_ty),
+                };
+
+                let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span);
+
+                if needs_parens {
+                    let suggestions = vec![
+                        (self.expr_span.shrink_to_lo(), String::from("(")),
+                        (cast_span, format!(").addr(){scalar_cast}")),
+                    ];
+
+                    err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
+                } else {
                     err.span_suggestion(
-                        self.span,
+                        cast_span,
                         msg,
-                        format!("({snippet}).addr(){scalar_cast}"),
-                        Applicability::MaybeIncorrect
+                        format!(".addr(){scalar_cast}"),
+                        Applicability::MaybeIncorrect,
                     );
-                } else {
-                    err.help(msg);
                 }
+
                 err.help(
                     "if you can't comply with strict provenance and need to expose the pointer \
                     provenance you can use `.expose_addr()` instead"
@@ -1028,16 +1041,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     self.expr_ty, self.cast_ty
                 ));
                 let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address";
-                if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) {
-                    err.span_suggestion(
-                        self.span,
-                        msg,
-                        format!("(...).with_addr({snippet})"),
-                        Applicability::HasPlaceholders,
-                    );
-                } else {
-                    err.help(msg);
-                }
+                let suggestions = vec![
+                    (self.expr_span.shrink_to_lo(), String::from("(...).with_addr(")),
+                    (self.expr_span.shrink_to_hi().to(self.cast_span), String::from(")")),
+                ];
+
+                err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
                 err.help(
                     "if you can't comply with strict provenance and don't have a pointer with \
                     the correct provenance you can use `std::ptr::from_exposed_addr()` instead"
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index 5809ed1f33b07..0bec38a877ed5 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -343,10 +343,10 @@ impl char {
                   without modifying the original"]
     #[inline]
     pub const fn to_digit(self, radix: u32) -> Option<u32> {
-        assert!(radix <= 36, "to_digit: radix is too high (maximum 36)");
         // If not a digit, a number greater than radix will be created.
         let mut digit = (self as u32).wrapping_sub('0' as u32);
         if radix > 10 {
+            assert!(radix <= 36, "to_digit: radix is too high (maximum 36)");
             if digit < 10 {
                 return Some(digit);
             }
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
index d95bc9b15c9c4..9a6778c0e869b 100644
--- a/library/std/src/os/unix/process.rs
+++ b/library/std/src/os/unix/process.rs
@@ -24,8 +24,8 @@ pub trait CommandExt: Sealed {
     #[stable(feature = "rust1", since = "1.0.0")]
     fn uid(
         &mut self,
-        #[cfg(not(target_os = "vxworks"))] id: u32,
-        #[cfg(target_os = "vxworks")] id: u16,
+        #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
+        #[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
     ) -> &mut process::Command;
 
     /// Similar to `uid`, but sets the group ID of the child process. This has
@@ -33,8 +33,8 @@ pub trait CommandExt: Sealed {
     #[stable(feature = "rust1", since = "1.0.0")]
     fn gid(
         &mut self,
-        #[cfg(not(target_os = "vxworks"))] id: u32,
-        #[cfg(target_os = "vxworks")] id: u16,
+        #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
+        #[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
     ) -> &mut process::Command;
 
     /// Sets the supplementary group IDs for the calling process. Translates to
@@ -42,8 +42,8 @@ pub trait CommandExt: Sealed {
     #[unstable(feature = "setgroups", issue = "90747")]
     fn groups(
         &mut self,
-        #[cfg(not(target_os = "vxworks"))] groups: &[u32],
-        #[cfg(target_os = "vxworks")] groups: &[u16],
+        #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] groups: &[u32],
+        #[cfg(any(target_os = "vxworks", target_os = "espidf"))] groups: &[u16],
     ) -> &mut process::Command;
 
     /// Schedules a closure to be run just before the `exec` function is
@@ -160,8 +160,8 @@ pub trait CommandExt: Sealed {
 impl CommandExt for process::Command {
     fn uid(
         &mut self,
-        #[cfg(not(target_os = "vxworks"))] id: u32,
-        #[cfg(target_os = "vxworks")] id: u16,
+        #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
+        #[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
     ) -> &mut process::Command {
         self.as_inner_mut().uid(id);
         self
@@ -169,8 +169,8 @@ impl CommandExt for process::Command {
 
     fn gid(
         &mut self,
-        #[cfg(not(target_os = "vxworks"))] id: u32,
-        #[cfg(target_os = "vxworks")] id: u16,
+        #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] id: u32,
+        #[cfg(any(target_os = "vxworks", target_os = "espidf"))] id: u16,
     ) -> &mut process::Command {
         self.as_inner_mut().gid(id);
         self
@@ -178,8 +178,8 @@ impl CommandExt for process::Command {
 
     fn groups(
         &mut self,
-        #[cfg(not(target_os = "vxworks"))] groups: &[u32],
-        #[cfg(target_os = "vxworks")] groups: &[u16],
+        #[cfg(not(any(target_os = "vxworks", target_os = "espidf")))] groups: &[u32],
+        #[cfg(any(target_os = "vxworks", target_os = "espidf"))] groups: &[u16],
     ) -> &mut process::Command {
         self.as_inner_mut().groups(groups);
         self
diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs
index 3de7c68a6866d..fd5580033e4ca 100644
--- a/library/std/src/sys/unix/fd.rs
+++ b/library/std/src/sys/unix/fd.rs
@@ -109,7 +109,7 @@ impl FileDesc {
                 self.as_raw_fd(),
                 buf.as_mut_ptr() as *mut c_void,
                 cmp::min(buf.len(), READ_LIMIT),
-                offset as i64,
+                offset as libc::off64_t,
             ))
             .map(|n| n as usize)
         }
@@ -176,7 +176,7 @@ impl FileDesc {
                 self.as_raw_fd(),
                 buf.as_ptr() as *const c_void,
                 cmp::min(buf.len(), READ_LIMIT),
-                offset as i64,
+                offset as libc::off64_t,
             ))
             .map(|n| n as usize)
         }
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 7181451de575f..2c3aaa6aa5cfa 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -966,7 +966,7 @@ impl File {
             SeekFrom::End(off) => (libc::SEEK_END, off),
             SeekFrom::Current(off) => (libc::SEEK_CUR, off),
         };
-        let n = cvt(unsafe { lseek64(self.as_raw_fd(), pos, whence) })?;
+        let n = cvt(unsafe { lseek64(self.as_raw_fd(), pos as libc::off64_t, whence) })?;
         Ok(n as u64)
     }
 
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 9534cc5f4341e..d7c29f6900a53 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -221,7 +221,7 @@ impl FromStr for LlvmLibunwind {
     }
 }
 
-#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct TargetSelection {
     pub triple: Interned<String>,
     file: Option<Interned<String>>,
@@ -276,6 +276,12 @@ impl fmt::Display for TargetSelection {
     }
 }
 
+impl fmt::Debug for TargetSelection {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self)
+    }
+}
+
 impl PartialEq<&str> for TargetSelection {
     fn eq(&self, other: &&str) -> bool {
         self.triple == *other
diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py
index 6bb235b2c8347..df215f318239e 100644
--- a/src/etc/htmldocck.py
+++ b/src/etc/htmldocck.py
@@ -285,6 +285,11 @@ def flatten(node):
     return ''.join(acc)
 
 
+def make_xml(text):
+    xml = ET.XML('<xml>%s</xml>' % text)
+    return xml
+
+
 def normalize_xpath(path):
     path = path.replace("{{channel}}", channel)
     if path.startswith('//'):
@@ -401,7 +406,7 @@ def get_tree_count(tree, path):
     return len(tree.findall(path))
 
 
-def check_snapshot(snapshot_name, tree, normalize_to_text):
+def check_snapshot(snapshot_name, actual_tree, normalize_to_text):
     assert rust_test_path.endswith('.rs')
     snapshot_path = '{}.{}.{}'.format(rust_test_path[:-3], snapshot_name, 'html')
     try:
@@ -414,11 +419,15 @@ def check_snapshot(snapshot_name, tree, normalize_to_text):
             raise FailedCheck('No saved snapshot value')
 
     if not normalize_to_text:
-        actual_str = ET.tostring(tree).decode('utf-8')
+        actual_str = ET.tostring(actual_tree).decode('utf-8')
     else:
-        actual_str = flatten(tree)
+        actual_str = flatten(actual_tree)
+
+    if not expected_str \
+        or (not normalize_to_text and
+            not compare_tree(make_xml(actual_str), make_xml(expected_str), stderr)) \
+        or (normalize_to_text and actual_str != expected_str):
 
-    if expected_str != actual_str:
         if bless:
             with open(snapshot_path, 'w') as snapshot_file:
                 snapshot_file.write(actual_str)
@@ -430,6 +439,59 @@ def check_snapshot(snapshot_name, tree, normalize_to_text):
             print()
             raise FailedCheck('Actual snapshot value is different than expected')
 
+
+# Adapted from https://github.com/formencode/formencode/blob/3a1ba9de2fdd494dd945510a4568a3afeddb0b2e/formencode/doctest_xml_compare.py#L72-L120
+def compare_tree(x1, x2, reporter=None):
+    if x1.tag != x2.tag:
+        if reporter:
+            reporter('Tags do not match: %s and %s' % (x1.tag, x2.tag))
+        return False
+    for name, value in x1.attrib.items():
+        if x2.attrib.get(name) != value:
+            if reporter:
+                reporter('Attributes do not match: %s=%r, %s=%r'
+                         % (name, value, name, x2.attrib.get(name)))
+            return False
+    for name in x2.attrib:
+        if name not in x1.attrib:
+            if reporter:
+                reporter('x2 has an attribute x1 is missing: %s'
+                         % name)
+            return False
+    if not text_compare(x1.text, x2.text):
+        if reporter:
+            reporter('text: %r != %r' % (x1.text, x2.text))
+        return False
+    if not text_compare(x1.tail, x2.tail):
+        if reporter:
+            reporter('tail: %r != %r' % (x1.tail, x2.tail))
+        return False
+    cl1 = list(x1)
+    cl2 = list(x2)
+    if len(cl1) != len(cl2):
+        if reporter:
+            reporter('children length differs, %i != %i'
+                     % (len(cl1), len(cl2)))
+        return False
+    i = 0
+    for c1, c2 in zip(cl1, cl2):
+        i += 1
+        if not compare_tree(c1, c2, reporter=reporter):
+            if reporter:
+                reporter('children %i do not match: %s'
+                         % (i, c1.tag))
+            return False
+    return True
+
+
+def text_compare(t1, t2):
+    if not t1 and not t2:
+        return True
+    if t1 == '*' or t2 == '*':
+        return True
+    return (t1 or '').strip() == (t2 or '').strip()
+
+
 def stderr(*args):
     if sys.version_info.major < 3:
         file = codecs.getwriter('utf-8')(sys.stderr)
diff --git a/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.stderr b/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.stderr
index e50d243b6ad6d..c85934aa3ba15 100644
--- a/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.stderr
+++ b/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.stderr
@@ -13,7 +13,7 @@ LL | #![deny(fuzzy_provenance_casts)]
 help: use `.with_addr()` to adjust a valid pointer in the same allocation, to this address
    |
 LL |     let dangling = (...).with_addr(16_usize);
-   |                    ~~~~~~~~~~~~~~~~~~~~~~~~~
+   |                    ++++++++++++++++        ~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lint/lint-strict-provenance-lossy-casts.rs b/src/test/ui/lint/lint-strict-provenance-lossy-casts.rs
index 3690fbc904d99..9799a05375682 100644
--- a/src/test/ui/lint/lint-strict-provenance-lossy-casts.rs
+++ b/src/test/ui/lint/lint-strict-provenance-lossy-casts.rs
@@ -8,4 +8,11 @@ fn main() {
 
     let addr_32bit = &x as *const u8 as u32;
     //~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
+
+    // don't add unnecessary parens in the suggestion
+    let ptr = &x as *const u8;
+    let ptr_addr = ptr as usize;
+    //~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize`
+    let ptr_addr_32bit = ptr as u32;
+    //~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
 }
diff --git a/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr b/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr
index e7a6c1837bd56..05178b34b1146 100644
--- a/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr
+++ b/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr
@@ -2,7 +2,7 @@ error: under strict provenance it is considered bad style to cast pointer `*cons
   --> $DIR/lint-strict-provenance-lossy-casts.rs:6:23
    |
 LL |     let addr: usize = &x as *const u8 as usize;
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.addr()` to obtain the address of a pointer: `(&x as *const u8).addr()`
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/lint-strict-provenance-lossy-casts.rs:2:9
@@ -10,14 +10,42 @@ note: the lint level is defined here
 LL | #![deny(lossy_provenance_casts)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
    = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+help: use `.addr()` to obtain the address of a pointer
+   |
+LL |     let addr: usize = (&x as *const u8).addr();
+   |                       +               ~~~~~~~~
 
 error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
   --> $DIR/lint-strict-provenance-lossy-casts.rs:9:22
    |
 LL |     let addr_32bit = &x as *const u8 as u32;
-   |                      ^^^^^^^^^^^^^^^^^^^^^^ help: use `.addr()` to obtain the address of a pointer: `(&x as *const u8).addr() as u32`
+   |                      ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+help: use `.addr()` to obtain the address of a pointer
+   |
+LL |     let addr_32bit = (&x as *const u8).addr() as u32;
+   |                      +               ~~~~~~~~~~~~~~~
+
+error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize`
+  --> $DIR/lint-strict-provenance-lossy-casts.rs:14:20
+   |
+LL |     let ptr_addr = ptr as usize;
+   |                    ^^^---------
+   |                       |
+   |                       help: use `.addr()` to obtain the address of a pointer: `.addr()`
+   |
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+
+error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
+  --> $DIR/lint-strict-provenance-lossy-casts.rs:16:26
+   |
+LL |     let ptr_addr_32bit = ptr as u32;
+   |                          ^^^-------
+   |                             |
+   |                             help: use `.addr()` to obtain the address of a pointer: `.addr() as u32`
    |
    = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/miri b/src/tools/miri
index c568f32f165d8..1ef91e1227750 160000
--- a/src/tools/miri
+++ b/src/tools/miri
@@ -1 +1 @@
-Subproject commit c568f32f165d86aba51ec544756c3c833acbabd7
+Subproject commit 1ef91e122775060acb1fbda2c9a366891af3ea89