From 0dfdb6c3da4698357b9895625dc743f9f2ff8e67 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Mon, 17 Nov 2025 01:50:10 -0500 Subject: [PATCH 01/13] rlib handling --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 14 ++++++++++++-- .../rustc_mir_transform/src/cross_crate_inline.rs | 8 ++++++++ .../rustc_monomorphize/src/collector/autodiff.rs | 2 ++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 84fc6ebbc3172..029c43e0ba82e 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -15,6 +15,7 @@ use rustc_middle::mir::BinOp; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, GenericArgsRef, Instance, SimdAlign, Ty, TyCtxt, TypingEnv}; use rustc_middle::{bug, span_bug}; +use rustc_session::config::CrateType; use rustc_span::{Span, Symbol, sym}; use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate}; use rustc_target::callconv::PassMode; @@ -1136,8 +1137,17 @@ fn codegen_autodiff<'ll, 'tcx>( if !tcx.sess.opts.unstable_opts.autodiff.contains(&rustc_session::config::AutoDiff::Enable) { let _ = tcx.dcx().emit_almost_fatal(AutoDiffWithoutEnable); } - if tcx.sess.lto() != rustc_session::config::Lto::Fat { - let _ = tcx.dcx().emit_almost_fatal(AutoDiffWithoutLto); + + let ct = tcx.crate_types(); + let lto = tcx.sess.lto(); + if ct.len() == 1 && ct.contains(&CrateType::Executable) { + if lto != rustc_session::config::Lto::Fat { + let _ = tcx.dcx().emit_almost_fatal(AutoDiffWithoutLto); + } + } else { + if lto != rustc_session::config::Lto::Fat && !tcx.sess.opts.cg.linker_plugin_lto.enabled() { + let _ = tcx.dcx().emit_almost_fatal(AutoDiffWithoutLto); + } } let fn_args = instance.args; diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs index 7fc9fb9cca2d7..69248cf91f241 100644 --- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs +++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs @@ -34,6 +34,14 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { return true; } + // FIXME(autodiff): replace this as per discussion in https://github.com/rust-lang/rust/pull/149033#discussion_r2535465880 + if tcx.has_attr(def_id, sym::autodiff_forward) + || tcx.has_attr(def_id, sym::autodiff_reverse) + || tcx.has_attr(def_id, sym::rustc_autodiff) + { + return true; + } + if tcx.has_attr(def_id, sym::rustc_intrinsic) { // Intrinsic fallback bodies are always cross-crate inlineable. // To ensure that the MIR inliner doesn't cluelessly try to inline fallback diff --git a/compiler/rustc_monomorphize/src/collector/autodiff.rs b/compiler/rustc_monomorphize/src/collector/autodiff.rs index 13868cca944a2..e3646596e75e6 100644 --- a/compiler/rustc_monomorphize/src/collector/autodiff.rs +++ b/compiler/rustc_monomorphize/src/collector/autodiff.rs @@ -7,6 +7,8 @@ use crate::collector::{MonoItems, create_fn_mono_item}; // mono so this does not interfere in `autodiff` intrinsics // codegen process. If they are unused, LLVM will remove them when // compiling with O3. +// FIXME(autodiff): Remove this whole file, as per discussion in +// https://github.com/rust-lang/rust/pull/149033#discussion_r2535465880 pub(crate) fn collect_autodiff_fn<'tcx>( tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>, From 2d1fc63101b9689472568a91188034fb62345f30 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Tue, 18 Nov 2025 23:37:30 -0500 Subject: [PATCH 02/13] adding a working rlib autodiff test --- tests/run-make/autodiff/rlib/dep.rs | 7 +++ tests/run-make/autodiff/rlib/lib.rs | 13 ++++++ tests/run-make/autodiff/rlib/main.rs | 8 ++++ tests/run-make/autodiff/rlib/rmake.rs | 66 +++++++++++++++++++++++++++ 4 files changed, 94 insertions(+) create mode 100644 tests/run-make/autodiff/rlib/dep.rs create mode 100644 tests/run-make/autodiff/rlib/lib.rs create mode 100644 tests/run-make/autodiff/rlib/main.rs create mode 100644 tests/run-make/autodiff/rlib/rmake.rs diff --git a/tests/run-make/autodiff/rlib/dep.rs b/tests/run-make/autodiff/rlib/dep.rs new file mode 100644 index 0000000000000..6fc9b2c2473f4 --- /dev/null +++ b/tests/run-make/autodiff/rlib/dep.rs @@ -0,0 +1,7 @@ +pub fn f(x: f64, y: f64) -> f64 { + 2.0 * x + y +} + +pub fn g(x: f64) -> f64 { + 2.0 * x +} diff --git a/tests/run-make/autodiff/rlib/lib.rs b/tests/run-make/autodiff/rlib/lib.rs new file mode 100644 index 0000000000000..b459fed643a1c --- /dev/null +++ b/tests/run-make/autodiff/rlib/lib.rs @@ -0,0 +1,13 @@ +#![feature(autodiff)] +extern crate simple_dep; +use std::autodiff::*; + +#[inline(never)] +pub fn f2(x: f64) -> f64 { + x.sin() +} + +#[autodiff_forward(df1_lib, Dual, Dual)] +pub fn _f1(x: f64) -> f64 { + simple_dep::f(x, x) * f2(x) +} diff --git a/tests/run-make/autodiff/rlib/main.rs b/tests/run-make/autodiff/rlib/main.rs new file mode 100644 index 0000000000000..a3e5fcde0381b --- /dev/null +++ b/tests/run-make/autodiff/rlib/main.rs @@ -0,0 +1,8 @@ +extern crate foo; + +fn main() { + //dbg!("Running main.rs"); + let enzyme_y1_lib = foo::df1_lib(1.5, 1.0); + println!("output1: {:?}", enzyme_y1_lib.0); + println!("output2: {:?}", enzyme_y1_lib.1); +} diff --git a/tests/run-make/autodiff/rlib/rmake.rs b/tests/run-make/autodiff/rlib/rmake.rs new file mode 100644 index 0000000000000..59eaa836864c7 --- /dev/null +++ b/tests/run-make/autodiff/rlib/rmake.rs @@ -0,0 +1,66 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use run_make_support::{cwd, run, rustc}; + +fn main() { + // Build the dependency crate. + rustc() + .input("dep.rs") + .arg("-Zautodiff=Enable") + .arg("--edition=2024") + .arg("-Copt-level=3") + .arg("--crate-name=simple_dep") + .arg("-Clinker-plugin-lto") + .arg("--crate-type=lib") + .emit("dep-info,metadata,link") + .run(); + + let cwd = cwd(); + let cwd_str = cwd.to_string_lossy(); + + let mydep = format!("-Ldependency={cwd_str}"); + + let simple_dep_rlib = + format!("--extern=simple_dep={}", cwd.join("libsimple_dep.rlib").to_string_lossy()); + + // Build the main library that depends on `simple_dep`. + rustc() + .input("lib.rs") + .arg("-Zautodiff=Enable") + .arg("--edition=2024") + .arg("-Copt-level=3") + .arg("--crate-name=foo") + .arg("-Clinker-plugin-lto") + .arg("--crate-type=lib") + .emit("dep-info,metadata,link") + .arg(&mydep) + .arg(&simple_dep_rlib) + .run(); + + let foo_rlib = format!("--extern=foo={}", cwd.join("libfoo.rlib").to_string_lossy()); + + // Build the final binary linking both rlibs. + rustc() + .input("main.rs") + .arg("-Zautodiff=Enable") + .arg("--edition=2024") + .arg("-Copt-level=3") + .arg("--crate-name=foo") + .arg("-Clto=fat") + .arg("--crate-type=bin") + .emit("dep-info,link") + .arg(&mydep) + .arg(&foo_rlib) + .arg(&simple_dep_rlib) + .run(); + + // Run the binary and check its output. + let binary = run("foo"); + assert!(binary.status().success(), "binary failed to run"); + + let binary_out = binary.stdout(); + let output = String::from_utf8_lossy(&binary_out); + assert!(output.contains("output1: 4.488727439718245")); + assert!(output.contains("output2: 3.3108023673168265")); +} From 9f49ac385aa0974eaa36c74c31e0f0b6b2253d99 Mon Sep 17 00:00:00 2001 From: Ximon Eighteen <3304436+ximon18@users.noreply.github.com> Date: Wed, 19 Nov 2025 11:03:00 +0100 Subject: [PATCH 03/13] Add missing trailing period to RustDoc for fn create_dir(). --- library/std/src/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index b548eb4939d42..8b3e943b4ccd0 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2918,7 +2918,7 @@ pub fn canonicalize>(path: P) -> io::Result { fs_imp::canonicalize(path.as_ref()) } -/// Creates a new, empty directory at the provided path +/// Creates a new, empty directory at the provided path. /// /// # Platform-specific behavior /// From 8c4e3ff0a6f056345196dffc81795927e947b3f9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 19 Nov 2025 14:20:00 -0600 Subject: [PATCH 04/13] fs: Update skipped file lock tests to match flock support The list of platforms for which file locks are tested is smaller than the list of platforms that support it. Synchronize these here. Link: https://github.com/rust-lang/rust/blob/07bdbaedc63094281483c40a88a1a8f2f8ffadc5/library/std/src/sys/fs/unix.rs#L1291-L1308 --- library/std/src/fs/tests.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 9fd87e119906e..294de60f7d43e 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -224,11 +224,15 @@ fn file_test_io_seek_and_write() { #[test] #[cfg(any( windows, + target_os = "aix", + target_os = "cygwin", target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", target_os = "solaris", - target_os = "illumos", target_vendor = "apple", ))] fn file_lock_multiple_shared() { @@ -249,11 +253,15 @@ fn file_lock_multiple_shared() { #[test] #[cfg(any( windows, + target_os = "aix", + target_os = "cygwin", target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", target_os = "solaris", - target_os = "illumos", target_vendor = "apple", ))] fn file_lock_blocking() { @@ -275,11 +283,15 @@ fn file_lock_blocking() { #[test] #[cfg(any( windows, + target_os = "aix", + target_os = "cygwin", target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", target_os = "solaris", - target_os = "illumos", target_vendor = "apple", ))] fn file_lock_drop() { @@ -298,11 +310,15 @@ fn file_lock_drop() { #[test] #[cfg(any( windows, + target_os = "aix", + target_os = "cygwin", target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", target_os = "solaris", - target_os = "illumos", target_vendor = "apple", ))] fn file_lock_dup() { From 4bf24d2b54c23dd00c7eb48dd6b9a82bead687ec Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 19 Nov 2025 14:20:00 -0600 Subject: [PATCH 05/13] fs: Expect a test failure if file locks aren't supported Rather than skipping the tests, make sure that they fail. This ensures that if file locking support is added for more platforms in the future, the tests don't wind up quietly skipped. --- library/std/src/fs/tests.rs | 135 +++++++++++++++++------------------- 1 file changed, 65 insertions(+), 70 deletions(-) diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 294de60f7d43e..a9195f09425c8 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1,24 +1,7 @@ use rand::RngCore; -#[cfg(any( - windows, - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "illumos", - target_vendor = "apple", -))] use crate::assert_matches::assert_matches; -#[cfg(any( - windows, - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "illumos", - target_vendor = "apple", -))] -use crate::fs::TryLockError; -use crate::fs::{self, File, FileTimes, OpenOptions}; +use crate::fs::{self, File, FileTimes, OpenOptions, TryLockError}; use crate::io::prelude::*; use crate::io::{BorrowedBuf, ErrorKind, SeekFrom}; use crate::mem::MaybeUninit; @@ -222,19 +205,22 @@ fn file_test_io_seek_and_write() { } #[test] -#[cfg(any( - windows, - target_os = "aix", - target_os = "cygwin", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris", - target_vendor = "apple", -))] +#[cfg_attr( + not(any( + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_vendor = "apple", + )), + should_panic +)] fn file_lock_multiple_shared() { let tmpdir = tmpdir(); let filename = &tmpdir.join("file_lock_multiple_shared_test.txt"); @@ -251,19 +237,22 @@ fn file_lock_multiple_shared() { } #[test] -#[cfg(any( - windows, - target_os = "aix", - target_os = "cygwin", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris", - target_vendor = "apple", -))] +#[cfg_attr( + not(any( + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_vendor = "apple", + )), + should_panic +)] fn file_lock_blocking() { let tmpdir = tmpdir(); let filename = &tmpdir.join("file_lock_blocking_test.txt"); @@ -281,19 +270,22 @@ fn file_lock_blocking() { } #[test] -#[cfg(any( - windows, - target_os = "aix", - target_os = "cygwin", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris", - target_vendor = "apple", -))] +#[cfg_attr( + not(any( + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_vendor = "apple", + )), + should_panic +)] fn file_lock_drop() { let tmpdir = tmpdir(); let filename = &tmpdir.join("file_lock_dup_test.txt"); @@ -308,19 +300,22 @@ fn file_lock_drop() { } #[test] -#[cfg(any( - windows, - target_os = "aix", - target_os = "cygwin", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris", - target_vendor = "apple", -))] +#[cfg_attr( + not(any( + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_vendor = "apple", + )), + should_panic +)] fn file_lock_dup() { let tmpdir = tmpdir(); let filename = &tmpdir.join("file_lock_dup_test.txt"); From cea9dd8dc8cddd9ecbdf1308418b63dfa047aca4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 19 Nov 2025 14:20:00 -0600 Subject: [PATCH 06/13] test: Use an ignore message for fs Android skips --- library/std/src/fs/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index a9195f09425c8..0a5d1153d860c 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1263,7 +1263,7 @@ fn readlink_not_symlink() { } #[test] -#[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating hardlinks +#[cfg_attr(target_os = "android", ignore = "Android SELinux rules prevent creating hardlinks")] fn links_work() { let tmpdir = tmpdir(); let input = tmpdir.join("in.txt"); @@ -1759,7 +1759,7 @@ fn metadata_access_times() { /// Test creating hard links to symlinks. #[test] -#[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating hardlinks +#[cfg_attr(target_os = "android", ignore = "Android SELinux rules prevent creating hardlinks")] fn symlink_hard_link() { let tmpdir = tmpdir(); if !got_symlink_permission(&tmpdir) { From ea3fe53ac0eb96c7efc367b9acc2907c4b041853 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Thu, 20 Nov 2025 10:13:11 +0530 Subject: [PATCH 07/13] std: sys: fs: uefi: Fix FileAttr size - The underlying file size is represented by file_size field. The size field is just the size of structure since it is a C DST. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index 18c1501a655fe..7625409007a46 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -81,7 +81,7 @@ impl FileAttr { unsafe { Self { attr: (*info.as_ptr()).attribute, - size: (*info.as_ptr()).size, + size: (*info.as_ptr()).file_size, modified: uefi_fs::uefi_to_systemtime((*info.as_ptr()).modification_time), accessed: uefi_fs::uefi_to_systemtime((*info.as_ptr()).last_access_time), created: uefi_fs::uefi_to_systemtime((*info.as_ptr()).create_time), From 4adcdbb58ba65d0af86c50d77ef42b344b9a5cb2 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Wed, 19 Nov 2025 22:49:44 -0600 Subject: [PATCH 08/13] In `BTreeMap::eq`, do not compare the elements if the sizes are different. Reverts 68a7c250788833305f73f816b284aafa9e62370a in library/ --- library/alloc/src/collections/btree/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 766f4589177a8..e9d0ad72c1e4c 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -2416,7 +2416,7 @@ impl Default for BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for BTreeMap { fn eq(&self, other: &BTreeMap) -> bool { - self.iter().eq(other) + self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b) } } From 907f5c118096eb2e2031f41a5a3337791c7a111e Mon Sep 17 00:00:00 2001 From: Zachary S Date: Thu, 20 Nov 2025 00:09:56 -0600 Subject: [PATCH 09/13] Add regression test for collections' PartialEq::eq impls not comparing elements if lengths are different. --- .../tests/collections/eq_diff_len.rs | 96 +++++++++++++++++++ library/alloctests/tests/collections/mod.rs | 1 + 2 files changed, 97 insertions(+) create mode 100644 library/alloctests/tests/collections/eq_diff_len.rs diff --git a/library/alloctests/tests/collections/eq_diff_len.rs b/library/alloctests/tests/collections/eq_diff_len.rs new file mode 100644 index 0000000000000..ee1e294d37c67 --- /dev/null +++ b/library/alloctests/tests/collections/eq_diff_len.rs @@ -0,0 +1,96 @@ +//! Regression tests which fail if some collections' `PartialEq::eq` impls compare +//! elements when the collections have different sizes. +//! This behavior is not guaranteed either way, so regressing these tests is fine +//! if it is done on purpose. +use std::cmp::Ordering; +use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, LinkedList}; + +/// This intentionally has a panicking `PartialEq` impl, to test that various +/// collections' `PartialEq` impls don't actually compare elements if their sizes +/// are unequal. +/// +/// This is not advisable in normal code. +#[derive(Debug, Clone, Copy, Hash)] +struct Evil; + +impl PartialEq for Evil { + fn eq(&self, _: &Self) -> bool { + panic!("Evil::eq is evil"); + } +} +impl Eq for Evil {} + +impl PartialOrd for Evil { + fn partial_cmp(&self, _: &Self) -> Option { + Some(Ordering::Equal) + } +} + +impl Ord for Evil { + fn cmp(&self, _: &Self) -> Ordering { + // Constructing a `BTreeSet`/`BTreeMap` uses `cmp` on the elements, + // but comparing it with with `==` uses `eq` on the elements, + // so Evil::cmp doesn't need to be evil. + Ordering::Equal + } +} + +// check Evil works +#[test] +#[should_panic = "Evil::eq is evil"] +fn evil_eq_works() { + let v1 = vec![Evil]; + let v2 = vec![Evil]; + + _ = v1 == v2; +} + +// check various containers don't compare if their sizes are different + +#[test] +fn vec_evil_eq() { + let v1 = vec![Evil]; + let v2 = vec![Evil; 2]; + + assert_eq!(false, v1 == v2); +} + +#[test] +fn hashset_evil_eq() { + let s1 = HashSet::from([(0, Evil)]); + let s2 = HashSet::from([(0, Evil), (1, Evil)]); + + assert_eq!(false, s1 == s2); +} + +#[test] +fn hashmap_evil_eq() { + let m1 = HashMap::from([(0, Evil)]); + let m2 = HashMap::from([(0, Evil), (1, Evil)]); + + assert_eq!(false, m1 == m2); +} + +#[test] +fn btreeset_evil_eq() { + let s1 = BTreeSet::from([(0, Evil)]); + let s2 = BTreeSet::from([(0, Evil), (1, Evil)]); + + assert_eq!(false, s1 == s2); +} + +#[test] +fn btreemap_evil_eq() { + let m1 = BTreeMap::from([(0, Evil)]); + let m2 = BTreeMap::from([(0, Evil), (1, Evil)]); + + assert_eq!(false, m1 == m2); +} + +#[test] +fn linkedlist_evil_eq() { + let m1 = LinkedList::from([Evil]); + let m2 = LinkedList::from([Evil; 2]); + + assert_eq!(false, m1 == m2); +} diff --git a/library/alloctests/tests/collections/mod.rs b/library/alloctests/tests/collections/mod.rs index e73f3aaef8c83..2d387f0e77eb5 100644 --- a/library/alloctests/tests/collections/mod.rs +++ b/library/alloctests/tests/collections/mod.rs @@ -1 +1,2 @@ mod binary_heap; +mod eq_diff_len; From 7ad3c5c4f8498f0683e1addc1b514c8e95ec7a48 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Nov 2025 22:14:46 +0100 Subject: [PATCH 10/13] sgx: avoid unnecessarily creating a slice --- library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs index a60b83213fd96..fb410c2851604 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs @@ -143,12 +143,6 @@ unsafe impl UserSafe for [T] { align_of::() } - /// # Safety - /// Behavior is undefined if any of these conditions are violated: - /// * `ptr` must be [valid] for writes of `size` many bytes, and it must be - /// properly aligned. - /// - /// [valid]: core::ptr#safety /// # Panics /// /// This function panics if: @@ -158,8 +152,7 @@ unsafe impl UserSafe for [T] { let elem_size = size_of::(); assert_eq!(size % elem_size, 0); let len = size / elem_size; - // SAFETY: The caller must uphold the safety contract for `from_raw_sized_unchecked` - unsafe { slice::from_raw_parts_mut(ptr as _, len) } + ptr::slice_from_raw_parts_mut(ptr as _, len) } } From c8ba2a59f897f01357149fc4ce14c029683e6b26 Mon Sep 17 00:00:00 2001 From: Fluid Date: Thu, 20 Nov 2025 12:09:44 +0200 Subject: [PATCH 11/13] remove an unused variable Deleted lines are duplicates of the lines 38 & 39. --- src/tools/compiletest/src/runtest/rustdoc_json.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tools/compiletest/src/runtest/rustdoc_json.rs b/src/tools/compiletest/src/runtest/rustdoc_json.rs index 6cb0c2a040535..89e9f31688379 100644 --- a/src/tools/compiletest/src/runtest/rustdoc_json.rs +++ b/src/tools/compiletest/src/runtest/rustdoc_json.rs @@ -18,8 +18,6 @@ impl TestCx<'_> { self.fatal_proc_rec("rustdoc failed!", &proc_res); } - let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap()); - json_out.set_extension("json"); let res = self.run_command_to_procres( Command::new(self.config.jsondocck_path.as_ref().unwrap()) .arg("--doc-dir") From 3f08502242399d10f879a5573c7f6ee1568462c4 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Thu, 20 Nov 2025 15:50:19 +0530 Subject: [PATCH 12/13] std: sys: net: uefi: Implement read_vectored - Basically a copy of write_vectored [0] - Tested on QEMU ovmf. [0]: https://github.com/rust-lang/rust/pull/146301 Signed-off-by: Ayush Singh --- .../std/src/sys/net/connection/uefi/mod.rs | 5 +- .../std/src/sys/net/connection/uefi/tcp.rs | 12 +++- .../std/src/sys/net/connection/uefi/tcp4.rs | 68 +++++++++++++++---- 3 files changed, 69 insertions(+), 16 deletions(-) diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs index d76e3e576f330..db2d18646d026 100644 --- a/library/std/src/sys/net/connection/uefi/mod.rs +++ b/library/std/src/sys/net/connection/uefi/mod.rs @@ -69,12 +69,11 @@ impl TcpStream { } pub fn read_vectored(&self, buf: &mut [IoSliceMut<'_>]) -> io::Result { - // FIXME: UEFI does support vectored read, so implement that. - crate::io::default_read_vectored(|b| self.read(b), buf) + self.inner.read_vectored(buf, self.read_timeout()?) } pub fn is_read_vectored(&self) -> bool { - false + true } pub fn write(&self, buf: &[u8]) -> io::Result { diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs index 16283e64fb35a..1e7e829c85f35 100644 --- a/library/std/src/sys/net/connection/uefi/tcp.rs +++ b/library/std/src/sys/net/connection/uefi/tcp.rs @@ -1,5 +1,5 @@ use super::tcp4; -use crate::io::{self, IoSlice}; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::SocketAddr; use crate::ptr::NonNull; use crate::sys::{helpers, unsupported}; @@ -44,6 +44,16 @@ impl Tcp { } } + pub(crate) fn read_vectored( + &self, + buf: &mut [IoSliceMut<'_>], + timeout: Option, + ) -> io::Result { + match self { + Self::V4(client) => client.read_vectored(buf, timeout), + } + } + pub(crate) fn ttl(&self) -> io::Result { match self { Self::V4(client) => client.get_mode_data().map(|x| x.time_to_live.into()), diff --git a/library/std/src/sys/net/connection/uefi/tcp4.rs b/library/std/src/sys/net/connection/uefi/tcp4.rs index ba0424454d738..0409997f02721 100644 --- a/library/std/src/sys/net/connection/uefi/tcp4.rs +++ b/library/std/src/sys/net/connection/uefi/tcp4.rs @@ -1,7 +1,7 @@ use r_efi::efi::{self, Status}; use r_efi::protocols::tcp4; -use crate::io::{self, IoSlice}; +use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::SocketAddrV4; use crate::ptr::NonNull; use crate::sync::atomic::{AtomicBool, Ordering}; @@ -193,30 +193,74 @@ impl Tcp4 { } pub(crate) fn read(&self, buf: &mut [u8], timeout: Option) -> io::Result { - let evt = unsafe { self.create_evt() }?; - let completion_token = - tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS }; let data_len = u32::try_from(buf.len()).unwrap_or(u32::MAX); let fragment = tcp4::FragmentData { fragment_length: data_len, fragment_buffer: buf.as_mut_ptr().cast::(), }; - let mut tx_data = tcp4::ReceiveData { + let mut rx_data = tcp4::ReceiveData { urgent_flag: r_efi::efi::Boolean::FALSE, data_length: data_len, fragment_count: 1, fragment_table: [fragment], }; - let protocol = self.protocol.as_ptr(); - let mut token = tcp4::IoToken { - completion_token, - packet: tcp4::IoTokenPacket { - rx_data: (&raw mut tx_data).cast::>(), - }, + self.read_inner((&raw mut rx_data).cast(), timeout).map(|_| data_len as usize) + } + + pub(crate) fn read_vectored( + &self, + buf: &[IoSliceMut<'_>], + timeout: Option, + ) -> io::Result { + let mut data_length = 0u32; + let mut fragment_count = 0u32; + + // Calculate how many IoSlice in buf can be transmitted. + for i in buf { + // IoSlice length is always <= u32::MAX in UEFI. + match data_length.checked_add(u32::try_from(i.len()).expect("value is stored as a u32")) + { + Some(x) => data_length = x, + None => break, + } + fragment_count += 1; + } + + let rx_data_size = size_of::>() + + size_of::() * (fragment_count as usize); + let mut rx_data = helpers::UefiBox::::new(rx_data_size)?; + rx_data.write(tcp4::ReceiveData { + urgent_flag: r_efi::efi::Boolean::FALSE, + data_length, + fragment_count, + fragment_table: [], + }); + unsafe { + // SAFETY: IoSlice and FragmentData are guaranteed to have same layout. + crate::ptr::copy_nonoverlapping( + buf.as_ptr().cast(), + (*rx_data.as_mut_ptr()).fragment_table.as_mut_ptr(), + fragment_count as usize, + ); }; + self.read_inner(rx_data.as_mut_ptr(), timeout).map(|_| data_length as usize) + } + + pub(crate) fn read_inner( + &self, + rx_data: *mut tcp4::ReceiveData, + timeout: Option, + ) -> io::Result<()> { + let evt = unsafe { self.create_evt() }?; + let completion_token = + tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS }; + + let protocol = self.protocol.as_ptr(); + let mut token = tcp4::IoToken { completion_token, packet: tcp4::IoTokenPacket { rx_data } }; + let r = unsafe { ((*protocol).receive)(protocol, &mut token) }; if r.is_error() { return Err(io::Error::from_raw_os_error(r.as_usize())); @@ -227,7 +271,7 @@ impl Tcp4 { if completion_token.status.is_error() { Err(io::Error::from_raw_os_error(completion_token.status.as_usize())) } else { - Ok(data_len as usize) + Ok(()) } } From 1e14a5dc737cb608a7a35f816266edb2362992f6 Mon Sep 17 00:00:00 2001 From: 12101111 Date: Thu, 20 Nov 2025 19:22:01 +0800 Subject: [PATCH 13/13] Enable host tools for aarch64-unknown-linux-ohos --- .../rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs index 5f1ab6069ef00..eb0d328b51b7c 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs @@ -11,7 +11,7 @@ pub(crate) fn target() -> Target { metadata: TargetMetadata { description: Some("ARM64 OpenHarmony".into()), tier: Some(2), - host_tools: Some(false), + host_tools: Some(true), std: Some(true), }, pointer_width: 64,