about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-01-10 03:26:29 +0000
committerbors <bors@rust-lang.org>2023-01-10 03:26:29 +0000
commitdeba5ddd0776108c51a69844d0ffe3f96886dd52 (patch)
treefd0f493b3efc585f9779903c7451d10a016a958b
parentd53924d8c7046aee91c7f83bf4c9c788c2406a7d (diff)
parented840a6c3b953c54e221951910bb33b351bec145 (diff)
downloadrust-deba5ddd0776108c51a69844d0ffe3f96886dd52.tar.gz
rust-deba5ddd0776108c51a69844d0ffe3f96886dd52.zip
Auto merge of #106656 - JohnTitor:rollup-rk2qltg, r=JohnTitor
Rollup of 9 pull requests

Successful merges:

 - #105034 (Add example for iterator_flatten)
 - #105708 (Enable atomic cas for bpf targets)
 - #106175 (Fix bad import suggestion with nested `use` tree)
 - #106204 (No need to take opaques in `check_type_bounds`)
 - #106387 (Revert "bootstrap: Get rid of `tail_args` in `stream_cargo`")
 - #106636 (Accept old spelling of Fuchsia target triples)
 - #106639 (update Miri)
 - #106640 (update test for inductive canonical cycles)
 - #106647 (rustdoc: merge common CSS for `a`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs2
-rw-r--r--compiler/rustc_const_eval/src/util/compare_types.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs18
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs3
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs5
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs6
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/table.rs5
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs13
-rw-r--r--compiler/rustc_resolve/src/imports.rs81
-rw-r--r--compiler/rustc_target/src/spec/aarch64_fuchsia.rs1
-rw-r--r--compiler/rustc_target/src/spec/bpf_base.rs6
-rw-r--r--compiler/rustc_target/src/spec/mod.rs6
-rw-r--r--compiler/rustc_target/src/spec/x86_64_fuchsia.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs3
-rw-r--r--compiler/rustc_traits/src/codegen.rs2
-rw-r--r--library/core/src/iter/traits/iterator.rs12
-rw-r--r--src/bootstrap/check.rs41
-rw-r--r--src/bootstrap/compile.rs12
-rw-r--r--src/bootstrap/tool.rs2
-rw-r--r--src/doc/rustc/src/platform-support.md2
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css5
-rw-r--r--src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr5
-rw-r--r--src/test/ui/imports/bad-import-in-nested.rs27
-rw-r--r--src/test/ui/imports/bad-import-in-nested.stderr30
-rw-r--r--src/test/ui/imports/bad-import-with-rename.rs16
-rw-r--r--src/test/ui/imports/bad-import-with-rename.stderr25
-rw-r--r--src/test/ui/test-attrs/inaccessible-test-modules.stderr13
-rw-r--r--src/test/ui/traits/solver-cycles/inductive-canonical-cycle.rs75
-rw-r--r--src/test/ui/traits/solver-cycles/inductive-canonical-cycle.stderr26
-rw-r--r--src/tools/miri/cargo-miri/src/phases.rs2
-rwxr-xr-xsrc/tools/miri/ci.sh3
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs12
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs2
-rw-r--r--src/tools/miri/src/helpers.rs11
-rw-r--r--src/tools/miri/src/range_map.rs1
-rw-r--r--src/tools/miri/src/shims/env.rs6
-rw-r--r--src/tools/miri/src/shims/os_str.rs51
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs40
-rw-r--r--src/tools/miri/test_dependencies/Cargo.lock81
-rw-r--r--src/tools/miri/test_dependencies/Cargo.toml4
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/aliasing_mut3.stderr4
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr2
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation2.stderr2
-rw-r--r--src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs57
-rw-r--r--src/tools/miri/tests/pass/shims/env/current_exe.rs1
48 files changed, 553 insertions, 177 deletions
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index d82d4cc39fb..4fe14c7af2f 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -318,7 +318,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
 
         // This is still required for many(half of the tests in ui/type-alias-impl-trait)
         // tests to pass
-        let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+        let _ = infcx.take_opaque_types();
 
         if errors.is_empty() {
             definition_ty
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 8778a19eeda..7a3db191f0c 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -209,7 +209,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
     );
 
     translate_outlives_facts(&mut checker);
-    let opaque_type_values = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+    let opaque_type_values = infcx.take_opaque_types();
 
     let opaque_type_values = opaque_type_values
         .into_iter()
diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs
index be786569cde..f5f3d5de6b5 100644
--- a/compiler/rustc_const_eval/src/util/compare_types.rs
+++ b/compiler/rustc_const_eval/src/util/compare_types.rs
@@ -58,6 +58,6 @@ pub fn is_subtype<'tcx>(
     // even if they're constrained in our current function.
     //
     // It seems very unlikely that this hides any bugs.
-    let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+    let _ = infcx.take_opaque_types();
     errors.is_empty()
 }
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index ef563360c4c..43795cfba3f 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -475,7 +475,7 @@ fn check_opaque_meets_bounds<'tcx>(
         }
     }
     // Clean up after ourselves
-    let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+    let _ = infcx.take_opaque_types();
 }
 
 fn is_enum_of_nonnullable_ptr<'tcx>(
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index b260b929beb..7af89934d14 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -424,7 +424,7 @@ fn compare_asyncness<'tcx>(
             ty::Alias(ty::Opaque, ..) => {
                 // allow both `async fn foo()` and `fn foo() -> impl Future`
             }
-            ty::Error(rustc_errors::ErrorGuaranteed { .. }) => {
+            ty::Error(_) => {
                 // We don't know if it's ok, but at least it's already an error.
             }
             _ => {
@@ -1972,22 +1972,6 @@ pub(super) fn check_type_bounds<'tcx>(
         &outlives_environment,
     )?;
 
-    let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
-    for (key, value) in constraints {
-        infcx
-            .err_ctxt()
-            .report_mismatched_types(
-                &ObligationCause::misc(
-                    value.hidden_type.span,
-                    tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()),
-                ),
-                tcx.mk_opaque(key.def_id.to_def_id(), key.substs),
-                value.hidden_type.ty,
-                TypeError::Mismatch,
-            )
-            .emit();
-    }
-
     Ok(())
 }
 
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index bb956ddc780..8c24b600644 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -534,8 +534,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
 
     #[instrument(skip(self), level = "debug")]
     fn visit_opaque_types(&mut self) {
-        let opaque_types =
-            self.fcx.infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+        let opaque_types = self.fcx.infcx.take_opaque_types();
         for (opaque_type_key, decl) in opaque_types {
             let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span);
             let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span);
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 108011013f5..3d49182f0b8 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -156,10 +156,7 @@ impl<'tcx> InferCtxt<'tcx> {
     /// As the new solver does canonicalization slightly differently, this is also used there
     /// for now. This should hopefully change fairly soon.
     pub fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> {
-        self.inner
-            .borrow_mut()
-            .opaque_type_storage
-            .take_opaque_types()
+        std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types)
             .into_iter()
             .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty))
             .collect()
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 31b546581e4..6bef3f000a5 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1338,6 +1338,12 @@ impl<'tcx> InferCtxt<'tcx> {
         var_infos
     }
 
+    #[instrument(level = "debug", skip(self), ret)]
+    pub fn take_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> {
+        debug_assert_ne!(self.defining_use_anchor, DefiningAnchor::Error);
+        std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types)
+    }
+
     pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
         self.resolve_vars_if_possible(t).to_string()
     }
diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs
index c146902d594..ae4b85c8799 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/table.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs
@@ -29,11 +29,6 @@ impl<'tcx> OpaqueTypeStorage<'tcx> {
         }
     }
 
-    #[instrument(level = "debug", ret)]
-    pub fn take_opaque_types(&mut self) -> OpaqueTypeMap<'tcx> {
-        std::mem::take(&mut self.opaque_types)
-    }
-
     #[inline]
     pub(crate) fn with_log<'a>(
         &'a mut self,
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 37771693417..7d62d67d64f 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -161,6 +161,7 @@ impl<'a> Resolver<'a> {
                     found_use,
                     DiagnosticMode::Normal,
                     path,
+                    "",
                 );
                 err.emit();
             } else if let Some((span, msg, sugg, appl)) = suggestion {
@@ -690,6 +691,7 @@ impl<'a> Resolver<'a> {
                         FoundUse::Yes,
                         DiagnosticMode::Pattern,
                         vec![],
+                        "",
                     );
                 }
                 err
@@ -1344,6 +1346,7 @@ impl<'a> Resolver<'a> {
             FoundUse::Yes,
             DiagnosticMode::Normal,
             vec![],
+            "",
         );
 
         if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
@@ -2309,7 +2312,7 @@ enum FoundUse {
 }
 
 /// Whether a binding is part of a pattern or a use statement. Used for diagnostics.
-enum DiagnosticMode {
+pub(crate) enum DiagnosticMode {
     Normal,
     /// The binding is part of a pattern
     Pattern,
@@ -2324,6 +2327,8 @@ pub(crate) fn import_candidates(
     // This is `None` if all placement locations are inside expansions
     use_placement_span: Option<Span>,
     candidates: &[ImportSuggestion],
+    mode: DiagnosticMode,
+    append: &str,
 ) {
     show_candidates(
         session,
@@ -2333,8 +2338,9 @@ pub(crate) fn import_candidates(
         candidates,
         Instead::Yes,
         FoundUse::Yes,
-        DiagnosticMode::Import,
+        mode,
         vec![],
+        append,
     );
 }
 
@@ -2352,6 +2358,7 @@ fn show_candidates(
     found_use: FoundUse,
     mode: DiagnosticMode,
     path: Vec<Segment>,
+    append: &str,
 ) {
     if candidates.is_empty() {
         return;
@@ -2416,7 +2423,7 @@ fn show_candidates(
                 // produce an additional newline to separate the new use statement
                 // from the directly following item.
                 let additional_newline = if let FoundUse::Yes = found_use { "" } else { "\n" };
-                candidate.0 = format!("{}{};\n{}", add_use, &candidate.0, additional_newline);
+                candidate.0 = format!("{add_use}{}{append};\n{additional_newline}", &candidate.0);
             }
 
             err.span_suggestions(
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 4d896b05526..00f65ac37b6 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -1,6 +1,6 @@
 //! A bunch of methods and structures more or less related to resolving imports.
 
-use crate::diagnostics::{import_candidates, Suggestion};
+use crate::diagnostics::{import_candidates, DiagnosticMode, Suggestion};
 use crate::Determinacy::{self, *};
 use crate::Namespace::*;
 use crate::{module_to_string, names_to_string, ImportSuggestion};
@@ -402,7 +402,7 @@ struct UnresolvedImportError {
     label: Option<String>,
     note: Option<String>,
     suggestion: Option<Suggestion>,
-    candidate: Option<Vec<ImportSuggestion>>,
+    candidates: Option<Vec<ImportSuggestion>>,
 }
 
 pub struct ImportResolver<'a, 'b> {
@@ -475,12 +475,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                     errors = vec![];
                 }
                 if seen_spans.insert(err.span) {
-                    let path = import_path_to_string(
-                        &import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
-                        &import.kind,
-                        err.span,
-                    );
-                    errors.push((path, err));
+                    errors.push((import, err));
                     prev_root_id = import.root_id;
                 }
             } else if is_indeterminate {
@@ -494,10 +489,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                     label: None,
                     note: None,
                     suggestion: None,
-                    candidate: None,
+                    candidates: None,
                 };
+                // FIXME: there should be a better way of doing this than
+                // formatting this as a string then checking for `::`
                 if path.contains("::") {
-                    errors.push((path, err))
+                    errors.push((import, err))
                 }
             }
         }
@@ -507,7 +504,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         }
     }
 
-    fn throw_unresolved_import_error(&self, errors: Vec<(String, UnresolvedImportError)>) {
+    fn throw_unresolved_import_error(&self, errors: Vec<(&Import<'_>, UnresolvedImportError)>) {
         if errors.is_empty() {
             return;
         }
@@ -516,7 +513,17 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         const MAX_LABEL_COUNT: usize = 10;
 
         let span = MultiSpan::from_spans(errors.iter().map(|(_, err)| err.span).collect());
-        let paths = errors.iter().map(|(path, _)| format!("`{}`", path)).collect::<Vec<_>>();
+        let paths = errors
+            .iter()
+            .map(|(import, err)| {
+                let path = import_path_to_string(
+                    &import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
+                    &import.kind,
+                    err.span,
+                );
+                format!("`{path}`")
+            })
+            .collect::<Vec<_>>();
         let msg = format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),);
 
         let mut diag = struct_span_err!(self.r.session, span, E0432, "{}", &msg);
@@ -525,7 +532,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
             diag.note(note);
         }
 
-        for (_, err) in errors.into_iter().take(MAX_LABEL_COUNT) {
+        for (import, err) in errors.into_iter().take(MAX_LABEL_COUNT) {
             if let Some(label) = err.label {
                 diag.span_label(err.span, label);
             }
@@ -538,14 +545,36 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                 diag.multipart_suggestion(&msg, suggestions, applicability);
             }
 
-            if let Some(candidate) = &err.candidate {
-                import_candidates(
-                    self.r.session,
-                    &self.r.untracked.source_span,
-                    &mut diag,
-                    Some(err.span),
-                    &candidate,
-                )
+            if let Some(candidates) = &err.candidates {
+                match &import.kind {
+                    ImportKind::Single { nested: false, source, target, .. } => import_candidates(
+                        self.r.session,
+                        &self.r.untracked.source_span,
+                        &mut diag,
+                        Some(err.span),
+                        &candidates,
+                        DiagnosticMode::Import,
+                        (source != target)
+                            .then(|| format!(" as {target}"))
+                            .as_deref()
+                            .unwrap_or(""),
+                    ),
+                    ImportKind::Single { nested: true, source, target, .. } => {
+                        import_candidates(
+                            self.r.session,
+                            &self.r.untracked.source_span,
+                            &mut diag,
+                            None,
+                            &candidates,
+                            DiagnosticMode::Normal,
+                            (source != target)
+                                .then(|| format!(" as {target}"))
+                                .as_deref()
+                                .unwrap_or(""),
+                        );
+                    }
+                    _ => {}
+                }
             }
         }
 
@@ -707,14 +736,14 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                                 String::from("a similar path exists"),
                                 Applicability::MaybeIncorrect,
                             )),
-                            candidate: None,
+                            candidates: None,
                         },
                         None => UnresolvedImportError {
                             span,
                             label: Some(label),
                             note: None,
                             suggestion,
-                            candidate: None,
+                            candidates: None,
                         },
                     };
                     return Some(err);
@@ -761,7 +790,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                                 )),
                                 note: None,
                                 suggestion: None,
-                                candidate: None,
+                                candidates: None,
                             });
                         }
                     }
@@ -873,7 +902,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                 let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter());
                 let names = resolutions
                     .filter_map(|(BindingKey { ident: i, .. }, resolution)| {
-                        if *i == ident {
+                        if i.name == ident.name {
                             return None;
                         } // Never suggest the same name
                         match *resolution.borrow() {
@@ -943,7 +972,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                     label: Some(label),
                     note,
                     suggestion,
-                    candidate: if !parent_suggestion.is_empty() {
+                    candidates: if !parent_suggestion.is_empty() {
                         Some(parent_suggestion)
                     } else {
                         None
diff --git a/compiler/rustc_target/src/spec/aarch64_fuchsia.rs b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs
new file mode 100644
index 00000000000..ddecbb1a8c4
--- /dev/null
+++ b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs
@@ -0,0 +1 @@
+pub use crate::spec::aarch64_unknown_fuchsia::target;
diff --git a/compiler/rustc_target/src/spec/bpf_base.rs b/compiler/rustc_target/src/spec/bpf_base.rs
index baf36587147..2b00cda44b5 100644
--- a/compiler/rustc_target/src/spec/bpf_base.rs
+++ b/compiler/rustc_target/src/spec/bpf_base.rs
@@ -6,7 +6,7 @@ pub fn opts(endian: Endian) -> TargetOptions {
         allow_asm: true,
         endian,
         linker_flavor: LinkerFlavor::Bpf,
-        atomic_cas: false,
+        atomic_cas: true,
         dynamic_linking: true,
         no_builtins: true,
         panic_strategy: PanicStrategy::Abort,
@@ -19,6 +19,10 @@ pub fn opts(endian: Endian) -> TargetOptions {
         obj_is_bitcode: true,
         requires_lto: false,
         singlethread: true,
+        // When targeting the `v3` cpu in llvm, 32-bit atomics are also supported.
+        // But making this value change based on the target cpu can be mostly confusing
+        // and would require a bit of a refactor.
+        min_atomic_width: Some(64),
         max_atomic_width: Some(64),
         ..Default::default()
     }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 0fafa52a45b..1e80b8b759d 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -981,7 +981,7 @@ impl fmt::Display for StackProtector {
 }
 
 macro_rules! supported_targets {
-    ( $(($triple:literal, $module:ident ),)+ ) => {
+    ( $(($triple:literal, $module:ident),)+ ) => {
         $(mod $module;)+
 
         /// List of supported targets
@@ -1109,7 +1109,11 @@ supported_targets! {
     ("x86_64-apple-darwin", x86_64_apple_darwin),
     ("i686-apple-darwin", i686_apple_darwin),
 
+    // FIXME(#106649): Remove aarch64-fuchsia in favor of aarch64-unknown-fuchsia
+    ("aarch64-fuchsia", aarch64_fuchsia),
     ("aarch64-unknown-fuchsia", aarch64_unknown_fuchsia),
+    // FIXME(#106649): Remove x86_64-fuchsia in favor of x86_64-unknown-fuchsia
+    ("x86_64-fuchsia", x86_64_fuchsia),
     ("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia),
 
     ("avr-unknown-gnu-atmega328", avr_unknown_gnu_atmega328),
diff --git a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
new file mode 100644
index 00000000000..96fed097566
--- /dev/null
+++ b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
@@ -0,0 +1 @@
+pub use crate::spec::x86_64_unknown_fuchsia::target;
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 2bab380dba0..37b40a2f75a 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -450,9 +450,6 @@ pub fn impossible_predicates<'tcx>(
     }
     let errors = ocx.select_all_or_error();
 
-    // Clean up after ourselves
-    let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
-
     let result = !errors.is_empty();
     debug!("impossible_predicates = {:?}", result);
     result
diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs
index f8f74b732ef..f127ef8343f 100644
--- a/compiler/rustc_traits/src/codegen.rs
+++ b/compiler/rustc_traits/src/codegen.rs
@@ -82,7 +82,7 @@ pub fn codegen_select_candidate<'tcx>(
     // Opaque types may have gotten their hidden types constrained, but we can ignore them safely
     // as they will get constrained elsewhere, too.
     // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass
-    let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+    let _ = infcx.take_opaque_types();
 
     Ok(&*tcx.arena.alloc(impl_source))
 }
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index fc4d4bff24f..99aaf798e41 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -1514,6 +1514,18 @@ pub trait Iterator {
     /// assert_eq!(merged, "alphabetagamma");
     /// ```
     ///
+    /// Flattening works on any `IntoIterator` type, including `Option` and `Result`:
+    ///
+    /// ```
+    /// let options = vec![Some(123), Some(321), None, Some(231)];
+    /// let flattened_options: Vec<_> = options.into_iter().flatten().collect();
+    /// assert_eq!(flattened_options, vec![123, 321, 231]);
+    ///
+    /// let results = vec![Ok(123), Ok(321), Err(456), Ok(231)];
+    /// let flattened_results: Vec<_> = results.into_iter().flatten().collect();
+    /// assert_eq!(flattened_results, vec![123, 321, 231]);
+    /// ```
+    ///
     /// Flattening only removes one level of nesting at a time:
     ///
     /// ```
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index b203ecd3844..2771bd2264c 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -99,13 +99,20 @@ impl Step for Std {
             cargo_subcommand(builder.kind),
         );
         std_cargo(builder, target, compiler.stage, &mut cargo);
-        cargo.args(args(builder));
 
         builder.info(&format!(
             "Checking stage{} library artifacts ({} -> {})",
             builder.top_stage, &compiler.host, target
         ));
-        run_cargo(builder, cargo, &libstd_stamp(builder, compiler, target), vec![], true, false);
+        run_cargo(
+            builder,
+            cargo,
+            args(builder),
+            &libstd_stamp(builder, compiler, target),
+            vec![],
+            true,
+            false,
+        );
 
         // We skip populating the sysroot in non-zero stage because that'll lead
         // to rlib/rmeta conflicts if std gets built during this session.
@@ -149,7 +156,6 @@ impl Step for Std {
         for krate in builder.in_tree_crates("test", Some(target)) {
             cargo.arg("-p").arg(krate.name);
         }
-        cargo.args(args(builder));
 
         builder.info(&format!(
             "Checking stage{} library test/bench/example targets ({} -> {})",
@@ -158,6 +164,7 @@ impl Step for Std {
         run_cargo(
             builder,
             cargo,
+            args(builder),
             &libstd_test_stamp(builder, compiler, target),
             vec![],
             true,
@@ -226,13 +233,20 @@ impl Step for Rustc {
         for krate in builder.in_tree_crates("rustc-main", Some(target)) {
             cargo.arg("-p").arg(krate.name);
         }
-        cargo.args(args(builder));
 
         builder.info(&format!(
             "Checking stage{} compiler artifacts ({} -> {})",
             builder.top_stage, &compiler.host, target
         ));
-        run_cargo(builder, cargo, &librustc_stamp(builder, compiler, target), vec![], true, false);
+        run_cargo(
+            builder,
+            cargo,
+            args(builder),
+            &librustc_stamp(builder, compiler, target),
+            vec![],
+            true,
+            false,
+        );
 
         let libdir = builder.sysroot_libdir(compiler, target);
         let hostdir = builder.sysroot_libdir(compiler, compiler.host);
@@ -279,7 +293,6 @@ impl Step for CodegenBackend {
             .arg("--manifest-path")
             .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
         rustc_cargo_env(builder, &mut cargo, target);
-        cargo.args(args(builder));
 
         builder.info(&format!(
             "Checking stage{} {} artifacts ({} -> {})",
@@ -289,6 +302,7 @@ impl Step for CodegenBackend {
         run_cargo(
             builder,
             cargo,
+            args(builder),
             &codegen_backend_stamp(builder, compiler, target, backend),
             vec![],
             true,
@@ -345,13 +359,19 @@ impl Step for RustAnalyzer {
             cargo.arg("--benches");
         }
 
-        cargo.args(args(builder));
-
         builder.info(&format!(
             "Checking stage{} {} artifacts ({} -> {})",
             compiler.stage, "rust-analyzer", &compiler.host.triple, target.triple
         ));
-        run_cargo(builder, cargo, &stamp(builder, compiler, target), vec![], true, false);
+        run_cargo(
+            builder,
+            cargo,
+            args(builder),
+            &stamp(builder, compiler, target),
+            vec![],
+            true,
+            false,
+        );
 
         /// Cargo's output path in a given stage, compiled by a particular
         /// compiler for the specified target.
@@ -405,8 +425,6 @@ macro_rules! tool_check_step {
                     cargo.arg("--all-targets");
                 }
 
-                cargo.args(args(builder));
-
                 // Enable internal lints for clippy and rustdoc
                 // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]`
                 // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
@@ -422,6 +440,7 @@ macro_rules! tool_check_step {
                 run_cargo(
                     builder,
                     cargo,
+                    args(builder),
                     &stamp(builder, compiler, target),
                     vec![],
                     true,
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 147ded3a9ee..6b211d3ec6e 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -144,6 +144,7 @@ impl Step for Std {
         run_cargo(
             builder,
             cargo,
+            vec![],
             &libstd_stamp(builder, compiler, target),
             target_deps,
             false,
@@ -738,6 +739,7 @@ impl Step for Rustc {
         run_cargo(
             builder,
             cargo,
+            vec![],
             &librustc_stamp(builder, compiler, target),
             vec![],
             false,
@@ -998,7 +1000,7 @@ impl Step for CodegenBackend {
             "Building stage{} codegen backend {} ({} -> {})",
             compiler.stage, backend, &compiler.host, target
         ));
-        let files = run_cargo(builder, cargo, &tmp_stamp, vec![], false, false);
+        let files = run_cargo(builder, cargo, vec![], &tmp_stamp, vec![], false, false);
         if builder.config.dry_run() {
             return;
         }
@@ -1422,6 +1424,7 @@ pub fn add_to_sysroot(
 pub fn run_cargo(
     builder: &Builder<'_>,
     cargo: Cargo,
+    tail_args: Vec<String>,
     stamp: &Path,
     additional_target_deps: Vec<(PathBuf, DependencyType)>,
     is_check: bool,
@@ -1448,7 +1451,7 @@ pub fn run_cargo(
     // files we need to probe for later.
     let mut deps = Vec::new();
     let mut toplevel = Vec::new();
-    let ok = stream_cargo(builder, cargo, &mut |msg| {
+    let ok = stream_cargo(builder, cargo, tail_args, &mut |msg| {
         let (filenames, crate_types) = match msg {
             CargoMessage::CompilerArtifact {
                 filenames,
@@ -1585,6 +1588,7 @@ pub fn run_cargo(
 pub fn stream_cargo(
     builder: &Builder<'_>,
     cargo: Cargo,
+    tail_args: Vec<String>,
     cb: &mut dyn FnMut(CargoMessage<'_>),
 ) -> bool {
     let mut cargo = Command::from(cargo);
@@ -1604,6 +1608,10 @@ pub fn stream_cargo(
     }
     cargo.arg("--message-format").arg(message_format).stdout(Stdio::piped());
 
+    for arg in tail_args {
+        cargo.arg(arg);
+    }
+
     builder.verbose(&format!("running: {:?}", cargo));
     let mut child = match cargo.spawn() {
         Ok(child) => child,
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index 63026bd44d4..24b033cc0dc 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -72,7 +72,7 @@ impl Step for ToolBuild {
 
         builder.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target));
         let mut duplicates = Vec::new();
-        let is_expected = compile::stream_cargo(builder, cargo, &mut |msg| {
+        let is_expected = compile::stream_cargo(builder, cargo, vec![], &mut |msg| {
             // Only care about big things like the RLS/Cargo for now
             match tool {
                 "rls" | "cargo" | "clippy-driver" | "miri" | "rustfmt" => {}
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 7ff26e420f1..16057048259 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -124,6 +124,7 @@ target | std | notes
 -------|:---:|-------
 `aarch64-apple-ios` | ✓ | ARM64 iOS
 [`aarch64-apple-ios-sim`](platform-support/aarch64-apple-ios-sim.md) | ✓ | Apple iOS Simulator on ARM64
+`aarch64-fuchsia` | ✓ | Alias for `aarch64-unknown-fuchsia`
 `aarch64-unknown-fuchsia` | ✓ | ARM64 Fuchsia
 [`aarch64-linux-android`](platform-support/android.md) | ✓ | ARM64 Android
 `aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat
@@ -177,6 +178,7 @@ target | std | notes
 `wasm32-wasi` | ✓ | WebAssembly with WASI
 `x86_64-apple-ios` | ✓ | 64-bit x86 iOS
 [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX
+`x86_64-fuchsia` | ✓ | Alias for `x86_64-unknown-fuchsia`
 `x86_64-unknown-fuchsia` | ✓ | 64-bit Fuchsia
 [`x86_64-linux-android`](platform-support/android.md) | ✓ | 64-bit x86 Android
 `x86_64-pc-solaris` | ✓ | 64-bit Solaris 10/11, illumos
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 77401e8b76e..8ec4631f7d0 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -253,6 +253,7 @@ h1 a,
 
 a {
 	color: var(--link-color);
+	text-decoration: none;
 }
 
 ol, ul {
@@ -662,10 +663,6 @@ nav.sub {
 	margin: 0 0 15px 0;
 }
 
-a {
-	text-decoration: none;
-}
-
 .small-section-header {
 	/* fields use <span> tags, but should get their own lines */
 	display: block;
diff --git a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr
index e89c19b5881..f1f4caee361 100644
--- a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr
+++ b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr
@@ -2,10 +2,7 @@ error[E0432]: unresolved import `my_core`
   --> $DIR/extern-prelude-from-opaque-fail.rs:20:9
    |
 LL |     use my_core;
-   |         ^^^^^^^
-   |         |
-   |         no `my_core` in the root
-   |         help: a similar name exists in the module: `my_core`
+   |         ^^^^^^^ no `my_core` in the root
 
 error[E0432]: unresolved import `my_core`
   --> $DIR/extern-prelude-from-opaque-fail.rs:7:13
diff --git a/src/test/ui/imports/bad-import-in-nested.rs b/src/test/ui/imports/bad-import-in-nested.rs
new file mode 100644
index 00000000000..2e95480ad41
--- /dev/null
+++ b/src/test/ui/imports/bad-import-in-nested.rs
@@ -0,0 +1,27 @@
+// edition: 2021
+
+#![allow(unused)]
+
+mod A {
+    pub(crate) type AA = ();
+    pub(crate) type BB = ();
+
+    mod A2 {
+        use super::{super::C::D::AA, AA as _};
+        //~^ ERROR unresolved import
+    }
+}
+
+mod C {
+    pub mod D {}
+}
+
+mod B {
+    use crate::C::{self, AA};
+    //~^ ERROR unresolved import
+
+    use crate::{A, C::BB};
+    //~^ ERROR unresolved import
+}
+
+fn main() {}
diff --git a/src/test/ui/imports/bad-import-in-nested.stderr b/src/test/ui/imports/bad-import-in-nested.stderr
new file mode 100644
index 00000000000..855b1e637e9
--- /dev/null
+++ b/src/test/ui/imports/bad-import-in-nested.stderr
@@ -0,0 +1,30 @@
+error[E0432]: unresolved import `super::super::C::D::AA`
+  --> $DIR/bad-import-in-nested.rs:10:21
+   |
+LL |         use super::{super::C::D::AA, AA as _};
+   |                     ^^^^^^^^^^^^^^^ no `AA` in `C::D`
+   |
+   = note: consider importing this type alias instead:
+           crate::A::AA
+
+error[E0432]: unresolved import `crate::C::AA`
+  --> $DIR/bad-import-in-nested.rs:20:26
+   |
+LL |     use crate::C::{self, AA};
+   |                          ^^ no `AA` in `C`
+   |
+   = note: consider importing this type alias instead:
+           crate::A::AA
+
+error[E0432]: unresolved import `crate::C::BB`
+  --> $DIR/bad-import-in-nested.rs:23:20
+   |
+LL |     use crate::{A, C::BB};
+   |                    ^^^^^ no `BB` in `C`
+   |
+   = note: consider importing this type alias instead:
+           crate::A::BB
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/src/test/ui/imports/bad-import-with-rename.rs b/src/test/ui/imports/bad-import-with-rename.rs
new file mode 100644
index 00000000000..ffe56916f92
--- /dev/null
+++ b/src/test/ui/imports/bad-import-with-rename.rs
@@ -0,0 +1,16 @@
+mod A {
+    pub type B = ();
+    pub type B2 = ();
+}
+
+mod C {
+    use crate::D::B as _;
+    //~^ ERROR unresolved import `crate::D::B`
+
+    use crate::D::B2;
+    //~^ ERROR unresolved import `crate::D::B2`
+}
+
+mod D {}
+
+fn main() {}
diff --git a/src/test/ui/imports/bad-import-with-rename.stderr b/src/test/ui/imports/bad-import-with-rename.stderr
new file mode 100644
index 00000000000..cace2a7a51c
--- /dev/null
+++ b/src/test/ui/imports/bad-import-with-rename.stderr
@@ -0,0 +1,25 @@
+error[E0432]: unresolved import `crate::D::B`
+  --> $DIR/bad-import-with-rename.rs:7:9
+   |
+LL |     use crate::D::B as _;
+   |         ^^^^^^^^^^^^^^^^ no `B` in `D`
+   |
+help: consider importing this type alias instead
+   |
+LL |     use A::B as _;
+   |         ~~~~~~~~~~
+
+error[E0432]: unresolved import `crate::D::B2`
+  --> $DIR/bad-import-with-rename.rs:10:9
+   |
+LL |     use crate::D::B2;
+   |         ^^^^^^^^^^^^ no `B2` in `D`
+   |
+help: consider importing this type alias instead
+   |
+LL |     use A::B2;
+   |         ~~~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/src/test/ui/test-attrs/inaccessible-test-modules.stderr b/src/test/ui/test-attrs/inaccessible-test-modules.stderr
index 0c16ecd4c86..a45c5bd4588 100644
--- a/src/test/ui/test-attrs/inaccessible-test-modules.stderr
+++ b/src/test/ui/test-attrs/inaccessible-test-modules.stderr
@@ -2,10 +2,7 @@ error[E0432]: unresolved import `main`
   --> $DIR/inaccessible-test-modules.rs:5:5
    |
 LL | use main as x;
-   |     ----^^^^^
-   |     |
-   |     no `main` in the root
-   |     help: a similar name exists in the module: `main`
+   |     ^^^^^^^^^ no `main` in the root
 
 error[E0432]: unresolved import `test`
   --> $DIR/inaccessible-test-modules.rs:6:5
@@ -13,14 +10,10 @@ error[E0432]: unresolved import `test`
 LL | use test as y;
    |     ^^^^^^^^^ no `test` in the root
    |
-help: a similar name exists in the module
-   |
-LL | use test as y;
-   |     ~~~~
 help: consider importing this module instead
    |
-LL | use test::test;
-   |     ~~~~~~~~~~~
+LL | use test::test as y;
+   |     ~~~~~~~~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.rs b/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.rs
index a3bb76d7e3b..5449f5f00d5 100644
--- a/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.rs
+++ b/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.rs
@@ -1,28 +1,69 @@
-// known-bug
+// check-pass
+
+// This test checks that we're correctly dealing with inductive cycles
+// with canonical inference variables.
 
-// This should compile but fails with the current solver.
-//
-// This checks that the new solver uses `Ambiguous` when hitting the
-// inductive cycle here when proving `exists<^0, ^1> (): Trait<^0, ^1>`
-// which requires proving `Trait<?1, ?0>` but that has the same
-// canonical representation.
 trait Trait<T, U> {}
 
-impl<T, U> Trait<T, U> for ()
+trait IsNotU32 {}
+impl IsNotU32 for i32 {}
+impl<T: IsNotU32, U> Trait<T, U> for () // impl 1
 where
-    (): Trait<U, T>,
-    T: OtherTrait,
+    (): Trait<U, T>
 {}
 
-trait OtherTrait {}
-impl OtherTrait for u32 {}
+impl<T> Trait<u32, T> for () {} // impl 2
+
+// If we now check whether `(): Trait<?0, ?1>` holds this has to
+// result in ambiguity as both `for<T> (): Trait<u32, T>` and `(): Trait<i32, u32>`
+// applies. The remainder of this test asserts that.
+
+// If we were to error on inductive cycles with canonical inference variables
+// this would be wrong:
 
-fn require_trait<T, U>()
+// (): Trait<?0, ?1>
+//  - impl 1
+//      - ?0: IsNotU32 // ambig
+//      - (): Trait<?1, ?0> // canonical cycle -> err
+//      - ERR
+//  - impl 2
+//      - OK ?0 == u32
+//
+// Result: OK ?0 == u32.
+
+// (): Trait<i32, u32>
+//  - impl 1
+//      - i32: IsNotU32 // ok
+//      - (): Trait<u32, i32>
+//          - impl 1
+//              - u32: IsNotU32 // err
+//              - ERR
+//          - impl 2
+//              - OK
+//      - OK
+//  - impl 2 (trivial ERR)
+//
+// Result OK
+
+// This would mean that `(): Trait<?0, ?1>` is not complete,
+// which is unsound if we're in coherence.
+
+fn implements_trait<T, U>() -> (T, U)
 where
-    (): Trait<T, U>
-{}
+    (): Trait<T, U>,
+{
+    todo!()
+}
+
+// A hack to only constrain the infer vars after first checking
+// the `(): Trait<_, _>`.
+trait Constrain<T> {}
+impl<T> Constrain<T> for  T {}
+fn constrain<T: Constrain<U>, U>(_: U) {}
 
 fn main() {
-    require_trait::<_, _>();
-    //~^ ERROR overflow evaluating
+    let (x, y) = implements_trait::<_, _>();
+
+    constrain::<i32, _>(x);
+    constrain::<u32, _>(y);
 }
diff --git a/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.stderr b/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.stderr
deleted file mode 100644
index e4b84e07822..00000000000
--- a/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.stderr
+++ /dev/null
@@ -1,26 +0,0 @@
-error[E0275]: overflow evaluating the requirement `_: Sized`
-  --> $DIR/inductive-canonical-cycle.rs:26:5
-   |
-LL |     require_trait::<_, _>();
-   |     ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inductive_canonical_cycle`)
-note: required for `()` to implement `Trait<_, _>`
-  --> $DIR/inductive-canonical-cycle.rs:11:12
-   |
-LL | impl<T, U> Trait<T, U> for ()
-   |            ^^^^^^^^^^^     ^^
-   = note: 128 redundant requirements hidden
-   = note: required for `()` to implement `Trait<_, _>`
-note: required by a bound in `require_trait`
-  --> $DIR/inductive-canonical-cycle.rs:22:9
-   |
-LL | fn require_trait<T, U>()
-   |    ------------- required by a bound in this
-LL | where
-LL |     (): Trait<T, U>
-   |         ^^^^^^^^^^^ required by this bound in `require_trait`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0275`.
diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs
index e51bfa3798f..37f66d0033f 100644
--- a/src/tools/miri/cargo-miri/src/phases.rs
+++ b/src/tools/miri/cargo-miri/src/phases.rs
@@ -185,7 +185,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
     // explicitly do this even if RUSTC_STAGE is set, since for these builds we do *not* want the
     // bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host
     // builds.
-    cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap());
+    cmd.env("RUSTC", fs::canonicalize(find_miri()).unwrap());
     cmd.env("MIRI_BE_RUSTC", "target"); // we better remember to *unset* this in the other phases!
 
     // Set rustdoc to us as well, so we can run doctests.
diff --git a/src/tools/miri/ci.sh b/src/tools/miri/ci.sh
index b35f7370d68..e01bfbc74d9 100755
--- a/src/tools/miri/ci.sh
+++ b/src/tools/miri/ci.sh
@@ -108,7 +108,8 @@ case $HOST_TARGET in
     MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests
     MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var
     MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic
-    MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer
+    MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings
+    MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings
     MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture
     MIRI_TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std # JSON target file
     ;;
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index ee75e7a2932..cf6d9c28080 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-4f4d0586ad20c66a16d547581ca379beafece93a
+c54c8cbac882e149e04a9e1f2d146fd548ae30ae
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
index 5f132bf11a9..2cc8f035466 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
@@ -88,11 +88,7 @@ impl fmt::Display for InvalidationCause {
         match self {
             InvalidationCause::Access(kind) => write!(f, "{kind}"),
             InvalidationCause::Retag(perm, kind) =>
-                if *kind == RetagCause::FnEntry {
-                    write!(f, "{perm:?} FnEntry retag")
-                } else {
-                    write!(f, "{perm:?} retag")
-                },
+                write!(f, "{perm:?} {retag}", retag = kind.summary()),
         }
     }
 }
@@ -193,7 +189,7 @@ struct RetagOp {
 #[derive(Debug, Clone, Copy, PartialEq)]
 pub enum RetagCause {
     Normal,
-    FnReturn,
+    FnReturnPlace,
     FnEntry,
     TwoPhase,
 }
@@ -495,8 +491,8 @@ impl RetagCause {
     fn summary(&self) -> String {
         match self {
             RetagCause::Normal => "retag",
-            RetagCause::FnEntry => "FnEntry retag",
-            RetagCause::FnReturn => "FnReturn retag",
+            RetagCause::FnEntry => "function-entry retag",
+            RetagCause::FnReturnPlace => "return-place retag",
             RetagCause::TwoPhase => "two-phase retag",
         }
         .to_string()
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index bcdf2e75179..ec555ba2895 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -998,7 +998,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             access: Some(AccessKind::Write),
             protector: Some(ProtectorKind::StrongProtector),
         };
-        let val = this.sb_retag_reference(&val, new_perm, RetagCause::FnReturn)?;
+        let val = this.sb_retag_reference(&val, new_perm, RetagCause::FnReturnPlace)?;
         // And use reborrowed pointer for return place.
         let return_place = this.ref_to_mplace(&val)?;
         this.frame_mut().return_place = return_place.into();
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index c11c6104c28..527d31d1f0a 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -943,7 +943,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         link_name: Symbol,
     ) -> InterpResult<'tcx, ()> {
         self.check_abi(abi, exp_abi)?;
-        if let Some((body, _)) = self.eval_context_mut().lookup_exported_symbol(link_name)? {
+        if let Some((body, instance)) = self.eval_context_mut().lookup_exported_symbol(link_name)? {
+            // If compiler-builtins is providing the symbol, then don't treat it as a clash.
+            // We'll use our built-in implementation in `emulate_foreign_item_by_name` for increased
+            // performance. Note that this means we won't catch any undefined behavior in
+            // compiler-builtins when running other crates, but Miri can still be run on
+            // compiler-builtins itself (or any crate that uses it as a normal dependency)
+            if self.eval_context_ref().tcx.is_compiler_builtins(instance.def_id().krate) {
+                return Ok(());
+            }
+
             throw_machine_stop!(TerminationInfo::SymbolShimClashing {
                 link_name,
                 span: body.span.data(),
diff --git a/src/tools/miri/src/range_map.rs b/src/tools/miri/src/range_map.rs
index c8ff06a3665..62198061827 100644
--- a/src/tools/miri/src/range_map.rs
+++ b/src/tools/miri/src/range_map.rs
@@ -219,7 +219,6 @@ mod tests {
     /// Query the map at every offset in the range and collect the results.
     fn to_vec<T: Copy>(map: &RangeMap<T>, offset: u64, len: u64) -> Vec<T> {
         (offset..offset + len)
-            .into_iter()
             .map(|i| {
                 map.iter(Size::from_bytes(i), Size::from_bytes(1)).next().map(|(_, &t)| t).unwrap()
             })
diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs
index e049eec57a3..ce24b23ca32 100644
--- a/src/tools/miri/src/shims/env.rs
+++ b/src/tools/miri/src/shims/env.rs
@@ -166,7 +166,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 // `buf_size` represents the size in characters.
                 let buf_size = u64::from(this.read_scalar(size_op)?.to_u32()?);
                 Scalar::from_u32(windows_check_buffer_size(
-                    this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?,
+                    this.write_os_str_to_wide_str(
+                        &var, buf_ptr, buf_size, /*truncate*/ false,
+                    )?,
                 ))
             }
             None => {
@@ -366,7 +368,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         match env::current_dir() {
             Ok(cwd) =>
                 return Ok(Scalar::from_u32(windows_check_buffer_size(
-                    this.write_path_to_wide_str(&cwd, buf, size)?,
+                    this.write_path_to_wide_str(&cwd, buf, size, /*truncate*/ false)?,
                 ))),
             Err(e) => this.set_last_error_from_io_error(e.kind())?,
         }
diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs
index 0375a228a21..f010d4251f4 100644
--- a/src/tools/miri/src/shims/os_str.rs
+++ b/src/tools/miri/src/shims/os_str.rs
@@ -101,17 +101,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         self.eval_context_mut().write_c_str(bytes, ptr, size)
     }
 
-    /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what
-    /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying
-    /// to write if `size` is not large enough to fit the contents of `os_string` plus a null
-    /// terminator. It returns `Ok((true, length))` if the writing process was successful. The
-    /// string length returned does include the null terminator. Length is measured in units of
-    /// `u16.`
+    /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what the
+    /// Windows APIs usually handle.
+    ///
+    /// If `truncate == false` (the usual mode of operation), this function returns `Ok((false,
+    /// length))` without trying to write if `size` is not large enough to fit the contents of
+    /// `os_string` plus a null terminator. It returns `Ok((true, length))` if the writing process
+    /// was successful. The string length returned does include the null terminator. Length is
+    /// measured in units of `u16.`
+    ///
+    /// If `truncate == true`, then in case `size` is not large enough it *will* write the first
+    /// `size.saturating_sub(1)` many items, followed by a null terminator (if `size > 0`).
     fn write_os_str_to_wide_str(
         &mut self,
         os_str: &OsStr,
         ptr: Pointer<Option<Provenance>>,
         size: u64,
+        truncate: bool,
     ) -> InterpResult<'tcx, (bool, u64)> {
         #[cfg(windows)]
         fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec<u16>> {
@@ -129,7 +135,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         }
 
         let u16_vec = os_str_to_u16vec(os_str)?;
-        self.eval_context_mut().write_wide_str(&u16_vec, ptr, size)
+        let (written, size_needed) = self.eval_context_mut().write_wide_str(&u16_vec, ptr, size)?;
+        if truncate && !written && size > 0 {
+            // Write the truncated part that fits.
+            let truncated_data = &u16_vec[..size.saturating_sub(1).try_into().unwrap()];
+            let (written, written_len) =
+                self.eval_context_mut().write_wide_str(truncated_data, ptr, size)?;
+            assert!(written && written_len == size);
+        }
+        Ok((written, size_needed))
     }
 
     /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes.
@@ -143,7 +157,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         let arg_type = this.tcx.mk_array(this.tcx.types.u8, size);
         let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?;
-        assert!(self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap().0);
+        let (written, _) = self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap();
+        assert!(written);
         Ok(arg_place.ptr)
     }
 
@@ -158,7 +173,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         let arg_type = this.tcx.mk_array(this.tcx.types.u16, size);
         let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?;
-        assert!(self.write_os_str_to_wide_str(os_str, arg_place.ptr, size).unwrap().0);
+        let (written, _) =
+            self.write_os_str_to_wide_str(os_str, arg_place.ptr, size, /*truncate*/ false).unwrap();
+        assert!(written);
         Ok(arg_place.ptr)
     }
 
@@ -212,11 +229,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         path: &Path,
         ptr: Pointer<Option<Provenance>>,
         size: u64,
+        truncate: bool,
     ) -> InterpResult<'tcx, (bool, u64)> {
         let this = self.eval_context_mut();
         let os_str =
             this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
-        this.write_os_str_to_wide_str(&os_str, ptr, size)
+        this.write_os_str_to_wide_str(&os_str, ptr, size, truncate)
     }
 
     /// Allocate enough memory to store a Path as a null-terminated sequence of bytes,
@@ -232,6 +250,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         this.alloc_os_str_as_c_str(&os_str, memkind)
     }
 
+    /// Allocate enough memory to store a Path as a null-terminated sequence of `u16`s,
+    /// adjusting path separators if needed.
+    fn alloc_path_as_wide_str(
+        &mut self,
+        path: &Path,
+        memkind: MemoryKind<MiriMemoryKind>,
+    ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
+        let this = self.eval_context_mut();
+        let os_str =
+            this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
+        this.alloc_os_str_as_wide_str(&os_str, memkind)
+    }
+
     #[allow(clippy::get_first)]
     fn convert_path<'a>(
         &self,
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index 1da8f7c0e3e..f310d16e861 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -381,6 +381,46 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
                 this.write_scalar(Scalar::from_u32(1), dest)?;
             }
+            "GetModuleFileNameW" => {
+                let [handle, filename, size] =
+                    this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
+                this.check_no_isolation("`GetModuleFileNameW`")?;
+
+                let handle = this.read_machine_usize(handle)?;
+                let filename = this.read_pointer(filename)?;
+                let size = this.read_scalar(size)?.to_u32()?;
+
+                if handle != 0 {
+                    throw_unsup_format!("`GetModuleFileNameW` only supports the NULL handle");
+                }
+
+                // Using the host current_exe is a bit off, but consistent with Linux
+                // (where stdlib reads /proc/self/exe).
+                // Unfortunately this Windows function has a crazy behavior so we can't just use
+                // `write_path_to_wide_str`...
+                let path = std::env::current_exe().unwrap();
+                let (all_written, size_needed) = this.write_path_to_wide_str(
+                    &path,
+                    filename,
+                    size.into(),
+                    /*truncate*/ true,
+                )?;
+
+                if all_written {
+                    // If the function succeeds, the return value is the length of the string that
+                    // is copied to the buffer, in characters, not including the terminating null
+                    // character.
+                    this.write_int(size_needed.checked_sub(1).unwrap(), dest)?;
+                } else {
+                    // If the buffer is too small to hold the module name, the string is truncated
+                    // to nSize characters including the terminating null character, the function
+                    // returns nSize, and the function sets the last error to
+                    // ERROR_INSUFFICIENT_BUFFER.
+                    this.write_int(size, dest)?;
+                    let insufficient_buffer = this.eval_windows("c", "ERROR_INSUFFICIENT_BUFFER");
+                    this.set_last_error(insufficient_buffer)?;
+                }
+            }
 
             // Threading
             "CreateThread" => {
diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock
index bf7f0411bed..a84ed859763 100644
--- a/src/tools/miri/test_dependencies/Cargo.lock
+++ b/src/tools/miri/test_dependencies/Cargo.lock
@@ -15,6 +15,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
+name = "bumpalo"
+version = "3.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
+
+[[package]]
 name = "bytes"
 version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -44,8 +50,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
 dependencies = [
  "cfg-if",
+ "js-sys",
  "libc",
  "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasm-bindgen",
 ]
 
 [[package]]
@@ -58,6 +66,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "js-sys"
+version = "0.3.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
 name = "libc"
 version = "0.2.139"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -124,6 +141,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "once_cell"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
+
+[[package]]
 name = "page_size"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -269,9 +292,9 @@ dependencies = [
 
 [[package]]
 name = "tokio"
-version = "1.23.0"
+version = "1.23.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46"
+checksum = "38a54aca0c15d014013256222ba0ebed095673f89345dd79119d912eb561b7a8"
 dependencies = [
  "autocfg",
  "bytes",
@@ -317,6 +340,60 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
+name = "wasm-bindgen"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
+
+[[package]]
 name = "winapi"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/miri/test_dependencies/Cargo.toml b/src/tools/miri/test_dependencies/Cargo.toml
index 1df35bbbe2f..f5ab6acf008 100644
--- a/src/tools/miri/test_dependencies/Cargo.toml
+++ b/src/tools/miri/test_dependencies/Cargo.toml
@@ -13,11 +13,11 @@ libc = "0.2"
 num_cpus = "1.10.1"
 
 getrandom_1 = { package = "getrandom", version = "0.1" }
-getrandom = { version = "0.2" }
+getrandom = { version = "0.2", features = ["js"] }
 rand = { version = "0.8", features = ["small_rng"] }
 
 [target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies]
 page_size = "0.5"
-tokio = { version = "1.0", features = ["full"] }
+tokio = { version = "1.23", features = ["full"] }
 
 [workspace]
diff --git a/src/tools/miri/tests/fail/stacked_borrows/aliasing_mut3.stderr b/src/tools/miri/tests/fail/stacked_borrows/aliasing_mut3.stderr
index 55aaed62f4f..ae54d0248dc 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/aliasing_mut3.stderr
+++ b/src/tools/miri/tests/fail/stacked_borrows/aliasing_mut3.stderr
@@ -5,7 +5,7 @@ LL | pub fn safe(_x: &mut i32, _y: &i32) {}
    |                           ^^
    |                           |
    |                           trying to retag from <TAG> for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
-   |                           this error occurs as part of FnEntry retag at ALLOC[0x0..0x4]
+   |                           this error occurs as part of function-entry retag at ALLOC[0x0..0x4]
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
    = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
@@ -14,7 +14,7 @@ help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0x4]
    |
 LL |     safe_raw(xraw, xshr);
    |                    ^^^^
-help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique FnEntry retag inside this call
+help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique function-entry retag inside this call
   --> $DIR/aliasing_mut3.rs:LL:CC
    |
 LL |     safe_raw(xraw, xshr);
diff --git a/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr b/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr
index e3bffde1f01..236c8fb0187 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr
+++ b/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr
@@ -14,7 +14,7 @@ help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4]
    |
 LL |     let z = &mut x as *mut i32;
    |             ^^^^^^
-help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique FnEntry retag inside this call
+help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique function-entry retag inside this call
   --> $DIR/fnentry_invalidation.rs:LL:CC
    |
 LL |     x.do_bad();
diff --git a/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation2.stderr b/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation2.stderr
index b104de4b8d9..45c2197050a 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation2.stderr
+++ b/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation2.stderr
@@ -14,7 +14,7 @@ help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0xc]
    |
 LL |     let ptr = t.sli.as_ptr();
    |               ^^^^^^^^^^^^^^
-help: <TAG> was later invalidated at offsets [0x0..0xc] by a Unique FnEntry retag inside this call
+help: <TAG> was later invalidated at offsets [0x0..0xc] by a Unique function-entry retag inside this call
   --> $DIR/fnentry_invalidation2.rs:LL:CC
    |
 LL |     let _ = t.sli.as_mut_ptr();
diff --git a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs
index 04e89ec361b..7ccafec6037 100644
--- a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs
+++ b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs
@@ -186,8 +186,65 @@ fn join_orders_after_tls_destructors() {
     }
 }
 
+fn dtors_in_dtors_in_dtors() {
+    use std::cell::UnsafeCell;
+    use std::sync::{Arc, Condvar, Mutex};
+
+    #[derive(Clone, Default)]
+    struct Signal(Arc<(Mutex<bool>, Condvar)>);
+
+    impl Signal {
+        fn notify(&self) {
+            let (set, cvar) = &*self.0;
+            *set.lock().unwrap() = true;
+            cvar.notify_one();
+        }
+
+        fn wait(&self) {
+            let (set, cvar) = &*self.0;
+            let mut set = set.lock().unwrap();
+            while !*set {
+                set = cvar.wait(set).unwrap();
+            }
+        }
+    }
+
+    struct NotifyOnDrop(Signal);
+
+    impl Drop for NotifyOnDrop {
+        fn drop(&mut self) {
+            let NotifyOnDrop(ref f) = *self;
+            f.notify();
+        }
+    }
+
+    struct S1(Signal);
+    thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
+    thread_local!(static K2: UnsafeCell<Option<NotifyOnDrop>> = UnsafeCell::new(None));
+
+    impl Drop for S1 {
+        fn drop(&mut self) {
+            let S1(ref signal) = *self;
+            unsafe {
+                let _ = K2.try_with(|s| *s.get() = Some(NotifyOnDrop(signal.clone())));
+            }
+        }
+    }
+
+    let signal = Signal::default();
+    let signal2 = signal.clone();
+    let _t = thread::spawn(move || unsafe {
+        let mut signal = Some(signal2);
+        K1.with(|s| *s.get() = Some(S1(signal.take().unwrap())));
+    });
+    // Note that this test will deadlock if TLS destructors aren't run (this
+    // requires the destructor to be run to pass the test).
+    signal.wait();
+}
+
 fn main() {
     check_destructors();
     check_blocking();
     join_orders_after_tls_destructors();
+    dtors_in_dtors_in_dtors();
 }
diff --git a/src/tools/miri/tests/pass/shims/env/current_exe.rs b/src/tools/miri/tests/pass/shims/env/current_exe.rs
index 3f1153d265d..898a42b72d1 100644
--- a/src/tools/miri/tests/pass/shims/env/current_exe.rs
+++ b/src/tools/miri/tests/pass/shims/env/current_exe.rs
@@ -1,4 +1,3 @@
-//@ignore-target-windows: current_exe not supported on Windows
 //@only-on-host: the Linux std implementation opens /proc/self/exe, which doesn't work cross-target
 //@compile-flags: -Zmiri-disable-isolation
 use std::env;