From 89d50591c06f084b80a5ce527781e07f8dc32be6 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Fri, 21 Nov 2025 00:14:03 -0800 Subject: [PATCH 1/6] Replace the first of 4 binary invocations for offload --- compiler/rustc_codegen_llvm/src/back/write.rs | 7 +++ compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 3 ++ .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 47 +++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index fde7dd6ef7a85..78b11c458d5aa 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -765,6 +765,13 @@ pub(crate) unsafe fn llvm_optimize( llvm_plugins.len(), ) }; + + if cgcx.target_is_like_gpu && config.offload.contains(&config::Offload::Enable) { + unsafe { + llvm::LLVMRustBundleImages(module.module_llvm.llmod(), module.module_llvm.tm.raw()); + } + } + result.into_result().unwrap_or_else(|()| llvm_err(dcx, LlvmError::RunLlvmPasses)) } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index ca64d96c2a33c..34f0e4b953381 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1641,6 +1641,9 @@ unsafe extern "C" { Name: *const c_char, ) -> &'a Value; + /// Processes the module and writes it in an offload compatible way into a "host.out" file. + pub(crate) fn LLVMRustBundleImages<'a>(M: &'a Module, TM: &'a TargetMachine) -> bool; + /// Writes a module to the specified path. Returns 0 on success. pub(crate) fn LLVMWriteBitcodeToFile(M: &Module, Path: *const c_char) -> c_int; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 8823c83922822..ba17aef92d0d5 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -25,6 +25,7 @@ #include "llvm/IR/Module.h" #include "llvm/IR/Value.h" #include "llvm/Object/COFFImportFile.h" +#include "llvm/Object/OffloadBinary.h" #include "llvm/Remarks/RemarkFormat.h" #include "llvm/Remarks/RemarkSerializer.h" #include "llvm/Remarks/RemarkStreamer.h" @@ -35,6 +36,7 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/Timer.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/ValueMapper.h" #include @@ -144,6 +146,51 @@ extern "C" void LLVMRustPrintStatistics(RustStringRef OutBuf) { llvm::PrintStatistics(OS); } +static Error writeFile(StringRef Filename, StringRef Data) { + Expected> OutputOrErr = + FileOutputBuffer::create(Filename, Data.size()); + if (!OutputOrErr) + return OutputOrErr.takeError(); + std::unique_ptr Output = std::move(*OutputOrErr); + llvm::copy(Data, Output->getBufferStart()); + if (Error E = Output->commit()) + return E; + return Error::success(); +} + +// This is the first of many steps in creating a binary using llvm offload, +// to run code on the gpu. Concrete, it replaces the following binary use: +// clang-offload-packager -o host.out +// --image=file=device.bc,triple=amdgcn-amd-amdhsa,arch=gfx90a,kind=openmp +// The input module is the rust code compiled for a gpu target like amdgpu. +// Based on clang/tools/clang-offload-packager/ClangOffloadPackager.cpp +extern "C" bool LLVMRustBundleImages(LLVMModuleRef M, TargetMachine &TM) { + std::string Storage; + llvm::raw_string_ostream OS1(Storage); + llvm::WriteBitcodeToFile(*unwrap(M), OS1); + OS1.flush(); + auto MB = llvm::MemoryBuffer::getMemBufferCopy(Storage, "module.bc"); + + SmallVector BinaryData; + raw_svector_ostream OS2(BinaryData); + + OffloadBinary::OffloadingImage ImageBinary{}; + ImageBinary.TheImageKind = object::IMG_Bitcode; + ImageBinary.Image = std::move(MB); + ImageBinary.TheOffloadKind = object::OFK_OpenMP; + ImageBinary.StringData["triple"] = TM.getTargetTriple().str(); + ImageBinary.StringData["arch"] = TM.getTargetCPU(); + llvm::SmallString<0> Buffer = OffloadBinary::write(ImageBinary); + if (Buffer.size() % OffloadBinary::getAlignment() != 0) + // Offload binary has invalid size alignment + return false; + OS2 << Buffer; + if (Error E = writeFile("host.out", + StringRef(BinaryData.begin(), BinaryData.size()))) + return false; + return true; +} + extern "C" void LLVMRustOffloadMapper(LLVMValueRef OldFn, LLVMValueRef NewFn) { llvm::Function *oldFn = llvm::unwrap(OldFn); llvm::Function *newFn = llvm::unwrap(NewFn); From 88ca3bc7322d8b0c8738da0dec9bc2f5502d2643 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Fri, 21 Nov 2025 01:47:47 -0800 Subject: [PATCH 2/6] update dev guide --- src/doc/rustc-dev-guide/src/offload/usage.md | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/offload/usage.md b/src/doc/rustc-dev-guide/src/offload/usage.md index 7abf90aa6e0b6..8350fb5777fba 100644 --- a/src/doc/rustc-dev-guide/src/offload/usage.md +++ b/src/doc/rustc-dev-guide/src/offload/usage.md @@ -79,19 +79,8 @@ Now we generate the device code. Replace the target-cpu with the right code for RUSTFLAGS="-Ctarget-cpu=gfx90a --emit=llvm-bc,llvm-ir -Zoffload=Enable -Zunstable-options" cargo +offload build -Zunstable-options -r -v --target amdgcn-amd-amdhsa -Zbuild-std=core ``` -Now find the `.ll` under target/amdgcn-amd-amdhsa folder and copy it to a device.ll file (or adjust the file names below). -If you work on an NVIDIA or Intel gpu, please adjust the names acordingly and open an issue to share your results (either if you succeed or fail). -First we compile our .ll files (good for manual inspections) to .bc files and clean up leftover artifacts. The cleanup is important, otherwise caching might interfere on following runs. -``` -opt lib.ll -o lib.bc -opt device.ll -o device.bc -rm *.o -rm bare.amdgcn.gfx90a.img* -``` ``` -"clang-offload-packager" "-o" "host.out" "--image=file=device.bc,triple=amdgcn-amd-amdhsa,arch=gfx90a,kind=openmp" - "clang-21" "-cc1" "-triple" "x86_64-unknown-linux-gnu" "-S" "-save-temps=cwd" "-disable-free" "-clear-ast-before-backend" "-main-file-name" "lib.rs" "-mrelocation-model" "pic" "-pic-level" "2" "-pic-is-pie" "-mframe-pointer=all" "-fmath-errno" "-ffp-contract=on" "-fno-rounding-math" "-mconstructor-aliases" "-funwind-tables=2" "-target-cpu" "x86-64" "-tune-cpu" "generic" "-resource-dir" "//rust/build/x86_64-unknown-linux-gnu/llvm/lib/clang/21" "-ferror-limit" "19" "-fopenmp" "-fopenmp-offload-mandatory" "-fgnuc-version=4.2.1" "-fskip-odr-check-in-gmf" "-fembed-offload-object=host.out" "-fopenmp-targets=amdgcn-amd-amdhsa" "-faddrsig" "-D__GCC_HAVE_DWARF2_CFI_ASM=1" "-o" "host.s" "-x" "ir" "lib.bc" "clang-21" "-cc1as" "-triple" "x86_64-unknown-linux-gnu" "-filetype" "obj" "-main-file-name" "lib.rs" "-target-cpu" "x86-64" "-mrelocation-model" "pic" "-o" "host.o" "host.s" @@ -99,7 +88,8 @@ rm bare.amdgcn.gfx90a.img* "clang-linker-wrapper" "--should-extract=gfx90a" "--device-compiler=amdgcn-amd-amdhsa=-g" "--device-compiler=amdgcn-amd-amdhsa=-save-temps=cwd" "--device-linker=amdgcn-amd-amdhsa=-lompdevice" "--host-triple=x86_64-unknown-linux-gnu" "--save-temps" "--linker-path=/ABSOlUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/lld/bin/ld.lld" "--hash-style=gnu" "--eh-frame-hdr" "-m" "elf_x86_64" "-pie" "-dynamic-linker" "/lib64/ld-linux-x86-64.so.2" "-o" "bare" "/lib/../lib64/Scrt1.o" "/lib/../lib64/crti.o" "/ABSOLUTE_PATH_TO/crtbeginS.o" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/bin/../lib/x86_64-unknown-linux-gnu" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/lib/clang/21/lib/x86_64-unknown-linux-gnu" "-L/lib/../lib64" "-L/usr/lib64" "-L/lib" "-L/usr/lib" "host.o" "-lstdc++" "-lm" "-lomp" "-lomptarget" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/lib" "-lgcc_s" "-lgcc" "-lpthread" "-lc" "-lgcc_s" "-lgcc" "/ABSOLUTE_PATH_TO/crtendS.o" "/lib/../lib64/crtn.o" ``` -Especially for the last command I recommend to not fix the paths, but rather just re-generate them by copying a bare-mode openmp example and compiling it with your clang. By adding `-###` to your clang invocation, you can see the invidual steps. +Especially for the last three commands I recommend to not fix the paths, but rather just re-generate them by copying a bare-mode openmp example and compiling it with your clang. By adding `-###` to your clang invocation, you can see the invidual steps. +You can ignore other steps, e.g. the invocation of a "clang-offload-packager". ``` myclang++ -fuse-ld=lld -O3 -fopenmp -fopenmp-offload-mandatory --offload-arch=gfx90a omp_bare.cpp -o main -### ``` From d340ea520b8981f088c7930821dc2b4a80c202f3 Mon Sep 17 00:00:00 2001 From: lapla-cogito Date: Fri, 21 Nov 2025 14:04:06 +0900 Subject: [PATCH 3/6] Fix ICE when collecting opaques from trait method declarations --- compiler/rustc_ty_utils/src/opaque_types.rs | 5 ++- .../ice-148622-opaque-as-const-generics.rs | 12 +++++++ ...ice-148622-opaque-as-const-generics.stderr | 31 +++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 tests/ui/impl-trait/ice-148622-opaque-as-const-generics.rs create mode 100644 tests/ui/impl-trait/ice-148622-opaque-as-const-generics.stderr diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 4dd45a09a4df3..445021801beff 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -64,7 +64,10 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { #[instrument(level = "trace", skip(self))] fn collect_taits_declared_in_body(&mut self) { - let body = self.tcx.hir_body_owned_by(self.item).value; + let Some(body) = self.tcx.hir_maybe_body_owned_by(self.item) else { + return; + }; + let body = body.value; struct TaitInBodyFinder<'a, 'tcx> { collector: &'a mut OpaqueTypeCollector<'tcx>, } diff --git a/tests/ui/impl-trait/ice-148622-opaque-as-const-generics.rs b/tests/ui/impl-trait/ice-148622-opaque-as-const-generics.rs new file mode 100644 index 0000000000000..03741dca32978 --- /dev/null +++ b/tests/ui/impl-trait/ice-148622-opaque-as-const-generics.rs @@ -0,0 +1,12 @@ +#![feature(type_alias_impl_trait)] + +pub type Opaque = impl std::future::Future; +//~^ ERROR: unconstrained opaque type + +trait Foo { + //~^ ERROR: `Opaque` is forbidden as the type of a const generic parameter + fn bar(&self) -> [u8; N]; + //~^ ERROR: the constant `N` is not of type `usize` +} + +fn main() {} diff --git a/tests/ui/impl-trait/ice-148622-opaque-as-const-generics.stderr b/tests/ui/impl-trait/ice-148622-opaque-as-const-generics.stderr new file mode 100644 index 0000000000000..bc76c6fe85e74 --- /dev/null +++ b/tests/ui/impl-trait/ice-148622-opaque-as-const-generics.stderr @@ -0,0 +1,31 @@ +error: `Opaque` is forbidden as the type of a const generic parameter + --> $DIR/ice-148622-opaque-as-const-generics.rs:6:20 + | +LL | trait Foo { + | ^^^^^^ + | + = note: the only supported types are integers, `bool`, and `char` + +error: the constant `N` is not of type `usize` + --> $DIR/ice-148622-opaque-as-const-generics.rs:8:22 + | +LL | fn bar(&self) -> [u8; N]; + | ^^^^^^^ expected `usize`, found future + | +note: this item must have a `#[define_opaque(Opaque)]` attribute to be able to define hidden types + --> $DIR/ice-148622-opaque-as-const-generics.rs:8:8 + | +LL | fn bar(&self) -> [u8; N]; + | ^^^ + = note: the length of array `[u8; N]` must be type `usize` + +error: unconstrained opaque type + --> $DIR/ice-148622-opaque-as-const-generics.rs:3:19 + | +LL | pub type Opaque = impl std::future::Future; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `Opaque` must be used in combination with a concrete type within the same crate + +error: aborting due to 3 previous errors + From 3ad82500ba53c5ad03695e5c57f3a77b3098bfeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Wed, 1 Oct 2025 14:54:21 +0200 Subject: [PATCH 4/6] Add `rust-mingw` component for `*-windows-gnullvm` hosts --- .../src/spec/base/windows_gnullvm.rs | 16 ++++--- .../targets/aarch64_pc_windows_gnullvm.rs | 3 +- .../spec/targets/x86_64_pc_windows_gnullvm.rs | 1 + src/bootstrap/src/core/build_steps/compile.rs | 2 +- src/bootstrap/src/core/build_steps/dist.rs | 48 ++++++++++++++++++- .../src/core/config/target_selection.rs | 4 ++ src/tools/build-manifest/src/main.rs | 2 +- 7 files changed, 65 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs index 58aff198a6601..3bd8ebd0ed3d5 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs @@ -1,8 +1,9 @@ use std::borrow::Cow; +use crate::spec::crt_objects::pre_mingw_self_contained; use crate::spec::{ - Abi, BinaryFormat, Cc, DebuginfoKind, Env, LinkerFlavor, Lld, Os, SplitDebuginfo, - TargetOptions, cvs, + Abi, BinaryFormat, Cc, DebuginfoKind, Env, LinkSelfContainedDefault, LinkerFlavor, Lld, Os, + SplitDebuginfo, TargetOptions, add_link_args, cvs, }; pub(crate) fn opts() -> TargetOptions { @@ -15,10 +16,11 @@ pub(crate) fn opts() -> TargetOptions { &["-nolibc", "--unwindlib=none"], ); // Order of `late_link_args*` does not matter with LLD. - let late_link_args = TargetOptions::link_args( - LinkerFlavor::Gnu(Cc::Yes, Lld::No), - &["-lmingw32", "-lmingwex", "-lmsvcrt", "-lkernel32", "-luser32"], - ); + let mingw_libs = &["-lmingw32", "-lmingwex", "-lmsvcrt", "-lkernel32", "-luser32"]; + + let mut late_link_args = + TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), mingw_libs); + add_link_args(&mut late_link_args, LinkerFlavor::Gnu(Cc::Yes, Lld::No), mingw_libs); TargetOptions { os: Os::Windows, @@ -36,6 +38,8 @@ pub(crate) fn opts() -> TargetOptions { binary_format: BinaryFormat::Coff, allows_weak_linkage: false, pre_link_args, + pre_link_objects_self_contained: pre_mingw_self_contained(), + link_self_contained: LinkSelfContainedDefault::InferredForMingw, late_link_args, abi_return_struct_as_int: true, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs index 9b7db11e2f29a..b6f82e5ccbf40 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs @@ -1,10 +1,11 @@ -use crate::spec::{Arch, FramePointer, Target, TargetMetadata, base}; +use crate::spec::{Arch, Cc, FramePointer, LinkerFlavor, Lld, Target, TargetMetadata, base}; pub(crate) fn target() -> Target { let mut base = base::windows_gnullvm::opts(); base.max_atomic_width = Some(128); base.features = "+v8a,+neon,+fp-armv8".into(); base.linker = Some("aarch64-w64-mingw32-clang".into()); + base.add_pre_link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), &["-m", "arm64pe"]); // Microsoft recommends enabling frame pointers on Arm64 Windows. // From https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#integer-registers diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs index 28c9e6251255c..938f1e49f1ef7 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs @@ -6,6 +6,7 @@ pub(crate) fn target() -> Target { base.features = "+cx16,+sse3,+sahf".into(); base.plt_by_default = false; base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); + base.add_pre_link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), &["-m", "i386pep"]); base.max_atomic_width = Some(128); base.linker = Some("x86_64-w64-mingw32-clang".into()); diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 6857a40ada81b..a6704a5675a12 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -448,7 +448,7 @@ fn copy_self_contained_objects( DependencyType::TargetSelfContained, ); } - } else if target.is_windows_gnu() { + } else if target.is_windows_gnu() || target.is_windows_gnullvm() { for obj in ["crt2.o", "dllcrt2.o"].iter() { let src = compiler_file(builder, &builder.cc(target), target, CLang::C, obj); let dst = libdir_self_contained.join(obj); diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 411d42962644d..8bdabb45f0b6c 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -295,6 +295,44 @@ fn make_win_dist(plat_root: &Path, target: TargetSelection, builder: &Builder<'_ } } +fn make_win_llvm_dist(plat_root: &Path, target: TargetSelection, builder: &Builder<'_>) { + if builder.config.dry_run() { + return; + } + + let (_, lib_path) = get_cc_search_dirs(target, builder); + + // Libraries necessary to link the windows-gnullvm toolchains. + // System libraries will be preferred if they are available (see #67429). + let target_libs = [ + // MinGW libs + "libunwind.a", + "libunwind.dll.a", + "libmingw32.a", + "libmingwex.a", + "libmsvcrt.a", + // Windows import libs, remove them once std transitions to raw-dylib + "libkernel32.a", + "libuser32.a", + "libntdll.a", + "libuserenv.a", + "libws2_32.a", + "libdbghelp.a", + ]; + + //Find mingw artifacts we want to bundle + let target_libs = find_files(&target_libs, &lib_path); + + //Copy platform libs to platform-specific lib directory + let plat_target_lib_self_contained_dir = + plat_root.join("lib/rustlib").join(target).join("lib/self-contained"); + fs::create_dir_all(&plat_target_lib_self_contained_dir) + .expect("creating plat_target_lib_self_contained_dir failed"); + for src in target_libs { + builder.copy_link_to_folder(&src, &plat_target_lib_self_contained_dir); + } +} + fn runtime_dll_dist(rust_root: &Path, target: TargetSelection, builder: &Builder<'_>) { if builder.config.dry_run() { return; @@ -394,14 +432,20 @@ impl Step for Mingw { fn run(self, builder: &Builder<'_>) -> Option { let target = self.target; - if !target.ends_with("pc-windows-gnu") || !builder.config.dist_include_mingw_linker { + if !target.contains("pc-windows-gnu") || !builder.config.dist_include_mingw_linker { return None; } let mut tarball = Tarball::new(builder, "rust-mingw", &target.triple); tarball.set_product_name("Rust MinGW"); - make_win_dist(tarball.image_dir(), target, builder); + if target.ends_with("pc-windows-gnu") { + make_win_dist(tarball.image_dir(), target, builder); + } else if target.ends_with("pc-windows-gnullvm") { + make_win_llvm_dist(tarball.image_dir(), target, builder); + } else { + unreachable!(); + } Some(tarball.generate()) } diff --git a/src/bootstrap/src/core/config/target_selection.rs b/src/bootstrap/src/core/config/target_selection.rs index 40b63a7f9c752..47f6d6f386dfb 100644 --- a/src/bootstrap/src/core/config/target_selection.rs +++ b/src/bootstrap/src/core/config/target_selection.rs @@ -86,6 +86,10 @@ impl TargetSelection { self.ends_with("windows-gnu") } + pub fn is_windows_gnullvm(&self) -> bool { + self.ends_with("windows-gnullvm") + } + pub fn is_cygwin(&self) -> bool { self.is_windows() && // ref. https://cygwin.com/pipermail/cygwin/2022-February/250802.html diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 9bae8b241a941..4ffd17ae52189 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -476,7 +476,7 @@ impl Builder { } // so is rust-mingw if it's available for the target PkgType::RustMingw => { - if host.ends_with("pc-windows-gnu") { + if host.contains("pc-windows-gnu") { components.push(host_component(pkg)); } } From f580357863c1689ea1903b9570092a53f85a5c44 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 21 Nov 2025 11:43:53 -0500 Subject: [PATCH 5/6] Handle cycles when checking impl candidates for `doc(hidden)` Fixes https://github.com/rust-lang/rust/issues/149092 --- .../traits/fulfillment_errors.rs | 13 +++++++--- compiler/rustc_trait_selection/src/lib.rs | 1 + .../ui/suggestions/auxiliary/hidden-struct.rs | 3 +++ .../dont-suggest-foreign-doc-hidden.rs | 5 ++++ .../dont-suggest-foreign-doc-hidden.stderr | 26 +++++++++++++++++-- 5 files changed, 43 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index d2f2c92dda080..0f5607dd7fecb 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1,12 +1,13 @@ // ignore-tidy-filelength use core::ops::ControlFlow; use std::borrow::Cow; +use std::collections::hash_set; use std::path::PathBuf; use rustc_abi::ExternAbi; use rustc_ast::ast::LitKind; use rustc_ast::{LitIntType, TraitObjectSyntax}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::{ @@ -1956,11 +1957,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if self.tcx.visibility(did).is_accessible_from(body_def_id, self.tcx) { // don't suggest foreign `#[doc(hidden)]` types if !did.is_local() { - while let Some(parent) = parent_map.get(&did) { + let mut previously_seen_dids: FxHashSet = Default::default(); + previously_seen_dids.insert(did); + while let Some(&parent) = parent_map.get(&did) + && let hash_set::Entry::Vacant(v) = + previously_seen_dids.entry(parent) + { if self.tcx.is_doc_hidden(did) { return false; } - did = *parent; + v.insert(); + did = parent; } } true diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index c5dfaa2a60d87..0184b2ccde784 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -17,6 +17,7 @@ #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(default_field_values)] +#![feature(hash_set_entry)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(iterator_try_reduce)] diff --git a/tests/ui/suggestions/auxiliary/hidden-struct.rs b/tests/ui/suggestions/auxiliary/hidden-struct.rs index 1f495a9f2224a..ee24389bebd7c 100644 --- a/tests/ui/suggestions/auxiliary/hidden-struct.rs +++ b/tests/ui/suggestions/auxiliary/hidden-struct.rs @@ -33,3 +33,6 @@ impl Marker for hidden::Foo {} impl Marker for hidden1::Bar {} impl Marker for Baz {} impl Marker for Quux {} + + +pub use crate as library; diff --git a/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.rs b/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.rs index a83e496f2703d..0716e4e2e143b 100644 --- a/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.rs +++ b/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.rs @@ -21,7 +21,12 @@ pub fn test4(_: Quux) {} fn test5() {} +fn test6() {} + fn main() { test5::(); //~^ ERROR [E0277] + + test6::(); + //~^ ERROR [E0277] } diff --git a/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.stderr b/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.stderr index e0444c93eeece..a111d0e5aa95a 100644 --- a/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.stderr +++ b/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.stderr @@ -38,7 +38,7 @@ LL + use hidden_struct::Quux; | error[E0277]: the trait bound `i32: Marker` is not satisfied - --> $DIR/dont-suggest-foreign-doc-hidden.rs:25:13 + --> $DIR/dont-suggest-foreign-doc-hidden.rs:27:13 | LL | test5::(); | ^^^ the trait `Marker` is not implemented for `i32` @@ -59,7 +59,29 @@ note: required by a bound in `test5` LL | fn test5() {} | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test5` -error: aborting due to 5 previous errors +error[E0277]: the trait bound `i32: Marker` is not satisfied + --> $DIR/dont-suggest-foreign-doc-hidden.rs:30:13 + | +LL | test6::(); + | ^^^ the trait `Marker` is not implemented for `i32` + | +help: the following other types implement trait `Marker` + --> $DIR/auxiliary/hidden-struct.rs:31:1 + | +LL | impl Marker for Option {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Option` +... +LL | impl Marker for Baz {} + | ^^^^^^^^^^^^^^^^^^^ `Baz` +LL | impl Marker for Quux {} + | ^^^^^^^^^^^^^^^^^^^^ `Quux` +note: required by a bound in `test6` + --> $DIR/dont-suggest-foreign-doc-hidden.rs:24:13 + | +LL | fn test6() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test6` + +error: aborting due to 6 previous errors Some errors have detailed explanations: E0277, E0412. For more information about an error, try `rustc --explain E0277`. From 3386da8f6fd77206acfa135c99727395a427bd2e Mon Sep 17 00:00:00 2001 From: chiri Date: Fri, 21 Nov 2025 22:52:19 +0300 Subject: [PATCH 6/6] Move safe computation out of unsafe block --- library/alloc/src/collections/vec_deque/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 52e079d3ae8e6..ea9d5b128ebe4 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2479,11 +2479,11 @@ impl VecDeque { let other_len = len - at; let mut other = VecDeque::with_capacity_in(other_len, self.allocator().clone()); - unsafe { - let (first_half, second_half) = self.as_slices(); + let (first_half, second_half) = self.as_slices(); + let first_len = first_half.len(); + let second_len = second_half.len(); - let first_len = first_half.len(); - let second_len = second_half.len(); + unsafe { if at < first_len { // `at` lies in the first half. let amount_in_first = first_len - at;