about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs123
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs7
-rw-r--r--library/std/src/sys/fs/unix.rs10
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs52
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs7
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs32
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs14
-rw-r--r--src/bootstrap/src/core/build_steps/vendor.rs1
-rw-r--r--src/bootstrap/src/core/builder/mod.rs10
-rw-r--r--src/bootstrap/src/core/builder/tests.rs8
-rw-r--r--tests/ui/methods/missing-bound-on-tuple.rs39
-rw-r--r--tests/ui/methods/missing-bound-on-tuple.stderr58
-rw-r--r--tests/ui/methods/tuple-suggestions-issue-142488.rs48
-rw-r--r--tests/ui/methods/tuple-suggestions-issue-142488.stderr61
-rw-r--r--tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.dump.stderr16
-rw-r--r--tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.rs49
-rw-r--r--tests/ui/traits/vtable/multiple-auto.rs50
-rw-r--r--tests/ui/traits/vtable/multiple-auto.stderr46
18 files changed, 373 insertions, 258 deletions
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 495f592baa8..f22f1856704 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -13,9 +13,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::codes::*;
-use rustc_errors::{
-    Applicability, Diag, DiagStyledString, MultiSpan, StashKey, pluralize, struct_span_code_err,
-};
+use rustc_errors::{Applicability, Diag, MultiSpan, StashKey, pluralize, struct_span_code_err};
 use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -1572,11 +1570,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
         }
 
-        if rcvr_ty.is_numeric() && rcvr_ty.is_fresh()
-            || restrict_type_params
-            || suggested_derive
-            || self.lookup_alternative_tuple_impls(&mut err, &unsatisfied_predicates)
-        {
+        if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params || suggested_derive {
         } else {
             self.suggest_traits_to_import(
                 &mut err,
@@ -1753,119 +1747,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err.emit()
     }
 
-    /// If the predicate failure is caused by an unmet bound on a tuple, recheck if the bound would
-    /// succeed if all the types on the tuple had no borrows. This is a common problem for libraries
-    /// like Bevy and ORMs, which rely heavily on traits being implemented on tuples.
-    fn lookup_alternative_tuple_impls(
-        &self,
-        err: &mut Diag<'_>,
-        unsatisfied_predicates: &[(
-            ty::Predicate<'tcx>,
-            Option<ty::Predicate<'tcx>>,
-            Option<ObligationCause<'tcx>>,
-        )],
-    ) -> bool {
-        let mut found_tuple = false;
-        for (pred, root, _ob) in unsatisfied_predicates {
-            let mut preds = vec![pred];
-            if let Some(root) = root {
-                // We will look at both the current predicate and the root predicate that caused it
-                // to be needed. If calling something like `<(A, &B)>::default()`, then `pred` is
-                // `&B: Default` and `root` is `(A, &B): Default`, which is the one we are checking
-                // for further down, so we check both.
-                preds.push(root);
-            }
-            for pred in preds {
-                if let Some(clause) = pred.as_clause()
-                    && let Some(clause) = clause.as_trait_clause()
-                    && let ty = clause.self_ty().skip_binder()
-                    && let ty::Tuple(types) = ty.kind()
-                {
-                    let path = clause.skip_binder().trait_ref.print_only_trait_path();
-                    let def_id = clause.def_id();
-                    let ty = Ty::new_tup(
-                        self.tcx,
-                        self.tcx.mk_type_list_from_iter(types.iter().map(|ty| ty.peel_refs())),
-                    );
-                    let args = ty::GenericArgs::for_item(self.tcx, def_id, |param, _| {
-                        if param.index == 0 {
-                            ty.into()
-                        } else {
-                            self.infcx.var_for_def(DUMMY_SP, param)
-                        }
-                    });
-                    if self
-                        .infcx
-                        .type_implements_trait(def_id, args, self.param_env)
-                        .must_apply_modulo_regions()
-                    {
-                        // "`Trait` is implemented for `(A, B)` but not for `(A, &B)`"
-                        let mut msg = DiagStyledString::normal(format!("`{path}` "));
-                        msg.push_highlighted("is");
-                        msg.push_normal(" implemented for `(");
-                        let len = types.len();
-                        for (i, t) in types.iter().enumerate() {
-                            msg.push(
-                                format!("{}", with_forced_trimmed_paths!(t.peel_refs())),
-                                t.peel_refs() != t,
-                            );
-                            if i < len - 1 {
-                                msg.push_normal(", ");
-                            }
-                        }
-                        msg.push_normal(")` but ");
-                        msg.push_highlighted("not");
-                        msg.push_normal(" for `(");
-                        for (i, t) in types.iter().enumerate() {
-                            msg.push(
-                                format!("{}", with_forced_trimmed_paths!(t)),
-                                t.peel_refs() != t,
-                            );
-                            if i < len - 1 {
-                                msg.push_normal(", ");
-                            }
-                        }
-                        msg.push_normal(")`");
-
-                        // Find the span corresponding to the impl that was found to point at it.
-                        if let Some(impl_span) = self
-                            .tcx
-                            .all_impls(def_id)
-                            .filter(|&impl_def_id| {
-                                let header = self.tcx.impl_trait_header(impl_def_id).unwrap();
-                                let trait_ref = header.trait_ref.instantiate(
-                                    self.tcx,
-                                    self.infcx.fresh_args_for_item(DUMMY_SP, impl_def_id),
-                                );
-
-                                let value = ty::fold_regions(self.tcx, ty, |_, _| {
-                                    self.tcx.lifetimes.re_erased
-                                });
-                                // FIXME: Don't bother dealing with non-lifetime binders here...
-                                if value.has_escaping_bound_vars() {
-                                    return false;
-                                }
-                                self.infcx.can_eq(ty::ParamEnv::empty(), trait_ref.self_ty(), value)
-                                    && header.polarity == ty::ImplPolarity::Positive
-                            })
-                            .map(|impl_def_id| self.tcx.def_span(impl_def_id))
-                            .next()
-                        {
-                            err.highlighted_span_note(impl_span, msg.0);
-                        } else {
-                            err.highlighted_note(msg.0);
-                        }
-                        found_tuple = true;
-                    }
-                    // If `pred` was already on the tuple, we don't need to look at the root
-                    // obligation too.
-                    break;
-                }
-            }
-        }
-        found_tuple
-    }
-
     /// If an appropriate error source is not found, check method chain for possible candidates
     fn lookup_segments_chain_for_no_match_method(
         &self,
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index 3565c11249a..7e8a41457d4 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -153,7 +153,12 @@ fn prepare_vtable_segments_inner<'tcx, T>(
 
         // emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level.
         while let Some((inner_most_trait_ref, emit_vptr, mut siblings)) = stack.pop() {
-            let has_entries = has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id);
+            // We don't need to emit a vptr for "truly-empty" supertraits, but we *do* need to emit a
+            // vptr for supertraits that have no methods, but that themselves have supertraits
+            // with methods, so we check if any transitive supertrait has entries here (this includes
+            // the trait itself).
+            let has_entries = ty::elaborate::supertrait_def_ids(tcx, inner_most_trait_ref.def_id)
+                .any(|def_id| has_own_existential_vtable_entries(tcx, def_id));
 
             segment_visitor(VtblSegment::TraitOwnEntries {
                 trait_ref: inner_most_trait_ref,
diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs
index b310db2dac4..4643ced9ad8 100644
--- a/library/std/src/sys/fs/unix.rs
+++ b/library/std/src/sys/fs/unix.rs
@@ -1263,6 +1263,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     ))]
     pub fn lock(&self) -> io::Result<()> {
@@ -1275,6 +1276,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     )))]
     pub fn lock(&self) -> io::Result<()> {
@@ -1286,6 +1288,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     ))]
     pub fn lock_shared(&self) -> io::Result<()> {
@@ -1298,6 +1301,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     )))]
     pub fn lock_shared(&self) -> io::Result<()> {
@@ -1309,6 +1313,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     ))]
     pub fn try_lock(&self) -> Result<(), TryLockError> {
@@ -1329,6 +1334,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     )))]
     pub fn try_lock(&self) -> Result<(), TryLockError> {
@@ -1343,6 +1349,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     ))]
     pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
@@ -1363,6 +1370,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     )))]
     pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
@@ -1377,6 +1385,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     ))]
     pub fn unlock(&self) -> io::Result<()> {
@@ -1389,6 +1398,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     )))]
     pub fn unlock(&self) -> io::Result<()> {
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 59541bf12de..30cbcc05c42 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -1416,8 +1416,8 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect
     if builder.config.llvm_enzyme {
         cargo.env("LLVM_ENZYME", "1");
     }
-    let llvm::LlvmResult { llvm_config, .. } = builder.ensure(llvm::Llvm { target });
-    cargo.env("LLVM_CONFIG", &llvm_config);
+    let llvm::LlvmResult { host_llvm_config, .. } = builder.ensure(llvm::Llvm { target });
+    cargo.env("LLVM_CONFIG", &host_llvm_config);
 
     // Some LLVM linker flags (-L and -l) may be needed to link `rustc_llvm`. Its build script
     // expects these to be passed via the `LLVM_LINKER_FLAGS` env variable, separated by
@@ -2012,14 +2012,52 @@ impl Step for Assemble {
         if builder.config.llvm_enabled(target_compiler.host) {
             trace!("target_compiler.host" = ?target_compiler.host, "LLVM enabled");
 
-            let llvm::LlvmResult { llvm_config, .. } =
-                builder.ensure(llvm::Llvm { target: target_compiler.host });
+            let target = target_compiler.host;
+            let llvm::LlvmResult { host_llvm_config, .. } = builder.ensure(llvm::Llvm { target });
             if !builder.config.dry_run() && builder.config.llvm_tools_enabled {
                 trace!("LLVM tools enabled");
 
-                let llvm_bin_dir =
-                    command(llvm_config).arg("--bindir").run_capture_stdout(builder).stdout();
-                let llvm_bin_dir = Path::new(llvm_bin_dir.trim());
+                let host_llvm_bin_dir = command(&host_llvm_config)
+                    .arg("--bindir")
+                    .run_capture_stdout(builder)
+                    .stdout()
+                    .trim()
+                    .to_string();
+
+                let llvm_bin_dir = if target == builder.host_target {
+                    PathBuf::from(host_llvm_bin_dir)
+                } else {
+                    // If we're cross-compiling, we cannot run the target llvm-config in order to
+                    // figure out where binaries are located. We thus have to guess.
+                    let external_llvm_config = builder
+                        .config
+                        .target_config
+                        .get(&target)
+                        .and_then(|t| t.llvm_config.clone());
+                    if let Some(external_llvm_config) = external_llvm_config {
+                        // If we have an external LLVM, just hope that the bindir is the directory
+                        // where the LLVM config is located
+                        external_llvm_config.parent().unwrap().to_path_buf()
+                    } else {
+                        // If we have built LLVM locally, then take the path of the host bindir
+                        // relative to its output build directory, and then apply it to the target
+                        // LLVM output build directory.
+                        let host_llvm_out = builder.llvm_out(builder.host_target);
+                        let target_llvm_out = builder.llvm_out(target);
+                        if let Ok(relative_path) =
+                            Path::new(&host_llvm_bin_dir).strip_prefix(host_llvm_out)
+                        {
+                            target_llvm_out.join(relative_path)
+                        } else {
+                            // This is the most desperate option, just replace the host target with
+                            // the actual target in the directory path...
+                            PathBuf::from(
+                                host_llvm_bin_dir
+                                    .replace(&*builder.host_target.triple, &target.triple),
+                            )
+                        }
+                    }
+                };
 
                 // Since we've already built the LLVM tools, install them to the sysroot.
                 // This is the equivalent of installing the `llvm-tools-preview` component via
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 4699813abf4..5cfaa6a7c77 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -2176,11 +2176,12 @@ fn maybe_install_llvm(
             builder.install(&llvm_dylib_path, dst_libdir, FileType::NativeLibrary);
         }
         !builder.config.dry_run()
-    } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult { llvm_config, .. }) =
-        llvm::prebuilt_llvm_config(builder, target, true)
+    } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult {
+        host_llvm_config, ..
+    }) = llvm::prebuilt_llvm_config(builder, target, true)
     {
         trace!("LLVM already built, installing LLVM files");
-        let mut cmd = command(llvm_config);
+        let mut cmd = command(host_llvm_config);
         cmd.arg("--libfiles");
         builder.verbose(|| println!("running {cmd:?}"));
         let files = cmd.run_capture_stdout(builder).stdout();
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index b2056f5cf37..8191a77b5c3 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -31,7 +31,7 @@ use crate::{CLang, GitRepo, Kind, trace};
 pub struct LlvmResult {
     /// Path to llvm-config binary.
     /// NB: This is always the host llvm-config!
-    pub llvm_config: PathBuf,
+    pub host_llvm_config: PathBuf,
     /// Path to LLVM cmake directory for the target.
     pub llvm_cmake_dir: PathBuf,
 }
@@ -111,14 +111,14 @@ pub fn prebuilt_llvm_config(
         && let Some(ref s) = config.llvm_config
     {
         check_llvm_version(builder, s);
-        let llvm_config = s.to_path_buf();
-        let mut llvm_cmake_dir = llvm_config.clone();
+        let host_llvm_config = s.to_path_buf();
+        let mut llvm_cmake_dir = host_llvm_config.clone();
         llvm_cmake_dir.pop();
         llvm_cmake_dir.pop();
         llvm_cmake_dir.push("lib");
         llvm_cmake_dir.push("cmake");
         llvm_cmake_dir.push("llvm");
-        return LlvmBuildStatus::AlreadyBuilt(LlvmResult { llvm_config, llvm_cmake_dir });
+        return LlvmBuildStatus::AlreadyBuilt(LlvmResult { host_llvm_config, llvm_cmake_dir });
     }
 
     if handle_submodule_when_needed {
@@ -143,7 +143,7 @@ pub fn prebuilt_llvm_config(
     };
 
     let llvm_cmake_dir = out_dir.join("lib/cmake/llvm");
-    let res = LlvmResult { llvm_config: build_llvm_config, llvm_cmake_dir };
+    let res = LlvmResult { host_llvm_config: build_llvm_config, llvm_cmake_dir };
 
     static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new();
     let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| {
@@ -488,11 +488,11 @@ impl Step for Llvm {
 
         // https://llvm.org/docs/HowToCrossCompileLLVM.html
         if !builder.config.is_host_target(target) {
-            let LlvmResult { llvm_config, .. } =
+            let LlvmResult { host_llvm_config, .. } =
                 builder.ensure(Llvm { target: builder.config.host_target });
             if !builder.config.dry_run() {
                 let llvm_bindir =
-                    command(&llvm_config).arg("--bindir").run_capture_stdout(builder).stdout();
+                    command(&host_llvm_config).arg("--bindir").run_capture_stdout(builder).stdout();
                 let host_bin = Path::new(llvm_bindir.trim());
                 cfg.define(
                     "LLVM_TABLEGEN",
@@ -501,7 +501,7 @@ impl Step for Llvm {
                 // LLVM_NM is required for cross compiling using MSVC
                 cfg.define("LLVM_NM", host_bin.join("llvm-nm").with_extension(EXE_EXTENSION));
             }
-            cfg.define("LLVM_CONFIG_PATH", llvm_config);
+            cfg.define("LLVM_CONFIG_PATH", host_llvm_config);
             if builder.config.llvm_clang {
                 let build_bin =
                     builder.llvm_out(builder.config.host_target).join("build").join("bin");
@@ -543,7 +543,7 @@ impl Step for Llvm {
 
         // Helper to find the name of LLVM's shared library on darwin and linux.
         let find_llvm_lib_name = |extension| {
-            let major = get_llvm_version_major(builder, &res.llvm_config);
+            let major = get_llvm_version_major(builder, &res.host_llvm_config);
             match &llvm_version_suffix {
                 Some(version_suffix) => format!("libLLVM-{major}{version_suffix}.{extension}"),
                 None => format!("libLLVM-{major}.{extension}"),
@@ -929,7 +929,7 @@ impl Step for Enzyme {
         }
         let target = self.target;
 
-        let LlvmResult { llvm_config, .. } = builder.ensure(Llvm { target: self.target });
+        let LlvmResult { host_llvm_config, .. } = builder.ensure(Llvm { target: self.target });
 
         static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new();
         let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| {
@@ -983,7 +983,7 @@ impl Step for Enzyme {
 
         cfg.out_dir(&out_dir)
             .profile(profile)
-            .env("LLVM_CONFIG_REAL", &llvm_config)
+            .env("LLVM_CONFIG_REAL", &host_llvm_config)
             .define("LLVM_ENABLE_ASSERTIONS", "ON")
             .define("ENZYME_EXTERNAL_SHARED_LIB", "ON")
             .define("LLVM_DIR", builder.llvm_out(target));
@@ -1019,13 +1019,13 @@ impl Step for Lld {
         }
         let target = self.target;
 
-        let LlvmResult { llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target });
+        let LlvmResult { host_llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target });
 
         // The `dist` step packages LLD next to LLVM's binaries for download-ci-llvm. The root path
         // we usually expect here is `./build/$triple/ci-llvm/`, with the binaries in its `bin`
         // subfolder. We check if that's the case, and if LLD's binary already exists there next to
         // `llvm-config`: if so, we can use it instead of building LLVM/LLD from source.
-        let ci_llvm_bin = llvm_config.parent().unwrap();
+        let ci_llvm_bin = host_llvm_config.parent().unwrap();
         if ci_llvm_bin.is_dir() && ci_llvm_bin.file_name().unwrap() == "bin" {
             let lld_path = ci_llvm_bin.join(exe("lld", target));
             if lld_path.exists() {
@@ -1108,7 +1108,7 @@ impl Step for Lld {
             // Use the host llvm-tblgen binary.
             cfg.define(
                 "LLVM_TABLEGEN_EXE",
-                llvm_config.with_file_name("llvm-tblgen").with_extension(EXE_EXTENSION),
+                host_llvm_config.with_file_name("llvm-tblgen").with_extension(EXE_EXTENSION),
             );
         }
 
@@ -1149,7 +1149,7 @@ impl Step for Sanitizers {
             return runtimes;
         }
 
-        let LlvmResult { llvm_config, .. } =
+        let LlvmResult { host_llvm_config, .. } =
             builder.ensure(Llvm { target: builder.config.host_target });
 
         static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new();
@@ -1189,7 +1189,7 @@ impl Step for Sanitizers {
         cfg.define("COMPILER_RT_BUILD_XRAY", "OFF");
         cfg.define("COMPILER_RT_DEFAULT_TARGET_ONLY", "ON");
         cfg.define("COMPILER_RT_USE_LIBCXX", "OFF");
-        cfg.define("LLVM_CONFIG_PATH", &llvm_config);
+        cfg.define("LLVM_CONFIG_PATH", &host_llvm_config);
 
         if self.target.contains("ohos") {
             cfg.define("COMPILER_RT_USE_BUILTINS_LIBRARY", "ON");
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 119fa4237bc..9f0d1cc8892 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -1976,12 +1976,14 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         let mut llvm_components_passed = false;
         let mut copts_passed = false;
         if builder.config.llvm_enabled(compiler.host) {
-            let llvm::LlvmResult { llvm_config, .. } =
+            let llvm::LlvmResult { host_llvm_config, .. } =
                 builder.ensure(llvm::Llvm { target: builder.config.host_target });
             if !builder.config.dry_run() {
-                let llvm_version = get_llvm_version(builder, &llvm_config);
-                let llvm_components =
-                    command(&llvm_config).arg("--components").run_capture_stdout(builder).stdout();
+                let llvm_version = get_llvm_version(builder, &host_llvm_config);
+                let llvm_components = command(&host_llvm_config)
+                    .arg("--components")
+                    .run_capture_stdout(builder)
+                    .stdout();
                 // Remove trailing newline from llvm-config output.
                 cmd.arg("--llvm-version")
                     .arg(llvm_version.trim())
@@ -1999,7 +2001,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
             // rustc args as a workaround.
             if !builder.config.dry_run() && suite.ends_with("fulldeps") {
                 let llvm_libdir =
-                    command(&llvm_config).arg("--libdir").run_capture_stdout(builder).stdout();
+                    command(&host_llvm_config).arg("--libdir").run_capture_stdout(builder).stdout();
                 let link_llvm = if target.is_msvc() {
                     format!("-Clink-arg=-LIBPATH:{llvm_libdir}")
                 } else {
@@ -2013,7 +2015,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
                 // tools. Pass the path to run-make tests so they can use them.
                 // (The coverage-run tests also need these tools to process
                 // coverage reports.)
-                let llvm_bin_path = llvm_config
+                let llvm_bin_path = host_llvm_config
                     .parent()
                     .expect("Expected llvm-config to be contained in directory");
                 assert!(llvm_bin_path.is_dir());
diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs
index 0caeb328811..9050f4069e8 100644
--- a/src/bootstrap/src/core/build_steps/vendor.rs
+++ b/src/bootstrap/src/core/build_steps/vendor.rs
@@ -19,6 +19,7 @@ pub const VENDOR_DIR: &str = "vendor";
 pub fn default_paths_to_vendor(builder: &Builder<'_>) -> Vec<(PathBuf, Vec<&'static str>)> {
     [
         ("src/tools/cargo/Cargo.toml", vec!["src/tools/cargo"]),
+        ("src/tools/clippy/clippy_test_deps/Cargo.toml", vec![]),
         ("src/tools/rust-analyzer/Cargo.toml", vec![]),
         ("compiler/rustc_codegen_cranelift/Cargo.toml", vec![]),
         ("compiler/rustc_codegen_gcc/Cargo.toml", vec![]),
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 96289a63785..deee041490b 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -1613,11 +1613,15 @@ You have to build a stage1 compiler for `{}` first, and then use it to build a s
     ///
     /// Note that this returns `None` if LLVM is disabled, or if we're in a
     /// check build or dry-run, where there's no need to build all of LLVM.
+    ///
+    /// FIXME(@kobzol)
+    /// **WARNING**: This actually returns the **HOST** LLVM config, not LLVM config for the given
+    /// *target*.
     pub fn llvm_config(&self, target: TargetSelection) -> Option<PathBuf> {
         if self.config.llvm_enabled(target) && self.kind != Kind::Check && !self.config.dry_run() {
-            let llvm::LlvmResult { llvm_config, .. } = self.ensure(llvm::Llvm { target });
-            if llvm_config.is_file() {
-                return Some(llvm_config);
+            let llvm::LlvmResult { host_llvm_config, .. } = self.ensure(llvm::Llvm { target });
+            if host_llvm_config.is_file() {
+                return Some(host_llvm_config);
             }
         }
         None
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index f012645b7ef..a2412879009 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -494,14 +494,14 @@ fn test_prebuilt_llvm_config_path_resolution() {
         false,
     )
     .llvm_result()
-    .llvm_config
+    .host_llvm_config
     .clone();
     let actual = drop_win_disk_prefix_if_present(actual);
     assert_eq!(expected, actual);
 
     let actual = prebuilt_llvm_config(&builder, builder.config.host_target, false)
         .llvm_result()
-        .llvm_config
+        .host_llvm_config
         .clone();
     let actual = drop_win_disk_prefix_if_present(actual);
     assert_eq!(expected, actual);
@@ -519,7 +519,7 @@ fn test_prebuilt_llvm_config_path_resolution() {
 
     let actual = prebuilt_llvm_config(&builder, builder.config.host_target, false)
         .llvm_result()
-        .llvm_config
+        .host_llvm_config
         .clone();
     let expected = builder
         .out
@@ -542,7 +542,7 @@ fn test_prebuilt_llvm_config_path_resolution() {
 
         let actual = prebuilt_llvm_config(&builder, builder.config.host_target, false)
             .llvm_result()
-            .llvm_config
+            .host_llvm_config
             .clone();
         let expected = builder
             .out
diff --git a/tests/ui/methods/missing-bound-on-tuple.rs b/tests/ui/methods/missing-bound-on-tuple.rs
deleted file mode 100644
index 25deabf5926..00000000000
--- a/tests/ui/methods/missing-bound-on-tuple.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-trait WorksOnDefault {
-    fn do_something() {}
-}
-
-impl<T: Default> WorksOnDefault for T {}
-//~^ NOTE the following trait bounds were not satisfied
-//~| NOTE unsatisfied trait bound introduced here
-
-trait Foo {}
-
-trait WorksOnFoo {
-    fn do_be_do() {}
-}
-
-impl<T: Foo> WorksOnFoo for T {}
-//~^ NOTE the following trait bounds were not satisfied
-//~| NOTE unsatisfied trait bound introduced here
-
-impl<A: Foo, B: Foo, C: Foo> Foo for (A, B, C) {}
-//~^ NOTE `Foo` is implemented for `(i32, u32, String)`
-impl Foo for i32 {}
-impl Foo for &i32 {}
-impl Foo for u32 {}
-impl Foo for String {}
-
-fn main() {
-    let _success = <(i32, u32, String)>::do_something();
-    let _failure = <(i32, &u32, String)>::do_something(); //~ ERROR E0599
-    //~^ NOTE `Default` is implemented for `(i32, u32, String)`
-    //~| NOTE function or associated item cannot be called on
-    let _success = <(i32, u32, String)>::do_be_do();
-    let _failure = <(i32, &u32, String)>::do_be_do(); //~ ERROR E0599
-    //~^ NOTE function or associated item cannot be called on
-    let _success = <(i32, u32, String)>::default();
-    let _failure = <(i32, &u32, String)>::default(); //~ ERROR E0599
-    //~^ NOTE `Default` is implemented for `(i32, u32, String)`
-    //~| NOTE function or associated item cannot be called on
-    //~| NOTE the following trait bounds were not satisfied
-}
diff --git a/tests/ui/methods/missing-bound-on-tuple.stderr b/tests/ui/methods/missing-bound-on-tuple.stderr
deleted file mode 100644
index f3e0897e5e6..00000000000
--- a/tests/ui/methods/missing-bound-on-tuple.stderr
+++ /dev/null
@@ -1,58 +0,0 @@
-error[E0599]: the function or associated item `do_something` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied
-  --> $DIR/missing-bound-on-tuple.rs:28:43
-   |
-LL |     let _failure = <(i32, &u32, String)>::do_something();
-   |                                           ^^^^^^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds
-   |
-note: the following trait bounds were not satisfied:
-      `&(i32, &u32, String): Default`
-      `&mut (i32, &u32, String): Default`
-      `(i32, &u32, String): Default`
-  --> $DIR/missing-bound-on-tuple.rs:5:9
-   |
-LL | impl<T: Default> WorksOnDefault for T {}
-   |         ^^^^^^^  --------------     -
-   |         |
-   |         unsatisfied trait bound introduced here
-note: `Default` is implemented for `(i32, u32, String)` but not for `(i32, &u32, String)`
-  --> $SRC_DIR/core/src/tuple.rs:LL:COL
-   = note: this error originates in the macro `tuple_impls` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0599]: the function or associated item `do_be_do` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied
-  --> $DIR/missing-bound-on-tuple.rs:32:43
-   |
-LL |     let _failure = <(i32, &u32, String)>::do_be_do();
-   |                                           ^^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds
-   |
-note: the following trait bounds were not satisfied:
-      `&(i32, &u32, String): Foo`
-      `&mut (i32, &u32, String): Foo`
-      `(i32, &u32, String): Foo`
-  --> $DIR/missing-bound-on-tuple.rs:15:9
-   |
-LL | impl<T: Foo> WorksOnFoo for T {}
-   |         ^^^  ----------     -
-   |         |
-   |         unsatisfied trait bound introduced here
-note: `Foo` is implemented for `(i32, u32, String)` but not for `(i32, &u32, String)`
-  --> $DIR/missing-bound-on-tuple.rs:19:1
-   |
-LL | impl<A: Foo, B: Foo, C: Foo> Foo for (A, B, C) {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0599]: the function or associated item `default` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied
-  --> $DIR/missing-bound-on-tuple.rs:35:43
-   |
-LL |     let _failure = <(i32, &u32, String)>::default();
-   |                                           ^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds
-   |
-   = note: the following trait bounds were not satisfied:
-           `&u32: Default`
-           which is required by `(i32, &u32, String): Default`
-note: `Default` is implemented for `(i32, u32, String)` but not for `(i32, &u32, String)`
-  --> $SRC_DIR/core/src/tuple.rs:LL:COL
-   = note: this error originates in the macro `tuple_impls` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/methods/tuple-suggestions-issue-142488.rs b/tests/ui/methods/tuple-suggestions-issue-142488.rs
new file mode 100644
index 00000000000..f6c58fce9a1
--- /dev/null
+++ b/tests/ui/methods/tuple-suggestions-issue-142488.rs
@@ -0,0 +1,48 @@
+// Regression test for issue #142488, a diagnostics ICE when trying to suggest missing methods
+// present in similar tuple types.
+// This is a few of the MCVEs from the issues and its many duplicates.
+
+// 1
+fn main() {
+    for a in x {
+        //~^ ERROR: cannot find value `x` in this scope
+        (a,).to_string()
+        //~^ ERROR: the method `to_string` exists for tuple
+    }
+}
+
+// 2
+trait Trait {
+    fn meth(self);
+}
+
+impl<T, U: Trait> Trait for (T, U) {
+    fn meth(self) {}
+}
+
+fn mcve2() {
+    ((), std::collections::HashMap::new()).meth()
+    //~^ ERROR: the method `meth` exists for tuple
+}
+
+// 3
+trait I {}
+
+struct Struct;
+impl I for Struct {}
+
+trait Tr {
+    fn f<A>(self) -> (A,)
+    where
+        Self: Sized,
+    {
+        loop {}
+    }
+}
+
+impl<T> Tr for T where T: I {}
+
+fn mcve3() {
+    Struct.f().f();
+    //~^ ERROR: the method `f` exists for tuple
+}
diff --git a/tests/ui/methods/tuple-suggestions-issue-142488.stderr b/tests/ui/methods/tuple-suggestions-issue-142488.stderr
new file mode 100644
index 00000000000..f9363bb216f
--- /dev/null
+++ b/tests/ui/methods/tuple-suggestions-issue-142488.stderr
@@ -0,0 +1,61 @@
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/tuple-suggestions-issue-142488.rs:7:14
+   |
+LL |     for a in x {
+   |              ^ not found in this scope
+
+error[E0599]: the method `to_string` exists for tuple `(_,)`, but its trait bounds were not satisfied
+  --> $DIR/tuple-suggestions-issue-142488.rs:9:14
+   |
+LL |         (a,).to_string()
+   |              ^^^^^^^^^ method cannot be called on `(_,)` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `(_,): std::fmt::Display`
+           which is required by `(_,): ToString`
+
+error[E0599]: the method `meth` exists for tuple `((), HashMap<_, _>)`, but its trait bounds were not satisfied
+  --> $DIR/tuple-suggestions-issue-142488.rs:24:44
+   |
+LL |     ((), std::collections::HashMap::new()).meth()
+   |                                            ^^^^ method cannot be called on `((), HashMap<_, _>)` due to unsatisfied trait bounds
+   |
+note: trait bound `HashMap<_, _>: Trait` was not satisfied
+  --> $DIR/tuple-suggestions-issue-142488.rs:19:12
+   |
+LL | impl<T, U: Trait> Trait for (T, U) {
+   |            ^^^^^  -----     ------
+   |            |
+   |            unsatisfied trait bound introduced here
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `Trait` defines an item `meth`, perhaps you need to implement it
+  --> $DIR/tuple-suggestions-issue-142488.rs:15:1
+   |
+LL | trait Trait {
+   | ^^^^^^^^^^^
+
+error[E0599]: the method `f` exists for tuple `(_,)`, but its trait bounds were not satisfied
+  --> $DIR/tuple-suggestions-issue-142488.rs:46:16
+   |
+LL |     Struct.f().f();
+   |                ^ method cannot be called on `(_,)` due to unsatisfied trait bounds
+   |
+note: the following trait bounds were not satisfied:
+      `&(_,): I`
+      `&mut (_,): I`
+      `(_,): I`
+  --> $DIR/tuple-suggestions-issue-142488.rs:43:27
+   |
+LL | impl<T> Tr for T where T: I {}
+   |         --     -          ^ unsatisfied trait bound introduced here
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `Tr` defines an item `f`, perhaps you need to implement it
+  --> $DIR/tuple-suggestions-issue-142488.rs:34:1
+   |
+LL | trait Tr {
+   | ^^^^^^^^
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0425, E0599.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.dump.stderr b/tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.dump.stderr
new file mode 100644
index 00000000000..d90a786498e
--- /dev/null
+++ b/tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.dump.stderr
@@ -0,0 +1,16 @@
+error: vtable entries: [
+           MetadataDropInPlace,
+           MetadataSize,
+           MetadataAlign,
+           Method(<dyn OneTwo as One>::one - shim(reify)),
+           Method(<dyn OneTwo as Two>::two - shim(reify)),
+           TraitVPtr(<dyn OneTwo as Two>),
+           TraitVPtr(<dyn OneTwo as TwoAgain>),
+       ]
+  --> $DIR/empty-supertrait-with-nonempty-supersupertrait.rs:40:1
+   |
+LL | type T = dyn OneTwo;
+   | ^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.rs b/tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.rs
new file mode 100644
index 00000000000..507cda63868
--- /dev/null
+++ b/tests/ui/traits/vtable/empty-supertrait-with-nonempty-supersupertrait.rs
@@ -0,0 +1,49 @@
+//@ revisions: run dump
+//@[run] run-pass
+//@[dump] check-fail
+//! Regression test for #145752
+//! Ensure that `OneTwo` contains a vptr for `TwoAgain`
+#![allow(unused)]
+#![cfg_attr(dump, feature(rustc_attrs))]
+
+trait One {
+    fn one(&self) {
+        panic!("don't call this");
+    }
+}
+impl One for () {}
+
+trait Two {
+    fn two(&self) {
+        println!("good");
+    }
+}
+impl Two for () {}
+
+trait TwoAgain: Two {}
+impl<T: Two> TwoAgain for T {}
+
+trait OneTwo: One + TwoAgain {}
+impl<T: One + Two> OneTwo for T {}
+
+fn main() {
+    (&()).two();
+    (&() as &dyn OneTwo).two();
+    (&() as &dyn OneTwo as &dyn Two).two();
+
+    // these two used to panic because they called `one` due to #145752
+    (&() as &dyn OneTwo as &dyn TwoAgain).two();
+    (&() as &dyn OneTwo as &dyn TwoAgain as &dyn Two).two();
+}
+
+#[cfg_attr(dump, rustc_dump_vtable)]
+type T = dyn OneTwo;
+//[dump]~^ ERROR vtable entries: [
+//[dump]~| ERROR            MetadataDropInPlace,
+//[dump]~| ERROR            MetadataSize,
+//[dump]~| ERROR            MetadataAlign,
+//[dump]~| ERROR            Method(<dyn OneTwo as One>::one - shim(reify)),
+//[dump]~| ERROR            Method(<dyn OneTwo as Two>::two - shim(reify)),
+//[dump]~| ERROR            TraitVPtr(<dyn OneTwo as Two>),
+//[dump]~| ERROR            TraitVPtr(<dyn OneTwo as TwoAgain>),
+//[dump]~| ERROR        ]
diff --git a/tests/ui/traits/vtable/multiple-auto.rs b/tests/ui/traits/vtable/multiple-auto.rs
new file mode 100644
index 00000000000..87ee865868b
--- /dev/null
+++ b/tests/ui/traits/vtable/multiple-auto.rs
@@ -0,0 +1,50 @@
+// Related to <https://github.com/rust-lang/rust/issues/113840>
+//
+// This test makes sure that multiple auto traits can reuse the
+// same pointer for upcasting (e.g. `Send`/`Sync`)
+
+#![crate_type = "lib"]
+#![feature(rustc_attrs, auto_traits)]
+
+// Markers
+auto trait M0 {}
+auto trait M1 {}
+auto trait M2 {}
+
+// Just a trait with a method
+trait T {
+    fn method(&self) {}
+}
+
+trait A: M0 + M1 + M2 + T {}
+
+trait B: M0 + M1 + T + M2 {}
+
+trait C: M0 + T + M1 + M2 {}
+
+trait D: T + M0 + M1 + M2 {}
+
+struct S;
+
+impl M0 for S {}
+impl M1 for S {}
+impl M2 for S {}
+impl T for S {}
+
+#[rustc_dump_vtable]
+impl A for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
+impl B for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
+impl C for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
+impl D for S {}
+//~^ ERROR vtable entries
+
+fn main() {}
diff --git a/tests/ui/traits/vtable/multiple-auto.stderr b/tests/ui/traits/vtable/multiple-auto.stderr
new file mode 100644
index 00000000000..0a7c3ebd36d
--- /dev/null
+++ b/tests/ui/traits/vtable/multiple-auto.stderr
@@ -0,0 +1,46 @@
+error: vtable entries: [
+           MetadataDropInPlace,
+           MetadataSize,
+           MetadataAlign,
+           Method(<S as T>::method),
+       ]
+  --> $DIR/multiple-auto.rs:35:1
+   |
+LL | impl A for S {}
+   | ^^^^^^^^^^^^
+
+error: vtable entries: [
+           MetadataDropInPlace,
+           MetadataSize,
+           MetadataAlign,
+           Method(<S as T>::method),
+       ]
+  --> $DIR/multiple-auto.rs:39:1
+   |
+LL | impl B for S {}
+   | ^^^^^^^^^^^^
+
+error: vtable entries: [
+           MetadataDropInPlace,
+           MetadataSize,
+           MetadataAlign,
+           Method(<S as T>::method),
+       ]
+  --> $DIR/multiple-auto.rs:43:1
+   |
+LL | impl C for S {}
+   | ^^^^^^^^^^^^
+
+error: vtable entries: [
+           MetadataDropInPlace,
+           MetadataSize,
+           MetadataAlign,
+           Method(<S as T>::method),
+       ]
+  --> $DIR/multiple-auto.rs:47:1
+   |
+LL | impl D for S {}
+   | ^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+