From acfca7a866c3fba220351ce6978f0e74d1c0ca0e Mon Sep 17 00:00:00 2001 From: KevinA-cpu Date: Wed, 2 Sep 2026 23:59:16 +0700 Subject: [PATCH 01/15] Suggest keyword order for `extern "C" const unsafe fn` --- compiler/rustc_parse/src/parser/function.rs | 9 ++++++++- .../wrong-const-async-unsafe-abi.rs | 15 +++++++++++++++ .../wrong-const-async-unsafe-abi.stderr | 15 +++++++++++++++ .../wrong-const-unsafe-abi.rs | 15 +++++++++++++++ .../wrong-const-unsafe-abi.stderr | 15 +++++++++++++++ .../wrong-pub-const-unsafe-abi.rs | 16 ++++++++++++++++ .../wrong-pub-const-unsafe-abi.stderr | 14 ++++++++++++++ 7 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-async-unsafe-abi.rs create mode 100644 tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-async-unsafe-abi.stderr create mode 100644 tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-unsafe-abi.rs create mode 100644 tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-unsafe-abi.stderr create mode 100644 tests/ui/parser/issues/issue-87217-keyword-order/wrong-pub-const-unsafe-abi.rs create mode 100644 tests/ui/parser/issues/issue-87217-keyword-order/wrong-pub-const-unsafe-abi.stderr diff --git a/compiler/rustc_parse/src/parser/function.rs b/compiler/rustc_parse/src/parser/function.rs index 1523aba4be9ab..f3c4e334cfcb7 100644 --- a/compiler/rustc_parse/src/parser/function.rs +++ b/compiler/rustc_parse/src/parser/function.rs @@ -362,6 +362,8 @@ impl<'a> Parser<'a> { }) == Some(true) || // This branch is only for better diagnostics; `pub`, `unsafe`, etc. are not // allowed here. + // This branch also follows `$qual fn` or `$qual $qual` rule + // above since a valid `fn` can be after `extern`. (self.may_recover() && self.tree_look_ahead(2, |tt| { match tt { @@ -374,7 +376,12 @@ impl<'a> Parser<'a> { }) == Some(true) && self.tree_look_ahead(3, |tt| { match tt { - TokenTree::Token(t, _) => t.is_keyword_case(kw::Fn, case), + TokenTree::Token(t, _) => { + t.is_keyword_case(kw::Fn, case) || + ALL_QUALS.iter().any(|exp| { + t.is_keyword(exp.kw) + }) + }, TokenTree::Delimited(..) => false, } }) == Some(true) diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-async-unsafe-abi.rs b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-async-unsafe-abi.rs new file mode 100644 index 0000000000000..24feb12985d75 --- /dev/null +++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-async-unsafe-abi.rs @@ -0,0 +1,15 @@ +// Test for issue https://github.com/rust-lang/rust/issues/140171 +// There is an order to respect for keywords before a function: +// `, const, async, unsafe, extern, ""` +// +// This test ensures the compiler is helpful about them being misplaced. +//@ edition:2018 + +extern "C" const async unsafe fn b() {} +//~^ ERROR expected `fn`, found keyword `const` +//~| NOTE expected `fn` +//~| HELP `const` must come before `extern "C"` +//~| SUGGESTION const extern "C" +//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` + +fn main() {} diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-async-unsafe-abi.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-async-unsafe-abi.stderr new file mode 100644 index 0000000000000..5c065b99444fd --- /dev/null +++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-async-unsafe-abi.stderr @@ -0,0 +1,15 @@ +error: expected `fn`, found keyword `const` + --> $DIR/wrong-const-async-unsafe-abi.rs:7:12 + | +LL | extern "C" const async unsafe fn b() {} + | ^^^^^ expected `fn` + | + = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` +help: `const` must come before `extern "C"` + | +LL - extern "C" const async unsafe fn b() {} +LL + const extern "C" async unsafe fn b() {} + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-unsafe-abi.rs b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-unsafe-abi.rs new file mode 100644 index 0000000000000..fb06dc310571a --- /dev/null +++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-unsafe-abi.rs @@ -0,0 +1,15 @@ +// Test for issue https://github.com/rust-lang/rust/issues/140171 +// There is an order to respect for keywords before a function: +// `, const, async, unsafe, extern, ""` +// +// This test ensures the compiler is helpful about them being misplaced. +//@ edition:2018 + +extern "C" const unsafe fn a() {} +//~^ ERROR expected `fn`, found keyword `const` +//~| NOTE expected `fn` +//~| HELP `const` must come before `extern "C"` +//~| SUGGESTION const extern "C" +//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` + +fn main() {} diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-unsafe-abi.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-unsafe-abi.stderr new file mode 100644 index 0000000000000..2f6c3e7831e53 --- /dev/null +++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-unsafe-abi.stderr @@ -0,0 +1,15 @@ +error: expected `fn`, found keyword `const` + --> $DIR/wrong-const-unsafe-abi.rs:7:12 + | +LL | extern "C" const unsafe fn a() {} + | ^^^^^ expected `fn` + | + = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` +help: `const` must come before `extern "C"` + | +LL - extern "C" const unsafe fn a() {} +LL + const extern "C" unsafe fn a() {} + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-pub-const-unsafe-abi.rs b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-pub-const-unsafe-abi.rs new file mode 100644 index 0000000000000..46ffeda1d40c8 --- /dev/null +++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-pub-const-unsafe-abi.rs @@ -0,0 +1,16 @@ +// Test for issue https://github.com/rust-lang/rust/issues/140171 +// There is an order to respect for keywords before a function: +// `, const, async, unsafe, extern, ""` +// +// This test ensures the compiler is helpful about them being misplaced. +//@ edition:2018 + +unsafe extern "C" { static errno: i32; } + +extern "C" pub const unsafe fn c() {} +//~^ ERROR expected `fn`, found keyword `pub` +//~| NOTE expected `fn` +//~| HELP visibility `pub` must come before `extern "C"` +//~| SUGGESTION pub extern "C" + +fn main() {} diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-pub-const-unsafe-abi.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-pub-const-unsafe-abi.stderr new file mode 100644 index 0000000000000..e07c8cd41aded --- /dev/null +++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-pub-const-unsafe-abi.stderr @@ -0,0 +1,14 @@ +error: expected `fn`, found keyword `pub` + --> $DIR/wrong-pub-const-unsafe-abi.rs:9:12 + | +LL | extern "C" pub const unsafe fn c() {} + | ^^^ expected `fn` + | +help: visibility `pub` must come before `extern "C"` + | +LL - extern "C" pub const unsafe fn c() {} +LL + pub extern "C" const unsafe fn c() {} + | + +error: aborting due to 1 previous error + From 6a8193fef218b872e306da2c738fe8c9897fbd44 Mon Sep 17 00:00:00 2001 From: KevinA-cpu Date: Thu, 3 Sep 2026 10:23:40 +0700 Subject: [PATCH 02/15] re-blessing tests to fix CI --- .../wrong-const-async-unsafe-abi.stderr | 2 +- .../issue-87217-keyword-order/wrong-const-unsafe-abi.stderr | 2 +- .../issue-87217-keyword-order/wrong-pub-const-unsafe-abi.stderr | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-async-unsafe-abi.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-async-unsafe-abi.stderr index 5c065b99444fd..6a28fb9f5595c 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-async-unsafe-abi.stderr +++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-async-unsafe-abi.stderr @@ -1,5 +1,5 @@ error: expected `fn`, found keyword `const` - --> $DIR/wrong-const-async-unsafe-abi.rs:7:12 + --> $DIR/wrong-const-async-unsafe-abi.rs:8:12 | LL | extern "C" const async unsafe fn b() {} | ^^^^^ expected `fn` diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-unsafe-abi.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-unsafe-abi.stderr index 2f6c3e7831e53..97ac70f45570d 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-unsafe-abi.stderr +++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const-unsafe-abi.stderr @@ -1,5 +1,5 @@ error: expected `fn`, found keyword `const` - --> $DIR/wrong-const-unsafe-abi.rs:7:12 + --> $DIR/wrong-const-unsafe-abi.rs:8:12 | LL | extern "C" const unsafe fn a() {} | ^^^^^ expected `fn` diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-pub-const-unsafe-abi.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-pub-const-unsafe-abi.stderr index e07c8cd41aded..56bc4d85a822e 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-pub-const-unsafe-abi.stderr +++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-pub-const-unsafe-abi.stderr @@ -1,5 +1,5 @@ error: expected `fn`, found keyword `pub` - --> $DIR/wrong-pub-const-unsafe-abi.rs:9:12 + --> $DIR/wrong-pub-const-unsafe-abi.rs:10:12 | LL | extern "C" pub const unsafe fn c() {} | ^^^ expected `fn` From 4d9a8b329d10dd43074761d377f81919ec099416 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Tue, 11 Aug 2026 10:13:47 +0100 Subject: [PATCH 03/15] Add test that d32 is not available by default --- tests/ui/asm/arm-high-dregs.baseline.stderr | 8 +++++++ tests/ui/asm/arm-high-dregs.rs | 25 +++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 tests/ui/asm/arm-high-dregs.baseline.stderr create mode 100644 tests/ui/asm/arm-high-dregs.rs diff --git a/tests/ui/asm/arm-high-dregs.baseline.stderr b/tests/ui/asm/arm-high-dregs.baseline.stderr new file mode 100644 index 0000000000000..f9d9fea799135 --- /dev/null +++ b/tests/ui/asm/arm-high-dregs.baseline.stderr @@ -0,0 +1,8 @@ +error: register class `dreg` requires at least one of the following target features: d32, neon + --> $DIR/arm-high-dregs.rs:23:42 + | +LL | asm!("vmov.f64 d16, d0", in("d0") x, out("d16") y); + | ^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/asm/arm-high-dregs.rs b/tests/ui/asm/arm-high-dregs.rs new file mode 100644 index 0000000000000..b12562221811d --- /dev/null +++ b/tests/ui/asm/arm-high-dregs.rs @@ -0,0 +1,25 @@ +//@ add-minicore +//@ only-arm +//@ only-eabihf +//@ ignore-backends: gcc +//@ revisions: baseline target-cpu +//@ [baseline] check-fail +//@ [target-cpu] check-pass +//@ [target-cpu] compile-flags: -Ctarget-cpu=cortex-a5 + +// As well as the error message, this also tests that d32 is not enabled by default on arm hardfloat +// targets and that it can be re-enabled by target-cpu. + +#![feature(f16, no_core)] +#![crate_type = "rlib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[no_mangle] +pub unsafe fn high(x: f64) { + let y: f64; + asm!("vmov.f64 d16, d0", in("d0") x, out("d16") y); + //[baseline]~^ ERROR register class `dreg` requires at least one of the following target features: d32, neon +} From 454090a81ac1628eb141fbd183c0e2fddeb36237 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 3 Sep 2026 15:41:36 +0100 Subject: [PATCH 04/15] Move armv7 targets to the generic LLVM target --- .../rustc_target/src/spec/targets/armv7_linux_androideabi.rs | 4 ++-- .../rustc_target/src/spec/targets/armv7_unknown_freebsd.rs | 4 ++-- .../src/spec/targets/armv7_unknown_linux_gnueabihf.rs | 4 ++-- .../src/spec/targets/armv7_unknown_linux_musleabihf.rs | 4 ++-- .../src/spec/targets/armv7_unknown_linux_uclibceabihf.rs | 2 +- .../src/spec/targets/armv7_unknown_netbsd_eabihf.rs | 4 ++-- .../rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs | 4 ++-- .../src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs | 4 ++-- compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs | 4 ++-- .../rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs | 4 ++-- 10 files changed, 19 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs index 99adc85947aba..109de4dfe313a 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { let mut base = base::android::opts(); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-march=armv7-a"]); Target { - llvm_target: "armv7-none-linux-android".into(), + llvm_target: "arm-none-linux-android".into(), metadata: TargetMetadata { description: Some("Armv7-A Android".into()), tier: Some(2), @@ -28,7 +28,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { cfg_abi: CfgAbi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), - features: "+v7,+thumb-mode,+thumb2,+vfp3d16,-neon".into(), + features: "+v7,+db,+dsp,+aclass,+perfmon,+thumb-mode,+thumb2,+vfp3d16".into(), supported_sanitizers: SanitizerSet::ADDRESS, max_atomic_width: Some(64), ..base diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs index cd6d8b76f1a99..91660d0b1ba76 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs @@ -2,7 +2,7 @@ use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, pub(crate) fn target() -> Target { Target { - llvm_target: "armv7-unknown-freebsd-gnueabihf".into(), + llvm_target: "arm-unknown-freebsd-gnueabihf".into(), metadata: TargetMetadata { description: Some("Armv7-A FreeBSD".into()), tier: Some(3), @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), - features: "+v7,+vfp3d16,+thumb2,-neon".into(), + features: "+v7,+db,+dsp,+aclass,+perfmon,+vfp3d16,+thumb2".into(), max_atomic_width: Some(64), mcount: "\u{1}__gnu_mcount_nc".into(), ..base::freebsd::opts() diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs index 8bf3dfd247229..4cce5f35afd4e 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs @@ -7,7 +7,7 @@ use crate::spec::{ pub(crate) fn target() -> Target { Target { - llvm_target: "armv7-unknown-linux-gnueabihf".into(), + llvm_target: "arm-unknown-linux-gnueabihf".into(), metadata: TargetMetadata { description: Some("Armv7-A Linux, hardfloat (kernel 3.2, glibc 2.17)".into()), tier: Some(2), @@ -21,7 +21,7 @@ pub(crate) fn target() -> Target { cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), // Info about features at https://wiki.debian.org/ArmHardFloatPort - features: "+v7,+vfp3d16,+thumb2,-neon".into(), + features: "+v7,+db,+dsp,+aclass,+perfmon,+vfp3d16,+thumb2".into(), max_atomic_width: Some(64), mcount: "\u{1}__gnu_mcount_nc".into(), llvm_mcount_intrinsic: Some("llvm.arm.gnu.eabi.mcount".into()), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs index 6ce45de909a8b..39c45161082ab 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs @@ -4,7 +4,7 @@ use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, pub(crate) fn target() -> Target { Target { - llvm_target: "armv7-unknown-linux-musleabihf".into(), + llvm_target: "arm-unknown-linux-musleabihf".into(), metadata: TargetMetadata { description: Some("Armv7-A Linux with musl 1.2.5, hardfloat".into()), tier: Some(2), @@ -20,7 +20,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), - features: "+v7,+vfp3d16,+thumb2,-neon".into(), + features: "+v7,+db,+dsp,+aclass,+perfmon,+vfp3d16,+thumb2".into(), max_atomic_width: Some(64), mcount: "\u{1}mcount".into(), // FIXME(compiler-team#422): musl targets should be dynamically linked by default. diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs index 63845a1a555c5..f585f890cb2f9 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { // Info about features at https://wiki.debian.org/ArmHardFloatPort - features: "+v7,+vfp3d16,+thumb2,-neon".into(), + features: "+v7,+db,+dsp,+aclass,+perfmon,+vfp3d16,+thumb2".into(), cpu: "generic".into(), max_atomic_width: Some(64), mcount: "_mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs index 4000e395c5bcb..2c4582871d410 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs @@ -2,7 +2,7 @@ use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, pub(crate) fn target() -> Target { Target { - llvm_target: "armv7-unknown-netbsdelf-eabihf".into(), + llvm_target: "arm-unknown-netbsdelf-eabihf".into(), metadata: TargetMetadata { description: Some("Armv7-A NetBSD w/hard-float".into()), tier: Some(3), @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), - features: "+v7,+vfp3d16,+thumb2,-neon".into(), + features: "+v7,+db,+dsp,+aclass,+perfmon,+vfp3d16,+thumb2".into(), max_atomic_width: Some(64), mcount: "__mcount".into(), ..base::netbsd::opts() diff --git a/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs index 63f82a0d7e68d..5a1798263cd48 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs @@ -2,7 +2,7 @@ use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, pub(crate) fn target() -> Target { Target { - llvm_target: "armv7-unknown-linux-gnueabihf".into(), + llvm_target: "arm-unknown-linux-gnueabihf".into(), metadata: TargetMetadata { description: Some("Armv7-A for VxWorks".into()), tier: Some(3), @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), // Info about features at https://wiki.debian.org/ArmHardFloatPort - features: "+v7,+vfp3d16,+thumb2,-neon".into(), + features: "+v7,+db,+dsp,+aclass,+perfmon,+vfp3d16,+thumb2".into(), max_atomic_width: Some(64), ..base::vxworks::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs index b59ce32b48e04..eac437ffdf2a5 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs @@ -5,7 +5,7 @@ use crate::spec::{ pub(crate) fn target() -> Target { let base = base::solid::opts(); Target { - llvm_target: "armv7a-none-eabihf".into(), + llvm_target: "arm-none-eabihf".into(), metadata: TargetMetadata { description: Some("Arm SOLID with TOPPERS/ASP3, hardfloat".into()), tier: Some(3), @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), linker: Some("arm-kmc-eabi-gcc".into()), - features: "+v7,+vfp3d16,+thumb2,-neon".into(), + features: "+v7,+db,+dsp,+aclass,+perfmon,+vfp3d16,+thumb2".into(), relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs index cbeb409110ff7..baca5c7c0b024 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs @@ -4,7 +4,7 @@ use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, pub(crate) fn target() -> Target { Target { - llvm_target: "armv7a-none-eabihf".into(), + llvm_target: "arm-none-eabihf".into(), metadata: TargetMetadata { description: Some("Bare Armv7-A, hardfloat".into()), tier: Some(2), @@ -17,7 +17,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), - features: "+vfp3d16,-neon,+strict-align".into(), + features: "+v7,+db,+dsp,+aclass,+perfmon,+vfp3d16,+strict-align".into(), max_atomic_width: Some(64), has_thumb_interworking: true, ..base::arm_none::opts() diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs index 4baa73c3cdb8b..0b5d8afb170cd 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs @@ -4,7 +4,7 @@ use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, pub(crate) fn target() -> Target { Target { - llvm_target: "thumbv7a-none-eabihf".into(), + llvm_target: "thumb-none-eabihf".into(), metadata: TargetMetadata { description: Some("Thumb-mode Bare Armv7-A, hardfloat".into()), tier: Some(2), @@ -17,7 +17,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), - features: "+vfp3d16,-neon,+strict-align".into(), + features: "+v7,+db,+dsp,+aclass,+perfmon,+vfp3d16,+strict-align".into(), max_atomic_width: Some(64), has_thumb_interworking: true, ..base::arm_none::opts() From c701054fcef7b0fcdfcb8105eabf7c45ae16cda6 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Tue, 11 Aug 2026 17:19:28 +0100 Subject: [PATCH 05/15] Fix VFP levels docs for armv7a-none-eabi --- src/doc/rustc/src/platform-support/armv7a-none-eabi.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc/src/platform-support/armv7a-none-eabi.md b/src/doc/rustc/src/platform-support/armv7a-none-eabi.md index 1ad81f264cbf4..3b927a573e30c 100644 --- a/src/doc/rustc/src/platform-support/armv7a-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv7a-none-eabi.md @@ -49,10 +49,10 @@ disabled as needed with `-C target-feature=(+/-)`. In general, the following four combinations are possible: -- VFPv3-D16, target feature `+vfp3` and `-d32` -- VFPv3-D32, target feature `+vfp3` and `+d32` -- VFPv4-D16, target feature `+vfp4` and `-d32` -- VFPv4-D32, target feature `+vfp4` and `+d32` +- VFPv3-D16, target default +- VFPv3-D32, target feature `+d32` +- VFPv4-D16, llvm target feature `+vfp4d16` +- VFPv4-D32, target feature `+vfp4` An Armv7-A processor may optionally include a NEON hardware unit which provides Single Instruction Multiple Data (SIMD) operations. The From 55469d6a61837d4c8d59dc5e973804e42b86ae4b Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Fri, 4 Sep 2026 12:54:24 +0100 Subject: [PATCH 06/15] Remove the last -d32 from armv6 HF targets --- compiler/rustc_target/src/spec/targets/armv6_none_eabihf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/armv6_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv6_none_eabihf.rs index d4886ee16e91a..8c3cf553adaf8 100644 --- a/compiler/rustc_target/src/spec/targets/armv6_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv6_none_eabihf.rs @@ -18,7 +18,7 @@ pub(crate) fn target() -> Target { cfg_abi: CfgAbi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), asm_args: cvs!["-mthumb-interwork", "-march=armv6", "-mlittle-endian",], - features: "+strict-align,+v6k,+vfp2,-d32".into(), + features: "+strict-align,+v6k,+vfp2".into(), atomic_cas: true, has_thumb_interworking: true, // LDREXD/STREXD available as of ARMv6K From 1699fba7fba16a06271b633e897b20dbf01d5ed1 Mon Sep 17 00:00:00 2001 From: malezjaa Date: Fri, 11 Sep 2026 07:57:45 +0200 Subject: [PATCH 07/15] hir_typeck: Don't ICE on closures without drop location in closure capture lint `drop_location_span` assumed that every closure had a valid drop location, which could cause an ICE for closures in unsupported contexts. This changes `drop_location_span` to return `Option`. If there is no valid drop location, the migration lint is not emitted because its drop-order diagnostic would be misleading. The span is computed before creating `MigrationLint` and stored there so it can be reused for the drop-order labels. --- compiler/rustc_hir_typeck/src/upvar.rs | 76 +++++++++++-------- tests/crashes/156288.rs | 3 - ...mpatible-captures-without-drop-location.rs | 22 ++++++ ...ible-captures-without-drop-location.stderr | 66 ++++++++++++++++ 4 files changed, 132 insertions(+), 35 deletions(-) delete mode 100644 tests/crashes/156288.rs create mode 100644 tests/ui/closures/2229_closure_analysis/incompatible-captures-without-drop-location.rs create mode 100644 tests/ui/closures/2229_closure_analysis/incompatible-captures-without-drop-location.stderr diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 72886730f18c5..d8e9dc3e34a8b 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -992,6 +992,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { struct MigrationLint<'a, 'tcx> { closure_def_id: LocalDefId, + closure_drop_location_span: Span, this: &'a FnCtxt<'a, 'tcx>, body_id: hir::BodyId, need_migrations: Vec, @@ -1000,8 +1001,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl<'a, 'b, 'tcx> Diagnostic<'a, ()> for MigrationLint<'b, 'tcx> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { - let Self { closure_def_id, this, body_id, need_migrations, migration_message } = - self; + let Self { + closure_def_id, + closure_drop_location_span, + this, + body_id, + need_migrations, + migration_message, + } = self; let mut lint = Diag::new(dcx, level, migration_message); let (migration_string, migrated_variables_concat) = @@ -1034,25 +1041,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => {} } - // Add a label pointing to where a captured variable affected by drop order - // is dropped + // Add a label pointing to where a captured variable affected by drop + // order is dropped. if lint_note.reason.drop_order { - let drop_location_span = drop_location_span(this.tcx, closure_hir_id); - + let var_name = this.tcx.hir_name(*var_hir_id); match &lint_note.captures_info { UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => { - lint.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure", - this.tcx.hir_name(*var_hir_id), - captured_name, - )); + lint.span_label( + closure_drop_location_span, + format!( + "in Rust 2018, `{var_name}` is dropped here, but in Rust 2021, \ + only `{captured_name}` will be dropped here as part of the closure" + ), + ); } UpvarMigrationInfo::CapturingNothing { use_span: _ } => { - lint.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure", - v = this.tcx.hir_name(*var_hir_id), - )); + lint.span_label( + closure_drop_location_span, + format!( + "in Rust 2018, `{var_name}` is dropped here along with \ + the closure, but in Rust 2021 `{var_name}` is not part \ + of the closure" + ), + ); } } } @@ -1189,13 +1203,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.typeck_results.borrow().closure_min_captures.get(&closure_def_id), ); - if !need_migrations.is_empty() { + // Without a valid drop location, the closure syntax is invalid, and + // emitted lints become nonsensical. + if !need_migrations.is_empty() + && let Some(drop_location_span) = + drop_location_span(self.tcx, self.tcx.local_def_id_to_hir_id(closure_def_id)) + { self.tcx.emit_node_span_lint( RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, self.tcx.local_def_id_to_hir_id(closure_def_id), self.tcx.def_span(closure_def_id), MigrationLint { this: self, + closure_drop_location_span: drop_location_span, migration_message: reasons.migration_message(), closure_def_id, body_id, @@ -2056,25 +2076,17 @@ fn apply_capture_kind_on_capture_ty<'tcx>( } /// Returns the Span of where the value with the provided HirId would be dropped -fn drop_location_span(tcx: TyCtxt<'_>, hir_id: HirId) -> Span { - let owner_id = tcx.hir_get_enclosing_scope(hir_id).unwrap(); - - let owner_node = tcx.hir_node(owner_id); - let owner_span = match owner_node { - hir::Node::Item(item) => match item.kind { - hir::ItemKind::Fn { body: owner_id, .. } => tcx.hir_span(owner_id.hir_id), - _ => { - bug!("Drop location span error: need to handle more ItemKind '{:?}'", item.kind); - } - }, - hir::Node::Block(block) => tcx.hir_span(block.hir_id), - hir::Node::TraitItem(item) => tcx.hir_span(item.hir_id()), - hir::Node::ImplItem(item) => tcx.hir_span(item.hir_id()), - _ => { - bug!("Drop location span error: need to handle more Node '{:?}'", owner_node); - } +fn drop_location_span(tcx: TyCtxt<'_>, hir_id: HirId) -> Option { + let owner_id = tcx.hir_get_enclosing_scope(hir_id)?; + + let hir_id = match tcx.hir_node(owner_id) { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { body, .. }, .. }) => body.hir_id, + hir::Node::Block(block) => block.hir_id, + hir::Node::TraitItem(item) => item.hir_id(), + hir::Node::ImplItem(item) => item.hir_id(), + _ => return None, }; - tcx.sess.source_map().end_point(owner_span) + Some(tcx.sess.source_map().end_point(tcx.hir_span(hir_id))) } struct InferBorrowKind<'a, 'tcx> { diff --git a/tests/crashes/156288.rs b/tests/crashes/156288.rs deleted file mode 100644 index b745cfe063dda..0000000000000 --- a/tests/crashes/156288.rs +++ /dev/null @@ -1,3 +0,0 @@ -//@ known-bug: #156288 -#[warn(rust_2021_incompatible_closure_captures)] -const _: () = |b| move || b; diff --git a/tests/ui/closures/2229_closure_analysis/incompatible-captures-without-drop-location.rs b/tests/ui/closures/2229_closure_analysis/incompatible-captures-without-drop-location.rs new file mode 100644 index 0000000000000..893c9c9f1e356 --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/incompatible-captures-without-drop-location.rs @@ -0,0 +1,22 @@ +//@ edition:2018 + +#[warn(rust_2021_incompatible_closure_captures)] +enum Functions { + Square = |b| move || format!("{b}"), + //~^ ERROR mismatched types +} + +#[warn(rust_2021_incompatible_closure_captures)] +static _static: () = |b| move || b; +//~^ ERROR mismatched types + +fn main() { + #[warn(rust_2021_incompatible_closure_captures)] + const _: () = |b| move || b; + //~^ ERROR mismatched types + + #[warn(rust_2021_incompatible_closure_captures)] + let _: () = |b| move || b; + //~^ ERROR mismatched types + //~| WARN changes to closure capture in Rust 2021 will affect drop order +} diff --git a/tests/ui/closures/2229_closure_analysis/incompatible-captures-without-drop-location.stderr b/tests/ui/closures/2229_closure_analysis/incompatible-captures-without-drop-location.stderr new file mode 100644 index 0000000000000..9798f783a4f1b --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/incompatible-captures-without-drop-location.stderr @@ -0,0 +1,66 @@ +error[E0308]: mismatched types + --> $DIR/incompatible-captures-without-drop-location.rs:5:14 + | +LL | Square = |b| move || format!("{b}"), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `isize`, found closure + | + = note: expected type `isize` + found closure `{closure@$DIR/incompatible-captures-without-drop-location.rs:5:14: 5:17}` + = note: enum variant discriminant can only be of a primitive type compatible with the enum's `repr` + +error[E0308]: mismatched types + --> $DIR/incompatible-captures-without-drop-location.rs:10:22 + | +LL | static _static: () = |b| move || b; + | -- ^^^^^^^^^^^^^ expected `()`, found closure + | | + | expected because of the type of the static + | + = note: expected unit type `()` + found closure `{closure@$DIR/incompatible-captures-without-drop-location.rs:10:22: 10:25}` + +error[E0308]: mismatched types + --> $DIR/incompatible-captures-without-drop-location.rs:19:17 + | +LL | let _: () = |b| move || b; + | -- ^^^^^^^^^^^^^ expected `()`, found closure + | | + | expected due to this + | + = note: expected unit type `()` + found closure `{closure@$DIR/incompatible-captures-without-drop-location.rs:19:17: 19:20}` + +warning: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/incompatible-captures-without-drop-location.rs:19:21 + | +LL | let _: () = |b| move || b; + | ^^^^^^^ - in Rust 2018, this causes the closure to capture `b`, but in Rust 2021, it has no effect +... +LL | } + | - in Rust 2018, `b` is dropped here along with the closure, but in Rust 2021 `b` is not part of the closure + | + = note: for more information, see +note: the lint level is defined here + --> $DIR/incompatible-captures-without-drop-location.rs:18:12 + | +LL | #[warn(rust_2021_incompatible_closure_captures)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a dummy let to cause `b` to be fully captured + | +LL | let _: () = |b| move || { let _ = &b; b }; + | +++++++++++++ + + +error[E0308]: mismatched types + --> $DIR/incompatible-captures-without-drop-location.rs:15:19 + | +LL | const _: () = |b| move || b; + | -- ^^^^^^^^^^^^^ expected `()`, found closure + | | + | expected because of the type of the constant + | + = note: expected unit type `()` + found closure `{closure@$DIR/incompatible-captures-without-drop-location.rs:15:19: 15:22}` + +error: aborting due to 4 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. From 3add62de54bbabd2883c50720046569aa2cf7ea3 Mon Sep 17 00:00:00 2001 From: albab-hasan Date: Fri, 11 Sep 2026 18:25:21 +0600 Subject: [PATCH 08/15] dont suggest changing the mutability of a borrow inside a macro the suggestion rewrote the borrow where it was written. for a borrow coming from a macro body that is the macro definition rather than the call site, and for a macro from another crate a file the user cannot edit. it was machine applicable so rustfix would apply it and a macro invoked at more than one call site could stop compiling. gate it on can_be_used_for_suggestions so those cases fall through to the existing note that the trait is implemented for the mutable borrow but not the shared one. --- .../src/error_reporting/traits/suggestions.rs | 9 ++++- .../suggestions/auxiliary/mut_borrow_macro.rs | 6 +++ .../suggestions/change-mut-borrow-in-macro.rs | 26 ++++++++++++ .../change-mut-borrow-in-macro.stderr | 40 +++++++++++++++++++ 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 tests/ui/suggestions/auxiliary/mut_borrow_macro.rs create mode 100644 tests/ui/suggestions/change-mut-borrow-in-macro.rs create mode 100644 tests/ui/suggestions/change-mut-borrow-in-macro.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 95bb2fd7e40c5..32eb2deabb198 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -2530,7 +2530,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .sess .source_map() .span_take_while(span, |c| c.is_whitespace() || *c == '&'); - if points_at_arg && mutability.is_not() && refs_number > 0 { + if points_at_arg + && mutability.is_not() + && refs_number > 0 + // The borrow can sit in a macro body, where rewriting it would edit the + // macro definition and so every one of its call sites, or a crate the user + // does not own. Fall through to the note in that case. + && span.can_be_used_for_suggestions() + { // If we have a call like foo(&mut buf), then don't suggest foo(&mut mut buf) if snippet .trim_start_matches(|c: char| c.is_whitespace() || c == '&') diff --git a/tests/ui/suggestions/auxiliary/mut_borrow_macro.rs b/tests/ui/suggestions/auxiliary/mut_borrow_macro.rs new file mode 100644 index 0000000000000..ae693d9eeddb4 --- /dev/null +++ b/tests/ui/suggestions/auxiliary/mut_borrow_macro.rs @@ -0,0 +1,6 @@ +#[macro_export] +macro_rules! call_it { + ($f:expr) => { + (0..100).for_each(&$f) + }; +} diff --git a/tests/ui/suggestions/change-mut-borrow-in-macro.rs b/tests/ui/suggestions/change-mut-borrow-in-macro.rs new file mode 100644 index 0000000000000..831c0632009aa --- /dev/null +++ b/tests/ui/suggestions/change-mut-borrow-in-macro.rs @@ -0,0 +1,26 @@ +//@ edition: 2021 +//@ aux-build: mut_borrow_macro.rs + +// The borrow that needs to become `&mut` lives in a macro body, so rewriting it would edit the +// macro definition rather than the call site, and for an external macro a file the user does not +// own. + +extern crate mut_borrow_macro; + +macro_rules! local_call_it { + ($f:expr) => { + (0..100).for_each(&$f) + }; +} + +fn main() { + let mut value = 0; + let mut func = |increment: usize| value += increment; + //~^ ERROR expected a closure that implements the `Fn` trait + local_call_it!(func); + + let mut other = 0; + let mut other_func = |increment: usize| other += increment; + //~^ ERROR expected a closure that implements the `Fn` trait + mut_borrow_macro::call_it!(other_func); +} diff --git a/tests/ui/suggestions/change-mut-borrow-in-macro.stderr b/tests/ui/suggestions/change-mut-borrow-in-macro.stderr new file mode 100644 index 0000000000000..b574ef3270710 --- /dev/null +++ b/tests/ui/suggestions/change-mut-borrow-in-macro.stderr @@ -0,0 +1,40 @@ +error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut` + --> $DIR/change-mut-borrow-in-macro.rs:18:20 + | +LL | (0..100).for_each(&$f) + | -------- --- the requirement to implement `Fn` derives from here + | | + | required by a bound introduced by this call +... +LL | let mut func = |increment: usize| value += increment; + | ^^^^^^^^^^^^^^^^^^ ----- closure is `FnMut` because it mutates the variable `value` here + | | + | this closure implements `FnMut`, not `Fn` + | + = note: `FnMut(usize)` is implemented for `&mut {closure@$DIR/change-mut-borrow-in-macro.rs:18:20: 18:38}`, but not for `&{closure@$DIR/change-mut-borrow-in-macro.rs:18:20: 18:38}` + = note: required for `&{closure@$DIR/change-mut-borrow-in-macro.rs:18:20: 18:38}` to implement `FnMut(usize)` +note: required by a bound in `for_each` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + +error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut` + --> $DIR/change-mut-borrow-in-macro.rs:23:26 + | +LL | let mut other_func = |increment: usize| other += increment; + | ^^^^^^^^^^^^^^^^^^ ----- closure is `FnMut` because it mutates the variable `other` here + | | + | this closure implements `FnMut`, not `Fn` +LL | +LL | mut_borrow_macro::call_it!(other_func); + | -------------------------------------- + | | + | the requirement to implement `Fn` derives from here + | required by a bound introduced by this call + | + = note: `FnMut(usize)` is implemented for `&mut {closure@$DIR/change-mut-borrow-in-macro.rs:23:26: 23:44}`, but not for `&{closure@$DIR/change-mut-borrow-in-macro.rs:23:26: 23:44}` + = note: required for `&{closure@$DIR/change-mut-borrow-in-macro.rs:23:26: 23:44}` to implement `FnMut(usize)` +note: required by a bound in `for_each` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0525`. From 4750ec7ba03a5499e9777a06172d00378a5649a5 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 11 Sep 2026 14:35:59 +0000 Subject: [PATCH 09/15] Fix `*_trailing_sep` for Windows verbatim paths --- library/std/src/path.rs | 6 ++++-- library/std/tests/path.rs | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 141bc72fb2e42..f06625613ec00 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2983,7 +2983,8 @@ impl Path { #[must_use] #[inline] pub fn has_trailing_sep(&self) -> bool { - self.as_os_str().as_encoded_bytes().last().copied().is_some_and(is_sep_byte) + let comps = self.components(); + self.as_os_str().as_encoded_bytes().last().copied().is_some_and(|b| comps.is_sep_byte(b)) } /// Ensures that a path has a trailing [separator](MAIN_SEPARATOR), @@ -3034,10 +3035,11 @@ impl Path { #[must_use] #[inline] pub fn trim_trailing_sep(&self) -> &Path { + let comps = self.components(); if self.has_trailing_sep() && (!self.has_root() || self.parent().is_some()) { let mut bytes = self.inner.as_encoded_bytes(); while let Some((last, init)) = bytes.split_last() - && is_sep_byte(*last) + && comps.is_sep_byte(*last) { bytes = init; } diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs index 4d42437fbd871..10bfe9eb2bd6c 100644 --- a/library/std/tests/path.rs +++ b/library/std/tests/path.rs @@ -2597,3 +2597,20 @@ fn test_trim_trailing_sep() { assert_eq!(Path::new("c:..\\\\").trim_trailing_sep().as_os_str(), OsStr::new("c:..")); } } + +#[cfg(windows)] +#[test] +fn trailing_sep_verbatim() { + assert_eq!(Path::new(r"\\?\C:\path").has_trailing_sep(), false); + assert_eq!(Path::new(r"\\?\C:\path/").has_trailing_sep(), false); + assert_eq!(Path::new(r"\\?\C:\path\").has_trailing_sep(), true); + assert_eq!(Path::new(r"\\?\C:\").has_trailing_sep(), true); + assert_eq!(Path::new(r"\\?\C:/").has_trailing_sep(), false); + + assert_eq!(Path::new(r"\\?\C:\path").trim_trailing_sep(), Path::new(r"\\?\C:\path")); + assert_eq!(Path::new(r"\\?\C:\path/").trim_trailing_sep(), Path::new(r"\\?\C:\path/")); + assert_eq!(Path::new(r"\\?\C:\path\").trim_trailing_sep(), Path::new(r"\\?\C:\path")); + assert_eq!(Path::new(r"\\?\C:\path/\\\").trim_trailing_sep(), Path::new(r"\\?\C:\path/")); + assert_eq!(Path::new(r"\\?\C:\").trim_trailing_sep(), Path::new(r"\\?\C:\")); + assert_eq!(Path::new(r"\\?\C:/").trim_trailing_sep(), Path::new(r"\\?\C:/")); +} From 0f916bb57936422a46d62c812d1ce974ce0f1e8e Mon Sep 17 00:00:00 2001 From: Mikhail Baykov Date: Sun, 23 Aug 2026 09:22:33 -0400 Subject: [PATCH 10/15] std: Make a lot of pub items crate private instead (ignore os/sys) Most of them don't need to be public, but there are scenarios where thing is private on one platform but public on the other, so having a lint on all the time gets complicated. Added #![warn(unreachable_pub)] in library/std/src/lib.rs Added #[allow(unreachable_pub)] on top of std::os and std::sys specifically. --- library/std/src/collections/hash/mod.rs | 4 ++-- library/std/src/fs/tests.rs | 2 +- library/std/src/io/stdio.rs | 2 +- library/std/src/lib.rs | 3 +++ library/std/src/panicking.rs | 10 +++++----- library/std/src/process/tests.rs | 8 ++++---- library/std/src/sync/mpmc/context.rs | 14 +++++++------- library/std/src/sync/mpmc/select.rs | 8 ++++---- library/std/src/sync/mpmc/utils.rs | 12 ++++++------ library/std/src/sync/mpmc/waker.rs | 2 +- library/std/src/sync/poison.rs | 16 ++++++++-------- library/std/src/test_helpers.rs | 8 ++++---- library/std/src/thread/lifecycle.rs | 2 +- library/std/src/thread/thread.rs | 4 ++-- 14 files changed, 49 insertions(+), 46 deletions(-) diff --git a/library/std/src/collections/hash/mod.rs b/library/std/src/collections/hash/mod.rs index 348820af54bff..0476b0206f3d7 100644 --- a/library/std/src/collections/hash/mod.rs +++ b/library/std/src/collections/hash/mod.rs @@ -1,4 +1,4 @@ //! Unordered containers, implemented as hash-tables -pub mod map; -pub mod set; +pub(crate) mod map; +pub(crate) mod set; diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index dab1df38aa1f5..148f1c32b08b9 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -45,7 +45,7 @@ macro_rules! error_contains { // have permission, and return otherwise. This way, we still don't run these // tests most of the time, but at least we do if the user has the right // permissions. -pub fn got_symlink_permission(tmpdir: &TempDir) -> bool { +pub(crate) fn got_symlink_permission(tmpdir: &TempDir) -> bool { if cfg!(not(windows)) || env::var_os("CI").is_some() { return true; } diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index b104ea69cd1fc..527671442fb72 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -726,7 +726,7 @@ pub fn stdout() -> Stdout { // Flush the data and disable buffering during shutdown // by replacing the line writer by one with zero // buffering capacity. -pub fn cleanup() { +pub(crate) fn cleanup() { let mut initialized = false; let stdout = STDOUT.get_or_init(|| { initialized = true; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 18ff174af2375..5f98aa54a6620 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -241,6 +241,7 @@ // Lints: #![warn(deprecated_in_future)] #![warn(missing_docs)] +#![warn(unreachable_pub)] #![warn(missing_debug_implementations)] #![allow(explicit_outlives_requirements)] #![allow(unused_lifetimes)] @@ -640,6 +641,7 @@ pub mod hash; pub mod io; pub mod net; pub mod num; +#[allow(unreachable_pub)] pub mod os; pub mod panic; #[unstable(feature = "pattern_type_macro", issue = "123646")] @@ -730,6 +732,7 @@ pub mod arch { #[stable(feature = "simd_x86", since = "1.27.0")] pub use std_detect::is_x86_feature_detected; +#[allow(unreachable_pub)] mod sys; pub mod alloc; diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 5a4684a973942..f69e0a749f579 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -41,7 +41,7 @@ use crate::{fmt, intrinsics, process, thread}; #[doc(hidden)] #[allow(dead_code)] #[used(compiler)] -pub static EMPTY_PANIC: fn(&'static str) -> ! = +pub(crate) static EMPTY_PANIC: fn(&'static str) -> ! = begin_panic::<&'static str> as fn(&'static str) -> !; // Binary interface to the panic runtime that the standard library depends on. @@ -495,7 +495,7 @@ pub unsafe fn catch_unwind R>(f: F) -> Result R>(f: F) -> Result> { +pub(crate) unsafe fn catch_unwind R>(f: F) -> Result> { union Data { f: ManuallyDrop, r: ManuallyDrop, @@ -599,14 +599,14 @@ pub unsafe fn catch_unwind R>(f: F) -> Result bool { +pub(crate) fn panicking() -> bool { !panic_count::count_is_zero() } /// Entry point of panics from the core crate (`panic_impl` lang item). #[cfg(not(any(test, doctest)))] #[panic_handler] -pub fn panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { +pub(crate) fn panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { struct FormatStringPayload<'a> { inner: &'a core::panic::PanicMessage<'a>, string: Option, @@ -839,7 +839,7 @@ fn panic_with_hook( /// This is the entry point for `resume_unwind`. /// It just forwards the payload to the panic runtime. #[cfg_attr(panic = "immediate-abort", inline)] -pub fn resume_unwind(payload: Box) -> ! { +pub(crate) fn resume_unwind(payload: Box) -> ! { if let Some(must_abort) = panic_count::increase(false) { match must_abort { panic_count::MustAbort::PanicInHook => { diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index 35ce30f1146e4..e31cb002c0265 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -95,7 +95,7 @@ fn signal_reported_right() { } } -pub fn run_output(mut cmd: Command) -> String { +pub(crate) fn run_output(mut cmd: Command) -> String { let p = cmd.spawn(); assert!(p.is_ok()); let mut p = p.unwrap(); @@ -361,18 +361,18 @@ fn test_wait_with_output_once() { } #[cfg(all(unix, not(target_os = "android")))] -pub fn env_cmd() -> Command { +pub(crate) fn env_cmd() -> Command { Command::new("env") } #[cfg(target_os = "android")] -pub fn env_cmd() -> Command { +pub(crate) fn env_cmd() -> Command { let mut cmd = Command::new("/system/bin/sh"); cmd.arg("-c").arg("set"); cmd } #[cfg(windows)] -pub fn env_cmd() -> Command { +pub(crate) fn env_cmd() -> Command { let mut cmd = Command::new("cmd"); cmd.arg("/c").arg("set"); cmd diff --git a/library/std/src/sync/mpmc/context.rs b/library/std/src/sync/mpmc/context.rs index 6b2f4cb6ffd29..b4fee60a574ff 100644 --- a/library/std/src/sync/mpmc/context.rs +++ b/library/std/src/sync/mpmc/context.rs @@ -11,7 +11,7 @@ use crate::time::Instant; /// Thread-local context. #[derive(Debug, Clone)] -pub struct Context { +pub(crate) struct Context { inner: Arc, } @@ -34,7 +34,7 @@ struct Inner { impl Context { /// Creates a new context for the duration of the closure. #[inline] - pub fn with(f: F) -> R + pub(crate) fn with(f: F) -> R where F: FnOnce(&Context) -> R, { @@ -86,7 +86,7 @@ impl Context { /// /// On failure, the previously selected operation is returned. #[inline] - pub fn try_select(&self, select: Selected) -> Result<(), Selected> { + pub(crate) fn try_select(&self, select: Selected) -> Result<(), Selected> { self.inner .select .compare_exchange( @@ -103,7 +103,7 @@ impl Context { /// /// This method must be called after `try_select` succeeds and there is a packet to provide. #[inline] - pub fn store_packet(&self, packet: *mut ()) { + pub(crate) fn store_packet(&self, packet: *mut ()) { if !packet.is_null() { self.inner.packet.store(packet, Ordering::Release); } @@ -116,7 +116,7 @@ impl Context { /// # Safety /// This may only be called from the thread this `Context` belongs to. #[inline] - pub unsafe fn wait_until(&self, deadline: Option) -> Selected { + pub(crate) unsafe fn wait_until(&self, deadline: Option) -> Selected { loop { // Check whether an operation has been selected. let sel = Selected::from(self.inner.select.load(Ordering::Acquire)); @@ -147,13 +147,13 @@ impl Context { /// Unparks the thread this context belongs to. #[inline] - pub fn unpark(&self) { + pub(crate) fn unpark(&self) { self.inner.thread.unpark(); } /// Returns the id of the thread this context belongs to. #[inline] - pub fn thread_id(&self) -> usize { + pub(crate) fn thread_id(&self) -> usize { self.inner.thread_id } } diff --git a/library/std/src/sync/mpmc/select.rs b/library/std/src/sync/mpmc/select.rs index ff537aa686157..60f81d863ae4f 100644 --- a/library/std/src/sync/mpmc/select.rs +++ b/library/std/src/sync/mpmc/select.rs @@ -3,7 +3,7 @@ /// /// Each field contains data associated with a specific channel flavor. #[derive(Debug, Default)] -pub struct Token { +pub(crate) struct Token { pub(crate) array: super::array::ArrayToken, pub(crate) list: super::list::ListToken, #[allow(dead_code)] @@ -12,7 +12,7 @@ pub struct Token { /// Identifier associated with an operation by a specific thread on a specific channel. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct Operation(usize); +pub(crate) struct Operation(usize); impl Operation { /// Creates an operation identifier from a mutable reference. @@ -21,7 +21,7 @@ impl Operation { /// reference should point to a variable that is specific to the thread and the operation, /// and is alive for the entire duration of a blocking operation. #[inline] - pub fn hook(r: &mut T) -> Operation { + pub(crate) fn hook(r: &mut T) -> Operation { let val = (r as *mut T).addr(); // Make sure that the pointer address doesn't equal the numerical representation of // `Selected::{Waiting, Aborted, Disconnected}`. @@ -32,7 +32,7 @@ impl Operation { /// Current state of a blocking operation. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Selected { +pub(crate) enum Selected { /// Still waiting for an operation. Waiting, diff --git a/library/std/src/sync/mpmc/utils.rs b/library/std/src/sync/mpmc/utils.rs index e3bcb149f648b..5a9bc7af6c36d 100644 --- a/library/std/src/sync/mpmc/utils.rs +++ b/library/std/src/sync/mpmc/utils.rs @@ -67,13 +67,13 @@ use crate::ops::{Deref, DerefMut}; )), repr(align(64)) )] -pub struct CachePadded { +pub(crate) struct CachePadded { value: T, } impl CachePadded { /// Pads and aligns a value to the length of a cache line. - pub fn new(value: T) -> CachePadded { + pub(crate) fn new(value: T) -> CachePadded { CachePadded:: { value } } } @@ -95,13 +95,13 @@ impl DerefMut for CachePadded { const SPIN_LIMIT: u32 = 6; /// Performs quadratic backoff in spin loops. -pub struct Backoff { +pub(crate) struct Backoff { step: Cell, } impl Backoff { /// Creates a new `Backoff`. - pub fn new() -> Self { + pub(crate) fn new() -> Self { Backoff { step: Cell::new(0) } } @@ -110,7 +110,7 @@ impl Backoff { /// This method should be used for retrying an operation because another thread made /// progress. i.e. on CAS failure. #[inline] - pub fn spin_light(&self) { + pub(crate) fn spin_light(&self) { let step = self.step.get().min(SPIN_LIMIT); for _ in 0..step.pow(2) { crate::hint::spin_loop(); @@ -123,7 +123,7 @@ impl Backoff { /// /// This method should be used in blocking loops where parking the thread is not an option. #[inline] - pub fn spin_heavy(&self) { + pub(crate) fn spin_heavy(&self) { if self.step.get() <= SPIN_LIMIT { for _ in 0..self.step.get().pow(2) { crate::hint::spin_loop() diff --git a/library/std/src/sync/mpmc/waker.rs b/library/std/src/sync/mpmc/waker.rs index 4216fb7ac5902..de913f0d421cc 100644 --- a/library/std/src/sync/mpmc/waker.rs +++ b/library/std/src/sync/mpmc/waker.rs @@ -201,7 +201,7 @@ impl Drop for SyncWaker { /// Returns a unique id for the current thread. #[inline] -pub fn current_thread_id() -> usize { +pub(crate) fn current_thread_id() -> usize { // `u8` is not drop so this variable will be available during thread destruction, // whereas `thread::current()` would not be thread_local! { static DUMMY: u8 = const { 0 } } diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index 3c32ec34dee5b..62d4c2754effe 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -97,7 +97,7 @@ pub(crate) struct Flag { impl Flag { #[inline] - pub const fn new() -> Flag { + pub(crate) const fn new() -> Flag { Flag { #[cfg(panic = "unwind")] failed: AtomicBool::new(false), @@ -106,13 +106,13 @@ impl Flag { /// Checks the flag for an unguarded borrow, where we only care about existing poison. #[inline] - pub fn borrow(&self) -> LockResult<()> { + pub(crate) fn borrow(&self) -> LockResult<()> { if self.get() { Err(PoisonError::new(())) } else { Ok(()) } } /// Checks the flag for a guarded borrow, where we may also set poison when `done`. #[inline] - pub fn guard(&self) -> LockResult { + pub(crate) fn guard(&self) -> LockResult { let ret = Guard { #[cfg(panic = "unwind")] panicking: thread::panicking(), @@ -122,7 +122,7 @@ impl Flag { #[inline] #[cfg(panic = "unwind")] - pub fn done(&self, guard: &Guard) { + pub(crate) fn done(&self, guard: &Guard) { if !guard.panicking && thread::panicking() { self.failed.store(true, Ordering::Relaxed); } @@ -130,22 +130,22 @@ impl Flag { #[inline] #[cfg(not(panic = "unwind"))] - pub fn done(&self, _guard: &Guard) {} + pub(crate) fn done(&self, _guard: &Guard) {} #[inline] #[cfg(panic = "unwind")] - pub fn get(&self) -> bool { + pub(crate) fn get(&self) -> bool { self.failed.load(Ordering::Relaxed) } #[inline(always)] #[cfg(not(panic = "unwind"))] - pub fn get(&self) -> bool { + pub(crate) fn get(&self) -> bool { false } #[inline] - pub fn clear(&self) { + pub(crate) fn clear(&self) { #[cfg(panic = "unwind")] self.failed.store(false, Ordering::Relaxed) } diff --git a/library/std/src/test_helpers.rs b/library/std/src/test_helpers.rs index 7c20f38c863b6..5690a40648ff2 100644 --- a/library/std/src/test_helpers.rs +++ b/library/std/src/test_helpers.rs @@ -27,15 +27,15 @@ pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { SeedableRng::from_seed(seed) } -pub struct TempDir(PathBuf); +pub(crate) struct TempDir(PathBuf); impl TempDir { - pub fn join(&self, path: &str) -> PathBuf { + pub(crate) fn join(&self, path: &str) -> PathBuf { let TempDir(ref p) = *self; p.join(path) } - pub fn path(&self) -> &Path { + pub(crate) fn path(&self) -> &Path { let TempDir(ref p) = *self; p } @@ -56,7 +56,7 @@ impl Drop for TempDir { } #[track_caller] // for `test_rng` -pub fn tmpdir() -> TempDir { +pub(crate) fn tmpdir() -> TempDir { let p = env::temp_dir(); let mut r = test_rng(); let ret = p.join(&format!("rust-{}", r.next_u32())); diff --git a/library/std/src/thread/lifecycle.rs b/library/std/src/thread/lifecycle.rs index 0dec359ccaec6..c22b97c39ecd5 100644 --- a/library/std/src/thread/lifecycle.rs +++ b/library/std/src/thread/lifecycle.rs @@ -125,7 +125,7 @@ pub(crate) struct ThreadInit { impl ThreadInit { /// Initialize the 'current thread' mechanism on this thread, returning the /// Rust entry point. - pub fn init(self: Box) -> Box { + pub(crate) fn init(self: Box) -> Box { // Set the current thread before any (de)allocations on the global allocator occur, // so that it may call std::thread::current() in its implementation. This is also // why we take Box, to ensure the Box is not destroyed until after this point. diff --git a/library/std/src/thread/thread.rs b/library/std/src/thread/thread.rs index d70c244c65d90..bfcf0fa4953d2 100644 --- a/library/std/src/thread/thread.rs +++ b/library/std/src/thread/thread.rs @@ -28,11 +28,11 @@ mod thread_name_string { } impl ThreadNameString { - pub fn as_cstr(&self) -> &CStr { + pub(crate) fn as_cstr(&self) -> &CStr { &self.inner } - pub fn as_str(&self) -> &str { + pub(crate) fn as_str(&self) -> &str { // SAFETY: `ThreadNameString` is guaranteed to be UTF-8. unsafe { str::from_utf8_unchecked(self.inner.to_bytes()) } } From 56aed553a063f918388af3a4f32147a7e4ae20a3 Mon Sep 17 00:00:00 2001 From: kulinsky Date: Mon, 14 Sep 2026 19:08:04 +0500 Subject: [PATCH 11/15] Respect do_not_recommend for a single impl candidate Add regression test for do_not_recommend on a single impl candidate --- .../traits/fulfillment_errors.rs | 4 +++- .../do_not_recommend/single-impl-candidate.rs | 21 ++++++++++++++++++ .../single-impl-candidate.stderr | 22 +++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 tests/ui/diagnostic_namespace/do_not_recommend/single-impl-candidate.rs create mode 100644 tests/ui/diagnostic_namespace/do_not_recommend/single-impl-candidate.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 7ee4481d12431..72e56ef428a0b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -2214,7 +2214,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { impl_candidates }; - if let [single] = &impl_candidates { + if let [single] = &impl_candidates + && !self.tcx.do_not_recommend_impl(single.impl_def_id) + { let self_ty = trait_pred.skip_binder().self_ty(); if !self_ty.has_escaping_bound_vars() { let self_ty = self.tcx.instantiate_bound_regions_with_erased(trait_pred.self_ty()); diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/single-impl-candidate.rs b/tests/ui/diagnostic_namespace/do_not_recommend/single-impl-candidate.rs new file mode 100644 index 0000000000000..313dca87464dd --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/single-impl-candidate.rs @@ -0,0 +1,21 @@ +//@ reference: attributes.diagnostic.do_not_recommend.intro + +pub struct Internal; + +#[diagnostic::do_not_recommend] +impl From for &str { + fn from(_: Internal) -> Self { + "" + } +} + +fn foo<'a, T>(_t: T) +where + T: Into<&'a str>, +{ +} + +fn main() { + foo(String::new()); + //~^ ERROR the trait bound `&str: From` is not satisfied +} diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/single-impl-candidate.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/single-impl-candidate.stderr new file mode 100644 index 0000000000000..a0d0e73a1172b --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/single-impl-candidate.stderr @@ -0,0 +1,22 @@ +error[E0277]: the trait bound `&str: From` is not satisfied + --> $DIR/single-impl-candidate.rs:19:9 + | +LL | foo(String::new()); + | --- ^^^^^^^^^^^^^ the trait `From` is not implemented for `&str` + | | + | required by a bound introduced by this call + | + = note: to coerce a `String` into a `&str`, use `&*` as a prefix + = note: required for `String` to implement `Into<&str>` +note: required by a bound in `foo` + --> $DIR/single-impl-candidate.rs:14:8 + | +LL | fn foo<'a, T>(_t: T) + | --- required by a bound in this function +LL | where +LL | T: Into<&'a str>, + | ^^^^^^^^^^^^^ required by this bound in `foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From 711a32b1bde0de0f26628d6fea15683244f83a1d Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 14 Sep 2026 15:33:13 -0400 Subject: [PATCH 12/15] rustdoc: Revert "fix bare urls split text" This reverts commit d4e6b8f2460d08f8028c71e5383a6300eaec1a9f. Reverted commit contains incorrect comments, does not implement all the functionality it claims to, and lacks test coverage. --- src/librustdoc/passes/lint/bare_urls.rs | 27 ++++++++++--------------- tests/rustdoc-ui/lints/bare-urls.fixed | 4 ---- tests/rustdoc-ui/lints/bare-urls.rs | 4 ---- tests/rustdoc-ui/lints/bare-urls.stderr | 14 +------------ 4 files changed, 12 insertions(+), 37 deletions(-) diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs index 287a1f50b5aa1..0928980e390a8 100644 --- a/src/librustdoc/passes/lint/bare_urls.rs +++ b/src/librustdoc/passes/lint/bare_urls.rs @@ -2,14 +2,13 @@ //! Suggests wrapping the link with angle brackets: `Go to .` to linkify it. use core::ops::Range; +use std::mem; use std::sync::LazyLock; use regex::Regex; use rustc_errors::{Applicability, DiagDecorator}; use rustc_hir::HirId; -use rustc_resolve::rustdoc::pulldown_cmark::{ - DefaultBrokenLinkCallback, Event, Tag, TextMergeWithOffset, -}; +use rustc_resolve::rustdoc::pulldown_cmark::{Event, Parser, Tag}; use rustc_resolve::rustdoc::source_span_for_markdown_range; use tracing::trace; @@ -56,20 +55,21 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: & ); }; - // pulldown-cmark can split a URL into multiple `Text` events while processing - // characters such as `_` according to CommonMark's emphasis rules. - // `TextMergeWithOffset` merges these events so we can check the complete URL. - let mut p = TextMergeWithOffset::::new_ext(dox, main_body_opts()); + let mut p = Parser::new_ext(dox, main_body_opts()).into_offset_iter(); while let Some((event, range)) = p.next() { match event { Event::Text(s) => find_raw_urls(cx, dox, &s, range, &report_diag), // We don't want to check the text inside code blocks or links. Event::Start(tag @ (Tag::CodeBlock(_) | Tag::Link { .. })) => { - let end = tag.to_end(); for (event, _) in p.by_ref() { - if matches!(event, Event::End(tag) if tag == end) { - break; + match event { + Event::End(end) + if mem::discriminant(&end) == mem::discriminant(&tag.to_end()) => + { + break; + } + _ => {} } } } @@ -83,12 +83,7 @@ static URL_REGEX: LazyLock = LazyLock::new(|| { r"https?://", // url scheme r"([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)+", // one or more subdomains r"[a-zA-Z]{2,63}", // root domain - // Match URL characters and balanced parenthesized segments, without - // consuming a trailing `)` that belongs to the surrounding prose. - r"\b(?:", - r"[-a-zA-Z0-9@:%_\+.~#?&/=]", - r"|\([-a-zA-Z0-9@:%_\+.~#?&/=]*\)", - r")*", + r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)", // optional query or url fragments )) .expect("failed to build regex") }); diff --git a/tests/rustdoc-ui/lints/bare-urls.fixed b/tests/rustdoc-ui/lints/bare-urls.fixed index b18aae11c77cf..996214b5ff14f 100644 --- a/tests/rustdoc-ui/lints/bare-urls.fixed +++ b/tests/rustdoc-ui/lints/bare-urls.fixed @@ -92,7 +92,3 @@ pub fn trailing_period() {} /// ] //~^ ERROR this URL is not a hyperlink pub fn lint_with_brackets() {} - -/// See -//~^ ERROR this URL is not a hyperlink -pub fn hippo() {} diff --git a/tests/rustdoc-ui/lints/bare-urls.rs b/tests/rustdoc-ui/lints/bare-urls.rs index fb39ec6b6ccbd..9b4fe68e00322 100644 --- a/tests/rustdoc-ui/lints/bare-urls.rs +++ b/tests/rustdoc-ui/lints/bare-urls.rs @@ -92,7 +92,3 @@ pub fn trailing_period() {} /// https://bloob.blob] //~^ ERROR this URL is not a hyperlink pub fn lint_with_brackets() {} - -/// See https://en.wikipedia.org/wiki/Rust_(programming_language) -//~^ ERROR this URL is not a hyperlink -pub fn hippo() {} diff --git a/tests/rustdoc-ui/lints/bare-urls.stderr b/tests/rustdoc-ui/lints/bare-urls.stderr index a3a291e8e4bca..05ddd2ed42ab1 100644 --- a/tests/rustdoc-ui/lints/bare-urls.stderr +++ b/tests/rustdoc-ui/lints/bare-urls.stderr @@ -364,17 +364,5 @@ help: use an automatic link instead LL | /// ] | + + -error: this URL is not a hyperlink - --> $DIR/bare-urls.rs:96:9 - | -LL | /// See https://en.wikipedia.org/wiki/Rust_(programming_language) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: bare URLs are not automatically turned into clickable links -help: use an automatic link instead - | -LL | /// See - | + + - -error: aborting due to 31 previous errors +error: aborting due to 30 previous errors From 6c291770a41d2e7b021042b2401216606fe669e8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 6 Sep 2026 14:47:51 +0200 Subject: [PATCH 13/15] Clean up `test/rustdoc-html` folder by moving tests where appropriate --- tests/rustdoc-html/{ => codeblock}/bad-codeblock-syntax.rs | 0 tests/rustdoc-html/{ => codeblock}/codeblock-title.rs | 0 tests/rustdoc-html/{ => codeblock}/custom_code_classes.rs | 0 .../doctest-escape-boring-41783.codeblock.html | 0 .../{doctest => codeblock}/doctest-escape-boring-41783.rs | 0 tests/rustdoc-html/{doctest => codeblock}/editions.rs | 0 tests/rustdoc-html/{ => codeblock}/hidden-line.rs | 0 tests/rustdoc-html/{doctest => codeblock}/ignore-sometimes.rs | 0 tests/rustdoc-html/{ => codeblock}/playground-arg.rs | 0 tests/rustdoc-html/{ => codeblock}/playground-empty.rs | 0 tests/rustdoc-html/{ => codeblock}/playground-none.rs | 0 tests/rustdoc-html/{ => codeblock}/playground-syntax-error.rs | 0 tests/rustdoc-html/{ => codeblock}/playground.rs | 0 tests/rustdoc-html/{ => codeblock}/short-docblock-codeblock.rs | 0 tests/rustdoc-html/{ => codeblock}/summary-codeblock-31899.rs | 0 tests/rustdoc-html/{ => codeblock}/unindent.md | 0 tests/rustdoc-html/{ => codeblock}/unindent.rs | 0 .../footnote-definition-without-blank-line-100638.rs | 0 tests/rustdoc-html/{ => footnote}/footnote-ids.rs | 0 tests/rustdoc-html/{ => footnote}/footnote-in-summary.rs | 0 tests/rustdoc-html/{ => footnote}/footnote-reference-ids.rs | 0 .../{ => footnote}/footnote-reference-in-footnote-def.rs | 0 tests/rustdoc-html/{ => hidden}/display-hidden-items.rs | 0 tests/rustdoc-html/{ => hidden}/document-hidden-items-15347.rs | 0 .../hidden-trait-methods-with-document-hidden-items.rs | 0 tests/rustdoc-html/{ => macro}/auxiliary/generated_macro.rs | 0 tests/rustdoc-html/{ => macro}/generated_macro.rs | 0 .../{ => reexport}/auxiliary/inline-default-methods.rs | 0 tests/rustdoc-html/{ => reexport}/auxiliary/issue-61592.rs | 0 tests/rustdoc-html/{ => reexport}/infinite-redirection.rs | 0 tests/rustdoc-html/{ => reexport}/inline-default-methods.rs | 0 tests/rustdoc-html/{ => reexport}/inline-rename-34473.rs | 0 tests/rustdoc-html/{ => reexport}/macro-reexport-inline.rs | 0 tests/rustdoc-html/{ => reexport}/pub-use-loop-107350.rs | 0 tests/rustdoc-html/{ => reexport}/pub-use-root-path-95873.rs | 0 tests/rustdoc-html/{ => reexport}/underscore-import-61592.rs | 0 tests/rustdoc-html/{ => reexport}/use-attr.rs | 0 .../{ => type-alias}/auxiliary/cross_crate_generic_typedef.rs | 0 .../{ => type-alias}/typedef-inner-variants-document-hidden.rs | 0 .../{ => type-alias}/typedef-inner-variants-lazy_type_alias.rs | 0 tests/rustdoc-html/{ => type-alias}/typedef-inner-variants.rs | 0 tests/rustdoc-html/{ => type-alias}/typedef.rs | 0 tests/rustdoc-html/{ => union}/union-fields-html.rs | 0 tests/rustdoc-html/{ => union}/union.rs | 0 44 files changed, 0 insertions(+), 0 deletions(-) rename tests/rustdoc-html/{ => codeblock}/bad-codeblock-syntax.rs (100%) rename tests/rustdoc-html/{ => codeblock}/codeblock-title.rs (100%) rename tests/rustdoc-html/{ => codeblock}/custom_code_classes.rs (100%) rename tests/rustdoc-html/{doctest => codeblock}/doctest-escape-boring-41783.codeblock.html (100%) rename tests/rustdoc-html/{doctest => codeblock}/doctest-escape-boring-41783.rs (100%) rename tests/rustdoc-html/{doctest => codeblock}/editions.rs (100%) rename tests/rustdoc-html/{ => codeblock}/hidden-line.rs (100%) rename tests/rustdoc-html/{doctest => codeblock}/ignore-sometimes.rs (100%) rename tests/rustdoc-html/{ => codeblock}/playground-arg.rs (100%) rename tests/rustdoc-html/{ => codeblock}/playground-empty.rs (100%) rename tests/rustdoc-html/{ => codeblock}/playground-none.rs (100%) rename tests/rustdoc-html/{ => codeblock}/playground-syntax-error.rs (100%) rename tests/rustdoc-html/{ => codeblock}/playground.rs (100%) rename tests/rustdoc-html/{ => codeblock}/short-docblock-codeblock.rs (100%) rename tests/rustdoc-html/{ => codeblock}/summary-codeblock-31899.rs (100%) rename tests/rustdoc-html/{ => codeblock}/unindent.md (100%) rename tests/rustdoc-html/{ => codeblock}/unindent.rs (100%) rename tests/rustdoc-html/{ => footnote}/footnote-definition-without-blank-line-100638.rs (100%) rename tests/rustdoc-html/{ => footnote}/footnote-ids.rs (100%) rename tests/rustdoc-html/{ => footnote}/footnote-in-summary.rs (100%) rename tests/rustdoc-html/{ => footnote}/footnote-reference-ids.rs (100%) rename tests/rustdoc-html/{ => footnote}/footnote-reference-in-footnote-def.rs (100%) rename tests/rustdoc-html/{ => hidden}/display-hidden-items.rs (100%) rename tests/rustdoc-html/{ => hidden}/document-hidden-items-15347.rs (100%) rename tests/rustdoc-html/{ => hidden}/hidden-trait-methods-with-document-hidden-items.rs (100%) rename tests/rustdoc-html/{ => macro}/auxiliary/generated_macro.rs (100%) rename tests/rustdoc-html/{ => macro}/generated_macro.rs (100%) rename tests/rustdoc-html/{ => reexport}/auxiliary/inline-default-methods.rs (100%) rename tests/rustdoc-html/{ => reexport}/auxiliary/issue-61592.rs (100%) rename tests/rustdoc-html/{ => reexport}/infinite-redirection.rs (100%) rename tests/rustdoc-html/{ => reexport}/inline-default-methods.rs (100%) rename tests/rustdoc-html/{ => reexport}/inline-rename-34473.rs (100%) rename tests/rustdoc-html/{ => reexport}/macro-reexport-inline.rs (100%) rename tests/rustdoc-html/{ => reexport}/pub-use-loop-107350.rs (100%) rename tests/rustdoc-html/{ => reexport}/pub-use-root-path-95873.rs (100%) rename tests/rustdoc-html/{ => reexport}/underscore-import-61592.rs (100%) rename tests/rustdoc-html/{ => reexport}/use-attr.rs (100%) rename tests/rustdoc-html/{ => type-alias}/auxiliary/cross_crate_generic_typedef.rs (100%) rename tests/rustdoc-html/{ => type-alias}/typedef-inner-variants-document-hidden.rs (100%) rename tests/rustdoc-html/{ => type-alias}/typedef-inner-variants-lazy_type_alias.rs (100%) rename tests/rustdoc-html/{ => type-alias}/typedef-inner-variants.rs (100%) rename tests/rustdoc-html/{ => type-alias}/typedef.rs (100%) rename tests/rustdoc-html/{ => union}/union-fields-html.rs (100%) rename tests/rustdoc-html/{ => union}/union.rs (100%) diff --git a/tests/rustdoc-html/bad-codeblock-syntax.rs b/tests/rustdoc-html/codeblock/bad-codeblock-syntax.rs similarity index 100% rename from tests/rustdoc-html/bad-codeblock-syntax.rs rename to tests/rustdoc-html/codeblock/bad-codeblock-syntax.rs diff --git a/tests/rustdoc-html/codeblock-title.rs b/tests/rustdoc-html/codeblock/codeblock-title.rs similarity index 100% rename from tests/rustdoc-html/codeblock-title.rs rename to tests/rustdoc-html/codeblock/codeblock-title.rs diff --git a/tests/rustdoc-html/custom_code_classes.rs b/tests/rustdoc-html/codeblock/custom_code_classes.rs similarity index 100% rename from tests/rustdoc-html/custom_code_classes.rs rename to tests/rustdoc-html/codeblock/custom_code_classes.rs diff --git a/tests/rustdoc-html/doctest/doctest-escape-boring-41783.codeblock.html b/tests/rustdoc-html/codeblock/doctest-escape-boring-41783.codeblock.html similarity index 100% rename from tests/rustdoc-html/doctest/doctest-escape-boring-41783.codeblock.html rename to tests/rustdoc-html/codeblock/doctest-escape-boring-41783.codeblock.html diff --git a/tests/rustdoc-html/doctest/doctest-escape-boring-41783.rs b/tests/rustdoc-html/codeblock/doctest-escape-boring-41783.rs similarity index 100% rename from tests/rustdoc-html/doctest/doctest-escape-boring-41783.rs rename to tests/rustdoc-html/codeblock/doctest-escape-boring-41783.rs diff --git a/tests/rustdoc-html/doctest/editions.rs b/tests/rustdoc-html/codeblock/editions.rs similarity index 100% rename from tests/rustdoc-html/doctest/editions.rs rename to tests/rustdoc-html/codeblock/editions.rs diff --git a/tests/rustdoc-html/hidden-line.rs b/tests/rustdoc-html/codeblock/hidden-line.rs similarity index 100% rename from tests/rustdoc-html/hidden-line.rs rename to tests/rustdoc-html/codeblock/hidden-line.rs diff --git a/tests/rustdoc-html/doctest/ignore-sometimes.rs b/tests/rustdoc-html/codeblock/ignore-sometimes.rs similarity index 100% rename from tests/rustdoc-html/doctest/ignore-sometimes.rs rename to tests/rustdoc-html/codeblock/ignore-sometimes.rs diff --git a/tests/rustdoc-html/playground-arg.rs b/tests/rustdoc-html/codeblock/playground-arg.rs similarity index 100% rename from tests/rustdoc-html/playground-arg.rs rename to tests/rustdoc-html/codeblock/playground-arg.rs diff --git a/tests/rustdoc-html/playground-empty.rs b/tests/rustdoc-html/codeblock/playground-empty.rs similarity index 100% rename from tests/rustdoc-html/playground-empty.rs rename to tests/rustdoc-html/codeblock/playground-empty.rs diff --git a/tests/rustdoc-html/playground-none.rs b/tests/rustdoc-html/codeblock/playground-none.rs similarity index 100% rename from tests/rustdoc-html/playground-none.rs rename to tests/rustdoc-html/codeblock/playground-none.rs diff --git a/tests/rustdoc-html/playground-syntax-error.rs b/tests/rustdoc-html/codeblock/playground-syntax-error.rs similarity index 100% rename from tests/rustdoc-html/playground-syntax-error.rs rename to tests/rustdoc-html/codeblock/playground-syntax-error.rs diff --git a/tests/rustdoc-html/playground.rs b/tests/rustdoc-html/codeblock/playground.rs similarity index 100% rename from tests/rustdoc-html/playground.rs rename to tests/rustdoc-html/codeblock/playground.rs diff --git a/tests/rustdoc-html/short-docblock-codeblock.rs b/tests/rustdoc-html/codeblock/short-docblock-codeblock.rs similarity index 100% rename from tests/rustdoc-html/short-docblock-codeblock.rs rename to tests/rustdoc-html/codeblock/short-docblock-codeblock.rs diff --git a/tests/rustdoc-html/summary-codeblock-31899.rs b/tests/rustdoc-html/codeblock/summary-codeblock-31899.rs similarity index 100% rename from tests/rustdoc-html/summary-codeblock-31899.rs rename to tests/rustdoc-html/codeblock/summary-codeblock-31899.rs diff --git a/tests/rustdoc-html/unindent.md b/tests/rustdoc-html/codeblock/unindent.md similarity index 100% rename from tests/rustdoc-html/unindent.md rename to tests/rustdoc-html/codeblock/unindent.md diff --git a/tests/rustdoc-html/unindent.rs b/tests/rustdoc-html/codeblock/unindent.rs similarity index 100% rename from tests/rustdoc-html/unindent.rs rename to tests/rustdoc-html/codeblock/unindent.rs diff --git a/tests/rustdoc-html/footnote-definition-without-blank-line-100638.rs b/tests/rustdoc-html/footnote/footnote-definition-without-blank-line-100638.rs similarity index 100% rename from tests/rustdoc-html/footnote-definition-without-blank-line-100638.rs rename to tests/rustdoc-html/footnote/footnote-definition-without-blank-line-100638.rs diff --git a/tests/rustdoc-html/footnote-ids.rs b/tests/rustdoc-html/footnote/footnote-ids.rs similarity index 100% rename from tests/rustdoc-html/footnote-ids.rs rename to tests/rustdoc-html/footnote/footnote-ids.rs diff --git a/tests/rustdoc-html/footnote-in-summary.rs b/tests/rustdoc-html/footnote/footnote-in-summary.rs similarity index 100% rename from tests/rustdoc-html/footnote-in-summary.rs rename to tests/rustdoc-html/footnote/footnote-in-summary.rs diff --git a/tests/rustdoc-html/footnote-reference-ids.rs b/tests/rustdoc-html/footnote/footnote-reference-ids.rs similarity index 100% rename from tests/rustdoc-html/footnote-reference-ids.rs rename to tests/rustdoc-html/footnote/footnote-reference-ids.rs diff --git a/tests/rustdoc-html/footnote-reference-in-footnote-def.rs b/tests/rustdoc-html/footnote/footnote-reference-in-footnote-def.rs similarity index 100% rename from tests/rustdoc-html/footnote-reference-in-footnote-def.rs rename to tests/rustdoc-html/footnote/footnote-reference-in-footnote-def.rs diff --git a/tests/rustdoc-html/display-hidden-items.rs b/tests/rustdoc-html/hidden/display-hidden-items.rs similarity index 100% rename from tests/rustdoc-html/display-hidden-items.rs rename to tests/rustdoc-html/hidden/display-hidden-items.rs diff --git a/tests/rustdoc-html/document-hidden-items-15347.rs b/tests/rustdoc-html/hidden/document-hidden-items-15347.rs similarity index 100% rename from tests/rustdoc-html/document-hidden-items-15347.rs rename to tests/rustdoc-html/hidden/document-hidden-items-15347.rs diff --git a/tests/rustdoc-html/hidden-trait-methods-with-document-hidden-items.rs b/tests/rustdoc-html/hidden/hidden-trait-methods-with-document-hidden-items.rs similarity index 100% rename from tests/rustdoc-html/hidden-trait-methods-with-document-hidden-items.rs rename to tests/rustdoc-html/hidden/hidden-trait-methods-with-document-hidden-items.rs diff --git a/tests/rustdoc-html/auxiliary/generated_macro.rs b/tests/rustdoc-html/macro/auxiliary/generated_macro.rs similarity index 100% rename from tests/rustdoc-html/auxiliary/generated_macro.rs rename to tests/rustdoc-html/macro/auxiliary/generated_macro.rs diff --git a/tests/rustdoc-html/generated_macro.rs b/tests/rustdoc-html/macro/generated_macro.rs similarity index 100% rename from tests/rustdoc-html/generated_macro.rs rename to tests/rustdoc-html/macro/generated_macro.rs diff --git a/tests/rustdoc-html/auxiliary/inline-default-methods.rs b/tests/rustdoc-html/reexport/auxiliary/inline-default-methods.rs similarity index 100% rename from tests/rustdoc-html/auxiliary/inline-default-methods.rs rename to tests/rustdoc-html/reexport/auxiliary/inline-default-methods.rs diff --git a/tests/rustdoc-html/auxiliary/issue-61592.rs b/tests/rustdoc-html/reexport/auxiliary/issue-61592.rs similarity index 100% rename from tests/rustdoc-html/auxiliary/issue-61592.rs rename to tests/rustdoc-html/reexport/auxiliary/issue-61592.rs diff --git a/tests/rustdoc-html/infinite-redirection.rs b/tests/rustdoc-html/reexport/infinite-redirection.rs similarity index 100% rename from tests/rustdoc-html/infinite-redirection.rs rename to tests/rustdoc-html/reexport/infinite-redirection.rs diff --git a/tests/rustdoc-html/inline-default-methods.rs b/tests/rustdoc-html/reexport/inline-default-methods.rs similarity index 100% rename from tests/rustdoc-html/inline-default-methods.rs rename to tests/rustdoc-html/reexport/inline-default-methods.rs diff --git a/tests/rustdoc-html/inline-rename-34473.rs b/tests/rustdoc-html/reexport/inline-rename-34473.rs similarity index 100% rename from tests/rustdoc-html/inline-rename-34473.rs rename to tests/rustdoc-html/reexport/inline-rename-34473.rs diff --git a/tests/rustdoc-html/macro-reexport-inline.rs b/tests/rustdoc-html/reexport/macro-reexport-inline.rs similarity index 100% rename from tests/rustdoc-html/macro-reexport-inline.rs rename to tests/rustdoc-html/reexport/macro-reexport-inline.rs diff --git a/tests/rustdoc-html/pub-use-loop-107350.rs b/tests/rustdoc-html/reexport/pub-use-loop-107350.rs similarity index 100% rename from tests/rustdoc-html/pub-use-loop-107350.rs rename to tests/rustdoc-html/reexport/pub-use-loop-107350.rs diff --git a/tests/rustdoc-html/pub-use-root-path-95873.rs b/tests/rustdoc-html/reexport/pub-use-root-path-95873.rs similarity index 100% rename from tests/rustdoc-html/pub-use-root-path-95873.rs rename to tests/rustdoc-html/reexport/pub-use-root-path-95873.rs diff --git a/tests/rustdoc-html/underscore-import-61592.rs b/tests/rustdoc-html/reexport/underscore-import-61592.rs similarity index 100% rename from tests/rustdoc-html/underscore-import-61592.rs rename to tests/rustdoc-html/reexport/underscore-import-61592.rs diff --git a/tests/rustdoc-html/use-attr.rs b/tests/rustdoc-html/reexport/use-attr.rs similarity index 100% rename from tests/rustdoc-html/use-attr.rs rename to tests/rustdoc-html/reexport/use-attr.rs diff --git a/tests/rustdoc-html/auxiliary/cross_crate_generic_typedef.rs b/tests/rustdoc-html/type-alias/auxiliary/cross_crate_generic_typedef.rs similarity index 100% rename from tests/rustdoc-html/auxiliary/cross_crate_generic_typedef.rs rename to tests/rustdoc-html/type-alias/auxiliary/cross_crate_generic_typedef.rs diff --git a/tests/rustdoc-html/typedef-inner-variants-document-hidden.rs b/tests/rustdoc-html/type-alias/typedef-inner-variants-document-hidden.rs similarity index 100% rename from tests/rustdoc-html/typedef-inner-variants-document-hidden.rs rename to tests/rustdoc-html/type-alias/typedef-inner-variants-document-hidden.rs diff --git a/tests/rustdoc-html/typedef-inner-variants-lazy_type_alias.rs b/tests/rustdoc-html/type-alias/typedef-inner-variants-lazy_type_alias.rs similarity index 100% rename from tests/rustdoc-html/typedef-inner-variants-lazy_type_alias.rs rename to tests/rustdoc-html/type-alias/typedef-inner-variants-lazy_type_alias.rs diff --git a/tests/rustdoc-html/typedef-inner-variants.rs b/tests/rustdoc-html/type-alias/typedef-inner-variants.rs similarity index 100% rename from tests/rustdoc-html/typedef-inner-variants.rs rename to tests/rustdoc-html/type-alias/typedef-inner-variants.rs diff --git a/tests/rustdoc-html/typedef.rs b/tests/rustdoc-html/type-alias/typedef.rs similarity index 100% rename from tests/rustdoc-html/typedef.rs rename to tests/rustdoc-html/type-alias/typedef.rs diff --git a/tests/rustdoc-html/union-fields-html.rs b/tests/rustdoc-html/union/union-fields-html.rs similarity index 100% rename from tests/rustdoc-html/union-fields-html.rs rename to tests/rustdoc-html/union/union-fields-html.rs diff --git a/tests/rustdoc-html/union.rs b/tests/rustdoc-html/union/union.rs similarity index 100% rename from tests/rustdoc-html/union.rs rename to tests/rustdoc-html/union/union.rs From 4e775637956cb098200acb56ffab80c78553faf1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 14 Sep 2026 22:17:54 +0200 Subject: [PATCH 14/15] Rename `tests/rustdoc-html/type-alias` folder into `tests/rustdoc-html/typedef` --- .../auxiliary/cross_crate_generic_typedef.rs | 0 .../{type-alias => typedef}/auxiliary/parent-crate-115718.rs | 0 tests/rustdoc-html/{type-alias => typedef}/cross-crate-115718.rs | 0 tests/rustdoc-html/{type-alias => typedef}/deref-32077.rs | 0 .../{type-alias => typedef}/impl_trait_in_assoc_type.rs | 0 .../{type-alias => typedef}/primitive-local-link-121106.rs | 0 tests/rustdoc-html/{type-alias => typedef}/repr.rs | 0 tests/rustdoc-html/{type-alias => typedef}/same-crate-115718.rs | 0 .../typedef-inner-variants-document-hidden.rs | 0 .../typedef-inner-variants-lazy_type_alias.rs | 0 .../{type-alias => typedef}/typedef-inner-variants.rs | 0 tests/rustdoc-html/{type-alias => typedef}/typedef.rs | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename tests/rustdoc-html/{type-alias => typedef}/auxiliary/cross_crate_generic_typedef.rs (100%) rename tests/rustdoc-html/{type-alias => typedef}/auxiliary/parent-crate-115718.rs (100%) rename tests/rustdoc-html/{type-alias => typedef}/cross-crate-115718.rs (100%) rename tests/rustdoc-html/{type-alias => typedef}/deref-32077.rs (100%) rename tests/rustdoc-html/{type-alias => typedef}/impl_trait_in_assoc_type.rs (100%) rename tests/rustdoc-html/{type-alias => typedef}/primitive-local-link-121106.rs (100%) rename tests/rustdoc-html/{type-alias => typedef}/repr.rs (100%) rename tests/rustdoc-html/{type-alias => typedef}/same-crate-115718.rs (100%) rename tests/rustdoc-html/{type-alias => typedef}/typedef-inner-variants-document-hidden.rs (100%) rename tests/rustdoc-html/{type-alias => typedef}/typedef-inner-variants-lazy_type_alias.rs (100%) rename tests/rustdoc-html/{type-alias => typedef}/typedef-inner-variants.rs (100%) rename tests/rustdoc-html/{type-alias => typedef}/typedef.rs (100%) diff --git a/tests/rustdoc-html/type-alias/auxiliary/cross_crate_generic_typedef.rs b/tests/rustdoc-html/typedef/auxiliary/cross_crate_generic_typedef.rs similarity index 100% rename from tests/rustdoc-html/type-alias/auxiliary/cross_crate_generic_typedef.rs rename to tests/rustdoc-html/typedef/auxiliary/cross_crate_generic_typedef.rs diff --git a/tests/rustdoc-html/type-alias/auxiliary/parent-crate-115718.rs b/tests/rustdoc-html/typedef/auxiliary/parent-crate-115718.rs similarity index 100% rename from tests/rustdoc-html/type-alias/auxiliary/parent-crate-115718.rs rename to tests/rustdoc-html/typedef/auxiliary/parent-crate-115718.rs diff --git a/tests/rustdoc-html/type-alias/cross-crate-115718.rs b/tests/rustdoc-html/typedef/cross-crate-115718.rs similarity index 100% rename from tests/rustdoc-html/type-alias/cross-crate-115718.rs rename to tests/rustdoc-html/typedef/cross-crate-115718.rs diff --git a/tests/rustdoc-html/type-alias/deref-32077.rs b/tests/rustdoc-html/typedef/deref-32077.rs similarity index 100% rename from tests/rustdoc-html/type-alias/deref-32077.rs rename to tests/rustdoc-html/typedef/deref-32077.rs diff --git a/tests/rustdoc-html/type-alias/impl_trait_in_assoc_type.rs b/tests/rustdoc-html/typedef/impl_trait_in_assoc_type.rs similarity index 100% rename from tests/rustdoc-html/type-alias/impl_trait_in_assoc_type.rs rename to tests/rustdoc-html/typedef/impl_trait_in_assoc_type.rs diff --git a/tests/rustdoc-html/type-alias/primitive-local-link-121106.rs b/tests/rustdoc-html/typedef/primitive-local-link-121106.rs similarity index 100% rename from tests/rustdoc-html/type-alias/primitive-local-link-121106.rs rename to tests/rustdoc-html/typedef/primitive-local-link-121106.rs diff --git a/tests/rustdoc-html/type-alias/repr.rs b/tests/rustdoc-html/typedef/repr.rs similarity index 100% rename from tests/rustdoc-html/type-alias/repr.rs rename to tests/rustdoc-html/typedef/repr.rs diff --git a/tests/rustdoc-html/type-alias/same-crate-115718.rs b/tests/rustdoc-html/typedef/same-crate-115718.rs similarity index 100% rename from tests/rustdoc-html/type-alias/same-crate-115718.rs rename to tests/rustdoc-html/typedef/same-crate-115718.rs diff --git a/tests/rustdoc-html/type-alias/typedef-inner-variants-document-hidden.rs b/tests/rustdoc-html/typedef/typedef-inner-variants-document-hidden.rs similarity index 100% rename from tests/rustdoc-html/type-alias/typedef-inner-variants-document-hidden.rs rename to tests/rustdoc-html/typedef/typedef-inner-variants-document-hidden.rs diff --git a/tests/rustdoc-html/type-alias/typedef-inner-variants-lazy_type_alias.rs b/tests/rustdoc-html/typedef/typedef-inner-variants-lazy_type_alias.rs similarity index 100% rename from tests/rustdoc-html/type-alias/typedef-inner-variants-lazy_type_alias.rs rename to tests/rustdoc-html/typedef/typedef-inner-variants-lazy_type_alias.rs diff --git a/tests/rustdoc-html/type-alias/typedef-inner-variants.rs b/tests/rustdoc-html/typedef/typedef-inner-variants.rs similarity index 100% rename from tests/rustdoc-html/type-alias/typedef-inner-variants.rs rename to tests/rustdoc-html/typedef/typedef-inner-variants.rs diff --git a/tests/rustdoc-html/type-alias/typedef.rs b/tests/rustdoc-html/typedef/typedef.rs similarity index 100% rename from tests/rustdoc-html/type-alias/typedef.rs rename to tests/rustdoc-html/typedef/typedef.rs From 03e4c769ec9f936506cb12d9688e6a9535e936ad Mon Sep 17 00:00:00 2001 From: Ben Reeves Date: Mon, 14 Sep 2026 13:04:40 -0700 Subject: [PATCH 15/15] AGENTS.md: Permit local experimentation, per the online policy. As previously written, AGENTS.md prohibited my LLM from performing edits as part of a prototype that I never intended to upstream. This is explicitly permitted by the policy. Text drafted by Claude Fable 5.1 and edited by me. Change [pre-approved](https://rust-lang.zulipchat.com/#narrow/channel/606558-llm-reviews/topic/AGENTS.2Emd.20forbidding.20experimentation/near/624161741) by @jyn514 --- AGENTS.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index af1ad378bebdd..ce36bada00558 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,6 +21,25 @@ for the user to implement from scratch remain allowed if independently requested Alongside any text that could potentially be used as a substitute for prohibited text, include *in the same response turn* a reminder of the policies against text originally created by an LLM, even if given during a previous turn of the session. Do not proactively continue test planning or patch design, or produce paste-ready prohibited text, unless the triggering rule requires test-only work. +### Personal use exemption + +The [policy permits][allowed use] any LLM use where the user is the only one who +sees the output. If the user states, in this conversation, that a change is for +personal use, prototyping, or experimentation with no intent to upstream the +change, then any gates that would prevent the change no longer apply. +Do not infer this; a statement from the user is required. + +Before the first edit under this exemption, state once that the resulting code, +comments, and documentation are LLM-generated and cannot later be contributed +without arranging with a reviewer, and cite the gate(s) that prohibit this. + +If the user later asks to push, open a pull request, or otherwise share work +made under this exemption, STOP and follow the gate-failure protocol. +Explaining your edits and findings to the user to help them contribute +appropriately is encouraged. + +[allowed use]: https://forge.rust-lang.org/policies/llm-usage.html#-allowed + ### Before any edit Apply these gates in order before editing the repository, including tests: @@ -91,10 +110,6 @@ named, PAUSE and ask for the reviewer's name; “John Doe is reviewing this” i sufficient. A reviewer name satisfies only this gate. Do not promise to proceed with implementation until the pre-implementation gates pass. -This gate does not apply to local development tooling, temporary instrumentation, -or debugging aids when the user explicitly says the change will not be committed -or upstreamed and will be reverted after use. All other gates still apply. - ### Before implementation Apply these gates in order after the pre-edit gates: