From 6000edd1372a526f67ef0302de7d8290a4e35f62 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Thu, 21 May 2026 13:19:55 -0700 Subject: [PATCH 01/14] Add `T: PartialEq` bounds to derived `StructuralPartialEq` impls. Fixes . The changes in `const_to_pat.rs` are entirely to avoid regressing diagnostic quality, and should not make any difference to what code is accepted. The change in `compute_applicable_impls_for_diagnostics` and its callers is entirely to be able to reuse that algorithm for this purpose. --- .../src/deriving/cmp/partial_eq.rs | 5 +- .../src/thir/pattern/const_to_pat.rs | 115 ++++++++++++++---- .../src/error_reporting/infer/mod.rs | 3 +- .../src/error_reporting/traits/ambiguity.rs | 44 ++++--- ...erive-and-manual-partialeq-issue-147714.rs | 31 +++++ ...e-and-manual-partialeq-issue-147714.stderr | 20 +++ .../ui/consts/const_in_pattern/issue-65466.rs | 2 +- .../const_in_pattern/issue-65466.stderr | 2 +- tests/ui/derives/deriving-all-codegen.stdout | 14 ++- 9 files changed, 184 insertions(+), 52 deletions(-) create mode 100644 tests/ui/consts/const_in_pattern/derive-and-manual-partialeq-issue-147714.rs create mode 100644 tests/ui/consts/const_in_pattern/derive-and-manual-partialeq-issue-147714.stderr diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index c8ec5deb92c43..372b4e820f72d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -22,7 +22,10 @@ pub(crate) fn expand_deriving_partial_eq( path: path_std!(marker::StructuralPartialEq), skip_path_as_bound: true, // crucial! needs_copy_as_bound_if_packed: false, - additional_bounds: Vec::new(), + // The `StructuralPartialEq` impl must have the *same* bounds as the `PartialEq` impl, + // or it will apply in situations where it should not, such as in the bug + // . + additional_bounds: vec![ty::Ty::Path(path_std!(cmp::PartialEq))], // We really don't support unions, but that's already checked by the impl generated below; // a second check here would lead to redundant error messages. supports_unions: true, diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 0c6e1b83c9535..a8de38e5ceb71 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -15,6 +15,9 @@ use rustc_middle::thir::{FieldPat, Pat, PatKind}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitableExt, TypeVisitor}; use rustc_span::def_id::DefId; use rustc_span::{DUMMY_SP, Span}; +use rustc_trait_selection::error_reporting::traits::ambiguity::{ + CandidateSource, compute_applicable_impls_for_diagnostics, +}; use rustc_trait_selection::traits::ObligationCause; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use tracing::{debug, instrument, trace}; @@ -209,15 +212,35 @@ impl<'tcx> ConstToPat<'tcx> { let kind = match ty.kind() { // Extremely important check for all ADTs! - // Make sure they are eligible to be used in patterns, and if not, emit an error. + // Make sure they are eligible to be used in patterns (structural), and if not, emit an + // error. ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => { // This ADT cannot be used as a constant in patterns. debug!(?adt_def, ?value.ty, "ADT type in pattern is not `type_marked_structural`"); let PartialEqImplStatus { - is_derived, structural_partial_eq, non_blanket_impl, .. + is_derived, + possibly_inapplicable_structural_partial_eq, + non_blanket_impl, + possibly_inapplicable_derived_partial_eq, + has_impl, + .. } = type_has_partial_eq_impl(self.tcx, self.typing_env, ty); + + // If we have a derived PartialEq impl but it does not apply, + // then error about that instead, because `TypeNotStructural` gives advice that is + // relevant only when the problem is that `ty` does not derive `PartialEq`. + // + // Note that this is a duplicate of a check in `unevaluated_to_pat()`, + // which we would run later if we weren’t emitting an error now. + if possibly_inapplicable_derived_partial_eq && !has_impl { + let mut err = + self.tcx.dcx().create_err(TypeNotPartialEq { span: self.span, ty }); + extend_type_not_partial_eq(self.tcx, self.typing_env, ty, &mut err); + return self.mk_err(err, ty); + } + let (manual_partialeq_impl_span, manual_partialeq_impl_note) = - match (structural_partial_eq, non_blanket_impl) { + match (possibly_inapplicable_structural_partial_eq, non_blanket_impl) { (true, _) => (None, false), (_, Some(def_id)) if def_id.is_local() && !is_derived => { (Some(tcx.def_span(def_id)), false) @@ -465,8 +488,9 @@ fn extend_type_not_partial_eq<'tcx>( let PartialEqImplStatus { has_impl, is_derived, - structural_partial_eq, + possibly_inapplicable_structural_partial_eq: structural_partial_eq, non_blanket_impl, + possibly_inapplicable_derived_partial_eq: _, } = type_has_partial_eq_impl(self.tcx, self.typing_env, ty); match (has_impl, is_derived, structural_partial_eq, non_blanket_impl) { (_, _, true, _) => {} @@ -535,10 +559,20 @@ fn extend_type_not_partial_eq<'tcx>( #[derive(Debug)] struct PartialEqImplStatus { + /// There is a `PartialEq` impl that applies to the type. has_impl: bool, + + /// The `PartialEq` impl is `#[automatically_derived]`. is_derived: bool, - structural_partial_eq: bool, + /// The `DefId` of the same impl that `is_derived` refers to. non_blanket_impl: Option, + + /// If true, there is a `StructuralPartialEq` implementation, + /// but its bounds might not be satisfied. + possibly_inapplicable_structural_partial_eq: bool, + /// If true, there is a derived `PartialEq` implementation for the type, + /// but its bounds might not be satisfied. + possibly_inapplicable_derived_partial_eq: bool, } #[instrument(level = "trace", skip(tcx), ret)] @@ -557,23 +591,6 @@ fn type_has_partial_eq_impl<'tcx>( let structural_partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::StructuralPeq, DUMMY_SP); - let partial_eq_obligation = Obligation::new( - tcx, - ObligationCause::dummy(), - param_env, - ty::TraitRef::new(tcx, partial_eq_trait_id, [ty, ty]), - ); - - let mut automatically_derived = false; - let mut structural_peq = false; - let mut impl_def_id = None; - for def_id in tcx.non_blanket_impls_for_ty(partial_eq_trait_id, ty) { - automatically_derived = find_attr!(tcx, def_id, AutomaticallyDerived); - impl_def_id = Some(def_id); - } - for _ in tcx.non_blanket_impls_for_ty(structural_partial_eq_trait_id, ty) { - structural_peq = true; - } // This *could* accept a type that isn't actually `PartialEq`, because region bounds get // ignored. However that should be pretty much impossible since consts that do not depend on // generics can only mention the `'static` lifetime, and how would one have a type that's @@ -584,10 +601,60 @@ fn type_has_partial_eq_impl<'tcx>( // that patterns can only do things that the code could also do without patterns, but it is // needed for backwards compatibility. The actual pattern matching compares primitive values, // `PartialEq::eq` never gets invoked, so there's no risk of us running non-const code. + let has_impl = { + let obligation = Obligation::new( + tcx, + ObligationCause::dummy(), + param_env, + ty::TraitRef::new(tcx, partial_eq_trait_id, [ty, ty]), + ); + infcx.predicate_must_hold_modulo_regions(&obligation) + }; + + // Determine whether there are is a derived `PartialEq` implementation, whether or not its + // bounds are met. + let possibly_inapplicable_derived_partial_eq = { + let obligation = Obligation::new( + tcx, + ObligationCause::dummy(), + param_env, + ty::Binder::dummy(ty::TraitRef::new(tcx, partial_eq_trait_id, [ty, ty])), + ); + compute_applicable_impls_for_diagnostics(&infcx, &obligation, true).iter().any( + |candidate_source| { + matches!( + candidate_source, + &CandidateSource::DefId(def_id) + if find_attr!(tcx, def_id, AutomaticallyDerived) + ) + }, + ) + }; + + let possibly_inapplicable_structural_partial_eq = { + let obligation = Obligation::new( + tcx, + ObligationCause::dummy(), + param_env, + ty::Binder::dummy(ty::TraitRef::new(tcx, structural_partial_eq_trait_id, [ty])), + ); + compute_applicable_impls_for_diagnostics(&infcx, &obligation, true) + .iter() + .any(|candidate_source| matches!(candidate_source, CandidateSource::DefId(_))) + }; + + let mut automatically_derived = false; + let mut impl_def_id = None; + for def_id in tcx.non_blanket_impls_for_ty(partial_eq_trait_id, ty) { + automatically_derived = find_attr!(tcx, def_id, AutomaticallyDerived); + impl_def_id = Some(def_id); + } + PartialEqImplStatus { - has_impl: infcx.predicate_must_hold_modulo_regions(&partial_eq_obligation), + has_impl, is_derived: automatically_derived, - structural_partial_eq: structural_peq, + possibly_inapplicable_structural_partial_eq, non_blanket_impl: impl_def_id, + possibly_inapplicable_derived_partial_eq, } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index c9e2312895820..c6e796c7e3de3 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -268,7 +268,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let obligation = Obligation::new(tcx, ObligationCause::dummy(), param_env, ty::Binder::dummy(trait_ref)); - let applicable_impls = compute_applicable_impls_for_diagnostics(self.infcx, &obligation); + let applicable_impls = + compute_applicable_impls_for_diagnostics(self.infcx, &obligation, false); for candidate in applicable_impls { let impl_def_id = match candidate { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index 108262d507ef7..904612015c404 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -32,6 +32,7 @@ pub enum CandidateSource { pub fn compute_applicable_impls_for_diagnostics<'tcx>( infcx: &InferCtxt<'tcx>, obligation: &PolyTraitObligation<'tcx>, + ignore_predicates_of_impls: bool, ) -> Vec { let tcx = infcx.tcx; let param_env = obligation.param_env; @@ -71,26 +72,28 @@ pub fn compute_applicable_impls_for_diagnostics<'tcx>( _ => return false, } - let obligations = tcx - .predicates_of(impl_def_id) - .instantiate(tcx, impl_args) - .into_iter() - .map(|(predicate, _)| { - Obligation::new( - tcx, - ObligationCause::dummy(), - param_env, - predicate.skip_norm_wip(), - ) - }) - // Kinda hacky, but let's just throw away obligations that overflow. - // This may reduce the accuracy of this check (if the obligation guides - // inference or it actually resulted in error after others are processed) - // ... but this is diagnostics code. - .filter(|obligation| { - infcx.next_trait_solver() || infcx.evaluate_obligation(obligation).is_ok() - }); - ocx.register_obligations(obligations); + if !ignore_predicates_of_impls { + let obligations = tcx + .predicates_of(impl_def_id) + .instantiate(tcx, impl_args) + .into_iter() + .map(|(predicate, _)| { + Obligation::new( + tcx, + ObligationCause::dummy(), + param_env, + predicate.skip_norm_wip(), + ) + }) + // Kinda hacky, but let's just throw away obligations that overflow. + // This may reduce the accuracy of this check (if the obligation guides + // inference or it actually resulted in error after others are processed) + // ... but this is diagnostics code. + .filter(|obligation| { + infcx.next_trait_solver() || infcx.evaluate_obligation(obligation).is_ok() + }); + ocx.register_obligations(obligations); + } ocx.try_evaluate_obligations().is_empty() }) @@ -306,6 +309,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut ambiguities = compute_applicable_impls_for_diagnostics( self.infcx, &obligation.with(self.tcx, trait_pred), + false, ); let has_non_region_infer = trait_pred .skip_binder() diff --git a/tests/ui/consts/const_in_pattern/derive-and-manual-partialeq-issue-147714.rs b/tests/ui/consts/const_in_pattern/derive-and-manual-partialeq-issue-147714.rs new file mode 100644 index 0000000000000..493023f6bdb0e --- /dev/null +++ b/tests/ui/consts/const_in_pattern/derive-and-manual-partialeq-issue-147714.rs @@ -0,0 +1,31 @@ +// `derive(PartialEq)`, which also implements `StructuralPartialEq`, must not allow the latter impl +// to be used with other non-derived implementations of `PartialEq`. +// +// Test case by theemathas from . + +#[allow(dead_code)] +#[derive(PartialEq)] +enum Thing { + A(T), + B, +} + +struct Incomparable; + +// This impl does not obey StructuralPartialEq's rules. +impl PartialEq for Thing { + fn eq(&self, _: &Self) -> bool { + panic!() + } +} + +// This constant does not obey StructuralPartialEq's rules, so it should not +// implement StructuralPartialEq. +const X: Thing = Thing::B; + +fn main() { + if let X = X { + //~^ ERROR constant of non-structural type `Thing` in a pattern + println!("equal"); + } +} diff --git a/tests/ui/consts/const_in_pattern/derive-and-manual-partialeq-issue-147714.stderr b/tests/ui/consts/const_in_pattern/derive-and-manual-partialeq-issue-147714.stderr new file mode 100644 index 0000000000000..52497e23df04d --- /dev/null +++ b/tests/ui/consts/const_in_pattern/derive-and-manual-partialeq-issue-147714.stderr @@ -0,0 +1,20 @@ +error: constant of non-structural type `Thing` in a pattern + --> $DIR/derive-and-manual-partialeq-issue-147714.rs:27:12 + | +LL | enum Thing { + | ------------- `Thing` must be annotated with `#[derive(PartialEq)]` to be usable in patterns +... +LL | const X: Thing = Thing::B; + | ---------------------------- constant defined here +... +LL | if let X = X { + | ^ constant of non-structural type + | +help: if `Thing` manually implemented `PartialEq`, you could check for equality instead of pattern matching + | +LL - if let X = X { +LL + if X == X { + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/consts/const_in_pattern/issue-65466.rs b/tests/ui/consts/const_in_pattern/issue-65466.rs index 82838657b02f5..dba8e7a92163a 100644 --- a/tests/ui/consts/const_in_pattern/issue-65466.rs +++ b/tests/ui/consts/const_in_pattern/issue-65466.rs @@ -11,7 +11,7 @@ const C: &[O] = &[O::None]; fn main() { let x = O::None; match &[x][..] { - C => (), //~ ERROR constant of non-structural type `&[O]` in a pattern + C => (), //~ ERROR constant of non-structural type `O` in a pattern _ => (), } } diff --git a/tests/ui/consts/const_in_pattern/issue-65466.stderr b/tests/ui/consts/const_in_pattern/issue-65466.stderr index 511a38bbc00d8..29c49223f044a 100644 --- a/tests/ui/consts/const_in_pattern/issue-65466.stderr +++ b/tests/ui/consts/const_in_pattern/issue-65466.stderr @@ -1,4 +1,4 @@ -error: constant of non-structural type `&[O]` in a pattern +error: constant of non-structural type `O` in a pattern --> $DIR/issue-65466.rs:14:9 | LL | struct B; diff --git a/tests/ui/derives/deriving-all-codegen.stdout b/tests/ui/derives/deriving-all-codegen.stdout index 94e8b886436df..4f56ce5765685 100644 --- a/tests/ui/derives/deriving-all-codegen.stdout +++ b/tests/ui/derives/deriving-all-codegen.stdout @@ -836,7 +836,10 @@ impl ::core::hash::Hash } } #[automatically_derived] -impl ::core::marker::StructuralPartialEq for Generic { } +impl + ::core::marker::StructuralPartialEq for Generic where + T::A: ::core::cmp::PartialEq { +} #[automatically_derived] impl ::core::cmp::PartialEq for Generic where @@ -953,8 +956,9 @@ impl ::core::marker::StructuralPartialEq for PackedGeneric - { +impl + ::core::marker::StructuralPartialEq for PackedGeneric where + T::A: ::core::cmp::PartialEq { } #[automatically_derived] impl ::core::hash::Hash for } } #[automatically_derived] -impl ::core::marker::StructuralPartialEq for EnumGeneric { } +impl + ::core::marker::StructuralPartialEq for EnumGeneric { +} #[automatically_derived] impl ::core::cmp::PartialEq for EnumGeneric { From 123d0d1f361205d81aca1d4c0bcc244bd192e816 Mon Sep 17 00:00:00 2001 From: Lars Schumann Date: Tue, 21 Apr 2026 20:04:28 +0000 Subject: [PATCH 02/14] constify array try from vec --- library/alloc/src/lib.rs | 1 + library/alloc/src/raw_vec/mod.rs | 6 +- library/alloc/src/vec/mod.rs | 17 +++-- .../consts/bad-array-size-in-type-err.stderr | 4 ++ .../const-eval/issue-65394.stock.stderr | 4 ++ tests/ui/consts/const-eval/livedrop.stderr | 4 ++ .../control-flow/drop-fail.precise.stderr | 10 +-- tests/ui/consts/control-flow/drop-fail.rs | 25 +++++--- .../control-flow/drop-fail.stock.stderr | 22 +++---- tests/ui/consts/miri_unleashed/assoc_const.rs | 15 +++-- .../consts/miri_unleashed/assoc_const.stderr | 24 +++---- tests/ui/consts/miri_unleashed/drop.rs | 18 ++++-- tests/ui/consts/miri_unleashed/drop.stderr | 10 +-- tests/ui/consts/promote-not.stderr | 4 ++ tests/ui/consts/promoted_const_call3.stderr | 8 +++ tests/ui/consts/promoted_const_call5.stderr | 4 ++ .../consts/qualif-indirect-mutation-fail.rs | 24 ++++--- .../qualif-indirect-mutation-fail.stderr | 62 +++++++++---------- tests/ui/drop/repeat-drop-2.stderr | 4 ++ ...op-elaboration-after-borrowck-error.stderr | 8 +++ ...-indestructible-indestructible.next.stderr | 12 ++-- ...h-indestructible-indestructible.old.stderr | 12 ++-- ...sure-with-indestructible-indestructible.rs | 14 ++++- 23 files changed, 196 insertions(+), 116 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 7b41023ff31bf..e9a31b37e5af9 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -104,6 +104,7 @@ #![feature(const_convert)] #![feature(const_default)] #![feature(const_destruct)] +#![feature(const_drop_in_place)] #![feature(const_eval_select)] #![feature(const_heap)] #![feature(const_index)] diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index 0309d63cce06d..11cf4c4d8d0b6 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -417,7 +417,8 @@ impl RawVec { } } -unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +const unsafe impl<#[may_dangle] T, A: [const] Allocator + [const] Destruct> Drop for RawVec { /// Frees the memory owned by the `RawVec` *without* trying to drop its contents. fn drop(&mut self) { // SAFETY: We are in a Drop impl, self.inner will not be used again. @@ -861,7 +862,10 @@ impl RawVecInner { } Ok(()) } +} +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +const impl RawVecInner { /// # Safety /// /// This function deallocates the owned allocation, but does not update `ptr` or `cap` to diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index a08e99a277d70..f16f2161b967c 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -79,9 +79,7 @@ use core::cmp::Ordering; use core::hash::{Hash, Hasher}; #[cfg(not(no_global_oom_handling))] use core::iter; -#[cfg(not(no_global_oom_handling))] -use core::marker::Destruct; -use core::marker::{Freeze, PhantomData}; +use core::marker::{Destruct, Freeze, PhantomData}; use core::mem::{self, Assume, ManuallyDrop, MaybeUninit, SizedTypeProperties, TransmuteFrom}; use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; @@ -2190,7 +2188,8 @@ impl Vec { /// [`spare_capacity_mut()`]: Vec::spare_capacity_mut #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub unsafe fn set_len(&mut self, new_len: usize) { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub const unsafe fn set_len(&mut self, new_len: usize) { ub_checks::assert_unsafe_precondition!( check_library_ub, "Vec::set_len requires that new_len <= capacity()", @@ -4255,7 +4254,10 @@ impl Ord for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T, A: Allocator> Drop for Vec { +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +const unsafe impl<#[may_dangle] T: [const] Destruct, A: [const] Allocator + [const] Destruct> Drop + for Vec +{ fn drop(&mut self) { unsafe { // use drop for [T] @@ -4474,7 +4476,10 @@ impl From<&str> for Vec { } #[stable(feature = "array_try_from_vec", since = "1.48.0")] -impl TryFrom> for [T; N] { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +const impl + TryFrom> for [T; N] +{ type Error = Vec; /// Gets the entire contents of the `Vec` as an array, diff --git a/tests/ui/consts/bad-array-size-in-type-err.stderr b/tests/ui/consts/bad-array-size-in-type-err.stderr index 84e16f8d931ea..13b0b6c4f4a65 100644 --- a/tests/ui/consts/bad-array-size-in-type-err.stderr +++ b/tests/ui/consts/bad-array-size-in-type-err.stderr @@ -57,6 +57,10 @@ LL | pub const fn i(_: Wrap) {} | ^ - value is dropped here | | | the destructor for this type cannot be evaluated in constant functions + | + = note: see issue #133214 for more information + = help: add `#![feature(const_destruct)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 7 previous errors diff --git a/tests/ui/consts/const-eval/issue-65394.stock.stderr b/tests/ui/consts/const-eval/issue-65394.stock.stderr index f33593862a763..514d454df3dc0 100644 --- a/tests/ui/consts/const-eval/issue-65394.stock.stderr +++ b/tests/ui/consts/const-eval/issue-65394.stock.stderr @@ -6,6 +6,10 @@ LL | let mut x = Vec::::new(); ... LL | }; | - value is dropped here + | + = note: see issue #133214 for more information + = help: add `#![feature(const_destruct)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/livedrop.stderr b/tests/ui/consts/const-eval/livedrop.stderr index 1add814060370..b090e35f07e3f 100644 --- a/tests/ui/consts/const-eval/livedrop.stderr +++ b/tests/ui/consts/const-eval/livedrop.stderr @@ -6,6 +6,10 @@ LL | let mut always_returned = None; ... LL | always_returned = never_returned; | --------------- value is dropped here + | + = note: see issue #133214 for more information + = help: add `#![feature(const_destruct)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 1 previous error diff --git a/tests/ui/consts/control-flow/drop-fail.precise.stderr b/tests/ui/consts/control-flow/drop-fail.precise.stderr index 32afc51c3ee34..6f07d2329615b 100644 --- a/tests/ui/consts/control-flow/drop-fail.precise.stderr +++ b/tests/ui/consts/control-flow/drop-fail.precise.stderr @@ -1,14 +1,14 @@ -error[E0493]: destructor of `Option>` cannot be evaluated at compile-time - --> $DIR/drop-fail.rs:9:9 +error[E0493]: destructor of `Option` cannot be evaluated at compile-time + --> $DIR/drop-fail.rs:16:9 | -LL | let x = Some(Vec::new()); +LL | let x = Some(NotConstDestruct); | ^ the destructor for this type cannot be evaluated in constants ... LL | }; | - value is dropped here -error[E0493]: destructor of `Option>` cannot be evaluated at compile-time - --> $DIR/drop-fail.rs:40:9 +error[E0493]: destructor of `Option` cannot be evaluated at compile-time + --> $DIR/drop-fail.rs:47:9 | LL | let mut tmp = None; | ^^^^^^^ the destructor for this type cannot be evaluated in constants diff --git a/tests/ui/consts/control-flow/drop-fail.rs b/tests/ui/consts/control-flow/drop-fail.rs index 2b73e37b23d03..3593e5af26b00 100644 --- a/tests/ui/consts/control-flow/drop-fail.rs +++ b/tests/ui/consts/control-flow/drop-fail.rs @@ -3,10 +3,17 @@ #![feature(const_destruct)] #![cfg_attr(precise, feature(const_precise_live_drops))] + +struct NotConstDestruct; + +impl Drop for NotConstDestruct { + fn drop(&mut self) {} +} + // `x` is *not* always moved into the final value and may be dropped inside the initializer. -const _: Option> = { - let y: Option> = None; - let x = Some(Vec::new()); +const _: Option = { + let y: Option = None; + let x = Some(NotConstDestruct); //[stock,precise]~^ ERROR destructor of if true { @@ -18,16 +25,16 @@ const _: Option> = { // We only clear `NeedsDrop` if a local is moved from in entirely. This is a shortcoming of the // existing analysis. -const _: Vec = { - let vec_tuple = (Vec::new(),); +const _: NotConstDestruct = { + let vec_tuple = (NotConstDestruct,); //[stock]~^ ERROR destructor of vec_tuple.0 }; // This applies to single-field enum variants as well. -const _: Vec = { - let x: Result<_, Vec> = Ok(Vec::new()); +const _: NotConstDestruct = { + let x: Result<_, NotConstDestruct> = Ok(NotConstDestruct); //[stock]~^ ERROR destructor of match x { @@ -35,8 +42,8 @@ const _: Vec = { } }; -const _: Option> = { - let mut some = Some(Vec::new()); +const _: Option = { + let mut some = Some(NotConstDestruct); let mut tmp = None; //[stock,precise]~^ ERROR destructor of diff --git a/tests/ui/consts/control-flow/drop-fail.stock.stderr b/tests/ui/consts/control-flow/drop-fail.stock.stderr index 8fe60fd736765..3caef5810939c 100644 --- a/tests/ui/consts/control-flow/drop-fail.stock.stderr +++ b/tests/ui/consts/control-flow/drop-fail.stock.stderr @@ -1,32 +1,32 @@ -error[E0493]: destructor of `Option>` cannot be evaluated at compile-time - --> $DIR/drop-fail.rs:9:9 +error[E0493]: destructor of `Option` cannot be evaluated at compile-time + --> $DIR/drop-fail.rs:16:9 | -LL | let x = Some(Vec::new()); +LL | let x = Some(NotConstDestruct); | ^ the destructor for this type cannot be evaluated in constants ... LL | }; | - value is dropped here -error[E0493]: destructor of `(Vec,)` cannot be evaluated at compile-time - --> $DIR/drop-fail.rs:22:9 +error[E0493]: destructor of `(NotConstDestruct,)` cannot be evaluated at compile-time + --> $DIR/drop-fail.rs:29:9 | -LL | let vec_tuple = (Vec::new(),); +LL | let vec_tuple = (NotConstDestruct,); | ^^^^^^^^^ the destructor for this type cannot be evaluated in constants ... LL | }; | - value is dropped here -error[E0493]: destructor of `Result, Vec>` cannot be evaluated at compile-time - --> $DIR/drop-fail.rs:30:9 +error[E0493]: destructor of `Result` cannot be evaluated at compile-time + --> $DIR/drop-fail.rs:37:9 | -LL | let x: Result<_, Vec> = Ok(Vec::new()); +LL | let x: Result<_, NotConstDestruct> = Ok(NotConstDestruct); | ^ the destructor for this type cannot be evaluated in constants ... LL | }; | - value is dropped here -error[E0493]: destructor of `Option>` cannot be evaluated at compile-time - --> $DIR/drop-fail.rs:40:9 +error[E0493]: destructor of `Option` cannot be evaluated at compile-time + --> $DIR/drop-fail.rs:47:9 | LL | let mut tmp = None; | ^^^^^^^ the destructor for this type cannot be evaluated in constants diff --git a/tests/ui/consts/miri_unleashed/assoc_const.rs b/tests/ui/consts/miri_unleashed/assoc_const.rs index 812207ee80900..753a53077e086 100644 --- a/tests/ui/consts/miri_unleashed/assoc_const.rs +++ b/tests/ui/consts/miri_unleashed/assoc_const.rs @@ -4,6 +4,13 @@ // a test demonstrating why we do need to run static const qualification on associated constants // instead of just checking the final constant + +struct NotConstDestruct; + +impl Drop for NotConstDestruct { + fn drop(&mut self) {} +} + trait Foo { const X: T; } @@ -15,18 +22,18 @@ trait Bar> { impl Foo for () { const X: u32 = 42; } -impl Foo> for String { - const X: Vec = Vec::new(); +impl Foo for NotConstDestruct { + const X: NotConstDestruct = NotConstDestruct; } impl Bar for () {} -impl Bar, String> for String {} +impl Bar for NotConstDestruct {} fn main() { // this is fine, but would have been forbidden by the static checks on `F` let x = <() as Bar>::F; // this test only causes errors due to the line below, so post-monomorphization - let y = , String>>::F; + let y = >::F; } //~? WARN skipping const checks diff --git a/tests/ui/consts/miri_unleashed/assoc_const.stderr b/tests/ui/consts/miri_unleashed/assoc_const.stderr index 0b276c8d70705..29f371373aef9 100644 --- a/tests/ui/consts/miri_unleashed/assoc_const.stderr +++ b/tests/ui/consts/miri_unleashed/assoc_const.stderr @@ -1,32 +1,32 @@ -error[E0080]: calling non-const function ` as Drop>::drop` - --> $DIR/assoc_const.rs:12:31 +error[E0080]: calling non-const function `::drop` + --> $DIR/assoc_const.rs:19:31 | LL | const F: u32 = (U::X, 42).1; - | ^ evaluation of `, std::string::String>>::F` failed inside this call + | ^ evaluation of `>::F` failed inside this call | -note: inside `std::ptr::drop_glue::<(Vec, u32)> - shim(Some((Vec, u32)))` +note: inside `std::ptr::drop_glue::<(NotConstDestruct, u32)> - shim(Some((NotConstDestruct, u32)))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `std::ptr::drop_glue::> - shim(Some(Vec))` +note: inside `std::ptr::drop_glue:: - shim(Some(NotConstDestruct))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL note: erroneous constant encountered - --> $DIR/assoc_const.rs:29:13 + --> $DIR/assoc_const.rs:36:13 | -LL | let y = , String>>::F; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let y = >::F; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: erroneous constant encountered - --> $DIR/assoc_const.rs:29:13 + --> $DIR/assoc_const.rs:36:13 | -LL | let y = , String>>::F; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let y = >::F; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/assoc_const.rs:12:20 + --> $DIR/assoc_const.rs:19:20 | LL | const F: u32 = (U::X, 42).1; | ^^^^^^^^^^ diff --git a/tests/ui/consts/miri_unleashed/drop.rs b/tests/ui/consts/miri_unleashed/drop.rs index 0edd3a03c5996..dc7d3f5aa243e 100644 --- a/tests/ui/consts/miri_unleashed/drop.rs +++ b/tests/ui/consts/miri_unleashed/drop.rs @@ -2,20 +2,26 @@ use std::mem::ManuallyDrop; + +struct NotConstDestruct; + +impl Drop for NotConstDestruct { + fn drop(&mut self) {} +} + fn main() {} static TEST_OK: () = { - let v: Vec = Vec::new(); + let v: NotConstDestruct = NotConstDestruct; let _v = ManuallyDrop::new(v); }; // Make sure we catch executing bad drop functions. // The actual error is tested by the error-pattern above. static TEST_BAD: () = { - let _v: Vec = Vec::new(); -}; -//~^ NOTE failed inside this call -//~| ERROR calling non-const function ` as Drop>::drop` -//~| NOTE inside `std::ptr::drop_glue::> - shim(Some(Vec))` + let _v: NotConstDestruct = NotConstDestruct; +}; //~ NOTE failed inside this call + //~| ERROR calling non-const function `::drop` + //~| NOTE inside `std::ptr::drop_glue:: - shim(Some(NotConstDestruct))` //~? WARN skipping const checks diff --git a/tests/ui/consts/miri_unleashed/drop.stderr b/tests/ui/consts/miri_unleashed/drop.stderr index 2dfe75c468595..6e2afda763171 100644 --- a/tests/ui/consts/miri_unleashed/drop.stderr +++ b/tests/ui/consts/miri_unleashed/drop.stderr @@ -1,18 +1,18 @@ -error[E0080]: calling non-const function ` as Drop>::drop` - --> $DIR/drop.rs:16:1 +error[E0080]: calling non-const function `::drop` + --> $DIR/drop.rs:23:1 | LL | }; | ^ evaluation of `TEST_BAD` failed inside this call | -note: inside `std::ptr::drop_glue::> - shim(Some(Vec))` +note: inside `std::ptr::drop_glue:: - shim(Some(NotConstDestruct))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/drop.rs:15:9 + --> $DIR/drop.rs:22:9 | -LL | let _v: Vec = Vec::new(); +LL | let _v: NotConstDestruct = NotConstDestruct; | ^^ error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/consts/promote-not.stderr b/tests/ui/consts/promote-not.stderr index ec552d9dd7d48..ebe2a963a74b1 100644 --- a/tests/ui/consts/promote-not.stderr +++ b/tests/ui/consts/promote-not.stderr @@ -46,6 +46,10 @@ LL | let x = &String::new(); ... LL | }; | - value is dropped here + | + = note: see issue #133214 for more information + = help: add `#![feature(const_destruct)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0716]: temporary value dropped while borrowed --> $DIR/promote-not.rs:60:33 diff --git a/tests/ui/consts/promoted_const_call3.stderr b/tests/ui/consts/promoted_const_call3.stderr index 34c833d5bb77c..22d017abe6111 100644 --- a/tests/ui/consts/promoted_const_call3.stderr +++ b/tests/ui/consts/promoted_const_call3.stderr @@ -6,6 +6,10 @@ LL | let _: &'static _ = &String::new(); LL | LL | }; | - value is dropped here + | + = note: see issue #133214 for more information + = help: add `#![feature(const_destruct)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0493]: destructor of `String` cannot be evaluated at compile-time --> $DIR/promoted_const_call3.rs:8:30 @@ -14,6 +18,10 @@ LL | let _: &'static _ = &id(&String::new()); | ^^^^^^^^^^^^^ - value is dropped here | | | the destructor for this type cannot be evaluated in constants + | + = note: see issue #133214 for more information + = help: add `#![feature(const_destruct)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0716]: temporary value dropped while borrowed --> $DIR/promoted_const_call3.rs:13:26 diff --git a/tests/ui/consts/promoted_const_call5.stderr b/tests/ui/consts/promoted_const_call5.stderr index 1b5fa4352837e..b65422e44a510 100644 --- a/tests/ui/consts/promoted_const_call5.stderr +++ b/tests/ui/consts/promoted_const_call5.stderr @@ -5,6 +5,10 @@ LL | let _: &'static _ = &id(&new_string()); | ^^^^^^^^^^^^ - value is dropped here | | | the destructor for this type cannot be evaluated in constants + | + = note: see issue #133214 for more information + = help: add `#![feature(const_destruct)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0716]: temporary value dropped while borrowed --> $DIR/promoted_const_call5.rs:31:26 diff --git a/tests/ui/consts/qualif-indirect-mutation-fail.rs b/tests/ui/consts/qualif-indirect-mutation-fail.rs index b70fca7b86430..00c9d4900f5f6 100644 --- a/tests/ui/consts/qualif-indirect-mutation-fail.rs +++ b/tests/ui/consts/qualif-indirect-mutation-fail.rs @@ -1,32 +1,38 @@ //@ compile-flags: --crate-type=lib #![feature(const_precise_live_drops)] +struct NotConstDestruct; + +impl Drop for NotConstDestruct { + fn drop(&mut self) {} +} + // Mutable borrow of a field with drop impl. pub const fn f() { - let mut a: (u32, Option) = (0, None); //~ ERROR destructor of + let mut a: (u32, Option) = (0, None); //~ ERROR destructor of let _ = &mut a.1; } // Mutable borrow of a type with drop impl. pub const A1: () = { let mut x = None; //~ ERROR destructor of - let mut y = Some(String::new()); + let mut y = Some(NotConstDestruct); let a = &mut x; let b = &mut y; std::mem::swap(a, b); std::mem::forget(y); -}; //~ ERROR calling non-const function ` as Drop>::drop` +}; //~ ERROR calling non-const function `::drop` // Mutable borrow of a type with drop impl. pub const A2: () = { let mut x = None; - let mut y = Some(String::new()); + let mut y = Some(NotConstDestruct); let a = &mut x; let b = &mut y; std::mem::swap(a, b); std::mem::forget(y); let _z = x; //~ ERROR destructor of -}; //~ ERROR calling non-const function ` as Drop>::drop` +}; //~ ERROR calling non-const function `::drop` // Shared borrow of a type that might be !Freeze and Drop. pub const fn g1() { @@ -43,19 +49,19 @@ pub const fn g2() { // Mutable raw reference to a Drop type. pub const fn address_of_mut() { - let mut x: Option = None; //~ ERROR destructor of + let mut x: Option = None; //~ ERROR destructor of &raw mut x; - let mut y: Option = None; //~ ERROR destructor of + let mut y: Option = None; //~ ERROR destructor of std::ptr::addr_of_mut!(y); } // Const raw reference to a Drop type. Conservatively assumed to allow mutation // until resolution of https://github.com/rust-lang/rust/issues/56604. pub const fn address_of_const() { - let x: Option = None; //~ ERROR destructor of + let x: Option = None; //~ ERROR destructor of &raw const x; - let y: Option = None; //~ ERROR destructor of + let y: Option = None; //~ ERROR destructor of std::ptr::addr_of!(y); } diff --git a/tests/ui/consts/qualif-indirect-mutation-fail.stderr b/tests/ui/consts/qualif-indirect-mutation-fail.stderr index 102bbe03b2efd..9bf679f8a5348 100644 --- a/tests/ui/consts/qualif-indirect-mutation-fail.stderr +++ b/tests/ui/consts/qualif-indirect-mutation-fail.stderr @@ -1,5 +1,5 @@ -error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:12:9 +error[E0493]: destructor of `Option` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:18:9 | LL | let mut x = None; | ^^^^^ the destructor for this type cannot be evaluated in constants @@ -7,51 +7,47 @@ LL | let mut x = None; LL | }; | - value is dropped here -error[E0080]: calling non-const function ` as Drop>::drop` - --> $DIR/qualif-indirect-mutation-fail.rs:18:1 +error[E0080]: calling non-const function `::drop` + --> $DIR/qualif-indirect-mutation-fail.rs:24:1 | LL | }; | ^ evaluation of `A1` failed inside this call | -note: inside `std::ptr::drop_glue::> - shim(Some(Option))` - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `std::ptr::drop_glue:: - shim(Some(String))` +note: inside `std::ptr::drop_glue::> - shim(Some(Option))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `std::ptr::drop_glue::> - shim(Some(Vec))` +note: inside `std::ptr::drop_glue:: - shim(Some(NotConstDestruct))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:28:9 +error[E0493]: destructor of `Option` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:34:9 | LL | let _z = x; | ^^ the destructor for this type cannot be evaluated in constants LL | }; | - value is dropped here -error[E0080]: calling non-const function ` as Drop>::drop` - --> $DIR/qualif-indirect-mutation-fail.rs:29:1 +error[E0080]: calling non-const function `::drop` + --> $DIR/qualif-indirect-mutation-fail.rs:35:1 | LL | }; | ^ evaluation of `A2` failed inside this call | -note: inside `std::ptr::drop_glue::> - shim(Some(Option))` +note: inside `std::ptr::drop_glue::> - shim(Some(Option))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `std::ptr::drop_glue:: - shim(Some(String))` - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `std::ptr::drop_glue::> - shim(Some(Vec))` +note: inside `std::ptr::drop_glue:: - shim(Some(NotConstDestruct))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -error[E0493]: destructor of `(u32, Option)` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:6:9 +error[E0493]: destructor of `(u32, Option)` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:12:9 | -LL | let mut a: (u32, Option) = (0, None); +LL | let mut a: (u32, Option) = (0, None); | ^^^^^ the destructor for this type cannot be evaluated in constant functions LL | let _ = &mut a.1; LL | } | - value is dropped here error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:33:9 + --> $DIR/qualif-indirect-mutation-fail.rs:39:9 | LL | let x: Option = None; | ^ the destructor for this type cannot be evaluated in constant functions @@ -60,44 +56,44 @@ LL | } | - value is dropped here error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:41:9 + --> $DIR/qualif-indirect-mutation-fail.rs:47:9 | LL | let _y = x; | ^^ the destructor for this type cannot be evaluated in constant functions LL | } | - value is dropped here -error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:49:9 +error[E0493]: destructor of `Option` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:55:9 | -LL | let mut y: Option = None; +LL | let mut y: Option = None; | ^^^^^ the destructor for this type cannot be evaluated in constant functions LL | std::ptr::addr_of_mut!(y); LL | } | - value is dropped here -error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:46:9 +error[E0493]: destructor of `Option` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:52:9 | -LL | let mut x: Option = None; +LL | let mut x: Option = None; | ^^^^^ the destructor for this type cannot be evaluated in constant functions ... LL | } | - value is dropped here -error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:59:9 +error[E0493]: destructor of `Option` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:65:9 | -LL | let y: Option = None; +LL | let y: Option = None; | ^ the destructor for this type cannot be evaluated in constant functions LL | std::ptr::addr_of!(y); LL | } | - value is dropped here -error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:56:9 +error[E0493]: destructor of `Option` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:62:9 | -LL | let x: Option = None; +LL | let x: Option = None; | ^ the destructor for this type cannot be evaluated in constant functions ... LL | } diff --git a/tests/ui/drop/repeat-drop-2.stderr b/tests/ui/drop/repeat-drop-2.stderr index cea7baf697664..ff2bc7fe6bf1d 100644 --- a/tests/ui/drop/repeat-drop-2.stderr +++ b/tests/ui/drop/repeat-drop-2.stderr @@ -6,6 +6,10 @@ LL | const _: [String; 0] = [String::new(); 0]; | || | |the destructor for this type cannot be evaluated in constants | value is dropped here + | + = note: see issue #133214 for more information + = help: add `#![feature(const_destruct)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0382]: use of moved value: `foo` --> $DIR/repeat-drop-2.rs:4:17 diff --git a/tests/ui/mir/drop-elaboration-after-borrowck-error.stderr b/tests/ui/mir/drop-elaboration-after-borrowck-error.stderr index 22d05fa4ddab0..a3b8b97b3ac0c 100644 --- a/tests/ui/mir/drop-elaboration-after-borrowck-error.stderr +++ b/tests/ui/mir/drop-elaboration-after-borrowck-error.stderr @@ -6,6 +6,10 @@ LL | a[0] = String::new(); | | | the destructor for this type cannot be evaluated in statics | value is dropped here + | + = note: see issue #133214 for more information + = help: add `#![feature(const_destruct)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0493]: destructor of `[String; 1]` cannot be evaluated at compile-time --> $DIR/drop-elaboration-after-borrowck-error.rs:5:9 @@ -15,6 +19,10 @@ LL | let a: [String; 1]; ... LL | }; | - value is dropped here + | + = note: see issue #133214 for more information + = help: add `#![feature(const_destruct)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/drop-elaboration-after-borrowck-error.rs:17:9 diff --git a/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.next.stderr b/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.next.stderr index 8b5c4f59fbdee..62d9091c50b10 100644 --- a/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.next.stderr +++ b/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.next.stderr @@ -1,20 +1,20 @@ -error[E0277]: the trait bound `Vec: const Destruct` is not satisfied - --> $DIR/const-closure-with-indestructible-indestructible.rs:10:16 +error[E0277]: the trait bound `NotConstDestruct: const Destruct` is not satisfied + --> $DIR/const-closure-with-indestructible-indestructible.rs:18:16 | LL | i_need(const || { | _________------_^ | | | | | required by a bound introduced by this call LL | | -LL | | let y = v; +LL | | let y = n; LL | | }) | |_________^ | note: required by a bound in `i_need` - --> $DIR/const-closure-with-indestructible-indestructible.rs:5:20 + --> $DIR/const-closure-with-indestructible-indestructible.rs:13:20 | -LL | const fn i_need(x: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `i_need` +LL | const fn i_need(x: F) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `i_need` error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.old.stderr b/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.old.stderr index 8b5c4f59fbdee..62d9091c50b10 100644 --- a/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.old.stderr +++ b/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.old.stderr @@ -1,20 +1,20 @@ -error[E0277]: the trait bound `Vec: const Destruct` is not satisfied - --> $DIR/const-closure-with-indestructible-indestructible.rs:10:16 +error[E0277]: the trait bound `NotConstDestruct: const Destruct` is not satisfied + --> $DIR/const-closure-with-indestructible-indestructible.rs:18:16 | LL | i_need(const || { | _________------_^ | | | | | required by a bound introduced by this call LL | | -LL | | let y = v; +LL | | let y = n; LL | | }) | |_________^ | note: required by a bound in `i_need` - --> $DIR/const-closure-with-indestructible-indestructible.rs:5:20 + --> $DIR/const-closure-with-indestructible-indestructible.rs:13:20 | -LL | const fn i_need(x: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `i_need` +LL | const fn i_need(x: F) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `i_need` error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.rs b/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.rs index d26260dd2d078..c6dcd119347d4 100644 --- a/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.rs +++ b/tests/ui/traits/const-traits/const-closure-with-indestructible-indestructible.rs @@ -2,14 +2,22 @@ //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver #![feature(const_trait_impl, const_closures, const_destruct)] -const fn i_need(x: F) {} + + +struct NotConstDestruct; + +impl Drop for NotConstDestruct { + fn drop(&mut self) {} +} + +const fn i_need(x: F) {} fn main() { const { - let v = Vec::::new(); + let n = NotConstDestruct; i_need(const || { //~^ ERROR the trait bound - let y = v; + let y = n; }) }; } From ed576bd42bed8b401c4cd7c36e9b3cbb5fc20113 Mon Sep 17 00:00:00 2001 From: Xi Ruoyao Date: Sat, 13 Jun 2026 20:39:50 +0800 Subject: [PATCH 03/14] mips: set llvm_args -mno-check-zero-division for all mips targets In rust interger divide by zero is defined to panic, thus the inserted conditional trap should never trigger as the program should have panicked if the divisor is zero. So disable the insertion of the redundant conditional trap. --- .../spec/targets/mips64_openwrt_linux_musl.rs | 3 +- .../targets/mips64_unknown_linux_gnuabi64.rs | 3 +- .../targets/mips64_unknown_linux_muslabi64.rs | 3 +- .../mips64el_unknown_linux_gnuabi64.rs | 3 +- .../mips64el_unknown_linux_muslabi64.rs | 3 +- .../src/spec/targets/mips_mti_none_elf.rs | 3 +- .../spec/targets/mips_unknown_linux_gnu.rs | 3 +- .../spec/targets/mips_unknown_linux_musl.rs | 3 +- .../spec/targets/mips_unknown_linux_uclibc.rs | 3 +- .../src/spec/targets/mipsel_mti_none_elf.rs | 3 +- .../spec/targets/mipsel_unknown_linux_gnu.rs | 3 +- .../spec/targets/mipsel_unknown_linux_musl.rs | 9 +- .../targets/mipsel_unknown_linux_uclibc.rs | 3 +- .../src/spec/targets/mipsel_unknown_netbsd.rs | 3 +- .../src/spec/targets/mipsel_unknown_none.rs | 3 +- .../targets/mipsisa32r6_unknown_linux_gnu.rs | 3 +- .../mipsisa32r6el_unknown_linux_gnu.rs | 3 +- .../mipsisa64r6_unknown_linux_gnuabi64.rs | 3 +- .../mipsisa64r6el_unknown_linux_gnuabi64.rs | 3 +- tests/assembly-llvm/mips-div-no-trap.rs | 120 ++++++++++++++++++ 20 files changed, 163 insertions(+), 20 deletions(-) create mode 100644 tests/assembly-llvm/mips-div-no-trap.rs diff --git a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs index 8b02e1235e609..ec91dbeb86ef9 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs @@ -2,7 +2,7 @@ use rustc_abi::Endian; -use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { let mut base = base::linux_musl::opts(); @@ -28,6 +28,7 @@ pub(crate) fn target() -> Target { endian: Endian::Big, mcount: "_mcount".into(), llvm_abiname: LlvmAbi::N64, + llvm_args: cvs!["-mno-check-zero-division"], ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs index 14942885c6b99..bb249d3335cf3 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -23,6 +23,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(64), mcount: "_mcount".into(), llvm_abiname: LlvmAbi::N64, + llvm_args: cvs!["-mno-check-zero-division"], ..base::linux_gnu::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs index c5336fd58fc93..c83d371692e69 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { let mut base = base::linux_musl::opts(); @@ -24,6 +24,7 @@ pub(crate) fn target() -> Target { endian: Endian::Big, mcount: "_mcount".into(), llvm_abiname: LlvmAbi::N64, + llvm_args: cvs!["-mno-check-zero-division"], ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs index 665cf1d4362d9..f3ab85ecdd2d2 100644 --- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs @@ -1,4 +1,4 @@ -use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -20,6 +20,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(64), mcount: "_mcount".into(), llvm_abiname: LlvmAbi::N64, + llvm_args: cvs!["-mno-check-zero-division"], ..base::linux_gnu::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs index bd237eaedc667..5685e84f140a4 100644 --- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs @@ -1,4 +1,4 @@ -use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { let mut base = base::linux_musl::opts(); @@ -21,6 +21,7 @@ pub(crate) fn target() -> Target { cfg_abi: CfgAbi::Abi64, mcount: "_mcount".into(), llvm_abiname: LlvmAbi::N64, + llvm_args: cvs!["-mno-check-zero-division"], ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/mips_mti_none_elf.rs b/compiler/rustc_target/src/spec/targets/mips_mti_none_elf.rs index 32440cdd92e99..b75c3e880cc17 100644 --- a/compiler/rustc_target/src/spec/targets/mips_mti_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/mips_mti_none_elf.rs @@ -2,7 +2,7 @@ use rustc_abi::Endian; use crate::spec::{ Arch, Cc, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, TargetMetadata, - TargetOptions, + TargetOptions, cvs, }; pub(crate) fn target() -> Target { @@ -26,6 +26,7 @@ pub(crate) fn target() -> Target { cpu: "mips32r2".into(), llvm_abiname: LlvmAbi::O32, + llvm_args: cvs!["-mno-check-zero-division"], max_atomic_width: Some(32), features: "+mips32r2,+soft-float,+noabicalls".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs index 8bfa8ecf60222..a706c4b1cbdc3 100644 --- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -19,6 +19,7 @@ pub(crate) fn target() -> Target { cpu: "mips32r2".into(), features: "+mips32r2,+fpxx,+nooddspreg".into(), llvm_abiname: LlvmAbi::O32, + llvm_args: cvs!["-mno-check-zero-division"], max_atomic_width: Some(32), mcount: "_mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs index 316e59dea88b8..7e3bebc60e9d3 100644 --- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { let mut base = base::linux_musl::opts(); @@ -21,6 +21,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { endian: Endian::Big, llvm_abiname: LlvmAbi::O32, + llvm_args: cvs!["-mno-check-zero-division"], mcount: "_mcount".into(), ..base }, diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs index b03dec5b5b6e8..d26a8c162e85e 100644 --- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs +++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -19,6 +19,7 @@ pub(crate) fn target() -> Target { cpu: "mips32r2".into(), features: "+mips32r2,+soft-float".into(), llvm_abiname: LlvmAbi::O32, + llvm_args: cvs!["-mno-check-zero-division"], max_atomic_width: Some(32), mcount: "_mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_mti_none_elf.rs b/compiler/rustc_target/src/spec/targets/mipsel_mti_none_elf.rs index ce50cedef99ff..c702dbc6c8243 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_mti_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_mti_none_elf.rs @@ -2,7 +2,7 @@ use rustc_abi::Endian; use crate::spec::{ Arch, Cc, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, TargetMetadata, - TargetOptions, + TargetOptions, cvs, }; pub(crate) fn target() -> Target { @@ -26,6 +26,7 @@ pub(crate) fn target() -> Target { cpu: "mips32r2".into(), llvm_abiname: LlvmAbi::O32, + llvm_args: cvs!["-mno-check-zero-division"], max_atomic_width: Some(32), features: "+mips32r2,+soft-float,+noabicalls".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs index 0541e0e9b2c5d..085f36c70a633 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs @@ -1,4 +1,4 @@ -use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -17,6 +17,7 @@ pub(crate) fn target() -> Target { cpu: "mips32r2".into(), features: "+mips32r2,+fpxx,+nooddspreg".into(), llvm_abiname: LlvmAbi::O32, + llvm_args: cvs!["-mno-check-zero-division"], max_atomic_width: Some(32), mcount: "_mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs index 5d0136a6699a7..c94f2fd87e589 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs @@ -1,4 +1,4 @@ -use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { let mut base = base::linux_musl::opts(); @@ -16,6 +16,11 @@ pub(crate) fn target() -> Target { pointer_width: 32, data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(), arch: Arch::Mips, - options: TargetOptions { llvm_abiname: LlvmAbi::O32, mcount: "_mcount".into(), ..base }, + options: TargetOptions { + llvm_abiname: LlvmAbi::O32, + llvm_args: cvs!["-mno-check-zero-division"], + mcount: "_mcount".into(), + ..base + }, } } diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs index 0add21bfc9c65..7b93f0e0ce433 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs @@ -1,4 +1,4 @@ -use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -17,6 +17,7 @@ pub(crate) fn target() -> Target { cpu: "mips32r2".into(), features: "+mips32r2,+soft-float".into(), llvm_abiname: LlvmAbi::O32, + llvm_args: cvs!["-mno-check-zero-division"], max_atomic_width: Some(32), mcount: "_mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs index 5395c15ad5813..f765409eb6d9c 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { let mut base = base::netbsd::opts(); @@ -21,6 +21,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+soft-float".into(), llvm_abiname: LlvmAbi::O32, + llvm_args: cvs!["-mno-check-zero-division"], mcount: "__mcount".into(), endian: Endian::Little, ..base diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs index 0e184c8348016..e99092a5c6c27 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs @@ -4,7 +4,7 @@ use crate::spec::{ Arch, Cc, LinkerFlavor, Lld, LlvmAbi, PanicStrategy, RelocModel, Target, TargetMetadata, - TargetOptions, + TargetOptions, cvs, }; pub(crate) fn target() -> Target { @@ -25,6 +25,7 @@ pub(crate) fn target() -> Target { cpu: "mips32r2".into(), features: "+mips32r2,+soft-float,+noabicalls".into(), llvm_abiname: LlvmAbi::O32, + llvm_args: cvs!["-mno-check-zero-division"], max_atomic_width: Some(32), linker: Some("rust-lld".into()), panic_strategy: PanicStrategy::Abort, diff --git a/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs index 80916500a4310..276d25432b6cb 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -19,6 +19,7 @@ pub(crate) fn target() -> Target { cpu: "mips32r6".into(), features: "+mips32r6".into(), llvm_abiname: LlvmAbi::O32, + llvm_args: cvs!["-mno-check-zero-division"], max_atomic_width: Some(32), mcount: "_mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs index 87db5a2828729..0de12904d9e02 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs @@ -1,4 +1,4 @@ -use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, LlvmAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -17,6 +17,7 @@ pub(crate) fn target() -> Target { cpu: "mips32r6".into(), features: "+mips32r6".into(), llvm_abiname: LlvmAbi::O32, + llvm_args: cvs!["-mno-check-zero-division"], max_atomic_width: Some(32), mcount: "_mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs index 8e66407470a25..88e3ab6d9fc39 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -23,6 +23,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(64), mcount: "_mcount".into(), llvm_abiname: LlvmAbi::N64, + llvm_args: cvs!["-mno-check-zero-division"], ..base::linux_gnu::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs index 5523f4470bd57..01046de7aa14b 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs @@ -1,4 +1,4 @@ -use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{Arch, CfgAbi, LlvmAbi, Target, TargetMetadata, TargetOptions, base, cvs}; pub(crate) fn target() -> Target { Target { @@ -20,6 +20,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(64), mcount: "_mcount".into(), llvm_abiname: LlvmAbi::N64, + llvm_args: cvs!["-mno-check-zero-division"], ..base::linux_gnu::opts() }, diff --git a/tests/assembly-llvm/mips-div-no-trap.rs b/tests/assembly-llvm/mips-div-no-trap.rs new file mode 100644 index 0000000000000..cb3d710846159 --- /dev/null +++ b/tests/assembly-llvm/mips-div-no-trap.rs @@ -0,0 +1,120 @@ +// Test that there's no conditional trap for zero divisor for all mips +// targets. Division by zero is defined as panic so the trap is redundant. +// +//@ add-minicore +//@ assembly-output: emit-asm +// +//@ revisions: mips64el-unknown-linux-gnuabi64 +//@[mips64el-unknown-linux-gnuabi64] compile-flags: --target=mips64el-unknown-linux-gnuabi64 +//@[mips64el-unknown-linux-gnuabi64] needs-llvm-components: mips +//@[mips64el-unknown-linux-gnuabi64] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mips64el-unknown-linux-muslabi64 +//@[mips64el-unknown-linux-muslabi64] compile-flags: --target=mips64el-unknown-linux-muslabi64 +//@[mips64el-unknown-linux-muslabi64] needs-llvm-components: mips +//@[mips64el-unknown-linux-muslabi64] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mips64-openwrt-linux-musl +//@[mips64-openwrt-linux-musl] compile-flags: --target=mips64-openwrt-linux-musl +//@[mips64-openwrt-linux-musl] needs-llvm-components: mips +//@[mips64-openwrt-linux-musl] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mips64-unknown-linux-gnuabi64 +//@[mips64-unknown-linux-gnuabi64] compile-flags: --target=mips64-unknown-linux-gnuabi64 +//@[mips64-unknown-linux-gnuabi64] needs-llvm-components: mips +//@[mips64-unknown-linux-gnuabi64] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mips64-unknown-linux-muslabi64 +//@[mips64-unknown-linux-muslabi64] compile-flags: --target=mips64-unknown-linux-muslabi64 +//@[mips64-unknown-linux-muslabi64] needs-llvm-components: mips +//@[mips64-unknown-linux-muslabi64] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mipsel-mti-none-elf +//@[mipsel-mti-none-elf] compile-flags: --target=mipsel-mti-none-elf +//@[mipsel-mti-none-elf] needs-llvm-components: mips +//@[mipsel-mti-none-elf] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mipsel-sony-psp +//@[mipsel-sony-psp] compile-flags: --target=mipsel-sony-psp +//@[mipsel-sony-psp] needs-llvm-components: mips +//@[mipsel-sony-psp] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mipsel-sony-psx +//@[mipsel-sony-psx] compile-flags: --target=mipsel-sony-psx +//@[mipsel-sony-psx] needs-llvm-components: mips +//@[mipsel-sony-psx] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mipsel-unknown-linux-gnu +//@[mipsel-unknown-linux-gnu] compile-flags: --target=mipsel-unknown-linux-gnu +//@[mipsel-unknown-linux-gnu] needs-llvm-components: mips +//@[mipsel-unknown-linux-gnu] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mipsel-unknown-linux-musl +//@[mipsel-unknown-linux-musl] compile-flags: --target=mipsel-unknown-linux-musl +//@[mipsel-unknown-linux-musl] needs-llvm-components: mips +//@[mipsel-unknown-linux-musl] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mipsel-unknown-linux-uclibc +//@[mipsel-unknown-linux-uclibc] compile-flags: --target=mipsel-unknown-linux-uclibc +//@[mipsel-unknown-linux-uclibc] needs-llvm-components: mips +//@[mipsel-unknown-linux-uclibc] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mipsel-unknown-netbsd +//@[mipsel-unknown-netbsd] compile-flags: --target=mipsel-unknown-netbsd +//@[mipsel-unknown-netbsd] needs-llvm-components: mips +//@[mipsel-unknown-netbsd] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mipsel-unknown-none +//@[mipsel-unknown-none] compile-flags: --target=mipsel-unknown-none +//@[mipsel-unknown-none] needs-llvm-components: mips +//@[mipsel-unknown-none] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mipsisa32r6el-unknown-linux-gnu +//@[mipsisa32r6el-unknown-linux-gnu] compile-flags: --target=mipsisa32r6el-unknown-linux-gnu +//@[mipsisa32r6el-unknown-linux-gnu] needs-llvm-components: mips +//@[mipsisa32r6el-unknown-linux-gnu] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mipsisa32r6-unknown-linux-gnu +//@[mipsisa32r6-unknown-linux-gnu] compile-flags: --target=mipsisa32r6-unknown-linux-gnu +//@[mipsisa32r6-unknown-linux-gnu] needs-llvm-components: mips +//@[mipsisa32r6-unknown-linux-gnu] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mipsisa64r6el-unknown-linux-gnuabi64 +//@[mipsisa64r6el-unknown-linux-gnuabi64] compile-flags: --target=mipsisa64r6el-unknown-linux-gnuabi64 +//@[mipsisa64r6el-unknown-linux-gnuabi64] needs-llvm-components: mips +//@[mipsisa64r6el-unknown-linux-gnuabi64] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mipsisa64r6-unknown-linux-gnuabi64 +//@[mipsisa64r6-unknown-linux-gnuabi64] compile-flags: --target=mipsisa64r6-unknown-linux-gnuabi64 +//@[mipsisa64r6-unknown-linux-gnuabi64] needs-llvm-components: mips +//@[mipsisa64r6-unknown-linux-gnuabi64] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mips-mti-none-elf +//@[mips-mti-none-elf] compile-flags: --target=mips-mti-none-elf +//@[mips-mti-none-elf] needs-llvm-components: mips +//@[mips-mti-none-elf] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mips-unknown-linux-gnu +//@[mips-unknown-linux-gnu] compile-flags: --target=mips-unknown-linux-gnu +//@[mips-unknown-linux-gnu] needs-llvm-components: mips +//@[mips-unknown-linux-gnu] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mips-unknown-linux-musl +//@[mips-unknown-linux-musl] compile-flags: --target=mips-unknown-linux-musl +//@[mips-unknown-linux-musl] needs-llvm-components: mips +//@[mips-unknown-linux-musl] filecheck-flags: --check-prefix NOTRAP +//@ revisions: mips-unknown-linux-uclibc +//@[mips-unknown-linux-uclibc] compile-flags: --target=mips-unknown-linux-uclibc +//@[mips-unknown-linux-uclibc] needs-llvm-components: mips +//@[mips-unknown-linux-uclibc] filecheck-flags: --check-prefix NOTRAP +// +//@ revisions: TRAP +//@[TRAP] compile-flags: --target=mips64el-unknown-linux-gnuabi64 -C llvm-args=-mno-check-zero-division=0 +//@[TRAP] needs-llvm-components: mips + +#![crate_type = "lib"] +#![feature(no_core, intrinsics)] +#![no_core] + +extern crate minicore; + +#[rustc_intrinsic] +pub unsafe fn unchecked_div(x: T, y: T) -> T; + +#[rustc_intrinsic] +pub fn abort() -> !; + +// NOTRAP-NOT: teq +// TRAP: teq +#[no_mangle] +pub fn div_i32(a: i32, b: i32) -> i32 { + match a { + 0 => abort(), + -1 => match b { + -2147483648 => abort(), + _ => unsafe { unchecked_div(a, b) }, + }, + _ => unsafe { unchecked_div(a, b) }, + } +} From 25acba896325cd73a09630e98e836e8096c8a182 Mon Sep 17 00:00:00 2001 From: Shivendra Sharma Date: Wed, 6 May 2026 14:15:43 +0530 Subject: [PATCH 04/14] diagnostics: point to coroutine body on higher-ranked auto trait errors --- .../nice_region_error/placeholder_error.rs | 43 ++++++++++++++++++- .../coroutine-auto-trait-span-issue-155880.rs | 30 +++++++++++++ ...outine-auto-trait-span-issue-155880.stderr | 17 ++++++++ ...er-ranked-auto-trait-11.assumptions.stderr | 5 ++- ...ranked-auto-trait-11.no_assumptions.stderr | 5 ++- .../issue-110963-early.no_assumptions.stderr | 10 ++++- tests/ui/coroutine/auto-trait-regions.stderr | 6 +++ 7 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 tests/ui/async-await/coroutine-auto-trait-span-issue-155880.rs create mode 100644 tests/ui/async-await/coroutine-auto-trait-span-issue-155880.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index fdbf4cf228de9..9307ea265c180 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -332,7 +332,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { leading_ellipsis, ); - self.tcx().dcx().create_err(TraitPlaceholderMismatch { + let mut err = self.tcx().dcx().create_err(TraitPlaceholderMismatch { span, satisfy_span, where_span, @@ -340,7 +340,46 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { def_id, trait_def_id: self.tcx().def_path_str(trait_def_id), actual_impl_expl_notes, - }) + }); + + let mut current_code = cause.code(); + let mut coroutine_def_id = None; + + loop { + match current_code { + ObligationCauseCode::MatchImpl(inner_cause, _) => { + current_code = inner_cause.code(); + } + ObligationCauseCode::BuiltinDerived(derived) => { + let self_ty = derived.parent_trait_pred.skip_binder().self_ty(); + + if let ty::Coroutine(def_id, _) | ty::CoroutineWitness(def_id, _) = + self_ty.kind() + { + coroutine_def_id = Some(*def_id); + break; + } + + current_code = &derived.parent_code; + } + _ => break, + } + } + + if let Some(def_id) = coroutine_def_id { + if self.tcx().trait_is_auto(trait_def_id) { + let c_span = self.tcx().def_span(def_id); + let descr = self.tcx().def_descr(def_id); + let trait_name = self.tcx().def_path_str(trait_def_id); + + err.span_label( + c_span, + format!("this {descr} captures a value whose type is not `{trait_name}`"), + ); + } + } + + err } /// Add notes with details about the expected and actual trait refs, with attention to cases diff --git a/tests/ui/async-await/coroutine-auto-trait-span-issue-155880.rs b/tests/ui/async-await/coroutine-auto-trait-span-issue-155880.rs new file mode 100644 index 0000000000000..8bc8ef550ad5a --- /dev/null +++ b/tests/ui/async-await/coroutine-auto-trait-span-issue-155880.rs @@ -0,0 +1,30 @@ +//@ edition: 2021 +// Regression test for + +trait Trait { + type Assoc<'a> + where + Self: 'a; +} + +impl Trait for T { + type Assoc<'a> = () + where + Self: 'a; +} + +async fn inner<'a, T: Trait + 'a>(_: T, x: T::Assoc<'a>) -> T::Assoc<'a> { + std::future::ready(x).await +} + +async fn outer<'a>() { + let x = 1u32; + inner(&x, ()).await; +} + +fn is_send(_: T) {} + +fn main() { + is_send(outer()) + //~^ ERROR implementation of `Send` is not general enough +} diff --git a/tests/ui/async-await/coroutine-auto-trait-span-issue-155880.stderr b/tests/ui/async-await/coroutine-auto-trait-span-issue-155880.stderr new file mode 100644 index 0000000000000..3048cc1d9c1c3 --- /dev/null +++ b/tests/ui/async-await/coroutine-auto-trait-span-issue-155880.stderr @@ -0,0 +1,17 @@ +error: implementation of `Send` is not general enough + --> $DIR/coroutine-auto-trait-span-issue-155880.rs:28:5 + | +LL | async fn inner<'a, T: Trait + 'a>(_: T, x: T::Assoc<'a>) -> T::Assoc<'a> { + | __________________________________________________________________________- +LL | | std::future::ready(x).await +LL | | } + | |_- this async fn captures a value whose type is not `Send` +... +LL | is_send(outer()) + | ^^^^^^^^^^^^^^^^ implementation of `Send` is not general enough + | + = note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... + = note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/higher-ranked-auto-trait-11.assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-11.assumptions.stderr index d39843f628c46..331a8c0540307 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-11.assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-11.assumptions.stderr @@ -11,7 +11,10 @@ error: implementation of `Send` is not general enough --> $DIR/higher-ranked-auto-trait-11.rs:27:9 | LL | Box::pin(async move { >::foo().await }) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Send` is not general enough + | ^^^^^^^^^----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | this async block captures a value whose type is not `Send` + | implementation of `Send` is not general enough | = note: `Send` would have to be implemented for the type `>::Future`, for any lifetime `'0`... = note: ...but `Send` is actually implemented for the type `>::Future`, for some specific lifetime `'1` diff --git a/tests/ui/async-await/higher-ranked-auto-trait-11.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-11.no_assumptions.stderr index d39843f628c46..331a8c0540307 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-11.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-11.no_assumptions.stderr @@ -11,7 +11,10 @@ error: implementation of `Send` is not general enough --> $DIR/higher-ranked-auto-trait-11.rs:27:9 | LL | Box::pin(async move { >::foo().await }) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Send` is not general enough + | ^^^^^^^^^----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | this async block captures a value whose type is not `Send` + | implementation of `Send` is not general enough | = note: `Send` would have to be implemented for the type `>::Future`, for any lifetime `'0`... = note: ...but `Send` is actually implemented for the type `>::Future`, for some specific lifetime `'1` diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr index bb43636492409..6b434ecca0109 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr @@ -1,7 +1,10 @@ error: implementation of `Send` is not general enough --> $DIR/issue-110963-early.rs:17:5 | -LL | / spawn(async move { +LL | spawn(async move { + | ^ ---------- this async block captures a value whose type is not `Send` + | _____| + | | LL | | let mut hc = hc; LL | | if !hc.check().await { LL | | log_health_check_failure().await; @@ -15,7 +18,10 @@ LL | | }); error: implementation of `Send` is not general enough --> $DIR/issue-110963-early.rs:17:5 | -LL | / spawn(async move { +LL | spawn(async move { + | ^ ---------- this async block captures a value whose type is not `Send` + | _____| + | | LL | | let mut hc = hc; LL | | if !hc.check().await { LL | | log_health_check_failure().await; diff --git a/tests/ui/coroutine/auto-trait-regions.stderr b/tests/ui/coroutine/auto-trait-regions.stderr index beb689d868d46..04acddafc414c 100644 --- a/tests/ui/coroutine/auto-trait-regions.stderr +++ b/tests/ui/coroutine/auto-trait-regions.stderr @@ -33,6 +33,9 @@ LL | let generator = #[coroutine] static move || { error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:31:5 | +LL | let generator = #[coroutine] move || { + | ------- this coroutine captures a value whose type is not `Foo` +... LL | assert_foo(generator); | ^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | @@ -42,6 +45,9 @@ LL | assert_foo(generator); error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:51:5 | +LL | let generator = #[coroutine] move || { + | ------- this coroutine captures a value whose type is not `Foo` +... LL | assert_foo(generator); | ^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | From 796bc5886004800d5571de9a9bc9deb5b0e0640a Mon Sep 17 00:00:00 2001 From: cezarbbb Date: Tue, 9 Jun 2026 11:06:08 +0800 Subject: [PATCH 05/14] add -Zstaticlib-rename-internal-symbols --- .../rustc_codegen_ssa/src/back/archive.rs | 66 ++- compiler/rustc_codegen_ssa/src/back/link.rs | 31 +- .../rustc_codegen_ssa/src/back/symbol_edit.rs | 473 +++++++++++++++--- compiler/rustc_codegen_ssa/src/base.rs | 1 + compiler/rustc_codegen_ssa/src/errors.rs | 8 + compiler/rustc_codegen_ssa/src/lib.rs | 1 + compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_session/src/config.rs | 8 + compiler/rustc_session/src/options.rs | 4 +- .../staticlib-rename-internal-symbols.md | 19 + .../rmake.rs | 163 ++++++ .../dual_main.c | 14 + .../staticlib-rename-internal-symbols/liba.rs | 17 + .../staticlib-rename-internal-symbols/libb.rs | 15 + .../rmake.rs | 165 ++++++ ...ename-internal-symbols-wrong-crate-type.rs | 8 + ...e-internal-symbols-wrong-crate-type.stderr | 2 + 17 files changed, 904 insertions(+), 92 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/staticlib-rename-internal-symbols.md create mode 100644 tests/run-make/staticlib-rename-internal-symbols-macho/rmake.rs create mode 100644 tests/run-make/staticlib-rename-internal-symbols/dual_main.c create mode 100644 tests/run-make/staticlib-rename-internal-symbols/liba.rs create mode 100644 tests/run-make/staticlib-rename-internal-symbols/libb.rs create mode 100644 tests/run-make/staticlib-rename-internal-symbols/rmake.rs create mode 100644 tests/ui/linking/staticlib-rename-internal-symbols-wrong-crate-type.rs create mode 100644 tests/ui/linking/staticlib-rename-internal-symbols-wrong-crate-type.stderr diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index b5d5893941ef2..bdf346d8e69d2 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::env; use std::error::Error; use std::ffi::OsString; @@ -22,7 +23,7 @@ use tracing::trace; use super::metadata::{create_compressed_metadata_file, search_for_section}; use super::rmeta_link; -use super::symbol_edit::apply_hide; +use super::symbol_edit::{apply_edits, collect_internal_names}; use crate::common; // Public for ArchiveBuilderBuilder::extract_bundled_libs pub use crate::errors::ExtractBundledLibsError; @@ -314,12 +315,18 @@ pub enum AddArchiveKind<'a> { Other, } +pub struct ArchiveSymbols { + pub exported: FxHashSet, + pub rename_suffix: Option, + pub hide: bool, +} + pub trait ArchiveBuilder { fn add_file(&mut self, path: &Path, kind: ArchiveEntryKind); fn add_archive(&mut self, archive: &Path, kind: AddArchiveKind<'_>) -> io::Result<()>; - fn build(self: Box, output: &Path, exported_symbols: Option>) -> bool; + fn build(self: Box, output: &Path, symbols: Option) -> bool; } fn target_archive_format_to_object_kind(format: &str) -> Option { @@ -534,9 +541,9 @@ impl<'a> ArchiveBuilder for ArArchiveBuilder<'a> { /// Combine the provided files, rlibs, and native libraries into a single /// `Archive`. - fn build(self: Box, output: &Path, exported_symbols: Option>) -> bool { + fn build(self: Box, output: &Path, symbols: Option) -> bool { let sess = self.sess; - match self.build_inner(output, exported_symbols) { + match self.build_inner(output, symbols) { Ok(any_members) => any_members, Err(error) => { sess.dcx().emit_fatal(ArchiveBuildFailure { path: output.to_owned(), error }) @@ -546,11 +553,7 @@ impl<'a> ArchiveBuilder for ArArchiveBuilder<'a> { } impl<'a> ArArchiveBuilder<'a> { - fn build_inner( - self, - output: &Path, - exported_symbols: Option>, - ) -> io::Result { + fn build_inner(self, output: &Path, symbols: Option) -> io::Result { let archive_kind = match &*self.sess.target.archive_format { "gnu" => ArchiveKind::Gnu, "bsd" => ArchiveKind::Bsd, @@ -562,6 +565,39 @@ impl<'a> ArArchiveBuilder<'a> { } }; + // Collect all internally-defined symbol names across every Rust object file. + // This set is needed because rename must also apply to *undefined* references + // (cross-object calls within the staticlib), but we cannot use `!exported.contains(name)` + // alone — that would also match external C symbols like `malloc` which must not be renamed. + let rename = if let Some(sym) = &symbols + && let Some(rename_suffix) = sym.rename_suffix.as_deref() + { + let mut names = FxHashSet::default(); + for (_, entry) in &self.entries { + if entry.kind != ArchiveEntryKind::RustObj { + continue; + } + match &entry.source { + ArchiveEntrySource::Archive { archive_index, file_range } => { + let src_archive = &self.src_archives[*archive_index]; + let start = file_range.0 as usize; + let end = start + file_range.1 as usize; + if let Some(data) = src_archive.1.get(start..end) { + collect_internal_names(data, &sym.exported, &mut names); + } + } + ArchiveEntrySource::File(file) => { + if let Ok(data) = fs::read(file) { + collect_internal_names(&data, &sym.exported, &mut names); + } + } + } + } + Some((names, rename_suffix)) + } else { + None + }; + let mut entries = Vec::new(); for (entry_name, entry) in self.entries { @@ -588,9 +624,9 @@ impl<'a> ArArchiveBuilder<'a> { }; if entry.kind == ArchiveEntryKind::RustObj - && let Some(exported) = &exported_symbols + && let Some(sym) = &symbols { - Box::new(apply_hide(data, exported)) + Box::new(apply_edits(data, &sym.exported, sym.hide, rename.as_ref())) } else { Box::new(data) } @@ -602,9 +638,13 @@ impl<'a> ArArchiveBuilder<'a> { ) .map_err(|err| io_error_context("failed to map object file", err))?; if entry.kind == ArchiveEntryKind::RustObj - && let Some(exported) = &exported_symbols + && let Some(sym) = &symbols { - Box::new(apply_hide(&mmap, exported)) + let edited = apply_edits(&mmap, &sym.exported, sym.hide, rename.as_ref()); + match edited { + Cow::Borrowed(_) => Box::new(mmap) as Box>, + Cow::Owned(v) => Box::new(v), + } } else { Box::new(mmap) as Box> } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index c68220aea78f7..2c3ee1bae09f8 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -53,7 +53,9 @@ use rustc_target::spec::{ }; use tracing::{debug, info, warn}; -use super::archive::{AddArchiveKind, ArchiveBuilder, ArchiveBuilderBuilder, ArchiveEntryKind}; +use super::archive::{ + AddArchiveKind, ArchiveBuilder, ArchiveBuilderBuilder, ArchiveEntryKind, ArchiveSymbols, +}; use super::command::Command; use super::linker::{self, Linker}; use super::metadata::{MetadataPosition, create_wrapper_file}; @@ -566,11 +568,21 @@ fn link_staticlib( sess.dcx().emit_fatal(e); } - let exported_symbols = if sess.opts.unstable_opts.staticlib_hide_internal_symbols { + let hide = sess.opts.unstable_opts.staticlib_hide_internal_symbols; + let rename = sess.opts.unstable_opts.staticlib_rename_internal_symbols; + + let exported_symbols = if hide || rename { if !matches!(sess.target.binary_format, BinaryFormat::Elf | BinaryFormat::MachO) { - sess.dcx().emit_warn(errors::StaticlibHideInternalSymbolsUnsupported { - binary_format: sess.target.archive_format.to_string(), - }); + if hide { + sess.dcx().emit_warn(errors::StaticlibHideInternalSymbolsUnsupported { + binary_format: sess.target.archive_format.to_string(), + }); + } + if rename { + sess.dcx().emit_warn(errors::StaticlibRenameInternalSymbolsUnsupported { + binary_format: sess.target.archive_format.to_string(), + }); + } None } else { crate_info @@ -581,7 +593,14 @@ fn link_staticlib( } else { None }; - ab.build(out_filename, exported_symbols); + + let symbols = exported_symbols.map(|exported| ArchiveSymbols { + exported, + rename_suffix: rename.then(|| crate_info.symbol_rename_suffix.clone()), + hide, + }); + + ab.build(out_filename, symbols); let crates = crate_info.used_crates.iter(); diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_edit.rs b/compiler/rustc_codegen_ssa/src/back/symbol_edit.rs index 19ecb3d92d209..ef8008216187a 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_edit.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_edit.rs @@ -1,42 +1,170 @@ -// We use the `object` crate for the read-only pass over ELF/Mach-O object files -// because its `Sym`/`Nlist` traits provide clean access to symbol properties without -// manual byte parsing. However, `object` does not expose mutable views into the data, -// so we cannot use it to modify symbol fields in place. Instead, the read-only pass -// collects byte-level patches (offset + new value), and the write pass -// (`apply_patches`) applies them to a copy of the byte buffer without any ELF/Mach-O -// parsing — similar to how linker relocations work. +//! Binary-level symbol editing for staticlib post-processing. +//! +//! - **Hide**: sets STV_HIDDEN (ELF) or N_PEXT (Mach-O) on non-exported symbols. +//! - **Rename**: appends a vendor-specific suffix to non-exported symbol names by +//! rebuilding the string table. +use std::borrow::Cow; use std::mem; -use object::read::elf::Sym as _; +use object::read::elf::{SectionHeader as _, Sym as _}; use object::read::macho::Nlist; use object::{Endianness, elf, macho}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -/// A byte-level patch collected in the read-only pass and applied in the write pass. struct Patch { offset: usize, value: u8, } -/// Apply a list of byte patches to `data`, returning the (possibly modified) bytes. -fn apply_patches(data: &[u8], patches: &[Patch]) -> Vec { - let mut buf = data.to_vec(); - for p in patches { - buf[p.offset] = p.value; +struct RenameEntry { + name_field_offset: usize, + name: String, +} + +pub(super) fn apply_edits<'a>( + data: &'a [u8], + exported: &FxHashSet, + hide: bool, + rename: Option<&(FxHashSet, &str)>, +) -> Cow<'a, [u8]> { + let result = match object::File::parse(data).ok() { + Some(object::File::Elf64(_)) => elf_edit_impl::>( + data, + exported, + hide, + rename, + mem::offset_of!(elf::Sym64, st_other), + ), + Some(object::File::Elf32(_)) => elf_edit_impl::>( + data, + exported, + hide, + rename, + mem::offset_of!(elf::Sym32, st_other), + ), + Some(object::File::MachO64(_)) => macho_edit_impl::>( + data, + exported, + hide, + rename, + mem::offset_of!(macho::Nlist64, n_type), + ), + Some(object::File::MachO32(_)) => macho_edit_impl::>( + data, + exported, + hide, + rename, + mem::offset_of!(macho::Nlist32, n_type), + ), + _ => None, + }; + match result { + Some(v) => Cow::Owned(v), + None => Cow::Borrowed(data), + } +} + +pub(super) fn collect_internal_names( + data: &[u8], + exported: &FxHashSet, + out: &mut FxHashSet, +) { + let Ok(file) = object::File::parse(data) else { return }; + match file { + object::File::Elf64(_) => { + elf_collect_impl::>(data, exported, out) + } + object::File::Elf32(_) => { + elf_collect_impl::>(data, exported, out) + } + object::File::MachO64(_) => { + macho_collect_impl::>(data, exported, out) + } + object::File::MachO32(_) => { + macho_collect_impl::>(data, exported, out) + } + _ => {} + } +} + +fn elf_collect_impl>( + data: &[u8], + exported: &FxHashSet, + out: &mut FxHashSet, +) where + u64: From, +{ + let Ok(header) = Elf::parse(data) else { return }; + let Ok(endian) = header.endian() else { return }; + let Ok(sections) = header.sections(endian, data) else { return }; + let Ok(symtab) = sections.symbols(endian, data, elf::SHT_SYMTAB) else { return }; + let strings = symtab.strings(); + + for sym in symtab.iter() { + let binding = sym.st_bind(); + if binding != elf::STB_GLOBAL && binding != elf::STB_WEAK { + continue; + } + if sym.is_undefined(endian) { + continue; + } + let Ok(name_bytes) = sym.name(endian, strings) else { continue }; + let Ok(name) = str::from_utf8(name_bytes) else { continue }; + if !exported.contains(name) { + out.insert(name.to_string()); + } + } +} + +fn macho_collect_impl>( + data: &[u8], + exported: &FxHashSet, + out: &mut FxHashSet, +) { + let Ok(header) = Mach::parse(data, 0) else { return }; + let Ok(endian) = header.endian() else { return }; + let Ok(mut commands) = header.load_commands(endian, data, 0) else { return }; + + let symtab_cmd = loop { + let Ok(Some(cmd)) = commands.next() else { return }; + if let Ok(Some(st)) = cmd.symtab() { + break st; + } + }; + let Ok(symtab) = symtab_cmd.symbols::(endian, data) else { return }; + let strings = symtab.strings(); + + for nlist in symtab.iter() { + if nlist.is_stab() { + continue; + } + if nlist.is_undefined() { + continue; + } + if nlist.n_type() & macho::N_EXT == 0 { + continue; + } + let Ok(name_bytes) = nlist.name(endian, strings) else { continue }; + let Ok(name) = str::from_utf8(name_bytes) else { continue }; + let name = name.strip_prefix('_').unwrap_or(name); + if !exported.contains(name) { + out.insert(name.to_string()); + } } - buf } // --------------------------------------------------------------------------- -// ELF hide – read-only pass uses `object` crate, write pass uses `Patch` list +// ELF: single-pass collection + apply // --------------------------------------------------------------------------- -fn elf_hide_patches_impl<'data, Elf: object::read::elf::FileHeader>( - data: &'data [u8], - st_other_offset: usize, +fn elf_edit_impl>( + data: &[u8], exported: &FxHashSet, -) -> Option> + hide: bool, + rename: Option<&(FxHashSet, &str)>, + st_other_offset: usize, +) -> Option> where u64: From, { @@ -44,113 +172,314 @@ where let endian = header.endian().ok()?; let sections = header.sections(endian, data).ok()?; let symtab = sections.symbols(endian, data, elf::SHT_SYMTAB).ok()?; - let data_ptr = data.as_ptr() as usize; let strings = symtab.strings(); + let mut patches = Vec::new(); + let mut renames = Vec::new(); for sym in symtab.iter() { let binding = sym.st_bind(); if binding != elf::STB_GLOBAL && binding != elf::STB_WEAK { continue; } - if sym.is_undefined(endian) { - continue; - } let Ok(name_bytes) = sym.name(endian, strings) else { continue }; let Ok(name) = str::from_utf8(name_bytes) else { continue }; - if !exported.contains(name) { - let sym_addr = sym as *const Elf::Sym as usize; + + let sym_addr = sym as *const Elf::Sym as usize; + + if hide && !sym.is_undefined(endian) && !exported.contains(name) { let offset = sym_addr - data_ptr + st_other_offset; let new_vis = (sym.st_other() & !0x03) | elf::STV_HIDDEN; patches.push(Patch { offset, value: new_vis }); } + if let Some((rename_set, _)) = rename { + if rename_set.contains(name) { + renames.push(RenameEntry { + name_field_offset: sym_addr - data_ptr, + name: name.to_string(), + }); + } + } + } + + if patches.is_empty() && renames.is_empty() { + return None; } - Some(patches) + let mut result = data.to_vec(); + for p in &patches { + result[p.offset] = p.value; + } + + if !renames.is_empty() { + let suffix = rename.unwrap().1; + if let Some(renamed) = + elf_rebuild_strtab::(&result, &renames, suffix, §ions, header, endian) + { + result = renamed; + } + } + + Some(result) +} + +fn elf_rebuild_strtab>( + data: &[u8], + renames: &[RenameEntry], + suffix: &str, + sections: &object::read::elf::SectionTable<'_, Elf>, + header: &Elf, + endian: Endianness, +) -> Option> +where + u64: From, +{ + let mut strtab_si: Option = None; + for section in sections.iter() { + if section.sh_type(endian) == elf::SHT_SYMTAB { + strtab_si = Some(section.sh_link(endian) as usize); + break; + } + } + let strtab_si = strtab_si?; + + let e_shoff = u64::from(header.e_shoff(endian)) as usize; + let e_shentsize = mem::size_of::(); + let e_shnum = sections.len(); + + let strtab_section = sections.section(object::SectionIndex(strtab_si)).ok()?; + let old_strtab_offset = u64::from(strtab_section.sh_offset(endian)) as usize; + let old_strtab_size = u64::from(strtab_section.sh_size(endian)) as usize; + let old_strtab = data.get(old_strtab_offset..old_strtab_offset + old_strtab_size)?; + + let (new_strtab, rename_map) = build_renamed_strtab(old_strtab, renames, suffix); + + let is_64 = mem::size_of::() == 8; + let new_strtab_file_off = data.len(); + let new_strtab_size = new_strtab.len(); + let new_e_shoff_raw = new_strtab_file_off + new_strtab_size; + let new_e_shoff = (new_e_shoff_raw + 7) & !7; + let padding = new_e_shoff - new_e_shoff_raw; + let section_headers_size = e_shentsize * e_shnum; + + let result_size = new_e_shoff + section_headers_size; + let mut result = Vec::with_capacity(result_size); + result.extend_from_slice(data); + result.extend_from_slice(&new_strtab); + result.resize(result.len() + padding, 0); + let sh_data = data.get(e_shoff..e_shoff + section_headers_size)?; + result.extend_from_slice(sh_data); + + if is_64 { + write_u64_at( + &mut result, + mem::offset_of!(elf::FileHeader64, e_shoff), + new_e_shoff as u64, + endian, + ); + } else { + write_u32_at( + &mut result, + mem::offset_of!(elf::FileHeader32, e_shoff), + new_e_shoff as u32, + endian, + ); + } + + let new_strtab_shdr_offset = new_e_shoff + strtab_si * e_shentsize; + + if is_64 { + let sh_offset_field = mem::offset_of!(elf::SectionHeader64, sh_offset); + let sh_size_field = mem::offset_of!(elf::SectionHeader64, sh_size); + write_u64_at( + &mut result, + new_strtab_shdr_offset + sh_offset_field, + new_strtab_file_off as u64, + endian, + ); + write_u64_at( + &mut result, + new_strtab_shdr_offset + sh_size_field, + new_strtab_size as u64, + endian, + ); + } else { + let sh_offset_field = mem::offset_of!(elf::SectionHeader32, sh_offset); + let sh_size_field = mem::offset_of!(elf::SectionHeader32, sh_size); + write_u32_at( + &mut result, + new_strtab_shdr_offset + sh_offset_field, + new_strtab_file_off as u32, + endian, + ); + write_u32_at( + &mut result, + new_strtab_shdr_offset + sh_size_field, + new_strtab_size as u32, + endian, + ); + } + + for entry in renames { + let new_st_name = rename_map[&entry.name]; + write_u32_at(&mut result, entry.name_field_offset, new_st_name, endian); + } + + Some(result) } // --------------------------------------------------------------------------- -// Mach-O hide – same architecture: read-only pass via `object`, write via patches +// Mach-O: single-pass collection + apply // --------------------------------------------------------------------------- -fn macho_hide_patches_impl<'data, Mach: object::read::macho::MachHeader>( - data: &'data [u8], - n_type_offset: usize, +fn macho_edit_impl>( + data: &[u8], exported: &FxHashSet, -) -> Option> { + hide: bool, + rename: Option<&(FxHashSet, &str)>, + n_type_offset: usize, +) -> Option> { let header = Mach::parse(data, 0).ok()?; let endian = header.endian().ok()?; let mut commands = header.load_commands(endian, data, 0).ok()?; - let symtab_cmd = loop { + let (symtab_cmd, symtab_cmd_offset) = loop { let cmd = commands.next().ok()??; if let Some(st) = cmd.symtab().ok().flatten() { - break st; + break (st, cmd.raw_data().as_ptr() as usize - data.as_ptr() as usize); } }; + let symtab: object::read::macho::SymbolTable<'_, Mach, &_> = symtab_cmd.symbols(endian, data).ok()?; - let data_ptr = data.as_ptr() as usize; let strings = symtab.strings(); + let mut patches = Vec::new(); + let mut renames = Vec::new(); for nlist in symtab.iter() { if nlist.is_stab() { continue; } - if nlist.is_undefined() { - continue; - } if nlist.n_type() & macho::N_EXT == 0 { continue; } let Ok(name_bytes) = nlist.name(endian, strings) else { continue }; - let Ok(name) = str::from_utf8(name_bytes) else { continue }; - let name = name.strip_prefix('_').unwrap_or(name); - if !exported.contains(name) { - let nlist_addr = nlist as *const Mach::Nlist as usize; + let Ok(raw_name) = str::from_utf8(name_bytes) else { continue }; + let name = raw_name.strip_prefix('_').unwrap_or(raw_name); + + let nlist_addr = nlist as *const Mach::Nlist as usize; + + if hide && !nlist.is_undefined() && !exported.contains(name) { let offset = nlist_addr - data_ptr + n_type_offset; patches.push(Patch { offset, value: nlist.n_type() | macho::N_PEXT }); } + if let Some((rename_set, _)) = rename { + if rename_set.contains(name) { + renames.push(RenameEntry { + name_field_offset: nlist_addr - data_ptr, + name: raw_name.to_string(), + }); + } + } + } + + if patches.is_empty() && renames.is_empty() { + return None; } - Some(patches) + let mut result = data.to_vec(); + for p in &patches { + result[p.offset] = p.value; + } + + if !renames.is_empty() { + let suffix = rename.unwrap().1; + if let Some(renamed) = + macho_rebuild_strtab(&result, &renames, suffix, &symtab_cmd, symtab_cmd_offset, endian) + { + result = renamed; + } + } + + Some(result) +} + +fn macho_rebuild_strtab( + data: &[u8], + renames: &[RenameEntry], + suffix: &str, + symtab_cmd: &macho::SymtabCommand, + symtab_cmd_offset: usize, + endian: Endianness, +) -> Option> { + let old_stroff = symtab_cmd.stroff.get(endian) as usize; + let old_strsize = symtab_cmd.strsize.get(endian) as usize; + let old_strtab = data.get(old_stroff..old_stroff + old_strsize)?; + + let (new_strtab, rename_map) = build_renamed_strtab(old_strtab, renames, suffix); + + let new_strtab_file_off = data.len(); + let new_strtab_size = new_strtab.len(); + + let mut result = Vec::with_capacity(data.len() + new_strtab_size); + result.extend_from_slice(data); + result.extend_from_slice(&new_strtab); + + let stroff_off = mem::offset_of!(macho::SymtabCommand, stroff); + let strsize_off = mem::offset_of!(macho::SymtabCommand, strsize); + write_u32_at(&mut result, symtab_cmd_offset + stroff_off, new_strtab_file_off as u32, endian); + write_u32_at(&mut result, symtab_cmd_offset + strsize_off, new_strtab_size as u32, endian); + + for entry in renames { + let new_strx = rename_map[&entry.name]; + write_u32_at(&mut result, entry.name_field_offset, new_strx, endian); + } + + Some(result) } // --------------------------------------------------------------------------- -// Unified dispatch: top-level detection via `object::File::parse` +// Shared helpers // --------------------------------------------------------------------------- -fn hide_patches(data: &[u8], exported: &FxHashSet) -> Option> { - let file = object::File::parse(data).ok()?; - match file { - object::File::Elf64(_) => elf_hide_patches_impl::>( - data, - mem::offset_of!(elf::Sym64, st_other), - exported, - ), - object::File::Elf32(_) => elf_hide_patches_impl::>( - data, - mem::offset_of!(elf::Sym32, st_other), - exported, - ), - object::File::MachO64(_) => macho_hide_patches_impl::>( - data, - mem::offset_of!(macho::Nlist64, n_type), - exported, - ), - object::File::MachO32(_) => macho_hide_patches_impl::>( - data, - mem::offset_of!(macho::Nlist32, n_type), - exported, - ), - _ => None, +fn build_renamed_strtab( + old_strtab: &[u8], + renames: &[RenameEntry], + suffix: &str, +) -> (Vec, FxHashMap) { + let mut new_strtab = old_strtab.to_vec(); + let mut rename_map: FxHashMap = FxHashMap::default(); + + let mut sorted_names: Vec<&str> = renames.iter().map(|r| r.name.as_str()).collect(); + sorted_names.sort(); + sorted_names.dedup(); + + for name in &sorted_names { + let new_offset = new_strtab.len() as u32; + new_strtab.extend_from_slice(name.as_bytes()); + new_strtab.extend_from_slice(suffix.as_bytes()); + new_strtab.push(0); + rename_map.insert(name.to_string(), new_offset); } + + (new_strtab, rename_map) } -pub(super) fn apply_hide(data: &[u8], exported: &FxHashSet) -> Vec { - let patches = hide_patches(data, exported).unwrap_or_default(); - apply_patches(data, &patches) +fn write_u32_at(buf: &mut [u8], offset: usize, value: u32, endian: Endianness) { + let bytes = match endian { + Endianness::Little => value.to_le_bytes(), + Endianness::Big => value.to_be_bytes(), + }; + buf[offset..offset + 4].copy_from_slice(&bytes); +} + +fn write_u64_at(buf: &mut [u8], offset: usize, value: u64, endian: Endianness) { + let bytes = match endian { + Endianness::Little => value.to_le_bytes(), + Endianness::Big => value.to_be_bytes(), + }; + buf[offset..offset + 8].copy_from_slice(&bytes); } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index c14d4aec48c35..2a5e421282f4e 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -962,6 +962,7 @@ impl CrateInfo { natvis_debugger_visualizers: Default::default(), lint_level_specs: CodegenLintLevelSpecs::from_tcx(tcx), metadata_symbol: exported_symbols::metadata_symbol_name(tcx), + symbol_rename_suffix: format!(".rs{:x}", tcx.stable_crate_id(LOCAL_CRATE)), each_linked_rlib_file_for_lto: Default::default(), exported_symbols_for_lto: Default::default(), }; diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 9326e477465f0..37352eaa7d55f 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -701,6 +701,14 @@ pub(crate) struct StaticlibHideInternalSymbolsUnsupported { pub binary_format: String, } +#[derive(Diagnostic)] +#[diag( + "-Zstaticlib-rename-internal-symbols only supports ELF and Mach-O targets, but the target uses `{$binary_format}`" +)] +pub(crate) struct StaticlibRenameInternalSymbolsUnsupported { + pub binary_format: String, +} + #[derive(Diagnostic)] #[diag("entry symbol `main` declared multiple times")] #[help( diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 616397dd77545..10ae8a9ee0b38 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -263,6 +263,7 @@ pub struct CrateInfo { pub natvis_debugger_visualizers: BTreeSet, pub lint_level_specs: CodegenLintLevelSpecs, pub metadata_symbol: String, + pub symbol_rename_suffix: String, pub each_linked_rlib_file_for_lto: Vec, pub exported_symbols_for_lto: Vec, } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 622077caddc40..7bbb651889fd8 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -867,6 +867,7 @@ fn test_unstable_options_tracking_hash() { tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1)); tracked!(stack_protector, StackProtector::All); tracked!(staticlib_hide_internal_symbols, true); + tracked!(staticlib_rename_internal_symbols, true); tracked!(teach, true); tracked!(thinlto, Some(true)); tracked!(tiny_const_eval_limit, true); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 1b3217ed0a030..a712e55bc4ce1 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2473,6 +2473,14 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M ); } + if unstable_opts.staticlib_rename_internal_symbols + && !crate_types.contains(&CrateType::StaticLib) + { + early_dcx.early_warn( + "-Zstaticlib-rename-internal-symbols has no effect without `--crate-type staticlib`", + ); + } + let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches); if !unstable_opts.unstable_options && json_timings { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 6ae0d9721bc00..ba8c433e3dfd7 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2689,7 +2689,9 @@ written to standard error output)"), staticlib_allow_rdylib_deps: bool = (false, parse_bool, [TRACKED], "allow staticlibs to have rust dylib dependencies"), staticlib_hide_internal_symbols: bool = (false, parse_bool, [TRACKED], - "hide non-exported symbols in ELF static libraries by setting STV_HIDDEN"), + "hide non-exported Rust symbols when building staticlibs by setting STV_HIDDEN"), + staticlib_rename_internal_symbols: bool = (false, parse_bool, [TRACKED], + "rename non-exported Rust symbols when building staticlibs to avoid conflicts"), staticlib_prefer_dynamic: bool = (false, parse_bool, [TRACKED], "prefer dynamic linking to static linking for staticlibs (default: no)"), strict_init_checks: bool = (false, parse_bool, [TRACKED], diff --git a/src/doc/unstable-book/src/compiler-flags/staticlib-rename-internal-symbols.md b/src/doc/unstable-book/src/compiler-flags/staticlib-rename-internal-symbols.md new file mode 100644 index 0000000000000..f25a45ae7efc9 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/staticlib-rename-internal-symbols.md @@ -0,0 +1,19 @@ +# `staticlib-rename-internal-symbols` + +When building a `staticlib`, this option renames all non-exported Rust-internal +symbols by appending a `_rs{hash}` suffix. This prevents symbol collisions when +multiple Rust static libraries are linked into the same final binary. + +This option only renames symbols; it does not change their visibility. +Use `-Zstaticlib-hide-internal-symbols` in addition if you also want to hide +internal symbols. + +Only symbols explicitly exported via `#[no_mangle]` or `#[export_name]` are left +unchanged. All other `GLOBAL`/`WEAK` symbols (including `pub(crate)` and `pub` +items without `#[no_mangle]`) are renamed. + +This option can only be used with `--crate-type staticlib`. Using it with +other crate types will result in a compilation warning. + +Supported on ELF targets (Linux, BSD, etc.) and Apple targets (macOS, iOS, etc.). +On unsupported targets (Windows), a warning is emitted and the flag has no effect. diff --git a/tests/run-make/staticlib-rename-internal-symbols-macho/rmake.rs b/tests/run-make/staticlib-rename-internal-symbols-macho/rmake.rs new file mode 100644 index 0000000000000..911dadc16325d --- /dev/null +++ b/tests/run-make/staticlib-rename-internal-symbols-macho/rmake.rs @@ -0,0 +1,163 @@ +//@ only-apple +//@ ignore-cross-compile + +use std::collections::HashSet; + +use run_make_support::object::Endianness; +use run_make_support::object::macho::{MachHeader64, N_EXT, N_PEXT, N_SECT, N_STAB, N_TYPE}; +use run_make_support::object::read::archive::ArchiveFile; +use run_make_support::object::read::macho::{MachHeader as _, Nlist as _}; +use run_make_support::path_helpers::source_root; +use run_make_support::{cc, extra_c_flags, object, rfs, run, rustc, static_lib_name}; + +type MachOFileHeader64 = MachHeader64; +type SymbolTable<'data> = + run_make_support::object::read::macho::SymbolTable<'data, MachOFileHeader64>; + +const EXPORTED: &[&str] = &["my_add", "my_hash_lookup", "call_internal", "my_safe_div"]; + +fn main() { + let hide_sibling = source_root().join("tests/run-make/staticlib-hide-internal-symbols"); + let rename_sibling = source_root().join("tests/run-make/staticlib-rename-internal-symbols"); + rfs::copy(hide_sibling.join("lib.rs"), "lib.rs"); + rfs::copy(hide_sibling.join("main.c"), "main.c"); + rfs::copy(rename_sibling.join("liba.rs"), "liba.rs"); + rfs::copy(rename_sibling.join("libb.rs"), "libb.rs"); + rfs::copy(rename_sibling.join("dual_main.c"), "dual_main.c"); + + test_basic_functionality(); + test_suffix_present(); + test_dual_staticlib_linking(); +} + +fn test_basic_functionality() { + let lib_name = static_lib_name("lib"); + + rustc() + .input("lib.rs") + .crate_type("staticlib") + .arg("-Zstaticlib-rename-internal-symbols") + .opt() + .run(); + + cc().input("main.c").input(&lib_name).out_exe("main").args(extra_c_flags()).run(); + run("main"); + + rfs::remove_file(&lib_name); +} + +fn test_suffix_present() { + let lib_name = static_lib_name("lib"); + + rustc() + .input("lib.rs") + .crate_type("staticlib") + .arg("-Zstaticlib-rename-internal-symbols") + .opt() + .run(); + + let data = rfs::read(&lib_name); + check_rename_symbols(&data); + + rfs::remove_file(&lib_name); +} + +fn test_dual_staticlib_linking() { + let liba_name = static_lib_name("liba"); + let libb_name = static_lib_name("libb"); + + rustc() + .input("liba.rs") + .crate_type("staticlib") + .arg("-Zstaticlib-rename-internal-symbols") + .opt() + .run(); + + rustc() + .input("libb.rs") + .crate_type("staticlib") + .arg("-Zstaticlib-rename-internal-symbols") + .opt() + .run(); + + cc().input("dual_main.c") + .input(&liba_name) + .input(&libb_name) + .out_exe("dual_main") + .args(extra_c_flags()) + .run(); + run("dual_main"); +} + +fn check_rename_symbols(archive_data: &[u8]) { + let archive = ArchiveFile::parse(archive_data).unwrap(); + let mut found_exported = HashSet::new(); + let mut found_suffix = false; + + for member in archive.members() { + let member = member.unwrap(); + if !member.name().ends_with(b".rcgu.o") { + continue; + } + let data = member.data(archive_data).unwrap(); + + let Ok(header) = MachOFileHeader64::parse(data, 0) else { continue }; + let Ok(endian) = header.endian() else { continue }; + + let Some(symtab) = find_symtab(header, endian, data) else { continue }; + let strtab = symtab.strings(); + + for nlist in symtab.iter() { + let n_type = nlist.n_type(); + if n_type & N_STAB != 0 { + continue; + } + if n_type & N_EXT == 0 { + continue; + } + if n_type & N_TYPE != N_SECT { + continue; + } + + let Ok(name_bytes) = nlist.name(endian, strtab) else { continue }; + let Ok(name) = std::str::from_utf8(name_bytes) else { continue }; + let name = name.strip_prefix('_').unwrap_or(name); + + if EXPORTED.contains(&name) { + assert!( + !name.contains(".rs"), + "exported symbol `{name}` should not contain .rs suffix" + ); + found_exported.insert(name.to_string()); + } else { + assert!( + name.contains(".rs"), + "internal symbol `{name}` should contain .rs suffix after rename" + ); + found_suffix = true; + } + } + } + + assert!(found_suffix, "expected to find at least one renamed symbol with .rs suffix"); + for expected in EXPORTED { + assert!( + found_exported.contains(*expected), + "expected to find exported symbol `{expected}` in archive" + ); + } +} + +fn find_symtab<'data>( + header: &MachOFileHeader64, + endian: Endianness, + data: &'data [u8], +) -> Option> { + let mut commands = header.load_commands(endian, data, 0).ok()?; + while let Ok(Some(command)) = commands.next() { + if let Ok(Some(symtab_cmd)) = command.symtab() { + return symtab_cmd.symbols::(endian, data).ok(); + } + } + None +} diff --git a/tests/run-make/staticlib-rename-internal-symbols/dual_main.c b/tests/run-make/staticlib-rename-internal-symbols/dual_main.c new file mode 100644 index 0000000000000..21f4d5cae9b55 --- /dev/null +++ b/tests/run-make/staticlib-rename-internal-symbols/dual_main.c @@ -0,0 +1,14 @@ +extern int liba_process(int v); +extern int liba_answer(); +extern int libb_multiply(int a, int b); +extern int libb_greet(); + +int main() { + if (liba_answer() != 42) return 1; + if (liba_process(10) != 31) return 1; + + if (libb_multiply(6, 7) != 42) return 1; + if (libb_greet() != 99) return 1; + + return 0; +} diff --git a/tests/run-make/staticlib-rename-internal-symbols/liba.rs b/tests/run-make/staticlib-rename-internal-symbols/liba.rs new file mode 100644 index 0000000000000..ca23944df44ea --- /dev/null +++ b/tests/run-make/staticlib-rename-internal-symbols/liba.rs @@ -0,0 +1,17 @@ +#![crate_type = "staticlib"] + +mod internal { + pub fn compute(v: i32) -> i32 { + v * 3 + 1 + } +} + +#[no_mangle] +pub extern "C" fn liba_process(v: i32) -> i32 { + internal::compute(v) +} + +#[no_mangle] +pub extern "C" fn liba_answer() -> i32 { + 42 +} diff --git a/tests/run-make/staticlib-rename-internal-symbols/libb.rs b/tests/run-make/staticlib-rename-internal-symbols/libb.rs new file mode 100644 index 0000000000000..1eca8f3d254ca --- /dev/null +++ b/tests/run-make/staticlib-rename-internal-symbols/libb.rs @@ -0,0 +1,15 @@ +#![crate_type = "staticlib"] + +fn internal_multiply(a: i32, b: i32) -> i32 { + a * b +} + +#[no_mangle] +pub extern "C" fn libb_multiply(a: i32, b: i32) -> i32 { + internal_multiply(a, b) +} + +#[no_mangle] +pub extern "C" fn libb_greet() -> i32 { + 99 +} diff --git a/tests/run-make/staticlib-rename-internal-symbols/rmake.rs b/tests/run-make/staticlib-rename-internal-symbols/rmake.rs new file mode 100644 index 0000000000000..57123dba38f45 --- /dev/null +++ b/tests/run-make/staticlib-rename-internal-symbols/rmake.rs @@ -0,0 +1,165 @@ +//@ only-elf +//@ ignore-cross-compile + +use std::collections::HashSet; + +use run_make_support::object::read::archive::ArchiveFile; +use run_make_support::object::read::elf::{FileHeader as _, SectionHeader as _, Sym as _}; +use run_make_support::object::{Endianness, elf}; +use run_make_support::path_helpers::source_root; +use run_make_support::{cc, extra_c_flags, rfs, run, rustc, static_lib_name}; + +const EXPORTED: &[&str] = &["my_add", "my_hash_lookup", "call_internal", "my_safe_div"]; + +fn main() { + let sibling = source_root().join("tests/run-make/staticlib-hide-internal-symbols"); + rfs::copy(sibling.join("lib.rs"), "lib.rs"); + rfs::copy(sibling.join("main.c"), "main.c"); + + test_basic_functionality(); + test_rs_suffix_present(); + test_dual_staticlib_linking(); +} + +fn test_basic_functionality() { + let lib_name = static_lib_name("lib"); + + rustc() + .input("lib.rs") + .crate_type("staticlib") + .arg("-Zstaticlib-rename-internal-symbols") + .opt() + .run(); + + cc().input("main.c").input(&lib_name).out_exe("main").args(extra_c_flags()).run(); + run("main"); + + rfs::remove_file(&lib_name); +} + +fn test_rs_suffix_present() { + let lib_name = static_lib_name("lib"); + + rustc() + .input("lib.rs") + .crate_type("staticlib") + .arg("-Zstaticlib-rename-internal-symbols") + .opt() + .run(); + + let data = rfs::read(&lib_name); + check_rename_symbols(&data); + + rfs::remove_file(&lib_name); +} + +fn test_dual_staticlib_linking() { + let liba_name = static_lib_name("liba"); + let libb_name = static_lib_name("libb"); + + rustc() + .input("liba.rs") + .crate_type("staticlib") + .arg("-Zstaticlib-rename-internal-symbols") + .opt() + .run(); + + rustc() + .input("libb.rs") + .crate_type("staticlib") + .arg("-Zstaticlib-rename-internal-symbols") + .opt() + .run(); + + cc().input("dual_main.c") + .input(&liba_name) + .input(&libb_name) + .out_exe("dual_main") + .args(extra_c_flags()) + .run(); + run("dual_main"); +} + +fn check_rename_symbols(archive_data: &[u8]) { + let archive = ArchiveFile::parse(archive_data).unwrap(); + let mut found_exported = HashSet::new(); + let mut found_rs_suffix = false; + + for member in archive.members() { + let member = member.unwrap(); + if !member.name().ends_with(b".rcgu.o") { + continue; + } + let data = member.data(archive_data).unwrap(); + + if let Ok(header) = elf::FileHeader64::::parse(data) { + check_elf_symbols(header, data, &mut found_exported, &mut found_rs_suffix); + } else if let Ok(header) = elf::FileHeader32::::parse(data) { + check_elf_symbols(header, data, &mut found_exported, &mut found_rs_suffix); + } + } + + assert!(found_rs_suffix, "expected to find at least one renamed symbol with .rs suffix"); + for expected in EXPORTED { + assert!( + found_exported.contains(*expected), + "expected to find exported symbol `{expected}` in archive" + ); + } +} + +fn check_elf_symbols>( + header: &Elf, + data: &[u8], + found_exported: &mut HashSet, + found_rs_suffix: &mut bool, +) { + let Ok(endian) = header.endian() else { return }; + let Ok(sections) = header.sections(endian, data) else { return }; + + for (si, section) in sections.enumerate() { + if section.sh_type(endian) != elf::SHT_SYMTAB { + continue; + } + let Ok(symbols) = run_make_support::object::read::elf::SymbolTable::parse( + endian, data, §ions, si, section, + ) else { + continue; + }; + let strtab = symbols.strings(); + + for symbol in symbols.symbols() { + let bind = symbol.st_bind(); + let shndx = symbol.st_shndx(endian); + + if shndx == elf::SHN_UNDEF { + continue; + } + if bind != elf::STB_GLOBAL && bind != elf::STB_WEAK { + continue; + } + + let Ok(name_bytes) = symbol.name(endian, strtab) else { continue }; + let Ok(name) = str::from_utf8(name_bytes) else { continue }; + + if EXPORTED.contains(&name) { + assert!( + !name.contains(".rs"), + "exported symbol `{name}` should not contain .rs suffix" + ); + assert_eq!( + symbol.st_visibility(), + elf::STV_DEFAULT, + "exported symbol `{name}` should be STV_DEFAULT" + ); + found_exported.insert(name.to_string()); + } else { + assert!( + name.contains(".rs"), + "internal symbol `{name}` should contain .rs suffix after rename" + ); + *found_rs_suffix = true; + } + } + } +} diff --git a/tests/ui/linking/staticlib-rename-internal-symbols-wrong-crate-type.rs b/tests/ui/linking/staticlib-rename-internal-symbols-wrong-crate-type.rs new file mode 100644 index 0000000000000..684bdbda6969b --- /dev/null +++ b/tests/ui/linking/staticlib-rename-internal-symbols-wrong-crate-type.rs @@ -0,0 +1,8 @@ +//@ check-pass +//@ compile-flags: -Zstaticlib-rename-internal-symbols --crate-type bin + +#![feature(no_core)] +#![no_core] +#![no_main] + +//~? WARN has no effect without `--crate-type staticlib` diff --git a/tests/ui/linking/staticlib-rename-internal-symbols-wrong-crate-type.stderr b/tests/ui/linking/staticlib-rename-internal-symbols-wrong-crate-type.stderr new file mode 100644 index 0000000000000..d4095ede81a34 --- /dev/null +++ b/tests/ui/linking/staticlib-rename-internal-symbols-wrong-crate-type.stderr @@ -0,0 +1,2 @@ +warning: -Zstaticlib-rename-internal-symbols has no effect without `--crate-type staticlib` + From ab61ffeecd8fb42ed55aa5e5b55a0276e33dd3a0 Mon Sep 17 00:00:00 2001 From: cezarbbb Date: Sat, 30 May 2026 15:31:35 +0800 Subject: [PATCH 06/14] export symbols: support macos/windows(32/64) Co-authored-by: Jesus Checa <101630491+jchecahi@users.noreply.github.com> --- compiler/rustc_codegen_ssa/src/back/link.rs | 81 +++++++++++++++++-- .../cdylib-export-c-library-symbols/rmake.rs | 40 ++++++--- 2 files changed, 103 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index c527dd95e2db4..3e30a84940607 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -47,7 +47,7 @@ use rustc_session::{Session, filesearch}; use rustc_span::Symbol; use rustc_target::spec::crt_objects::CrtObjects; use rustc_target::spec::{ - BinaryFormat, Cc, CfgAbi, Env, LinkOutputKind, LinkSelfContainedComponents, + Arch, BinaryFormat, Cc, CfgAbi, Env, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault, LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, Os, RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, }; @@ -2346,6 +2346,69 @@ fn add_rpath_args( } } +fn strip_numeric_suffix<'a>(base: &'a str, suffix: impl AsRef, fallback: &'a str) -> &'a str { + if suffix.as_ref().parse::().is_ok() { base } else { fallback } +} + +fn undecorate_c_symbol<'a>( + name: &'a str, + sess: &Session, + kind: SymbolExportKind, +) -> Option<&'a str> { + match sess.target.binary_format { + BinaryFormat::MachO => { + // Mach-O: strip the leading underscore that all external symbols have. + // The Darwin linker's export_symbols will add it back. + name.strip_prefix('_') + } + BinaryFormat::Coff => { + // MSVC C++ mangled names start with '?' and use a completely different + // decorating scheme that includes '@@' as structural delimiters. + // They must not be subjected to C calling-convention undecoration. + if name.starts_with('?') { + return Some(name); + } + Some(match sess.target.arch { + Arch::X86 => { + // COFF 32-bit: strip calling-convention decorations. + if let Some(rest) = name.strip_prefix('@') { + // fastcall: @foo@N -> foo + rest.rsplit_once('@') + .map(|(base, suffix)| strip_numeric_suffix(base, suffix, name)) + .unwrap_or(name) + } else if let Some(stripped) = name.strip_prefix('_') { + if let Some((base, suffix)) = stripped.rsplit_once('@') { + // stdcall: _foo@N -> foo + strip_numeric_suffix(base, suffix, stripped) + } else { + // cdecl: _foo -> foo + stripped + } + } else { + // vectorcall: foo@@N -> foo + name.rsplit_once("@@") + .map(|(base, suffix)| strip_numeric_suffix(base, suffix, name)) + .unwrap_or(name) + } + } + Arch::X86_64 => { + // COFF 64-bit: vectorcall mangling (foo@@N -> foo) also applies on x86_64. + name.rsplit_once("@@") + .map(|(base, suffix)| strip_numeric_suffix(base, suffix, name)) + .unwrap_or(name) + } + Arch::Arm64EC if kind == SymbolExportKind::Text => { + // Arm64EC: `#` prefix distinguishes ARM64EC text symbols from x64 thunks. + name.strip_prefix('#').unwrap_or(name) + } + _ => name, + }) + } + // ELF: no decoration + _ => Some(name), + } +} + fn add_c_staticlib_symbols( sess: &Session, lib: &NativeLib, @@ -2387,7 +2450,14 @@ fn add_c_staticlib_symbols( } for symbol in object.symbols() { - if symbol.scope() != object::SymbolScope::Dynamic { + // The `object` crate returns `Dynamic` for ELF/Mach-O global symbols, + // but always returns `Linkage` for COFF external symbols. + // Accept both for COFF (Windows and UEFI). + let scope = symbol.scope(); + if scope != object::SymbolScope::Dynamic + && !(sess.target.binary_format == BinaryFormat::Coff + && scope == object::SymbolScope::Linkage) + { continue; } @@ -2402,9 +2472,10 @@ fn add_c_staticlib_symbols( _ => continue, }; - // FIXME:The symbol mangle rules are slightly different in Windows(32-bit) and Apple. - // Need to be resolved. - out.push((name.to_string(), export_kind)); + let Some(undecorated) = undecorate_c_symbol(name, sess, export_kind) else { + continue; + }; + out.push((undecorated.to_string(), export_kind)); } } diff --git a/tests/run-make/cdylib-export-c-library-symbols/rmake.rs b/tests/run-make/cdylib-export-c-library-symbols/rmake.rs index cb237eceedadf..a2c0796da582e 100644 --- a/tests/run-make/cdylib-export-c-library-symbols/rmake.rs +++ b/tests/run-make/cdylib-export-c-library-symbols/rmake.rs @@ -1,34 +1,48 @@ //@ ignore-nvptx64 //@ ignore-wasm //@ ignore-cross-compile -// FIXME:The symbol mangle rules are slightly different in Windows(32-bit) and Apple. -// Need to be resolved. -//@ ignore-windows -//@ ignore-apple // Reason: the compiled binary is executed -use run_make_support::{build_native_static_lib, cc, dynamic_lib_name, is_darwin, llvm_nm, rustc}; +use run_make_support::{ + cc, dynamic_lib_name, is_darwin, is_windows, llvm_ar, llvm_nm, llvm_readobj, rfs, rustc, + static_lib_name, +}; fn main() { - cc().input("foo.c").arg("-c").out_exe("foo.o").run(); - build_native_static_lib("foo"); + cc().input("foo.c").arg("-c").arg("-fno-lto").out_exe("foo.o").run(); + llvm_ar().obj_to_ar().output_input(&static_lib_name("foo"), "foo.o").run(); rustc().input("foo.rs").arg("-lstatic=foo").crate_type("cdylib").run(); - let out = llvm_nm() - .input(dynamic_lib_name("foo")) - .run() - .assert_stdout_not_contains_regex("T *my_function"); + if is_darwin() { + llvm_nm().input(dynamic_lib_name("foo")).run().assert_stdout_not_contains("T _my_function"); + } else if is_windows() { + llvm_readobj() + .arg("--coff-exports") + .input(dynamic_lib_name("foo")) + .run() + .assert_stdout_not_contains("my_function"); + } else { + llvm_nm().input(dynamic_lib_name("foo")).run().assert_stdout_not_contains("T my_function"); + } + + rfs::remove_file(dynamic_lib_name("foo")); rustc().input("foo_export.rs").arg("-lstatic:+export-symbols=foo").crate_type("cdylib").run(); if is_darwin() { - let out = llvm_nm() + llvm_nm() .input(dynamic_lib_name("foo_export")) .run() .assert_stdout_contains("T _my_function"); + } else if is_windows() { + llvm_readobj() + .arg("--coff-exports") + .input(dynamic_lib_name("foo_export")) + .run() + .assert_stdout_contains("my_function"); } else { - let out = llvm_nm() + llvm_nm() .input(dynamic_lib_name("foo_export")) .run() .assert_stdout_contains("T my_function"); From 52ed05cd97171ca04725484691393b9883ab7de7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 2 Jun 2026 13:03:09 +0200 Subject: [PATCH 07/14] Generalize where bound handling --- .../src/collect/item_bounds.rs | 4 ++ .../src/collect/predicates_of.rs | 16 ++++-- .../src/hir_ty_lowering/bounds.rs | 49 ++++++++++++------- .../src/hir_ty_lowering/dyn_trait.rs | 1 + .../src/hir_ty_lowering/mod.rs | 5 +- 5 files changed, 52 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 4409f2c068eb8..f005a831de2a0 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -58,6 +58,7 @@ fn associated_type_bounds<'tcx>( &mut bounds, item_ty, hir_bounds, + &[], ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, ); @@ -65,6 +66,7 @@ fn associated_type_bounds<'tcx>( &mut bounds, item_ty, hir_bounds, + &[], ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, ); @@ -384,6 +386,7 @@ fn opaque_type_bounds<'tcx>( &mut bounds, item_ty, hir_bounds, + &[], ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, ); @@ -391,6 +394,7 @@ fn opaque_type_bounds<'tcx>( &mut bounds, item_ty, hir_bounds, + &[], ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, ); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index db22b57ad22a6..6e6b6602f3a74 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -200,6 +200,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen &mut bounds, tcx.types.self_param, self_bounds, + &[], ImpliedBoundsContext::TraitDef(def_id), span, ); @@ -207,6 +208,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen &mut bounds, tcx.types.self_param, self_bounds, + &[], ImpliedBoundsContext::TraitDef(def_id), span, ); @@ -239,14 +241,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen &mut bounds, param_ty, &[], - ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates), + hir_generics.predicates, + ImpliedBoundsContext::TyParam(param.def_id), param.span, ); icx.lowerer().add_default_traits( &mut bounds, param_ty, &[], - ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates), + hir_generics.predicates, + ImpliedBoundsContext::TyParam(param.def_id), param.span, ); trace!(?bounds); @@ -692,6 +696,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>( &mut bounds, self_param_ty, superbounds, + &[], ImpliedBoundsContext::TraitDef(trait_def_id), item.span, ); @@ -699,6 +704,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>( &mut bounds, self_param_ty, superbounds, + &[], ImpliedBoundsContext::TraitDef(trait_def_id), item.span, ); @@ -994,14 +1000,16 @@ impl<'tcx> ItemCtxt<'tcx> { &mut bounds, param_ty, &[], - ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates), + hir_generics.predicates, + ImpliedBoundsContext::TyParam(param.def_id), param.span, ); self.lowerer().add_default_traits( &mut bounds, param_ty, &[], - ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates), + hir_generics.predicates, + ImpliedBoundsContext::TyParam(param.def_id), param.span, ); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 9d6c647329aa0..c586eba36f9ec 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -59,7 +59,8 @@ impl CollectedSizednessBounds { fn search_bounds_for<'tcx>( hir_bounds: &'tcx [hir::GenericBound<'tcx>], - context: ImpliedBoundsContext<'tcx>, + where_bounds: &'tcx [hir::WherePredicate<'tcx>], + context: ImpliedBoundsContext, mut f: impl FnMut(&'tcx PolyTraitRef<'tcx>), ) { let mut search_bounds = |hir_bounds: &'tcx [hir::GenericBound<'tcx>]| { @@ -73,8 +74,8 @@ fn search_bounds_for<'tcx>( }; search_bounds(hir_bounds); - if let ImpliedBoundsContext::TyParam(self_ty, where_clause) = context { - for clause in where_clause { + if let ImpliedBoundsContext::TyParam(self_ty) = context { + for clause in where_bounds { if let hir::WherePredicateKind::BoundPredicate(pred) = clause.kind && pred.is_param_bound(self_ty.to_def_id()) { @@ -86,11 +87,12 @@ fn search_bounds_for<'tcx>( fn collect_bounds<'a, 'tcx>( hir_bounds: &'a [hir::GenericBound<'tcx>], - context: ImpliedBoundsContext<'tcx>, + where_bounds: &'tcx [hir::WherePredicate<'tcx>], + context: ImpliedBoundsContext, target_did: DefId, ) -> CollectedBound { let mut collect_into = CollectedBound::default(); - search_bounds_for(hir_bounds, context, |ptr| { + search_bounds_for(hir_bounds, where_bounds, context, |ptr| { if !matches!(ptr.trait_ref.path.res, Res::Def(DefKind::Trait, did) if did == target_did) { return; } @@ -107,17 +109,18 @@ fn collect_bounds<'a, 'tcx>( fn collect_sizedness_bounds<'tcx>( tcx: TyCtxt<'tcx>, hir_bounds: &'tcx [hir::GenericBound<'tcx>], - context: ImpliedBoundsContext<'tcx>, + where_bounds: &'tcx [hir::WherePredicate<'tcx>], + context: ImpliedBoundsContext, span: Span, ) -> CollectedSizednessBounds { let sized_did = tcx.require_lang_item(hir::LangItem::Sized, span); - let sized = collect_bounds(hir_bounds, context, sized_did); + let sized = collect_bounds(hir_bounds, where_bounds, context, sized_did); let meta_sized_did = tcx.require_lang_item(hir::LangItem::MetaSized, span); - let meta_sized = collect_bounds(hir_bounds, context, meta_sized_did); + let meta_sized = collect_bounds(hir_bounds, where_bounds, context, meta_sized_did); let pointee_sized_did = tcx.require_lang_item(hir::LangItem::PointeeSized, span); - let pointee_sized = collect_bounds(hir_bounds, context, pointee_sized_did); + let pointee_sized = collect_bounds(hir_bounds, where_bounds, context, pointee_sized_did); CollectedSizednessBounds { sized, meta_sized, pointee_sized } } @@ -150,7 +153,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, self_ty: Ty<'tcx>, hir_bounds: &'tcx [hir::GenericBound<'tcx>], - context: ImpliedBoundsContext<'tcx>, + where_bounds: &'tcx [hir::WherePredicate<'tcx>], + context: ImpliedBoundsContext, span: Span, ) { let tcx = self.tcx(); @@ -181,7 +185,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - let collected = collect_sizedness_bounds(tcx, hir_bounds, context, span); + let collected = collect_sizedness_bounds(tcx, hir_bounds, where_bounds, context, span); if (collected.sized.maybe || collected.sized.negative) && !collected.sized.positive && !collected.meta_sized.any() @@ -213,11 +217,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, self_ty: Ty<'tcx>, hir_bounds: &[hir::GenericBound<'tcx>], - context: ImpliedBoundsContext<'tcx>, + where_bounds: &'tcx [hir::WherePredicate<'tcx>], + context: ImpliedBoundsContext, span: Span, ) { self.tcx().default_traits().iter().for_each(|default_trait| { - self.add_default_trait(*default_trait, bounds, self_ty, hir_bounds, context, span); + self.add_default_trait( + *default_trait, + bounds, + self_ty, + hir_bounds, + where_bounds, + context, + span, + ); }); } @@ -230,7 +243,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, self_ty: Ty<'tcx>, hir_bounds: &[hir::GenericBound<'tcx>], - context: ImpliedBoundsContext<'tcx>, + where_bounds: &'tcx [hir::WherePredicate<'tcx>], + context: ImpliedBoundsContext, span: Span, ) { let tcx = self.tcx(); @@ -244,7 +258,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } if let Some(trait_did) = tcx.lang_items().get(trait_) - && self.should_add_default_traits(trait_did, hir_bounds, context) + && self.should_add_default_traits(trait_did, hir_bounds, where_bounds, context) { add_trait_bound(tcx, bounds, self_ty, trait_did, span); } @@ -255,9 +269,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, trait_def_id: DefId, hir_bounds: &'a [hir::GenericBound<'tcx>], - context: ImpliedBoundsContext<'tcx>, + where_bounds: &'tcx [hir::WherePredicate<'tcx>], + context: ImpliedBoundsContext, ) -> bool { - let collected = collect_bounds(hir_bounds, context, trait_def_id); + let collected = collect_bounds(hir_bounds, where_bounds, context, trait_def_id); !find_attr!(self.tcx(), crate, RustcNoImplicitBounds) && !collected.any() } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index 761af258822dd..c6edd30cd63de 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -83,6 +83,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .iter() .map(|&trait_ref| hir::GenericBound::Trait(trait_ref)) .collect::>(), + &[], ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, ); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 7909fdbf2365e..fbf184e17f5ce 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -59,12 +59,12 @@ use crate::{NoVariantNamed, check_c_variadic_abi}; /// The context in which an implied bound is being added to a item being lowered (i.e. a sizedness /// trait or a default trait) #[derive(Clone, Copy)] -pub(crate) enum ImpliedBoundsContext<'tcx> { +pub(crate) enum ImpliedBoundsContext { /// An implied bound is added to a trait definition (i.e. a new supertrait), used when adding /// a default `MetaSized` supertrait TraitDef(LocalDefId), /// An implied bound is added to a type parameter - TyParam(LocalDefId, &'tcx [hir::WherePredicate<'tcx>]), + TyParam(LocalDefId), /// An implied bound being added in any other context AssociatedTypeOrImplTrait, } @@ -3093,6 +3093,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &mut bounds, self_ty, hir_bounds, + &[], ImpliedBoundsContext::AssociatedTypeOrImplTrait, hir_ty.span, ); From 9abb8acdc014dbfa107df0a871d0d48878b34977 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 2 Jun 2026 10:28:51 +0200 Subject: [PATCH 08/14] Exhaustively match on `DesugaringKind` --- compiler/rustc_span/src/hygiene.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 1c742052783cd..a2537939ff8ad 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -928,7 +928,17 @@ impl SyntaxContext { | DesugaringKind::Async | DesugaringKind::Await, ) => false, - ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" + ExpnKind::AstPass(_) + | ExpnKind::Desugaring( + DesugaringKind::BoundModifier + | DesugaringKind::QuestionMark + | DesugaringKind::TryBlock + | DesugaringKind::Contract + | DesugaringKind::RangeExpr + | DesugaringKind::PatTyRange + | DesugaringKind::FormatLiteral { .. } + | DesugaringKind::YeetExpr, + ) => true, // well, it's "external" ExpnKind::Macro(MacroKind::Bang, _) => { // Dummy span for the `def_site` means it's an external macro. expn_data.def_site.is_dummy() || sm.is_imported(expn_data.def_site) From d3c8318ff26f9ca944cf64f474e5020aa4c6b759 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 2 Jun 2026 10:16:10 +0200 Subject: [PATCH 09/14] Add expansion info to default bounds --- .../rustc_hir_analysis/src/check/check.rs | 6 ++-- .../src/hir_ty_lowering/bounds.rs | 34 +++++++++++++------ .../rustc_hir_typeck/src/method/suggest.rs | 8 ++--- compiler/rustc_span/src/hygiene.rs | 10 ++++++ .../src/error_reporting/traits/suggestions.rs | 22 +++++------- tests/ui/box/into-boxed-slice-fail.stderr | 4 +-- tests/ui/closures/unsized_value_move.stderr | 2 +- tests/ui/coherence/deep-bad-copy-reason.rs | 1 + .../ui/coherence/deep-bad-copy-reason.stderr | 6 ++-- .../unused-type-param-suggestion.rs | 3 +- .../unused-type-param-suggestion.stderr | 1 - tests/ui/dst/dst-rvalue.stderr | 4 +-- tests/ui/extern/extern-types-unsized.stderr | 8 ++--- .../sized-hierarchy/overflow.current.stderr | 6 ++-- .../enum-unit-variant-trait-bound.stderr | 2 +- 15 files changed, 68 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 917360ab8119e..ba938eb91a4aa 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -24,7 +24,7 @@ use rustc_middle::ty::{ TypeVisitable, TypeVisitableExt, Unnormalized, fold_regions, }; use rustc_session::lint::builtin::UNINHABITED_STATIC; -use rustc_span::sym; +use rustc_span::{DesugaringKind, sym}; use rustc_target::spec::{AbiMap, AbiMapping}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits; @@ -2117,7 +2117,9 @@ fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalD // * check for emptiness to detect lone user-written `?Sized` bounds // * compare the param span to the pred span to detect lone user-written `Sized` bounds let has_explicit_bounds = bounded_params.is_empty() - || (*bounded_params).get(¶m.index).is_some_and(|&&pred_sp| pred_sp != span); + || (*bounded_params).get(¶m.index).is_some_and(|&&pred_sp| { + !pred_sp.is_desugaring(DesugaringKind::DefaultBound { def: param.def_id }) + }); let const_param_help = !has_explicit_bounds; let mut diag = tcx.dcx().create_err(diagnostics::UnusedGenericParameter { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index c586eba36f9ec..e0e2926dfeb83 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -12,7 +12,7 @@ use rustc_middle::ty::{ self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, Upcast, }; -use rustc_span::{ErrorGuaranteed, Ident, Span, kw}; +use rustc_span::{DesugaringKind, ErrorGuaranteed, Ident, Span, kw}; use rustc_trait_selection::traits; use tracing::{debug, instrument}; @@ -25,17 +25,17 @@ use crate::hir_ty_lowering::{ #[derive(Debug, Default)] struct CollectedBound { /// `Trait` - positive: bool, + positive: Option, /// `?Trait` - maybe: bool, + maybe: Option, /// `!Trait` - negative: bool, + negative: Option, } impl CollectedBound { /// Returns `true` if any of `Trait`, `?Trait` or `!Trait` were encountered. fn any(&self) -> bool { - self.positive || self.maybe || self.negative + self.positive.is_some() || self.maybe.is_some() || self.negative.is_some() } } @@ -98,9 +98,9 @@ fn collect_bounds<'a, 'tcx>( } match ptr.modifiers.polarity { - hir::BoundPolarity::Maybe(_) => collect_into.maybe = true, - hir::BoundPolarity::Negative(_) => collect_into.negative = true, - hir::BoundPolarity::Positive => collect_into.positive = true, + hir::BoundPolarity::Maybe(_) => collect_into.maybe = Some(ptr.span), + hir::BoundPolarity::Negative(_) => collect_into.negative = Some(ptr.span), + hir::BoundPolarity::Positive => collect_into.positive = Some(ptr.span), } }); collect_into @@ -184,10 +184,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ImpliedBoundsContext::TyParam(..) | ImpliedBoundsContext::AssociatedTypeOrImplTrait => { } } - let collected = collect_sizedness_bounds(tcx, hir_bounds, where_bounds, context, span); - if (collected.sized.maybe || collected.sized.negative) - && !collected.sized.positive + if let Some(span) = collected.sized.maybe.or(collected.sized.negative) + && collected.sized.positive.is_none() && !collected.meta_sized.any() && !collected.pointee_sized.any() { @@ -195,6 +194,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // other explicit ones) - this can happen for trait aliases as well as bounds. add_trait_bound(tcx, bounds, self_ty, meta_sized_did, span); } else if !collected.any() { + let span = match context { + ImpliedBoundsContext::TyParam(def) => { + self.tcx().with_stable_hashing_context(|hcx| { + span.mark_with_reason( + None, + DesugaringKind::DefaultBound { def: def.into() }, + span.edition(), + hcx, + ) + }) + } + _ => span, + }; match context { ImpliedBoundsContext::TraitDef(..) => { // If there are no explicit sizedness bounds on a trait then add a default diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 8c9f764c0bded..7110a1edbe28b 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -34,8 +34,8 @@ use rustc_middle::ty::print::{ use rustc_middle::ty::{self, GenericArgKind, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::def_id::DefIdSet; use rustc_span::{ - DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, Ident, MacroKind, Span, Symbol, edit_distance, - kw, sym, + DUMMY_SP, DesugaringKind, ErrorGuaranteed, ExpnKind, FileName, Ident, MacroKind, Span, Symbol, + edit_distance, kw, sym, }; use rustc_trait_selection::error_reporting::traits::DefIdOrName; use rustc_trait_selection::infer::InferCtxtExt; @@ -1948,8 +1948,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => false, } }); - for param in generics.params { - if param.span == cause_span && sized_pred { + if sized_pred && let Some(DesugaringKind::DefaultBound { def }) = cause_span.desugaring_kind() { + if let Some(param) = generics.params.iter().find(|p| p.def_id.to_def_id() == def) { let (sp, sugg) = match param.colon_span { Some(sp) => (sp.shrink_to_hi(), " ?Sized +"), None => (param.span.shrink_to_hi(), ": ?Sized"), diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index a2537939ff8ad..9688978f35fec 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -926,6 +926,7 @@ impl SyntaxContext { | DesugaringKind::WhileLoop | DesugaringKind::OpaqueTy | DesugaringKind::Async + | DesugaringKind::DefaultBound { .. } | DesugaringKind::Await, ) => false, ExpnKind::AstPass(_) @@ -1235,6 +1236,13 @@ pub enum DesugaringKind { source: bool, }, RangeExpr, + /// Implicit `Sized` or `MetaSized` bounds. The actual source location points to just the + /// param or item for which the implicit bound was generated. + DefaultBound { + /// The definition this implied bound was added to. + /// So far only supports params, but may be used for super trait bounds and assoc ty bounds in the future + def: DefId, + }, } impl DesugaringKind { @@ -1257,6 +1265,7 @@ impl DesugaringKind { "expression that expanded into a format string literal" } DesugaringKind::RangeExpr => "range expression", + DesugaringKind::DefaultBound { .. } => "implied bound", } } @@ -1277,6 +1286,7 @@ impl DesugaringKind { DesugaringKind::PatTyRange => value == "PatTyRange", DesugaringKind::FormatLiteral { .. } => value == "FormatLiteral", DesugaringKind::RangeExpr => value == "RangeExpr", + DesugaringKind::DefaultBound { .. } => value == "ImpliedBound", } } } 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 0849215c13404..b0f2bafa9eafc 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3598,12 +3598,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { tcx.visible_parent_map(()).get(&def_id).is_some() }; if tcx.is_lang_item(def_id, LangItem::Sized) { - // Check if this is an implicit bound, even in foreign crates. - if tcx - .generics_of(item_def_id) - .own_params - .iter() - .any(|param| tcx.def_span(param.def_id) == span) + if let Some(DesugaringKind::DefaultBound { .. }) = + span.desugaring_kind() { a = "an implicit `Sized`"; this = @@ -4217,12 +4213,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // implicit, mention it as such. if let Some(pred) = predicate.as_trait_clause() && self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) - && self - .tcx - .generics_of(data.impl_or_alias_def_id) - .own_params - .iter() - .any(|param| self.tcx.def_span(param.def_id) == data.span) + && let Some(DesugaringKind::DefaultBound { .. }) = + data.span.desugaring_kind() { spans.push_span_label( data.span, @@ -5912,7 +5904,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let sized_trait = self.tcx.lang_items().sized_trait(); debug!(?generics.params); debug!(?generics.predicates); - let Some(param) = generics.params.iter().find(|param| param.span == span) else { + let Some(DesugaringKind::DefaultBound { def }) = span.desugaring_kind() else { + return; + }; + let Some(param) = generics.params.iter().find(|param| param.def_id.to_def_id() == def) + else { return; }; // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit diff --git a/tests/ui/box/into-boxed-slice-fail.stderr b/tests/ui/box/into-boxed-slice-fail.stderr index f102f666dc276..2d57c4b75e751 100644 --- a/tests/ui/box/into-boxed-slice-fail.stderr +++ b/tests/ui/box/into-boxed-slice-fail.stderr @@ -7,7 +7,7 @@ LL | let _ = Box::into_boxed_slice(boxed_slice); | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `Box::::into_boxed_slice` +note: required by an implicit `Sized` bound in `Box::::into_boxed_slice` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -28,7 +28,7 @@ LL | let _ = Box::into_boxed_slice(boxed_trait); | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `dyn Debug` -note: required by a bound in `Box::::into_boxed_slice` +note: required by an implicit `Sized` bound in `Box::::into_boxed_slice` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time diff --git a/tests/ui/closures/unsized_value_move.stderr b/tests/ui/closures/unsized_value_move.stderr index a9a26a42d1675..4c7273c3a0060 100644 --- a/tests/ui/closures/unsized_value_move.stderr +++ b/tests/ui/closures/unsized_value_move.stderr @@ -7,7 +7,7 @@ LL | (|| Box::new(*(&[0][..])))(); | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[{integer}]` -note: required by a bound in `Box::::new` +note: required by an implicit `Sized` bound in `Box::::new` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression | diff --git a/tests/ui/coherence/deep-bad-copy-reason.rs b/tests/ui/coherence/deep-bad-copy-reason.rs index f1c2698bad5cc..dbc33c009e542 100644 --- a/tests/ui/coherence/deep-bad-copy-reason.rs +++ b/tests/ui/coherence/deep-bad-copy-reason.rs @@ -14,6 +14,7 @@ pub struct ListS { pub struct Interned<'a, T>(&'a T); //~^ NOTE: required by an implicit `Sized` //~| NOTE: required by the implicit `Sized` +//~| NOTE: in this expansion of desugaring of implied bound impl<'a, T> Clone for Interned<'a, T> { fn clone(&self) -> Self { diff --git a/tests/ui/coherence/deep-bad-copy-reason.stderr b/tests/ui/coherence/deep-bad-copy-reason.stderr index 534f26c39c2d4..131796a6c05b0 100644 --- a/tests/ui/coherence/deep-bad-copy-reason.stderr +++ b/tests/ui/coherence/deep-bad-copy-reason.stderr @@ -1,5 +1,5 @@ error[E0204]: the trait `Copy` cannot be implemented for this type - --> $DIR/deep-bad-copy-reason.rs:38:24 + --> $DIR/deep-bad-copy-reason.rs:39:24 | LL | pub struct List<'tcx, T>(Interned<'tcx, ListS>); | ------------------------ this field does not implement `Copy` @@ -8,13 +8,13 @@ LL | impl<'tcx, T> Copy for List<'tcx, T> {} | ^^^^^^^^^^^^^ | note: the `Copy` impl for `Interned<'tcx, ListS>` requires that `OpaqueListContents: Sized` - --> $DIR/deep-bad-copy-reason.rs:26:26 + --> $DIR/deep-bad-copy-reason.rs:27:26 | LL | pub struct List<'tcx, T>(Interned<'tcx, ListS>); | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `OpaqueListContents` cannot be known at compilation time - --> $DIR/deep-bad-copy-reason.rs:26:26 + --> $DIR/deep-bad-copy-reason.rs:27:26 | LL | pub struct List<'tcx, T>(Interned<'tcx, ListS>); | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time diff --git a/tests/ui/const-generics/unused-type-param-suggestion.rs b/tests/ui/const-generics/unused-type-param-suggestion.rs index b8ae4f6b56b70..917dc972eb737 100644 --- a/tests/ui/const-generics/unused-type-param-suggestion.rs +++ b/tests/ui/const-generics/unused-type-param-suggestion.rs @@ -1,4 +1,4 @@ -#![crate_type="lib"] +#![crate_type = "lib"] struct S; //~^ ERROR type parameter `N` is never used @@ -25,4 +25,3 @@ type C = (); type D = (); //~^ ERROR type parameter `N` is never used //~| HELP consider removing `N` -//~| HELP if you intended `N` to be a const parameter diff --git a/tests/ui/const-generics/unused-type-param-suggestion.stderr b/tests/ui/const-generics/unused-type-param-suggestion.stderr index a7aa477ab31a5..67b704d8bc725 100644 --- a/tests/ui/const-generics/unused-type-param-suggestion.stderr +++ b/tests/ui/const-generics/unused-type-param-suggestion.stderr @@ -47,7 +47,6 @@ LL | type D = (); | ^ unused type parameter | = help: consider removing `N` or referring to it in the body of the type alias - = help: if you intended `N` to be a const parameter, use `const N: /* Type */` instead error: aborting due to 6 previous errors diff --git a/tests/ui/dst/dst-rvalue.stderr b/tests/ui/dst/dst-rvalue.stderr index d8c529617f75f..b452311f70a56 100644 --- a/tests/ui/dst/dst-rvalue.stderr +++ b/tests/ui/dst/dst-rvalue.stderr @@ -7,7 +7,7 @@ LL | let _x: Box = Box::new(*"hello world"); | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `str` -note: required by a bound in `Box::::new` +note: required by an implicit `Sized` bound in `Box::::new` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression | @@ -24,7 +24,7 @@ LL | let _x: Box<[isize]> = Box::new(*array); | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[isize]` -note: required by a bound in `Box::::new` +note: required by an implicit `Sized` bound in `Box::::new` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression | diff --git a/tests/ui/extern/extern-types-unsized.stderr b/tests/ui/extern/extern-types-unsized.stderr index 9953e5686632a..6c1d7a7b61b3c 100644 --- a/tests/ui/extern/extern-types-unsized.stderr +++ b/tests/ui/extern/extern-types-unsized.stderr @@ -67,10 +67,10 @@ LL | assert_sized::>(); | = help: the nightly-only, unstable trait `MetaSized` is not implemented for `A` note: required by a bound in `Bar` - --> $DIR/extern-types-unsized.rs:14:12 + --> $DIR/extern-types-unsized.rs:14:15 | LL | struct Bar { - | ^ required by this bound in `Bar` + | ^^^^^^ required by this bound in `Bar` error[E0277]: the size for values of type `A` cannot be known at compilation time --> $DIR/extern-types-unsized.rs:32:20 @@ -102,10 +102,10 @@ LL | assert_sized::>>(); | = help: the nightly-only, unstable trait `MetaSized` is not implemented for `A` note: required by a bound in `Bar` - --> $DIR/extern-types-unsized.rs:14:12 + --> $DIR/extern-types-unsized.rs:14:15 | LL | struct Bar { - | ^ required by this bound in `Bar` + | ^^^^^^ required by this bound in `Bar` error: aborting due to 6 previous errors diff --git a/tests/ui/sized-hierarchy/overflow.current.stderr b/tests/ui/sized-hierarchy/overflow.current.stderr index da58a6d2f7bf6..9853be2a7f8e0 100644 --- a/tests/ui/sized-hierarchy/overflow.current.stderr +++ b/tests/ui/sized-hierarchy/overflow.current.stderr @@ -8,9 +8,9 @@ note: required for `Box` to implement `ParseTokens` --> $DIR/overflow.rs:13:31 | LL | impl ParseTokens for Box { - | - ^^^^^^^^^^^ ^^^^^^ - | | - | unsatisfied trait bound introduced here + | ------ ^^^^^^^^^^^ ^^^^^^ + | | + | unsatisfied trait bound introduced here = note: 1 redundant requirement hidden = note: required for `Box>` to implement `ParseTokens` diff --git a/tests/ui/trait-bounds/enum-unit-variant-trait-bound.stderr b/tests/ui/trait-bounds/enum-unit-variant-trait-bound.stderr index 9a3bcaa0c4aa4..7402129cddeac 100644 --- a/tests/ui/trait-bounds/enum-unit-variant-trait-bound.stderr +++ b/tests/ui/trait-bounds/enum-unit-variant-trait-bound.stderr @@ -5,7 +5,7 @@ LL | let _ = Option::<[u8]>::None; | ^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `None` +note: required by an implicit `Sized` bound in `None` --> $SRC_DIR/core/src/option.rs:LL:COL error: aborting due to 1 previous error From 0981e9c2cb1abecd02b64aed991d09cdb3fd513e Mon Sep 17 00:00:00 2001 From: James Barford-Evans Date: Tue, 16 Jun 2026 10:10:53 +0100 Subject: [PATCH 10/14] Refactor `AliasTy`, `AliasTerm` and `UnevaluatedConst` to use `Alias` --- compiler/rustc_type_ir/src/const_kind.rs | 26 +-------- compiler/rustc_type_ir/src/lib.rs | 2 + compiler/rustc_type_ir/src/predicate.rs | 74 ++++++------------------ compiler/rustc_type_ir/src/ty/alias.rs | 56 ++++++++++++++++++ compiler/rustc_type_ir/src/ty/mod.rs | 3 + compiler/rustc_type_ir/src/ty_kind.rs | 40 +------------ 6 files changed, 85 insertions(+), 116 deletions(-) create mode 100644 compiler/rustc_type_ir/src/ty/alias.rs create mode 100644 compiler/rustc_type_ir/src/ty/mod.rs diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index b3a33b775ad10..2955aff10eb6a 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -9,7 +9,7 @@ use rustc_type_ir_macros::{ GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic, }; -use crate::{self as ty, BoundVarIndexKind, Interner}; +use crate::{self as ty, BoundVarIndexKind, Interner, UnevaluatedConst}; /// Represents a constant in Rust. #[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)] @@ -67,26 +67,6 @@ impl fmt::Debug for ConstKind { } } -/// An unevaluated (potentially generic) constant used in the type-system. -#[derive_where(Clone, Copy, Debug, Hash, PartialEq; I: Interner)] -#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr( - feature = "nightly", - derive(Decodable_NoContext, Encodable_NoContext, StableHash_NoContext) -)] -pub struct UnevaluatedConst { - #[type_foldable(identity)] - #[type_visitable(ignore)] - pub kind: UnevaluatedConstKind, - pub args: I::GenericArgs, - - /// This field exists to prevent the creation of `UnevaluatedConst` without using [`UnevaluatedConst::new`]. - #[derive_where(skip(Debug))] - pub(crate) _use_unevaluated_const_new_instead: (), -} - -impl Eq for UnevaluatedConst {} - impl UnevaluatedConst { #[inline] pub fn new( @@ -103,7 +83,7 @@ impl UnevaluatedConst { }; interner.debug_assert_args_compatible(def_id, args); } - UnevaluatedConst { kind, args, _use_unevaluated_const_new_instead: () } + UnevaluatedConst { kind, args, _use_alias_new_instead: () } } pub fn type_of(self, interner: I) -> ty::Unnormalized { @@ -121,7 +101,7 @@ impl UnevaluatedConst { /// and handled in very similar ways. The documentation for AliasTyKind/etc. may be helpful when /// learning about UnevaluatedConstKind. #[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] -#[derive(GenericTypeVisitable, Lift_Generic)] +#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, StableHash_NoContext) diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index d9906795dfba6..82fa72825d4d4 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -52,6 +52,7 @@ mod pattern; mod predicate; mod predicate_kind; mod region_kind; +mod ty; mod ty_info; mod ty_kind; mod unnormalized; @@ -80,6 +81,7 @@ pub use predicate_kind::*; pub use region_kind::*; pub use rustc_ast_ir::{FloatTy, IntTy, Movability, Mutability, Pinnedness, UintTy}; use rustc_type_ir_macros::GenericTypeVisitable; +pub use ty::{Alias, AliasTerm, AliasTy, UnevaluatedConst}; pub use ty_info::*; pub use ty_kind::*; pub use unnormalized::Unnormalized; diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index a7f7c2fa44358..1a07010442ab4 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -9,9 +9,10 @@ use rustc_type_ir_macros::{ }; use crate::inherent::*; +use crate::ty::AliasTerm; use crate::upcast::{Upcast, UpcastFrom}; use crate::visit::TypeVisitableExt as _; -use crate::{self as ty, AliasTyKind, Interner, UnevaluatedConstKind}; +use crate::{self as ty, Alias, AliasTyKind, Interner, UnevaluatedConstKind}; /// `A: 'region` #[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, A)] @@ -537,7 +538,7 @@ impl ty::Binder> { } #[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] -#[derive(Lift_Generic, TypeVisitable_Generic, GenericTypeVisitable)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic, GenericTypeVisitable)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, StableHash_NoContext) @@ -640,41 +641,6 @@ impl From> for AliasTermKind { } } -/// Represents the unprojected term of a projection goal. -/// -/// * For a projection, this would be `>::N<...>`. -/// * For an inherent projection, this would be `Ty::N<...>`. -/// * For an opaque type, there is no explicit syntax. -#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] -#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr( - feature = "nightly", - derive(Decodable_NoContext, Encodable_NoContext, StableHash_NoContext) -)] -pub struct AliasTerm { - /// The parameters of the associated or opaque item. - /// - /// For a projection, these are the generic parameters for the trait and the - /// GAT parameters, if there are any. - /// - /// For an inherent projection, they consist of the self type and the GAT parameters, - /// if there are any. - /// - /// For RPIT the generic parameters are for the generics of the function, - /// while for TAIT it is used for the generic parameters of the alias. - pub args: I::GenericArgs, - - #[type_foldable(identity)] - #[type_visitable(ignore)] - pub kind: AliasTermKind, - - /// This field exists to prevent the creation of `AliasTerm` without using [`AliasTerm::new_from_args`]. - #[derive_where(skip(Debug))] - _use_alias_term_new_instead: (), -} - -impl Eq for AliasTerm {} - impl AliasTerm { pub fn new_from_args( interner: I, @@ -694,7 +660,7 @@ impl AliasTerm { }; interner.debug_assert_args_compatible(def_id, args); } - AliasTerm { kind, args, _use_alias_term_new_instead: () } + AliasTerm { kind, args, _use_alias_new_instead: () } } pub fn new( @@ -724,7 +690,7 @@ impl AliasTerm { panic!("Cannot turn `{}` into `AliasTy`", kind.descr()) } }; - ty::AliasTy { kind, args: self.args, _use_alias_ty_new_instead: () } + ty::AliasTy { kind, args: self.args, _use_alias_new_instead: () } } pub fn expect_ct(self) -> ty::UnevaluatedConst { @@ -742,7 +708,7 @@ impl AliasTerm { panic!("Cannot turn `{}` into `UnevaluatedConst`", kind.descr()) } }; - ty::UnevaluatedConst { kind, args: self.args, _use_unevaluated_const_new_instead: () } + ty::UnevaluatedConst { kind, args: self.args, _use_alias_new_instead: () } } pub fn to_term(self, interner: I) -> I::Term { @@ -897,21 +863,13 @@ impl AliasTerm { impl From> for AliasTerm { fn from(ty: ty::AliasTy) -> Self { - AliasTerm { - args: ty.args, - kind: AliasTermKind::from(ty.kind), - _use_alias_term_new_instead: (), - } + AliasTerm { args: ty.args, kind: AliasTermKind::from(ty.kind), _use_alias_new_instead: () } } } impl From> for AliasTerm { fn from(ty: ty::UnevaluatedConst) -> Self { - AliasTerm { - args: ty.args, - kind: AliasTermKind::from(ty.kind), - _use_alias_term_new_instead: (), - } + AliasTerm { args: ty.args, kind: AliasTermKind::from(ty.kind), _use_alias_new_instead: () } } } @@ -990,19 +948,17 @@ impl fmt::Debug for ProjectionPredicate { /// Used by the new solver to normalize an alias. This always expects the `term` to /// be an unconstrained inference variable which is used as the output. -#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)] +#[derive_where(Clone, Copy, Hash, Eq, PartialEq; I: Interner, K)] #[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", derive(Decodable_NoContext, Encodable_NoContext, StableHash_NoContext) )] -pub struct NormalizesTo { - pub alias: AliasTerm, +pub struct NormalizesTo> { + pub alias: Alias, pub term: I::Term, } -impl Eq for NormalizesTo {} - impl NormalizesTo { pub fn self_ty(self) -> I::Ty { self.alias.self_ty() @@ -1017,7 +973,13 @@ impl NormalizesTo { } } -impl fmt::Debug for NormalizesTo { +impl fmt::Debug for NormalizesTo +where + // `TypeVisitable_Generic` derived on `NormalizesTo` creates a field-level + // `Alias: TypeVisitable` bound. Since `TypeVisitable: fmt::Debug`, + // that proves `Alias: fmt::Debug`, but not `K: fmt::Debug`. + Alias: fmt::Debug, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "NormalizesTo({:?}, {:?})", self.alias, self.term) } diff --git a/compiler/rustc_type_ir/src/ty/alias.rs b/compiler/rustc_type_ir/src/ty/alias.rs new file mode 100644 index 0000000000000..d61c2f2ca7ff7 --- /dev/null +++ b/compiler/rustc_type_ir/src/ty/alias.rs @@ -0,0 +1,56 @@ +use derive_where::derive_where; +#[cfg(feature = "nightly")] +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, StableHash_NoContext}; +use rustc_type_ir_macros::{ + GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic, +}; + +use crate::predicate::AliasTermKind; +use crate::ty_kind::AliasTyKind; +use crate::{Interner, UnevaluatedConstKind}; + +/// Represents an alias of a type, constant, or other term-like item. +/// +/// * For a projection, this would be `>::N<...>`. +/// * For an inherent projection, this would be `Ty::N<...>`. +/// * For an opaque type, there is no explicit syntax. +#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner, K)] +#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, StableHash_NoContext) +)] +pub struct Alias { + pub kind: K, + + /// The parameters of the associated, opaque, or constant alias. + /// + /// For a projection, these are the generic parameters for the trait and the + /// GAT parameters, if there are any. + /// + /// For an inherent projection, they consist of the self type and the GAT parameters, + /// if there are any. + /// + /// For RPIT the generic parameters are for the generics of the function, + /// while for TAIT it is used for the generic parameters of the alias. + pub args: I::GenericArgs, + + /// This field exists to prevent the creation of `Alias` without using the relevant constructor. + #[derive_where(skip(Debug))] + #[type_visitable(ignore)] + #[type_foldable(identity)] + #[lift(identity)] + pub(crate) _use_alias_new_instead: (), +} + +impl Eq for Alias {} + +impl Alias { + pub fn kind(self, _interner: I) -> K { + self.kind + } +} + +pub type AliasTerm = Alias>; +pub type AliasTy = Alias>; +pub type UnevaluatedConst = Alias>; diff --git a/compiler/rustc_type_ir/src/ty/mod.rs b/compiler/rustc_type_ir/src/ty/mod.rs new file mode 100644 index 0000000000000..fec25193513c0 --- /dev/null +++ b/compiler/rustc_type_ir/src/ty/mod.rs @@ -0,0 +1,3 @@ +mod alias; + +pub use alias::{Alias, AliasTerm, AliasTy, UnevaluatedConst}; diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 784a91424156f..c3d52f4a191ac 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -17,6 +17,7 @@ use rustc_type_ir_macros::{ use self::TyKind::*; pub use self::closure::*; use crate::inherent::*; +use crate::ty::AliasTy; #[cfg(feature = "nightly")] use crate::visit::TypeVisitable; use crate::{self as ty, BoundVarIndexKind, FloatTy, IntTy, Interner, UintTy}; @@ -24,7 +25,7 @@ use crate::{self as ty, BoundVarIndexKind, FloatTy, IntTy, Interner, UintTy}; mod closure; #[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] -#[derive(GenericTypeVisitable, Lift_Generic)] +#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, StableHash_NoContext) @@ -427,45 +428,10 @@ impl fmt::Debug for TyKind { } } -/// Represents the projection of an associated, opaque, or lazy-type-alias type. -/// -/// * For a projection, this would be `>::N<...>`. -/// * For an inherent projection, this would be `Ty::N<...>`. -/// * For an opaque type, there is no explicit syntax. -#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] -#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr( - feature = "nightly", - derive(Decodable_NoContext, Encodable_NoContext, StableHash_NoContext) -)] -pub struct AliasTy { - /// The parameters of the associated or opaque type. - /// - /// For a projection, these are the generic parameters for the trait and the - /// GAT parameters, if there are any. - /// - /// For an inherent projection, they consist of the self type and the GAT parameters, - /// if there are any. - /// - /// For RPIT the generic parameters are for the generics of the function, - /// while for TAIT it is used for the generic parameters of the alias. - pub args: I::GenericArgs, - - #[type_foldable(identity)] - #[type_visitable(ignore)] - pub kind: AliasTyKind, - - /// This field exists to prevent the creation of `AliasTy` without using [`AliasTy::new_from_args`]. - #[derive_where(skip(Debug))] - pub(crate) _use_alias_ty_new_instead: (), -} - -impl Eq for AliasTy {} - impl AliasTy { pub fn new_from_args(interner: I, kind: AliasTyKind, args: I::GenericArgs) -> AliasTy { interner.debug_assert_args_compatible(kind.def_id(), args); - AliasTy { kind, args, _use_alias_ty_new_instead: () } + AliasTy { kind, args, _use_alias_new_instead: () } } pub fn new( From 30e608d1fe58e9b7f466e1ee6178eb27334b3d73 Mon Sep 17 00:00:00 2001 From: James Barford-Evans Date: Tue, 16 Jun 2026 10:11:17 +0100 Subject: [PATCH 11/14] Update tests to reflect Alias changes --- tests/mir-opt/issue_99325.main.built.after.32bit.mir | 2 +- tests/mir-opt/issue_99325.main.built.after.64bit.mir | 2 +- tests/ui/attributes/dump-preds.stderr | 2 +- tests/ui/coherence/occurs-check/associated-type.next.stderr | 4 ++-- tests/ui/coherence/occurs-check/associated-type.old.stderr | 4 ++-- tests/ui/higher-ranked/structually-relate-aliases.stderr | 2 +- tests/ui/offset-of/inside-array-length.stderr | 2 +- tests/ui/traits/next-solver/issue-118950-root-region.stderr | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/mir-opt/issue_99325.main.built.after.32bit.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir index 29fdccf85aa00..14a14ffe377f2 100644 --- a/tests/mir-opt/issue_99325.main.built.after.32bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir @@ -2,7 +2,7 @@ | User Type Annotations | 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { kind: Anon { def_id: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}) }, args: [], .. }], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [Alias { kind: Anon { def_id: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}) }, args: [], .. }], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir index 29fdccf85aa00..14a14ffe377f2 100644 --- a/tests/mir-opt/issue_99325.main.built.after.64bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir @@ -2,7 +2,7 @@ | User Type Annotations | 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { kind: Anon { def_id: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}) }, args: [], .. }], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [Alias { kind: Anon { def_id: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}) }, args: [], .. }], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} | fn main() -> () { let mut _0: (); diff --git a/tests/ui/attributes/dump-preds.stderr b/tests/ui/attributes/dump-preds.stderr index 12d9308431734..b4be76450c6a9 100644 --- a/tests/ui/attributes/dump-preds.stderr +++ b/tests/ui/attributes/dump-preds.stderr @@ -33,7 +33,7 @@ error: rustc_dump_item_bounds LL | type Assoc: std::ops::Deref | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: Binder { value: ProjectionPredicate(AliasTerm { args: [Alias(AliasTy { args: [Self/#0, T/#1, P/#2], kind: Projection { def_id: DefId(..) }, .. })], kind: ProjectionTy { def_id: DefId(..) }, .. }, Term::Ty(())), bound_vars: [] } + = note: Binder { value: ProjectionPredicate(Alias { kind: ProjectionTy { def_id: DefId(..) }, args: [Alias(Alias { kind: Projection { def_id: DefId(..) }, args: [Self/#0, T/#1, P/#2], .. })], .. }, Term::Ty(())), bound_vars: [] } = note: Binder { value: TraitPredicate(<>::Assoc

as std::ops::Deref>, polarity:Positive), bound_vars: [] } = note: Binder { value: TraitPredicate(<>::Assoc

as std::marker::Sized>, polarity:Positive), bound_vars: [] } diff --git a/tests/ui/coherence/occurs-check/associated-type.next.stderr b/tests/ui/coherence/occurs-check/associated-type.next.stderr index 38fb75483f3b3..d68808010bead 100644 --- a/tests/ui/coherence/occurs-check/associated-type.next.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.next.stderr @@ -1,5 +1,5 @@ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], kind: ProjectionTy { def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }, .. } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], kind: ProjectionTy { def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }, .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias { kind: ProjectionTy { def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }, args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias { kind: ProjectionTy { def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }, args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], .. } error[E0119]: conflicting implementations of trait `Overlap fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` --> $DIR/associated-type.rs:32:1 | diff --git a/tests/ui/coherence/occurs-check/associated-type.old.stderr b/tests/ui/coherence/occurs-check/associated-type.old.stderr index 1dac3ecea2687..0472f93cae32f 100644 --- a/tests/ui/coherence/occurs-check/associated-type.old.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.old.stderr @@ -1,5 +1,5 @@ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], kind: ProjectionTy { def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }, .. } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], kind: ProjectionTy { def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }, .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias { kind: ProjectionTy { def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }, args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias { kind: ProjectionTy { def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }, args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], .. } error[E0119]: conflicting implementations of trait `Overlap fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` --> $DIR/associated-type.rs:32:1 | diff --git a/tests/ui/higher-ranked/structually-relate-aliases.stderr b/tests/ui/higher-ranked/structually-relate-aliases.stderr index 4649aac47cdbf..8996bf11b3721 100644 --- a/tests/ui/higher-ranked/structually-relate-aliases.stderr +++ b/tests/ui/higher-ranked/structually-relate-aliases.stderr @@ -1,4 +1,4 @@ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a))], kind: ProjectionTy { def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) }, .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias { kind: ProjectionTy { def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) }, args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a))], .. } error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied --> $DIR/structually-relate-aliases.rs:13:36 | diff --git a/tests/ui/offset-of/inside-array-length.stderr b/tests/ui/offset-of/inside-array-length.stderr index fd47e6c8b6805..4b2a50acf82cb 100644 --- a/tests/ui/offset-of/inside-array-length.stderr +++ b/tests/ui/offset-of/inside-array-length.stderr @@ -37,7 +37,7 @@ LL | fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {} = note: ...which requires caching mir of `foo::{constant#0}` for CTFE... = note: ...which requires elaborating drops for `foo::{constant#0}`... = note: ...which requires borrow-checking `foo::{constant#0}`... - = note: ...which requires normalizing `Binder { value: ConstEvaluatable(UnevaluatedConst { kind: Anon { def_id: DefId(0:7 ~ inside_array_length[07d6]::foo::{constant#0}) }, args: ['^c_1, T/#1], .. }), bound_vars: [] }`... + = note: ...which requires normalizing `Binder { value: ConstEvaluatable(Alias { kind: Anon { def_id: DefId(0:7 ~ inside_array_length[07d6]::foo::{constant#0}) }, args: ['^c_1, T/#1], .. }), bound_vars: [] }`... = note: ...which again requires evaluating type-level constant, completing the cycle = note: cycle used when normalizing `inside_array_length::::foo::{constant#0}` = note: for more information, see and diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr index 32adbb491bee7..eac8b6e11bf1b 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr +++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr @@ -16,7 +16,7 @@ help: this trait has no implementations, consider adding one LL | trait ToUnit<'a> { | ^^^^^^^^^^^^^^^^ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a)), ?1t], kind: FreeTy { def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }, .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias { kind: FreeTy { def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }, args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a)), ?1t], .. } error: aborting due to 2 previous errors Some errors have detailed explanations: E0277, E0425. From 16c1bf45bd2caf7b587a8bfe7c65e696b3b6aebd Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 2 Jun 2026 12:50:22 +0200 Subject: [PATCH 12/14] Add expansion info to assoc type default bounds --- .../src/collect/item_bounds.rs | 8 ++++---- .../src/hir_ty_lowering/bounds.rs | 16 ++++++++++++---- .../src/hir_ty_lowering/dyn_trait.rs | 2 +- .../src/hir_ty_lowering/mod.rs | 9 ++++++--- .../src/error_reporting/traits/suggestions.rs | 10 ++++++---- .../associated-types/issue-63593.current.stderr | 4 ++-- .../ui/associated-types/issue-63593.next.stderr | 4 ++-- tests/ui/drop/dropck-normalize-errors.nll.stderr | 4 ++-- .../drop/dropck-normalize-errors.polonius.stderr | 4 ++-- .../assoc_type_bounds_implicit_sized.stderr | 4 ++-- ...ed-gat-bound-during-assoc-ty-selection.stderr | 4 ++-- .../issue-74816.current.stderr | 4 ++-- .../issue-74816.next.stderr | 4 ++-- .../in-trait/refine-resolution-errors.stderr | 4 ++-- .../suggest-maybe-sized-bound.stderr | 4 ++-- tests/ui/traits/cycle-cache-err-60010.stderr | 4 ++-- ...ned-projection-normalization-2.current.stderr | 4 ++-- ...rained-projection-normalization-2.next.stderr | 4 ++-- ...ained-projection-normalization.current.stderr | 4 ++-- ...strained-projection-normalization.next.stderr | 4 ++-- 20 files changed, 59 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index f005a831de2a0..7603f11b7ebef 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -59,7 +59,7 @@ fn associated_type_bounds<'tcx>( item_ty, hir_bounds, &[], - ImpliedBoundsContext::AssociatedTypeOrImplTrait, + ImpliedBoundsContext::AssociatedType(assoc_item_def_id), span, ); icx.lowerer().add_default_traits( @@ -67,7 +67,7 @@ fn associated_type_bounds<'tcx>( item_ty, hir_bounds, &[], - ImpliedBoundsContext::AssociatedTypeOrImplTrait, + ImpliedBoundsContext::AssociatedType(assoc_item_def_id), span, ); @@ -387,7 +387,7 @@ fn opaque_type_bounds<'tcx>( item_ty, hir_bounds, &[], - ImpliedBoundsContext::AssociatedTypeOrImplTrait, + ImpliedBoundsContext::ImplTrait, span, ); icx.lowerer().add_default_traits( @@ -395,7 +395,7 @@ fn opaque_type_bounds<'tcx>( item_ty, hir_bounds, &[], - ImpliedBoundsContext::AssociatedTypeOrImplTrait, + ImpliedBoundsContext::ImplTrait, span, ); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index e0e2926dfeb83..74d5447b03e80 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -181,8 +181,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return; } } - ImpliedBoundsContext::TyParam(..) | ImpliedBoundsContext::AssociatedTypeOrImplTrait => { - } + ImpliedBoundsContext::TyParam(..) + | ImpliedBoundsContext::AssociatedType(..) + | ImpliedBoundsContext::TraitObject + | ImpliedBoundsContext::TraitAscription + | ImpliedBoundsContext::ImplTrait => {} } let collected = collect_sizedness_bounds(tcx, hir_bounds, where_bounds, context, span); if let Some(span) = collected.sized.maybe.or(collected.sized.negative) @@ -195,7 +198,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { add_trait_bound(tcx, bounds, self_ty, meta_sized_did, span); } else if !collected.any() { let span = match context { - ImpliedBoundsContext::TyParam(def) => { + ImpliedBoundsContext::TraitDef(def) + | ImpliedBoundsContext::TyParam(def) + | ImpliedBoundsContext::AssociatedType(def) => { self.tcx().with_stable_hashing_context(|hcx| { span.mark_with_reason( None, @@ -214,7 +219,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { add_trait_bound(tcx, bounds, self_ty, meta_sized_did, span); } ImpliedBoundsContext::TyParam(..) - | ImpliedBoundsContext::AssociatedTypeOrImplTrait => { + | ImpliedBoundsContext::AssociatedType(..) + | ImpliedBoundsContext::TraitObject + | ImpliedBoundsContext::TraitAscription + | ImpliedBoundsContext::ImplTrait => { // If there are no explicit sizedness bounds on a parameter then add a default // `Sized` bound. let sized_did = tcx.require_lang_item(hir::LangItem::Sized, span); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index c6edd30cd63de..e75e5059bc1dc 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -84,7 +84,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .map(|&trait_ref| hir::GenericBound::Trait(trait_ref)) .collect::>(), &[], - ImpliedBoundsContext::AssociatedTypeOrImplTrait, + ImpliedBoundsContext::TraitObject, span, ); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index fbf184e17f5ce..e029a7b311fb0 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -65,8 +65,11 @@ pub(crate) enum ImpliedBoundsContext { TraitDef(LocalDefId), /// An implied bound is added to a type parameter TyParam(LocalDefId), - /// An implied bound being added in any other context - AssociatedTypeOrImplTrait, + /// Associated type bounds + AssociatedType(LocalDefId), + ImplTrait, + TraitObject, + TraitAscription, } /// A path segment that is semantically allowed to have generic arguments. @@ -3094,7 +3097,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self_ty, hir_bounds, &[], - ImpliedBoundsContext::AssociatedTypeOrImplTrait, + ImpliedBoundsContext::TraitAscription, hir_ty.span, ); self.register_trait_ascription_bounds(bounds, hir_ty.hir_id, hir_ty.span); 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 b0f2bafa9eafc..c3f4a09b2d431 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3571,7 +3571,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } let mut a = "a"; - let mut this = "this bound"; + let mut this = "this bound".to_owned(); let mut note = None; let mut help = None; if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() { @@ -3598,12 +3598,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { tcx.visible_parent_map(()).get(&def_id).is_some() }; if tcx.is_lang_item(def_id, LangItem::Sized) { - if let Some(DesugaringKind::DefaultBound { .. }) = + if let Some(DesugaringKind::DefaultBound { def }) = span.desugaring_kind() { a = "an implicit `Sized`"; - this = - "the implicit `Sized` requirement on this type parameter"; + this = format!( + "the implicit `Sized` requirement on this {}", + tcx.def_kind(def).descr(def) + ); } if let Some(hir::Node::TraitItem(hir::TraitItem { generics, diff --git a/tests/ui/associated-types/issue-63593.current.stderr b/tests/ui/associated-types/issue-63593.current.stderr index 76fdefeb4e521..4fd7489dca019 100644 --- a/tests/ui/associated-types/issue-63593.current.stderr +++ b/tests/ui/associated-types/issue-63593.current.stderr @@ -4,11 +4,11 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation LL | type This = Self; | ^^^^ doesn't have a size known at compile-time | -note: required by a bound in `MyTrait::This` +note: required by an implicit `Sized` bound in `MyTrait::This` --> $DIR/issue-63593.rs:13:5 | LL | type This = Self; - | ^^^^^^^^^^^^^^^^^ required by this bound in `MyTrait::This` + | ^^^^^^^^^^^^^^^^^ required by the implicit `Sized` requirement on this associated type in `MyTrait::This` help: consider further restricting `Self` | LL | trait MyTrait: Sized { diff --git a/tests/ui/associated-types/issue-63593.next.stderr b/tests/ui/associated-types/issue-63593.next.stderr index 76fdefeb4e521..4fd7489dca019 100644 --- a/tests/ui/associated-types/issue-63593.next.stderr +++ b/tests/ui/associated-types/issue-63593.next.stderr @@ -4,11 +4,11 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation LL | type This = Self; | ^^^^ doesn't have a size known at compile-time | -note: required by a bound in `MyTrait::This` +note: required by an implicit `Sized` bound in `MyTrait::This` --> $DIR/issue-63593.rs:13:5 | LL | type This = Self; - | ^^^^^^^^^^^^^^^^^ required by this bound in `MyTrait::This` + | ^^^^^^^^^^^^^^^^^ required by the implicit `Sized` requirement on this associated type in `MyTrait::This` help: consider further restricting `Self` | LL | trait MyTrait: Sized { diff --git a/tests/ui/drop/dropck-normalize-errors.nll.stderr b/tests/ui/drop/dropck-normalize-errors.nll.stderr index 39ec4033eab2f..1766f136ac4d1 100644 --- a/tests/ui/drop/dropck-normalize-errors.nll.stderr +++ b/tests/ui/drop/dropck-normalize-errors.nll.stderr @@ -47,11 +47,11 @@ note: required because it appears within the type `BDecoder` | LL | pub struct BDecoder { | ^^^^^^^^ -note: required by a bound in `Decode::Decoder` +note: required by an implicit `Sized` bound in `Decode::Decoder` --> $DIR/dropck-normalize-errors.rs:8:5 | LL | type Decoder; - | ^^^^^^^^^^^^^ required by this bound in `Decode::Decoder` + | ^^^^^^^^^^^^^ required by the implicit `Sized` requirement on this associated type in `Decode::Decoder` help: consider relaxing the implicit `Sized` restriction | LL | type Decoder: ?Sized; diff --git a/tests/ui/drop/dropck-normalize-errors.polonius.stderr b/tests/ui/drop/dropck-normalize-errors.polonius.stderr index 3d72801b34363..3a08a2268d6bc 100644 --- a/tests/ui/drop/dropck-normalize-errors.polonius.stderr +++ b/tests/ui/drop/dropck-normalize-errors.polonius.stderr @@ -47,11 +47,11 @@ note: required because it appears within the type `BDecoder` | LL | pub struct BDecoder { | ^^^^^^^^ -note: required by a bound in `Decode::Decoder` +note: required by an implicit `Sized` bound in `Decode::Decoder` --> $DIR/dropck-normalize-errors.rs:8:5 | LL | type Decoder; - | ^^^^^^^^^^^^^ required by this bound in `Decode::Decoder` + | ^^^^^^^^^^^^^ required by the implicit `Sized` requirement on this associated type in `Decode::Decoder` help: consider relaxing the implicit `Sized` restriction | LL | type Decoder: ?Sized; diff --git a/tests/ui/dyn-compatibility/assoc_type_bounds_implicit_sized.stderr b/tests/ui/dyn-compatibility/assoc_type_bounds_implicit_sized.stderr index 9bb770ce43199..8092333d6d200 100644 --- a/tests/ui/dyn-compatibility/assoc_type_bounds_implicit_sized.stderr +++ b/tests/ui/dyn-compatibility/assoc_type_bounds_implicit_sized.stderr @@ -5,11 +5,11 @@ LL | type Item = dyn Trait; | ^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Trait + 'static)` -note: required by a bound in `TraitWithAType::Item` +note: required by an implicit `Sized` bound in `TraitWithAType::Item` --> $DIR/assoc_type_bounds_implicit_sized.rs:4:5 | LL | type Item; - | ^^^^^^^^^^ required by this bound in `TraitWithAType::Item` + | ^^^^^^^^^^ required by the implicit `Sized` requirement on this associated type in `TraitWithAType::Item` help: consider relaxing the implicit `Sized` restriction | LL | type Item: ?Sized; diff --git a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr index 674e28829073f..7bef897e032d1 100644 --- a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr +++ b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr @@ -5,11 +5,11 @@ LL | type Pointer = dyn Deref; | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Deref + 'static)` -note: required by a bound in `PointerFamily::Pointer` +note: required by an implicit `Sized` bound in `PointerFamily::Pointer` --> $DIR/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs:4:5 | LL | type Pointer: Deref; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `PointerFamily::Pointer` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by the implicit `Sized` requirement on this associated type in `PointerFamily::Pointer` help: consider relaxing the implicit `Sized` restriction | LL | type Pointer: Deref + ?Sized; diff --git a/tests/ui/generic-associated-types/issue-74816.current.stderr b/tests/ui/generic-associated-types/issue-74816.current.stderr index 335486c6538c1..79aeaa79b4f19 100644 --- a/tests/ui/generic-associated-types/issue-74816.current.stderr +++ b/tests/ui/generic-associated-types/issue-74816.current.stderr @@ -20,11 +20,11 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation LL | type Associated: Trait1 = Self; | ^^^^ doesn't have a size known at compile-time | -note: required by a bound in `Trait2::Associated` +note: required by an implicit `Sized` bound in `Trait2::Associated` --> $DIR/issue-74816.rs:12:5 | LL | type Associated: Trait1 = Self; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait2::Associated` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by the implicit `Sized` requirement on this associated type in `Trait2::Associated` help: consider further restricting `Self` | LL | trait Trait2: Sized { diff --git a/tests/ui/generic-associated-types/issue-74816.next.stderr b/tests/ui/generic-associated-types/issue-74816.next.stderr index 335486c6538c1..79aeaa79b4f19 100644 --- a/tests/ui/generic-associated-types/issue-74816.next.stderr +++ b/tests/ui/generic-associated-types/issue-74816.next.stderr @@ -20,11 +20,11 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation LL | type Associated: Trait1 = Self; | ^^^^ doesn't have a size known at compile-time | -note: required by a bound in `Trait2::Associated` +note: required by an implicit `Sized` bound in `Trait2::Associated` --> $DIR/issue-74816.rs:12:5 | LL | type Associated: Trait1 = Self; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait2::Associated` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by the implicit `Sized` requirement on this associated type in `Trait2::Associated` help: consider further restricting `Self` | LL | trait Trait2: Sized { diff --git a/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr b/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr index af71e52b87d71..8b730d9535d0a 100644 --- a/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr +++ b/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr @@ -13,11 +13,11 @@ LL | LL | type Assoc = T; | ^ doesn't have a size known at compile-time | -note: required by a bound in `Mirror::Assoc` +note: required by an implicit `Sized` bound in `Mirror::Assoc` --> $DIR/refine-resolution-errors.rs:7:5 | LL | type Assoc; - | ^^^^^^^^^^^ required by this bound in `Mirror::Assoc` + | ^^^^^^^^^^^ required by the implicit `Sized` requirement on this associated type in `Mirror::Assoc` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - impl Mirror for () { diff --git a/tests/ui/trait-bounds/suggest-maybe-sized-bound.stderr b/tests/ui/trait-bounds/suggest-maybe-sized-bound.stderr index b459ad47e067a..63d3b01f27a2e 100644 --- a/tests/ui/trait-bounds/suggest-maybe-sized-bound.stderr +++ b/tests/ui/trait-bounds/suggest-maybe-sized-bound.stderr @@ -22,11 +22,11 @@ LL | type P = [u8]; | ^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` -note: required by a bound in `main::Trait::P` +note: required by an implicit `Sized` bound in `main::Trait::P` --> $DIR/suggest-maybe-sized-bound.rs:13:9 | LL | type P; - | ^^^^^^^^^^ required by this bound in `Trait::P` + | ^^^^^^^^^^ required by the implicit `Sized` requirement on this associated type in `Trait::P` help: consider relaxing the implicit `Sized` restriction | LL | type P: ?Sized; diff --git a/tests/ui/traits/cycle-cache-err-60010.stderr b/tests/ui/traits/cycle-cache-err-60010.stderr index 9665d5badf599..605ef34e5d2b8 100644 --- a/tests/ui/traits/cycle-cache-err-60010.stderr +++ b/tests/ui/traits/cycle-cache-err-60010.stderr @@ -80,11 +80,11 @@ note: required because it appears within the type `SalsaStorage` | LL | struct SalsaStorage { | ^^^^^^^^^^^^ -note: required by a bound in `Database::Storage` +note: required by an implicit `Sized` bound in `Database::Storage` --> $DIR/cycle-cache-err-60010.rs:7:5 | LL | type Storage; - | ^^^^^^^^^^^^^ required by this bound in `Database::Storage` + | ^^^^^^^^^^^^^ required by the implicit `Sized` requirement on this associated type in `Database::Storage` help: consider relaxing the implicit `Sized` restriction | LL | type Storage: ?Sized; diff --git a/tests/ui/traits/normalize/unconstrained-projection-normalization-2.current.stderr b/tests/ui/traits/normalize/unconstrained-projection-normalization-2.current.stderr index e8742e7f09902..3ec07397ec148 100644 --- a/tests/ui/traits/normalize/unconstrained-projection-normalization-2.current.stderr +++ b/tests/ui/traits/normalize/unconstrained-projection-normalization-2.current.stderr @@ -22,11 +22,11 @@ LL | LL | type Assoc = T; | ^ doesn't have a size known at compile-time | -note: required by a bound in `Every::Assoc` +note: required by an implicit `Sized` bound in `Every::Assoc` --> $DIR/unconstrained-projection-normalization-2.rs:12:5 | LL | type Assoc; - | ^^^^^^^^^^^ required by this bound in `Every::Assoc` + | ^^^^^^^^^^^ required by the implicit `Sized` requirement on this associated type in `Every::Assoc` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - impl Every for Thing { diff --git a/tests/ui/traits/normalize/unconstrained-projection-normalization-2.next.stderr b/tests/ui/traits/normalize/unconstrained-projection-normalization-2.next.stderr index e8742e7f09902..3ec07397ec148 100644 --- a/tests/ui/traits/normalize/unconstrained-projection-normalization-2.next.stderr +++ b/tests/ui/traits/normalize/unconstrained-projection-normalization-2.next.stderr @@ -22,11 +22,11 @@ LL | LL | type Assoc = T; | ^ doesn't have a size known at compile-time | -note: required by a bound in `Every::Assoc` +note: required by an implicit `Sized` bound in `Every::Assoc` --> $DIR/unconstrained-projection-normalization-2.rs:12:5 | LL | type Assoc; - | ^^^^^^^^^^^ required by this bound in `Every::Assoc` + | ^^^^^^^^^^^ required by the implicit `Sized` requirement on this associated type in `Every::Assoc` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - impl Every for Thing { diff --git a/tests/ui/traits/normalize/unconstrained-projection-normalization.current.stderr b/tests/ui/traits/normalize/unconstrained-projection-normalization.current.stderr index 6e908df0aba2d..73bf568d8aec0 100644 --- a/tests/ui/traits/normalize/unconstrained-projection-normalization.current.stderr +++ b/tests/ui/traits/normalize/unconstrained-projection-normalization.current.stderr @@ -22,11 +22,11 @@ LL | LL | type Assoc = T; | ^ doesn't have a size known at compile-time | -note: required by a bound in `Every::Assoc` +note: required by an implicit `Sized` bound in `Every::Assoc` --> $DIR/unconstrained-projection-normalization.rs:11:5 | LL | type Assoc; - | ^^^^^^^^^^^ required by this bound in `Every::Assoc` + | ^^^^^^^^^^^ required by the implicit `Sized` requirement on this associated type in `Every::Assoc` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - impl Every for Thing { diff --git a/tests/ui/traits/normalize/unconstrained-projection-normalization.next.stderr b/tests/ui/traits/normalize/unconstrained-projection-normalization.next.stderr index 6e908df0aba2d..73bf568d8aec0 100644 --- a/tests/ui/traits/normalize/unconstrained-projection-normalization.next.stderr +++ b/tests/ui/traits/normalize/unconstrained-projection-normalization.next.stderr @@ -22,11 +22,11 @@ LL | LL | type Assoc = T; | ^ doesn't have a size known at compile-time | -note: required by a bound in `Every::Assoc` +note: required by an implicit `Sized` bound in `Every::Assoc` --> $DIR/unconstrained-projection-normalization.rs:11:5 | LL | type Assoc; - | ^^^^^^^^^^^ required by this bound in `Every::Assoc` + | ^^^^^^^^^^^ required by the implicit `Sized` requirement on this associated type in `Every::Assoc` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - impl Every for Thing { From 52b20ab57b0ac6aa9e61cc5dcda0e6686d4fbc03 Mon Sep 17 00:00:00 2001 From: Jamie Hill-Daniel Date: Tue, 16 Jun 2026 12:07:52 +0100 Subject: [PATCH 13/14] doc: Document `-Zlint-rust-version` --- .../src/compiler-flags/lint-rust-version.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/doc/unstable-book/src/compiler-flags/lint-rust-version.md diff --git a/src/doc/unstable-book/src/compiler-flags/lint-rust-version.md b/src/doc/unstable-book/src/compiler-flags/lint-rust-version.md new file mode 100644 index 0000000000000..ecc0e7fba6350 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/lint-rust-version.md @@ -0,0 +1,9 @@ +# `lint-rust-version` + +The tracking issue for this feature is: [#157574](https://github.com/rust-lang/rust/issues/157574). + +------------------------ + +This feature allows you to specify a minimum Rust version for the crate, which will affect lint +emission. If following a lint suggestion would raise the MSRV above the provided value, it should +not be emitted. From 209ea4726e23ff0e190562fdd29e09cf2bdd31e6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Jun 2026 14:06:52 +0000 Subject: [PATCH 14/14] fix(rustc_codegen_ssa): Use cg_operand for Freeze check * fix(rustc_codegen_ssa): Use cg_operand for Freeze check * chore: remove unnecessary comment * test: add test for ssa rval monomorphization issue * fix: move ssa-rval-monomorphization test * tweak comment Co-authored-by: Ralf Jung --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- .../ssa-rval-monomorphization-issue-157922.rs | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/ui/generics/ssa-rval-monomorphization-issue-157922.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index d792e3d126f5d..deb8ca12b059d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -43,7 +43,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // If this is storing a &Freeze reference with a retag, record that it's not // possible to perform writes through the stored pointer. let flags = if let ty::Ref(_, pointee_ty, Mutability::Not) = - operand.ty(self.mir, self.cx.tcx()).kind() + cg_operand.layout.ty.kind() && with_retag.yes() && pointee_ty.is_freeze(self.cx.tcx(), self.cx.typing_env()) { diff --git a/tests/ui/generics/ssa-rval-monomorphization-issue-157922.rs b/tests/ui/generics/ssa-rval-monomorphization-issue-157922.rs new file mode 100644 index 0000000000000..f7ebc58e5400a --- /dev/null +++ b/tests/ui/generics/ssa-rval-monomorphization-issue-157922.rs @@ -0,0 +1,25 @@ +//@ build-pass +// (codegen test) +// +// Ensure that the "freeze" check on stores works correctly in generic functions. +// Regression test for [#157922](https://github.com/rust-lang/rust/issues/157922). + +pub trait Field { + type Value; +} + +pub struct S; + +impl Field for S

{ + type Value = (); +} + +pub struct Foo(F::Value); + +fn f(a: &Foo>) { + let _f = if 1 > 0 { a } else { a }; +} + +pub fn main() { + f(&Foo::>(())); +}