From c957c4e7043169743355066640d4c18d93264b3e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 19 Aug 2025 18:51:08 +0000 Subject: [PATCH 01/10] Account for impossible bounds making seemingly unsatisfyable dyn-to-dyn casts --- compiler/rustc_borrowck/src/type_check/mod.rs | 33 ++++++++++++------- tests/ui/coercion/fake-sized-ptr-cast.rs | 16 +++++++++ 2 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 tests/ui/coercion/fake-sized-ptr-cast.rs diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 0e1dd5c701fe5..7d19b57e40c53 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -34,6 +34,7 @@ use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::source_map::Spanned; use rustc_span::{Span, sym}; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; use tracing::{debug, instrument, trace}; @@ -1457,22 +1458,32 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let ty_from = op.ty(self.body, tcx); let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); + match (cast_ty_from, cast_ty_to) { (Some(CastTy::Ptr(src)), Some(CastTy::Ptr(dst))) => { - let src_tail = self.struct_tail(src.ty, location); - let dst_tail = self.struct_tail(dst.ty, location); - - // This checks (lifetime part of) vtable validity for pointer casts, - // which is irrelevant when there are aren't principal traits on - // both sides (aka only auto traits). - // - // Note that other checks (such as denying `dyn Send` -> `dyn - // Debug`) are in `rustc_hir_typeck`. - if let ty::Dynamic(src_tty, _src_lt, ty::Dyn) = *src_tail.kind() - && let ty::Dynamic(dst_tty, dst_lt, ty::Dyn) = *dst_tail.kind() + if self + .infcx + .type_is_sized_modulo_regions(self.infcx.param_env, dst.ty) + { + // Wide to thin ptr cast. This may even occur in an env with + // impossible predicates, such as `where dyn Trait: Sized`. + // In this case, we don't want to fall into the case below, + // since the types may not actually be equatable, but it's + // fine to perform this operation in an impossible env. + } else if let ty::Dynamic(src_tty, _src_lt, ty::Dyn) = + *self.struct_tail(src.ty, location).kind() + && let ty::Dynamic(dst_tty, dst_lt, ty::Dyn) = + *self.struct_tail(dst.ty, location).kind() && src_tty.principal().is_some() && dst_tty.principal().is_some() { + // This checks (lifetime part of) vtable validity for pointer casts, + // which is irrelevant when there are aren't principal traits on + // both sides (aka only auto traits). + // + // Note that other checks (such as denying `dyn Send` -> `dyn + // Debug`) are in `rustc_hir_typeck`. + // Remove auto traits. // Auto trait checks are handled in `rustc_hir_typeck` as FCW. let src_obj = Ty::new_dynamic( diff --git a/tests/ui/coercion/fake-sized-ptr-cast.rs b/tests/ui/coercion/fake-sized-ptr-cast.rs new file mode 100644 index 0000000000000..4b6bf0eb5168e --- /dev/null +++ b/tests/ui/coercion/fake-sized-ptr-cast.rs @@ -0,0 +1,16 @@ +// Make sure borrowck doesn't ICE because it thinks a pointer cast is a metadata-preserving +// wide-to-wide ptr cast when it's actually (falsely) a wide-to-thin ptr cast due to an +// impossible dyn sized bound. + +//@ check-pass + +trait Trait {} + +fn func<'a>(x: *const (dyn Trait<()> + 'a)) +where + dyn Trait + 'a: Sized, +{ + let _x: *const dyn Trait = x as _; +} + +fn main() {} From e0fb6ebf7ba47eb67642e83186736149d5083e7d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 23 Aug 2025 17:13:03 +0000 Subject: [PATCH 02/10] Nits --- compiler/rustc_borrowck/src/type_check/mod.rs | 143 +++++++++--------- 1 file changed, 72 insertions(+), 71 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 7d19b57e40c53..d661fb6403c91 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1456,78 +1456,79 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } CastKind::PtrToPtr => { let ty_from = op.ty(self.body, tcx); - let cast_ty_from = CastTy::from_ty(ty_from); - let cast_ty_to = CastTy::from_ty(*ty); + let Some(CastTy::Ptr(src)) = CastTy::from_ty(ty_from) else { + unreachable!(); + }; + let Some(CastTy::Ptr(dst)) = CastTy::from_ty(*ty) else { + unreachable!(); + }; - match (cast_ty_from, cast_ty_to) { - (Some(CastTy::Ptr(src)), Some(CastTy::Ptr(dst))) => { - if self - .infcx - .type_is_sized_modulo_regions(self.infcx.param_env, dst.ty) - { - // Wide to thin ptr cast. This may even occur in an env with - // impossible predicates, such as `where dyn Trait: Sized`. - // In this case, we don't want to fall into the case below, - // since the types may not actually be equatable, but it's - // fine to perform this operation in an impossible env. - } else if let ty::Dynamic(src_tty, _src_lt, ty::Dyn) = - *self.struct_tail(src.ty, location).kind() - && let ty::Dynamic(dst_tty, dst_lt, ty::Dyn) = - *self.struct_tail(dst.ty, location).kind() - && src_tty.principal().is_some() - && dst_tty.principal().is_some() - { - // This checks (lifetime part of) vtable validity for pointer casts, - // which is irrelevant when there are aren't principal traits on - // both sides (aka only auto traits). - // - // Note that other checks (such as denying `dyn Send` -> `dyn - // Debug`) are in `rustc_hir_typeck`. - - // Remove auto traits. - // Auto trait checks are handled in `rustc_hir_typeck` as FCW. - let src_obj = Ty::new_dynamic( - tcx, - tcx.mk_poly_existential_predicates( - &src_tty.without_auto_traits().collect::>(), - ), - // FIXME: Once we disallow casting `*const dyn Trait + 'short` - // to `*const dyn Trait + 'long`, then this can just be `src_lt`. - dst_lt, - ty::Dyn, - ); - let dst_obj = Ty::new_dynamic( - tcx, - tcx.mk_poly_existential_predicates( - &dst_tty.without_auto_traits().collect::>(), - ), - dst_lt, - ty::Dyn, - ); - - debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj); - - self.sub_types( - src_obj, - dst_obj, - location.to_locations(), - ConstraintCategory::Cast { - is_implicit_coercion: false, - unsize_to: None, - }, - ) - .unwrap(); - } - } - _ => { - span_mirbug!( - self, - rvalue, - "Invalid PtrToPtr cast {:?} -> {:?}", - ty_from, - ty - ) - } + if self.infcx.type_is_sized_modulo_regions(self.infcx.param_env, dst.ty) { + // Wide to thin ptr cast. This may even occur in an env with + // impossible predicates, such as `where dyn Trait: Sized`. + // In this case, we don't want to fall into the case below, + // since the types may not actually be equatable, but it's + // fine to perform this operation in an impossible env. + let trait_ref = ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::Sized, self.last_span), + [dst.ty], + ); + self.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::Cast { + is_implicit_coercion: true, + unsize_to: None, + }, + ); + } else if let ty::Dynamic(src_tty, _src_lt, ty::Dyn) = + *self.struct_tail(src.ty, location).kind() + && let ty::Dynamic(dst_tty, dst_lt, ty::Dyn) = + *self.struct_tail(dst.ty, location).kind() + && src_tty.principal().is_some() + && dst_tty.principal().is_some() + { + // This checks (lifetime part of) vtable validity for pointer casts, + // which is irrelevant when there are aren't principal traits on + // both sides (aka only auto traits). + // + // Note that other checks (such as denying `dyn Send` -> `dyn + // Debug`) are in `rustc_hir_typeck`. + + // Remove auto traits. + // Auto trait checks are handled in `rustc_hir_typeck` as FCW. + let src_obj = Ty::new_dynamic( + tcx, + tcx.mk_poly_existential_predicates( + &src_tty.without_auto_traits().collect::>(), + ), + // FIXME: Once we disallow casting `*const dyn Trait + 'short` + // to `*const dyn Trait + 'long`, then this can just be `src_lt`. + dst_lt, + ty::Dyn, + ); + let dst_obj = Ty::new_dynamic( + tcx, + tcx.mk_poly_existential_predicates( + &dst_tty.without_auto_traits().collect::>(), + ), + dst_lt, + ty::Dyn, + ); + + debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj); + + self.sub_types( + src_obj, + dst_obj, + location.to_locations(), + ConstraintCategory::Cast { + is_implicit_coercion: false, + unsize_to: None, + }, + ) + .unwrap(); } } CastKind::Transmute => { From 03ab22415a57a488e81414cc08a685cc77e6b72c Mon Sep 17 00:00:00 2001 From: Valdemar Erk Date: Sat, 23 Aug 2025 11:37:53 +0200 Subject: [PATCH 03/10] add span to struct pattern rest (..) --- compiler/rustc_ast/src/ast.rs | 6 +++--- compiler/rustc_ast_lowering/src/expr.rs | 6 +++--- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_ast_lowering/src/pat.rs | 9 +++++---- compiler/rustc_ast_pretty/src/pprust/state.rs | 2 +- compiler/rustc_hir/src/hir.rs | 8 ++++---- compiler/rustc_hir_pretty/src/lib.rs | 4 ++-- compiler/rustc_hir_typeck/src/pat.rs | 12 ++++++++++-- compiler/rustc_parse/src/parser/pat.rs | 2 +- compiler/rustc_passes/src/liveness.rs | 2 +- compiler/rustc_resolve/src/late.rs | 2 +- .../clippy/clippy_lints/src/equatable_if_let.rs | 2 +- src/tools/clippy/clippy_lints/src/manual_let_else.rs | 4 ++-- .../src/matches/rest_pat_in_fully_bound_struct.rs | 2 +- src/tools/clippy/clippy_lints/src/utils/author.rs | 3 ++- src/tools/clippy/clippy_utils/src/lib.rs | 2 +- src/tools/rustfmt/src/patterns.rs | 2 +- 17 files changed, 40 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index de3e0e0c87f5a..802a6fa324984 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -937,7 +937,7 @@ pub enum PatKind { #[derive(Clone, Copy, Encodable, Decodable, Debug, PartialEq, Walkable)] pub enum PatFieldsRest { /// `module::StructName { field, ..}` - Rest, + Rest(Span), /// `module::StructName { field, syntax error }` Recovered(ErrorGuaranteed), /// `module::StructName { field }` @@ -4051,8 +4051,8 @@ mod size_asserts { static_assert_size!(Local, 96); static_assert_size!(MetaItemLit, 40); static_assert_size!(Param, 40); - static_assert_size!(Pat, 72); - static_assert_size!(PatKind, 48); + static_assert_size!(Pat, 80); + static_assert_size!(PatKind, 56); static_assert_size!(Path, 24); static_assert_size!(PathSegment, 24); static_assert_size!(Stmt, 32); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index cbd17d66b7548..3674814b796c2 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1434,10 +1434,10 @@ impl<'hir> LoweringContext<'_, 'hir> { self.dcx().emit_err(FunctionalRecordUpdateDestructuringAssignment { span: e.span, }); - true + Some(self.lower_span(e.span)) } - StructRest::Rest(_) => true, - StructRest::None => false, + StructRest::Rest(span) => Some(self.lower_span(*span)), + StructRest::None => None, }; let struct_pat = hir::PatKind::Struct(qpath, field_pats, fields_omitted); return self.pat_without_dbm(lhs.span, struct_pat); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 70595391b85bc..137207bde1f12 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2508,7 +2508,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fields: &'hir [hir::PatField<'hir>], ) -> &'hir hir::Pat<'hir> { let qpath = hir::QPath::LangItem(lang_item, self.lower_span(span)); - self.pat(span, hir::PatKind::Struct(qpath, fields, false)) + self.pat(span, hir::PatKind::Struct(qpath, fields, None)) } fn pat_ident(&mut self, span: Span, ident: Ident) -> (&'hir hir::Pat<'hir>, HirId) { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index b8f8624787565..ed159f37051c1 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -106,10 +106,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { break hir::PatKind::Struct( qpath, fs, - matches!( - etc, - ast::PatFieldsRest::Rest | ast::PatFieldsRest::Recovered(_) - ), + match etc { + ast::PatFieldsRest::Rest(sp) => Some(self.lower_span(*sp)), + ast::PatFieldsRest::Recovered(_) => Some(Span::default()), + _ => None, + }, ); } PatKind::Tuple(pats) => { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index a056ce3e29d28..41b520b04c993 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1769,7 +1769,7 @@ impl<'a> State<'a> { }, |f| f.pat.span, ); - if let ast::PatFieldsRest::Rest | ast::PatFieldsRest::Recovered(_) = etc { + if let ast::PatFieldsRest::Rest(_) | ast::PatFieldsRest::Recovered(_) = etc { if !fields.is_empty() { self.word_space(","); } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e397c286de289..e3c27c73638c1 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1884,8 +1884,8 @@ pub enum PatKind<'hir> { Binding(BindingMode, HirId, Ident, Option<&'hir Pat<'hir>>), /// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`). - /// The `bool` is `true` in the presence of a `..`. - Struct(QPath<'hir>, &'hir [PatField<'hir>], bool), + /// The `Option` contains the span of a possible `..`. + Struct(QPath<'hir>, &'hir [PatField<'hir>], Option), /// A tuple struct/variant pattern `Variant(x, y, .., z)`. /// If the `..` pattern fragment is present, then `DotDotPos` denotes its position. @@ -4979,8 +4979,8 @@ mod size_asserts { static_assert_size!(ItemKind<'_>, 64); static_assert_size!(LetStmt<'_>, 72); static_assert_size!(Param<'_>, 32); - static_assert_size!(Pat<'_>, 72); - static_assert_size!(PatKind<'_>, 48); + static_assert_size!(Pat<'_>, 80); + static_assert_size!(PatKind<'_>, 56); static_assert_size!(Path<'_>, 40); static_assert_size!(PathSegment<'_>, 48); static_assert_size!(QPath<'_>, 24); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index be5859b57c5e0..52b29e05dcb0e 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1958,12 +1958,12 @@ impl<'a> State<'a> { self.print_qpath(qpath, true); self.nbsp(); self.word("{"); - let empty = fields.is_empty() && !etc; + let empty = fields.is_empty() && etc.is_none(); if !empty { self.space(); } self.commasep_cmnt(Consistent, fields, |s, f| s.print_patfield(f), |f| f.pat.span); - if etc { + if etc.is_some() { if !fields.is_empty() { self.word_space(","); } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 7dc736e5e6b14..f735c0a416099 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -605,7 +605,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, PatKind::Struct(_, fields, has_rest_pat) => match opt_path_res.unwrap() { Ok(ResolvedPat { ty, kind: ResolvedPatKind::Struct { variant } }) => self - .check_pat_struct(pat, fields, has_rest_pat, ty, variant, expected, pat_info), + .check_pat_struct( + pat, + fields, + has_rest_pat.is_some(), + ty, + variant, + expected, + pat_info, + ), Err(guar) => { let ty_err = Ty::new_error(self.tcx, guar); for field in fields { @@ -2428,7 +2436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let len = unmentioned_fields.len(); let (prefix, postfix, sp) = match fields { [] => match &pat.kind { - PatKind::Struct(path, [], false) => { + PatKind::Struct(path, [], None) => { (" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi())) } _ => return err, diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 9754691a0b9ca..c4d30b3d32832 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1516,7 +1516,7 @@ impl<'a> Parser<'a> { || self.check_noexpect(&token::DotDotDot) || self.check_keyword(exp!(Underscore)) { - etc = PatFieldsRest::Rest; + etc = PatFieldsRest::Rest(self.token.span); let mut etc_sp = self.token.span; if first_etc_and_maybe_comma_span.is_none() { if let Some(comma_tok) = diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 801a533c94338..ae16a51bc693c 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1583,7 +1583,7 @@ impl<'tcx> Liveness<'_, 'tcx> { }); let can_remove = match pat.kind { - hir::PatKind::Struct(_, fields, true) => { + hir::PatKind::Struct(_, fields, Some(_)) => { // if all fields are shorthand, remove the struct field, otherwise, mark with _ as prefix fields.iter().all(|f| f.is_shorthand) } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 679e663f88614..84108f0b8663d 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3922,7 +3922,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { fn record_patterns_with_skipped_bindings(&mut self, pat: &Pat, rest: &ast::PatFieldsRest) { match rest { - ast::PatFieldsRest::Rest | ast::PatFieldsRest::Recovered(_) => { + ast::PatFieldsRest::Rest(_) | ast::PatFieldsRest::Recovered(_) => { // Record that the pattern doesn't introduce all the bindings it could. if let Some(partial_res) = self.r.partial_res_map.get(&pat.id) && let Some(res) = partial_res.full_res() diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index 72f5eaf8a4bcc..c3fc09343dbfe 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -53,7 +53,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { | PatKind::Never | PatKind::Or(_) | PatKind::Err(_) => false, - PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), + PatKind::Struct(_, a, etc) => etc.is_none() && a.iter().all(|x| unary_pattern(x.pat)), PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a), PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x), PatKind::Expr(_) => true, diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index 5a7967bbf9468..2705ef20b795d 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -287,7 +287,7 @@ fn replace_in_pattern( } return or_pat; }, - PatKind::Struct(path, fields, has_dot_dot) => { + PatKind::Struct(path, fields, dot_dot) => { let fields = fields .iter() .map(|fld| { @@ -311,7 +311,7 @@ fn replace_in_pattern( .collect::>(); let fields_string = fields.join(", "); - let dot_dot_str = if has_dot_dot { " .." } else { "" }; + let dot_dot_str = if dot_dot.is_some() { " .." } else { "" }; let (sn_pth, _) = snippet_with_context(cx, path.span(), span.ctxt(), "", app); return format!("{sn_pth} {{ {fields_string}{dot_dot_str} }}"); }, diff --git a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs index 2154cd5b24a54..ae09c2e87d6b7 100644 --- a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs +++ b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs @@ -7,7 +7,7 @@ use super::REST_PAT_IN_FULLY_BOUND_STRUCTS; pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) { if !pat.span.from_expansion() - && let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind + && let PatKind::Struct(QPath::Resolved(_, path), fields, Some(_)) = pat.kind && let Some(def_id) = path.res.opt_def_id() && let ty = cx.tcx.type_of(def_id).instantiate_identity() && let ty::Adt(def, _) = ty.kind() diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 2113cb92137eb..ece29362a39f9 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -754,7 +754,8 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.ident(name); sub.if_some(|p| self.pat(p)); }, - PatKind::Struct(ref qpath, fields, ignore) => { + PatKind::Struct(ref qpath, fields, etc) => { + let ignore = etc.is_some(); bind!(self, qpath, fields); kind!("Struct(ref {qpath}, {fields}, {ignore})"); self.qpath(qpath, pat); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 8533fa8554199..011c9b2f931ae 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -2011,7 +2011,7 @@ pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr< false } }, - (PatKind::Struct(pat_ident, field_pats, false), ExprKind::Struct(ident, fields, hir::StructTailExpr::None)) + (PatKind::Struct(pat_ident, field_pats, None), ExprKind::Struct(ident, fields, hir::StructTailExpr::None)) if field_pats.len() == fields.len() => { // check ident diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index d212ecf392a7f..848bd0766e786 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -303,7 +303,7 @@ impl Rewrite for Pat { qself, path, fields, - rest == ast::PatFieldsRest::Rest, + matches!(rest, ast::PatFieldsRest::Rest(_)), self.span, context, shape, From 4e4325c47701081dab1a32a7c9217f80ae5284c6 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Sat, 23 Aug 2025 19:36:19 +0000 Subject: [PATCH 04/10] remove deprecated Error::description in impls --- compiler/rustc_thread_pool/src/lib.rs | 15 ++----- library/alloc/src/boxed.rs | 5 --- library/alloc/src/boxed/convert.rs | 7 +-- .../alloc/src/collections/btree/map/entry.rs | 4 -- library/alloc/src/ffi/c_str.rs | 21 +-------- library/alloc/src/string.rs | 14 +----- library/alloc/src/sync.rs | 5 --- library/core/src/array/mod.rs | 10 +---- library/core/src/char/convert.rs | 17 +++---- library/core/src/char/decode.rs | 7 +-- library/core/src/convert/mod.rs | 6 +-- library/core/src/error.rs | 33 ++------------ library/core/src/net/parser.rs | 15 +++---- library/core/src/num/dec2flt/mod.rs | 17 +++---- library/core/src/num/error.rs | 25 +++-------- library/core/src/str/error.rs | 14 +----- library/core/src/time.rs | 17 +++---- library/std/src/collections/hash/map.rs | 7 +-- library/std/src/env.rs | 10 +---- library/std/src/io/buffered/bufwriter.rs | 12 +---- library/std/src/io/buffered/mod.rs | 7 +-- library/std/src/io/error.rs | 9 ---- library/std/src/path.rs | 10 +---- library/std/src/sync/mpsc.rs | 44 +++---------------- library/std/src/sync/poison.rs | 18 +------- library/std/src/sys/net/connection/sgx.rs | 7 +-- library/std/src/sys/pal/hermit/os.rs | 8 +--- library/std/src/sys/pal/sgx/mod.rs | 3 +- library/std/src/sys/pal/sgx/os.rs | 17 +++---- library/std/src/sys/pal/solid/os.rs | 8 +--- library/std/src/sys/pal/teeos/os.rs | 8 +--- library/std/src/sys/pal/uefi/os.rs | 3 +- library/std/src/sys/pal/unix/os.rs | 8 +--- library/std/src/sys/pal/unsupported/os.rs | 8 +--- library/std/src/sys/pal/wasi/os.rs | 8 +--- library/std/src/sys/pal/windows/os.rs | 8 +--- library/std/src/sys/pal/xous/os.rs | 8 +--- library/std/src/sys/pal/zkvm/os.rs | 8 +--- library/std/src/time.rs | 7 +-- tests/ui/resolve/issue-102946.rs | 1 - .../issue-87455-static-lifetime-ice.rs | 6 +-- 41 files changed, 83 insertions(+), 382 deletions(-) diff --git a/compiler/rustc_thread_pool/src/lib.rs b/compiler/rustc_thread_pool/src/lib.rs index 34252d919e38e..7ce7fbc27eabe 100644 --- a/compiler/rustc_thread_pool/src/lib.rs +++ b/compiler/rustc_thread_pool/src/lib.rs @@ -787,18 +787,7 @@ impl ThreadPoolBuildError { } } -const GLOBAL_POOL_ALREADY_INITIALIZED: &str = - "The global thread pool has already been initialized."; - impl Error for ThreadPoolBuildError { - #[allow(deprecated)] - fn description(&self) -> &str { - match self.kind { - ErrorKind::GlobalPoolAlreadyInitialized => GLOBAL_POOL_ALREADY_INITIALIZED, - ErrorKind::IOError(ref e) => e.description(), - } - } - fn source(&self) -> Option<&(dyn Error + 'static)> { match &self.kind { ErrorKind::GlobalPoolAlreadyInitialized => None, @@ -810,7 +799,9 @@ impl Error for ThreadPoolBuildError { impl fmt::Display for ThreadPoolBuildError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.kind { - ErrorKind::GlobalPoolAlreadyInitialized => GLOBAL_POOL_ALREADY_INITIALIZED.fmt(f), + ErrorKind::GlobalPoolAlreadyInitialized => { + "The global thread pool has already been initialized.".fmt(f) + } ErrorKind::IOError(e) => e.fmt(f), } } diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index fa12d379c8cae..98c9f6b51ab86 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -2128,11 +2128,6 @@ impl Future for Box { #[stable(feature = "box_error", since = "1.8.0")] impl Error for Box { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - Error::description(&**self) - } - #[allow(deprecated)] fn cause(&self) -> Option<&dyn Error> { Error::cause(&**self) diff --git a/library/alloc/src/boxed/convert.rs b/library/alloc/src/boxed/convert.rs index 8062658020239..45c46fb526365 100644 --- a/library/alloc/src/boxed/convert.rs +++ b/library/alloc/src/boxed/convert.rs @@ -608,12 +608,7 @@ impl<'a> From for Box { fn from(err: String) -> Box { struct StringError(String); - impl Error for StringError { - #[allow(deprecated)] - fn description(&self) -> &str { - &self.0 - } - } + impl Error for StringError {} impl fmt::Display for StringError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index ea8fa363c3805..ec9b774c30877 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -136,10 +136,6 @@ impl<'a, K: Debug + Ord, V: Debug, A: Allocator + Clone> fmt::Display impl<'a, K: core::fmt::Debug + Ord, V: core::fmt::Debug> core::error::Error for crate::collections::btree_map::OccupiedError<'a, K, V> { - #[allow(deprecated)] - fn description(&self) -> &str { - "key already exists" - } } impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> { diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index fe6c89a30949d..b0c8c4b1ca4a7 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -1061,17 +1061,10 @@ impl IntoStringError { } } -impl IntoStringError { - fn description(&self) -> &str { - "C string contained non-utf8 bytes" - } -} - #[stable(feature = "cstring_into", since = "1.7.0")] impl fmt::Display for IntoStringError { - #[allow(deprecated, deprecated_in_future)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.description().fmt(f) + "C string contained non-utf8 bytes".fmt(f) } } @@ -1291,23 +1284,13 @@ impl PartialEq for Cow<'_, CStr> { } #[stable(feature = "rust1", since = "1.0.0")] -impl core::error::Error for NulError { - #[allow(deprecated)] - fn description(&self) -> &str { - "nul byte found in data" - } -} +impl core::error::Error for NulError {} #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] impl core::error::Error for FromVecWithNulError {} #[stable(feature = "cstring_into", since = "1.7.0")] impl core::error::Error for IntoStringError { - #[allow(deprecated)] - fn description(&self) -> &str { - "C string contained non-utf8 bytes" - } - fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { Some(&self.error) } diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 9eacbf00e4233..11fd4346ff504 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2285,20 +2285,10 @@ impl fmt::Display for FromUtf16Error { } #[stable(feature = "rust1", since = "1.0.0")] -impl Error for FromUtf8Error { - #[allow(deprecated)] - fn description(&self) -> &str { - "invalid utf-8" - } -} +impl Error for FromUtf8Error {} #[stable(feature = "rust1", since = "1.0.0")] -impl Error for FromUtf16Error { - #[allow(deprecated)] - fn description(&self) -> &str { - "invalid utf-16" - } -} +impl Error for FromUtf16Error {} #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 29caa7bc5393c..a21b6880674c6 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -4113,11 +4113,6 @@ impl Drop for UniqueArcUninit { #[stable(feature = "arc_error", since = "1.52.0")] impl core::error::Error for Arc { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - core::error::Error::description(&**self) - } - #[allow(deprecated)] fn cause(&self) -> Option<&dyn core::error::Error> { core::error::Error::cause(&**self) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index bb75ec74c8177..835ee57ce230b 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -184,18 +184,12 @@ pub struct TryFromSliceError(()); impl fmt::Display for TryFromSliceError { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[allow(deprecated)] - self.description().fmt(f) + "could not convert slice to array".fmt(f) } } #[stable(feature = "try_from", since = "1.34.0")] -impl Error for TryFromSliceError { - #[allow(deprecated)] - fn description(&self) -> &str { - "could not convert slice to array" - } -} +impl Error for TryFromSliceError {} #[stable(feature = "try_from_slice_error", since = "1.36.0")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs index 23061cb663bc6..cf5a91bf8ddb5 100644 --- a/library/core/src/char/convert.rs +++ b/library/core/src/char/convert.rs @@ -193,21 +193,16 @@ enum CharErrorKind { } #[stable(feature = "char_from_str", since = "1.20.0")] -impl Error for ParseCharError { - #[allow(deprecated)] - fn description(&self) -> &str { - match self.kind { - CharErrorKind::EmptyString => "cannot parse char from empty string", - CharErrorKind::TooManyChars => "too many characters in string", - } - } -} +impl Error for ParseCharError {} #[stable(feature = "char_from_str", since = "1.20.0")] impl fmt::Display for ParseCharError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[allow(deprecated)] - self.description().fmt(f) + match self.kind { + CharErrorKind::EmptyString => "cannot parse char from empty string", + CharErrorKind::TooManyChars => "too many characters in string", + } + .fmt(f) } } diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs index 23319fbe5ddc4..d7c5f45ae4ed7 100644 --- a/library/core/src/char/decode.rs +++ b/library/core/src/char/decode.rs @@ -126,9 +126,4 @@ impl fmt::Display for DecodeUtf16Error { } #[stable(feature = "decode_utf16", since = "1.9.0")] -impl Error for DecodeUtf16Error { - #[allow(deprecated)] - fn description(&self) -> &str { - "unpaired surrogate found" - } -} +impl Error for DecodeUtf16Error {} diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 0c3034c3d4cf2..a0a7b7928d16c 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -958,11 +958,7 @@ impl fmt::Display for Infallible { } #[stable(feature = "str_parse_error2", since = "1.8.0")] -impl Error for Infallible { - fn description(&self) -> &str { - match *self {} - } -} +impl Error for Infallible {} #[stable(feature = "convert_infallible", since = "1.34.0")] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 88e633c9eef3f..92b3c83d1bf34 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -1042,11 +1042,6 @@ impl<'a> crate::iter::FusedIterator for Source<'a> {} #[stable(feature = "error_by_ref", since = "1.51.0")] impl<'a, T: Error + ?Sized> Error for &'a T { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - Error::description(&**self) - } - #[allow(deprecated)] fn cause(&self) -> Option<&dyn Error> { Error::cause(&**self) @@ -1062,36 +1057,16 @@ impl<'a, T: Error + ?Sized> Error for &'a T { } #[stable(feature = "fmt_error", since = "1.11.0")] -impl Error for crate::fmt::Error { - #[allow(deprecated)] - fn description(&self) -> &str { - "an error occurred when formatting an argument" - } -} +impl Error for crate::fmt::Error {} #[stable(feature = "try_borrow", since = "1.13.0")] -impl Error for crate::cell::BorrowError { - #[allow(deprecated)] - fn description(&self) -> &str { - "already mutably borrowed" - } -} +impl Error for crate::cell::BorrowError {} #[stable(feature = "try_borrow", since = "1.13.0")] -impl Error for crate::cell::BorrowMutError { - #[allow(deprecated)] - fn description(&self) -> &str { - "already borrowed" - } -} +impl Error for crate::cell::BorrowMutError {} #[stable(feature = "try_from", since = "1.34.0")] -impl Error for crate::char::CharTryFromError { - #[allow(deprecated)] - fn description(&self) -> &str { - "converted integer out of range for `char`" - } -} +impl Error for crate::char::CharTryFromError {} #[stable(feature = "duration_checked_float", since = "1.66.0")] impl Error for crate::time::TryFromFloatSecsError {} diff --git a/library/core/src/net/parser.rs b/library/core/src/net/parser.rs index 73230f6ee5b03..3aab24a90d817 100644 --- a/library/core/src/net/parser.rs +++ b/library/core/src/net/parser.rs @@ -497,16 +497,7 @@ pub struct AddrParseError(AddrKind); #[stable(feature = "addr_parse_error_error", since = "1.4.0")] impl fmt::Display for AddrParseError { - #[allow(deprecated, deprecated_in_future)] - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.write_str(self.description()) - } -} - -#[stable(feature = "addr_parse_error_error", since = "1.4.0")] -impl Error for AddrParseError { - #[allow(deprecated)] - fn description(&self) -> &str { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 { AddrKind::Ip => "invalid IP address syntax", AddrKind::Ipv4 => "invalid IPv4 address syntax", @@ -515,5 +506,9 @@ impl Error for AddrParseError { AddrKind::SocketV4 => "invalid IPv4 socket address syntax", AddrKind::SocketV6 => "invalid IPv6 socket address syntax", } + .fmt(f) } } + +#[stable(feature = "addr_parse_error_error", since = "1.4.0")] +impl Error for AddrParseError {} diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index 3118a6e5ca62e..dd4eccd24de03 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -219,21 +219,16 @@ enum FloatErrorKind { } #[stable(feature = "rust1", since = "1.0.0")] -impl Error for ParseFloatError { - #[allow(deprecated)] - fn description(&self) -> &str { - match self.kind { - FloatErrorKind::Empty => "cannot parse float from empty string", - FloatErrorKind::Invalid => "invalid float literal", - } - } -} +impl Error for ParseFloatError {} #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for ParseFloatError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[allow(deprecated)] - self.description().fmt(f) + match self.kind { + FloatErrorKind::Empty => "cannot parse float from empty string", + FloatErrorKind::Invalid => "invalid float literal", + } + .fmt(f) } } diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index cfedd465cab0b..faa52329827c1 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -11,19 +11,13 @@ pub struct TryFromIntError(pub(crate) ()); #[stable(feature = "try_from", since = "1.34.0")] impl fmt::Display for TryFromIntError { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - #[allow(deprecated)] - self.description().fmt(fmt) + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "out of range integral type conversion attempted".fmt(f) } } #[stable(feature = "try_from", since = "1.34.0")] -impl Error for TryFromIntError { - #[allow(deprecated)] - fn description(&self) -> &str { - "out of range integral type conversion attempted" - } -} +impl Error for TryFromIntError {} #[stable(feature = "try_from", since = "1.34.0")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] @@ -128,15 +122,6 @@ impl ParseIntError { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for ParseIntError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[allow(deprecated)] - self.description().fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for ParseIntError { - #[allow(deprecated)] - fn description(&self) -> &str { match self.kind { IntErrorKind::Empty => "cannot parse integer from empty string", IntErrorKind::InvalidDigit => "invalid digit found in string", @@ -144,5 +129,9 @@ impl Error for ParseIntError { IntErrorKind::NegOverflow => "number too small to fit in target type", IntErrorKind::Zero => "number would be zero for non-zero type", } + .fmt(f) } } + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for ParseIntError {} diff --git a/library/core/src/str/error.rs b/library/core/src/str/error.rs index 4c8231a2286e1..1677c849ae4bf 100644 --- a/library/core/src/str/error.rs +++ b/library/core/src/str/error.rs @@ -124,12 +124,7 @@ impl fmt::Display for Utf8Error { } #[stable(feature = "rust1", since = "1.0.0")] -impl Error for Utf8Error { - #[allow(deprecated)] - fn description(&self) -> &str { - "invalid utf-8: corrupt contents" - } -} +impl Error for Utf8Error {} /// An error returned when parsing a `bool` using [`from_str`] fails /// @@ -147,9 +142,4 @@ impl fmt::Display for ParseBoolError { } #[stable(feature = "rust1", since = "1.0.0")] -impl Error for ParseBoolError { - #[allow(deprecated)] - fn description(&self) -> &str { - "failed to parse bool" - } -} +impl Error for ParseBoolError {} diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 0cc570f4b7335..f37e47f132d54 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -927,7 +927,7 @@ impl Duration { pub fn from_secs_f64(secs: f64) -> Duration { match Duration::try_from_secs_f64(secs) { Ok(v) => v, - Err(e) => panic!("{}", e.description()), + Err(e) => panic!("{e}"), } } @@ -964,7 +964,7 @@ impl Duration { pub fn from_secs_f32(secs: f32) -> Duration { match Duration::try_from_secs_f32(secs) { Ok(v) => v, - Err(e) => panic!("{}", e.description()), + Err(e) => panic!("{e}"), } } @@ -1445,8 +1445,9 @@ pub struct TryFromFloatSecsError { kind: TryFromFloatSecsErrorKind, } -impl TryFromFloatSecsError { - const fn description(&self) -> &'static str { +#[stable(feature = "duration_checked_float", since = "1.66.0")] +impl fmt::Display for TryFromFloatSecsError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.kind { TryFromFloatSecsErrorKind::Negative => { "cannot convert float seconds to Duration: value is negative" @@ -1455,13 +1456,7 @@ impl TryFromFloatSecsError { "cannot convert float seconds to Duration: value is either too big or NaN" } } - } -} - -#[stable(feature = "duration_checked_float", since = "1.66.0")] -impl fmt::Display for TryFromFloatSecsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.description().fmt(f) + .fmt(f) } } diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 15a7a770d1a87..fc0fef620e3b6 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1875,12 +1875,7 @@ impl<'a, K: Debug, V: Debug> fmt::Display for OccupiedError<'a, K, V> { } #[unstable(feature = "map_try_insert", issue = "82766")] -impl<'a, K: fmt::Debug, V: fmt::Debug> Error for OccupiedError<'a, K, V> { - #[allow(deprecated)] - fn description(&self) -> &str { - "key already exists" - } -} +impl<'a, K: Debug, V: Debug> Error for OccupiedError<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V, S> IntoIterator for &'a HashMap { diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 9f17ff7644557..e457cd61c7596 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -296,15 +296,7 @@ impl fmt::Display for VarError { } #[stable(feature = "env", since = "1.0.0")] -impl Error for VarError { - #[allow(deprecated)] - fn description(&self) -> &str { - match *self { - VarError::NotPresent => "environment variable not found", - VarError::NotUnicode(..) => "environment variable was not valid unicode", - } - } -} +impl Error for VarError {} /// Sets the environment variable `key` to the value `value` for the currently running /// process. diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index 574eb83dc5649..d569fed24c561 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -492,23 +492,15 @@ impl WriterPanicked { pub fn into_inner(self) -> Vec { self.buf } - - const DESCRIPTION: &'static str = - "BufWriter inner writer panicked, what data remains unwritten is not known"; } #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] -impl error::Error for WriterPanicked { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - Self::DESCRIPTION - } -} +impl error::Error for WriterPanicked {} #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] impl fmt::Display for WriterPanicked { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", Self::DESCRIPTION) + "BufWriter inner writer panicked, what data remains unwritten is not known".fmt(f) } } diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs index 475d877528f7f..e36f2d92108d0 100644 --- a/library/std/src/io/buffered/mod.rs +++ b/library/std/src/io/buffered/mod.rs @@ -179,12 +179,7 @@ impl From> for Error { } #[stable(feature = "rust1", since = "1.0.0")] -impl error::Error for IntoInnerError { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - error::Error::description(self.error()) - } -} +impl error::Error for IntoInnerError {} #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for IntoInnerError { diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index dcfa189823f89..57a980d6acdb5 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -1049,15 +1049,6 @@ impl fmt::Display for Error { #[stable(feature = "rust1", since = "1.0.0")] impl error::Error for Error { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - match self.repr.data() { - ErrorData::Os(..) | ErrorData::Simple(..) => self.kind().as_str(), - ErrorData::SimpleMessage(msg) => msg.message, - ErrorData::Custom(c) => c.error.description(), - } - } - #[allow(deprecated)] fn cause(&self) -> Option<&dyn error::Error> { match self.repr.data() { diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 3899fbf86db8c..470d300d2d95b 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3677,19 +3677,13 @@ impl_cmp_os_str!(<'a> Cow<'a, Path>, OsString); #[stable(since = "1.7.0", feature = "strip_prefix")] impl fmt::Display for StripPrefixError { - #[allow(deprecated, deprecated_in_future)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.description().fmt(f) + "prefix not found".fmt(f) } } #[stable(since = "1.7.0", feature = "strip_prefix")] -impl Error for StripPrefixError { - #[allow(deprecated)] - fn description(&self) -> &str { - "prefix not found" - } -} +impl Error for StripPrefixError {} #[unstable(feature = "normalize_lexically", issue = "134694")] impl fmt::Display for NormalizeError { diff --git a/library/std/src/sync/mpsc.rs b/library/std/src/sync/mpsc.rs index 03d7fddc2faef..f91c26aa22cf8 100644 --- a/library/std/src/sync/mpsc.rs +++ b/library/std/src/sync/mpsc.rs @@ -1108,12 +1108,7 @@ impl fmt::Display for SendError { } #[stable(feature = "rust1", since = "1.0.0")] -impl error::Error for SendError { - #[allow(deprecated)] - fn description(&self) -> &str { - "sending on a closed channel" - } -} +impl error::Error for SendError {} #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for TrySendError { @@ -1136,15 +1131,7 @@ impl fmt::Display for TrySendError { } #[stable(feature = "rust1", since = "1.0.0")] -impl error::Error for TrySendError { - #[allow(deprecated)] - fn description(&self) -> &str { - match *self { - TrySendError::Full(..) => "sending on a full channel", - TrySendError::Disconnected(..) => "sending on a closed channel", - } - } -} +impl error::Error for TrySendError {} #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] impl From> for TrySendError { @@ -1168,12 +1155,7 @@ impl fmt::Display for RecvError { } #[stable(feature = "rust1", since = "1.0.0")] -impl error::Error for RecvError { - #[allow(deprecated)] - fn description(&self) -> &str { - "receiving on a closed channel" - } -} +impl error::Error for RecvError {} #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for TryRecvError { @@ -1186,15 +1168,7 @@ impl fmt::Display for TryRecvError { } #[stable(feature = "rust1", since = "1.0.0")] -impl error::Error for TryRecvError { - #[allow(deprecated)] - fn description(&self) -> &str { - match *self { - TryRecvError::Empty => "receiving on an empty channel", - TryRecvError::Disconnected => "receiving on a closed channel", - } - } -} +impl error::Error for TryRecvError {} #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] impl From for TryRecvError { @@ -1221,15 +1195,7 @@ impl fmt::Display for RecvTimeoutError { } #[stable(feature = "mpsc_recv_timeout_error", since = "1.15.0")] -impl error::Error for RecvTimeoutError { - #[allow(deprecated)] - fn description(&self) -> &str { - match *self { - RecvTimeoutError::Timeout => "timed out waiting on channel", - RecvTimeoutError::Disconnected => "channel is empty and sending half is closed", - } - } -} +impl error::Error for RecvTimeoutError {} #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] impl From for RecvTimeoutError { diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index 31889dcc10fad..49a71b9ad10bd 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -263,12 +263,7 @@ impl fmt::Display for PoisonError { } #[stable(feature = "rust1", since = "1.0.0")] -impl Error for PoisonError { - #[allow(deprecated)] - fn description(&self) -> &str { - "poisoned lock: another task failed inside" - } -} +impl Error for PoisonError {} impl PoisonError { /// Creates a `PoisonError`. @@ -376,17 +371,6 @@ impl fmt::Display for TryLockError { #[stable(feature = "rust1", since = "1.0.0")] impl Error for TryLockError { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - match *self { - #[cfg(panic = "unwind")] - TryLockError::Poisoned(ref p) => p.description(), - #[cfg(not(panic = "unwind"))] - TryLockError::Poisoned(ref p) => match p._never {}, - TryLockError::WouldBlock => "try_lock failed because the operation would block", - } - } - #[allow(deprecated)] fn cause(&self) -> Option<&dyn Error> { match *self { diff --git a/library/std/src/sys/net/connection/sgx.rs b/library/std/src/sys/net/connection/sgx.rs index 242df10bc3270..2389fd1bcb6ca 100644 --- a/library/std/src/sys/net/connection/sgx.rs +++ b/library/std/src/sys/net/connection/sgx.rs @@ -452,12 +452,7 @@ pub struct NonIpSockAddr { host: String, } -impl error::Error for NonIpSockAddr { - #[allow(deprecated)] - fn description(&self) -> &str { - "Failed to convert address to SocketAddr" - } -} +impl error::Error for NonIpSockAddr {} impl fmt::Display for NonIpSockAddr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/std/src/sys/pal/hermit/os.rs b/library/std/src/sys/pal/hermit/os.rs index a998c3165e52f..0fe713a503bd0 100644 --- a/library/std/src/sys/pal/hermit/os.rs +++ b/library/std/src/sys/pal/hermit/os.rs @@ -1,5 +1,4 @@ use super::hermit_abi; -use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::path::{self, PathBuf}; @@ -52,12 +51,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported on hermit yet" - } -} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result { unsupported() diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 6e43a79ddec2c..4a297b6823f20 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -59,8 +59,7 @@ pub fn sgx_ineffective(v: T) -> crate::io::Result { #[inline] pub fn is_interrupted(code: i32) -> bool { - use fortanix_sgx_abi::Error; - code == Error::Interrupted as _ + code == fortanix_sgx_abi::Error::Interrupted as _ } pub fn decode_error_kind(code: i32) -> ErrorKind { diff --git a/library/std/src/sys/pal/sgx/os.rs b/library/std/src/sys/pal/sgx/os.rs index 70f838679c9ca..6b62320a0862a 100644 --- a/library/std/src/sys/pal/sgx/os.rs +++ b/library/std/src/sys/pal/sgx/os.rs @@ -1,6 +1,3 @@ -use fortanix_sgx_abi::{Error, RESULT_SUCCESS}; - -use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::path::{self, PathBuf}; @@ -12,9 +9,12 @@ pub fn errno() -> i32 { } pub fn error_string(errno: i32) -> String { - if errno == RESULT_SUCCESS { + use fortanix_sgx_abi as abi; + + if errno == abi::RESULT_SUCCESS { "operation successful".into() - } else if ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&errno) { + } else if ((abi::Error::UserRangeStart as _)..=(abi::Error::UserRangeEnd as _)).contains(&errno) + { format!("user-specified error {errno:08x}") } else { decode_error_kind(errno).as_str().into() @@ -59,12 +59,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported in SGX yet" - } -} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result { unsupported() diff --git a/library/std/src/sys/pal/solid/os.rs b/library/std/src/sys/pal/solid/os.rs index 8f5976b0592ec..cb6e2cbceae6c 100644 --- a/library/std/src/sys/pal/solid/os.rs +++ b/library/std/src/sys/pal/solid/os.rs @@ -1,5 +1,4 @@ use super::{error, itron, unsupported}; -use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::path::{self, PathBuf}; use crate::{fmt, io}; @@ -58,12 +57,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported on this platform yet" - } -} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result { unsupported() diff --git a/library/std/src/sys/pal/teeos/os.rs b/library/std/src/sys/pal/teeos/os.rs index 03f3c72b0229a..512b3e2885bf0 100644 --- a/library/std/src/sys/pal/teeos/os.rs +++ b/library/std/src/sys/pal/teeos/os.rs @@ -3,7 +3,6 @@ use core::marker::PhantomData; use super::unsupported; -use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::path::PathBuf; use crate::{fmt, io, path}; @@ -62,12 +61,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported on this platform yet" - } -} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result { unsupported() diff --git a/library/std/src/sys/pal/uefi/os.rs b/library/std/src/sys/pal/uefi/os.rs index bfd4dc81cb44f..aae6cb9e06462 100644 --- a/library/std/src/sys/pal/uefi/os.rs +++ b/library/std/src/sys/pal/uefi/os.rs @@ -2,7 +2,6 @@ use r_efi::efi::Status; use r_efi::efi::protocols::{device_path, loaded_image_device_path}; use super::{RawOsError, helpers, unsupported_err}; -use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::os::uefi; @@ -122,7 +121,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError {} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result { let protocol = helpers::image_handle_protocol::( diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 1110b775c0953..81275afa70777 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -7,7 +7,6 @@ mod tests; use libc::{c_char, c_int, c_void}; -use crate::error::Error as StdError; use crate::ffi::{CStr, OsStr, OsString}; use crate::os::unix::prelude::*; use crate::path::{self, PathBuf}; @@ -248,12 +247,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "failed to join paths" - } -} +impl crate::error::Error for JoinPathsError {} #[cfg(target_os = "aix")] pub fn current_exe() -> io::Result { diff --git a/library/std/src/sys/pal/unsupported/os.rs b/library/std/src/sys/pal/unsupported/os.rs index a8ef97ecf67ac..13d2a2044f48a 100644 --- a/library/std/src/sys/pal/unsupported/os.rs +++ b/library/std/src/sys/pal/unsupported/os.rs @@ -1,5 +1,4 @@ use super::unsupported; -use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::path::{self, PathBuf}; @@ -51,12 +50,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported on this platform yet" - } -} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result { unsupported() diff --git a/library/std/src/sys/pal/wasi/os.rs b/library/std/src/sys/pal/wasi/os.rs index 672cf70d1a5b2..151ba254ec4cf 100644 --- a/library/std/src/sys/pal/wasi/os.rs +++ b/library/std/src/sys/pal/wasi/os.rs @@ -1,6 +1,5 @@ #![forbid(unsafe_op_in_unsafe_fn)] -use crate::error::Error as StdError; use crate::ffi::{CStr, OsStr, OsString}; use crate::marker::PhantomData; use crate::os::wasi::prelude::*; @@ -105,12 +104,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported on wasm yet" - } -} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result { unsupported() diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index f331282d2d72a..1b3c80c079bef 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -8,7 +8,6 @@ mod tests; use super::api; #[cfg(not(target_vendor = "uwp"))] use super::api::WinError; -use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::os::windows::ffi::EncodeWide; use crate::os::windows::prelude::*; @@ -162,12 +161,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "failed to join paths" - } -} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result { super::fill_utf16_buf( diff --git a/library/std/src/sys/pal/xous/os.rs b/library/std/src/sys/pal/xous/os.rs index d612a27d2bdb6..d9b8418e6c33c 100644 --- a/library/std/src/sys/pal/xous/os.rs +++ b/library/std/src/sys/pal/xous/os.rs @@ -1,5 +1,4 @@ use super::unsupported; -use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::os::xous::ffi::Error as XousError; @@ -110,12 +109,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported on this platform yet" - } -} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result { unsupported() diff --git a/library/std/src/sys/pal/zkvm/os.rs b/library/std/src/sys/pal/zkvm/os.rs index a8ef97ecf67ac..13d2a2044f48a 100644 --- a/library/std/src/sys/pal/zkvm/os.rs +++ b/library/std/src/sys/pal/zkvm/os.rs @@ -1,5 +1,4 @@ use super::unsupported; -use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::path::{self, PathBuf}; @@ -51,12 +50,7 @@ impl fmt::Display for JoinPathsError { } } -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "not supported on this platform yet" - } -} +impl crate::error::Error for JoinPathsError {} pub fn current_exe() -> io::Result { unsupported() diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 07bb41f14961b..84fbb4c2fe4b1 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -717,12 +717,7 @@ impl SystemTimeError { } #[stable(feature = "time2", since = "1.8.0")] -impl Error for SystemTimeError { - #[allow(deprecated)] - fn description(&self) -> &str { - "other time was not earlier than self" - } -} +impl Error for SystemTimeError {} #[stable(feature = "time2", since = "1.8.0")] impl fmt::Display for SystemTimeError { diff --git a/tests/ui/resolve/issue-102946.rs b/tests/ui/resolve/issue-102946.rs index c6feca6f32f60..8d90e61bb5d3f 100644 --- a/tests/ui/resolve/issue-102946.rs +++ b/tests/ui/resolve/issue-102946.rs @@ -1,7 +1,6 @@ impl Error for str::Utf8Error { //~^ ERROR cannot find trait `Error` in this scope //~| ERROR ambiguous associated type - fn description(&self) {} } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-87455-static-lifetime-ice.rs b/tests/ui/type-alias-impl-trait/issue-87455-static-lifetime-ice.rs index 987fad2efeadb..476babdfb0512 100644 --- a/tests/ui/type-alias-impl-trait/issue-87455-static-lifetime-ice.rs +++ b/tests/ui/type-alias-impl-trait/issue-87455-static-lifetime-ice.rs @@ -1,6 +1,6 @@ //@ check-pass -use std::error::Error as StdError; +use std::error::Error; use std::pin::Pin; use std::task::{Context, Poll}; @@ -51,7 +51,7 @@ impl Stream for SseKeepAlive where S: TryStream + Send + 'static, S::Ok: ServerSentEvent, - S::Error: StdError + Send + Sync + 'static, + S::Error: Error + Send + Sync + 'static, { type Item = Result, ()>; fn poll_next(self: Pin<&mut Self>, _cx: &mut Context) -> Poll> { @@ -65,7 +65,7 @@ pub fn keep( where S: TryStream + Send + 'static, S::Ok: ServerSentEvent + Send, - S::Error: StdError + Send + Sync + 'static, + S::Error: Error + Send + Sync + 'static, { SseKeepAlive { event_stream } } From 3f339ab84926eaf34d2caaa7394bb84744017960 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Mon, 20 Jan 2025 10:59:42 +0100 Subject: [PATCH 05/10] Dial down detail of B-tree description fixes 134088, though it is a shame to lose some of this wonderful detail. --- library/alloc/src/collections/btree/map.rs | 29 ++++------------------ 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index c4e599222e501..673487549fcad 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -40,30 +40,10 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// An ordered map based on a [B-Tree]. /// -/// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing -/// the amount of work performed in a search. In theory, a binary search tree (BST) is the optimal -/// choice for a sorted map, as a perfectly balanced BST performs the theoretical minimum amount of -/// comparisons necessary to find an element (log2n). However, in practice the way this -/// is done is *very* inefficient for modern computer architectures. In particular, every element -/// is stored in its own individually heap-allocated node. This means that every single insertion -/// triggers a heap-allocation, and every single comparison should be a cache-miss. Since these -/// are both notably expensive things to do in practice, we are forced to, at the very least, -/// reconsider the BST strategy. -/// -/// A B-Tree instead makes each node contain B-1 to 2B-1 elements in a contiguous array. By doing -/// this, we reduce the number of allocations by a factor of B, and improve cache efficiency in -/// searches. However, this does mean that searches will have to do *more* comparisons on average. -/// The precise number of comparisons depends on the node search strategy used. For optimal cache -/// efficiency, one could search the nodes linearly. For optimal comparisons, one could search -/// the node using binary search. As a compromise, one could also perform a linear search -/// that initially only checks every ith element for some choice of i. -/// -/// Currently, our implementation simply performs naive linear search. This provides excellent -/// performance on *small* nodes of elements which are cheap to compare. However in the future we -/// would like to further explore choosing the optimal search strategy based on the choice of B, -/// and possibly other factors. Using linear search, searching for a random element is expected -/// to take B * log(n) comparisons, which is generally worse than a BST. In practice, -/// however, performance is excellent. +/// A B-tree resembles a [binary search tree], but each leaf (node) contains +/// an entire array (of unspecified size) of elements, instead of just a single element. +/// A search first traverses the tree structure to find, in logarithmic time, the correct leaf. +/// This leaf is then searched linearly, which is very fast on modern hardware. /// /// It is a logic error for a key to be modified in such a way that the key's ordering relative to /// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is @@ -77,6 +57,7 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// amortized constant time per item returned. /// /// [B-Tree]: https://en.wikipedia.org/wiki/B-tree +/// [binary search tree]: https://en.wikipedia.org/wiki/Binary_search_tree /// [`Cell`]: core::cell::Cell /// [`RefCell`]: core::cell::RefCell /// From bb7993f80793ee4dce16f77532dc44c0048b3261 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Tue, 21 Jan 2025 12:00:44 +0100 Subject: [PATCH 06/10] focus more on ordered aspect and restore old comments --- library/alloc/src/collections/btree/map.rs | 58 +++++++++++++++++----- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 673487549fcad..b23a62c55459a 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -40,10 +40,15 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// An ordered map based on a [B-Tree]. /// -/// A B-tree resembles a [binary search tree], but each leaf (node) contains -/// an entire array (of unspecified size) of elements, instead of just a single element. -/// A search first traverses the tree structure to find, in logarithmic time, the correct leaf. -/// This leaf is then searched linearly, which is very fast on modern hardware. +/// An ordered map is a map in which the keys are totally ordered. +/// That means that keys must be of a type that implements the [`Ord`] trait, +/// such that two keys can always be compared to determine their [`Ordering`]. +/// Examples of totally ordered keys are strings with lexicographical order, +/// and numbers with their natural order. +/// +/// Iterators obtained from functions such as [`BTreeMap::iter`], [`BTreeMap::into_iter`], [`BTreeMap::values`], or +/// [`BTreeMap::keys`] produce their items in key order, and take worst-case logarithmic and +/// amortized constant time per item returned. /// /// It is a logic error for a key to be modified in such a way that the key's ordering relative to /// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is @@ -52,15 +57,6 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// `BTreeMap` that observed the logic error and not result in undefined behavior. This could /// include panics, incorrect results, aborts, memory leaks, and non-termination. /// -/// Iterators obtained from functions such as [`BTreeMap::iter`], [`BTreeMap::into_iter`], [`BTreeMap::values`], or -/// [`BTreeMap::keys`] produce their items in order by key, and take worst-case logarithmic and -/// amortized constant time per item returned. -/// -/// [B-Tree]: https://en.wikipedia.org/wiki/B-tree -/// [binary search tree]: https://en.wikipedia.org/wiki/Binary_search_tree -/// [`Cell`]: core::cell::Cell -/// [`RefCell`]: core::cell::RefCell -/// /// # Examples /// /// ``` @@ -150,6 +146,42 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// // modify an entry before an insert with in-place mutation /// player_stats.entry("mana").and_modify(|mana| *mana += 200).or_insert(100); /// ``` +/// +/// # Background +/// +/// A B-tree is (like) a [binary search tree], but adapted to the natural granularity that modern +/// machines like to consume data at. This means that each node contains an entire array of elements, +/// instead of just a single element. +/// +/// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing +/// the amount of work performed in a search. In theory, a binary search tree (BST) is the optimal +/// choice for a sorted map, as a perfectly balanced BST performs the theoretical minimum number of +/// comparisons necessary to find an element (log2n). However, in practice the way this +/// is done is *very* inefficient for modern computer architectures. In particular, every element +/// is stored in its own individually heap-allocated node. This means that every single insertion +/// triggers a heap-allocation, and every comparison is a potential cache-miss due to the indirection. +/// Since both heap-allocations and cache-misses are notably expensive in practice, we are forced to, +/// at the very least, reconsider the BST strategy. +/// +/// A B-Tree instead makes each node contain B-1 to 2B-1 elements in a contiguous array. By doing +/// this, we reduce the number of allocations by a factor of B, and improve cache efficiency in +/// searches. However, this does mean that searches will have to do *more* comparisons on average. +/// The precise number of comparisons depends on the node search strategy used. For optimal cache +/// efficiency, one could search the nodes linearly. For optimal comparisons, one could search +/// the node using binary search. As a compromise, one could also perform a linear search +/// that initially only checks every ith element for some choice of i. +/// +/// Currently, our implementation simply performs naive linear search. This provides excellent +/// performance on *small* nodes of elements which are cheap to compare. However in the future we +/// would like to further explore choosing the optimal search strategy based on the choice of B, +/// and possibly other factors. Using linear search, searching for a random element is expected +/// to take B * log(n) comparisons, which is generally worse than a BST. In practice, +/// however, performance is excellent. +/// +/// [B-Tree]: https://en.wikipedia.org/wiki/B-tree +/// [binary search tree]: https://en.wikipedia.org/wiki/Binary_search_tree +/// [`Cell`]: core::cell::Cell +/// [`RefCell`]: core::cell::RefCell #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "BTreeMap")] #[rustc_insignificant_dtor] From 1b773870854bac0fa898be2e5d1ba7d44d16b83c Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 22 Jan 2025 10:05:55 +0100 Subject: [PATCH 07/10] Prevent confusion with insertion-ordered maps. --- library/alloc/src/collections/btree/map.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index b23a62c55459a..8b6d86a288866 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -40,10 +40,10 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// An ordered map based on a [B-Tree]. /// -/// An ordered map is a map in which the keys are totally ordered. +/// Given a key type with a [total order], an ordered map stores its entries in key order. /// That means that keys must be of a type that implements the [`Ord`] trait, /// such that two keys can always be compared to determine their [`Ordering`]. -/// Examples of totally ordered keys are strings with lexicographical order, +/// Examples of keys with a total order are strings with lexicographical order, /// and numbers with their natural order. /// /// Iterators obtained from functions such as [`BTreeMap::iter`], [`BTreeMap::into_iter`], [`BTreeMap::values`], or @@ -180,6 +180,7 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// /// [B-Tree]: https://en.wikipedia.org/wiki/B-tree /// [binary search tree]: https://en.wikipedia.org/wiki/Binary_search_tree +/// [total order]: https://en.wikipedia.org/wiki/Total_order /// [`Cell`]: core::cell::Cell /// [`RefCell`]: core::cell::RefCell #[stable(feature = "rust1", since = "1.0.0")] From 455a67bd4f38b10e613fc6e2103598db10ad57fe Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 24 Aug 2025 15:05:26 +1000 Subject: [PATCH 08/10] Replace the `llvm::Bool` typedef with a proper newtype --- compiler/rustc_codegen_llvm/src/asm.rs | 11 ++-- compiler/rustc_codegen_llvm/src/builder.rs | 21 +++----- compiler/rustc_codegen_llvm/src/common.rs | 4 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 57 ++++++++++++++++++-- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 4 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 2 +- compiler/rustc_codegen_llvm/src/mono_item.rs | 2 +- compiler/rustc_codegen_llvm/src/type_.rs | 8 +-- 8 files changed, 75 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index a643a91141e19..38c1d3b53e87c 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -16,6 +16,7 @@ use tracing::debug; use crate::builder::Builder; use crate::common::Funclet; use crate::context::CodegenCx; +use crate::llvm::ToLlvmBool; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; @@ -470,10 +471,6 @@ pub(crate) fn inline_asm_call<'ll>( dest: Option<&'ll llvm::BasicBlock>, catch_funclet: Option<(&'ll llvm::BasicBlock, Option<&Funclet<'ll>>)>, ) -> Option<&'ll Value> { - let volatile = if volatile { llvm::True } else { llvm::False }; - let alignstack = if alignstack { llvm::True } else { llvm::False }; - let can_throw = if unwind { llvm::True } else { llvm::False }; - let argtys = inputs .iter() .map(|v| { @@ -500,10 +497,10 @@ pub(crate) fn inline_asm_call<'ll>( asm.len(), cons.as_ptr(), cons.len(), - volatile, - alignstack, + volatile.to_llvm_bool(), + alignstack.to_llvm_bool(), dia, - can_throw, + unwind.to_llvm_bool(), ) }; diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 427c75d40e9c6..836d227456c40 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -35,7 +35,7 @@ use crate::attributes; use crate::common::Funclet; use crate::context::{CodegenCx, FullCx, GenericCx, SCx}; use crate::llvm::{ - self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, GEPNoWrapFlags, Metadata, True, + self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, GEPNoWrapFlags, Metadata, ToLlvmBool, True, }; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; @@ -717,7 +717,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let mut const_llval = None; let llty = place.layout.llvm_type(self); if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) { - if llvm::LLVMIsGlobalConstant(global) == llvm::True { + if llvm::LLVMIsGlobalConstant(global).is_true() { if let Some(init) = llvm::LLVMGetInitializer(global) { if self.val_ty(init) == llty { const_llval = Some(init); @@ -1067,13 +1067,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn intcast(&mut self, val: &'ll Value, dest_ty: &'ll Type, is_signed: bool) -> &'ll Value { unsafe { - llvm::LLVMBuildIntCast2( - self.llbuilder, - val, - dest_ty, - if is_signed { True } else { False }, - UNNAMED, - ) + llvm::LLVMBuildIntCast2(self.llbuilder, val, dest_ty, is_signed.to_llvm_bool(), UNNAMED) } } @@ -1317,7 +1311,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { failure_order: rustc_middle::ty::AtomicOrdering, weak: bool, ) -> (&'ll Value, &'ll Value) { - let weak = if weak { llvm::True } else { llvm::False }; unsafe { let value = llvm::LLVMBuildAtomicCmpXchg( self.llbuilder, @@ -1328,7 +1321,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { AtomicOrdering::from_generic(failure_order), llvm::False, // SingleThreaded ); - llvm::LLVMSetWeak(value, weak); + llvm::LLVMSetWeak(value, weak.to_llvm_bool()); let val = self.extract_value(value, 0); let success = self.extract_value(value, 1); (val, success) @@ -1368,14 +1361,14 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { scope: SynchronizationScope, ) { let single_threaded = match scope { - SynchronizationScope::SingleThread => llvm::True, - SynchronizationScope::CrossThread => llvm::False, + SynchronizationScope::SingleThread => true, + SynchronizationScope::CrossThread => false, }; unsafe { llvm::LLVMBuildFence( self.llbuilder, AtomicOrdering::from_generic(order), - single_threaded, + single_threaded.to_llvm_bool(), UNNAMED, ); } diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index f29fefb66f0fe..1b341c1f6afe3 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -20,7 +20,7 @@ use tracing::debug; use crate::consts::const_alloc_to_llvm; pub(crate) use crate::context::CodegenCx; use crate::context::{GenericCx, SCx}; -use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, Metadata, True}; +use crate::llvm::{self, BasicBlock, ConstantInt, False, Metadata, ToLlvmBool, True}; use crate::type_::Type; use crate::value::Value; @@ -392,7 +392,7 @@ fn struct_in_context<'ll>( packed: bool, ) -> &'ll Value { let len = c_uint::try_from(elts.len()).expect("LLVMConstStructInContext elements len overflow"); - unsafe { llvm::LLVMConstStructInContext(llcx, elts.as_ptr(), len, packed as Bool) } + unsafe { llvm::LLVMConstStructInContext(llcx, elts.as_ptr(), len, packed.to_llvm_bool()) } } #[inline] diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 2461f70a86e35..912e3d6ff2424 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -13,7 +13,7 @@ #![allow(non_camel_case_types)] #![allow(non_upper_case_globals)] -use std::fmt::Debug; +use std::fmt::{self, Debug}; use std::marker::PhantomData; use std::num::NonZero; use std::ptr; @@ -33,10 +33,59 @@ use crate::llvm; /// In the LLVM-C API, boolean values are passed as `typedef int LLVMBool`, /// which has a different ABI from Rust or C++ `bool`. -pub(crate) type Bool = c_int; +/// +/// This wrapper does not implement `PartialEq`. +/// To test the underlying boolean value, use [`Self::is_true`]. +#[derive(Clone, Copy)] +#[repr(transparent)] +pub(crate) struct Bool { + value: c_int, +} + +pub(crate) const True: Bool = Bool::TRUE; +pub(crate) const False: Bool = Bool::FALSE; + +impl Bool { + pub(crate) const TRUE: Self = Self { value: 1 }; + pub(crate) const FALSE: Self = Self { value: 0 }; + + pub(crate) const fn from_bool(rust_bool: bool) -> Self { + if rust_bool { Self::TRUE } else { Self::FALSE } + } + + /// Converts this LLVM-C boolean to a Rust `bool` + pub(crate) fn is_true(self) -> bool { + // Since we're interacting with a C API, follow the C convention of + // treating any nonzero value as true. + self.value != Self::FALSE.value + } +} -pub(crate) const True: Bool = 1 as Bool; -pub(crate) const False: Bool = 0 as Bool; +impl Debug for Bool { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.value { + 0 => f.write_str("FALSE"), + 1 => f.write_str("TRUE"), + // As with `Self::is_true`, treat any nonzero value as true. + v => write!(f, "TRUE ({v})"), + } + } +} + +/// Convenience trait to convert `bool` to `llvm::Bool` with an explicit method call. +/// +/// Being able to write `b.to_llvm_bool()` is less noisy than `llvm::Bool::from(b)`, +/// while being more explicit and less mistake-prone than something like `b.into()`. +pub(crate) trait ToLlvmBool: Copy { + fn to_llvm_bool(self) -> llvm::Bool; +} + +impl ToLlvmBool for bool { + #[inline(always)] + fn to_llvm_bool(self) -> llvm::Bool { + llvm::Bool::from_bool(self) + } +} /// Wrapper for a raw enum value returned from LLVM's C APIs. /// diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 7fea7b79a8cfb..6adabe5312969 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -215,7 +215,7 @@ pub(crate) fn set_initializer(llglobal: &Value, constant_val: &Value) { } pub(crate) fn set_global_constant(llglobal: &Value, is_constant: bool) { - LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False }); + LLVMSetGlobalConstant(llglobal, is_constant.to_llvm_bool()); } pub(crate) fn get_linkage(llglobal: &Value) -> Linkage { @@ -229,7 +229,7 @@ pub(crate) fn set_linkage(llglobal: &Value, linkage: Linkage) { } pub(crate) fn is_declaration(llglobal: &Value) -> bool { - unsafe { LLVMIsDeclaration(llglobal) == ffi::True } + unsafe { LLVMIsDeclaration(llglobal) }.is_true() } pub(crate) fn get_visibility(llglobal: &Value) -> Visibility { diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 90f7cd43268fa..d5025bb405cc5 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -26,7 +26,7 @@ static INIT: Once = Once::new(); pub(crate) fn init(sess: &Session) { unsafe { // Before we touch LLVM, make sure that multithreading is enabled. - if llvm::LLVMIsMultithreaded() != 1 { + if !llvm::LLVMIsMultithreaded().is_true() { bug!("LLVM compiled without support for threads"); } INIT.call_once(|| { diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 5075befae8a54..52eefe2d4d243 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -133,7 +133,7 @@ impl CodegenCx<'_, '_> { // Thread-local variables generally don't support copy relocations. let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval) - .is_some_and(|v| llvm::LLVMIsThreadLocal(v) == llvm::True); + .is_some_and(|v| llvm::LLVMIsThreadLocal(v).is_true()); if is_thread_local_var { return false; } diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index f02d16baf94e7..499771aa12427 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -15,7 +15,7 @@ use rustc_target::callconv::{CastTarget, FnAbi}; use crate::abi::{FnAbiLlvmExt, LlvmType}; use crate::context::{CodegenCx, GenericCx, SCx}; pub(crate) use crate::llvm::Type; -use crate::llvm::{Bool, False, Metadata, True}; +use crate::llvm::{False, Metadata, ToLlvmBool, True}; use crate::type_of::LayoutLlvmExt; use crate::value::Value; use crate::{common, llvm}; @@ -53,7 +53,9 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { } pub(crate) fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: bool) { - unsafe { llvm::LLVMStructSetBody(ty, els.as_ptr(), els.len() as c_uint, packed as Bool) } + unsafe { + llvm::LLVMStructSetBody(ty, els.as_ptr(), els.len() as c_uint, packed.to_llvm_bool()) + } } pub(crate) fn type_void(&self) -> &'ll Type { unsafe { llvm::LLVMVoidTypeInContext(self.llcx()) } @@ -152,7 +154,7 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { self.llcx(), els.as_ptr(), els.len() as c_uint, - packed as Bool, + packed.to_llvm_bool(), ) } } From b4e97e5d866dd43c110d337affc419d5ac482765 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 24 Aug 2025 20:49:32 +1000 Subject: [PATCH 09/10] Rename `llvm::Bool` aliases to standard const case This avoids the need for `#![allow(non_upper_case_globals)]`. --- compiler/rustc_codegen_llvm/src/allocator.rs | 6 ++-- compiler/rustc_codegen_llvm/src/back/write.rs | 2 +- compiler/rustc_codegen_llvm/src/builder.rs | 30 +++++++++---------- .../src/builder/autodiff.rs | 4 +-- compiler/rustc_codegen_llvm/src/common.rs | 8 ++--- compiler/rustc_codegen_llvm/src/context.rs | 2 +- .../rustc_codegen_llvm/src/debuginfo/gdb.rs | 2 +- .../src/debuginfo/namespace.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 5 ++-- compiler/rustc_codegen_llvm/src/type_.rs | 6 ++-- 10 files changed, 33 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 23610aa856cb1..df3e49279d976 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -12,7 +12,7 @@ use smallvec::SmallVec; use crate::builder::SBuilder; use crate::declare::declare_simple_fn; -use crate::llvm::{self, False, True, Type, Value}; +use crate::llvm::{self, FALSE, TRUE, Type, Value}; use crate::{SimpleCx, attributes, debuginfo, llvm_util}; pub(crate) unsafe fn codegen( @@ -80,7 +80,7 @@ pub(crate) unsafe fn codegen( &cx, &mangle_internal_symbol(tcx, OomStrategy::SYMBOL), &i8, - &llvm::LLVMConstInt(i8, tcx.sess.opts.unstable_opts.oom.should_panic() as u64, False), + &llvm::LLVMConstInt(i8, tcx.sess.opts.unstable_opts.oom.should_panic() as u64, FALSE), ); // __rust_no_alloc_shim_is_unstable_v2 @@ -201,7 +201,7 @@ fn create_wrapper_function( .map(|(i, _)| llvm::get_param(llfn, i as c_uint)) .collect::>(); let ret = bx.call(ty, callee, &args, None); - llvm::LLVMSetTailCall(ret, True); + llvm::LLVMSetTailCall(ret, TRUE); if output.is_some() { bx.ret(ret); } else { diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 62998003ca114..7c65d667bda88 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -1110,7 +1110,7 @@ fn embed_bitcode( llvm::set_section(llglobal, bitcode_section_name(cgcx)); llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); - llvm::LLVMSetGlobalConstant(llglobal, llvm::True); + llvm::LLVMSetGlobalConstant(llglobal, llvm::TRUE); let llconst = common::bytes_in_context(llcx, &[]); let llglobal = llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline"); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 836d227456c40..37379586d5828 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -35,7 +35,7 @@ use crate::attributes; use crate::common::Funclet; use crate::context::{CodegenCx, FullCx, GenericCx, SCx}; use crate::llvm::{ - self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, GEPNoWrapFlags, Metadata, ToLlvmBool, True, + self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, GEPNoWrapFlags, Metadata, TRUE, ToLlvmBool, }; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; @@ -493,8 +493,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { let add = llvm::LLVMBuildAdd(self.llbuilder, a, b, UNNAMED); if llvm::LLVMIsAInstruction(add).is_some() { - llvm::LLVMSetNUW(add, True); - llvm::LLVMSetNSW(add, True); + llvm::LLVMSetNUW(add, TRUE); + llvm::LLVMSetNSW(add, TRUE); } add } @@ -503,8 +503,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { let sub = llvm::LLVMBuildSub(self.llbuilder, a, b, UNNAMED); if llvm::LLVMIsAInstruction(sub).is_some() { - llvm::LLVMSetNUW(sub, True); - llvm::LLVMSetNSW(sub, True); + llvm::LLVMSetNUW(sub, TRUE); + llvm::LLVMSetNSW(sub, TRUE); } sub } @@ -513,8 +513,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { let mul = llvm::LLVMBuildMul(self.llbuilder, a, b, UNNAMED); if llvm::LLVMIsAInstruction(mul).is_some() { - llvm::LLVMSetNUW(mul, True); - llvm::LLVMSetNSW(mul, True); + llvm::LLVMSetNUW(mul, TRUE); + llvm::LLVMSetNSW(mul, TRUE); } mul } @@ -528,7 +528,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // an instruction, so we need to check before setting the flag. // (See also `LLVMBuildNUWNeg` which also needs a check.) if llvm::LLVMIsAInstruction(or).is_some() { - llvm::LLVMSetIsDisjoint(or, True); + llvm::LLVMSetIsDisjoint(or, TRUE); } or } @@ -629,7 +629,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn volatile_load(&mut self, ty: &'ll Type, ptr: &'ll Value) -> &'ll Value { unsafe { let load = llvm::LLVMBuildLoad2(self.llbuilder, ty, ptr, UNNAMED); - llvm::LLVMSetVolatile(load, llvm::True); + llvm::LLVMSetVolatile(load, llvm::TRUE); load } } @@ -838,7 +838,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { if flags.contains(MemFlags::UNALIGNED) { 1 } else { align.bytes() as c_uint }; llvm::LLVMSetAlignment(store, align); if flags.contains(MemFlags::VOLATILE) { - llvm::LLVMSetVolatile(store, llvm::True); + llvm::LLVMSetVolatile(store, llvm::TRUE); } if flags.contains(MemFlags::NONTEMPORAL) { // Make sure that the current target architectures supports "sane" non-temporal @@ -956,7 +956,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let trunc = self.trunc(val, dest_ty); unsafe { if llvm::LLVMIsAInstruction(trunc).is_some() { - llvm::LLVMSetNUW(trunc, True); + llvm::LLVMSetNUW(trunc, TRUE); } } trunc @@ -968,7 +968,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let trunc = self.trunc(val, dest_ty); unsafe { if llvm::LLVMIsAInstruction(trunc).is_some() { - llvm::LLVMSetNSW(trunc, True); + llvm::LLVMSetNSW(trunc, TRUE); } } trunc @@ -1223,7 +1223,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let ty = self.type_struct(&[self.type_ptr(), self.type_i32()], false); let landing_pad = self.landing_pad(ty, pers_fn, 0); unsafe { - llvm::LLVMSetCleanup(landing_pad, llvm::True); + llvm::LLVMSetCleanup(landing_pad, llvm::TRUE); } (self.extract_value(landing_pad, 0), self.extract_value(landing_pad, 1)) } @@ -1319,7 +1319,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { src, AtomicOrdering::from_generic(order), AtomicOrdering::from_generic(failure_order), - llvm::False, // SingleThreaded + llvm::FALSE, // SingleThreaded ); llvm::LLVMSetWeak(value, weak.to_llvm_bool()); let val = self.extract_value(value, 0); @@ -1346,7 +1346,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { dst, src, AtomicOrdering::from_generic(order), - llvm::False, // SingleThreaded + llvm::FALSE, // SingleThreaded ) }; if ret_ptr && self.val_ty(res) != self.type_ptr() { diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index e2df3265f6f7d..6ddf53cdc87f0 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -11,7 +11,7 @@ use crate::builder::{Builder, PlaceRef, UNNAMED}; use crate::context::SimpleCx; use crate::declare::declare_simple_fn; use crate::llvm; -use crate::llvm::{Metadata, True, Type}; +use crate::llvm::{Metadata, TRUE, Type}; use crate::value::Value; pub(crate) fn adjust_activity_to_abi<'tcx>( @@ -293,7 +293,7 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( // ret double %0 // } // ``` - let enzyme_ty = unsafe { llvm::LLVMFunctionType(ret_ty, ptr::null(), 0, True) }; + let enzyme_ty = unsafe { llvm::LLVMFunctionType(ret_ty, ptr::null(), 0, TRUE) }; // FIXME(ZuseZ4): the CC/Addr/Vis values are best effort guesses, we should look at tests and // think a bit more about what should go here. diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 1b341c1f6afe3..11b79a7fe68c6 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -20,7 +20,7 @@ use tracing::debug; use crate::consts::const_alloc_to_llvm; pub(crate) use crate::context::CodegenCx; use crate::context::{GenericCx, SCx}; -use crate::llvm::{self, BasicBlock, ConstantInt, False, Metadata, ToLlvmBool, True}; +use crate::llvm::{self, BasicBlock, ConstantInt, FALSE, Metadata, TRUE, ToLlvmBool}; use crate::type_::Type; use crate::value::Value; @@ -158,7 +158,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { self.type_kind(t) == TypeKind::Integer, "only allows integer types in const_int" ); - unsafe { llvm::LLVMConstInt(t, i as u64, True) } + unsafe { llvm::LLVMConstInt(t, i as u64, TRUE) } } fn const_u8(&self, i: u8) -> &'ll Value { @@ -192,7 +192,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { self.type_kind(t) == TypeKind::Integer, "only allows integer types in const_uint" ); - unsafe { llvm::LLVMConstInt(t, i, False) } + unsafe { llvm::LLVMConstInt(t, i, FALSE) } } fn const_uint_big(&self, t: &'ll Type, u: u128) -> &'ll Value { @@ -377,7 +377,7 @@ pub(crate) fn val_ty(v: &Value) -> &Type { pub(crate) fn bytes_in_context<'ll>(llcx: &'ll llvm::Context, bytes: &[u8]) -> &'ll Value { unsafe { let ptr = bytes.as_ptr() as *const c_char; - llvm::LLVMConstStringInContext2(llcx, ptr, bytes.len(), True) + llvm::LLVMConstStringInContext2(llcx, ptr, bytes.len(), TRUE) } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 4a7de7d2e69e2..4fd6110ac4a11 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -701,7 +701,7 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { } pub(crate) fn get_const_int(&self, ty: &'ll Type, val: u64) -> &'ll Value { - unsafe { llvm::LLVMConstInt(ty, val, llvm::False) } + unsafe { llvm::LLVMConstInt(ty, val, llvm::FALSE) } } pub(crate) fn get_const_i64(&self, n: u64) -> &'ll Value { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 6eb7042da6171..7a6dc008c7b9e 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -72,7 +72,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>( .unwrap_or_else(|| bug!("symbol `{}` is already defined", section_var_name)); llvm::set_section(section_var, c".debug_gdb_scripts"); llvm::set_initializer(section_var, cx.const_bytes(section_contents)); - llvm::LLVMSetGlobalConstant(section_var, llvm::True); + llvm::LLVMSetGlobalConstant(section_var, llvm::TRUE); llvm::set_unnamed_address(section_var, llvm::UnnamedAddr::Global); llvm::set_linkage(section_var, llvm::Linkage::LinkOnceODRLinkage); // This should make sure that the whole section is not larger than diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs index b4d639368b005..1dcf4ff3062a2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs @@ -38,7 +38,7 @@ pub(crate) fn item_namespace<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'l parent_scope, namespace_name_string.as_ptr(), namespace_name_string.len(), - llvm::False, // ExportSymbols (only relevant for C++ anonymous namespaces) + llvm::FALSE, // ExportSymbols (only relevant for C++ anonymous namespaces) ) }; diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 912e3d6ff2424..fa2802a891fbd 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -11,7 +11,6 @@ //! the need for an extra cast from `*const u8` on the Rust side. #![allow(non_camel_case_types)] -#![allow(non_upper_case_globals)] use std::fmt::{self, Debug}; use std::marker::PhantomData; @@ -42,8 +41,8 @@ pub(crate) struct Bool { value: c_int, } -pub(crate) const True: Bool = Bool::TRUE; -pub(crate) const False: Bool = Bool::FALSE; +pub(crate) const TRUE: Bool = Bool::TRUE; +pub(crate) const FALSE: Bool = Bool::FALSE; impl Bool { pub(crate) const TRUE: Self = Self { value: 1 }; diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 499771aa12427..9ecaf5f24fe15 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -15,7 +15,7 @@ use rustc_target::callconv::{CastTarget, FnAbi}; use crate::abi::{FnAbiLlvmExt, LlvmType}; use crate::context::{CodegenCx, GenericCx, SCx}; pub(crate) use crate::llvm::Type; -use crate::llvm::{False, Metadata, ToLlvmBool, True}; +use crate::llvm::{FALSE, Metadata, TRUE, ToLlvmBool}; use crate::type_of::LayoutLlvmExt; use crate::value::Value; use crate::{common, llvm}; @@ -141,7 +141,7 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { } pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type { - unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) } + unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, TRUE) } } pub(crate) fn type_i1(&self) -> &'ll Type { @@ -202,7 +202,7 @@ impl<'ll, CX: Borrow>> BaseTypeCodegenMethods for GenericCx<'ll, CX> { } fn type_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type { - unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, False) } + unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, FALSE) } } fn type_kind(&self, ty: &'ll Type) -> TypeKind { From b1be775dd67b2b9a871f6e7076d7d2f2c7f1c8ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Sat, 23 Aug 2025 18:26:11 +0200 Subject: [PATCH 10/10] raw-dylib-elf: set correct `DT_VERDEFNUM` Previously it indicated a single version, regardless of their count. Observed in: https://github.com/davidlattimore/wild/pull/1041 --- .../rustc_codegen_ssa/src/back/link/raw_dylib.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs b/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs index b9e0c95736331..509168b2cd283 100644 --- a/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs +++ b/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs @@ -307,11 +307,14 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport] stub.reserve_section_headers(); stub.reserve_dynsym(); stub.reserve_dynstr(); + let verdef_count = 1 + vers.len(); + let mut dynamic_entries = 2; // DT_SONAME, DT_NULL if !vers.is_empty() { stub.reserve_gnu_versym(); - stub.reserve_gnu_verdef(1 + vers.len(), 1 + vers.len()); + stub.reserve_gnu_verdef(verdef_count, verdef_count); + dynamic_entries += 1; // DT_VERDEFNUM } - stub.reserve_dynamic(2); // DT_SONAME, DT_NULL + stub.reserve_dynamic(dynamic_entries); // First write the ELF header with the arch information. let e_machine = match (arch, sub_arch) { @@ -443,9 +446,13 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport] // .dynamic // the DT_SONAME will be used by the linker to populate DT_NEEDED // which the loader uses to find the library. - // DT_NULL terminates the .dynamic table. stub.write_align_dynamic(); stub.write_dynamic_string(elf::DT_SONAME, soname); + // LSB section "2.7. Symbol Versioning" requires `DT_VERDEFNUM` to be reliable. + if verdef_count > 1 { + stub.write_dynamic(elf::DT_VERDEFNUM, verdef_count as u64); + } + // DT_NULL terminates the .dynamic table. stub.write_dynamic(elf::DT_NULL, 0); stub_buf