about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-03-23 21:16:57 +0000
committerbors <bors@rust-lang.org>2023-03-23 21:16:57 +0000
commit1459b3128e288a85fcc4dd1fee7ada2cdcf28794 (patch)
treef31be534855b77ac6d4ac49aeb9374499be2fe0e
parente2163008763c326ec4003e07b8e6eef0c98f6204 (diff)
parent3961ef5bc84f8f6057e34bf61b92561bef5c8e64 (diff)
downloadrust-1459b3128e288a85fcc4dd1fee7ada2cdcf28794.tar.gz
rust-1459b3128e288a85fcc4dd1fee7ada2cdcf28794.zip
Auto merge of #109538 - matthiaskrgr:rollup-ct58npj, r=matthiaskrgr
Rollup of 8 pull requests

Successful merges:

 - #106964 (Clarify `Error::last_os_error` can be weird)
 - #107718 (Add `-Z time-passes-format` to allow specifying a JSON output for `-Z time-passes`)
 - #107880 (Lint ambiguous glob re-exports)
 - #108549 (Remove issue number for `link_cfg`)
 - #108588 (Fix the ffi_unwind_calls lint documentation)
 - #109231 (Add `try_canonicalize` to `rustc_fs_util` and use it over `fs::canonicalize`)
 - #109472 (Add parentheses properly for method calls)
 - #109487 (Move useless_anynous_reexport lint into unused_imports)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock4
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs1
-rw-r--r--compiler/rustc_data_structures/Cargo.toml1
-rw-r--r--compiler/rustc_data_structures/src/graph/scc/tests.rs6
-rw-r--r--compiler/rustc_data_structures/src/graph/vec_graph/tests.rs6
-rw-r--r--compiler/rustc_data_structures/src/profiling.rs72
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs13
-rw-r--r--compiler/rustc_feature/src/active.rs4
-rw-r--r--compiler/rustc_fs_util/src/lib.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs4
-rw-r--r--compiler/rustc_incremental/src/persist/fs.rs8
-rw-r--r--compiler/rustc_interface/Cargo.toml1
-rw-r--r--compiler/rustc_interface/src/passes.rs5
-rw-r--r--compiler/rustc_interface/src/tests.rs2
-rw-r--r--compiler/rustc_lint/messages.ftl3
-rw-r--r--compiler/rustc_lint/src/context.rs4
-rw-r--r--compiler/rustc_lint/src/lib.rs3
-rw-r--r--compiler/rustc_lint/src/lints.rs8
-rw-r--r--compiler/rustc_lint/src/reexports.rs82
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs49
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs10
-rw-r--r--compiler/rustc_metadata/Cargo.toml1
-rw-r--r--compiler/rustc_metadata/src/locator.rs7
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs42
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs68
-rw-r--r--compiler/rustc_resolve/src/imports.rs32
-rw-r--r--compiler/rustc_resolve/src/lib.rs5
-rw-r--r--compiler/rustc_session/src/filesearch.rs5
-rw-r--r--compiler/rustc_session/src/options.rs19
-rw-r--r--compiler/rustc_session/src/session.rs5
-rw-r--r--compiler/rustc_session/src/utils.rs3
-rw-r--r--compiler/rustc_target/Cargo.toml1
-rw-r--r--compiler/rustc_target/src/spec/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs32
-rw-r--r--library/std/src/io/error.rs12
-rw-r--r--src/tools/lint-docs/src/lib.rs95
-rw-r--r--tests/rustdoc-ui/z-help.stdout1
-rw-r--r--tests/ui/feature-gates/feature-gate-link_cfg.stderr1
-rw-r--r--tests/ui/imports/auxiliary/glob-conflict.rs2
-rw-r--r--tests/ui/imports/issue-99695-b.fixed2
-rw-r--r--tests/ui/imports/issue-99695-b.rs2
-rw-r--r--tests/ui/imports/issue-99695.fixed2
-rw-r--r--tests/ui/imports/issue-99695.rs2
-rw-r--r--tests/ui/imports/local-modularized-tricky-fail-1.rs1
-rw-r--r--tests/ui/imports/local-modularized-tricky-fail-1.stderr14
-rw-r--r--tests/ui/lint/anonymous-reexport.rs16
-rw-r--r--tests/ui/lint/anonymous-reexport.stderr49
-rw-r--r--tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs33
-rw-r--r--tests/ui/resolve/issue-107563-ambiguous-glob-reexports.stderr47
-rw-r--r--tests/ui/suggestions/issue-109436.rs13
-rw-r--r--tests/ui/suggestions/issue-109436.stderr15
52 files changed, 566 insertions, 266 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 3495f4d51af..449f0c73588 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4523,6 +4523,7 @@ dependencies = [
  "rustc_index",
  "rustc_macros",
  "rustc_serialize",
+ "serde_json",
  "smallvec",
  "stable_deref_trait",
  "stacker",
@@ -4826,6 +4827,7 @@ dependencies = [
  "rustc_data_structures",
  "rustc_errors",
  "rustc_expand",
+ "rustc_fs_util",
  "rustc_hir",
  "rustc_hir_analysis",
  "rustc_hir_typeck",
@@ -4950,6 +4952,7 @@ dependencies = [
  "rustc_errors",
  "rustc_expand",
  "rustc_feature",
+ "rustc_fs_util",
  "rustc_hir",
  "rustc_hir_pretty",
  "rustc_index",
@@ -5335,6 +5338,7 @@ dependencies = [
  "rustc_abi",
  "rustc_data_structures",
  "rustc_feature",
+ "rustc_fs_util",
  "rustc_index",
  "rustc_macros",
  "rustc_serialize",
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 8dafe1b750b..e5bae009ed6 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -361,12 +361,12 @@ impl CodegenBackend for LlvmCodegenBackend {
             .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
             .join(sess);
 
-        sess.time("llvm_dump_timing_file", || {
-            if sess.opts.unstable_opts.llvm_time_trace {
+        if sess.opts.unstable_opts.llvm_time_trace {
+            sess.time("llvm_dump_timing_file", || {
                 let file_name = outputs.with_extension("llvm_timings.json");
                 llvm_util::time_trace_profiler_finish(&file_name);
-            }
-        });
+            });
+        }
 
         Ok((codegen_results, work_products))
     }
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 4d34b3da5f5..c3c8649dbff 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -786,6 +786,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
             total_codegen_time,
             start_rss.unwrap(),
             end_rss,
+            tcx.sess.opts.unstable_opts.time_passes_format,
         );
     }
 
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 24cf9812a25..056ee1f63be 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -21,6 +21,7 @@ rustc-hash = "1.1.0"
 rustc_index = { path = "../rustc_index", package = "rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
+serde_json = "1.0.59"
 smallvec = { version = "1.8.1", features = [
     "const_generics",
     "union",
diff --git a/compiler/rustc_data_structures/src/graph/scc/tests.rs b/compiler/rustc_data_structures/src/graph/scc/tests.rs
index 820a70fc8e4..513df666d0d 100644
--- a/compiler/rustc_data_structures/src/graph/scc/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/scc/tests.rs
@@ -56,7 +56,7 @@ fn test_three_sccs() {
     assert_eq!(sccs.scc(1), 0);
     assert_eq!(sccs.scc(2), 0);
     assert_eq!(sccs.scc(3), 2);
-    assert_eq!(sccs.successors(0), &[]);
+    assert_eq!(sccs.successors(0), &[] as &[usize]);
     assert_eq!(sccs.successors(1), &[0]);
     assert_eq!(sccs.successors(2), &[0]);
 }
@@ -113,7 +113,7 @@ fn test_find_state_2() {
     assert_eq!(sccs.scc(2), 0);
     assert_eq!(sccs.scc(3), 0);
     assert_eq!(sccs.scc(4), 0);
-    assert_eq!(sccs.successors(0), &[]);
+    assert_eq!(sccs.successors(0), &[] as &[usize]);
 }
 
 #[test]
@@ -138,7 +138,7 @@ fn test_find_state_3() {
     assert_eq!(sccs.scc(3), 0);
     assert_eq!(sccs.scc(4), 0);
     assert_eq!(sccs.scc(5), 1);
-    assert_eq!(sccs.successors(0), &[]);
+    assert_eq!(sccs.successors(0), &[] as &[usize]);
     assert_eq!(sccs.successors(1), &[0]);
 }
 
diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs
index c8f97926717..7c866da6009 100644
--- a/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs
@@ -27,11 +27,11 @@ fn successors() {
     let graph = create_graph();
     assert_eq!(graph.successors(0), &[1]);
     assert_eq!(graph.successors(1), &[2, 3]);
-    assert_eq!(graph.successors(2), &[]);
+    assert_eq!(graph.successors(2), &[] as &[usize]);
     assert_eq!(graph.successors(3), &[4]);
-    assert_eq!(graph.successors(4), &[]);
+    assert_eq!(graph.successors(4), &[] as &[usize]);
     assert_eq!(graph.successors(5), &[1]);
-    assert_eq!(graph.successors(6), &[]);
+    assert_eq!(graph.successors(6), &[] as &[usize]);
 }
 
 #[test]
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index 3d9c7f6eae2..58a0609e296 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -97,6 +97,7 @@ use std::time::{Duration, Instant};
 pub use measureme::EventId;
 use measureme::{EventIdBuilder, Profiler, SerializableString, StringId};
 use parking_lot::RwLock;
+use serde_json::json;
 use smallvec::SmallVec;
 
 bitflags::bitflags! {
@@ -145,6 +146,15 @@ const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[
 /// Something that uniquely identifies a query invocation.
 pub struct QueryInvocationId(pub u32);
 
+/// Which format to use for `-Z time-passes`
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+pub enum TimePassesFormat {
+    /// Emit human readable text
+    Text,
+    /// Emit structured JSON
+    Json,
+}
+
 /// A reference to the SelfProfiler. It can be cloned and sent across thread
 /// boundaries at will.
 #[derive(Clone)]
@@ -158,14 +168,14 @@ pub struct SelfProfilerRef {
     // actually enabled.
     event_filter_mask: EventFilter,
 
-    // Print verbose generic activities to stderr?
-    print_verbose_generic_activities: bool,
+    // Print verbose generic activities to stderr.
+    print_verbose_generic_activities: Option<TimePassesFormat>,
 }
 
 impl SelfProfilerRef {
     pub fn new(
         profiler: Option<Arc<SelfProfiler>>,
-        print_verbose_generic_activities: bool,
+        print_verbose_generic_activities: Option<TimePassesFormat>,
     ) -> SelfProfilerRef {
         // If there is no SelfProfiler then the filter mask is set to NONE,
         // ensuring that nothing ever tries to actually access it.
@@ -207,9 +217,10 @@ impl SelfProfilerRef {
     /// a measureme event, "verbose" generic activities also print a timing entry to
     /// stderr if the compiler is invoked with -Ztime-passes.
     pub fn verbose_generic_activity(&self, event_label: &'static str) -> VerboseTimingGuard<'_> {
-        let message = self.print_verbose_generic_activities.then(|| event_label.to_owned());
+        let message_and_format =
+            self.print_verbose_generic_activities.map(|format| (event_label.to_owned(), format));
 
-        VerboseTimingGuard::start(message, self.generic_activity(event_label))
+        VerboseTimingGuard::start(message_and_format, self.generic_activity(event_label))
     }
 
     /// Like `verbose_generic_activity`, but with an extra arg.
@@ -221,11 +232,14 @@ impl SelfProfilerRef {
     where
         A: Borrow<str> + Into<String>,
     {
-        let message = self
+        let message_and_format = self
             .print_verbose_generic_activities
-            .then(|| format!("{}({})", event_label, event_arg.borrow()));
+            .map(|format| (format!("{}({})", event_label, event_arg.borrow()), format));
 
-        VerboseTimingGuard::start(message, self.generic_activity_with_arg(event_label, event_arg))
+        VerboseTimingGuard::start(
+            message_and_format,
+            self.generic_activity_with_arg(event_label, event_arg),
+        )
     }
 
     /// Start profiling a generic activity. Profiling continues until the
@@ -703,17 +717,32 @@ impl<'a> TimingGuard<'a> {
     }
 }
 
+struct VerboseInfo {
+    start_time: Instant,
+    start_rss: Option<usize>,
+    message: String,
+    format: TimePassesFormat,
+}
+
 #[must_use]
 pub struct VerboseTimingGuard<'a> {
-    start_and_message: Option<(Instant, Option<usize>, String)>,
+    info: Option<VerboseInfo>,
     _guard: TimingGuard<'a>,
 }
 
 impl<'a> VerboseTimingGuard<'a> {
-    pub fn start(message: Option<String>, _guard: TimingGuard<'a>) -> Self {
+    pub fn start(
+        message_and_format: Option<(String, TimePassesFormat)>,
+        _guard: TimingGuard<'a>,
+    ) -> Self {
         VerboseTimingGuard {
             _guard,
-            start_and_message: message.map(|msg| (Instant::now(), get_resident_set_size(), msg)),
+            info: message_and_format.map(|(message, format)| VerboseInfo {
+                start_time: Instant::now(),
+                start_rss: get_resident_set_size(),
+                message,
+                format,
+            }),
         }
     }
 
@@ -726,10 +755,10 @@ impl<'a> VerboseTimingGuard<'a> {
 
 impl Drop for VerboseTimingGuard<'_> {
     fn drop(&mut self) {
-        if let Some((start_time, start_rss, ref message)) = self.start_and_message {
+        if let Some(info) = &self.info {
             let end_rss = get_resident_set_size();
-            let dur = start_time.elapsed();
-            print_time_passes_entry(message, dur, start_rss, end_rss);
+            let dur = info.start_time.elapsed();
+            print_time_passes_entry(&info.message, dur, info.start_rss, end_rss, info.format);
         }
     }
 }
@@ -739,7 +768,22 @@ pub fn print_time_passes_entry(
     dur: Duration,
     start_rss: Option<usize>,
     end_rss: Option<usize>,
+    format: TimePassesFormat,
 ) {
+    match format {
+        TimePassesFormat::Json => {
+            let json = json!({
+                "pass": what,
+                "time": dur.as_secs_f64(),
+                "rss_start": start_rss,
+                "rss_end": end_rss,
+            });
+            eprintln!("time: {}", json.to_string());
+            return;
+        }
+        TimePassesFormat::Text => (),
+    }
+
     // Print the pass if its duration is greater than 5 ms, or it changed the
     // measured RSS.
     let is_notable = || {
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 14d6569271e..1e835f6065a 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -20,7 +20,9 @@ pub extern crate rustc_plugin_impl as plugin;
 
 use rustc_ast as ast;
 use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults};
-use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
+use rustc_data_structures::profiling::{
+    get_resident_set_size, print_time_passes_entry, TimePassesFormat,
+};
 use rustc_data_structures::sync::SeqCst;
 use rustc_errors::registry::{InvalidErrorCode, Registry};
 use rustc_errors::{
@@ -161,7 +163,7 @@ pub trait Callbacks {
 
 #[derive(Default)]
 pub struct TimePassesCallbacks {
-    time_passes: bool,
+    time_passes: Option<TimePassesFormat>,
 }
 
 impl Callbacks for TimePassesCallbacks {
@@ -171,7 +173,8 @@ impl Callbacks for TimePassesCallbacks {
         // If a --print=... option has been given, we don't print the "total"
         // time because it will mess up the --print output. See #64339.
         //
-        self.time_passes = config.opts.prints.is_empty() && config.opts.unstable_opts.time_passes;
+        self.time_passes = (config.opts.prints.is_empty() && config.opts.unstable_opts.time_passes)
+            .then(|| config.opts.unstable_opts.time_passes_format);
         config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath;
     }
 }
@@ -1354,9 +1357,9 @@ pub fn main() -> ! {
         RunCompiler::new(&args, &mut callbacks).run()
     });
 
-    if callbacks.time_passes {
+    if let Some(format) = callbacks.time_passes {
         let end_rss = get_resident_set_size();
-        print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss);
+        print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss, format);
     }
 
     process::exit(exit_code)
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index e0a7c864b94..b7d280b8751 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -160,6 +160,8 @@ declare_features! (
     (active, intrinsics, "1.0.0", None, None),
     /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
     (active, lang_items, "1.0.0", None, None),
+    /// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406
+    (active, link_cfg, "1.14.0", None, None),
     /// Allows the `multiple_supertrait_upcastable` lint.
     (active, multiple_supertrait_upcastable, "1.69.0", None, None),
     /// Allows using `#[omit_gdb_pretty_printer_section]`.
@@ -432,8 +434,6 @@ declare_features! (
     (active, large_assignments, "1.52.0", Some(83518), None),
     /// Allows `if/while p && let q = r && ...` chains.
     (active, let_chains, "1.37.0", Some(53667), None),
-    /// Allows `#[link(..., cfg(..))]`.
-    (active, link_cfg, "1.14.0", Some(37406), None),
     /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check.
     (active, lint_reasons, "1.31.0", Some(54503), None),
     /// Give access to additional metadata about declarative macro meta-variables.
diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs
index a7dfce3b9b8..81d63338145 100644
--- a/compiler/rustc_fs_util/src/lib.rs
+++ b/compiler/rustc_fs_util/src/lib.rs
@@ -1,10 +1,11 @@
+#![feature(absolute_path)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 
 use std::ffi::CString;
 use std::fs;
 use std::io;
-use std::path::{Path, PathBuf};
+use std::path::{absolute, Path, PathBuf};
 
 // Unfortunately, on windows, it looks like msvcrt.dll is silently translating
 // verbatim paths under the hood to non-verbatim paths! This manifests itself as
@@ -91,3 +92,8 @@ pub fn path_to_c_string(p: &Path) -> CString {
 pub fn path_to_c_string(p: &Path) -> CString {
     CString::new(p.to_str().unwrap()).unwrap()
 }
+
+#[inline]
+pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
+    fs::canonicalize(&path).or_else(|_| absolute(&path))
+}
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index 23490bc091c..465e787c92a 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -133,8 +133,8 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) {
         check_impl(tcx, impl_def_id, trait_ref);
         check_object_overlap(tcx, impl_def_id, trait_ref);
 
-        tcx.sess.time("unsafety_checking", || unsafety::check_item(tcx, impl_def_id));
-        tcx.sess.time("orphan_checking", || tcx.ensure().orphan_check_impl(impl_def_id));
+        unsafety::check_item(tcx, impl_def_id);
+        tcx.ensure().orphan_check_impl(impl_def_id);
     }
 
     builtin::check_trait(tcx, def_id);
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index 4deae9f41c7..d6f83838a04 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -108,7 +108,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::{base_n, flock};
 use rustc_errors::ErrorGuaranteed;
-use rustc_fs_util::{link_or_copy, LinkOrCopy};
+use rustc_fs_util::{link_or_copy, try_canonicalize, LinkOrCopy};
 use rustc_session::{Session, StableCrateId};
 use rustc_span::Symbol;
 
@@ -223,7 +223,7 @@ pub fn prepare_session_directory(
     // because, on windows, long paths can cause problems;
     // canonicalization inserts this weird prefix that makes windows
     // tolerate long paths.
-    let crate_dir = match crate_dir.canonicalize() {
+    let crate_dir = match try_canonicalize(&crate_dir) {
         Ok(v) => v,
         Err(err) => {
             return Err(sess.emit_err(errors::CanonicalizePath { path: crate_dir, err }));
@@ -867,7 +867,7 @@ fn all_except_most_recent(
 /// before passing it to std::fs::remove_dir_all(). This will convert the path
 /// into the '\\?\' format, which supports much longer paths.
 fn safe_remove_dir_all(p: &Path) -> io::Result<()> {
-    let canonicalized = match std_fs::canonicalize(p) {
+    let canonicalized = match try_canonicalize(p) {
         Ok(canonicalized) => canonicalized,
         Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()),
         Err(err) => return Err(err),
@@ -877,7 +877,7 @@ fn safe_remove_dir_all(p: &Path) -> io::Result<()> {
 }
 
 fn safe_remove_file(p: &Path) -> io::Result<()> {
-    let canonicalized = match std_fs::canonicalize(p) {
+    let canonicalized = match try_canonicalize(p) {
         Ok(canonicalized) => canonicalized,
         Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()),
         Err(err) => return Err(err),
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index ac6e8fca695..96d6a1cb062 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -16,6 +16,7 @@ rustc_attr = { path = "../rustc_attr" }
 rustc_borrowck = { path = "../rustc_borrowck" }
 rustc_builtin_macros = { path = "../rustc_builtin_macros" }
 rustc_expand = { path = "../rustc_expand" }
+rustc_fs_util = { path = "../rustc_fs_util" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_parse = { path = "../rustc_parse" }
 rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 7623c5f7327..413b40ab808 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -11,6 +11,7 @@ use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
 use rustc_errors::PResult;
 use rustc_expand::base::{ExtCtxt, LintStoreExpand};
+use rustc_fs_util::try_canonicalize;
 use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
 use rustc_lint::{unerased_lint_store, BufferedEarlyLint, EarlyCheckNode, LintStore};
 use rustc_metadata::creader::CStore;
@@ -408,12 +409,12 @@ where
 }
 
 fn output_contains_path(output_paths: &[PathBuf], input_path: &Path) -> bool {
-    let input_path = input_path.canonicalize().ok();
+    let input_path = try_canonicalize(input_path).ok();
     if input_path.is_none() {
         return false;
     }
     let check = |output_path: &PathBuf| {
-        if output_path.canonicalize().ok() == input_path { Some(()) } else { None }
+        if try_canonicalize(output_path).ok() == input_path { Some(()) } else { None }
     };
     check_output(output_paths, check).is_some()
 }
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 014810dba9c..eb5990507fb 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -2,6 +2,7 @@
 use crate::interface::parse_cfgspecs;
 
 use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::profiling::TimePassesFormat;
 use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
 use rustc_session::config::rustc_optgroups;
 use rustc_session::config::Input;
@@ -699,6 +700,7 @@ fn test_unstable_options_tracking_hash() {
     untracked!(threads, 99);
     untracked!(time_llvm_passes, true);
     untracked!(time_passes, true);
+    untracked!(time_passes_format, TimePassesFormat::Json);
     untracked!(trace_macros, true);
     untracked!(track_diagnostics, true);
     untracked!(trim_diagnostic_paths, false);
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index c822237413c..68e62c9789a 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -508,6 +508,3 @@ lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its ass
     .specifically = this associated type bound is unsatisfied for `{$proj_ty}`
 
 lint_opaque_hidden_inferred_bound_sugg = add this bound
-
-lint_useless_anonymous_reexport = useless anonymous re-export
-    .note = only anonymous re-exports of traits are useful, this is {$article} `{$desc}`
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index f5a711315ea..626c09fea07 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -910,6 +910,10 @@ pub trait LintContext: Sized {
                         Applicability::MachineApplicable,
                     );
                 }
+                BuiltinLintDiagnostics::AmbiguousGlobReexports { name, namespace, first_reexport_span, duplicate_reexport_span } => {
+                    db.span_label(first_reexport_span, format!("the name `{}` in the {} namespace is first re-exported here", name, namespace));
+                    db.span_label(duplicate_reexport_span, format!("but the name `{}` in the {} namespace is also re-exported here", name, namespace));
+                }
             }
             // Rewrap `db`, and pass control to the user.
             decorate(db)
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index c2cc2fcdf55..b3578540516 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -74,7 +74,6 @@ mod opaque_hidden_inferred_bound;
 mod pass_by_value;
 mod passes;
 mod redundant_semicolon;
-mod reexports;
 mod traits;
 mod types;
 mod unused;
@@ -112,7 +111,6 @@ use noop_method_call::*;
 use opaque_hidden_inferred_bound::*;
 use pass_by_value::*;
 use redundant_semicolon::*;
-use reexports::*;
 use traits::*;
 use types::*;
 use unused::*;
@@ -244,7 +242,6 @@ late_lint_methods!(
             OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
             MultipleSupertraitUpcastable: MultipleSupertraitUpcastable,
             MapUnitFn: MapUnitFn,
-            UselessAnonymousReexport: UselessAnonymousReexport,
         ]
     ]
 );
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 46a025f41e0..308c02929ca 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1528,11 +1528,3 @@ pub struct UnusedAllocationDiag;
 #[derive(LintDiagnostic)]
 #[diag(lint_unused_allocation_mut)]
 pub struct UnusedAllocationMutDiag;
-
-#[derive(LintDiagnostic)]
-#[diag(lint_useless_anonymous_reexport)]
-#[note]
-pub struct UselessAnonymousReexportDiag {
-    pub article: &'static str,
-    pub desc: &'static str,
-}
diff --git a/compiler/rustc_lint/src/reexports.rs b/compiler/rustc_lint/src/reexports.rs
deleted file mode 100644
index 8737a57ea02..00000000000
--- a/compiler/rustc_lint/src/reexports.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-use crate::lints::UselessAnonymousReexportDiag;
-use crate::{LateContext, LateLintPass, LintContext};
-use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefId;
-use rustc_hir::{Item, ItemKind, UseKind};
-use rustc_middle::ty::Visibility;
-use rustc_span::symbol::kw;
-use rustc_span::Span;
-
-declare_lint! {
-    /// The `useless_anonymous_reexport` lint checks if anonymous re-exports
-    /// are re-exports of traits.
-    ///
-    /// ### Example
-    ///
-    /// ```rust,compile_fail
-    /// #![deny(useless_anonymous_reexport)]
-    ///
-    /// mod sub {
-    ///     pub struct Bar;
-    /// }
-    ///
-    /// pub use self::sub::Bar as _;
-    /// # fn main() {}
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// Anonymous re-exports are only useful if it's a re-export of a trait
-    /// in case you want to give access to it. If you re-export any other kind,
-    /// you won't be able to use it since its name won't be accessible.
-    pub USELESS_ANONYMOUS_REEXPORT,
-    Warn,
-    "useless anonymous re-export"
-}
-
-declare_lint_pass!(UselessAnonymousReexport => [USELESS_ANONYMOUS_REEXPORT]);
-
-fn emit_err(cx: &LateContext<'_>, span: Span, def_id: DefId) {
-    let article = cx.tcx.def_descr_article(def_id);
-    let desc = cx.tcx.def_descr(def_id);
-    cx.emit_spanned_lint(
-        USELESS_ANONYMOUS_REEXPORT,
-        span,
-        UselessAnonymousReexportDiag { article, desc },
-    );
-}
-
-impl<'tcx> LateLintPass<'tcx> for UselessAnonymousReexport {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
-        if let ItemKind::Use(path, kind) = item.kind &&
-            !matches!(kind, UseKind::Glob) &&
-            item.ident.name == kw::Underscore &&
-            // We only want re-exports. If it's just a `use X;`, then we ignore it.
-            match cx.tcx.local_visibility(item.owner_id.def_id) {
-                Visibility::Public => true,
-                Visibility::Restricted(level) => {
-                    level != cx.tcx.parent_module_from_def_id(item.owner_id.def_id)
-                }
-            }
-        {
-            for def_id in path.res.iter().filter_map(|r| r.opt_def_id()) {
-                match cx.tcx.def_kind(def_id) {
-                    DefKind::Trait | DefKind::TraitAlias => {}
-                    DefKind::TyAlias => {
-                        let ty = cx.tcx.type_of(def_id);
-                        if !ty.0.is_trait() {
-                            emit_err(cx, item.span, def_id);
-                            break;
-                        }
-                    }
-                    _ => {
-                        emit_err(cx, item.span, def_id);
-                        break;
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 91966e75b5f..9d6ab0b75df 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3230,6 +3230,45 @@ declare_lint! {
     };
 }
 
+declare_lint! {
+    /// The `ambiguous_glob_reexports` lint detects cases where names re-exported via globs
+    /// collide. Downstream users trying to use the same name re-exported from multiple globs
+    /// will receive a warning pointing out redefinition of the same name.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(ambiguous_glob_reexports)]
+    /// pub mod foo {
+    ///     pub type X = u8;
+    /// }
+    ///
+    /// pub mod bar {
+    ///     pub type Y = u8;
+    ///     pub type X = u8;
+    /// }
+    ///
+    /// pub use foo::*;
+    /// pub use bar::*;
+    ///
+    ///
+    /// pub fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This was previously accepted but it could silently break a crate's downstream users code.
+    /// For example, if `foo::*` and `bar::*` were re-exported before `bar::X` was added to the
+    /// re-exports, down stream users could use `this_crate::X` without problems. However, adding
+    /// `bar::X` would cause compilation errors in downstream crates because `X` is defined
+    /// multiple times in the same namespace of `this_crate`.
+    pub AMBIGUOUS_GLOB_REEXPORTS,
+    Warn,
+    "ambiguous glob re-exports",
+}
+
 declare_lint_pass! {
     /// Does nothing as a lint pass, but registers some `Lint`s
     /// that are used by other parts of the compiler.
@@ -3337,6 +3376,7 @@ declare_lint_pass! {
         NAMED_ARGUMENTS_USED_POSITIONALLY,
         IMPLIED_BOUNDS_ENTAILMENT,
         BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
+        AMBIGUOUS_GLOB_REEXPORTS,
     ]
 }
 
@@ -3968,14 +4008,9 @@ declare_lint! {
     ///
     /// ### Example
     ///
-    /// ```rust,ignore (need FFI)
-    /// #![feature(ffi_unwind_calls)]
+    /// ```rust
     /// #![feature(c_unwind)]
-    ///
-    /// # mod impl {
-    /// #     #[no_mangle]
-    /// #     pub fn "C-unwind" fn foo() {}
-    /// # }
+    /// #![warn(ffi_unwind_calls)]
     ///
     /// extern "C-unwind" {
     ///     fn foo();
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 6f22bdabff4..69a8b691ab2 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -529,6 +529,16 @@ pub enum BuiltinLintDiagnostics {
         vis_span: Span,
         ident_span: Span,
     },
+    AmbiguousGlobReexports {
+        /// The name for which collision(s) have occurred.
+        name: String,
+        /// The name space for whihc the collision(s) occurred in.
+        namespace: String,
+        /// Span where the name is first re-exported.
+        first_reexport_span: Span,
+        /// Span where the same name is also re-exported.
+        duplicate_reexport_span: Span,
+    },
 }
 
 /// Lints that are buffered up early on in the `Session` before the
diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml
index bee5c8541d6..4d7c133e09b 100644
--- a/compiler/rustc_metadata/Cargo.toml
+++ b/compiler/rustc_metadata/Cargo.toml
@@ -18,6 +18,7 @@ rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_feature = { path = "../rustc_feature" }
+rustc_fs_util = { path = "../rustc_fs_util" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_hir_pretty = { path = "../rustc_hir_pretty" }
 rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index c48e681eb94..79c42a128e7 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -222,6 +222,7 @@ use rustc_data_structures::owning_ref::OwningRef;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::MetadataRef;
 use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg};
+use rustc_fs_util::try_canonicalize;
 use rustc_session::config::{self, CrateType};
 use rustc_session::cstore::{CrateSource, MetadataLoader};
 use rustc_session::filesearch::FileSearch;
@@ -236,7 +237,7 @@ use snap::read::FrameDecoder;
 use std::borrow::Cow;
 use std::io::{Read, Result as IoResult, Write};
 use std::path::{Path, PathBuf};
-use std::{cmp, fmt, fs};
+use std::{cmp, fmt};
 
 #[derive(Clone)]
 pub(crate) struct CrateLocator<'a> {
@@ -441,7 +442,7 @@ impl<'a> CrateLocator<'a> {
                 info!("lib candidate: {}", spf.path.display());
 
                 let (rlibs, rmetas, dylibs) = candidates.entry(hash.to_string()).or_default();
-                let path = fs::canonicalize(&spf.path).unwrap_or_else(|_| spf.path.clone());
+                let path = try_canonicalize(&spf.path).unwrap_or_else(|_| spf.path.clone());
                 if seen_paths.contains(&path) {
                     continue;
                 };
@@ -636,7 +637,7 @@ impl<'a> CrateLocator<'a> {
             // as well.
             if let Some((prev, _)) = &ret {
                 let sysroot = self.sysroot;
-                let sysroot = sysroot.canonicalize().unwrap_or_else(|_| sysroot.to_path_buf());
+                let sysroot = try_canonicalize(sysroot).unwrap_or_else(|_| sysroot.to_path_buf());
                 if prev.starts_with(&sysroot) {
                     continue;
                 }
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index b2578e4c4b4..dbf6cec788b 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -32,9 +32,10 @@ use rustc_ast::visit::{self, Visitor};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::{pluralize, MultiSpan};
+use rustc_hir::def::{DefKind, Res};
 use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS};
 use rustc_session::lint::BuiltinLintDiagnostics;
-use rustc_span::symbol::Ident;
+use rustc_span::symbol::{kw, Ident};
 use rustc_span::{Span, DUMMY_SP};
 
 struct UnusedImport<'a> {
@@ -58,6 +59,7 @@ struct UnusedImportCheckVisitor<'a, 'b, 'tcx> {
     base_use_tree: Option<&'a ast::UseTree>,
     base_id: ast::NodeId,
     item_span: Span,
+    base_use_is_pub: bool,
 }
 
 struct ExternCrateToLint {
@@ -110,6 +112,35 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
             unused: Default::default(),
         })
     }
+
+    fn check_import_as_underscore(&mut self, item: &ast::UseTree, id: ast::NodeId) {
+        match item.kind {
+            ast::UseTreeKind::Simple(Some(ident)) => {
+                if ident.name == kw::Underscore
+                    && !self
+                        .r
+                        .import_res_map
+                        .get(&id)
+                        .map(|per_ns| {
+                            per_ns.iter().filter_map(|res| res.as_ref()).any(|res| {
+                                matches!(res, Res::Def(DefKind::Trait | DefKind::TraitAlias, _))
+                            })
+                        })
+                        .unwrap_or(false)
+                {
+                    self.unused_import(self.base_id).add(id);
+                }
+            }
+            ast::UseTreeKind::Nested(ref items) => self.check_imports_as_underscore(items),
+            _ => {}
+        }
+    }
+
+    fn check_imports_as_underscore(&mut self, items: &[(ast::UseTree, ast::NodeId)]) {
+        for (item, id) in items {
+            self.check_import_as_underscore(item, *id);
+        }
+    }
 }
 
 impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
@@ -119,7 +150,8 @@ impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
             // whether they're used or not. Also ignore imports with a dummy span
             // because this means that they were generated in some fashion by the
             // compiler and we don't need to consider them.
-            ast::ItemKind::Use(..) if item.vis.kind.is_pub() || item.span.is_dummy() => return,
+            ast::ItemKind::Use(..) if item.span.is_dummy() => return,
+            ast::ItemKind::Use(..) => self.base_use_is_pub = item.vis.kind.is_pub(),
             ast::ItemKind::ExternCrate(orig_name) => {
                 self.extern_crate_items.push(ExternCrateToLint {
                     id: item.id,
@@ -146,6 +178,11 @@ impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
             self.base_use_tree = Some(use_tree);
         }
 
+        if self.base_use_is_pub {
+            self.check_import_as_underscore(use_tree, id);
+            return;
+        }
+
         if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
             if items.is_empty() {
                 self.unused_import(self.base_id).add(id);
@@ -300,6 +337,7 @@ impl Resolver<'_, '_> {
             base_use_tree: None,
             base_id: ast::DUMMY_NODE_ID,
             item_span: DUMMY_SP,
+            base_use_is_pub: false,
         };
         visit::walk_crate(&mut visitor, krate);
 
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index 4bb252bfb29..a1ae9b8a521 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -4,6 +4,7 @@ use rustc_ast::visit;
 use rustc_ast::visit::Visitor;
 use rustc_ast::Crate;
 use rustc_ast::EnumDef;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::intern::Interned;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::def_id::CRATE_DEF_ID;
@@ -70,11 +71,11 @@ impl Resolver<'_, '_> {
 impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
     /// Fills the `Resolver::effective_visibilities` table with public & exported items
     /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
-    /// need access to a TyCtxt for that.
+    /// need access to a TyCtxt for that. Returns the set of ambiguous re-exports.
     pub(crate) fn compute_effective_visibilities<'c>(
         r: &'r mut Resolver<'a, 'tcx>,
         krate: &'c Crate,
-    ) {
+    ) -> FxHashSet<Interned<'a, NameBinding<'a>>> {
         let mut visitor = EffectiveVisibilitiesVisitor {
             r,
             def_effective_visibilities: Default::default(),
@@ -93,18 +94,26 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
         }
         visitor.r.effective_visibilities = visitor.def_effective_visibilities;
 
+        let mut exported_ambiguities = FxHashSet::default();
+
         // Update visibilities for import def ids. These are not used during the
         // `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based
         // information, but are used by later passes. Effective visibility of an import def id
         // is the maximum value among visibilities of bindings corresponding to that def id.
         for (binding, eff_vis) in visitor.import_effective_visibilities.iter() {
             let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() };
-            if let Some(node_id) = import.id() {
-                r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx)
+            if !binding.is_ambiguity() {
+                if let Some(node_id) = import.id() {
+                    r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx)
+                }
+            } else if binding.ambiguity.is_some() && eff_vis.is_public_at_level(Level::Reexported) {
+                exported_ambiguities.insert(*binding);
             }
         }
 
         info!("resolve::effective_visibilities: {:#?}", r.effective_visibilities);
+
+        exported_ambiguities
     }
 
     /// Update effective visibilities of bindings in the given module,
@@ -115,21 +124,44 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
         let resolutions = self.r.resolutions(module);
 
         for (_, name_resolution) in resolutions.borrow().iter() {
-            if let Some(mut binding) = name_resolution.borrow().binding() && !binding.is_ambiguity() {
-                // Set the given effective visibility level to `Level::Direct` and
-                // sets the rest of the `use` chain to `Level::Reexported` until
-                // we hit the actual exported item.
-                let mut parent_id = ParentId::Def(module_id);
-                while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind {
-                    let binding_id = ImportId::new_unchecked(binding);
-                    self.update_import(binding_id, parent_id);
-
-                    parent_id = ParentId::Import(binding_id);
-                    binding = nested_binding;
-                }
+            if let Some(mut binding) = name_resolution.borrow().binding() {
+                if !binding.is_ambiguity() {
+                    // Set the given effective visibility level to `Level::Direct` and
+                    // sets the rest of the `use` chain to `Level::Reexported` until
+                    // we hit the actual exported item.
+                    let mut parent_id = ParentId::Def(module_id);
+                    while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind
+                    {
+                        let binding_id = ImportId::new_unchecked(binding);
+                        self.update_import(binding_id, parent_id);
+
+                        parent_id = ParentId::Import(binding_id);
+                        binding = nested_binding;
+                    }
+
+                    if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
+                        self.update_def(def_id, binding.vis.expect_local(), parent_id);
+                    }
+                } else {
+                    // Put the root ambiguity binding and all reexports leading to it into the
+                    // table. They are used by the `ambiguous_glob_reexports` lint. For all
+                    // bindings added to the table here `is_ambiguity` returns true.
+                    let mut parent_id = ParentId::Def(module_id);
+                    while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind
+                    {
+                        let binding_id = ImportId::new_unchecked(binding);
+                        self.update_import(binding_id, parent_id);
 
-                if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
-                    self.update_def(def_id, binding.vis.expect_local(), parent_id);
+                        if binding.ambiguity.is_some() {
+                            // Stop at the root ambiguity, further bindings in the chain should not
+                            // be reexported because the root ambiguity blocks any access to them.
+                            // (Those further bindings are most likely not ambiguities themselves.)
+                            break;
+                        }
+
+                        parent_id = ParentId::Import(binding_id);
+                        binding = nested_binding;
+                    }
                 }
             }
         }
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 4d4bc1be349..bc17ce571a7 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -19,7 +19,9 @@ use rustc_hir::def::{self, DefKind, PartialRes};
 use rustc_middle::metadata::ModChild;
 use rustc_middle::span_bug;
 use rustc_middle::ty;
-use rustc_session::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS};
+use rustc_session::lint::builtin::{
+    AMBIGUOUS_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS,
+};
 use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::hygiene::LocalExpnId;
@@ -510,6 +512,34 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
     }
 
+    pub(crate) fn check_reexport_ambiguities(
+        &mut self,
+        exported_ambiguities: FxHashSet<Interned<'a, NameBinding<'a>>>,
+    ) {
+        for module in self.arenas.local_modules().iter() {
+            module.for_each_child(self, |this, ident, ns, binding| {
+                if let NameBindingKind::Import { import, .. } = binding.kind
+                && let Some((amb_binding, _)) = binding.ambiguity
+                && binding.res() != Res::Err
+                && exported_ambiguities.contains(&Interned::new_unchecked(binding))
+                {
+                    this.lint_buffer.buffer_lint_with_diagnostic(
+                        AMBIGUOUS_GLOB_REEXPORTS,
+                        import.root_id,
+                        import.root_span,
+                        "ambiguous glob re-exports",
+                        BuiltinLintDiagnostics::AmbiguousGlobReexports {
+                            name: ident.to_string(),
+                            namespace: ns.descr().to_string(),
+                            first_reexport_span: import.root_span,
+                            duplicate_reexport_span: amb_binding.span,
+                        },
+                    );
+                }
+            });
+        }
+    }
+
     fn throw_unresolved_import_error(&self, errors: Vec<(&Import<'_>, UnresolvedImportError)>) {
         if errors.is_empty() {
             return;
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index aa50699890c..7afd43c303f 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1475,9 +1475,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     pub fn resolve_crate(&mut self, krate: &Crate) {
         self.tcx.sess.time("resolve_crate", || {
             self.tcx.sess.time("finalize_imports", || self.finalize_imports());
-            self.tcx.sess.time("compute_effective_visibilities", || {
+            let exported_ambiguities = self.tcx.sess.time("compute_effective_visibilities", || {
                 EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate)
             });
+            self.tcx.sess.time("check_reexport_ambiguities", || {
+                self.check_reexport_ambiguities(exported_ambiguities)
+            });
             self.tcx.sess.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
             self.tcx.sess.time("late_resolve_crate", || self.late_resolve_crate(krate));
             self.tcx.sess.time("resolve_main", || self.resolve_main());
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index e734599cbfc..2404928b254 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -1,5 +1,6 @@
 //! A module for searching for libraries
 
+use rustc_fs_util::try_canonicalize;
 use smallvec::{smallvec, SmallVec};
 use std::env;
 use std::fs;
@@ -125,7 +126,7 @@ pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> {
     let target = crate::config::host_triple();
     let mut sysroot_candidates: SmallVec<[PathBuf; 2]> =
         smallvec![get_or_default_sysroot().expect("Failed finding sysroot")];
-    let path = current_dll_path().and_then(|s| s.canonicalize().map_err(|e| e.to_string()));
+    let path = current_dll_path().and_then(|s| try_canonicalize(s).map_err(|e| e.to_string()));
     if let Ok(dll) = path {
         // use `parent` twice to chop off the file name and then also the
         // directory containing the dll which should be either `lib` or `bin`.
@@ -160,7 +161,7 @@ pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> {
 pub fn get_or_default_sysroot() -> Result<PathBuf, String> {
     // Follow symlinks. If the resolved path is relative, make it absolute.
     fn canonicalize(path: PathBuf) -> PathBuf {
-        let path = fs::canonicalize(&path).unwrap_or(path);
+        let path = try_canonicalize(&path).unwrap_or(path);
         // See comments on this target function, but the gist is that
         // gcc chokes on verbatim paths which fs::canonicalize generates
         // so we try to avoid those kinds of paths.
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 0548379dc2f..c75af48e80a 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -4,6 +4,7 @@ use crate::early_error;
 use crate::lint;
 use crate::search_paths::SearchPath;
 use crate::utils::NativeLib;
+use rustc_data_structures::profiling::TimePassesFormat;
 use rustc_errors::{LanguageIdentifier, TerminalUrl};
 use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet};
 use rustc_target::spec::{
@@ -365,6 +366,7 @@ mod desc {
     pub const parse_number: &str = "a number";
     pub const parse_opt_number: &str = parse_number;
     pub const parse_threads: &str = parse_number;
+    pub const parse_time_passes_format: &str = "`text` (default) or `json`";
     pub const parse_passes: &str = "a space-separated list of passes, or `all`";
     pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
     pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
@@ -829,6 +831,21 @@ mod parse {
         true
     }
 
+    pub(crate) fn parse_time_passes_format(slot: &mut TimePassesFormat, v: Option<&str>) -> bool {
+        match v {
+            None => true,
+            Some("json") => {
+                *slot = TimePassesFormat::Json;
+                true
+            }
+            Some("text") => {
+                *slot = TimePassesFormat::Text;
+                true
+            }
+            Some(_) => false,
+        }
+    }
+
     pub(crate) fn parse_dump_mono_stats(slot: &mut DumpMonoStatsFormat, v: Option<&str>) -> bool {
         match v {
             None => true,
@@ -1709,6 +1726,8 @@ options! {
         "measure time of each LLVM pass (default: no)"),
     time_passes: bool = (false, parse_bool, [UNTRACKED],
         "measure time of each rustc pass (default: no)"),
+    time_passes_format: TimePassesFormat = (TimePassesFormat::Text, parse_time_passes_format, [UNTRACKED],
+        "the format to use for -Z time-passes (`text` (default) or `json`)"),
     tiny_const_eval_limit: bool = (false, parse_bool, [TRACKED],
         "sets a tiny, non-configurable limit for const eval; useful for compiler tests"),
     #[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")]
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 700a059c368..5730df9d5c6 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1453,7 +1453,10 @@ pub fn build_session(
         CguReuseTracker::new_disabled()
     };
 
-    let prof = SelfProfilerRef::new(self_profiler, sopts.unstable_opts.time_passes);
+    let prof = SelfProfilerRef::new(
+        self_profiler,
+        sopts.unstable_opts.time_passes.then(|| sopts.unstable_opts.time_passes_format),
+    );
 
     let ctfe_backtrace = Lock::new(match env::var("RUSTC_CTFE_BACKTRACE") {
         Ok(ref val) if val == "immediate" => CtfeBacktrace::Immediate,
diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs
index 3b3d4ca5d6b..1d15e2c28d8 100644
--- a/compiler/rustc_session/src/utils.rs
+++ b/compiler/rustc_session/src/utils.rs
@@ -1,5 +1,6 @@
 use crate::session::Session;
 use rustc_data_structures::profiling::VerboseTimingGuard;
+use rustc_fs_util::try_canonicalize;
 use std::path::{Path, PathBuf};
 
 impl Session {
@@ -98,7 +99,7 @@ pub struct CanonicalizedPath {
 
 impl CanonicalizedPath {
     pub fn new(path: &Path) -> Self {
-        Self { original: path.to_owned(), canonicalized: std::fs::canonicalize(path).ok() }
+        Self { original: path.to_owned(), canonicalized: try_canonicalize(path).ok() }
     }
 
     pub fn canonicalized(&self) -> &PathBuf {
diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml
index 568c916a163..4e7a8d166ae 100644
--- a/compiler/rustc_target/Cargo.toml
+++ b/compiler/rustc_target/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2021"
 bitflags = "1.2.1"
 tracing = "0.1"
 serde_json = "1.0.59"
+rustc_fs_util = { path = "../rustc_fs_util" }
 rustc_abi = { path = "../rustc_abi" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_feature = { path = "../rustc_feature" }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index f3304e91429..2553b11d878 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -40,6 +40,7 @@ use crate::json::{Json, ToJson};
 use crate::spec::abi::{lookup as lookup_abi, Abi};
 use crate::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_fs_util::try_canonicalize;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_span::symbol::{sym, Symbol};
 use serde_json::Value;
@@ -2949,7 +2950,7 @@ impl TargetTriple {
 
     /// Creates a target triple from the passed target path.
     pub fn from_path(path: &Path) -> Result<Self, io::Error> {
-        let canonicalized_path = path.canonicalize()?;
+        let canonicalized_path = try_canonicalize(path)?;
         let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| {
             io::Error::new(
                 io::ErrorKind::InvalidInput,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index af108ab6f30..be0817472ea 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1356,6 +1356,31 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             Applicability::MaybeIncorrect,
                         );
                     } else {
+                        let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
+                        let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" });
+                        let sugg_msg = &format!(
+                            "consider{} borrowing here",
+                            if is_mut { " mutably" } else { "" }
+                        );
+
+                        // Issue #109436, we need to add parentheses properly for method calls
+                        // for example, `foo.into()` should be `(&foo).into()`
+                        if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(
+                            self.tcx.sess.source_map().span_look_ahead(span, Some("."), Some(50)),
+                        ) {
+                            if snippet == "." {
+                                err.multipart_suggestion_verbose(
+                                    sugg_msg,
+                                    vec![
+                                        (span.shrink_to_lo(), format!("({}", sugg_prefix)),
+                                        (span.shrink_to_hi(), ")".to_string()),
+                                    ],
+                                    Applicability::MaybeIncorrect,
+                                );
+                                return true;
+                            }
+                        }
+
                         // Issue #104961, we need to add parentheses properly for compond expressions
                         // for example, `x.starts_with("hi".to_string() + "you")`
                         // should be `x.starts_with(&("hi".to_string() + "you"))`
@@ -1372,14 +1397,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             _ => false,
                         };
 
-                        let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
                         let span = if needs_parens { span } else { span.shrink_to_lo() };
-                        let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" });
-                        let sugg_msg = &format!(
-                            "consider{} borrowing here",
-                            if is_mut { " mutably" } else { "" }
-                        );
-
                         let suggestions = if !needs_parens {
                             vec![(span.shrink_to_lo(), format!("{}", sugg_prefix))]
                         } else {
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index 7f07e4fddef..1cedd6eedfa 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -370,7 +370,7 @@ pub enum ErrorKind {
 
     // "Unusual" error kinds which do not correspond simply to (sets
     // of) OS error codes, should be added just above this comment.
-    // `Other` and `Uncategorised` should remain at the end:
+    // `Other` and `Uncategorized` should remain at the end:
     //
     /// A custom error that does not fall under any other I/O error kind.
     ///
@@ -882,6 +882,13 @@ impl Error {
 
     /// Returns the corresponding [`ErrorKind`] for this error.
     ///
+    /// This may be a value set by Rust code constructing custom `io::Error`s,
+    /// or if this `io::Error` was sourced from the operating system,
+    /// it will be a value inferred from the system's error encoding.
+    /// See [`last_os_error`] for more details.
+    ///
+    /// [`last_os_error`]: Error::last_os_error
+    ///
     /// # Examples
     ///
     /// ```
@@ -892,7 +899,8 @@ impl Error {
     /// }
     ///
     /// fn main() {
-    ///     // Will print "Uncategorized".
+    ///     // As no error has (visibly) occurred, this may print anything!
+    ///     // It likely prints a placeholder for unidentified (non-)errors.
     ///     print_error(Error::last_os_error());
     ///     // Will print "AddrInUse".
     ///     print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
index 3842a649c6f..034c6aa0708 100644
--- a/src/tools/lint-docs/src/lib.rs
+++ b/src/tools/lint-docs/src/lib.rs
@@ -45,6 +45,36 @@ impl Lint {
     fn check_style(&self) -> Result<(), Box<dyn Error>> {
         for &expected in &["### Example", "### Explanation", "{{produces}}"] {
             if expected == "{{produces}}" && self.is_ignored() {
+                if self.doc_contains("{{produces}}") {
+                    return Err(format!(
+                        "the lint example has `ignore`, but also contains the {{{{produces}}}} marker\n\
+                        \n\
+                        The documentation generator cannot generate the example output when the \
+                        example is ignored.\n\
+                        Manually include the sample output below the example. For example:\n\
+                        \n\
+                        /// ```rust,ignore (needs command line option)\n\
+                        /// #[cfg(widnows)]\n\
+                        /// fn foo() {{}}\n\
+                        /// ```\n\
+                        ///\n\
+                        /// This will produce:\n\
+                        /// \n\
+                        /// ```text\n\
+                        /// warning: unknown condition name used\n\
+                        ///  --> lint_example.rs:1:7\n\
+                        ///   |\n\
+                        /// 1 | #[cfg(widnows)]\n\
+                        ///   |       ^^^^^^^\n\
+                        ///   |\n\
+                        ///   = note: `#[warn(unexpected_cfgs)]` on by default\n\
+                        /// ```\n\
+                        \n\
+                        Replacing the output with the text of the example you \
+                        compiled manually yourself.\n\
+                        "
+                    ).into());
+                }
                 continue;
             }
             if !self.doc_contains(expected) {
@@ -317,10 +347,10 @@ impl<'a> LintExtractor<'a> {
                             ..,
                             &format!(
                                 "This will produce:\n\
-                            \n\
-                            ```text\n\
-                            {}\
-                            ```",
+                                \n\
+                                ```text\n\
+                                {}\
+                                ```",
                                 output
                             ),
                         );
@@ -392,37 +422,36 @@ impl<'a> LintExtractor<'a> {
             .filter(|line| line.starts_with('{'))
             .map(serde_json::from_str)
             .collect::<Result<Vec<serde_json::Value>, _>>()?;
-        match msgs
+        // First try to find the messages with the `code` field set to our lint.
+        let matches: Vec<_> = msgs
             .iter()
-            .find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name))
-        {
-            Some(msg) => {
-                let rendered = msg["rendered"].as_str().expect("rendered field should exist");
-                Ok(rendered.to_string())
-            }
-            None => {
-                match msgs.iter().find(
-                    |msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)),
-                ) {
-                    Some(msg) => {
-                        let rendered = msg["rendered"].as_str().expect("rendered field should exist");
-                        Ok(rendered.to_string())
-                    }
-                    None => {
-                        let rendered: Vec<&str> =
-                            msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
-                        let non_json: Vec<&str> =
-                            stderr.lines().filter(|line| !line.starts_with('{')).collect();
-                        Err(format!(
-                            "did not find lint `{}` in output of example, got:\n{}\n{}",
-                            name,
-                            non_json.join("\n"),
-                            rendered.join("\n")
-                        )
-                        .into())
-                    }
-                }
+            .filter(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name))
+            .map(|msg| msg["rendered"].as_str().expect("rendered field should exist").to_string())
+            .collect();
+        if matches.is_empty() {
+            // Some lints override their code to something else (E0566).
+            // Try to find something that looks like it could be our lint.
+            let matches: Vec<_> = msgs.iter().filter(|msg|
+                matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)))
+                .map(|msg| msg["rendered"].as_str().expect("rendered field should exist").to_string())
+                .collect();
+            if matches.is_empty() {
+                let rendered: Vec<&str> =
+                    msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
+                let non_json: Vec<&str> =
+                    stderr.lines().filter(|line| !line.starts_with('{')).collect();
+                Err(format!(
+                    "did not find lint `{}` in output of example, got:\n{}\n{}",
+                    name,
+                    non_json.join("\n"),
+                    rendered.join("\n")
+                )
+                .into())
+            } else {
+                Ok(matches.join("\n"))
             }
+        } else {
+            Ok(matches.join("\n"))
         }
     }
 
diff --git a/tests/rustdoc-ui/z-help.stdout b/tests/rustdoc-ui/z-help.stdout
index 5ad38e4fd98..72f5f933d8d 100644
--- a/tests/rustdoc-ui/z-help.stdout
+++ b/tests/rustdoc-ui/z-help.stdout
@@ -183,6 +183,7 @@
     -Z                               threads=val -- use a thread pool with N threads
     -Z                      time-llvm-passes=val -- measure time of each LLVM pass (default: no)
     -Z                           time-passes=val -- measure time of each rustc pass (default: no)
+    -Z                    time-passes-format=val -- the format to use for -Z time-passes (`text` (default) or `json`)
     -Z                 tiny-const-eval-limit=val -- sets a tiny, non-configurable limit for const eval; useful for compiler tests
     -Z                             tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details)
     -Z                          trace-macros=val -- for every macro invocation, print its name and arguments (default: no)
diff --git a/tests/ui/feature-gates/feature-gate-link_cfg.stderr b/tests/ui/feature-gates/feature-gate-link_cfg.stderr
index 8f47d596521..97b6cbca412 100644
--- a/tests/ui/feature-gates/feature-gate-link_cfg.stderr
+++ b/tests/ui/feature-gates/feature-gate-link_cfg.stderr
@@ -4,7 +4,6 @@ error[E0658]: link cfg is unstable
 LL | #[link(name = "foo", cfg(foo))]
    |                      ^^^^^^^^
    |
-   = note: see issue #37406 <https://github.com/rust-lang/rust/issues/37406> for more information
    = help: add `#![feature(link_cfg)]` to the crate attributes to enable
 
 error: aborting due to previous error
diff --git a/tests/ui/imports/auxiliary/glob-conflict.rs b/tests/ui/imports/auxiliary/glob-conflict.rs
index c83db64c643..8a146378b43 100644
--- a/tests/ui/imports/auxiliary/glob-conflict.rs
+++ b/tests/ui/imports/auxiliary/glob-conflict.rs
@@ -1,3 +1,5 @@
+#![allow(ambiguous_glob_reexports)]
+
 mod m1 {
     pub fn f() {}
 }
diff --git a/tests/ui/imports/issue-99695-b.fixed b/tests/ui/imports/issue-99695-b.fixed
index 0f688fa2823..0e60c73b67a 100644
--- a/tests/ui/imports/issue-99695-b.fixed
+++ b/tests/ui/imports/issue-99695-b.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
+#![allow(unused, nonstandard_style)]
 mod m {
 
     mod p {
diff --git a/tests/ui/imports/issue-99695-b.rs b/tests/ui/imports/issue-99695-b.rs
index b433997e53f..031443a1f5d 100644
--- a/tests/ui/imports/issue-99695-b.rs
+++ b/tests/ui/imports/issue-99695-b.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
+#![allow(unused, nonstandard_style)]
 mod m {
 
     mod p {
diff --git a/tests/ui/imports/issue-99695.fixed b/tests/ui/imports/issue-99695.fixed
index 17ff409324e..6bf228b23aa 100644
--- a/tests/ui/imports/issue-99695.fixed
+++ b/tests/ui/imports/issue-99695.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
+#![allow(unused, nonstandard_style)]
 mod m {
     #[macro_export]
     macro_rules! nu {
diff --git a/tests/ui/imports/issue-99695.rs b/tests/ui/imports/issue-99695.rs
index b8979bcb734..f7199f1497a 100644
--- a/tests/ui/imports/issue-99695.rs
+++ b/tests/ui/imports/issue-99695.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
+#![allow(unused, nonstandard_style)]
 mod m {
     #[macro_export]
     macro_rules! nu {
diff --git a/tests/ui/imports/local-modularized-tricky-fail-1.rs b/tests/ui/imports/local-modularized-tricky-fail-1.rs
index 29e9b8ec841..ce700ae0de9 100644
--- a/tests/ui/imports/local-modularized-tricky-fail-1.rs
+++ b/tests/ui/imports/local-modularized-tricky-fail-1.rs
@@ -1,4 +1,5 @@
 #![feature(decl_macro)]
+#![allow(ambiguous_glob_reexports)]
 
 macro_rules! define_exported { () => {
     #[macro_export]
diff --git a/tests/ui/imports/local-modularized-tricky-fail-1.stderr b/tests/ui/imports/local-modularized-tricky-fail-1.stderr
index 20eadaaaa56..52a01e8bcdf 100644
--- a/tests/ui/imports/local-modularized-tricky-fail-1.stderr
+++ b/tests/ui/imports/local-modularized-tricky-fail-1.stderr
@@ -1,12 +1,12 @@
 error[E0659]: `exported` is ambiguous
-  --> $DIR/local-modularized-tricky-fail-1.rs:28:1
+  --> $DIR/local-modularized-tricky-fail-1.rs:29:1
    |
 LL | exported!();
    | ^^^^^^^^ ambiguous name
    |
    = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
 note: `exported` could refer to the macro defined here
-  --> $DIR/local-modularized-tricky-fail-1.rs:5:5
+  --> $DIR/local-modularized-tricky-fail-1.rs:6:5
    |
 LL | /     macro_rules! exported {
 LL | |         () => ()
@@ -16,7 +16,7 @@ LL | |     }
 LL |       define_exported!();
    |       ------------------ in this macro invocation
 note: `exported` could also refer to the macro imported here
-  --> $DIR/local-modularized-tricky-fail-1.rs:22:5
+  --> $DIR/local-modularized-tricky-fail-1.rs:23:5
    |
 LL | use inner1::*;
    |     ^^^^^^^^^
@@ -24,7 +24,7 @@ LL | use inner1::*;
    = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0659]: `panic` is ambiguous
-  --> $DIR/local-modularized-tricky-fail-1.rs:35:5
+  --> $DIR/local-modularized-tricky-fail-1.rs:36:5
    |
 LL |     panic!();
    |     ^^^^^ ambiguous name
@@ -32,7 +32,7 @@ LL |     panic!();
    = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
    = note: `panic` could refer to a macro from prelude
 note: `panic` could also refer to the macro defined here
-  --> $DIR/local-modularized-tricky-fail-1.rs:11:5
+  --> $DIR/local-modularized-tricky-fail-1.rs:12:5
    |
 LL | /     macro_rules! panic {
 LL | |         () => ()
@@ -45,7 +45,7 @@ LL |       define_panic!();
    = note: this error originates in the macro `define_panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0659]: `include` is ambiguous
-  --> $DIR/local-modularized-tricky-fail-1.rs:46:1
+  --> $DIR/local-modularized-tricky-fail-1.rs:47:1
    |
 LL | include!();
    | ^^^^^^^ ambiguous name
@@ -53,7 +53,7 @@ LL | include!();
    = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
    = note: `include` could refer to a macro from prelude
 note: `include` could also refer to the macro defined here
-  --> $DIR/local-modularized-tricky-fail-1.rs:17:5
+  --> $DIR/local-modularized-tricky-fail-1.rs:18:5
    |
 LL | /     macro_rules! include {
 LL | |         () => ()
diff --git a/tests/ui/lint/anonymous-reexport.rs b/tests/ui/lint/anonymous-reexport.rs
index 5d56ae6f969..11ac5d07140 100644
--- a/tests/ui/lint/anonymous-reexport.rs
+++ b/tests/ui/lint/anonymous-reexport.rs
@@ -1,4 +1,4 @@
-#![deny(useless_anonymous_reexport)]
+#![deny(unused_imports)]
 #![crate_type = "rlib"]
 
 mod my_mod {
@@ -9,13 +9,11 @@ mod my_mod {
 }
 
 pub use self::my_mod::Foo as _;
-pub use self::my_mod::TyFoo as _;
-pub use self::my_mod::Bar as _; //~ ERROR
-pub use self::my_mod::TyBar as _; //~ ERROR
-pub use self::my_mod::{Bar as _}; //~ ERROR
-pub use self::my_mod::{Bar as _, Foo as _}; //~ ERROR
-pub use self::my_mod::{Bar as _, TyBar as _};
-//~^ ERROR
-//~| ERROR
+pub use self::my_mod::TyFoo as _; //~ ERROR unused import
+pub use self::my_mod::Bar as _; //~ ERROR unused import
+pub use self::my_mod::TyBar as _; //~ ERROR unused import
+pub use self::my_mod::{Bar as _}; //~ ERROR unused import
+pub use self::my_mod::{Bar as _, Foo as _}; //~ ERROR unused import
+pub use self::my_mod::{Bar as _, TyBar as _}; //~ ERROR unused imports
 #[allow(unused_imports)]
 use self::my_mod::TyBar as _;
diff --git a/tests/ui/lint/anonymous-reexport.stderr b/tests/ui/lint/anonymous-reexport.stderr
index f4f8b41c417..e3854a5459e 100644
--- a/tests/ui/lint/anonymous-reexport.stderr
+++ b/tests/ui/lint/anonymous-reexport.stderr
@@ -1,55 +1,44 @@
-error: useless anonymous re-export
-  --> $DIR/anonymous-reexport.rs:13:1
+error: unused import: `self::my_mod::TyFoo as _`
+  --> $DIR/anonymous-reexport.rs:12:9
    |
-LL | pub use self::my_mod::Bar as _;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | pub use self::my_mod::TyFoo as _;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only anonymous re-exports of traits are useful, this is a `struct`
 note: the lint level is defined here
   --> $DIR/anonymous-reexport.rs:1:9
    |
-LL | #![deny(useless_anonymous_reexport)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![deny(unused_imports)]
+   |         ^^^^^^^^^^^^^^
 
-error: useless anonymous re-export
-  --> $DIR/anonymous-reexport.rs:14:1
+error: unused import: `self::my_mod::Bar as _`
+  --> $DIR/anonymous-reexport.rs:13:9
    |
-LL | pub use self::my_mod::TyBar as _;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | pub use self::my_mod::Bar as _;
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error: unused import: `self::my_mod::TyBar as _`
+  --> $DIR/anonymous-reexport.rs:14:9
    |
-   = note: only anonymous re-exports of traits are useful, this is a `type alias`
+LL | pub use self::my_mod::TyBar as _;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: useless anonymous re-export
+error: unused import: `Bar as _`
   --> $DIR/anonymous-reexport.rs:15:24
    |
 LL | pub use self::my_mod::{Bar as _};
    |                        ^^^^^^^^
-   |
-   = note: only anonymous re-exports of traits are useful, this is a `struct`
 
-error: useless anonymous re-export
+error: unused import: `Bar as _`
   --> $DIR/anonymous-reexport.rs:16:24
    |
 LL | pub use self::my_mod::{Bar as _, Foo as _};
    |                        ^^^^^^^^
-   |
-   = note: only anonymous re-exports of traits are useful, this is a `struct`
 
-error: useless anonymous re-export
+error: unused imports: `Bar as _`, `TyBar as _`
   --> $DIR/anonymous-reexport.rs:17:24
    |
 LL | pub use self::my_mod::{Bar as _, TyBar as _};
-   |                        ^^^^^^^^
-   |
-   = note: only anonymous re-exports of traits are useful, this is a `struct`
-
-error: useless anonymous re-export
-  --> $DIR/anonymous-reexport.rs:17:34
-   |
-LL | pub use self::my_mod::{Bar as _, TyBar as _};
-   |                                  ^^^^^^^^^^
-   |
-   = note: only anonymous re-exports of traits are useful, this is a `type alias`
+   |                        ^^^^^^^^  ^^^^^^^^^^
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs
new file mode 100644
index 00000000000..431213e25e4
--- /dev/null
+++ b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs
@@ -0,0 +1,33 @@
+#![deny(ambiguous_glob_reexports)]
+
+pub mod foo {
+    pub type X = u8;
+}
+
+pub mod bar {
+    pub type X = u8;
+    pub type Y = u8;
+}
+
+pub use foo::*;
+//~^ ERROR ambiguous glob re-exports
+pub use bar::*;
+
+mod ambiguous {
+    mod m1 { pub type A = u8; }
+    mod m2 { pub type A = u8; }
+    pub use self::m1::*;
+    //~^ ERROR ambiguous glob re-exports
+    pub use self::m2::*;
+}
+
+pub mod single {
+    pub use ambiguous::A;
+    //~^ ERROR `A` is ambiguous
+}
+
+pub mod glob {
+    pub use ambiguous::*;
+}
+
+pub fn main() {}
diff --git a/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.stderr b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.stderr
new file mode 100644
index 00000000000..07e61dd8643
--- /dev/null
+++ b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.stderr
@@ -0,0 +1,47 @@
+error[E0659]: `A` is ambiguous
+  --> $DIR/issue-107563-ambiguous-glob-reexports.rs:25:24
+   |
+LL |     pub use ambiguous::A;
+   |                        ^ ambiguous name
+   |
+   = note: ambiguous because of multiple glob imports of a name in the same module
+note: `A` could refer to the type alias imported here
+  --> $DIR/issue-107563-ambiguous-glob-reexports.rs:19:13
+   |
+LL |     pub use self::m1::*;
+   |             ^^^^^^^^^^^
+   = help: consider adding an explicit import of `A` to disambiguate
+note: `A` could also refer to the type alias imported here
+  --> $DIR/issue-107563-ambiguous-glob-reexports.rs:21:13
+   |
+LL |     pub use self::m2::*;
+   |             ^^^^^^^^^^^
+   = help: consider adding an explicit import of `A` to disambiguate
+
+error: ambiguous glob re-exports
+  --> $DIR/issue-107563-ambiguous-glob-reexports.rs:12:9
+   |
+LL | pub use foo::*;
+   |         ^^^^^^ the name `X` in the type namespace is first re-exported here
+LL |
+LL | pub use bar::*;
+   |         ------ but the name `X` in the type namespace is also re-exported here
+   |
+note: the lint level is defined here
+  --> $DIR/issue-107563-ambiguous-glob-reexports.rs:1:9
+   |
+LL | #![deny(ambiguous_glob_reexports)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: ambiguous glob re-exports
+  --> $DIR/issue-107563-ambiguous-glob-reexports.rs:19:13
+   |
+LL |     pub use self::m1::*;
+   |             ^^^^^^^^^^^ the name `A` in the type namespace is first re-exported here
+LL |
+LL |     pub use self::m2::*;
+   |             ----------- but the name `A` in the type namespace is also re-exported here
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0659`.
diff --git a/tests/ui/suggestions/issue-109436.rs b/tests/ui/suggestions/issue-109436.rs
new file mode 100644
index 00000000000..e45ee5991db
--- /dev/null
+++ b/tests/ui/suggestions/issue-109436.rs
@@ -0,0 +1,13 @@
+struct Foo;
+struct Bar;
+
+impl From<&Foo> for Bar {
+    fn from(foo: &Foo) -> Bar {
+        Bar
+    }
+}
+
+fn main() {
+    let foo = Foo;
+    let b: Bar = foo.into(); //~ ERROR E0277
+}
diff --git a/tests/ui/suggestions/issue-109436.stderr b/tests/ui/suggestions/issue-109436.stderr
new file mode 100644
index 00000000000..48518b33d12
--- /dev/null
+++ b/tests/ui/suggestions/issue-109436.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `Foo: Into<_>` is not satisfied
+  --> $DIR/issue-109436.rs:12:22
+   |
+LL |     let b: Bar = foo.into();
+   |                      ^^^^ the trait `~const Into<_>` is not implemented for `Foo`
+   |
+   = note: required for `Foo` to implement `Into<Bar>`
+help: consider borrowing here
+   |
+LL |     let b: Bar = (&foo).into();
+   |                  ++   +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.