From f31860e82c161908437d92441c53fd4ca6a4191c Mon Sep 17 00:00:00 2001 From: Kyuuhachi Date: Tue, 16 Dec 2025 23:03:24 +0100 Subject: [PATCH 01/14] Implement clamp_to Remove trivial bounds Panic on NaN Make assert messages consistent with field names Add clamp_to coretests Update to fmt style --- library/core/src/cmp.rs | 32 +++++++++ library/core/src/cmp/clamp.rs | 100 ++++++++++++++++++++++++++ library/core/src/num/f128.rs | 35 +++++++++ library/core/src/num/f16.rs | 35 +++++++++ library/core/src/num/f32.rs | 35 +++++++++ library/core/src/num/f64.rs | 35 +++++++++ library/coretests/tests/lib.rs | 1 + library/coretests/tests/num/floats.rs | 42 +++++++++++ 8 files changed, 315 insertions(+) create mode 100644 library/core/src/cmp/clamp.rs diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 3371b2cecbd79..5680904da1ee0 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -26,7 +26,10 @@ #![stable(feature = "rust1", since = "1.0.0")] mod bytewise; +mod clamp; pub(crate) use bytewise::BytewiseEq; +#[unstable(feature = "clamp_bounds", issue = "147781")] +pub use clamp::ClampBounds; use self::Ordering::*; use crate::marker::{Destruct, PointeeSized}; @@ -1109,6 +1112,35 @@ pub const trait Ord: [const] Eq + [const] PartialOrd + PointeeSized { self } } + + /// Restrict a value to a certain range. + /// + /// This is equal to `max`, `min`, or `clamp`, depending on whether the range is `min..`, + /// `..=max`, or `min..=max`, respectively. Exclusive ranges are not permitted. + /// + /// # Panics + /// + /// Panics on `min..=max` if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp_to)] + /// assert_eq!((-3).clamp_to(-2..=1), -2); + /// assert_eq!(0.clamp_to(-2..=1), 0); + /// assert_eq!(2.clamp_to(..=1), 1); + /// assert_eq!(5.clamp_to(7..), 7); + /// ``` + #[must_use] + #[inline] + #[unstable(feature = "clamp_to", issue = "147781")] + fn clamp_to(self, range: R) -> Self + where + Self: Sized + [const] Destruct, + R: [const] ClampBounds, + { + range.clamp(self) + } } /// Derive macro generating an impl of the trait [`Ord`]. diff --git a/library/core/src/cmp/clamp.rs b/library/core/src/cmp/clamp.rs new file mode 100644 index 0000000000000..2743c5710d2f6 --- /dev/null +++ b/library/core/src/cmp/clamp.rs @@ -0,0 +1,100 @@ +use crate::marker::Destruct; +use crate::ops::{RangeFrom, RangeFull, RangeInclusive, RangeToInclusive}; + +/// Trait for ranges supported by [`Ord::clamp_to`]. +#[unstable(feature = "clamp_bounds", issue = "147781")] +#[rustc_const_unstable(feature = "clamp_bounds", issue = "147781")] +pub const trait ClampBounds: Sized { + /// The implementation of [`Ord::clamp_to`]. + fn clamp(self, value: T) -> T + where + T: [const] Destruct; +} + +#[unstable(feature = "clamp_bounds", issue = "147781")] +#[rustc_const_unstable(feature = "clamp_bounds", issue = "147781")] +const impl ClampBounds for RangeFrom +where + T: [const] Ord, +{ + fn clamp(self, value: T) -> T + where + T: [const] Destruct, + { + value.max(self.start) + } +} + +#[unstable(feature = "clamp_bounds", issue = "147781")] +#[rustc_const_unstable(feature = "clamp_bounds", issue = "147781")] +const impl ClampBounds for RangeToInclusive +where + T: [const] Ord, +{ + fn clamp(self, value: T) -> T + where + T: [const] Destruct, + { + value.min(self.end) + } +} + +#[unstable(feature = "clamp_bounds", issue = "147781")] +#[rustc_const_unstable(feature = "clamp_bounds", issue = "147781")] +const impl ClampBounds for RangeInclusive +where + T: [const] Ord, +{ + fn clamp(self, value: T) -> T + where + T: [const] Destruct, + { + let (start, end) = self.into_inner(); + value.clamp(start, end) + } +} + +#[unstable(feature = "clamp_bounds", issue = "147781")] +#[rustc_const_unstable(feature = "clamp_bounds", issue = "147781")] +const impl ClampBounds for RangeFull { + fn clamp(self, value: T) -> T { + value + } +} + +macro impl_for_float($t:ty) { + #[unstable(feature = "clamp_bounds", issue = "147781")] + #[rustc_const_unstable(feature = "clamp_bounds", issue = "147781")] + const impl ClampBounds<$t> for RangeFrom<$t> { + fn clamp(self, value: $t) -> $t { + assert!(!self.start.is_nan(), "start was NaN"); + value.max(self.start) + } + } + + #[unstable(feature = "clamp_bounds", issue = "147781")] + #[rustc_const_unstable(feature = "clamp_bounds", issue = "147781")] + const impl ClampBounds<$t> for RangeToInclusive<$t> { + fn clamp(self, value: $t) -> $t { + assert!(!self.end.is_nan(), "end was NaN"); + value.min(self.end) + } + } + + #[unstable(feature = "clamp_bounds", issue = "147781")] + #[rustc_const_unstable(feature = "clamp_bounds", issue = "147781")] + const impl ClampBounds<$t> for RangeInclusive<$t> { + fn clamp(self, value: $t) -> $t { + let (start, end) = self.into_inner(); + assert!(start <= end, "start > end, or either was NaN"); + value.clamp(start, end) + } + } +} + +// #[unstable(feature = "f16", issue = "116909")] +impl_for_float!(f16); +impl_for_float!(f32); +impl_for_float!(f64); +// #[unstable(feature = "f128", issue = "116909")] +impl_for_float!(f128); diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 4875835695e69..e95e61b73344c 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1455,6 +1455,41 @@ impl f128 { self.clamp(-limit, limit) } + /// Restrict a value to a certain range, unless it is NaN. + /// + /// This is largely equal to `max`, `min`, or `clamp`, depending on whether the range is + /// `min..`, `..=max`, or `min..=max`, respectively. However, unlike `max` and `min`, it will + /// panic if any bound is NaN. + /// + /// Note that this function returns NaN if the initial value was NaN as + /// well. + /// + /// Exclusive ranges are not permitted. + /// + /// # Panics + /// + /// Panics on `min..=max` if `min > max`, or if any bound is NaN. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128, clamp_to)] + /// assert_eq!((-3.0f128).clamp_to(-2.0..=1.0), -2.0); + /// assert_eq!(0.0f128.clamp_to(-2.0..=1.0), 0.0); + /// assert_eq!(2.0f128.clamp_to(..=1.0), 1.0); + /// assert_eq!(5.0f128.clamp_to(7.0..), 7.0); + /// assert!(f128::NAN.clamp_to(1.0..=2.0).is_nan()); + /// ``` + #[must_use] + #[inline] + #[unstable(feature = "clamp_to", issue = "147781")] + pub fn clamp_to(self, range: R) -> Self + where + R: crate::cmp::ClampBounds, + { + range.clamp(self) + } + /// Computes the absolute value of `self`. /// /// This function always returns the precise result. diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 186945db9ae92..0eb2da3594281 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1441,6 +1441,41 @@ impl f16 { self.clamp(-limit, limit) } + /// Restrict a value to a certain range, unless it is NaN. + /// + /// This is largely equal to `max`, `min`, or `clamp`, depending on whether the range is + /// `min..`, `..=max`, or `min..=max`, respectively. However, unlike `max` and `min`, it will + /// panic if any bound is NaN. + /// + /// Note that this function returns NaN if the initial value was NaN as + /// well. + /// + /// Exclusive ranges are not permitted. + /// + /// # Panics + /// + /// Panics on `min..=max` if `min > max`, or if any bound is NaN. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16, clamp_to)] + /// assert_eq!((-3.0f16).clamp_to(-2.0..=1.0), -2.0); + /// assert_eq!(0.0f16.clamp_to(-2.0..=1.0), 0.0); + /// assert_eq!(2.0f16.clamp_to(..=1.0), 1.0); + /// assert_eq!(5.0f16.clamp_to(7.0..), 7.0); + /// assert!(f16::NAN.clamp_to(1.0..=2.0).is_nan()); + /// ``` + #[must_use] + #[inline] + #[unstable(feature = "clamp_to", issue = "147781")] + pub fn clamp_to(self, range: R) -> Self + where + R: crate::cmp::ClampBounds, + { + range.clamp(self) + } + /// Computes the absolute value of `self`. /// /// This function always returns the precise result. diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 92ecabc581839..4751c5fe0cdd7 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1609,6 +1609,41 @@ impl f32 { self.clamp(-limit, limit) } + /// Restrict a value to a certain range, unless it is NaN. + /// + /// This is largely equal to `max`, `min`, or `clamp`, depending on whether the range is + /// `min..`, `..=max`, or `min..=max`, respectively. However, unlike `max` and `min`, it will + /// panic if any bound is NaN. + /// + /// Note that this function returns NaN if the initial value was NaN as + /// well. + /// + /// Exclusive ranges are not permitted. + /// + /// # Panics + /// + /// Panics on `min..=max` if `min > max`, or if any bound is NaN. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp_to)] + /// assert_eq!((-3.0f32).clamp_to(-2.0..=1.0), -2.0); + /// assert_eq!(0.0f32.clamp_to(-2.0..=1.0), 0.0); + /// assert_eq!(2.0f32.clamp_to(..=1.0), 1.0); + /// assert_eq!(5.0f32.clamp_to(7.0..), 7.0); + /// assert!(f32::NAN.clamp_to(1.0..=2.0).is_nan()); + /// ``` + #[must_use] + #[inline] + #[unstable(feature = "clamp_to", issue = "147781")] + pub fn clamp_to(self, range: R) -> Self + where + R: crate::cmp::ClampBounds, + { + range.clamp(self) + } + /// Computes the absolute value of `self`. /// /// This function always returns the precise result. diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 6470658d3ea35..53712505afc20 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1589,6 +1589,41 @@ impl f64 { self.clamp(-limit, limit) } + /// Restrict a value to a certain range, unless it is NaN. + /// + /// This is largely equal to `max`, `min`, or `clamp`, depending on whether the range is + /// `min..`, `..=max`, or `min..=max`, respectively. However, unlike `max` and `min`, it will + /// panic if any bound is NaN. + /// + /// Note that this function returns NaN if the initial value was NaN as + /// well. + /// + /// Exclusive ranges are not permitted. + /// + /// # Panics + /// + /// Panics on `min..=max` if `min > max`, or if any bound is NaN. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp_to)] + /// assert_eq!((-3.0f64).clamp_to(-2.0..=1.0), -2.0); + /// assert_eq!(0.0f64.clamp_to(-2.0..=1.0), 0.0); + /// assert_eq!(2.0f64.clamp_to(..=1.0), 1.0); + /// assert_eq!(5.0f64.clamp_to(7.0..), 7.0); + /// assert!(f64::NAN.clamp_to(1.0..=2.0).is_nan()); + /// ``` + #[must_use] + #[inline] + #[unstable(feature = "clamp_to", issue = "147781")] + pub fn clamp_to(self, range: R) -> Self + where + R: crate::cmp::ClampBounds, + { + range.clamp(self) + } + /// Computes the absolute value of `self`. /// /// This function always returns the precise result. diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index ec2201aa7b9da..f528746a09af7 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -13,6 +13,7 @@ #![feature(casefold)] #![feature(cfg_target_has_reliable_f16_f128)] #![feature(char_internals)] +#![feature(clamp_to)] #![feature(clone_to_uninit)] #![feature(cmp_minmax)] #![feature(const_array)] diff --git a/library/coretests/tests/num/floats.rs b/library/coretests/tests/num/floats.rs index 1d7956b41c9d1..e20540091da0c 100644 --- a/library/coretests/tests/num/floats.rs +++ b/library/coretests/tests/num/floats.rs @@ -1359,6 +1359,48 @@ float_test! { } } +float_test! { + name: clamp_to_min_greater_than_max, + attrs: { + const: #[cfg(false)], + f16: #[should_panic, cfg(target_has_reliable_f16)], + f32: #[should_panic], + f64: #[should_panic], + f128: #[should_panic, cfg(target_has_reliable_f128)], + }, + test { + let _ = Float::ONE.clamp_to(3.0..=1.0); + } +} + +float_test! { + name: clamp_to_min_is_nan, + attrs: { + const: #[cfg(false)], + f16: #[should_panic, cfg(target_has_reliable_f16)], + f32: #[should_panic], + f64: #[should_panic], + f128: #[should_panic, cfg(target_has_reliable_f128)], + }, + test { + let _ = Float::ONE.clamp_to(Float::NAN..=1.0); + } +} + +float_test! { + name: clamp_to_max_is_nan, + attrs: { + const: #[cfg(false)], + f16: #[should_panic, cfg(target_has_reliable_f16)], + f32: #[should_panic], + f64: #[should_panic], + f128: #[should_panic, cfg(target_has_reliable_f128)], + }, + test { + let _ = Float::ONE.clamp_to(3.0..=Float::NAN); + } +} + float_test! { name: total_cmp, attrs: { From 1a7439cc0ff575fd39e71e1519b3f4c80b9140f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 20 Jun 2026 11:22:40 +0200 Subject: [PATCH 02/14] Fix `flag_if_supported` in `cc-rs` by configuring an `out_dir` --- src/bootstrap/src/utils/cc_detect.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index d010226f0dfdb..9524d5fd8672f 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -36,6 +36,8 @@ fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build { .opt_level(2) .warnings(false) .debug(false) + // We have to configure out_dir, otherwise flag_if_supported will not work + .out_dir(build.tempdir().join("cc-rs-out-dir")) // Compress debuginfo .flag_if_supported("-gz") .target(&target.triple) From f832372b5e64a8c82fc703c2825b42325bad4f94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 20 Jun 2026 11:23:07 +0200 Subject: [PATCH 03/14] Slightly refactor cc code --- src/bootstrap/src/utils/cc_detect.rs | 14 ++++++-------- src/bootstrap/src/utils/cc_detect/tests.rs | 4 ++-- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index 9524d5fd8672f..8a4f991bdafa5 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -102,17 +102,15 @@ pub fn fill_target_compiler(build: &mut Build, target: TargetSelection) { let config = build.config.target_config.get(&target); if let Some(cc) = config .and_then(|c| c.cc.clone()) - .or_else(|| default_compiler(&mut cfg, Language::C, target, build)) + .or_else(|| default_compiler(&cfg, Language::C, target, build)) { cfg.compiler(cc); } let compiler = cfg.get_compiler(); - let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) { - ar - } else { - cfg.try_get_archiver().map(|c| PathBuf::from(c.get_program())).ok() - }; + let ar = config + .and_then(|c| c.ar.clone()) + .or_else(|| cfg.try_get_archiver().map(|c| PathBuf::from(c.get_program())).ok()); build.cc.insert(target, compiler.clone()); let mut cflags = build.cc_handled_clags(target, CLang::C); @@ -124,7 +122,7 @@ pub fn fill_target_compiler(build: &mut Build, target: TargetSelection) { cfg.cpp(true); let cxx_configured = if let Some(cxx) = config .and_then(|c| c.cxx.clone()) - .or_else(|| default_compiler(&mut cfg, Language::CPlusPlus, target, build)) + .or_else(|| default_compiler(&cfg, Language::CPlusPlus, target, build)) { cfg.compiler(cxx); true @@ -160,7 +158,7 @@ pub fn fill_target_compiler(build: &mut Build, target: TargetSelection) { /// Determines the default compiler for a given target and language when not explicitly /// configured in `bootstrap.toml`. fn default_compiler( - cfg: &mut cc::Build, + cfg: &cc::Build, compiler: Language, target: TargetSelection, build: &Build, diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs index a6233e6b61c1f..30757a39caa1c 100644 --- a/src/bootstrap/src/utils/cc_detect/tests.rs +++ b/src/bootstrap/src/utils/cc_detect/tests.rs @@ -86,7 +86,7 @@ fn test_default_compiler_wasi() { build.wasi_sdk_path = Some(wasi_sdk.clone()); let mut cfg = cc::Build::new(); - if let Some(result) = default_compiler(&mut cfg, Language::C, target.clone(), &build) { + if let Some(result) = default_compiler(&cfg, Language::C, target.clone(), &build) { let expected = { let compiler = format!("{}-clang", target.triple); wasi_sdk.join("bin").join(compiler) @@ -105,7 +105,7 @@ fn test_default_compiler_fallback() { let build = Build::new(config); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); let mut cfg = cc::Build::new(); - let result = default_compiler(&mut cfg, Language::C, target, &build); + let result = default_compiler(&cfg, Language::C, target, &build); assert!(result.is_none(), "default_compiler should return None for generic targets"); } From ae0fb2792bd0e992ed558c3e69ed7357e7406a3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 20 Jun 2026 12:54:03 +0200 Subject: [PATCH 04/14] Add missing zlib library to `x86_64-gnu-distcheck` --- src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile index 5ab44df7a8033..48be0b9f96e9d 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile @@ -28,6 +28,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils \ libssl-dev \ pkg-config \ + zlib1g-dev \ && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ From 65f06572fb81da89a1a87373aa3e6128060210c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 21 Jun 2026 13:42:16 +0200 Subject: [PATCH 05/14] Add `compress-debuginfo` option to bootstrap and fix debuginfo compression with LLD. --- bootstrap.example.toml | 14 ++++++ src/bootstrap/src/core/builder/cargo.rs | 11 +++-- src/bootstrap/src/core/config/config.rs | 14 +++++- src/bootstrap/src/core/config/mod.rs | 48 ++++++++++++++++++++ src/bootstrap/src/core/config/toml/rust.rs | 5 +- src/bootstrap/src/core/config/toml/target.rs | 4 +- src/bootstrap/src/utils/cc_detect.rs | 12 +++-- src/bootstrap/src/utils/change_tracker.rs | 5 ++ 8 files changed, 103 insertions(+), 10 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 25e2ca5948bfb..a52d2e945536e 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -697,6 +697,13 @@ # FIXME(#61117): Some tests fail when this option is enabled. #rust.debuginfo-level-tests = 0 +# Compress debuginfo of Rust and C/C++ code. +# Valid options: +# - "off" or false: disable compression +# - true: compress debuginfo with the default compression method (currently zlib) +# - "zlib": compress debuginfo with zlib +#rust.compress-debuginfo = "off" + # Should rustc and the standard library be built with split debuginfo? Default # is platform dependent. # @@ -1019,6 +1026,13 @@ # and enabling it causes issues. #split-debuginfo = if linux || windows-gnu { off } else if windows-msvc { packed } else if apple { unpacked } +# Compress debuginfo for Rust and C/C++ code of this target. +# Valid options: +# - "off" or false: disable compression +# - true: compress debuginfo with the default compression method (currently zlib) +# - "zlib": compress debuginfo with zlib +#compress-debuginfo = "off" + # Path to the `llvm-config` binary of the installation of a custom LLVM to link # against. Note that if this is specified we don't compile LLVM at all for this # target. diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index e7fe8bd1f3858..9122815d8db32 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -5,8 +5,8 @@ use std::path::{Path, PathBuf}; use super::{Builder, Kind}; use crate::core::build_steps::test; use crate::core::build_steps::tool::SourceType; -use crate::core::config::SplitDebuginfo; use crate::core::config::flags::Color; +use crate::core::config::{CompressDebuginfo, SplitDebuginfo}; use crate::utils::build_stamp; use crate::utils::helpers::{self, LldThreads, check_cfg_arg, linker_flags}; use crate::{ @@ -340,8 +340,13 @@ impl Cargo { self.rustdocflags.arg(&arg); } - if !builder.config.dry_run() && builder.cc[&target].args().iter().any(|arg| arg == "-gz") { - self.rustflags.arg("-Clink-arg=-gz"); + if !builder.config.dry_run() { + match builder.config.compress_debuginfo(target) { + CompressDebuginfo::Zlib => { + self.rustflags.arg("-Clink-arg=-Wl,--compress-debug-sections=zlib"); + } + CompressDebuginfo::Off => {} + } } // Ignore linker warnings for now. These are complicated to fix and don't affect the build. diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 5a9c7264c006f..ed5dd9c9ee9fa 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -49,8 +49,8 @@ use crate::core::config::toml::target::{ DefaultLinuxLinkerOverride, Target, TomlTarget, default_linux_linker_overrides, }; use crate::core::config::{ - CompilerBuiltins, DebuginfoLevel, DryRun, GccCiMode, LlvmLibunwind, Merge, ReplaceOpt, - RustcLto, SplitDebuginfo, StringOrBool, threads_from_config, + CompilerBuiltins, CompressDebuginfo, DebuginfoLevel, DryRun, GccCiMode, LlvmLibunwind, Merge, + ReplaceOpt, RustcLto, SplitDebuginfo, StringOrBool, threads_from_config, }; use crate::core::download::{ DownloadContext, download_beta_toolchain, is_download_ci_available, maybe_download_rustfmt, @@ -210,6 +210,7 @@ pub struct Config { pub rust_debuginfo_level_std: DebuginfoLevel, pub rust_debuginfo_level_tools: DebuginfoLevel, pub rust_debuginfo_level_tests: DebuginfoLevel, + pub rust_compress_debuginfo: CompressDebuginfo, pub rust_rpath: bool, pub rust_strip: bool, pub rust_frame_pointers: bool, @@ -550,6 +551,7 @@ impl Config { debuginfo_level_std: rust_debuginfo_level_std, debuginfo_level_tools: rust_debuginfo_level_tools, debuginfo_level_tests: rust_debuginfo_level_tests, + compress_debuginfo: rust_compress_debuginfo, backtrace: rust_backtrace, incremental: rust_incremental, randomize_layout: rust_randomize_layout, @@ -1469,6 +1471,7 @@ impl Config { .unwrap_or(vec![CodegenBackendKind::Llvm]), rust_codegen_units: rust_codegen_units.map(threads_from_config), rust_codegen_units_std: rust_codegen_units_std.map(threads_from_config), + rust_compress_debuginfo: rust_compress_debuginfo.unwrap_or_default(), rust_debug_logging: rust_debug_logging .or(rust_rustc_debug_assertions) .unwrap_or(rust_debug == Some(true)), @@ -1925,6 +1928,13 @@ impl Config { .unwrap_or_else(|| SplitDebuginfo::default_for_platform(target)) } + pub fn compress_debuginfo(&self, target: TargetSelection) -> CompressDebuginfo { + self.target_config + .get(&target) + .and_then(|t| t.compress_debuginfo) + .unwrap_or(self.rust_compress_debuginfo) + } + /// Checks if the given target is the same as the host target. pub fn is_host_target(&self, target: TargetSelection) -> bool { self.host_target == target diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs index 7651def62672a..c29849cf5a5d6 100644 --- a/src/bootstrap/src/core/config/mod.rs +++ b/src/bootstrap/src/core/config/mod.rs @@ -32,6 +32,7 @@ use std::path::PathBuf; use build_helper::exit; pub use config::*; +use serde::de::Unexpected; use serde::{Deserialize, Deserializer}; use serde_derive::Deserialize; pub use target_selection::TargetSelection; @@ -378,6 +379,53 @@ impl std::str::FromStr for SplitDebuginfo { } } +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)] +pub enum CompressDebuginfo { + Zlib, + #[default] + Off, +} + +impl CompressDebuginfo { + fn default_on() -> Self { + Self::Zlib + } +} + +impl std::str::FromStr for CompressDebuginfo { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "zlib" => Ok(CompressDebuginfo::Zlib), + "off" => Ok(CompressDebuginfo::Off), + _ => Err(()), + } + } +} + +impl<'de> Deserialize<'de> for CompressDebuginfo { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use serde::de::Error; + + Ok(match Deserialize::deserialize(deserializer)? { + StringOrBool::Bool(value) => { + if value { + CompressDebuginfo::default_on() + } else { + CompressDebuginfo::Off + } + } + StringOrBool::String(value) => CompressDebuginfo::from_str(&value).map_err(|_| { + D::Error::invalid_value(Unexpected::Str(&value), &"`zlib` or `off`") + })?, + }) + } +} + /// Describes how to handle conflicts in merging two `TomlConfig` #[derive(Copy, Clone, Debug)] pub enum ReplaceOpt { diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index a872671343405..f190eec3761ed 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -5,7 +5,7 @@ use build_helper::ci::CiEnv; use serde::{Deserialize, Deserializer}; use crate::core::config::toml::TomlConfig; -use crate::core::config::{DebuginfoLevel, Merge, ReplaceOpt, StringOrBool}; +use crate::core::config::{CompressDebuginfo, DebuginfoLevel, Merge, ReplaceOpt, StringOrBool}; use crate::{BTreeSet, CodegenBackendKind, HashSet, PathBuf, TargetSelection, define_config, exit}; define_config! { @@ -28,6 +28,7 @@ define_config! { debuginfo_level_std: Option = "debuginfo-level-std", debuginfo_level_tools: Option = "debuginfo-level-tools", debuginfo_level_tests: Option = "debuginfo-level-tests", + compress_debuginfo: Option = "compress-debuginfo", backtrace: Option = "backtrace", incremental: Option = "incremental", default_linker: Option = "default-linker", @@ -322,6 +323,7 @@ pub fn check_incompatible_options_for_ci_rustc( randomize_layout, debug_logging, debuginfo_level_rustc, + compress_debuginfo, llvm_tools, llvm_bitcode_linker, stack_protector, @@ -389,6 +391,7 @@ pub fn check_incompatible_options_for_ci_rustc( err!(current_rust_config.optimize, optimize, "rust"); err!(current_rust_config.randomize_layout, randomize_layout, "rust"); + err!(current_rust_config.compress_debuginfo, compress_debuginfo, "rust"); err!(current_rust_config.debug_logging, debug_logging, "rust"); err!(current_rust_config.debuginfo_level_rustc, debuginfo_level_rustc, "rust"); err!(current_rust_config.rpath, rpath, "rust"); diff --git a/src/bootstrap/src/core/config/toml/target.rs b/src/bootstrap/src/core/config/toml/target.rs index 847b75e696b47..311d9add9a144 100644 --- a/src/bootstrap/src/core/config/toml/target.rs +++ b/src/bootstrap/src/core/config/toml/target.rs @@ -15,7 +15,8 @@ use serde::de::Error; use serde::{Deserialize, Deserializer}; use crate::core::config::{ - CompilerBuiltins, LlvmLibunwind, Merge, ReplaceOpt, SplitDebuginfo, StringOrBool, + CompilerBuiltins, CompressDebuginfo, LlvmLibunwind, Merge, ReplaceOpt, SplitDebuginfo, + StringOrBool, }; use crate::{CodegenBackendKind, HashSet, PathBuf, define_config, exit}; @@ -68,6 +69,7 @@ pub struct Target { pub default_linker_linux_override: DefaultLinuxLinkerOverride, pub linker: Option, pub split_debuginfo: Option, + pub compress_debuginfo: Option, pub sanitizers: Option, pub profiler: Option, pub rpath: Option, diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index 8a4f991bdafa5..320dfcc4e69ed 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -25,7 +25,7 @@ use std::collections::HashSet; use std::iter; use std::path::{Path, PathBuf}; -use crate::core::config::TargetSelection; +use crate::core::config::{CompressDebuginfo, TargetSelection}; use crate::utils::exec::{BootstrapCommand, command}; use crate::{Build, CLang, GitRepo}; @@ -38,10 +38,16 @@ fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build { .debug(false) // We have to configure out_dir, otherwise flag_if_supported will not work .out_dir(build.tempdir().join("cc-rs-out-dir")) - // Compress debuginfo - .flag_if_supported("-gz") .target(&target.triple) .host(&build.host_target.triple); + + match build.config.compress_debuginfo(target) { + CompressDebuginfo::Zlib => { + cfg.flag_if_supported("-gz"); + } + CompressDebuginfo::Off => {} + } + match build.crt_static(target) { Some(a) => { cfg.static_crt(a); diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 566ad003ebe01..b34c1b55700f8 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -631,4 +631,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "New `--verbose-run-make-subprocess-output` flag for `x.py test` (defaults to true). Set `--verbose-run-make-subprocess-output=false` to suppress verbose subprocess output for passing run-make tests when using `--no-capture`.", }, + ChangeInfo { + change_id: 158169, + severity: ChangeSeverity::Info, + summary: "New option `rust.compress-debuginfo` allows configuring whether Rust and C/C++ debuginfo should be compressed.", + }, ]; From 10c2c9decb27dcfb846da377269c3e5d991d9866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 21 Jun 2026 13:44:49 +0200 Subject: [PATCH 06/14] Enable debuginfo compression by default in dist builds --- src/bootstrap/defaults/bootstrap.dist.toml | 2 ++ src/ci/run.sh | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/bootstrap/defaults/bootstrap.dist.toml b/src/bootstrap/defaults/bootstrap.dist.toml index cce3f068aabcd..03e012079b079 100644 --- a/src/bootstrap/defaults/bootstrap.dist.toml +++ b/src/bootstrap/defaults/bootstrap.dist.toml @@ -26,6 +26,8 @@ download-rustc = false llvm-bitcode-linker = true # Required to make builds reproducible. remap-debuginfo = true +# Compress debuginfo in generated artifacts to reduce their size +compress-debuginfo = "zlib" [dist] # Use better compression when preparing tarballs. diff --git a/src/ci/run.sh b/src/ci/run.sh index 18b5bf2e2bbb3..883cc20ba0014 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -145,6 +145,8 @@ if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then fi else RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.remap-debuginfo=false" + # No need to compress debuginfo for tests, and we do not want to depend on zlib + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.compress-debuginfo=off" # We almost always want debug assertions enabled, but sometimes this takes too # long for too little benefit, so we just turn them off. From d3e3e6781f8679ba045655e47438197a2afc4fb1 Mon Sep 17 00:00:00 2001 From: jyn Date: Thu, 25 Jun 2026 11:54:32 +0200 Subject: [PATCH 07/14] give a better error when `getrandom` fails --- library/std/src/sys/random/linux.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/random/linux.rs b/library/std/src/sys/random/linux.rs index 9b6d16e196ac1..6a4e4f3e670db 100644 --- a/library/std/src/sys/random/linux.rs +++ b/library/std/src/sys/random/linux.rs @@ -123,7 +123,9 @@ fn getrandom(mut bytes: &mut [u8], insecure: bool) { GETRANDOM_AVAILABLE.store(false, Relaxed); break; } - _ => panic!("failed to generate random data"), + other => { + panic!("failed to generate random data: errno={other:?}, flags={flags:?}") + } } } } From 3886e7ff0d4bb5c8bfd95a657e98e56466dbbcc2 Mon Sep 17 00:00:00 2001 From: Rachel Barker Date: Thu, 25 Jun 2026 14:27:34 +0100 Subject: [PATCH 08/14] Mark linux-getrandom-fallback test as needs-unwind Fixes test failures on {aarch64*-none, armv7r-eabihf, thumbv7em-eabi*} targets which have panic=abort by default --- tests/ui/std/linux-getrandom-fallback.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ui/std/linux-getrandom-fallback.rs b/tests/ui/std/linux-getrandom-fallback.rs index c50fbe8257af6..81c0fa623d835 100644 --- a/tests/ui/std/linux-getrandom-fallback.rs +++ b/tests/ui/std/linux-getrandom-fallback.rs @@ -1,5 +1,6 @@ //@ only-linux //@ run-pass +//@ needs-unwind #![feature(random)] #![feature(rustc_private)] From 03d78511882193e5b3a19839ee04a69a37746605 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 30 Jun 2026 15:32:00 +0000 Subject: [PATCH 09/14] add EarlyBinder::def_id helper and remove direct calls to instantiate_identity().skip_norm_wip().def_id --- compiler/rustc_hir_analysis/src/check/check.rs | 5 ++--- compiler/rustc_mir_transform/src/check_call_recursion.rs | 2 +- compiler/rustc_type_ir/src/binder.rs | 6 ++++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 0aa31c3a016b9..aa204a20e2d57 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -839,9 +839,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), tcx.ensure_ok().associated_items(def_id); if of_trait { let impl_trait_header = tcx.impl_trait_header(def_id); - res = res.and(tcx.ensure_result().coherent_trait( - impl_trait_header.trait_ref.instantiate_identity().skip_norm_wip().def_id, - )); + res = res + .and(tcx.ensure_result().coherent_trait(impl_trait_header.trait_ref.def_id())); if res.is_ok() { // Checking this only makes sense if the all trait impls satisfy basic diff --git a/compiler/rustc_mir_transform/src/check_call_recursion.rs b/compiler/rustc_mir_transform/src/check_call_recursion.rs index 216ada600ce34..73c1510b9a0e2 100644 --- a/compiler/rustc_mir_transform/src/check_call_recursion.rs +++ b/compiler/rustc_mir_transform/src/check_call_recursion.rs @@ -45,7 +45,7 @@ impl<'tcx> MirLint<'tcx> for CheckDropRecursion { if let DefKind::AssocFn = tcx.def_kind(def_id) && let Some(impl_id) = tcx.trait_impl_of_assoc(def_id.to_def_id()) && let trait_ref = tcx.impl_trait_ref(impl_id) - && tcx.is_lang_item(trait_ref.instantiate_identity().skip_norm_wip().def_id, LangItem::Drop) + && tcx.is_lang_item(trait_ref.def_id(), LangItem::Drop) // avoid erroneous `Drop` impls from causing ICEs below && let sig = tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip() && sig.inputs().skip_binder().len() == 1 diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 8ddc53b8e0ab5..6f41a608763e3 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -448,6 +448,12 @@ impl EarlyBinder { } } +impl EarlyBinder> { + pub fn def_id(&self) -> I::TraitId { + self.value.def_id + } +} + impl EarlyBinder> { pub fn transpose(self) -> Option> { self.value.map(|value| EarlyBinder { value, _tcx: PhantomData }) From 9f7569bb6a570bcb111ffcb82d9eccedd8619293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 30 Jun 2026 09:55:36 +0200 Subject: [PATCH 10/14] Do not use zlib compression on Windows and macOS --- src/bootstrap/src/core/builder/cargo.rs | 7 ++++++- src/bootstrap/src/core/config/target_selection.rs | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 9122815d8db32..f495f0f209750 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -343,7 +343,12 @@ impl Cargo { if !builder.config.dry_run() { match builder.config.compress_debuginfo(target) { CompressDebuginfo::Zlib => { - self.rustflags.arg("-Clink-arg=-Wl,--compress-debug-sections=zlib"); + // Do not enable Zlib compression on: + // - Windows, because MSVC/PDB doesn't support it + // - macOS, because its linker doesn't know the flag + if !self.target.is_windows() && !self.target.is_apple() { + self.rustflags.arg("-Clink-arg=-Wl,--compress-debug-sections=zlib"); + } } CompressDebuginfo::Off => {} } diff --git a/src/bootstrap/src/core/config/target_selection.rs b/src/bootstrap/src/core/config/target_selection.rs index 8457607b897dd..39bf2890017fa 100644 --- a/src/bootstrap/src/core/config/target_selection.rs +++ b/src/bootstrap/src/core/config/target_selection.rs @@ -82,6 +82,10 @@ impl TargetSelection { self.contains("windows") } + pub fn is_apple(&self) -> bool { + self.contains("apple") + } + pub fn is_windows_gnu(&self) -> bool { self.ends_with("windows-gnu") } From cd642bb6f95767991625d6be37bdc05ce957077b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 1 Jul 2026 08:36:07 +1000 Subject: [PATCH 11/14] Remove unnecessary `Clone` derives on resolver types The starting point of this commit is that `ModuleData`, `ImportData`, and `DeclData` are all interned, and don't need to be `Clone`. Then there are various types nestled within these types that also don't need to be `Clone`. --- compiler/rustc_expand/src/base.rs | 2 +- compiler/rustc_resolve/src/error_helper.rs | 2 +- compiler/rustc_resolve/src/imports.rs | 9 ++++----- compiler/rustc_resolve/src/late/diagnostics.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 4 ++-- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 31c776f3fef00..821f541170f62 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1199,7 +1199,7 @@ pub trait LintStoreExpand { type LintStoreExpandDyn<'a> = Option<&'a (dyn LintStoreExpand + 'a)>; -#[derive(Debug, Clone, Default)] +#[derive(Debug, Default)] pub struct ModuleData { /// Path to the module starting from the crate name, like `my_crate::foo::bar`. pub mod_path: Vec, diff --git a/compiler/rustc_resolve/src/error_helper.rs b/compiler/rustc_resolve/src/error_helper.rs index 1b7d799cadd35..c8abc3556f8fe 100644 --- a/compiler/rustc_resolve/src/error_helper.rs +++ b/compiler/rustc_resolve/src/error_helper.rs @@ -109,7 +109,7 @@ impl TypoSuggestion { } /// A free importable items suggested in case of resolution failure. -#[derive(Debug, Clone)] +#[derive(Debug)] pub(crate) struct ImportSuggestion { pub did: Option, pub descr: &'static str, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index a3cb526e60a87..303e333c4100e 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -69,7 +69,6 @@ impl<'ra> PendingDecl<'ra> { } /// Contains data for specific kinds of imports. -#[derive(Clone)] pub(crate) enum ImportKind<'ra> { Single { /// `source` in `use prefix::source as target`. @@ -157,7 +156,7 @@ impl<'ra> std::fmt::Debug for ImportKind<'ra> { } /// One import. -#[derive(Debug, Clone)] +#[derive(Debug)] pub(crate) struct ImportData<'ra> { pub kind: ImportKind<'ra>, @@ -280,7 +279,7 @@ impl<'ra> ImportData<'ra> { } /// Records information about the resolution of a name in a namespace of a module. -#[derive(Clone, Debug)] +#[derive(Debug)] pub(crate) struct NameResolution<'ra> { /// Single imports that may define the name in the namespace. /// Imports are arena-allocated, so it's ok to use pointers as keys. @@ -322,7 +321,7 @@ impl<'ra> NameResolution<'ra> { /// An error that may be transformed into a diagnostic later. Used to combine multiple unresolved /// import errors within the same use tree into a single diagnostic. -#[derive(Debug, Clone)] +#[derive(Debug)] pub(crate) struct UnresolvedImportError { pub(crate) span: Span, pub(crate) label: Option, @@ -341,7 +340,7 @@ fn pub_use_of_private_extern_crate_hack( import: ImportSummary, decl: Decl<'_>, ) -> Option { - match (import.is_single, decl.kind) { + match (import.is_single, &decl.kind) { (true, DeclKind::Import { import: decl_import, .. }) if let ImportKind::ExternCrate { def_id, .. } = decl_import.kind && import.vis.is_public() => diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 045e0ff523c7d..8c5c7f5b2d76d 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -133,7 +133,7 @@ pub(super) struct MissingLifetime { /// Description of the lifetimes appearing in a function parameter. /// This is used to provide a literal explanation to the elision failure. -#[derive(Clone, Debug)] +#[derive(Debug)] pub(super) struct ElisionFnParameter { /// The index of the argument in the original definition. pub index: usize, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index e6cfa469e91d0..382a3eecb455f 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -992,7 +992,7 @@ impl<'ra> fmt::Debug for LocalModule<'ra> { } /// Data associated with any name declaration. -#[derive(Clone, Debug)] +#[derive(Debug)] struct DeclData<'ra> { kind: DeclKind<'ra>, ambiguity: CmCell, bool /*warning*/)>>, @@ -1026,7 +1026,7 @@ impl std::hash::Hash for DeclData<'_> { } /// Name declaration kind. -#[derive(Clone, Copy, Debug)] +#[derive(Debug)] enum DeclKind<'ra> { /// The name declaration is a definition (possibly without a `DefId`), /// can be provided by source code or built into the language. From c6f92dcae05d07e723733f2c82cbe923480af832 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 1 Jul 2026 10:19:48 +1000 Subject: [PATCH 12/14] Add missing `needs_drop` check to `DroplessArena`. Three of the four public allocation functions in `DroplessArena` check that the allocated type doesn't implement `Drop`: `alloc`, `alloc_slice`, `alloc_from_iter`. This commit adds the missing check to `try_alloc_from_iter`. It also moves and reorders some lines in `alloc_from_iter` for consistency with the other methods. --- compiler/rustc_arena/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 24ade7300c33b..a4248a82bce73 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -542,11 +542,12 @@ impl DroplessArena { #[inline] pub fn alloc_from_iter>(&self, iter: I) -> &mut [T] { + assert!(!mem::needs_drop::()); + assert!(size_of::() != 0); + // Warning: this function is reentrant: `iter` could hold a reference to `&self` and // allocate additional elements while we're iterating. let iter = iter.into_iter(); - assert!(size_of::() != 0); - assert!(!mem::needs_drop::()); let size_hint = iter.size_hint(); @@ -577,6 +578,7 @@ impl DroplessArena { ) -> Result<&mut [T], E> { // Despite the similarity with `alloc_from_iter`, we cannot reuse their fast case, as we // cannot know the minimum length of the iterator in this case. + assert!(!mem::needs_drop::()); assert!(size_of::() != 0); // Takes care of reentrancy. From 4f436ab72ebd285b22a36170db0e807804b3f306 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas) Chirananthavat" Date: Wed, 1 Jul 2026 15:56:39 +0700 Subject: [PATCH 13/14] Document `strip_circumfix` behavior on overlapping prefix and suffix. Fixes https://github.com/rust-lang/rust/issues/158388, as per T-libs-api decision there. --- library/core/src/slice/mod.rs | 9 ++++++--- library/core/src/str/mod.rs | 7 +++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 7ab476e785d16..4b02e73a4dcc3 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2738,10 +2738,12 @@ impl [T] { /// Returns a subslice with the prefix and suffix removed. /// - /// If the slice starts with `prefix` and ends with `suffix`, returns the subslice after the - /// prefix and before the suffix, wrapped in `Some`. + /// If the slice starts with `prefix`, ends with `suffix`, and + /// the prefix and suffix don't overlap, returns the subslice after + /// the prefix and before the suffix, wrapped in `Some`. /// - /// If the slice does not start with `prefix` or does not end with `suffix`, returns `None`. + /// If the slice does not start with `prefix`, does not end with `suffix`, + /// or the prefix and suffix overlap in the slice, returns `None`. /// /// # Examples /// @@ -2754,6 +2756,7 @@ impl [T] { /// assert_eq!(v.strip_circumfix(&[10], &[40]), None); /// assert_eq!(v.strip_circumfix(&[], &[40, 30]), Some(&[10, 50][..])); /// assert_eq!(v.strip_circumfix(&[10, 50], &[]), Some(&[40, 30][..])); + /// assert_eq!(v.strip_circumfix(&[10, 50, 40], &[50, 40, 30]), None); /// ``` #[must_use = "returns the subslice without modifying the original"] #[stable(feature = "strip_circumfix", since = "CURRENT_RUSTC_VERSION")] diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 78cb8ca665e1e..2128ce328a9c6 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -2492,12 +2492,14 @@ impl str { /// Returns a string slice with the prefix and suffix removed. /// - /// If the string starts with the pattern `prefix` and ends with the pattern `suffix`, returns + /// If the string starts with the pattern `prefix` and ends with + /// the pattern `suffix`, and the prefix and suffix don't overlap, returns /// the substring after the prefix and before the suffix, wrapped in `Some`. /// Unlike [`trim_start_matches`] and [`trim_end_matches`], this method removes both the prefix /// and suffix exactly once. /// - /// If the string does not start with `prefix` or does not end with `suffix`, returns `None`. + /// If the string does not start with `prefix`, does not end with `suffix`, + /// or the prefix and suffix overlap in the string, returns `None`. /// /// Each [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. @@ -2513,6 +2515,7 @@ impl str { /// assert_eq!("bar:hello:foo".strip_circumfix("bar:", ":foo"), Some("hello")); /// assert_eq!("bar:foo".strip_circumfix("foo", "foo"), None); /// assert_eq!("foo:bar;".strip_circumfix("foo:", ';'), Some("bar")); + /// assert_eq!("foo:bar:baz".strip_circumfix("foo:bar:", ":bar:baz"), None); /// ``` #[must_use = "this returns the remaining substring as a new slice, \ without modifying the original"] From 92c10f9771fb1f5e05fc3c40a843d62395a53dc2 Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Wed, 1 Jul 2026 15:36:36 +0300 Subject: [PATCH 14/14] Support simplest output `Self` mapping in delegation --- compiler/rustc_ast_lowering/src/delegation.rs | 68 ++- .../src/delegation/generics.rs | 13 +- .../pretty/delegation/self-mapping-output.pp | 44 ++ .../pretty/delegation/self-mapping-output.rs | 33 ++ .../delegation/self-mapping-output-privacy.rs | 28 ++ .../self-mapping-output-privacy.stderr | 15 + tests/ui/delegation/self-mapping-output.rs | 357 +++++++++++++ .../ui/delegation/self-mapping-output.stderr | 468 ++++++++++++++++++ 8 files changed, 1021 insertions(+), 5 deletions(-) create mode 100644 tests/pretty/delegation/self-mapping-output.pp create mode 100644 tests/pretty/delegation/self-mapping-output.rs create mode 100644 tests/ui/delegation/self-mapping-output-privacy.rs create mode 100644 tests/ui/delegation/self-mapping-output-privacy.stderr create mode 100644 tests/ui/delegation/self-mapping-output.rs create mode 100644 tests/ui/delegation/self-mapping-output.stderr diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 078ebd6987ae3..2680e7223c1bc 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -53,7 +53,7 @@ use rustc_middle::span_bug; use rustc_middle::ty::{Asyncness, PerOwnerResolverData}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::symbol::kw; -use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; +use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym}; use crate::delegation::generics::{GenericsGenerationResult, GenericsGenerationResults}; use crate::diagnostics::{ @@ -661,11 +661,34 @@ impl<'hir> LoweringContext<'_, 'hir> { let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(new_path), span)); let args = self.arena.alloc_from_iter(args); - let call = self.arena.alloc(self.mk_expr(hir::ExprKind::Call(callee_path, args), span)); + let call = self.mk_expr(hir::ExprKind::Call(callee_path, args), span); + + let expr = if let Some((parent, of_trait)) = self.should_wrap_return_value(delegation) { + let res = Res::SelfTyAlias { alias_to: parent.to_def_id(), is_trait_impl: of_trait }; + let ident = Ident::new(kw::SelfUpper, span); + let path = self.create_resolved_path(res, ident, span); + + // FIXME(fn_delegation): add default `..` for all other fields. + let initializer = hir::ExprKind::Struct( + self.arena.alloc(path), + self.arena.alloc_slice(&[hir::ExprField { + hir_id: self.next_id(), + is_shorthand: false, + ident: Ident::new(sym::integer(0), span), + expr: self.arena.alloc(call), + span, + }]), + hir::StructTailExpr::None, + ); + + self.arena.alloc(self.mk_expr(initializer, span)) + } else { + self.arena.alloc(call) + }; let block = self.arena.alloc(hir::Block { stmts, - expr: Some(call), + expr: Some(expr), hir_id: self.next_id(), rules: hir::BlockCheckMode::DefaultBlock, span, @@ -675,6 +698,45 @@ impl<'hir> LoweringContext<'_, 'hir> { (self.mk_expr(hir::ExprKind::Block(block, None), span), call.hir_id) } + fn should_wrap_return_value(&self, delegation: &Delegation) -> Option<(LocalDefId, bool)> { + // Heuristic: don't do wrapping if there is no target expression. + if delegation.body.is_none() { + return None; + } + + let tcx = self.tcx; + let parent = tcx.local_parent(self.owner.def_id); + let parent_kind = tcx.def_kind(parent); + + // Apply wrapping for delegations inside + // 1) Trait impls, as the return type of both signature function + // and generated delegation has `Self` generic param returned + // (checked below). + // FIXME(fn_delegation): think of enabling wrapping in more scenarios: + // trait-(impl)-to-free + // trait-(impl)-to-inherent + // inherent-to-free + // 2) Inherent methods when delegating to trait, as we change the type of + // `Self` to type of struct or enum we delegate from. + if !matches!(tcx.def_kind(parent), DefKind::Impl { .. }) { + return None; + } + + let is_trait_impl = parent_kind == DefKind::Impl { of_trait: true }; + + // Check that delegation path resolves to a trait AssocFn, not to a free method. + Some((parent, is_trait_impl)).filter(|_| { + self.get_resolution_id(delegation.id).is_some_and(|id| { + tcx.def_kind(id) == DefKind::AssocFn + // Check that the return type of the callee is `Self` param. + // After previous check we are sure that `sig_id` and `delegation.id` + // point to the same function. + && tcx.def_kind(tcx.parent(id)) == DefKind::Trait + && tcx.fn_sig(id).skip_binder().output().skip_binder().is_param(0) + }) + }) + } + fn process_segment( &mut self, span: Span, diff --git a/compiler/rustc_ast_lowering/src/delegation/generics.rs b/compiler/rustc_ast_lowering/src/delegation/generics.rs index 79a3961c22a53..41e66ddc5e993 100644 --- a/compiler/rustc_ast_lowering/src/delegation/generics.rs +++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs @@ -581,18 +581,27 @@ impl<'hir> LoweringContext<'_, 'hir> { p.def_id.to_def_id(), ); + self.create_resolved_path(res, p.name.ident(), p.span) + } + + pub(super) fn create_resolved_path( + &mut self, + res: Res, + ident: Ident, + span: Span, + ) -> hir::QPath<'hir> { hir::QPath::Resolved( None, self.arena.alloc(hir::Path { segments: self.arena.alloc_slice(&[hir::PathSegment { args: None, hir_id: self.next_id(), - ident: p.name.ident(), + ident, infer_args: false, res, }]), res, - span: p.span, + span, }), ) } diff --git a/tests/pretty/delegation/self-mapping-output.pp b/tests/pretty/delegation/self-mapping-output.pp new file mode 100644 index 0000000000000..84e98d6e97b06 --- /dev/null +++ b/tests/pretty/delegation/self-mapping-output.pp @@ -0,0 +1,44 @@ +#![attr = Feature([fn_delegation#0])] +extern crate std; +#[attr = PreludeImport] +use ::std::prelude::rust_2015::*; +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:self-mapping-output.pp + + +trait Trait { + fn method(&self) + -> Self; + fn r#static() + -> Self; + fn raw_S(&self) -> S { S } +} + +struct S; +impl Trait for S { + fn method(&self) -> S { S } + fn r#static() -> S { S } +} + +struct W(S); +impl Trait for W { + #[attr = Inline(Hint)] + fn method(self: _) -> _ { Self { 0: Trait::method(self.0) } } + #[attr = Inline(Hint)] + fn r#static() -> _ { Trait::r#static() } + //~^ WARN: function cannot return without recursing [unconditional_recursion] + #[attr = Inline(Hint)] + fn raw_S(self: _) -> _ { Trait::raw_S(self.0) } +} + +impl W { + #[attr = Inline(Hint)] + fn method(self: _) -> _ { Self { 0: Trait::method(self.0) } } + #[attr = Inline(Hint)] + fn r#static() -> _ { Trait::r#static() } + #[attr = Inline(Hint)] + fn raw_S(self: _) -> _ { Trait::raw_S(self.0) } +} + +fn main() { } diff --git a/tests/pretty/delegation/self-mapping-output.rs b/tests/pretty/delegation/self-mapping-output.rs new file mode 100644 index 0000000000000..11699d710e081 --- /dev/null +++ b/tests/pretty/delegation/self-mapping-output.rs @@ -0,0 +1,33 @@ +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:self-mapping-output.pp + +#![feature(fn_delegation)] + +trait Trait { + fn method(&self) -> Self; + fn r#static() -> Self; + fn raw_S(&self) -> S { S } +} + +struct S; +impl Trait for S { + fn method(&self) -> S { S } + fn r#static() -> S { S } +} + +struct W(S); +impl Trait for W { + reuse Trait::method { self.0 } + reuse Trait::r#static; + //~^ WARN: function cannot return without recursing [unconditional_recursion] + reuse Trait::raw_S { self.0 } +} + +impl W { + reuse Trait::method { self.0 } + reuse Trait::r#static; + reuse Trait::raw_S { self.0 } +} + +fn main() {} diff --git a/tests/ui/delegation/self-mapping-output-privacy.rs b/tests/ui/delegation/self-mapping-output-privacy.rs new file mode 100644 index 0000000000000..f072d240608f8 --- /dev/null +++ b/tests/ui/delegation/self-mapping-output-privacy.rs @@ -0,0 +1,28 @@ +#![feature(fn_delegation)] + +trait Trait { + fn method(&self) -> Self; +} + +pub struct S; +impl Trait for S { + fn method(&self) -> S { + S + } +} + +mod private { + pub struct W(super::S); +} + +impl Trait for private::W { + reuse Trait::method { S } + //~^ ERROR: field `0` of struct `W` is private +} + +impl private::W { + reuse Trait::method { S } + //~^ ERROR: field `0` of struct `W` is private +} + +fn main() {} diff --git a/tests/ui/delegation/self-mapping-output-privacy.stderr b/tests/ui/delegation/self-mapping-output-privacy.stderr new file mode 100644 index 0000000000000..38f6b1a4a9ddf --- /dev/null +++ b/tests/ui/delegation/self-mapping-output-privacy.stderr @@ -0,0 +1,15 @@ +error[E0451]: field `0` of struct `W` is private + --> $DIR/self-mapping-output-privacy.rs:19:18 + | +LL | reuse Trait::method { S } + | ^^^^^^ private field + +error[E0451]: field `0` of struct `W` is private + --> $DIR/self-mapping-output-privacy.rs:24:18 + | +LL | reuse Trait::method { S } + | ^^^^^^ private field + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0451`. diff --git a/tests/ui/delegation/self-mapping-output.rs b/tests/ui/delegation/self-mapping-output.rs new file mode 100644 index 0000000000000..47b122b0accda --- /dev/null +++ b/tests/ui/delegation/self-mapping-output.rs @@ -0,0 +1,357 @@ +#![feature(fn_delegation)] + +mod success { + trait Trait { + fn method(&self) -> Self; + fn r#static() -> Self; + fn raw_S(&self) -> S { S } + } + + struct S; + impl Trait for S { + fn method(&self) -> S { S } + fn r#static() -> S { S } + } + + struct W(S); + impl Trait for W { + reuse Trait::method { self.0 } + reuse Trait::r#static; + //~^ WARN: function cannot return without recursing [unconditional_recursion] + reuse Trait::raw_S { self.0 } + } + + impl W { + reuse Trait::method { self.0 } + reuse Trait::r#static; + reuse Trait::raw_S { self.0 } + } +} + +mod success_non_field { + trait Trait { + fn method(&self) -> Self; + fn r#static() -> Self; + fn raw_S(&self) -> S { S } + } + + struct S; + impl Trait for S { + fn method(&self) -> S { S } + fn r#static() -> S { S } + } + + struct W(S); + impl Trait for W { + reuse Trait::method { S } + reuse Trait::r#static; + //~^ WARN: function cannot return without recursing [unconditional_recursion] + reuse Trait::raw_S { S } + } + + impl W { + reuse Trait::method { S } + reuse Trait::r#static; + reuse Trait::raw_S { S } + } +} + +mod success_generics { + trait Trait<'a, T, const N: usize> { + fn method(&self) -> Self; + fn r#static() -> Self; + fn raw_S(&self) -> S<'a, 'static, T, (), N, 123> { + S::<'a, 'static, T, (), N, 123>(std::marker::PhantomData) + } + } + + struct S<'a, 'b, A, B, const N: usize, const M: usize>( + std::marker::PhantomData<&'a &'b (A, B, &'a [(); N], &'b [(); M])> + ); + + impl<'a, T, const N: usize> Trait<'a, T, N> for S<'a, 'static, T, (), N, 123> { + fn method(&self) -> S<'a, 'static, T, (), N, 123> { + S(std::marker::PhantomData) + } + + fn r#static() -> S<'a, 'static, T, (), N, 123> { S(std::marker::PhantomData) } + } + + struct W<'a, 'b, A, B, const N: usize, const M: usize>(S<'a, 'b, A, B, N, M>); + impl<'a, T, const N: usize> Trait<'a, T, N> for W<'a, 'static, T, (), N, 123> { + reuse Trait::<'a, T, N>::method { self.0 } + reuse Trait::<'a, T, N>::r#static; + //~^ WARN: function cannot return without recursing [unconditional_recursion] + reuse Trait::<'a, T, N>::raw_S { self.0 } + } + + impl<'a, T, const N: usize> W<'a, 'static, T, (), N, 123> { + reuse Trait::<'a, T, N>::method { self.0 } + reuse Trait::<'a, T, N>::r#static; + reuse Trait::<'a, T, N>::raw_S { self.0 } + } +} + +mod no_constructor { + trait Trait { + fn method(&self) -> Self; + fn r#static() -> Self; + fn raw_S(&self) -> S { S } + } + + struct S; + impl Trait for S { + fn method(&self) -> S { S } + fn r#static() -> S { S } + } + + struct W { s: S } + impl Trait for W { + reuse Trait::method { self.0 } + //~^ ERROR: no field `0` on type `&no_constructor::W` + //~| ERROR: struct `no_constructor::W` has no field named `0` + reuse Trait::r#static; + //~^ WARN: function cannot return without recursing [unconditional_recursion] + reuse Trait::raw_S { self.0 } + //~^ ERROR: no field `0` on type `&no_constructor::W` + } + + impl W { + reuse Trait::method { self.0 } + //~^ ERROR: no field `0` on type `&no_constructor::W` + //~| ERROR: struct `no_constructor::W` has no field named `0` + reuse Trait::r#static; + reuse Trait::raw_S { self.0 } + //~^ ERROR: no field `0` on type `&no_constructor::W` + } +} + +mod more_than_one_field { + trait Trait { + fn method(&self) -> Self; + fn r#static() -> Self; + fn raw_S(&self) -> S { S } + } + + struct S; + impl Trait for S { + fn method(&self) -> S { S } + fn r#static() -> S { S } + } + + struct W(S, S, S); + impl Trait for W { + reuse Trait::method { self.0 } + //~^ ERROR: missing fields `1` and `2` in initializer of `more_than_one_field::W` + reuse Trait::r#static; + //~^ WARN: function cannot return without recursing [unconditional_recursion] + reuse Trait::raw_S { self.0 } + } + + impl W { + reuse Trait::method { self.0 } + //~^ ERROR: missing fields `1` and `2` in initializer of `more_than_one_field::W` + reuse Trait::r#static; + reuse Trait::raw_S { self.0 } + } +} + +mod non_trait_path_reuse { + trait Trait { + fn method(&self) -> Self; + fn r#static() -> Self; + fn raw_S(&self) -> S { S } + } + + mod to_reuse { + pub fn method(_: impl super::Trait) -> impl super::Trait { + super::S + } + + pub fn r#static() -> impl super::Trait { + super::S + } + } + + pub struct S; + impl Trait for S { + fn method(&self) -> S { S } + fn r#static() -> S { S } + } + + struct W(S); + impl Trait for W { + reuse to_reuse::method { self.0 } + //~^ ERROR: mismatched types + reuse to_reuse::r#static; + //~^ ERROR: mismatched types + } + + impl W { + reuse to_reuse::method { self.0 } + //~^ ERROR: no field `0` on type `impl super::Trait` + reuse to_reuse::r#static; + } +} + +mod non_Self_return_type { + trait Trait { + fn method(&self) -> (); + fn r#static() -> (); + fn raw_S(&self) -> S { S } + } + + struct S; + impl Trait for S { + fn method(&self) -> () { () } + fn r#static() -> () { () } + fn raw_S(&self) -> S { S } + } + + struct W(()); + impl Trait for W { + reuse Trait::method { self.0 } + //~^ ERROR: mismatched types + + reuse Trait::r#static; + //~^ ERROR: type annotations needed + + reuse Trait::raw_S { self.0 } + //~^ ERROR: mismatched types + } + + impl W { + reuse Trait::method { self.0 } + //~^ ERROR: mismatched types + + reuse Trait::r#static; + //~^ ERROR: type annotations needed + + reuse Trait::raw_S { self.0 } + //~^ ERROR: mismatched types + } +} + +mod wrong_return_type { + trait Trait { + fn method(&self) -> Self; + fn r#static() -> Self; + fn raw_S(&self) -> S { S } + } + + struct F; + impl Trait for F { + fn method(&self) -> F { F } + fn r#static() -> F { F } + } + + struct S; + impl Trait for S { + fn method(&self) -> S { S } + fn r#static() -> S { S } + } + + struct W(S); + impl Trait for W { + reuse ::method { self.0 } + //~^ ERROR: mismatched types + //~| ERROR: mismatched types + + reuse ::r#static; + //~^ ERROR: mismatched types + + reuse ::raw_S { self.0 } + //~^ ERROR: mismatched types + } + + impl W { + reuse ::method { self.0 } + //~^ ERROR: mismatched types + //~| ERROR: mismatched types + + reuse ::r#static; + //~^ ERROR: mismatched types + + reuse ::raw_S { self.0 } + //~^ ERROR: mismatched types + } +} + +mod wrong_target_expression { + trait Trait { + fn method(&self) -> Self; + fn r#static() -> Self; + fn raw_S(&self) -> S { S } + } + + struct S; + impl Trait for S { + fn method(&self) -> S { S } + fn r#static() -> S { S } + } + + struct F; + impl Trait for F { + fn method(&self) -> F { F } + fn r#static() -> F { F } + } + + struct W(S); + impl Trait for W { + reuse Trait::method { F } + //~^ ERROR: mismatched types + + reuse Trait::r#static; + //~^ WARN: function cannot return without recursing [unconditional_recursion] + reuse Trait::raw_S { F } + } + + impl W { + reuse Trait::method { F } + //~^ ERROR: mismatched types + + reuse Trait::r#static; + reuse Trait::raw_S { F } + } +} + +mod privacy { + trait Trait { + fn method(&self) -> Self; + fn r#static() -> Self; + fn raw_S(&self) -> S { S } + } + + pub struct S; + impl Trait for S { + fn method(&self) -> S { S } + fn r#static() -> S { S } + } + + mod private { + pub struct W(super::S); + } + + impl Trait for private::W { + reuse Trait::method { self.0 } + //~^ ERROR: field `0` of struct `private::W` is private + + reuse Trait::r#static; + //~^ WARN: function cannot return without recursing [unconditional_recursion] + + reuse Trait::raw_S { self.0 } + //~^ ERROR: field `0` of struct `private::W` is private + } + + impl private::W { + reuse Trait::method { self.0 } + //~^ ERROR: field `0` of struct `private::W` is private + + reuse Trait::r#static; + + reuse Trait::raw_S { self.0 } + //~^ ERROR: field `0` of struct `private::W` is private + } +} + +fn main() {} diff --git a/tests/ui/delegation/self-mapping-output.stderr b/tests/ui/delegation/self-mapping-output.stderr new file mode 100644 index 0000000000000..86ce822a1821c --- /dev/null +++ b/tests/ui/delegation/self-mapping-output.stderr @@ -0,0 +1,468 @@ +error[E0560]: struct `no_constructor::W` has no field named `0` + --> $DIR/self-mapping-output.rs:110:22 + | +LL | reuse Trait::method { self.0 } + | ^^^^^^ unknown field + | +help: a field with a similar name exists + | +LL - reuse Trait::method { self.0 } +LL + reuse Trait::s { self.0 } + | + +error[E0609]: no field `0` on type `&no_constructor::W` + --> $DIR/self-mapping-output.rs:110:36 + | +LL | reuse Trait::method { self.0 } + | ^ unknown field + | +help: a field with a similar name exists + | +LL - reuse Trait::method { self.0 } +LL + reuse Trait::method { self.s } + | + +error[E0609]: no field `0` on type `&no_constructor::W` + --> $DIR/self-mapping-output.rs:115:35 + | +LL | reuse Trait::raw_S { self.0 } + | ^ unknown field + | +help: a field with a similar name exists + | +LL - reuse Trait::raw_S { self.0 } +LL + reuse Trait::raw_S { self.s } + | + +error[E0560]: struct `no_constructor::W` has no field named `0` + --> $DIR/self-mapping-output.rs:120:22 + | +LL | reuse Trait::method { self.0 } + | ^^^^^^ unknown field + | +help: a field with a similar name exists + | +LL - reuse Trait::method { self.0 } +LL + reuse Trait::s { self.0 } + | + +error[E0609]: no field `0` on type `&no_constructor::W` + --> $DIR/self-mapping-output.rs:120:36 + | +LL | reuse Trait::method { self.0 } + | ^ unknown field + | +help: a field with a similar name exists + | +LL - reuse Trait::method { self.0 } +LL + reuse Trait::method { self.s } + | + +error[E0609]: no field `0` on type `&no_constructor::W` + --> $DIR/self-mapping-output.rs:124:35 + | +LL | reuse Trait::raw_S { self.0 } + | ^ unknown field + | +help: a field with a similar name exists + | +LL - reuse Trait::raw_S { self.0 } +LL + reuse Trait::raw_S { self.s } + | + +error[E0063]: missing fields `1` and `2` in initializer of `more_than_one_field::W` + --> $DIR/self-mapping-output.rs:144:22 + | +LL | reuse Trait::method { self.0 } + | ^^^^^^ missing `1` and `2` + +error[E0063]: missing fields `1` and `2` in initializer of `more_than_one_field::W` + --> $DIR/self-mapping-output.rs:152:22 + | +LL | reuse Trait::method { self.0 } + | ^^^^^^ missing `1` and `2` + +error[E0308]: mismatched types + --> $DIR/self-mapping-output.rs:184:25 + | +LL | pub fn method(_: impl super::Trait) -> impl super::Trait { + | ----------------- the found opaque type +... +LL | reuse to_reuse::method { self.0 } + | ^^^^^^ + | | + | expected `W`, found opaque type + | expected `non_trait_path_reuse::W` because of return type + | + = note: expected struct `non_trait_path_reuse::W` + found opaque type `impl non_trait_path_reuse::Trait` + +error[E0308]: mismatched types + --> $DIR/self-mapping-output.rs:186:25 + | +LL | pub fn r#static() -> impl super::Trait { + | ----------------- the found opaque type +... +LL | reuse to_reuse::r#static; + | ^^^^^^^^ + | | + | expected `W`, found opaque type + | expected `non_trait_path_reuse::W` because of return type + | + = note: expected struct `non_trait_path_reuse::W` + found opaque type `impl non_trait_path_reuse::Trait` + +error[E0609]: no field `0` on type `impl super::Trait` + --> $DIR/self-mapping-output.rs:191:39 + | +LL | reuse to_reuse::method { self.0 } + | ^ unknown field + +error[E0308]: mismatched types + --> $DIR/self-mapping-output.rs:213:31 + | +LL | reuse Trait::method { self.0 } + | ------ ^^^^^^ expected `&_`, found `()` + | | + | arguments to this function are incorrect + | + = note: expected reference `&_` + found unit type `()` +note: method defined here + --> $DIR/self-mapping-output.rs:199:12 + | +LL | fn method(&self) -> (); + | ^^^^^^ ---- +help: consider borrowing here + | +LL | reuse Trait::method { &self.0 } + | + + +error[E0283]: type annotations needed + --> $DIR/self-mapping-output.rs:216:22 + | +LL | reuse Trait::r#static; + | ^^^^^^^^ cannot infer type + | + = note: the type must implement `non_Self_return_type::Trait` +help: the following types implement trait `non_Self_return_type::Trait` + --> $DIR/self-mapping-output.rs:205:5 + | +LL | impl Trait for S { + | ^^^^^^^^^^^^^^^^ `non_Self_return_type::S` +... +LL | impl Trait for W { + | ^^^^^^^^^^^^^^^^ `non_Self_return_type::W` + +error[E0308]: mismatched types + --> $DIR/self-mapping-output.rs:219:30 + | +LL | reuse Trait::raw_S { self.0 } + | ----- ^^^^^^ expected `&_`, found `()` + | | + | arguments to this function are incorrect + | + = note: expected reference `&_` + found unit type `()` +note: method defined here + --> $DIR/self-mapping-output.rs:201:12 + | +LL | fn raw_S(&self) -> S { S } + | ^^^^^ ----- +help: consider borrowing here + | +LL | reuse Trait::raw_S { &self.0 } + | + + +error[E0308]: mismatched types + --> $DIR/self-mapping-output.rs:224:31 + | +LL | reuse Trait::method { self.0 } + | ------ ^^^^^^ expected `&_`, found `()` + | | + | arguments to this function are incorrect + | + = note: expected reference `&_` + found unit type `()` +note: method defined here + --> $DIR/self-mapping-output.rs:199:12 + | +LL | fn method(&self) -> (); + | ^^^^^^ ---- +help: consider borrowing here + | +LL | reuse Trait::method { &self.0 } + | + + +error[E0283]: type annotations needed + --> $DIR/self-mapping-output.rs:227:22 + | +LL | reuse Trait::r#static; + | ^^^^^^^^ cannot infer type + | + = note: the type must implement `non_Self_return_type::Trait` +help: the following types implement trait `non_Self_return_type::Trait` + --> $DIR/self-mapping-output.rs:205:5 + | +LL | impl Trait for S { + | ^^^^^^^^^^^^^^^^ `non_Self_return_type::S` +... +LL | impl Trait for W { + | ^^^^^^^^^^^^^^^^ `non_Self_return_type::W` + +error[E0308]: mismatched types + --> $DIR/self-mapping-output.rs:230:30 + | +LL | reuse Trait::raw_S { self.0 } + | ----- ^^^^^^ expected `&_`, found `()` + | | + | arguments to this function are incorrect + | + = note: expected reference `&_` + found unit type `()` +note: method defined here + --> $DIR/self-mapping-output.rs:201:12 + | +LL | fn raw_S(&self) -> S { S } + | ^^^^^ ----- +help: consider borrowing here + | +LL | reuse Trait::raw_S { &self.0 } + | + + +error[E0308]: mismatched types + --> $DIR/self-mapping-output.rs:256:38 + | +LL | reuse ::method { self.0 } + | ------ ^^^^^^ expected `&F`, found `&S` + | | + | arguments to this function are incorrect + | this return type influences the call expression's return type + | + = note: expected reference `&wrong_return_type::F` + found reference `&wrong_return_type::S` +note: method defined here + --> $DIR/self-mapping-output.rs:237:12 + | +LL | fn method(&self) -> Self; + | ^^^^^^ ---- + +error[E0308]: mismatched types + --> $DIR/self-mapping-output.rs:256:29 + | +LL | reuse ::method { self.0 } + | ^^^^^^ expected `S`, found `F` + +error[E0308]: mismatched types + --> $DIR/self-mapping-output.rs:260:29 + | +LL | reuse ::r#static; + | ^^^^^^^^ + | | + | expected `W`, found `F` + | expected `wrong_return_type::W` because of return type + +error[E0308]: mismatched types + --> $DIR/self-mapping-output.rs:263:37 + | +LL | reuse ::raw_S { self.0 } + | ----- ^^^^^^ expected `&F`, found `&S` + | | + | arguments to this function are incorrect + | + = note: expected reference `&wrong_return_type::F` + found reference `&wrong_return_type::S` +note: method defined here + --> $DIR/self-mapping-output.rs:239:12 + | +LL | fn raw_S(&self) -> S { S } + | ^^^^^ ----- + +error[E0308]: mismatched types + --> $DIR/self-mapping-output.rs:268:38 + | +LL | reuse ::method { self.0 } + | ------ ^^^^^^ expected `&F`, found `&S` + | | + | arguments to this function are incorrect + | this return type influences the call expression's return type + | + = note: expected reference `&wrong_return_type::F` + found reference `&wrong_return_type::S` +note: method defined here + --> $DIR/self-mapping-output.rs:237:12 + | +LL | fn method(&self) -> Self; + | ^^^^^^ ---- + +error[E0308]: mismatched types + --> $DIR/self-mapping-output.rs:268:29 + | +LL | reuse ::method { self.0 } + | ^^^^^^ expected `S`, found `F` + +error[E0308]: mismatched types + --> $DIR/self-mapping-output.rs:272:29 + | +LL | reuse ::r#static; + | ^^^^^^^^ + | | + | expected `W`, found `F` + | expected `wrong_return_type::W` because of return type + +error[E0308]: mismatched types + --> $DIR/self-mapping-output.rs:275:37 + | +LL | reuse ::raw_S { self.0 } + | ----- ^^^^^^ expected `&F`, found `&S` + | | + | arguments to this function are incorrect + | + = note: expected reference `&wrong_return_type::F` + found reference `&wrong_return_type::S` +note: method defined here + --> $DIR/self-mapping-output.rs:239:12 + | +LL | fn raw_S(&self) -> S { S } + | ^^^^^ ----- + +error[E0308]: mismatched types + --> $DIR/self-mapping-output.rs:301:31 + | +LL | reuse Trait::method { F } + | ------ ^ expected `&S`, found `&F` + | | + | arguments to this function are incorrect + | this return type influences the call expression's return type + | + = note: expected reference `&wrong_target_expression::S` + found reference `&wrong_target_expression::F` +note: method defined here + --> $DIR/self-mapping-output.rs:282:12 + | +LL | fn method(&self) -> Self; + | ^^^^^^ ---- + +error[E0308]: mismatched types + --> $DIR/self-mapping-output.rs:310:31 + | +LL | reuse Trait::method { F } + | ------ ^ expected `&S`, found `&F` + | | + | arguments to this function are incorrect + | this return type influences the call expression's return type + | + = note: expected reference `&wrong_target_expression::S` + found reference `&wrong_target_expression::F` +note: method defined here + --> $DIR/self-mapping-output.rs:282:12 + | +LL | fn method(&self) -> Self; + | ^^^^^^ ---- + +error[E0616]: field `0` of struct `private::W` is private + --> $DIR/self-mapping-output.rs:336:36 + | +LL | reuse Trait::method { self.0 } + | ^ private field + +error[E0616]: field `0` of struct `private::W` is private + --> $DIR/self-mapping-output.rs:342:35 + | +LL | reuse Trait::raw_S { self.0 } + | ^ private field + +error[E0616]: field `0` of struct `private::W` is private + --> $DIR/self-mapping-output.rs:347:36 + | +LL | reuse Trait::method { self.0 } + | ^ private field + +error[E0616]: field `0` of struct `private::W` is private + --> $DIR/self-mapping-output.rs:352:35 + | +LL | reuse Trait::raw_S { self.0 } + | ^ private field + +warning: function cannot return without recursing + --> $DIR/self-mapping-output.rs:19:22 + | +LL | reuse Trait::r#static; + | ^^^^^^^^ + | | + | cannot return without recursing + | recursive call site + | + = help: a `loop` may express intention better if this is on purpose + = note: `#[warn(unconditional_recursion)]` on by default + +warning: function cannot return without recursing + --> $DIR/self-mapping-output.rs:47:22 + | +LL | reuse Trait::r#static; + | ^^^^^^^^ + | | + | cannot return without recursing + | recursive call site + | + = help: a `loop` may express intention better if this is on purpose + +warning: function cannot return without recursing + --> $DIR/self-mapping-output.rs:83:34 + | +LL | reuse Trait::<'a, T, N>::r#static; + | ^^^^^^^^ + | | + | cannot return without recursing + | recursive call site + | + = help: a `loop` may express intention better if this is on purpose + +warning: function cannot return without recursing + --> $DIR/self-mapping-output.rs:113:22 + | +LL | reuse Trait::r#static; + | ^^^^^^^^ + | | + | cannot return without recursing + | recursive call site + | + = help: a `loop` may express intention better if this is on purpose + +warning: function cannot return without recursing + --> $DIR/self-mapping-output.rs:146:22 + | +LL | reuse Trait::r#static; + | ^^^^^^^^ + | | + | cannot return without recursing + | recursive call site + | + = help: a `loop` may express intention better if this is on purpose + +warning: function cannot return without recursing + --> $DIR/self-mapping-output.rs:304:22 + | +LL | reuse Trait::r#static; + | ^^^^^^^^ + | | + | cannot return without recursing + | recursive call site + | + = help: a `loop` may express intention better if this is on purpose + +warning: function cannot return without recursing + --> $DIR/self-mapping-output.rs:339:22 + | +LL | reuse Trait::r#static; + | ^^^^^^^^ + | | + | cannot return without recursing + | recursive call site + | + = help: a `loop` may express intention better if this is on purpose + +error: aborting due to 31 previous errors; 7 warnings emitted + +Some errors have detailed explanations: E0063, E0283, E0308, E0560, E0609, E0616. +For more information about an error, try `rustc --explain E0063`.