From 721e0a8be922844dbd9a0aa035fc76a6f3298cc2 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 18 Jul 2026 16:50:31 +0200 Subject: [PATCH 01/16] modify `asm_experimental_reg` example to not need x86_64 --- .../feature-gate-asm_experimental_reg.rs | 23 ++++++++--- .../feature-gate-asm_experimental_reg.stderr | 40 ++++++++++++++++--- 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs index bfc79ae8db663..0d2c4fe2b67c3 100644 --- a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs +++ b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs @@ -1,16 +1,27 @@ //@ add-minicore -//@ compile-flags: --target x86_64-unknown-linux-gnu -//@ needs-llvm-components: x86 +//@ compile-flags: --target loongarch64-unknown-none +//@ needs-llvm-components: loongarch //@ ignore-backends: gcc -#![feature(no_core, lang_items, rustc_attrs)] +#![feature(no_core, lang_items, rustc_attrs, repr_simd)] #![crate_type = "rlib"] #![no_core] +#![allow(non_camel_case_types)] extern crate minicore; use minicore::*; -unsafe fn main() { - asm!("{:x}", in(xmm_reg) 0u128); - //~^ ERROR type `u128` cannot be used with this register class in stable +#[repr(simd)] +pub struct i8x16([i8; 16]); + +impl Copy for i8x16 {} + +unsafe fn main(x: i8x16) -> i8x16 { + let y; + asm!("xvadd.h {1:u}, {0:u}, {0:u}", out(vreg) y, in(vreg) x); + //~^ ERROR register class `vreg` can only be used as a clobber in stable + //~| ERROR register class `vreg` can only be used as a clobber in stable + //~| ERROR type `i8x16` cannot be used with this register class in stable + //~| ERROR type `i8x16` cannot be used with this register class in stable + y } diff --git a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr index 4042ee7029b53..fb54438ef589e 100644 --- a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr +++ b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr @@ -1,13 +1,43 @@ -error[E0658]: type `u128` cannot be used with this register class in stable - --> $DIR/feature-gate-asm_experimental_reg.rs:14:30 +error[E0658]: register class `vreg` can only be used as a clobber in stable + --> $DIR/feature-gate-asm_experimental_reg.rs:21:41 | -LL | asm!("{:x}", in(xmm_reg) 0u128); - | ^^^^^ +LL | asm!("xvadd.h {1:u}, {0:u}, {0:u}", out(vreg) y, in(vreg) x); + | ^^^^^^^^^^^ | = note: see issue #133416 for more information = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 1 previous error +error[E0658]: register class `vreg` can only be used as a clobber in stable + --> $DIR/feature-gate-asm_experimental_reg.rs:21:54 + | +LL | asm!("xvadd.h {1:u}, {0:u}, {0:u}", out(vreg) y, in(vreg) x); + | ^^^^^^^^^^ + | + = note: see issue #133416 for more information + = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: type `i8x16` cannot be used with this register class in stable + --> $DIR/feature-gate-asm_experimental_reg.rs:21:51 + | +LL | asm!("xvadd.h {1:u}, {0:u}, {0:u}", out(vreg) y, in(vreg) x); + | ^ + | + = note: see issue #133416 for more information + = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: type `i8x16` cannot be used with this register class in stable + --> $DIR/feature-gate-asm_experimental_reg.rs:21:63 + | +LL | asm!("xvadd.h {1:u}, {0:u}, {0:u}", out(vreg) y, in(vreg) x); + | ^ + | + = note: see issue #133416 for more information + = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0658`. From b68b9bc201d6b9284c596657855ee8797316b227 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 18 Jul 2026 16:59:52 +0200 Subject: [PATCH 02/16] stabilize passing 128-bit integers via vector registers with `asm!` on x86 --- compiler/rustc_target/src/asm/x86.rs | 44 ++---- .../language-features/asm-experimental-reg.md | 3 - .../x86_64/bad-reg.experimental_reg.stderr | 64 ++++----- tests/ui/asm/x86_64/bad-reg.rs | 21 +-- tests/ui/asm/x86_64/bad-reg.stable.stderr | 127 +++++------------- tests/ui/asm/x86_64/type-check-3.stderr | 2 +- 6 files changed, 83 insertions(+), 178 deletions(-) diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs index 6f0faffa32984..c582c06d8f4bb 100644 --- a/compiler/rustc_target/src/asm/x86.rs +++ b/compiler/rustc_target/src/asm/x86.rs @@ -105,7 +105,7 @@ impl X86InlineAsmRegClass { pub fn supported_types( self, arch: InlineAsmArch, - allow_experimental_reg: bool, + _allow_experimental_reg: bool, ) -> &'static [(InlineAsmType, Option)] { match self { Self::reg | Self::reg_abcd => { @@ -117,48 +117,24 @@ impl X86InlineAsmRegClass { } Self::reg_byte => types! { _: I8; }, Self::xmm_reg => { - if allow_experimental_reg { - types! { - sse: I32, I64, I128, F16, F32, F64, F128, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2); - } - } else { - types! { - sse: I32, I64, F16, F32, F64, F128, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2); - } + types! { + sse: I32, I64, I128, F16, F32, F64, F128, + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2); } } Self::ymm_reg => { - if allow_experimental_reg { - types! { - avx: I32, I64, I128, F16, F32, F64, F128, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2), - VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF16(16), VecF32(8), VecF64(4); - } - } else { - types! { - avx: I32, I64, F16, F32, F64, F128, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2), - VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF16(16), VecF32(8), VecF64(4); - } + types! { + avx: I32, I64, I128, F16, F32, F64, F128, + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2), + VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF16(16), VecF32(8), VecF64(4); } } Self::zmm_reg => { - if allow_experimental_reg { - types! { - avx512f: I32, I64, I128, F16, F32, F64, F128, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2), - VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF16(16), VecF32(8), VecF64(4), - VecI8(64), VecI16(32), VecI32(16), VecI64(8), VecF16(32), VecF32(16), VecF64(8); - } - } else { - types! { - avx512f: I32, I64, F16, F32, F64, F128, + types! { + avx512f: I32, I64, I128, F16, F32, F64, F128, VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2), VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF16(16), VecF32(8), VecF64(4), VecI8(64), VecI16(32), VecI32(16), VecI64(8), VecF16(32), VecF32(16), VecF64(8); - } } } diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-reg.md b/src/doc/unstable-book/src/language-features/asm-experimental-reg.md index 095b541da6e46..db72c44a2dc92 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-reg.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-reg.md @@ -19,9 +19,6 @@ This tracks support for additional registers in architectures where inline assem | Architecture | Register class | Target feature | Allowed types | | ------------ | -------------- | -------------- | ------------- | -| x86 | `xmm_reg` | `sse` | `i128` | -| x86 | `ymm_reg` | `avx` | `i128` | -| x86 | `zmm_reg` | `avx512f` | `i128` | | LoongArch | `vreg` | `lsx` | `f32`, `f64`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` | | LoongArch | `xreg` | `lasx` | `f32`, `f64`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2`,
`i8x32`, `i16x16`, `i32x8`, `i64x4`, `f32x8`, `f64x4` | diff --git a/tests/ui/asm/x86_64/bad-reg.experimental_reg.stderr b/tests/ui/asm/x86_64/bad-reg.experimental_reg.stderr index fe2a53aec5d48..a03791b9222cc 100644 --- a/tests/ui/asm/x86_64/bad-reg.experimental_reg.stderr +++ b/tests/ui/asm/x86_64/bad-reg.experimental_reg.stderr @@ -1,5 +1,5 @@ error: invalid register class `foo`: unknown register class - --> $DIR/bad-reg.rs:20:20 + --> $DIR/bad-reg.rs:19:20 | LL | asm!("{}", in(foo) foo); | ^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | asm!("{}", in(foo) foo); = note: the following register classes are supported on this target: `reg`, `reg_abcd`, `reg_byte`, `xmm_reg`, `ymm_reg`, `zmm_reg`, `kreg`, `kreg0`, `mmx_reg`, `x87_reg`, and `tmm_reg` error: invalid register `foo`: unknown register - --> $DIR/bad-reg.rs:22:18 + --> $DIR/bad-reg.rs:21:18 | LL | asm!("", in("foo") foo); | ^^^^^^^^^^^^^ error: invalid asm template modifier `z` for this register class - --> $DIR/bad-reg.rs:24:15 + --> $DIR/bad-reg.rs:23:15 | LL | asm!("{:z}", in(reg) foo); | ^^^^ ----------- argument @@ -23,7 +23,7 @@ LL | asm!("{:z}", in(reg) foo); = note: the `reg` register class supports the following template modifiers: `l`, `x`, `e`, and `r` error: invalid asm template modifier `r` for this register class - --> $DIR/bad-reg.rs:26:15 + --> $DIR/bad-reg.rs:25:15 | LL | asm!("{:r}", in(xmm_reg) foo); | ^^^^ --------------- argument @@ -33,7 +33,7 @@ LL | asm!("{:r}", in(xmm_reg) foo); = note: the `xmm_reg` register class supports the following template modifiers: `x`, `y`, and `z` error: asm template modifiers are not allowed for `const` arguments - --> $DIR/bad-reg.rs:28:15 + --> $DIR/bad-reg.rs:27:15 | LL | asm!("{:a}", const 0); | ^^^^ ------- argument @@ -41,7 +41,7 @@ LL | asm!("{:a}", const 0); | template modifier error: asm template modifiers are not allowed for `sym` arguments - --> $DIR/bad-reg.rs:30:15 + --> $DIR/bad-reg.rs:29:15 | LL | asm!("{:a}", sym main); | ^^^^ -------- argument @@ -49,67 +49,67 @@ LL | asm!("{:a}", sym main); | template modifier error: invalid register `ebp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:32:18 + --> $DIR/bad-reg.rs:31:18 | LL | asm!("", in("ebp") foo); | ^^^^^^^^^^^^^ error: invalid register `rsp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:34:18 + --> $DIR/bad-reg.rs:33:18 | LL | asm!("", in("rsp") foo); | ^^^^^^^^^^^^^ error: invalid register `ip`: the instruction pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:36:18 + --> $DIR/bad-reg.rs:35:18 | LL | asm!("", in("ip") foo); | ^^^^^^^^^^^^ error: register class `x87_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:43:18 + --> $DIR/bad-reg.rs:42:18 | LL | asm!("", in("st(2)") foo); | ^^^^^^^^^^^^^^^ error: register class `mmx_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:46:18 + --> $DIR/bad-reg.rs:45:18 | LL | asm!("", in("mm0") foo); | ^^^^^^^^^^^^^ error: register class `kreg0` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:49:18 + --> $DIR/bad-reg.rs:48:18 | LL | asm!("", in("k0") foo); | ^^^^^^^^^^^^ error: register class `x87_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:54:20 + --> $DIR/bad-reg.rs:53:20 | LL | asm!("{}", in(x87_reg) foo); | ^^^^^^^^^^^^^^^ error: register class `mmx_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:57:20 + --> $DIR/bad-reg.rs:56:20 | LL | asm!("{}", in(mmx_reg) foo); | ^^^^^^^^^^^^^^^ error: register class `x87_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:60:20 + --> $DIR/bad-reg.rs:59:20 | LL | asm!("{}", out(x87_reg) _); | ^^^^^^^^^^^^^^ error: register class `mmx_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:62:20 + --> $DIR/bad-reg.rs:61:20 | LL | asm!("{}", out(mmx_reg) _); | ^^^^^^^^^^^^^^ error: register `al` conflicts with register `eax` - --> $DIR/bad-reg.rs:68:33 + --> $DIR/bad-reg.rs:67:33 | LL | asm!("", in("eax") foo, in("al") bar); | ------------- ^^^^^^^^^^^^ register `al` @@ -117,7 +117,7 @@ LL | asm!("", in("eax") foo, in("al") bar); | register `eax` error: register `rax` conflicts with register `rax` - --> $DIR/bad-reg.rs:71:33 + --> $DIR/bad-reg.rs:70:33 | LL | asm!("", in("rax") foo, out("rax") bar); | ------------- ^^^^^^^^^^^^^^ register `rax` @@ -125,13 +125,13 @@ LL | asm!("", in("rax") foo, out("rax") bar); | register `rax` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:71:18 + --> $DIR/bad-reg.rs:70:18 | LL | asm!("", in("rax") foo, out("rax") bar); | ^^^^^^^^^^^^^ error: register `ymm0` conflicts with register `xmm0` - --> $DIR/bad-reg.rs:76:34 + --> $DIR/bad-reg.rs:75:34 | LL | asm!("", in("xmm0") foo, in("ymm0") bar); | -------------- ^^^^^^^^^^^^^^ register `ymm0` @@ -139,7 +139,7 @@ LL | asm!("", in("xmm0") foo, in("ymm0") bar); | register `xmm0` error: register `ymm0` conflicts with register `xmm0` - --> $DIR/bad-reg.rs:78:34 + --> $DIR/bad-reg.rs:77:34 | LL | asm!("", in("xmm0") foo, out("ymm0") bar); | -------------- ^^^^^^^^^^^^^^^ register `ymm0` @@ -147,25 +147,25 @@ LL | asm!("", in("xmm0") foo, out("ymm0") bar); | register `xmm0` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:78:18 + --> $DIR/bad-reg.rs:77:18 | LL | asm!("", in("xmm0") foo, out("ymm0") bar); | ^^^^^^^^^^^^^^ error: cannot use register `bl`: rbx is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:38:18 + --> $DIR/bad-reg.rs:37:18 | LL | asm!("", in("bl") foo); | ^^^^^^^^^^^^ error: cannot use register `bh`: rbx is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:40:18 + --> $DIR/bad-reg.rs:39:18 | LL | asm!("", in("bh") foo); | ^^^^^^^^^^^^ error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:43:30 + --> $DIR/bad-reg.rs:42:30 | LL | asm!("", in("st(2)") foo); | ^^^ @@ -173,7 +173,7 @@ LL | asm!("", in("st(2)") foo); = note: register class `x87_reg` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:46:28 + --> $DIR/bad-reg.rs:45:28 | LL | asm!("", in("mm0") foo); | ^^^ @@ -181,7 +181,7 @@ LL | asm!("", in("mm0") foo); = note: register class `mmx_reg` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:49:27 + --> $DIR/bad-reg.rs:48:27 | LL | asm!("", in("k0") foo); | ^^^ @@ -189,7 +189,7 @@ LL | asm!("", in("k0") foo); = note: register class `kreg0` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:54:32 + --> $DIR/bad-reg.rs:53:32 | LL | asm!("{}", in(x87_reg) foo); | ^^^ @@ -197,7 +197,7 @@ LL | asm!("{}", in(x87_reg) foo); = note: register class `x87_reg` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:57:32 + --> $DIR/bad-reg.rs:56:32 | LL | asm!("{}", in(mmx_reg) foo); | ^^^ @@ -205,7 +205,7 @@ LL | asm!("{}", in(mmx_reg) foo); = note: register class `mmx_reg` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:68:42 + --> $DIR/bad-reg.rs:67:42 | LL | asm!("", in("eax") foo, in("al") bar); | ^^^ @@ -213,7 +213,7 @@ LL | asm!("", in("eax") foo, in("al") bar); = note: register class `reg_byte` supports these types: i8 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:73:27 + --> $DIR/bad-reg.rs:72:27 | LL | asm!("", in("al") foo, lateout("al") bar); | ^^^ @@ -221,7 +221,7 @@ LL | asm!("", in("al") foo, lateout("al") bar); = note: register class `reg_byte` supports these types: i8 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:73:46 + --> $DIR/bad-reg.rs:72:46 | LL | asm!("", in("al") foo, lateout("al") bar); | ^^^ diff --git a/tests/ui/asm/x86_64/bad-reg.rs b/tests/ui/asm/x86_64/bad-reg.rs index cc3def95508ff..3e9858f4d9664 100644 --- a/tests/ui/asm/x86_64/bad-reg.rs +++ b/tests/ui/asm/x86_64/bad-reg.rs @@ -3,7 +3,6 @@ //@ compile-flags: --target x86_64-unknown-linux-gnu -C target-feature=+avx2,+avx512f //@ needs-llvm-components: x86 #![cfg_attr(experimental_reg, feature(asm_experimental_reg))] - #![crate_type = "lib"] #![feature(no_core)] #![no_core] @@ -79,22 +78,16 @@ fn main() { //~^ ERROR register `ymm0` conflicts with register `xmm0` asm!("", in("xmm0") foo, lateout("ymm0") bar); - // Passing u128/i128 is currently experimental. + // Use 128-bit integers with vector registers. let mut xmmword = 0u128; - asm!("/* {:x} */", in(xmm_reg) xmmword); // requires asm_experimental_reg - //[stable]~^ ERROR type `u128` cannot be used with this register class in stable - asm!("/* {:x} */", out(xmm_reg) xmmword); // requires asm_experimental_reg - //[stable]~^ ERROR type `u128` cannot be used with this register class in stable + asm!("/* {:x} */", in(xmm_reg) xmmword); + asm!("/* {:x} */", out(xmm_reg) xmmword); - asm!("/* {:y} */", in(ymm_reg) xmmword); // requires asm_experimental_reg - //[stable]~^ ERROR type `u128` cannot be used with this register class in stable - asm!("/* {:y} */", out(ymm_reg) xmmword); // requires asm_experimental_reg - //[stable]~^ ERROR type `u128` cannot be used with this register class in stable + asm!("/* {:y} */", in(ymm_reg) xmmword); + asm!("/* {:y} */", out(ymm_reg) xmmword); - asm!("/* {:z} */", in(zmm_reg) xmmword); // requires asm_experimental_reg - //[stable]~^ ERROR type `u128` cannot be used with this register class in stable - asm!("/* {:z} */", out(zmm_reg) xmmword); // requires asm_experimental_reg - //[stable]~^ ERROR type `u128` cannot be used with this register class in stable + asm!("/* {:z} */", in(zmm_reg) xmmword); + asm!("/* {:z} */", out(zmm_reg) xmmword); } } diff --git a/tests/ui/asm/x86_64/bad-reg.stable.stderr b/tests/ui/asm/x86_64/bad-reg.stable.stderr index d8a37933065e1..a03791b9222cc 100644 --- a/tests/ui/asm/x86_64/bad-reg.stable.stderr +++ b/tests/ui/asm/x86_64/bad-reg.stable.stderr @@ -1,5 +1,5 @@ error: invalid register class `foo`: unknown register class - --> $DIR/bad-reg.rs:20:20 + --> $DIR/bad-reg.rs:19:20 | LL | asm!("{}", in(foo) foo); | ^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | asm!("{}", in(foo) foo); = note: the following register classes are supported on this target: `reg`, `reg_abcd`, `reg_byte`, `xmm_reg`, `ymm_reg`, `zmm_reg`, `kreg`, `kreg0`, `mmx_reg`, `x87_reg`, and `tmm_reg` error: invalid register `foo`: unknown register - --> $DIR/bad-reg.rs:22:18 + --> $DIR/bad-reg.rs:21:18 | LL | asm!("", in("foo") foo); | ^^^^^^^^^^^^^ error: invalid asm template modifier `z` for this register class - --> $DIR/bad-reg.rs:24:15 + --> $DIR/bad-reg.rs:23:15 | LL | asm!("{:z}", in(reg) foo); | ^^^^ ----------- argument @@ -23,7 +23,7 @@ LL | asm!("{:z}", in(reg) foo); = note: the `reg` register class supports the following template modifiers: `l`, `x`, `e`, and `r` error: invalid asm template modifier `r` for this register class - --> $DIR/bad-reg.rs:26:15 + --> $DIR/bad-reg.rs:25:15 | LL | asm!("{:r}", in(xmm_reg) foo); | ^^^^ --------------- argument @@ -33,7 +33,7 @@ LL | asm!("{:r}", in(xmm_reg) foo); = note: the `xmm_reg` register class supports the following template modifiers: `x`, `y`, and `z` error: asm template modifiers are not allowed for `const` arguments - --> $DIR/bad-reg.rs:28:15 + --> $DIR/bad-reg.rs:27:15 | LL | asm!("{:a}", const 0); | ^^^^ ------- argument @@ -41,7 +41,7 @@ LL | asm!("{:a}", const 0); | template modifier error: asm template modifiers are not allowed for `sym` arguments - --> $DIR/bad-reg.rs:30:15 + --> $DIR/bad-reg.rs:29:15 | LL | asm!("{:a}", sym main); | ^^^^ -------- argument @@ -49,67 +49,67 @@ LL | asm!("{:a}", sym main); | template modifier error: invalid register `ebp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:32:18 + --> $DIR/bad-reg.rs:31:18 | LL | asm!("", in("ebp") foo); | ^^^^^^^^^^^^^ error: invalid register `rsp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:34:18 + --> $DIR/bad-reg.rs:33:18 | LL | asm!("", in("rsp") foo); | ^^^^^^^^^^^^^ error: invalid register `ip`: the instruction pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:36:18 + --> $DIR/bad-reg.rs:35:18 | LL | asm!("", in("ip") foo); | ^^^^^^^^^^^^ error: register class `x87_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:43:18 + --> $DIR/bad-reg.rs:42:18 | LL | asm!("", in("st(2)") foo); | ^^^^^^^^^^^^^^^ error: register class `mmx_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:46:18 + --> $DIR/bad-reg.rs:45:18 | LL | asm!("", in("mm0") foo); | ^^^^^^^^^^^^^ error: register class `kreg0` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:49:18 + --> $DIR/bad-reg.rs:48:18 | LL | asm!("", in("k0") foo); | ^^^^^^^^^^^^ error: register class `x87_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:54:20 + --> $DIR/bad-reg.rs:53:20 | LL | asm!("{}", in(x87_reg) foo); | ^^^^^^^^^^^^^^^ error: register class `mmx_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:57:20 + --> $DIR/bad-reg.rs:56:20 | LL | asm!("{}", in(mmx_reg) foo); | ^^^^^^^^^^^^^^^ error: register class `x87_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:60:20 + --> $DIR/bad-reg.rs:59:20 | LL | asm!("{}", out(x87_reg) _); | ^^^^^^^^^^^^^^ error: register class `mmx_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:62:20 + --> $DIR/bad-reg.rs:61:20 | LL | asm!("{}", out(mmx_reg) _); | ^^^^^^^^^^^^^^ error: register `al` conflicts with register `eax` - --> $DIR/bad-reg.rs:68:33 + --> $DIR/bad-reg.rs:67:33 | LL | asm!("", in("eax") foo, in("al") bar); | ------------- ^^^^^^^^^^^^ register `al` @@ -117,7 +117,7 @@ LL | asm!("", in("eax") foo, in("al") bar); | register `eax` error: register `rax` conflicts with register `rax` - --> $DIR/bad-reg.rs:71:33 + --> $DIR/bad-reg.rs:70:33 | LL | asm!("", in("rax") foo, out("rax") bar); | ------------- ^^^^^^^^^^^^^^ register `rax` @@ -125,13 +125,13 @@ LL | asm!("", in("rax") foo, out("rax") bar); | register `rax` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:71:18 + --> $DIR/bad-reg.rs:70:18 | LL | asm!("", in("rax") foo, out("rax") bar); | ^^^^^^^^^^^^^ error: register `ymm0` conflicts with register `xmm0` - --> $DIR/bad-reg.rs:76:34 + --> $DIR/bad-reg.rs:75:34 | LL | asm!("", in("xmm0") foo, in("ymm0") bar); | -------------- ^^^^^^^^^^^^^^ register `ymm0` @@ -139,7 +139,7 @@ LL | asm!("", in("xmm0") foo, in("ymm0") bar); | register `xmm0` error: register `ymm0` conflicts with register `xmm0` - --> $DIR/bad-reg.rs:78:34 + --> $DIR/bad-reg.rs:77:34 | LL | asm!("", in("xmm0") foo, out("ymm0") bar); | -------------- ^^^^^^^^^^^^^^^ register `ymm0` @@ -147,25 +147,25 @@ LL | asm!("", in("xmm0") foo, out("ymm0") bar); | register `xmm0` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:78:18 + --> $DIR/bad-reg.rs:77:18 | LL | asm!("", in("xmm0") foo, out("ymm0") bar); | ^^^^^^^^^^^^^^ error: cannot use register `bl`: rbx is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:38:18 + --> $DIR/bad-reg.rs:37:18 | LL | asm!("", in("bl") foo); | ^^^^^^^^^^^^ error: cannot use register `bh`: rbx is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:40:18 + --> $DIR/bad-reg.rs:39:18 | LL | asm!("", in("bh") foo); | ^^^^^^^^^^^^ error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:43:30 + --> $DIR/bad-reg.rs:42:30 | LL | asm!("", in("st(2)") foo); | ^^^ @@ -173,7 +173,7 @@ LL | asm!("", in("st(2)") foo); = note: register class `x87_reg` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:46:28 + --> $DIR/bad-reg.rs:45:28 | LL | asm!("", in("mm0") foo); | ^^^ @@ -181,7 +181,7 @@ LL | asm!("", in("mm0") foo); = note: register class `mmx_reg` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:49:27 + --> $DIR/bad-reg.rs:48:27 | LL | asm!("", in("k0") foo); | ^^^ @@ -189,7 +189,7 @@ LL | asm!("", in("k0") foo); = note: register class `kreg0` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:54:32 + --> $DIR/bad-reg.rs:53:32 | LL | asm!("{}", in(x87_reg) foo); | ^^^ @@ -197,7 +197,7 @@ LL | asm!("{}", in(x87_reg) foo); = note: register class `x87_reg` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:57:32 + --> $DIR/bad-reg.rs:56:32 | LL | asm!("{}", in(mmx_reg) foo); | ^^^ @@ -205,7 +205,7 @@ LL | asm!("{}", in(mmx_reg) foo); = note: register class `mmx_reg` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:68:42 + --> $DIR/bad-reg.rs:67:42 | LL | asm!("", in("eax") foo, in("al") bar); | ^^^ @@ -213,7 +213,7 @@ LL | asm!("", in("eax") foo, in("al") bar); = note: register class `reg_byte` supports these types: i8 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:73:27 + --> $DIR/bad-reg.rs:72:27 | LL | asm!("", in("al") foo, lateout("al") bar); | ^^^ @@ -221,73 +221,12 @@ LL | asm!("", in("al") foo, lateout("al") bar); = note: register class `reg_byte` supports these types: i8 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:73:46 + --> $DIR/bad-reg.rs:72:46 | LL | asm!("", in("al") foo, lateout("al") bar); | ^^^ | = note: register class `reg_byte` supports these types: i8 -error[E0658]: type `u128` cannot be used with this register class in stable - --> $DIR/bad-reg.rs:85:40 - | -LL | asm!("/* {:x} */", in(xmm_reg) xmmword); // requires asm_experimental_reg - | ^^^^^^^ - | - = note: see issue #133416 for more information - = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: type `u128` cannot be used with this register class in stable - --> $DIR/bad-reg.rs:87:41 - | -LL | asm!("/* {:x} */", out(xmm_reg) xmmword); // requires asm_experimental_reg - | ^^^^^^^ - | - = note: see issue #133416 for more information - = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: type `u128` cannot be used with this register class in stable - --> $DIR/bad-reg.rs:90:40 - | -LL | asm!("/* {:y} */", in(ymm_reg) xmmword); // requires asm_experimental_reg - | ^^^^^^^ - | - = note: see issue #133416 for more information - = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: type `u128` cannot be used with this register class in stable - --> $DIR/bad-reg.rs:92:41 - | -LL | asm!("/* {:y} */", out(ymm_reg) xmmword); // requires asm_experimental_reg - | ^^^^^^^ - | - = note: see issue #133416 for more information - = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: type `u128` cannot be used with this register class in stable - --> $DIR/bad-reg.rs:95:40 - | -LL | asm!("/* {:z} */", in(zmm_reg) xmmword); // requires asm_experimental_reg - | ^^^^^^^ - | - = note: see issue #133416 for more information - = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: type `u128` cannot be used with this register class in stable - --> $DIR/bad-reg.rs:97:41 - | -LL | asm!("/* {:z} */", out(zmm_reg) xmmword); // requires asm_experimental_reg - | ^^^^^^^ - | - = note: see issue #133416 for more information - = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 36 previous errors +error: aborting due to 30 previous errors -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/asm/x86_64/type-check-3.stderr b/tests/ui/asm/x86_64/type-check-3.stderr index 5a7b349413e45..ea9a3955e7078 100644 --- a/tests/ui/asm/x86_64/type-check-3.stderr +++ b/tests/ui/asm/x86_64/type-check-3.stderr @@ -28,7 +28,7 @@ error: type `u8` cannot be used with this register class LL | asm!("{}", in(xmm_reg) 0u8); | ^^^ | - = note: register class `xmm_reg` supports these types: i32, i64, f16, f32, f64, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 + = note: register class `xmm_reg` supports these types: i32, i64, i128, f16, f32, f64, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 error: `avx512bw` target feature is not enabled --> $DIR/type-check-3.rs:27:29 From dcf4a3d67dd092b755de9b7cde4e57bba08a1b44 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 22 Jul 2026 18:24:15 +0200 Subject: [PATCH 03/16] allocations are allowed to grow --- library/core/src/ptr/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index c758d5f4b89d6..9365e6e792f28 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -145,6 +145,13 @@ //! the allocation), `base + o` will not wrap around the address space (in //! other words, will not overflow `usize`) //! +//! Allocations typically have a fixed size that cannot change. However, allocations created by +//! directly invoking page table operations of the operating system, e.g. via `mmap`, are allowed to +//! grow by adding more pages to them at the end. Unmapping parts of an allocation (i.e., shrinking +//! it or punching holes into it) is currently not supported. Allocations created via +//! "compiler-recognized" operations, such as `std::alloc` methods or `libc::malloc`, can never +//! change their size, even if they use `mmap` under the hood. +//! //! [`null()`]: null //! //! # Provenance From 56f6073ea2b5d2c4d3fa9ccf623b2405ee88a9fb Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 9 Jan 2023 16:33:34 +0000 Subject: [PATCH 04/16] Allow only implementing `Read::read_buf` --- library/alloc/src/io/read.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/io/read.rs b/library/alloc/src/io/read.rs index c0123c860b453..80b9838df1a72 100644 --- a/library/alloc/src/io/read.rs +++ b/library/alloc/src/io/read.rs @@ -84,6 +84,7 @@ use crate::vec::Vec; #[stable(feature = "rust1", since = "1.0.0")] #[doc(notable_trait)] #[cfg_attr(not(test), rustc_diagnostic_item = "IoRead")] +#[rustc_must_implement_one_of(read, read_buf)] pub trait Read { /// Pull some bytes from this source into the specified buffer, returning /// how many bytes were read. @@ -164,7 +165,10 @@ pub trait Read { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - fn read(&mut self, buf: &mut [u8]) -> Result; + fn read(&mut self, buf: &mut [u8]) -> Result { + let mut buf = BorrowedBuf::from(buf); + self.read_buf(buf.unfilled()).map(|()| buf.len()) + } /// Like `read`, except that it reads into a slice of buffers. /// From 39429fd245eb2cb2aad95ac867cae656709079f4 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 28 Jul 2026 15:02:38 -0700 Subject: [PATCH 05/16] Fix links to `std::io::Read::read` --- library/core/src/io/util.rs | 2 +- tests/rustdoc-html/jump-to-def/non-local-method.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/io/util.rs b/library/core/src/io/util.rs index b022d876eb8f5..07173f13eb08b 100644 --- a/library/core/src/io/util.rs +++ b/library/core/src/io/util.rs @@ -130,7 +130,7 @@ impl Seek for Empty { /// [`Ok(0)`]: Ok /// /// [`write`]: crate::io::Write::write -/// [`read`]: ../../std/io/trait.Read.html#tymethod.read +/// [`read`]: ../../std/io/trait.Read.html#method.read /// /// # Examples /// diff --git a/tests/rustdoc-html/jump-to-def/non-local-method.rs b/tests/rustdoc-html/jump-to-def/non-local-method.rs index e785ab8d204f9..db85d31bf656c 100644 --- a/tests/rustdoc-html/jump-to-def/non-local-method.rs +++ b/tests/rustdoc-html/jump-to-def/non-local-method.rs @@ -16,7 +16,7 @@ use std::cmp::Ordering; use std::marker::PhantomData; pub fn bar2(readable: T) { - //@ has - '//a[@href="{{channel}}/alloc/io/read/trait.Read.html#tymethod.read"]' 'read' + //@ has - '//a[@href="{{channel}}/alloc/io/read/trait.Read.html#method.read"]' 'read' let _ = readable.read(&mut []); } From 7d0aafd7e64e9090f35d3ccd1a6f9f81d966ec0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Sat, 1 Aug 2026 16:16:32 +0200 Subject: [PATCH 06/16] Specialize `advance_by` method of `Fuse` --- library/core/src/iter/adapters/fuse.rs | 33 ++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index ef956e8bdef5d..f614c31430745 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -4,6 +4,7 @@ use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::{ FusedIterator, TrustedFused, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce, }; +use crate::num::NonZero; use crate::ops::Try; /// An iterator that yields `None` forever after the underlying iterator @@ -50,6 +51,10 @@ where FuseImpl::next(self) } + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + FuseImpl::advance_by(self, n) + } + #[inline] fn nth(&mut self, n: usize) -> Option { FuseImpl::nth(self, n) @@ -259,6 +264,7 @@ trait FuseImpl { // Functions specific to any normal Iterators fn next(&mut self) -> Option; + fn advance_by(&mut self, n: usize) -> Result<(), NonZero>; fn nth(&mut self, n: usize) -> Option; fn try_fold(&mut self, acc: Acc, fold: Fold) -> R where @@ -301,6 +307,22 @@ where and_then_or_clear(&mut self.iter, Iterator::next) } + #[inline] + default fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + let Some(iter) = &mut self.iter else { + return match NonZero::new(n) { + Some(n) => Err(n), + None => Ok(()), + }; + }; + + let res = iter.advance_by(n); + if res.is_err() { + self.iter = None; + } + res + } + #[inline] default fn nth(&mut self, n: usize) -> Option { and_then_or_clear(&mut self.iter, |iter| iter.nth(n)) @@ -381,6 +403,17 @@ where self.iter.as_mut()?.next() } + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + match &mut self.iter { + Some(iter) => iter.advance_by(n), + None => match NonZero::new(n) { + Some(n) => Err(n), + None => Ok(()), + }, + } + } + #[inline] fn nth(&mut self, n: usize) -> Option { self.iter.as_mut()?.nth(n) From e5b636479b89f1fcb3120cbdfa98532f513470ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zal=C3=A1n=20B=C3=A1lint=20L=C3=A9vai?= Date: Sat, 25 Jul 2026 04:54:59 +0100 Subject: [PATCH 07/16] fix: Do not stop `visible_parent_map` breadth-first search reaching children of `#[doc(hidden)]` modules --- .../src/rmeta/decoder/cstore_impl.rs | 32 ++++++++++++------- .../auxiliary/direct-dep-with-nesting.rs | 14 ++++++++ .../auxiliary/direct-dep.rs | 12 +++++++ .../auxiliary/transitive-dep.rs | 3 ++ ...-reexport-of-nested-transitive-dep-item.rs | 16 ++++++++++ ...xport-of-nested-transitive-dep-item.stderr | 23 +++++++++++++ .../hidden-reexport-of-transitive-dep-item.rs | 16 ++++++++++ ...den-reexport-of-transitive-dep-item.stderr | 23 +++++++++++++ 8 files changed, 128 insertions(+), 11 deletions(-) create mode 100644 tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/direct-dep-with-nesting.rs create mode 100644 tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/direct-dep.rs create mode 100644 tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/transitive-dep.rs create mode 100644 tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-nested-transitive-dep-item.rs create mode 100644 tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-nested-transitive-dep-item.stderr create mode 100644 tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-transitive-dep-item.rs create mode 100644 tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-transitive-dep-item.stderr diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 9acebc1a4822f..277b187441a3b 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -501,14 +501,14 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { } if let Some(def_id) = child.res.opt_def_id() { + let mut fallback = false; + if child.ident.name == kw::Underscore { - fallback_map.push((def_id, parent)); - return; + fallback = true; } if tcx.is_doc_hidden(parent) { - fallback_map.push((def_id, parent)); - return; + fallback = true; } // If the re-export itself is `#[doc(hidden)]`, deprioritize it. @@ -519,20 +519,30 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { .and_then(|r| r.id()) .is_some_and(|id| tcx.is_doc_hidden(id)) { - fallback_map.push((def_id, parent)); - return; + fallback = true; } match visible_parent_map.entry(def_id) { Entry::Occupied(mut entry) => { - // If `child` is defined in crate `cnum`, ensure - // that it is mapped to a parent in `cnum`. - if def_id.is_local() && entry.get().is_local() { - entry.insert(parent); + if !fallback { + // If `child` is defined in crate `cnum`, ensure + // that it is mapped to a parent in `cnum`. + if def_id.is_local() && entry.get().is_local() { + entry.insert(parent); + } } } Entry::Vacant(entry) => { - entry.insert(parent); + if fallback { + // We do all of the same steps to fallback entries as to + // preferred entries, except for recording them in a separate map. + // It is important to not return early in the fallback cases to + // ensure that we extend the BFS to the children of fallback items. + fallback_map.push((def_id, parent)); + } else { + entry.insert(parent); + } + if child.res.module_like_def_id().is_some() { bfs_queue.push_back(def_id); } diff --git a/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/direct-dep-with-nesting.rs b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/direct-dep-with-nesting.rs new file mode 100644 index 0000000000000..927892c19a063 --- /dev/null +++ b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/direct-dep-with-nesting.rs @@ -0,0 +1,14 @@ +#![crate_type = "lib"] + +extern crate transitive_dep; + +mod private { + pub mod inner { + pub use crate::transitive_dep::Struct; + } +} + +#[doc(hidden)] +pub mod __private { + pub use crate::private::*; +} diff --git a/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/direct-dep.rs b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/direct-dep.rs new file mode 100644 index 0000000000000..cb37184c0ba85 --- /dev/null +++ b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/direct-dep.rs @@ -0,0 +1,12 @@ +#![crate_type = "lib"] + +extern crate transitive_dep; + +mod private { + pub use crate::transitive_dep::Struct; +} + +#[doc(hidden)] +pub mod __private { + pub use crate::private::*; +} diff --git a/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/transitive-dep.rs b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/transitive-dep.rs new file mode 100644 index 0000000000000..a2c189e59d80e --- /dev/null +++ b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/transitive-dep.rs @@ -0,0 +1,3 @@ +#![crate_type = "lib"] + +pub struct Struct; diff --git a/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-nested-transitive-dep-item.rs b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-nested-transitive-dep-item.rs new file mode 100644 index 0000000000000..c8d04a9f049f1 --- /dev/null +++ b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-nested-transitive-dep-item.rs @@ -0,0 +1,16 @@ +//@ aux-build: transitive-dep.rs +//@ aux-build: direct-dep-with-nesting.rs + +extern crate direct_dep_with_nesting as direct_dep; + +struct Struct; +//~^ NOTE `Struct` is defined in the current crate + +fn main() { + let _: direct_dep::__private::inner::Struct = Struct; + //~^ ERROR mismatched types + //~| NOTE expected `direct_dep::__private::inner::Struct`, found `Struct` + //~| NOTE expected due to this + //~| NOTE `Struct` and `direct_dep::__private::inner::Struct` have similar names, but are actually distinct types + //~| NOTE `direct_dep::__private::inner::Struct` is defined in crate `transitive_dep` +} diff --git a/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-nested-transitive-dep-item.stderr b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-nested-transitive-dep-item.stderr new file mode 100644 index 0000000000000..5ab50bebc294c --- /dev/null +++ b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-nested-transitive-dep-item.stderr @@ -0,0 +1,23 @@ +error[E0308]: mismatched types + --> $DIR/hidden-reexport-of-nested-transitive-dep-item.rs:10:51 + | +LL | let _: direct_dep::__private::inner::Struct = Struct; + | ------------------------------------ ^^^^^^ expected `direct_dep::__private::inner::Struct`, found `Struct` + | | + | expected due to this + | + = note: `Struct` and `direct_dep::__private::inner::Struct` have similar names, but are actually distinct types +note: `Struct` is defined in the current crate + --> $DIR/hidden-reexport-of-nested-transitive-dep-item.rs:6:1 + | +LL | struct Struct; + | ^^^^^^^^^^^^^ +note: `direct_dep::__private::inner::Struct` is defined in crate `transitive_dep` + --> $DIR/auxiliary/transitive-dep.rs:3:1 + | +LL | pub struct Struct; + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-transitive-dep-item.rs b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-transitive-dep-item.rs new file mode 100644 index 0000000000000..e92b3afaf4e6f --- /dev/null +++ b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-transitive-dep-item.rs @@ -0,0 +1,16 @@ +//@ aux-build: transitive-dep.rs +//@ aux-build: direct-dep.rs + +extern crate direct_dep; + +struct Struct; +//~^ NOTE `Struct` is defined in the current crate + +fn main() { + let _: direct_dep::__private::Struct = Struct; + //~^ ERROR mismatched types + //~| NOTE expected `direct_dep::__private::Struct`, found `Struct` + //~| NOTE expected due to this + //~| NOTE `Struct` and `direct_dep::__private::Struct` have similar names, but are actually distinct types + //~| NOTE `direct_dep::__private::Struct` is defined in crate `transitive_dep` +} diff --git a/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-transitive-dep-item.stderr b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-transitive-dep-item.stderr new file mode 100644 index 0000000000000..3dd899eb36f0c --- /dev/null +++ b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-transitive-dep-item.stderr @@ -0,0 +1,23 @@ +error[E0308]: mismatched types + --> $DIR/hidden-reexport-of-transitive-dep-item.rs:10:44 + | +LL | let _: direct_dep::__private::Struct = Struct; + | ----------------------------- ^^^^^^ expected `direct_dep::__private::Struct`, found `Struct` + | | + | expected due to this + | + = note: `Struct` and `direct_dep::__private::Struct` have similar names, but are actually distinct types +note: `Struct` is defined in the current crate + --> $DIR/hidden-reexport-of-transitive-dep-item.rs:6:1 + | +LL | struct Struct; + | ^^^^^^^^^^^^^ +note: `direct_dep::__private::Struct` is defined in crate `transitive_dep` + --> $DIR/auxiliary/transitive-dep.rs:3:1 + | +LL | pub struct Struct; + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. From c4d12cba88de290cc5ef6b64ef0c12ab4995e640 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Fri, 22 May 2026 08:38:41 +1000 Subject: [PATCH 08/16] Setup `core::io::prelude` --- library/core/src/io/mod.rs | 2 ++ library/core/src/io/prelude.rs | 12 ++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 library/core/src/io/prelude.rs diff --git a/library/core/src/io/mod.rs b/library/core/src/io/mod.rs index 0134540ae86c8..a44d271535a9e 100644 --- a/library/core/src/io/mod.rs +++ b/library/core/src/io/mod.rs @@ -5,6 +5,8 @@ mod cursor; mod error; mod impls; mod io_slice; +#[unstable(feature = "core_io", issue = "154046")] +pub mod prelude; mod seek; mod size_hint; mod util; diff --git a/library/core/src/io/prelude.rs b/library/core/src/io/prelude.rs new file mode 100644 index 0000000000000..15dacaa3a4fa0 --- /dev/null +++ b/library/core/src/io/prelude.rs @@ -0,0 +1,12 @@ +//! The I/O Prelude. +//! +//! The purpose of this module is to alleviate imports of many common I/O traits +//! by adding a glob import to the top of I/O heavy modules: +//! +//! ``` +//! # #![allow(unused_imports)] +//! use std::io::prelude::*; +//! ``` + +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::io::{Seek, Write}; From 0791c08ecbef1e98f72fcf42792e6017d8a4684b Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Fri, 22 May 2026 08:38:58 +1000 Subject: [PATCH 09/16] Setup `alloc::io::prelude` --- library/alloc/src/io/mod.rs | 2 ++ library/alloc/src/io/prelude.rs | 12 ++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 library/alloc/src/io/prelude.rs diff --git a/library/alloc/src/io/mod.rs b/library/alloc/src/io/mod.rs index 5c043240daba8..be2d17bb5a9e6 100644 --- a/library/alloc/src/io/mod.rs +++ b/library/alloc/src/io/mod.rs @@ -6,6 +6,8 @@ mod copy; mod cursor; mod error; mod impls; +#[unstable(feature = "alloc_io", issue = "154046")] +pub mod prelude; mod read; mod util; diff --git a/library/alloc/src/io/prelude.rs b/library/alloc/src/io/prelude.rs new file mode 100644 index 0000000000000..86ae040d1d6f6 --- /dev/null +++ b/library/alloc/src/io/prelude.rs @@ -0,0 +1,12 @@ +//! The I/O Prelude. +//! +//! The purpose of this module is to alleviate imports of many common I/O traits +//! by adding a glob import to the top of I/O heavy modules: +//! +//! ``` +//! # #![allow(unused_imports)] +//! use std::io::prelude::*; +//! ``` + +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::io::{BufRead, Read, Seek, Write}; From d95198739c2623c9e0b4f26d26c54ccd70d8e0a9 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Sun, 19 Jul 2026 21:13:23 +1000 Subject: [PATCH 10/16] Expand documentation for `alloc::io` --- library/alloc/src/io/mod.rs | 175 ++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/library/alloc/src/io/mod.rs b/library/alloc/src/io/mod.rs index be2d17bb5a9e6..44d780292317f 100644 --- a/library/alloc/src/io/mod.rs +++ b/library/alloc/src/io/mod.rs @@ -1,4 +1,179 @@ //! Traits, helpers, and type definitions for core I/O functionality. +//! +//! The `io` module contains a number of common things you'll need +//! when doing input and output. The most core part of this module is +//! the [`Read`] and [`Write`] traits, which provide the +//! most general interface for reading and writing input and output. +//! +//! ## Read and Write +//! +//! Because they are traits, [`Read`] and [`Write`] are implemented by a number +//! of other types, and you can implement them for your types too. As such, +//! you'll see a few different types of I/O throughout the documentation in +//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec`]s. For +//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on +//! [`File`]s: +//! +//! ```no_run +//! use std::io; +//! use std::io::prelude::*; +//! use std::fs::File; +//! +//! fn main() -> io::Result<()> { +//! let mut f = File::open("foo.txt")?; +//! let mut buffer = [0; 10]; +//! +//! // read up to 10 bytes +//! let n = f.read(&mut buffer)?; +//! +//! println!("The bytes: {:?}", &buffer[..n]); +//! Ok(()) +//! } +//! ``` +//! +//! [`Read`] and [`Write`] are so important, implementors of the two traits have a +//! nickname: readers and writers. So you'll sometimes see 'a reader' instead +//! of 'a type that implements the [`Read`] trait'. Much easier! +//! +//! ## Seek and BufRead +//! +//! Beyond that, there are two important traits that are provided: [`Seek`] +//! and [`BufRead`]. Both of these build on top of a reader to control +//! how the reading happens. [`Seek`] lets you control where the next byte is +//! coming from: +//! +//! ```no_run +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::SeekFrom; +//! use std::fs::File; +//! +//! fn main() -> io::Result<()> { +//! let mut f = File::open("foo.txt")?; +//! let mut buffer = [0; 10]; +//! +//! // skip to the last 10 bytes of the file +//! f.seek(SeekFrom::End(-10))?; +//! +//! // read up to 10 bytes +//! let n = f.read(&mut buffer)?; +//! +//! println!("The bytes: {:?}", &buffer[..n]); +//! Ok(()) +//! } +//! ``` +//! +//! [`BufRead`] uses an internal buffer to provide a number of other ways to read, but +//! to show it off, we'll need to talk about buffers in general. Keep reading! +//! +//! ## BufReader and BufWriter +//! +//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be +//! making near-constant calls to the operating system. To help with this, +//! `std::io` comes with two structs, [`BufReader`] and [`BufWriter`], which wrap +//! readers and writers. The wrapper uses a buffer, reducing the number of +//! calls and providing nicer methods for accessing exactly what you want. +//! +//! For example, [`BufReader`] works with the [`BufRead`] trait to add extra +//! methods to any reader: +//! +//! ```no_run +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufReader; +//! use std::fs::File; +//! +//! fn main() -> io::Result<()> { +//! let f = File::open("foo.txt")?; +//! let mut reader = BufReader::new(f); +//! let mut buffer = String::new(); +//! +//! // read a line into buffer +//! reader.read_line(&mut buffer)?; +//! +//! println!("{buffer}"); +//! Ok(()) +//! } +//! ``` +//! +//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call +//! to [`write`][`Write::write`]: +//! +//! ```no_run +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufWriter; +//! use std::fs::File; +//! +//! fn main() -> io::Result<()> { +//! let f = File::create("foo.txt")?; +//! { +//! let mut writer = BufWriter::new(f); +//! +//! // write a byte to the buffer +//! writer.write(&[42])?; +//! +//! } // the buffer is flushed once writer goes out of scope +//! +//! Ok(()) +//! } +//! ``` +//! +//! ## Iterator types +//! +//! A large number of the structures provided by `std::io` are for various +//! ways of iterating over I/O. For example, [`Lines`] is used to split over +//! lines: +//! +//! ```no_run +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufReader; +//! use std::fs::File; +//! +//! fn main() -> io::Result<()> { +//! let f = File::open("foo.txt")?; +//! let reader = BufReader::new(f); +//! +//! for line in reader.lines() { +//! println!("{}", line?); +//! } +//! Ok(()) +//! } +//! ``` +//! +//! ## io::Result +//! +//! Last, but certainly not least, is [`io::Result`]. This type is used +//! as the return type of many `std::io` functions that can cause an error, and +//! can be returned from your own functions as well. Many of the examples in this +//! module use the [`?` operator]: +//! +//! ```no_run +//! use std::io; +//! +//! # #[allow(dead_code)] +//! fn read_input() -> io::Result<()> { +//! let mut input = String::new(); +//! +//! io::stdin().read_line(&mut input)?; +//! +//! println!("You typed: {}", input.trim()); +//! +//! Ok(()) +//! } +//! ``` +//! +//! The return type of `read_input()`, [`io::Result<()>`][`io::Result`], is a very +//! common type for functions which don't have a 'real' return value, but do want to +//! return errors if they happen. In this case, the only purpose of this function is +//! to read the line and print it, so we use `()`. +//! +//! [`File`]: ../../std/fs/struct.File.html +//! [`TcpStream`]: ../../std/net/struct.TcpStream.html +//! [`Vec`]: crate::vec::Vec +//! [`io::Result`]: self::Result +//! [`?` operator]: ../../book/appendix-02-operators.html mod buf_read; mod buffered; From 32117cda49c21aecbe8d0430f766b53211e73094 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Thu, 21 May 2026 11:18:11 +1000 Subject: [PATCH 11/16] Move general IO tests to `alloctests` --- .../io/tests.rs => alloctests/tests/io/mod.rs} | 16 ++++++++++------ library/alloctests/tests/lib.rs | 12 ++++++++++++ library/std/src/io/mod.rs | 3 --- 3 files changed, 22 insertions(+), 9 deletions(-) rename library/{std/src/io/tests.rs => alloctests/tests/io/mod.rs} (98%) diff --git a/library/std/src/io/tests.rs b/library/alloctests/tests/io/mod.rs similarity index 98% rename from library/std/src/io/tests.rs rename to library/alloctests/tests/io/mod.rs index 3b4f871268cd1..fcc27dbbd73f7 100644 --- a/library/std/src/io/tests.rs +++ b/library/alloctests/tests/io/mod.rs @@ -1,7 +1,11 @@ -use super::{BorrowedBuf, Cursor, SeekFrom, repeat}; -use crate::cmp::{self, min}; -use crate::io::{self, BufRead, BufReader, DEFAULT_BUF_SIZE, IoSlice, Read, Seek, Write}; -use crate::mem::MaybeUninit; +use alloc::io::{ + self, BorrowedBuf, BufRead, BufReader, Cursor, DEFAULT_BUF_SIZE, IoSlice, Read, Seek, SeekFrom, + Write, repeat, +}; +use core::cmp::{self, min}; +use core::mem::MaybeUninit; + +extern crate test; #[test] fn read_until() { @@ -270,7 +274,7 @@ fn chain_bufread() { #[test] fn chain_splitted_char() { let chain = b"\xc3".chain(b"\xa9".as_slice()); - assert_eq!(crate::io::read_to_string(chain).unwrap(), "é"); + assert_eq!(alloc::io::read_to_string(chain).unwrap(), "é"); let mut chain = b"\xc3".chain(b"\xa9\n".as_slice()); let mut buf = String::new(); @@ -360,7 +364,7 @@ fn bench_read_to_end(b: &mut test::Bencher) { b.iter(|| { let mut lr = repeat(1).take(10000000); let mut vec = Vec::with_capacity(1024); - super::default_read_to_end(&mut lr, &mut vec, None) + alloc::io::default_read_to_end(&mut lr, &mut vec, None) }); } diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 7ccc8d9c6a115..e787e3af9b636 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -2,23 +2,30 @@ #![allow(internal_features)] #![deny(implicit_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] +#![feature(alloc_io)] #![feature(allocator_api)] #![feature(binary_heap_drain_sorted)] #![feature(binary_heap_into_iter_sorted)] #![feature(binary_heap_pop_if)] +#![feature(borrowed_buf_init)] +#![feature(buf_read_has_data_left)] #![feature(casefold)] #![feature(const_btree_len)] #![feature(const_cmp)] #![feature(const_heap)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] +#![feature(core_io_borrowed_buf)] +#![feature(core_io_internals)] #![feature(cow_is_borrowed)] +#![feature(cursor_split)] #![feature(deque_extend_front)] #![feature(downcast_unchecked)] #![feature(drain_keep_rest)] #![feature(exact_size_is_empty)] #![feature(hashmap_internals)] #![feature(inplace_iteration)] +#![feature(io_const_error)] #![feature(iter_advance_by)] #![feature(iter_array_chunks)] #![feature(iter_next_chunk)] @@ -28,6 +35,9 @@ #![feature(map_try_insert)] #![feature(pattern)] #![feature(ptr_cast_slice)] +#![feature(read_buf)] +#![feature(seek_io_take_position)] +#![feature(seek_stream_len)] #![feature(slice_partial_sort_unstable)] #![feature(slice_partition_dedup)] #![feature(slice_ptr_get)] @@ -48,6 +58,7 @@ #![feature(vec_deque_retain_range)] #![feature(vec_peek_mut)] #![feature(vec_try_remove)] +#![feature(write_all_vectored)] // tidy-alphabetical-end extern crate alloc; @@ -67,6 +78,7 @@ mod const_fns; mod cow_str; mod fmt; mod heap; +mod io; mod linked_list; mod misc_tests; mod num; diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 203572c9067b6..d9cbe15c1d4f6 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -294,9 +294,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -#[cfg(test)] -mod tests; - use alloc_crate::io::OsFunctions; #[unstable(feature = "raw_os_error_ty", issue = "107792")] pub use alloc_crate::io::RawOsError; From 125be4beff372ce676908a5e7de60c6bcac7daa7 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Thu, 21 May 2026 11:31:20 +1000 Subject: [PATCH 12/16] Move `std::io::util` tests to `alloctests` --- library/alloctests/tests/io/mod.rs | 2 ++ .../io/util/tests.rs => alloctests/tests/io/util.rs} | 10 +++++----- library/alloctests/tests/lib.rs | 1 + library/std/src/io/mod.rs | 1 - library/std/src/io/util.rs | 2 -- 5 files changed, 8 insertions(+), 8 deletions(-) rename library/{std/src/io/util/tests.rs => alloctests/tests/io/util.rs} (96%) delete mode 100644 library/std/src/io/util.rs diff --git a/library/alloctests/tests/io/mod.rs b/library/alloctests/tests/io/mod.rs index fcc27dbbd73f7..77fd3723ff158 100644 --- a/library/alloctests/tests/io/mod.rs +++ b/library/alloctests/tests/io/mod.rs @@ -1,3 +1,5 @@ +mod util; + use alloc::io::{ self, BorrowedBuf, BufRead, BufReader, Cursor, DEFAULT_BUF_SIZE, IoSlice, Read, Seek, SeekFrom, Write, repeat, diff --git a/library/std/src/io/util/tests.rs b/library/alloctests/tests/io/util.rs similarity index 96% rename from library/std/src/io/util/tests.rs rename to library/alloctests/tests/io/util.rs index ed1d6891577da..52e0c3013dde7 100644 --- a/library/std/src/io/util/tests.rs +++ b/library/alloctests/tests/io/util.rs @@ -1,9 +1,9 @@ -use crate::fmt; -use crate::io::prelude::*; -use crate::io::{ - BorrowedBuf, Empty, ErrorKind, IoSlice, IoSliceMut, Repeat, SeekFrom, Sink, empty, repeat, sink, +use alloc::io::{ + BorrowedBuf, Empty, ErrorKind, IoSlice, IoSliceMut, Read, Repeat, Seek, SeekFrom, Sink, Write, + empty, repeat, sink, }; -use crate::mem::MaybeUninit; +use core::fmt; +use core::mem::MaybeUninit; struct ErrorDisplay; diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index e787e3af9b636..eb9ea287d950f 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -9,6 +9,7 @@ #![feature(binary_heap_pop_if)] #![feature(borrowed_buf_init)] #![feature(buf_read_has_data_left)] +#![feature(can_vector)] #![feature(casefold)] #![feature(const_btree_len)] #![feature(const_cmp)] diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index d9cbe15c1d4f6..385b8081a33ff 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -349,4 +349,3 @@ mod impls; mod pipe; pub mod prelude; mod stdio; -mod util; diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs deleted file mode 100644 index 87c2771955a9d..0000000000000 --- a/library/std/src/io/util.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(test)] -mod tests; From 39bf757d697baad2fae42fc2df9d59bd8e1d7a55 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Thu, 21 May 2026 11:42:23 +1000 Subject: [PATCH 13/16] Move `std::io::cursor` tests to `alloctests` --- .../src/io/cursor/tests.rs => alloctests/tests/io/cursor.rs} | 5 +++-- library/alloctests/tests/io/mod.rs | 1 + library/std/src/io/cursor.rs | 2 -- library/std/src/io/mod.rs | 1 - 4 files changed, 4 insertions(+), 5 deletions(-) rename library/{std/src/io/cursor/tests.rs => alloctests/tests/io/cursor.rs} (99%) delete mode 100644 library/std/src/io/cursor.rs diff --git a/library/std/src/io/cursor/tests.rs b/library/alloctests/tests/io/cursor.rs similarity index 99% rename from library/std/src/io/cursor/tests.rs rename to library/alloctests/tests/io/cursor.rs index d7c203c297fe6..5e863f29af53c 100644 --- a/library/std/src/io/cursor/tests.rs +++ b/library/alloctests/tests/io/cursor.rs @@ -1,5 +1,6 @@ -use crate::io::prelude::*; -use crate::io::{Cursor, IoSlice, IoSliceMut, SeekFrom}; +use alloc::io::{Cursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; + +extern crate test; #[test] fn test_vec_writer() { diff --git a/library/alloctests/tests/io/mod.rs b/library/alloctests/tests/io/mod.rs index 77fd3723ff158..a3fbbf96653cb 100644 --- a/library/alloctests/tests/io/mod.rs +++ b/library/alloctests/tests/io/mod.rs @@ -1,3 +1,4 @@ +mod cursor; mod util; use alloc::io::{ diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs deleted file mode 100644 index 87c2771955a9d..0000000000000 --- a/library/std/src/io/cursor.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(test)] -mod tests; diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 385b8081a33ff..9cb63ebe9cd72 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -343,7 +343,6 @@ pub use self::stdio::{set_output_capture, try_set_output_capture}; mod buffered; mod copy; -mod cursor; mod error; mod impls; mod pipe; From f67f57d68c00f11620ddaf7736d86e199a341583 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Thu, 21 May 2026 11:45:18 +1000 Subject: [PATCH 14/16] Move `std::io::buffered` tests to `alloctests` --- .../tests/io/buffered.rs} | 31 ++++++++++--------- library/alloctests/tests/io/mod.rs | 1 + library/std/src/io/buffered/mod.rs | 4 --- library/std/src/io/mod.rs | 1 - 4 files changed, 18 insertions(+), 19 deletions(-) rename library/{std/src/io/buffered/tests.rs => alloctests/tests/io/buffered.rs} (98%) delete mode 100644 library/std/src/io/buffered/mod.rs diff --git a/library/std/src/io/buffered/tests.rs b/library/alloctests/tests/io/buffered.rs similarity index 98% rename from library/std/src/io/buffered/tests.rs rename to library/alloctests/tests/io/buffered.rs index ff4585a60cae9..0abaa63870e15 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/alloctests/tests/io/buffered.rs @@ -1,10 +1,14 @@ -use crate::io::prelude::*; -use crate::io::{ - self, BorrowedBuf, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom, +//! Tests for buffering wrappers for I/O traits + +use alloc::io::{ + self, BorrowedBuf, BufRead, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, Read, Seek, + SeekFrom, Write, }; -use crate::mem::MaybeUninit; -use crate::sync::atomic::{AtomicUsize, Ordering}; -use crate::{panic, thread}; +use core::mem::MaybeUninit; +use core::sync::atomic::{AtomicUsize, Ordering}; +use std::{panic, thread}; + +extern crate test; /// A dummy reader intended at testing short-reads propagation. pub struct ShortReader { @@ -488,7 +492,7 @@ fn dont_panic_in_drop_on_panicked_flush() { } #[test] -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn panic_in_write_doesnt_flush_in_drop() { static WRITES: AtomicUsize = AtomicUsize::new(0); @@ -504,12 +508,11 @@ fn panic_in_write_doesnt_flush_in_drop() { } } - thread::spawn(|| { + panic::catch_unwind(panic::AssertUnwindSafe(|| { let mut writer = BufWriter::new(PanicWriter); let _ = writer.write(b"hello world"); let _ = writer.flush(); - }) - .join() + })) .unwrap_err(); assert_eq!(WRITES.load(Ordering::SeqCst), 1); @@ -681,7 +684,7 @@ fn line_vectored() { #[test] fn line_vectored_partial_and_errors() { - use crate::collections::VecDeque; + use alloc::collections::VecDeque; enum Call { Write { inputs: Vec<&'static [u8]>, output: io::Result }, @@ -1150,7 +1153,7 @@ struct WriteRecorder { impl Write for WriteRecorder { fn write(&mut self, buf: &[u8]) -> io::Result { - use crate::str::from_utf8; + use core::str::from_utf8; self.events.push(RecordedEvent::Write(from_utf8(buf).unwrap().to_string())); Ok(buf.len()) @@ -1183,7 +1186,7 @@ fn single_formatted_write() { fn bufreader_full_initialize() { struct OneByteReader; impl Read for OneByteReader { - fn read(&mut self, buf: &mut [u8]) -> crate::io::Result { + fn read(&mut self, buf: &mut [u8]) -> alloc::io::Result { if buf.len() > 0 { buf[0] = 0; Ok(1) @@ -1206,7 +1209,7 @@ fn bufreader_full_initialize() { /// This is a regression test for https://github.com/rust-lang/rust/issues/127584. #[test] fn bufwriter_aliasing() { - use crate::io::{BufWriter, Cursor}; + use alloc::io::{BufWriter, Cursor}; let mut v = vec![0; 1024]; let c = Cursor::new(&mut v); let w = BufWriter::new(Box::new(c)); diff --git a/library/alloctests/tests/io/mod.rs b/library/alloctests/tests/io/mod.rs index a3fbbf96653cb..b0df3b51094ca 100644 --- a/library/alloctests/tests/io/mod.rs +++ b/library/alloctests/tests/io/mod.rs @@ -1,3 +1,4 @@ +mod buffered; mod cursor; mod util; diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs deleted file mode 100644 index 1d09ff7d8dc1c..0000000000000 --- a/library/std/src/io/buffered/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -//! Buffering wrappers for I/O traits - -#[cfg(test)] -mod tests; diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 9cb63ebe9cd72..945de19424f3b 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -341,7 +341,6 @@ pub(crate) use self::stdio::{attempt_print_to_stderr, cleanup}; #[doc(no_inline, hidden)] pub use self::stdio::{set_output_capture, try_set_output_capture}; -mod buffered; mod copy; mod error; mod impls; From 29da936fe337721cdb5c320e2229339cdaa6dd7f Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Mon, 25 May 2026 13:29:57 +1000 Subject: [PATCH 15/16] Move `std::io::impls` benchmarks to `alloctests` --- library/{std/src/io/impls/tests.rs => alloctests/benches/io.rs} | 2 +- library/alloctests/benches/lib.rs | 1 + library/std/src/io/impls.rs | 2 -- library/std/src/io/mod.rs | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) rename library/{std/src/io/impls/tests.rs => alloctests/benches/io.rs} (97%) delete mode 100644 library/std/src/io/impls.rs diff --git a/library/std/src/io/impls/tests.rs b/library/alloctests/benches/io.rs similarity index 97% rename from library/std/src/io/impls/tests.rs rename to library/alloctests/benches/io.rs index d1cd84a67ada5..5ee8263b8cea4 100644 --- a/library/std/src/io/impls/tests.rs +++ b/library/alloctests/benches/io.rs @@ -1,4 +1,4 @@ -use crate::io::prelude::*; +use std::io::prelude::*; #[bench] fn bench_read_slice(b: &mut test::Bencher) { diff --git a/library/alloctests/benches/lib.rs b/library/alloctests/benches/lib.rs index 4b7139d943593..974b389a765d5 100644 --- a/library/alloctests/benches/lib.rs +++ b/library/alloctests/benches/lib.rs @@ -12,6 +12,7 @@ extern crate test; mod binary_heap; mod btree; +mod io; mod linked_list; mod slice; mod str; diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs deleted file mode 100644 index 87c2771955a9d..0000000000000 --- a/library/std/src/io/impls.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(test)] -mod tests; diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 945de19424f3b..ebd69e93fa98f 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -343,7 +343,6 @@ pub use self::stdio::{set_output_capture, try_set_output_capture}; mod copy; mod error; -mod impls; mod pipe; pub mod prelude; mod stdio; From 5b49a9daf874ea1779139d9bf48bec98e9bc4b62 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Sun, 2 Aug 2026 07:08:45 +1000 Subject: [PATCH 16/16] Move `std::io::copy` tests to `alloctests` --- library/alloctests/benches/io.rs | 23 +++++++++++ .../tests.rs => alloctests/tests/io/copy.rs} | 40 +++---------------- library/alloctests/tests/io/mod.rs | 1 + library/std/src/io/copy.rs | 2 - library/std/src/io/mod.rs | 1 - 5 files changed, 29 insertions(+), 38 deletions(-) rename library/{std/src/io/copy/tests.rs => alloctests/tests/io/copy.rs} (74%) delete mode 100644 library/std/src/io/copy.rs diff --git a/library/alloctests/benches/io.rs b/library/alloctests/benches/io.rs index 5ee8263b8cea4..f2e3f2cd3c998 100644 --- a/library/alloctests/benches/io.rs +++ b/library/alloctests/benches/io.rs @@ -55,3 +55,26 @@ fn bench_write_vec(b: &mut test::Bencher) { } }) } + +#[bench] +#[cfg(unix)] +#[cfg_attr(target_os = "emscripten", ignore)] // no /dev +fn bench_copy_buf_reader(b: &mut test::Bencher) { + use std::fs::{File, OpenOptions}; + + let mut file_in = File::open("/dev/zero").expect("opening /dev/zero failed"); + // use dyn to avoid specializations unrelated to readbuf + let dyn_in = &mut file_in as &mut dyn Read; + let mut reader = std::io::BufReader::with_capacity(256 * 1024, dyn_in.take(0)); + let mut writer = + OpenOptions::new().write(true).open("/dev/null").expect("opening /dev/null failed"); + + const BYTES: u64 = 1024 * 1024; + + b.bytes = BYTES; + + b.iter(|| { + reader.get_mut().set_limit(BYTES); + std::io::copy(&mut reader, &mut writer).unwrap() + }); +} diff --git a/library/std/src/io/copy/tests.rs b/library/alloctests/tests/io/copy.rs similarity index 74% rename from library/std/src/io/copy/tests.rs rename to library/alloctests/tests/io/copy.rs index 7bdba3a04416e..485deeaea80e7 100644 --- a/library/std/src/io/copy/tests.rs +++ b/library/alloctests/tests/io/copy.rs @@ -1,7 +1,6 @@ -use crate::cmp::{max, min}; -use crate::collections::VecDeque; -use crate::io; -use crate::io::*; +use alloc::collections::VecDeque; +use alloc::io::{self, *}; +use core::cmp::{max, min}; #[test] fn copy_copies() { @@ -65,7 +64,7 @@ fn copy_specializes_bufreader() { let mut buffered = BufReader::with_capacity(256 * 1024, Cursor::new(&mut source)); let mut sink = Vec::new(); - assert_eq!(crate::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64); + assert_eq!(io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64); assert_eq!(source.as_slice(), sink.as_slice()); let buf_sz = 71 * 1024; @@ -73,7 +72,7 @@ fn copy_specializes_bufreader() { let mut buffered = BufReader::with_capacity(buf_sz, Cursor::new(&mut source)); let mut sink = WriteObserver { observed_buffer: 0 }; - assert_eq!(crate::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64); + assert_eq!(io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64); assert_eq!( sink.observed_buffer, buf_sz, "expected a large buffer to be provided to the writer" @@ -117,32 +116,3 @@ fn copy_specializes_from_slice() { assert_eq!(60 * 1024u64, io::copy(&mut source, &mut sink).unwrap()); assert_eq!(60 * 1024, sink.observed_buffer); } - -#[cfg(unix)] -mod io_benches { - use test::Bencher; - - use crate::fs::{File, OpenOptions}; - use crate::io::BufReader; - use crate::io::prelude::*; - - #[bench] - #[cfg_attr(target_os = "emscripten", ignore)] // no /dev - fn bench_copy_buf_reader(b: &mut Bencher) { - let mut file_in = File::open("/dev/zero").expect("opening /dev/zero failed"); - // use dyn to avoid specializations unrelated to readbuf - let dyn_in = &mut file_in as &mut dyn Read; - let mut reader = BufReader::with_capacity(256 * 1024, dyn_in.take(0)); - let mut writer = - OpenOptions::new().write(true).open("/dev/null").expect("opening /dev/null failed"); - - const BYTES: u64 = 1024 * 1024; - - b.bytes = BYTES; - - b.iter(|| { - reader.get_mut().set_limit(BYTES); - crate::io::copy(&mut reader, &mut writer).unwrap() - }); - } -} diff --git a/library/alloctests/tests/io/mod.rs b/library/alloctests/tests/io/mod.rs index b0df3b51094ca..712e322d79f1c 100644 --- a/library/alloctests/tests/io/mod.rs +++ b/library/alloctests/tests/io/mod.rs @@ -1,4 +1,5 @@ mod buffered; +mod copy; mod cursor; mod util; diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs deleted file mode 100644 index 87c2771955a9d..0000000000000 --- a/library/std/src/io/copy.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(test)] -mod tests; diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index ebd69e93fa98f..c0ed06d5311bc 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -341,7 +341,6 @@ pub(crate) use self::stdio::{attempt_print_to_stderr, cleanup}; #[doc(no_inline, hidden)] pub use self::stdio::{set_output_capture, try_set_output_capture}; -mod copy; mod error; mod pipe; pub mod prelude;