From 3c1abf4c95627092f0562d365e30cbb22705b7f0 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 20 Aug 2026 09:15:02 +0000 Subject: [PATCH 01/49] apply various clippy lint fixes --- compiler/rustc_builtin_macros/src/asm.rs | 2 +- compiler/rustc_builtin_macros/src/assert.rs | 2 +- .../src/assert/context.rs | 2 +- compiler/rustc_builtin_macros/src/autodiff.rs | 48 ++++++++----------- .../rustc_builtin_macros/src/cfg_select.rs | 2 +- .../src/deriving/cmp/ord.rs | 2 +- .../src/deriving/cmp/partial_eq.rs | 2 +- .../src/deriving/generic/mod.rs | 6 +-- .../src/deriving/generic/ty.rs | 2 +- .../rustc_builtin_macros/src/edition_panic.rs | 2 +- compiler/rustc_builtin_macros/src/eii.rs | 10 ++-- compiler/rustc_builtin_macros/src/format.rs | 4 +- .../src/format_foreign.rs | 46 +++++------------- compiler/rustc_builtin_macros/src/offload.rs | 2 +- .../rustc_builtin_macros/src/source_util.rs | 4 +- compiler/rustc_builtin_macros/src/test.rs | 2 +- .../rustc_builtin_macros/src/test_harness.rs | 6 +-- 17 files changed, 55 insertions(+), 89 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 3b592a5277fba..19b3311965f9a 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -340,7 +340,7 @@ fn expand_preparsed_asm( if let Some(pos) = snippet.find(needle) { let end = pos + snippet[pos..] - .find(|c| matches!(c, '\n' | ';' | '\\' | '"')) + .find(['\n', ';', '\\', '"']) .unwrap_or(snippet[pos..].len() - 1); let inner = InnerSpan::new(pos, end); return template_sp.from_inner(inner); diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 264b285a35670..106b67d1c8ec7 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -39,7 +39,7 @@ pub(crate) fn expand_assert<'cx>( segments: cx .std_path(&[sym::panic, sym::panic_2021]) .into_iter() - .map(|ident| PathSegment::from_ident(ident)) + .map(PathSegment::from_ident) .collect(), } } else { diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 1bc2bc8342559..80ea2e3d877fc 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -153,7 +153,7 @@ impl<'cx, 'a> Context<'cx, 'a> { } else { format!( "Assertion failed: {escaped_expr_str}\nWith captures:\n{}", - &self.fmt_string + self.fmt_string ) }), suffix: None, diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index c3fb727ede7bd..5a9988e076b0d 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -68,7 +68,7 @@ mod llvm_enzyme { let lit = x.lit()?; match lit.kind { ast::LitKind::Int(x, _) => Some(x.get()), - _ => return None, + _ => None, } } @@ -76,7 +76,7 @@ mod llvm_enzyme { fn extract_item_info(iitem: &Box) -> Option<(Visibility, FnSig, Ident, Generics)> { match &iitem.kind { ItemKind::Fn(ast::Fn { sig, ident, generics, .. }) => { - Some((iitem.vis.clone(), sig.clone(), ident.clone(), generics.clone())) + Some((iitem.vis.clone(), sig.clone(), *ident, generics.clone())) } _ => None, } @@ -115,7 +115,7 @@ mod llvm_enzyme { let mut activities: Vec = vec![]; let mut errors = false; for x in &meta_item[first_activity..] { - let activity_str = name(&x); + let activity_str = name(x); let res = DiffActivity::from_str(&activity_str); match res { Ok(x) => activities.push(x), @@ -158,7 +158,7 @@ mod llvm_enzyme { let val = first_ident(t); let t = Token::from_ast_ident(val); ts.push(TokenTree::Token(t, Spacing::Joint)); - ts.push(TokenTree::Token(comma.clone(), Spacing::Alone)); + ts.push(TokenTree::Token(comma, Spacing::Alone)); } pub(crate) fn expand_forward( @@ -226,13 +226,9 @@ mod llvm_enzyme { }, Annotatable::AssocItem(assoc_item, _ctxt @ (Impl { of_trait: _ } | Trait)) => { match &assoc_item.kind { - ast::AssocItemKind::Fn(ast::Fn { sig, ident, generics, .. }) => Some(( - assoc_item.vis.clone(), - sig.clone(), - ident.clone(), - generics.clone(), - true, - )), + ast::AssocItemKind::Fn(ast::Fn { sig, ident, generics, .. }) => { + Some((assoc_item.vis.clone(), sig.clone(), *ident, generics.clone(), true)) + } _ => None, } } @@ -255,7 +251,7 @@ mod llvm_enzyme { // create TokenStream from vec elemtents: // meta_item doesn't have a .tokens field let mut ts: Vec = vec![]; - if meta_item_vec.len() < 1 { + if meta_item_vec.is_empty() { // At the bare minimum, we need a fnc name. dcx.emit_err(diagnostics::AutoDiffMissingConfig { span: item.span() }); return vec![item]; @@ -294,7 +290,7 @@ mod llvm_enzyme { let t = Token::new(TokenKind::Literal(l), Span::default()); let comma = Token::new(TokenKind::Comma, Span::default()); ts.push(TokenTree::Token(t, Spacing::Joint)); - ts.push(TokenTree::Token(comma.clone(), Spacing::Alone)); + ts.push(TokenTree::Token(comma, Spacing::Alone)); for t in meta_item_vec.clone()[start_position..].iter() { meta_item_inner_to_ts(t, &mut ts); @@ -474,7 +470,7 @@ mod llvm_enzyme { } }; - return vec![orig_annotatable, d_annotatable]; + vec![orig_annotatable, d_annotatable] } // shadow arguments (the extra ones which were not in the original (primal) function), in reverse mode must be @@ -519,10 +515,8 @@ mod llvm_enzyme { .map(|param| { let ty = match ¶m.ty.kind { TyKind::ImplicitSelf => self_ty(), - TyKind::Ref(lt, mt) if matches!(mt.ty.kind, TyKind::ImplicitSelf) => ecx.ty( - span, - TyKind::Ref(lt.clone(), ast::MutTy { ty: self_ty(), mutbl: mt.mutbl }), - ), + TyKind::Ref(lt, mt) if matches!(mt.ty.kind, TyKind::ImplicitSelf) => ecx + .ty(span, TyKind::Ref(*lt, ast::MutTy { ty: self_ty(), mutbl: mt.mutbl })), TyKind::Ptr(mt) if matches!(mt.ty.kind, TyKind::ImplicitSelf) => { ecx.ty(span, TyKind::Ptr(ast::MutTy { ty: self_ty(), mutbl: mt.mutbl })) } @@ -603,7 +597,7 @@ mod llvm_enzyme { let anon_const = AnonConst { id: ast::DUMMY_NODE_ID, value: expr }; Some(AngleBracketedArg::Arg(GenericArg::Const(anon_const))) } - GenericParamKind::Lifetime { .. } => None, + GenericParamKind::Lifetime => None, }) .collect::>(); @@ -722,7 +716,7 @@ mod llvm_enzyme { for i in 0..x.width { let mut shadow_arg = arg.clone(); // We += into the shadow in reverse mode. - shadow_arg.ty = Box::new(assure_mut_ref(&arg.ty)); + *shadow_arg.ty = assure_mut_ref(&arg.ty); let old_name = if let PatKind::Ident(_, ident, _) = arg.pat.kind { ident.name } else { @@ -732,11 +726,11 @@ mod llvm_enzyme { let name: String = format!("d{}_{}", old_name, i); new_inputs.push(name.clone()); let ident = Ident::from_str_and_span(&name, shadow_arg.pat.span); - shadow_arg.pat = Box::new(ast::Pat { + *shadow_arg.pat = ast::Pat { id: ast::DUMMY_NODE_ID, kind: PatKind::Ident(BindingMode::NONE, ident, None), span: shadow_arg.pat.span, - }); + }; d_inputs.push(shadow_arg.clone()); } } @@ -763,11 +757,11 @@ mod llvm_enzyme { let name: String = format!("b{}_{}", old_name, i); new_inputs.push(name.clone()); let ident = Ident::from_str_and_span(&name, shadow_arg.pat.span); - shadow_arg.pat = Box::new(ast::Pat { + *shadow_arg.pat = ast::Pat { id: ast::DUMMY_NODE_ID, kind: PatKind::Ident(BindingMode::NONE, ident, None), span: shadow_arg.pat.span, - }); + }; d_inputs.push(shadow_arg.clone()); } } @@ -779,7 +773,7 @@ mod llvm_enzyme { } } if let PatKind::Ident(_, ident, _) = arg.pat.kind { - idents.push(ident.clone()); + idents.push(ident); } else { panic!("not an ident?"); } @@ -891,7 +885,7 @@ mod llvm_enzyme { if act_ret.len() == 1 { act_ret[0].clone() } else { - let kind = TyKind::Tup(act_ret.iter().map(|arg| arg.clone()).collect()); + let kind = TyKind::Tup(act_ret); Box::new(rustc_ast::Ty { kind, id: ast::DUMMY_NODE_ID, span }) } } @@ -899,7 +893,7 @@ mod llvm_enzyme { d_decl.output = FnRetTy::Ty(ret_ty); } - let mut d_header = sig.header.clone(); + let mut d_header = sig.header; if unsafe_activities { d_header.safety = rustc_ast::Safety::Unsafe(span); } diff --git a/compiler/rustc_builtin_macros/src/cfg_select.rs b/compiler/rustc_builtin_macros/src/cfg_select.rs index 526ddd6a3811d..5df24c1a47ed6 100644 --- a/compiler/rustc_builtin_macros/src/cfg_select.rs +++ b/compiler/rustc_builtin_macros/src/cfg_select.rs @@ -74,7 +74,7 @@ pub(super) fn expand_cfg_select<'cx>( ) { Ok(mut branches) => { if let Some((selected_tts, selected_span)) = branches.pop_first_match(|cfg| { - matches!(attr::eval_config_entry(&ecx.sess, cfg), EvalConfigResult::True) + matches!(attr::eval_config_entry(ecx.sess, cfg), EvalConfigResult::True) }) { let mac = CfgSelectResult { ecx, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 4a8e4e07942bf..01bae641dbee6 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -30,7 +30,7 @@ pub(crate) fn expand_deriving_ord( ret_ty: Path(path_std!(cmp::Ordering)), attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, - combine_substructure: combine_substructure(Box::new(|a, b, c| cs_cmp(a, b, c))), + combine_substructure: combine_substructure(Box::new(cs_cmp)), }], associated_types: Vec::new(), is_const, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 372b4e820f72d..8feb70fb5d21e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -206,7 +206,7 @@ fn get_field_equality_expr(cx: &ExtCtxt<'_>, field: &FieldInfo) -> Box { /// references are preserved. fn peel_refs(mut expr: &Box) -> Box { while let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = &expr.kind { - expr = &inner; + expr = inner; } expr.clone() } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index c5f6c96bd8634..a2bce479e22de 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -632,7 +632,7 @@ impl<'a> TraitDef<'a> { .params .iter() .map(|param| match ¶m.kind { - GenericParamKind::Lifetime { .. } => param.clone(), + GenericParamKind::Lifetime => param.clone(), GenericParamKind::Type { .. } => { // Extra restrictions on the generics parameters to the // type being derived upon. @@ -711,7 +711,7 @@ impl<'a> TraitDef<'a> { if !ty_param_names.is_empty() { for field_ty in field_tys { - let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx); + let field_ty_params = find_type_parameters(field_ty, &ty_param_names, cx); for field_ty_param in field_ty_params { // if we have already handled this type, skip it @@ -776,7 +776,7 @@ impl<'a> TraitDef<'a> { .params .iter() .map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { + GenericParamKind::Lifetime => { GenericArg::Lifetime(cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident)) } GenericParamKind::Type { .. } => { diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index e7972c5436e13..a3c540de95379 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -119,7 +119,7 @@ impl Ty { .params .iter() .map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { + GenericParamKind::Lifetime => { GenericArg::Lifetime(ast::Lifetime { id: param.id, ident: param.ident }) } GenericParamKind::Type { .. } => { diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs index 9c26e59f0d628..ac5c43c660088 100644 --- a/compiler/rustc_builtin_macros/src/edition_panic.rs +++ b/compiler/rustc_builtin_macros/src/edition_panic.rs @@ -53,7 +53,7 @@ fn expand<'cx>( segments: cx .std_path(&[sym::panic, mac]) .into_iter() - .map(|ident| PathSegment::from_ident(ident)) + .map(PathSegment::from_ident) .collect(), }, args: Box::new(DelimArgs { diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index cf50460422f52..8d245fde87952 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -150,7 +150,7 @@ fn eii_( let (macro_attrs, foreign_item_attrs, default_func_attrs) = split_attrs(ecx, item_span, attrs_from_decl); - let Ok(macro_name) = name_for_impl_macro(ecx, foreign_item_name, &meta_item) else { + let Ok(macro_name) = name_for_impl_macro(ecx, foreign_item_name, meta_item) else { // we don't need to wrap in Annotatable::Stmt conditionally since // EII can't be used on items in statement position return vec![Annotatable::Item(item)]; @@ -302,14 +302,10 @@ fn generate_default_impl( ) -> Option> { match item_kind { ItemKind::Fn(func) => { - if func.body.is_none() { - return None; - } + func.body.as_ref()?; } ItemKind::Static(stat) => { - if stat.expr.is_none() { - return None; - } + stat.expr.as_ref()?; } _ => unreachable!("Target was checked earlier"), }; diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 89ea581d34d60..26d223353c62e 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -225,7 +225,7 @@ fn make_format_args( let mut sugg_fmt = String::new(); for kind in std::iter::once(&efmt.kind) - .chain(args.explicit_args().into_iter().map(|a| &a.expr.kind)) + .chain(args.explicit_args().iter().map(|a| &a.expr.kind)) { sugg_fmt.push_str(if should_suggest(kind) { "{:?} " @@ -928,7 +928,7 @@ fn report_redundant_format_arguments<'a>( suggestion_spans.push(span); } - let sugg = if args.named_args().len() == 0 { + let sugg = if args.named_args().is_empty() { Some(diagnostics::FormatRedundantArgsSugg { spans: suggestion_spans }) } else { None diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index cf563a53973ca..3b8181842b169 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -185,17 +185,7 @@ pub(crate) mod printf { s.push('{'); if let Some(arg) = self.parameter { - match write!( - s, - "{}", - match arg.checked_sub(1) { - Some(a) => a, - None => return Err(None), - } - ) { - Err(_) => return Err(None), - _ => {} - } + write!(s, "{}", arg.checked_sub(1).ok_or(None)?).map_err(|_| None)?; } if has_options { @@ -225,18 +215,12 @@ pub(crate) mod printf { } if let Some(width) = width { - match width.translate(&mut s) { - Err(_) => return Err(None), - _ => {} - } + width.translate(&mut s).map_err(|_| None)?; } if let Some(precision) = precision { s.push('.'); - match precision.translate(&mut s) { - Err(_) => return Err(None), - _ => {} - } + precision.translate(&mut s).map_err(|_| None)?; } if let Some(type_) = type_ { @@ -268,11 +252,11 @@ pub(crate) mod printf { impl Num { fn from_str(s: &str, arg: Option<&str>) -> Option { if let Some(arg) = arg { - arg.parse().ok().map(|arg| Num::Arg(arg)) + arg.parse().ok().map(Num::Arg) } else if s == "*" { Some(Num::Next) } else { - s.parse().ok().map(|num| Num::Num(num)) + s.parse().ok().map(Num::Num) } } @@ -597,14 +581,10 @@ pub(crate) mod printf { { loop { match cur.next_cp() { - Some((c, next)) => { - if pred(&c) { - cur = next; - } else { - return cur; - } + Some((c, next)) if pred(&c) => { + cur = next; } - None => return cur, + _ => return cur, } } } @@ -722,14 +702,10 @@ pub(crate) mod shell { { loop { match cur.next_cp() { - Some((c, next)) => { - if pred(c) { - cur = next; - } else { - return cur; - } + Some((c, next)) if pred(c) => { + cur = next; } - None => return cur, + _ => return cur, } } } diff --git a/compiler/rustc_builtin_macros/src/offload.rs b/compiler/rustc_builtin_macros/src/offload.rs index 006332b8c40c9..d9304a978ccd4 100644 --- a/compiler/rustc_builtin_macros/src/offload.rs +++ b/compiler/rustc_builtin_macros/src/offload.rs @@ -144,7 +144,7 @@ pub(crate) fn expand_kernel( }); for param in host_fn.sig.decl.inputs.iter_mut() { - param.pat = Box::new(ecx.pat_wild(param.pat.span)); + *param.pat = ecx.pat_wild(param.pat.span); } // inline(never) attr diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index d327439ec6c83..5dc62298cccab 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -326,7 +326,7 @@ fn find_path_suggestion( break; } // base_dir may be absolute - while let Some(base_next) = base_c.next() { + for base_next in base_c.by_ref() { if base_next == wanted_next { without_base = Some(wanted_c.as_path()); break; @@ -371,5 +371,5 @@ fn find_path_suggestion( root_absolute .chain(add) .chain(remove) - .find(|new_path| source_map.file_exists(&base_dir.join(&new_path))) + .find(|new_path| source_map.file_exists(&base_dir.join(new_path))) } diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index bb725998c5947..a00023d8eb884 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -264,7 +264,7 @@ pub(crate) fn expand_test_or_bench( &fn_.ident, )); - let location_info = get_location_info(cx, &fn_); + let location_info = get_location_info(cx, fn_); let mut test_const = cx.item( diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index a39db94b4fe55..b8882f5a57aab 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -130,7 +130,7 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { } fn visit_item(&mut self, item: &mut ast::Item) { - if let Some(name) = get_test_name(&item) { + if let Some(name) = get_test_name(item) { debug!("this is a test item"); // `unwrap` is ok because only functions, consts, and static should reach here. @@ -151,7 +151,7 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { self.add_test_cases(item.id, span, prev_tests); } else { // But in those cases, we emit a lint to warn the user of these missing tests. - ast::visit::walk_item(&mut InnerItemLinter { sess: self.cx.ext_cx.sess }, &item); + ast::visit::walk_item(&mut InnerItemLinter { sess: self.cx.ext_cx.sess }, item); } } } @@ -202,7 +202,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> { // Remove any #[rustc_main] from the AST so it doesn't // clash with the one we're going to add, but mark it as // #[allow(dead_code)] to avoid printing warnings. - match entry_point_type(&item, self.depth == 0) { + match entry_point_type(item, self.depth == 0) { EntryPointType::RustcMainAttr => { let allow_dead_code = attr::mk_attr_nested_word( &self.sess.psess.attr_id_generator, From 7705a937efa90711fa28982707b7c8ee123f5140 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 20 Aug 2026 09:25:32 +0000 Subject: [PATCH 02/49] remove some unneeded `format!` uses --- .../src/deriving/clone.rs | 32 ++++++------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index af3db65bd0a63..12d2dbb419ba0 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -38,29 +38,26 @@ pub(crate) fn expand_deriving_clone( | ItemKind::Enum(_, Generics { params, .. }, _) => { let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); let has_derive_copy = cx.resolver.has_derive_copy(container_id); + bounds = vec![]; if has_derive_copy && !params .iter() .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) { - bounds = vec![]; is_simple = true; substructure = combine_substructure(Box::new(|c, s, sub| { - cs_clone_simple("Clone", c, s, sub, false) + cs_clone_simple(c, s, sub, false) })); } else { - bounds = vec![]; is_simple = false; - substructure = - combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub))); + substructure = combine_substructure(Box::new(cs_clone)); } } ItemKind::Union(..) => { bounds = vec![Path(path_std!(marker::Copy))]; is_simple = true; - substructure = combine_substructure(Box::new(|c, s, sub| { - cs_clone_simple("Clone", c, s, sub, true) - })); + substructure = + combine_substructure(Box::new(|c, s, sub| cs_clone_simple(c, s, sub, true))); } _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on wrong item kind"), }, @@ -119,7 +116,6 @@ pub(crate) fn expand_deriving_clone( } fn cs_clone_simple( - name: &str, cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>, @@ -172,21 +168,13 @@ fn cs_clone_simple( process_variant(&variant.data); } } - _ => cx.dcx().span_bug( - trait_span, - format!("unexpected substructure in simple `derive({name})`"), - ), + _ => cx.dcx().span_bug(trait_span, "unexpected substructure in simple `derive(Clone)`"), } } BlockOrExpr::new_mixed(stmts, Some(cx.expr_deref(trait_span, cx.expr_self(trait_span)))) } -fn cs_clone( - name: &str, - cx: &ExtCtxt<'_>, - trait_span: Span, - substr: &Substructure<'_>, -) -> BlockOrExpr { +fn cs_clone(cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>) -> BlockOrExpr { let ctor_path; let all_fields; let fn_path = cx.std_path(&[sym::clone, sym::Clone, sym::clone]); @@ -208,10 +196,10 @@ fn cs_clone( vdata = &variant.data; } EnumDiscr(..) | AllFieldlessEnum(..) => { - cx.dcx().span_bug(trait_span, format!("enum discriminants in `derive({name})`",)) + cx.dcx().span_bug(trait_span, "enum discriminants in `derive(Clone)`") } StaticEnum(..) | StaticStruct(..) => { - cx.dcx().span_bug(trait_span, format!("associated function in `derive({name})`")) + cx.dcx().span_bug(trait_span, "associated function in `derive(Clone)`") } } @@ -223,7 +211,7 @@ fn cs_clone( let Some(ident) = field.name else { cx.dcx().span_bug( trait_span, - format!("unnamed field in normal struct in `derive({name})`",), + "unnamed field in normal struct in `derive(Clone)`", ); }; let call = subcall(cx, field); From e94980b366ba4fa822c7168c1843a56007e24bfe Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 20 Aug 2026 09:30:36 +0000 Subject: [PATCH 03/49] create the `Box` inside of `combine_substructure` --- compiler/rustc_builtin_macros/src/deriving/clone.rs | 10 ++++------ compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs | 4 +--- compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs | 2 +- .../src/deriving/cmp/partial_eq.rs | 4 ++-- .../src/deriving/cmp/partial_ord.rs | 9 ++++----- compiler/rustc_builtin_macros/src/deriving/debug.rs | 4 +--- compiler/rustc_builtin_macros/src/deriving/default.rs | 4 ++-- compiler/rustc_builtin_macros/src/deriving/from.rs | 4 ++-- .../rustc_builtin_macros/src/deriving/generic/mod.rs | 8 ++++---- compiler/rustc_builtin_macros/src/deriving/hash.rs | 4 +--- 10 files changed, 22 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 12d2dbb419ba0..d2915de1f0829 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -45,19 +45,17 @@ pub(crate) fn expand_deriving_clone( .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) { is_simple = true; - substructure = combine_substructure(Box::new(|c, s, sub| { - cs_clone_simple(c, s, sub, false) - })); + substructure = + combine_substructure(|c, s, sub| cs_clone_simple(c, s, sub, false)); } else { is_simple = false; - substructure = combine_substructure(Box::new(cs_clone)); + substructure = combine_substructure(cs_clone); } } ItemKind::Union(..) => { bounds = vec![Path(path_std!(marker::Copy))]; is_simple = true; - substructure = - combine_substructure(Box::new(|c, s, sub| cs_clone_simple(c, s, sub, true))); + substructure = combine_substructure(|c, s, sub| cs_clone_simple(c, s, sub, true)); } _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on wrong item kind"), }, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 7520df43bf4cc..776e56b17efb0 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -39,9 +39,7 @@ pub(crate) fn expand_deriving_eq( cx.attr_nested_word(sym::coverage, sym::off, span), ], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - cs_total_eq_assert(a, b, c) - })), + combine_substructure: combine_substructure(cs_total_eq_assert), }], associated_types: Vec::new(), is_const, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 01bae641dbee6..35af63feef70a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -30,7 +30,7 @@ pub(crate) fn expand_deriving_ord( ret_ty: Path(path_std!(cmp::Ordering)), attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, - combine_substructure: combine_substructure(Box::new(cs_cmp)), + combine_substructure: combine_substructure(cs_cmp), }], associated_types: Vec::new(), is_const, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 8feb70fb5d21e..d9f6f8b4976fc 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -48,9 +48,9 @@ pub(crate) fn expand_deriving_partial_eq( ret_ty: Path(path_local!(bool)), attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, - combine_substructure: combine_substructure(Box::new(|a, b, c| { + combine_substructure: combine_substructure(|a, b, c| { BlockOrExpr::new_expr(get_substructure_equality_expr(a, b, c)) - })), + }), }]; let trait_def = TraitDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index d66d14bb881a1..7855ceb6a9423 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -49,12 +49,11 @@ pub(crate) fn expand_deriving_partial_ord( && !params.iter().any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) }; - let default_substructure = combine_substructure(Box::new(|cx, span, substr| { - cs_partial_cmp(cx, span, substr, discr_then_data) - })); - let simple_substructure = combine_substructure(Box::new(|cx, span, _| { + let default_substructure = + combine_substructure(|cx, span, substr| cs_partial_cmp(cx, span, substr, discr_then_data)); + let simple_substructure = combine_substructure(|cx, span, _| { cs_partial_cmp_simple(cx, span, cx.expr_ident(span, Ident::new(sym::other, span))) - })); + }); let (is_simple, substructure) = match item { Annotatable::Item(annitem) => match &annitem.kind { // For unit structs/zero-variant enums, the default generated code is better. diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index c41a4e4fd6b8d..38042d2080618 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -35,9 +35,7 @@ pub(crate) fn expand_deriving_debug( attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - show_substructure(a, b, c) - })), + combine_substructure: combine_substructure(show_substructure), }], associated_types: Vec::new(), is_const, diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index bbd83f71c0462..d059586d61afd 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -36,7 +36,7 @@ pub(crate) fn expand_deriving_default( ret_ty: Self_, attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Default, - combine_substructure: combine_substructure(Box::new(|cx, trait_span, substr| { + combine_substructure: combine_substructure(|cx, trait_span, substr| { match substr.fields { StaticStruct(_, fields) => { default_struct_substructure(cx, trait_span, substr, fields) @@ -46,7 +46,7 @@ pub(crate) fn expand_deriving_default( } _ => cx.dcx().span_bug(trait_span, "method in `derive(Default)`"), } - })), + }), }], associated_types: Vec::new(), is_const, diff --git a/compiler/rustc_builtin_macros/src/deriving/from.rs b/compiler/rustc_builtin_macros/src/deriving/from.rs index c5fd0d87251f6..7d3e79359f1c9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/from.rs +++ b/compiler/rustc_builtin_macros/src/deriving/from.rs @@ -88,7 +88,7 @@ pub(crate) fn expand_deriving_from( ret_ty: Ty::Self_, attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Default, - combine_substructure: combine_substructure(Box::new(|cx, span, substructure| { + combine_substructure: combine_substructure(|cx, span, substructure| { let field = match field { Ok(ref field) => field, Err(guar) => { @@ -122,7 +122,7 @@ pub(crate) fn expand_deriving_from( _ => cx.dcx().bug("Invalid derive(From) ADT input"), }; BlockOrExpr::new_expr(expr) - })), + }), }], associated_types: Vec::new(), is_const, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index a2bce479e22de..e05f6473db31d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -341,10 +341,10 @@ pub(crate) enum SubstructureFields<'a> { pub(crate) type CombineSubstructureFunc<'a> = Box, Span, &Substructure<'_>) -> BlockOrExpr + 'a>; -pub(crate) fn combine_substructure( - f: CombineSubstructureFunc<'_>, -) -> RefCell> { - RefCell::new(f) +pub(crate) fn combine_substructure<'a>( + f: impl FnMut(&ExtCtxt<'_>, Span, &Substructure<'_>) -> BlockOrExpr + 'a, +) -> RefCell> { + RefCell::new(Box::new(f)) } struct TypeParameter { diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index e18c8e1750d81..42a184a591710 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -35,9 +35,7 @@ pub(crate) fn expand_deriving_hash( ret_ty: Unit, attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - hash_substructure(a, b, c) - })), + combine_substructure: combine_substructure(hash_substructure), }], associated_types: Vec::new(), is_const, From a572603e36866e1c45bc2ea5ab71e6813776db78 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 20 Aug 2026 10:40:34 +0000 Subject: [PATCH 04/49] split `format_foreign.rs` into actual file modules --- .../src/format_foreign.rs | 817 +----------------- .../src/format_foreign/printf/mod.rs | 596 +++++++++++++ .../src/format_foreign/shell/mod.rs | 122 +++ 3 files changed, 762 insertions(+), 773 deletions(-) create mode 100644 compiler/rustc_builtin_macros/src/format_foreign/printf/mod.rs create mode 100644 compiler/rustc_builtin_macros/src/format_foreign/shell/mod.rs diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index 3b8181842b169..55c253befc73a 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -1,804 +1,75 @@ -pub(crate) mod printf { - use rustc_span::InnerSpan; +pub(crate) mod printf; - use super::strcursor::StrCursor as Cur; +pub(crate) mod shell; - /// Represents a single `printf`-style substitution. - #[derive(Clone, PartialEq, Debug)] - pub(crate) enum Substitution<'a> { - /// A formatted output substitution with its internal byte offset. - Format(Format<'a>), - /// A literal `%%` escape, with its start and end indices. - Escape((usize, usize)), - } - - impl ToString for Substitution<'_> { - fn to_string(&self) -> String { - match self { - Substitution::Format(fmt) => fmt.span.into(), - Substitution::Escape(_) => "%%".into(), - } - } - } - - impl Substitution<'_> { - pub(crate) fn position(&self) -> InnerSpan { - match self { - Substitution::Format(fmt) => fmt.position, - &Substitution::Escape((start, end)) => InnerSpan::new(start, end), - } - } - - pub(crate) fn set_position(&mut self, start: usize, end: usize) { - match self { - Substitution::Format(fmt) => fmt.position = InnerSpan::new(start, end), - Substitution::Escape(pos) => *pos = (start, end), - } - } - - /// Translate this substitution into an equivalent Rust formatting directive. - /// - /// This ignores cases where the substitution does not have an exact equivalent, or where - /// the substitution would be unnecessary. - pub(crate) fn translate(&self) -> Result> { - match self { - Substitution::Format(fmt) => fmt.translate(), - Substitution::Escape(_) => Err(None), - } - } - } - - #[derive(Clone, PartialEq, Debug)] - /// A single `printf`-style formatting directive. - pub(crate) struct Format<'a> { - /// The entire original formatting directive. - span: &'a str, - /// The (1-based) parameter to be converted. - parameter: Option, - /// Formatting flags. - flags: &'a str, - /// Minimum width of the output. - width: Option, - /// Precision of the conversion. - precision: Option, - /// Length modifier for the conversion. - length: Option<&'a str>, - /// Type of parameter being converted. - type_: &'a str, - /// Byte offset for the start and end of this formatting directive. - position: InnerSpan, - } - - impl Format<'_> { - /// Translate this directive into an equivalent Rust formatting directive. - /// - /// Returns `Err` in cases where the `printf` directive does not have an exact Rust - /// equivalent, rather than guessing. - pub(crate) fn translate(&self) -> Result> { - use std::fmt::Write; - - let (c_alt, c_zero, c_left, c_plus) = { - let mut c_alt = false; - let mut c_zero = false; - let mut c_left = false; - let mut c_plus = false; - for c in self.flags.chars() { - match c { - '#' => c_alt = true, - '0' => c_zero = true, - '-' => c_left = true, - '+' => c_plus = true, - _ => { - return Err(Some(format!("the flag `{c}` is unknown or unsupported"))); - } - } - } - (c_alt, c_zero, c_left, c_plus) - }; - - // Has a special form in Rust for numbers. - let fill = c_zero.then_some("0"); - - let align = c_left.then_some("<"); - - // Rust doesn't have an equivalent to the `' '` flag. - let sign = c_plus.then_some("+"); - - // Not *quite* the same, depending on the type... - let alt = c_alt; - - let width = match self.width { - Some(Num::Next) => { - // NOTE: Rust doesn't support this. - return Err(Some( - "you have to use a positional or named parameter for the width".to_string(), - )); - } - w @ Some(Num::Arg(_)) => w, - w @ Some(Num::Num(_)) => w, - None => None, - }; - - let precision = self.precision; - - // NOTE: although length *can* have an effect, we can't duplicate the effect in Rust, so - // we just ignore it. - - let (type_, use_zero_fill, is_int) = match self.type_ { - "d" | "i" | "u" => (None, true, true), - "f" | "F" => (None, false, false), - "s" | "c" => (None, false, false), - "e" | "E" => (Some(self.type_), true, false), - "x" | "X" | "o" => (Some(self.type_), true, true), - "p" => (Some(self.type_), false, true), - "g" => (Some("e"), true, false), - "G" => (Some("E"), true, false), - _ => { - return Err(Some(format!( - "the conversion specifier `{}` is unknown or unsupported", - self.type_ - ))); - } - }; - - let (fill, width, precision) = match (is_int, width, precision) { - (true, Some(_), Some(_)) => { - // Rust can't duplicate this insanity. - return Err(Some( - "width and precision cannot both be specified for integer conversions" - .to_string(), - )); - } - (true, None, Some(p)) => (Some("0"), Some(p), None), - (true, w, None) => (fill, w, None), - (false, w, p) => (fill, w, p), - }; - - let align = match (self.type_, width.is_some(), align.is_some()) { - ("s", true, false) => Some(">"), - _ => align, - }; - - let (fill, zero_fill) = match (fill, use_zero_fill) { - (Some("0"), true) => (None, true), - (fill, _) => (fill, false), - }; - - let alt = match type_ { - Some("x" | "X") => alt, - _ => false, - }; - - let has_options = fill.is_some() - || align.is_some() - || sign.is_some() - || alt - || zero_fill - || width.is_some() - || precision.is_some() - || type_.is_some(); - - // Initialise with a rough guess. - let cap = self.span.len() + if has_options { 2 } else { 0 }; - let mut s = String::with_capacity(cap); - - s.push('{'); - - if let Some(arg) = self.parameter { - write!(s, "{}", arg.checked_sub(1).ok_or(None)?).map_err(|_| None)?; - } - - if has_options { - s.push(':'); - - let align = if let Some(fill) = fill { - s.push_str(fill); - align.or(Some(">")) - } else { - align - }; - - if let Some(align) = align { - s.push_str(align); - } - - if let Some(sign) = sign { - s.push_str(sign); - } - - if alt { - s.push('#'); - } - - if zero_fill { - s.push('0'); - } - - if let Some(width) = width { - width.translate(&mut s).map_err(|_| None)?; - } - - if let Some(precision) = precision { - s.push('.'); - precision.translate(&mut s).map_err(|_| None)?; - } - - if let Some(type_) = type_ { - s.push_str(type_); - } - } - - s.push('}'); - Ok(s) - } - } - - /// A general number used in a `printf` formatting directive. - #[derive(Copy, Clone, PartialEq, Debug)] - enum Num { - // The range of these values is technically bounded by `NL_ARGMAX`... but, at least for GNU - // libc, it apparently has no real fixed limit. A `u16` is used here on the basis that it - // is *vanishingly* unlikely that *anyone* is going to try formatting something wider, or - // with more precision, than 32 thousand positions which is so wide it couldn't possibly fit - // on a screen. - /// A specific, fixed value. - Num(u16), - /// The value is derived from a positional argument. - Arg(u16), - /// The value is derived from the "next" unconverted argument. - Next, - } - - impl Num { - fn from_str(s: &str, arg: Option<&str>) -> Option { - if let Some(arg) = arg { - arg.parse().ok().map(Num::Arg) - } else if s == "*" { - Some(Num::Next) - } else { - s.parse().ok().map(Num::Num) - } - } - - fn translate(&self, s: &mut String) -> std::fmt::Result { - use std::fmt::Write; - match *self { - Num::Num(n) => write!(s, "{n}"), - Num::Arg(n) => { - let n = n.checked_sub(1).ok_or(std::fmt::Error)?; - write!(s, "{n}$") - } - Num::Next => write!(s, "*"), - } - } - } - - /// Returns an iterator over all substitutions in a given string. - pub(crate) fn iter_subs(s: &str, start_pos: usize) -> Substitutions<'_> { - Substitutions { s, pos: start_pos } - } - - /// Iterator over substitutions in a string. - pub(crate) struct Substitutions<'a> { - s: &'a str, - pos: usize, - } - - impl<'a> Iterator for Substitutions<'a> { - type Item = Substitution<'a>; - fn next(&mut self) -> Option { - let (mut sub, tail) = parse_next_substitution(self.s)?; - self.s = tail; - let InnerSpan { start, end } = sub.position(); - sub.set_position(start + self.pos, end + self.pos); - self.pos += end; - Some(sub) - } - - fn size_hint(&self) -> (usize, Option) { - // Substitutions are at least 2 characters long. - (0, Some(self.s.len() / 2)) - } - } - - enum State { - Start, - Flags, - Width, - WidthArg, - Prec, - PrecInner, - Length, - Type, - } - - /// Parse the next substitution from the input string. - fn parse_next_substitution(s: &str) -> Option<(Substitution<'_>, &str)> { - use self::State::*; - - let at = { - let start = s.find('%')?; - if let '%' = s[start + 1..].chars().next()? { - return Some((Substitution::Escape((start, start + 2)), &s[start + 2..])); - } - - Cur::new_at(s, start) - }; - - // This is meant to be a translation of the following regex: - // - // ```regex - // (?x) - // ^ % - // (?: (?Box \d+) \$ )? - // (?Box [-+ 0\#']* ) - // (?Box \d+ | \* (?: (?Box \d+) \$ )? )? - // (?: \. (?Box \d+ | \* (?: (?Box \d+) \$ )? ) )? - // (?Box - // # Standard - // hh | h | ll | l | L | z | j | t - // - // # Other - // | I32 | I64 | I | q - // )? - // (?Box . ) - // ``` - - // Used to establish the full span at the end. - let start = at; - // The current position within the string. - let mut at = at.at_next_cp()?; - // `c` is the next codepoint, `next` is a cursor after it. - let (mut c, mut next) = at.next_cp()?; - - // Update `at`, `c`, and `next`, exiting if we're out of input. - macro_rules! move_to { - ($cur:expr) => {{ - at = $cur; - let (c_, next_) = at.next_cp()?; - c = c_; - next = next_; - }}; - } - - // Constructs a result when parsing fails. - // - // Note: `move` used to capture copies of the cursors as they are *now*. - let fallback = move || { - Some(( - Substitution::Format(Format { - span: start.slice_between(next).unwrap(), - parameter: None, - flags: "", - width: None, - precision: None, - length: None, - type_: at.slice_between(next).unwrap(), - position: InnerSpan::new(start.at, next.at), - }), - next.slice_after(), - )) - }; - - // Next parsing state. - let mut state = Start; - - // Sadly, Rust isn't *quite* smart enough to know these *must* be initialised by the end. - let mut parameter: Option = None; - let mut flags: &str = ""; - let mut width: Option = None; - let mut precision: Option = None; - let mut length: Option<&str> = None; - let mut type_: &str = ""; - let end: Cur<'_>; - - if let Start = state { - match c { - '1'..='9' => { - let end = at_next_cp_while(next, char::is_ascii_digit); - match end.next_cp() { - // Yes, this *is* the parameter. - Some(('$', end2)) => { - state = Flags; - parameter = at.slice_between(end).unwrap().parse().ok(); - move_to!(end2); - } - // Wait, no, actually, it's the width. - Some(_) => { - state = Prec; - parameter = None; - flags = ""; - width = at.slice_between(end).and_then(|num| Num::from_str(num, None)); - if width.is_none() { - return fallback(); - } - move_to!(end); - } - // It's invalid, is what it is. - None => return fallback(), - } - } - _ => { - state = Flags; - parameter = None; - move_to!(at); - } - } - } - - if let Flags = state { - let end = at_next_cp_while(at, is_flag); - state = Width; - flags = at.slice_between(end).unwrap(); - move_to!(end); - } - - if let Width = state { - match c { - '*' => { - state = WidthArg; - move_to!(next); - } - '1'..='9' => { - let end = at_next_cp_while(next, char::is_ascii_digit); - state = Prec; - width = at.slice_between(end).and_then(|num| Num::from_str(num, None)); - if width.is_none() { - return fallback(); - } - move_to!(end); - } - _ => { - state = Prec; - width = None; - move_to!(at); - } - } - } - - if let WidthArg = state { - let end = at_next_cp_while(at, char::is_ascii_digit); - match end.next_cp() { - Some(('$', end2)) => { - state = Prec; - width = Num::from_str("", at.slice_between(end)); - move_to!(end2); - } - _ => { - state = Prec; - width = Some(Num::Next); - move_to!(end); - } - } - } - - if let Prec = state { - match c { - '.' => { - state = PrecInner; - move_to!(next); - } - _ => { - state = Length; - precision = None; - move_to!(at); - } - } - } - - if let PrecInner = state { - match c { - '*' => { - let end = at_next_cp_while(next, char::is_ascii_digit); - match end.next_cp() { - Some(('$', end2)) => { - state = Length; - precision = Num::from_str("*", next.slice_between(end)); - move_to!(end2); - } - _ => { - state = Length; - precision = Some(Num::Next); - move_to!(end); - } - } - } - '0'..='9' => { - let end = at_next_cp_while(next, char::is_ascii_digit); - state = Length; - precision = at.slice_between(end).and_then(|num| Num::from_str(num, None)); - move_to!(end); - } - _ => return fallback(), - } - } - - if let Length = state { - let c1_next1 = next.next_cp(); - match (c, c1_next1) { - ('h', Some(('h', next1))) | ('l', Some(('l', next1))) => { - state = Type; - length = Some(at.slice_between(next1).unwrap()); - move_to!(next1); - } - - ('h' | 'l' | 'L' | 'z' | 'j' | 't' | 'q', _) => { - state = Type; - length = Some(at.slice_between(next).unwrap()); - move_to!(next); - } - - ('I', _) => { - let end = next - .at_next_cp() - .and_then(|end| end.at_next_cp()) - .map(|end| (next.slice_between(end).unwrap(), end)); - let end = match end { - Some(("32" | "64", end)) => end, - _ => next, - }; - state = Type; - length = Some(at.slice_between(end).unwrap()); - move_to!(end); - } - - _ => { - state = Type; - length = None; - move_to!(at); - } - } - } - - if let Type = state { - type_ = at.slice_between(next).unwrap(); - - // Don't use `move_to!` here, as we *can* be at the end of the input. - at = next; - } - - let _ = c; // to avoid never used value - - end = at; - let position = InnerSpan::new(start.at, end.at); - - let f = Format { - span: start.slice_between(end).unwrap(), - parameter, - flags, - width, - precision, - length, - type_, - position, - }; - Some((Substitution::Format(f), end.slice_after())) - } - - fn at_next_cp_while(mut cur: Cur<'_>, mut pred: F) -> Cur<'_> - where - F: FnMut(&char) -> bool, - { - loop { - match cur.next_cp() { - Some((c, next)) if pred(&c) => { - cur = next; - } - _ => return cur, - } - } - } - - fn is_flag(c: &char) -> bool { - matches!(c, '0' | '-' | '+' | ' ' | '#' | '\'') - } - - #[cfg(test)] - mod tests; +#[derive(Clone, Copy)] +struct StrCursor<'a> { + s: &'a str, + pub at: usize, } -pub(crate) mod shell { - use rustc_span::InnerSpan; - - use super::strcursor::StrCursor as Cur; - - #[derive(Clone, PartialEq, Debug)] - pub(crate) enum Substitution<'a> { - Ordinal(u8, (usize, usize)), - Name(&'a str, (usize, usize)), - Escape((usize, usize)), - } - - impl ToString for Substitution<'_> { - fn to_string(&self) -> String { - match self { - Substitution::Ordinal(n, _) => format!("${n}"), - Substitution::Name(n, _) => format!("${n}"), - Substitution::Escape(_) => "$$".into(), - } - } +impl<'a> StrCursor<'a> { + fn new_at(s: &'a str, at: usize) -> StrCursor<'a> { + StrCursor { s, at } } - impl Substitution<'_> { - pub(crate) fn position(&self) -> InnerSpan { - let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self; - InnerSpan::new(pos.0, pos.1) - } - - fn set_position(&mut self, start: usize, end: usize) { - let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self; - *pos = (start, end); - } - - pub(crate) fn translate(&self) -> Result> { - match self { - Substitution::Ordinal(n, _) => Ok(format!("{{{}}}", n)), - Substitution::Name(n, _) => Ok(format!("{{{}}}", n)), - Substitution::Escape(_) => Err(None), - } + fn at_next_cp(mut self) -> Option> { + match self.try_seek_right_cp() { + true => Some(self), + false => None, } } - /// Returns an iterator over all substitutions in a given string. - pub(crate) fn iter_subs(s: &str, start_pos: usize) -> Substitutions<'_> { - Substitutions { s, pos: start_pos } + fn next_cp(mut self) -> Option<(char, StrCursor<'a>)> { + let cp = self.cp_after()?; + self.seek_right(cp.len_utf8()); + Some((cp, self)) } - /// Iterator over substitutions in a string. - pub(crate) struct Substitutions<'a> { - s: &'a str, - pos: usize, + fn slice_before(&self) -> &'a str { + &self.s[0..self.at] } - impl<'a> Iterator for Substitutions<'a> { - type Item = Substitution<'a>; - fn next(&mut self) -> Option { - let (mut sub, tail) = parse_next_substitution(self.s)?; - self.s = tail; - let InnerSpan { start, end } = sub.position(); - sub.set_position(start + self.pos, end + self.pos); - self.pos += end; - Some(sub) - } - - fn size_hint(&self) -> (usize, Option) { - (0, Some(self.s.len())) - } + fn slice_after(&self) -> &'a str { + &self.s[self.at..] } - /// Parse the next substitution from the input string. - fn parse_next_substitution(s: &str) -> Option<(Substitution<'_>, &str)> { - let at = { - let start = s.find('$')?; - match s[start + 1..].chars().next()? { - '$' => return Some((Substitution::Escape((start, start + 2)), &s[start + 2..])), - c @ '0'..='9' => { - let n = (c as u8) - b'0'; - return Some((Substitution::Ordinal(n, (start, start + 2)), &s[start + 2..])); - } - _ => { /* fall-through */ } - } - - Cur::new_at(s, start) - }; - - let at = at.at_next_cp()?; - let (c, inner) = at.next_cp()?; - - if !is_ident_head(c) { + fn slice_between(&self, until: StrCursor<'a>) -> Option<&'a str> { + if !str_eq_literal(self.s, until.s) { None } else { - let end = at_next_cp_while(inner, is_ident_tail); - let slice = at.slice_between(end).unwrap(); - let start = at.at - 1; - let end_pos = at.at + slice.len(); - Some((Substitution::Name(slice, (start, end_pos)), end.slice_after())) + use std::cmp::{max, min}; + let beg = min(self.at, until.at); + let end = max(self.at, until.at); + Some(&self.s[beg..end]) } } - fn at_next_cp_while(mut cur: Cur<'_>, mut pred: F) -> Cur<'_> - where - F: FnMut(char) -> bool, - { - loop { - match cur.next_cp() { - Some((c, next)) if pred(c) => { - cur = next; - } - _ => return cur, - } - } + fn cp_after(&self) -> Option { + self.slice_after().chars().next() } - fn is_ident_head(c: char) -> bool { - c.is_ascii_alphabetic() || c == '_' - } - - fn is_ident_tail(c: char) -> bool { - c.is_ascii_alphanumeric() || c == '_' - } - - #[cfg(test)] - mod tests; -} - -mod strcursor { - pub(crate) struct StrCursor<'a> { - s: &'a str, - pub at: usize, - } - - impl<'a> StrCursor<'a> { - pub(crate) fn new_at(s: &'a str, at: usize) -> StrCursor<'a> { - StrCursor { s, at } - } - - pub(crate) fn at_next_cp(mut self) -> Option> { - match self.try_seek_right_cp() { - true => Some(self), - false => None, - } - } - - pub(crate) fn next_cp(mut self) -> Option<(char, StrCursor<'a>)> { - let cp = self.cp_after()?; - self.seek_right(cp.len_utf8()); - Some((cp, self)) - } - - fn slice_before(&self) -> &'a str { - &self.s[0..self.at] - } - - pub(crate) fn slice_after(&self) -> &'a str { - &self.s[self.at..] - } - - pub(crate) fn slice_between(&self, until: StrCursor<'a>) -> Option<&'a str> { - if !str_eq_literal(self.s, until.s) { - None - } else { - use std::cmp::{max, min}; - let beg = min(self.at, until.at); - let end = max(self.at, until.at); - Some(&self.s[beg..end]) + fn try_seek_right_cp(&mut self) -> bool { + match self.slice_after().chars().next() { + Some(c) => { + self.at += c.len_utf8(); + true } - } - - fn cp_after(&self) -> Option { - self.slice_after().chars().next() - } - - fn try_seek_right_cp(&mut self) -> bool { - match self.slice_after().chars().next() { - Some(c) => { - self.at += c.len_utf8(); - true - } - None => false, - } - } - - fn seek_right(&mut self, bytes: usize) { - self.at += bytes; + None => false, } } - impl Copy for StrCursor<'_> {} - - impl<'a> Clone for StrCursor<'a> { - fn clone(&self) -> StrCursor<'a> { - *self - } + fn seek_right(&mut self, bytes: usize) { + self.at += bytes; } +} - impl std::fmt::Debug for StrCursor<'_> { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(fmt, "StrCursor({:?} | {:?})", self.slice_before(), self.slice_after()) - } +impl std::fmt::Debug for StrCursor<'_> { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(fmt, "StrCursor({:?} | {:?})", self.slice_before(), self.slice_after()) } +} - fn str_eq_literal(a: &str, b: &str) -> bool { - a.as_bytes().as_ptr() == b.as_bytes().as_ptr() && a.len() == b.len() - } +fn str_eq_literal(a: &str, b: &str) -> bool { + a.as_bytes().as_ptr() == b.as_bytes().as_ptr() && a.len() == b.len() } diff --git a/compiler/rustc_builtin_macros/src/format_foreign/printf/mod.rs b/compiler/rustc_builtin_macros/src/format_foreign/printf/mod.rs new file mode 100644 index 0000000000000..602db4379af5f --- /dev/null +++ b/compiler/rustc_builtin_macros/src/format_foreign/printf/mod.rs @@ -0,0 +1,596 @@ +use rustc_span::InnerSpan; + +use super::StrCursor as Cur; + +/// Represents a single `printf`-style substitution. +#[derive(Clone, PartialEq, Debug)] +pub(crate) enum Substitution<'a> { + /// A formatted output substitution with its internal byte offset. + Format(Format<'a>), + /// A literal `%%` escape, with its start and end indices. + Escape((usize, usize)), +} + +impl ToString for Substitution<'_> { + fn to_string(&self) -> String { + match self { + Substitution::Format(fmt) => fmt.span.into(), + Substitution::Escape(_) => "%%".into(), + } + } +} + +impl Substitution<'_> { + pub(crate) fn position(&self) -> InnerSpan { + match self { + Substitution::Format(fmt) => fmt.position, + &Substitution::Escape((start, end)) => InnerSpan::new(start, end), + } + } + + pub(crate) fn set_position(&mut self, start: usize, end: usize) { + match self { + Substitution::Format(fmt) => fmt.position = InnerSpan::new(start, end), + Substitution::Escape(pos) => *pos = (start, end), + } + } + + /// Translate this substitution into an equivalent Rust formatting directive. + /// + /// This ignores cases where the substitution does not have an exact equivalent, or where + /// the substitution would be unnecessary. + pub(crate) fn translate(&self) -> Result> { + match self { + Substitution::Format(fmt) => fmt.translate(), + Substitution::Escape(_) => Err(None), + } + } +} + +#[derive(Clone, PartialEq, Debug)] +/// A single `printf`-style formatting directive. +pub(crate) struct Format<'a> { + /// The entire original formatting directive. + span: &'a str, + /// The (1-based) parameter to be converted. + parameter: Option, + /// Formatting flags. + flags: &'a str, + /// Minimum width of the output. + width: Option, + /// Precision of the conversion. + precision: Option, + /// Length modifier for the conversion. + length: Option<&'a str>, + /// Type of parameter being converted. + type_: &'a str, + /// Byte offset for the start and end of this formatting directive. + position: InnerSpan, +} + +impl Format<'_> { + /// Translate this directive into an equivalent Rust formatting directive. + /// + /// Returns `Err` in cases where the `printf` directive does not have an exact Rust + /// equivalent, rather than guessing. + pub(crate) fn translate(&self) -> Result> { + use std::fmt::Write; + + let (c_alt, c_zero, c_left, c_plus) = { + let mut c_alt = false; + let mut c_zero = false; + let mut c_left = false; + let mut c_plus = false; + for c in self.flags.chars() { + match c { + '#' => c_alt = true, + '0' => c_zero = true, + '-' => c_left = true, + '+' => c_plus = true, + _ => { + return Err(Some(format!("the flag `{c}` is unknown or unsupported"))); + } + } + } + (c_alt, c_zero, c_left, c_plus) + }; + + // Has a special form in Rust for numbers. + let fill = c_zero.then_some("0"); + + let align = c_left.then_some("<"); + + // Rust doesn't have an equivalent to the `' '` flag. + let sign = c_plus.then_some("+"); + + // Not *quite* the same, depending on the type... + let alt = c_alt; + + let width = match self.width { + Some(Num::Next) => { + // NOTE: Rust doesn't support this. + return Err(Some( + "you have to use a positional or named parameter for the width".to_string(), + )); + } + w @ Some(Num::Arg(_)) => w, + w @ Some(Num::Num(_)) => w, + None => None, + }; + + let precision = self.precision; + + // NOTE: although length *can* have an effect, we can't duplicate the effect in Rust, so + // we just ignore it. + + let (type_, use_zero_fill, is_int) = match self.type_ { + "d" | "i" | "u" => (None, true, true), + "f" | "F" => (None, false, false), + "s" | "c" => (None, false, false), + "e" | "E" => (Some(self.type_), true, false), + "x" | "X" | "o" => (Some(self.type_), true, true), + "p" => (Some(self.type_), false, true), + "g" => (Some("e"), true, false), + "G" => (Some("E"), true, false), + _ => { + return Err(Some(format!( + "the conversion specifier `{}` is unknown or unsupported", + self.type_ + ))); + } + }; + + let (fill, width, precision) = match (is_int, width, precision) { + (true, Some(_), Some(_)) => { + // Rust can't duplicate this insanity. + return Err(Some( + "width and precision cannot both be specified for integer conversions" + .to_string(), + )); + } + (true, None, Some(p)) => (Some("0"), Some(p), None), + (true, w, None) => (fill, w, None), + (false, w, p) => (fill, w, p), + }; + + let align = match (self.type_, width.is_some(), align.is_some()) { + ("s", true, false) => Some(">"), + _ => align, + }; + + let (fill, zero_fill) = match (fill, use_zero_fill) { + (Some("0"), true) => (None, true), + (fill, _) => (fill, false), + }; + + let alt = match type_ { + Some("x" | "X") => alt, + _ => false, + }; + + let has_options = fill.is_some() + || align.is_some() + || sign.is_some() + || alt + || zero_fill + || width.is_some() + || precision.is_some() + || type_.is_some(); + + // Initialise with a rough guess. + let cap = self.span.len() + if has_options { 2 } else { 0 }; + let mut s = String::with_capacity(cap); + + s.push('{'); + + if let Some(arg) = self.parameter { + write!(s, "{}", arg.checked_sub(1).ok_or(None)?).map_err(|_| None)?; + } + + if has_options { + s.push(':'); + + let align = if let Some(fill) = fill { + s.push_str(fill); + align.or(Some(">")) + } else { + align + }; + + if let Some(align) = align { + s.push_str(align); + } + + if let Some(sign) = sign { + s.push_str(sign); + } + + if alt { + s.push('#'); + } + + if zero_fill { + s.push('0'); + } + + if let Some(width) = width { + width.translate(&mut s).map_err(|_| None)?; + } + + if let Some(precision) = precision { + s.push('.'); + precision.translate(&mut s).map_err(|_| None)?; + } + + if let Some(type_) = type_ { + s.push_str(type_); + } + } + + s.push('}'); + Ok(s) + } +} + +/// A general number used in a `printf` formatting directive. +#[derive(Copy, Clone, PartialEq, Debug)] +enum Num { + // The range of these values is technically bounded by `NL_ARGMAX`... but, at least for GNU + // libc, it apparently has no real fixed limit. A `u16` is used here on the basis that it + // is *vanishingly* unlikely that *anyone* is going to try formatting something wider, or + // with more precision, than 32 thousand positions which is so wide it couldn't possibly fit + // on a screen. + /// A specific, fixed value. + Num(u16), + /// The value is derived from a positional argument. + Arg(u16), + /// The value is derived from the "next" unconverted argument. + Next, +} + +impl Num { + fn from_str(s: &str, arg: Option<&str>) -> Option { + if let Some(arg) = arg { + arg.parse().ok().map(Num::Arg) + } else if s == "*" { + Some(Num::Next) + } else { + s.parse().ok().map(Num::Num) + } + } + + fn translate(&self, s: &mut String) -> std::fmt::Result { + use std::fmt::Write; + match *self { + Num::Num(n) => write!(s, "{n}"), + Num::Arg(n) => { + let n = n.checked_sub(1).ok_or(std::fmt::Error)?; + write!(s, "{n}$") + } + Num::Next => write!(s, "*"), + } + } +} + +/// Returns an iterator over all substitutions in a given string. +pub(crate) fn iter_subs(s: &str, start_pos: usize) -> Substitutions<'_> { + Substitutions { s, pos: start_pos } +} + +/// Iterator over substitutions in a string. +pub(crate) struct Substitutions<'a> { + s: &'a str, + pos: usize, +} + +impl<'a> Iterator for Substitutions<'a> { + type Item = Substitution<'a>; + fn next(&mut self) -> Option { + let (mut sub, tail) = parse_next_substitution(self.s)?; + self.s = tail; + let InnerSpan { start, end } = sub.position(); + sub.set_position(start + self.pos, end + self.pos); + self.pos += end; + Some(sub) + } + + fn size_hint(&self) -> (usize, Option) { + // Substitutions are at least 2 characters long. + (0, Some(self.s.len() / 2)) + } +} + +enum State { + Start, + Flags, + Width, + WidthArg, + Prec, + PrecInner, + Length, + Type, +} + +/// Parse the next substitution from the input string. +fn parse_next_substitution(s: &str) -> Option<(Substitution<'_>, &str)> { + use self::State::*; + + let at = { + let start = s.find('%')?; + if let '%' = s[start + 1..].chars().next()? { + return Some((Substitution::Escape((start, start + 2)), &s[start + 2..])); + } + + Cur::new_at(s, start) + }; + + // This is meant to be a translation of the following regex: + // + // ```regex + // (?x) + // ^ % + // (?: (?Box \d+) \$ )? + // (?Box [-+ 0\#']* ) + // (?Box \d+ | \* (?: (?Box \d+) \$ )? )? + // (?: \. (?Box \d+ | \* (?: (?Box \d+) \$ )? ) )? + // (?Box + // # Standard + // hh | h | ll | l | L | z | j | t + // + // # Other + // | I32 | I64 | I | q + // )? + // (?Box . ) + // ``` + + // Used to establish the full span at the end. + let start = at; + // The current position within the string. + let mut at = at.at_next_cp()?; + // `c` is the next codepoint, `next` is a cursor after it. + let (mut c, mut next) = at.next_cp()?; + + // Update `at`, `c`, and `next`, exiting if we're out of input. + macro_rules! move_to { + ($cur:expr) => {{ + at = $cur; + let (c_, next_) = at.next_cp()?; + c = c_; + next = next_; + }}; + } + + // Constructs a result when parsing fails. + // + // Note: `move` used to capture copies of the cursors as they are *now*. + let fallback = move || { + Some(( + Substitution::Format(Format { + span: start.slice_between(next).unwrap(), + parameter: None, + flags: "", + width: None, + precision: None, + length: None, + type_: at.slice_between(next).unwrap(), + position: InnerSpan::new(start.at, next.at), + }), + next.slice_after(), + )) + }; + + // Next parsing state. + let mut state = Start; + + // Sadly, Rust isn't *quite* smart enough to know these *must* be initialised by the end. + let mut parameter: Option = None; + let mut flags: &str = ""; + let mut width: Option = None; + let mut precision: Option = None; + let mut length: Option<&str> = None; + let mut type_: &str = ""; + let end: Cur<'_>; + + if let Start = state { + match c { + '1'..='9' => { + let end = at_next_cp_while(next, char::is_ascii_digit); + match end.next_cp() { + // Yes, this *is* the parameter. + Some(('$', end2)) => { + state = Flags; + parameter = at.slice_between(end).unwrap().parse().ok(); + move_to!(end2); + } + // Wait, no, actually, it's the width. + Some(_) => { + state = Prec; + parameter = None; + flags = ""; + width = at.slice_between(end).and_then(|num| Num::from_str(num, None)); + if width.is_none() { + return fallback(); + } + move_to!(end); + } + // It's invalid, is what it is. + None => return fallback(), + } + } + _ => { + state = Flags; + parameter = None; + move_to!(at); + } + } + } + + if let Flags = state { + let end = at_next_cp_while(at, is_flag); + state = Width; + flags = at.slice_between(end).unwrap(); + move_to!(end); + } + + if let Width = state { + match c { + '*' => { + state = WidthArg; + move_to!(next); + } + '1'..='9' => { + let end = at_next_cp_while(next, char::is_ascii_digit); + state = Prec; + width = at.slice_between(end).and_then(|num| Num::from_str(num, None)); + if width.is_none() { + return fallback(); + } + move_to!(end); + } + _ => { + state = Prec; + width = None; + move_to!(at); + } + } + } + + if let WidthArg = state { + let end = at_next_cp_while(at, char::is_ascii_digit); + match end.next_cp() { + Some(('$', end2)) => { + state = Prec; + width = Num::from_str("", at.slice_between(end)); + move_to!(end2); + } + _ => { + state = Prec; + width = Some(Num::Next); + move_to!(end); + } + } + } + + if let Prec = state { + match c { + '.' => { + state = PrecInner; + move_to!(next); + } + _ => { + state = Length; + precision = None; + move_to!(at); + } + } + } + + if let PrecInner = state { + match c { + '*' => { + let end = at_next_cp_while(next, char::is_ascii_digit); + match end.next_cp() { + Some(('$', end2)) => { + state = Length; + precision = Num::from_str("*", next.slice_between(end)); + move_to!(end2); + } + _ => { + state = Length; + precision = Some(Num::Next); + move_to!(end); + } + } + } + '0'..='9' => { + let end = at_next_cp_while(next, char::is_ascii_digit); + state = Length; + precision = at.slice_between(end).and_then(|num| Num::from_str(num, None)); + move_to!(end); + } + _ => return fallback(), + } + } + + if let Length = state { + let c1_next1 = next.next_cp(); + match (c, c1_next1) { + ('h', Some(('h', next1))) | ('l', Some(('l', next1))) => { + state = Type; + length = Some(at.slice_between(next1).unwrap()); + move_to!(next1); + } + + ('h' | 'l' | 'L' | 'z' | 'j' | 't' | 'q', _) => { + state = Type; + length = Some(at.slice_between(next).unwrap()); + move_to!(next); + } + + ('I', _) => { + let end = next + .at_next_cp() + .and_then(|end| end.at_next_cp()) + .map(|end| (next.slice_between(end).unwrap(), end)); + let end = match end { + Some(("32" | "64", end)) => end, + _ => next, + }; + state = Type; + length = Some(at.slice_between(end).unwrap()); + move_to!(end); + } + + _ => { + state = Type; + length = None; + move_to!(at); + } + } + } + + if let Type = state { + type_ = at.slice_between(next).unwrap(); + + // Don't use `move_to!` here, as we *can* be at the end of the input. + at = next; + } + + let _ = c; // to avoid never used value + + end = at; + let position = InnerSpan::new(start.at, end.at); + + let f = Format { + span: start.slice_between(end).unwrap(), + parameter, + flags, + width, + precision, + length, + type_, + position, + }; + Some((Substitution::Format(f), end.slice_after())) +} + +fn at_next_cp_while(mut cur: Cur<'_>, mut pred: F) -> Cur<'_> +where + F: FnMut(&char) -> bool, +{ + loop { + match cur.next_cp() { + Some((c, next)) if pred(&c) => { + cur = next; + } + _ => return cur, + } + } +} + +fn is_flag(c: &char) -> bool { + matches!(c, '0' | '-' | '+' | ' ' | '#' | '\'') +} + +#[cfg(test)] +mod tests; diff --git a/compiler/rustc_builtin_macros/src/format_foreign/shell/mod.rs b/compiler/rustc_builtin_macros/src/format_foreign/shell/mod.rs new file mode 100644 index 0000000000000..d40cce2c570c5 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/format_foreign/shell/mod.rs @@ -0,0 +1,122 @@ +use rustc_span::InnerSpan; + +use super::StrCursor as Cur; + +#[derive(Clone, PartialEq, Debug)] +pub(crate) enum Substitution<'a> { + Ordinal(u8, (usize, usize)), + Name(&'a str, (usize, usize)), + Escape((usize, usize)), +} + +impl ToString for Substitution<'_> { + fn to_string(&self) -> String { + match self { + Substitution::Ordinal(n, _) => format!("${n}"), + Substitution::Name(n, _) => format!("${n}"), + Substitution::Escape(_) => "$$".into(), + } + } +} + +impl Substitution<'_> { + pub(crate) fn position(&self) -> InnerSpan { + let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self; + InnerSpan::new(pos.0, pos.1) + } + + fn set_position(&mut self, start: usize, end: usize) { + let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self; + *pos = (start, end); + } + + pub(crate) fn translate(&self) -> Result> { + match self { + Substitution::Ordinal(n, _) => Ok(format!("{{{}}}", n)), + Substitution::Name(n, _) => Ok(format!("{{{}}}", n)), + Substitution::Escape(_) => Err(None), + } + } +} + +/// Returns an iterator over all substitutions in a given string. +pub(crate) fn iter_subs(s: &str, start_pos: usize) -> Substitutions<'_> { + Substitutions { s, pos: start_pos } +} + +/// Iterator over substitutions in a string. +pub(crate) struct Substitutions<'a> { + s: &'a str, + pos: usize, +} + +impl<'a> Iterator for Substitutions<'a> { + type Item = Substitution<'a>; + fn next(&mut self) -> Option { + let (mut sub, tail) = parse_next_substitution(self.s)?; + self.s = tail; + let InnerSpan { start, end } = sub.position(); + sub.set_position(start + self.pos, end + self.pos); + self.pos += end; + Some(sub) + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.s.len())) + } +} + +/// Parse the next substitution from the input string. +fn parse_next_substitution(s: &str) -> Option<(Substitution<'_>, &str)> { + let at = { + let start = s.find('$')?; + match s[start + 1..].chars().next()? { + '$' => return Some((Substitution::Escape((start, start + 2)), &s[start + 2..])), + c @ '0'..='9' => { + let n = (c as u8) - b'0'; + return Some((Substitution::Ordinal(n, (start, start + 2)), &s[start + 2..])); + } + _ => { /* fall-through */ } + } + + Cur::new_at(s, start) + }; + + let at = at.at_next_cp()?; + let (c, inner) = at.next_cp()?; + + if !is_ident_head(c) { + None + } else { + let end = at_next_cp_while(inner, is_ident_tail); + let slice = at.slice_between(end).unwrap(); + let start = at.at - 1; + let end_pos = at.at + slice.len(); + Some((Substitution::Name(slice, (start, end_pos)), end.slice_after())) + } +} + +fn at_next_cp_while(mut cur: Cur<'_>, mut pred: F) -> Cur<'_> +where + F: FnMut(char) -> bool, +{ + loop { + match cur.next_cp() { + Some((c, next)) if pred(c) => { + cur = next; + } + _ => return cur, + } + } +} + +fn is_ident_head(c: char) -> bool { + c.is_ascii_alphabetic() || c == '_' +} + +fn is_ident_tail(c: char) -> bool { + c.is_ascii_alphanumeric() || c == '_' +} + +#[cfg(test)] +mod tests; From 2ea3197d68fb8a3f822972d546881efe827f75a0 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 20 Aug 2026 10:59:39 +0000 Subject: [PATCH 05/49] inline `is_staged_api_crate` --- compiler/rustc_builtin_macros/src/deriving/bounds.rs | 2 -- compiler/rustc_builtin_macros/src/deriving/clone.rs | 2 -- compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs | 1 - compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs | 1 - compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs | 2 -- compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs | 1 - compiler/rustc_builtin_macros/src/deriving/debug.rs | 1 - compiler/rustc_builtin_macros/src/deriving/default.rs | 1 - compiler/rustc_builtin_macros/src/deriving/from.rs | 1 - compiler/rustc_builtin_macros/src/deriving/generic/mod.rs | 4 +--- compiler/rustc_builtin_macros/src/deriving/hash.rs | 1 - 11 files changed, 1 insertion(+), 16 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 06b0d0512e700..11e4eb2c55faa 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -23,7 +23,6 @@ pub(crate) fn expand_deriving_copy( methods: Vec::new(), associated_types: Vec::new(), is_const, - is_staged_api_crate: cx.ecfg.features.staged_api(), safety: Safety::Default, document: true, }; @@ -49,7 +48,6 @@ pub(crate) fn expand_deriving_const_param_ty( methods: Vec::new(), associated_types: Vec::new(), is_const, - is_staged_api_crate: cx.ecfg.features.staged_api(), safety: Safety::Default, document: true, }; diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index d2915de1f0829..4cc466b74f4c5 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -76,7 +76,6 @@ pub(crate) fn expand_deriving_clone( methods: Vec::new(), associated_types: Vec::new(), is_const, - is_staged_api_crate: cx.ecfg.features.staged_api(), safety: Safety::Unsafe(DUMMY_SP), // `TrivialClone` is not part of an API guarantee, so it shouldn't // appear in rustdoc output. @@ -105,7 +104,6 @@ pub(crate) fn expand_deriving_clone( }], associated_types: Vec::new(), is_const, - is_staged_api_crate: cx.ecfg.features.staged_api(), safety: Safety::Default, document: true, }; diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 776e56b17efb0..f7898a02bf11a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -43,7 +43,6 @@ pub(crate) fn expand_deriving_eq( }], associated_types: Vec::new(), is_const, - is_staged_api_crate: cx.ecfg.features.staged_api(), safety: Safety::Default, document: true, }; diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 35af63feef70a..db80d1ca5fe6d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -34,7 +34,6 @@ pub(crate) fn expand_deriving_ord( }], associated_types: Vec::new(), is_const, - is_staged_api_crate: cx.ecfg.features.staged_api(), safety: Safety::Default, document: true, }; diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index d9f6f8b4976fc..6c460cc8018c0 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -32,7 +32,6 @@ pub(crate) fn expand_deriving_partial_eq( methods: Vec::new(), associated_types: Vec::new(), is_const: false, - is_staged_api_crate: cx.ecfg.features.staged_api(), safety: Safety::Default, document: true, }; @@ -63,7 +62,6 @@ pub(crate) fn expand_deriving_partial_eq( methods, associated_types: Vec::new(), is_const, - is_staged_api_crate: cx.ecfg.features.staged_api(), safety: Safety::Default, document: true, }; diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 7855ceb6a9423..8abd64a6a777c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -100,7 +100,6 @@ pub(crate) fn expand_deriving_partial_ord( methods: vec![partial_cmp_def], associated_types: Vec::new(), is_const, - is_staged_api_crate: cx.ecfg.features.staged_api(), safety: Safety::Default, document: true, }; diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 38042d2080618..68ecc28d1855a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -39,7 +39,6 @@ pub(crate) fn expand_deriving_debug( }], associated_types: Vec::new(), is_const, - is_staged_api_crate: cx.ecfg.features.staged_api(), safety: Safety::Default, document: true, }; diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index d059586d61afd..7821c704a3096 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -50,7 +50,6 @@ pub(crate) fn expand_deriving_default( }], associated_types: Vec::new(), is_const, - is_staged_api_crate: cx.ecfg.features.staged_api(), safety: Safety::Default, document: true, }; diff --git a/compiler/rustc_builtin_macros/src/deriving/from.rs b/compiler/rustc_builtin_macros/src/deriving/from.rs index 7d3e79359f1c9..9abd895c2235a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/from.rs +++ b/compiler/rustc_builtin_macros/src/deriving/from.rs @@ -126,7 +126,6 @@ pub(crate) fn expand_deriving_from( }], associated_types: Vec::new(), is_const, - is_staged_api_crate: cx.ecfg.features.staged_api(), safety: Safety::Default, document: true, }; diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index e05f6473db31d..41cf39bc06fd2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -223,8 +223,6 @@ pub(crate) struct TraitDef<'a> { pub is_const: bool, - pub is_staged_api_crate: bool, - /// The safety of the `impl`. pub safety: Safety, @@ -800,7 +798,7 @@ impl<'a> TraitDef<'a> { // Only add `rustc_const_unstable` attributes if `derive_const` is used within libcore/libstd, // Other crates don't need stability attributes, so adding them is not useful, but libcore needs them // on all const trait impls. - if self.is_const && self.is_staged_api_crate { + if self.is_const && cx.ecfg.features.staged_api() { attrs.push( cx.attr_nested( rustc_ast::AttrItem { diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index 42a184a591710..4d53e57417650 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -39,7 +39,6 @@ pub(crate) fn expand_deriving_hash( }], associated_types: Vec::new(), is_const, - is_staged_api_crate: cx.ecfg.features.staged_api(), safety: Safety::Default, document: true, }; From 21c02fb5e194d2ffbe05c4f10c8159e68c93f457 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 20 Aug 2026 11:47:17 +0000 Subject: [PATCH 06/49] remove the `RefCell` from `CombineSubstructureFunc` --- .../src/deriving/generic/mod.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 41cf39bc06fd2..f0e85a753f242 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -174,7 +174,6 @@ //! ) //! ``` -use std::cell::RefCell; use std::ops::Not; use std::{iter, vec}; @@ -249,7 +248,7 @@ pub(crate) struct MethodDef<'a> { pub fieldless_variants_strategy: FieldlessVariantsStrategy, - pub combine_substructure: RefCell>, + pub combine_substructure: CombineSubstructureFunc<'a>, } /// How to handle fieldless enum variants. @@ -337,12 +336,12 @@ pub(crate) enum SubstructureFields<'a> { /// Combine the values of all the fields together. The last argument is /// all the fields of all the structures. pub(crate) type CombineSubstructureFunc<'a> = - Box, Span, &Substructure<'_>) -> BlockOrExpr + 'a>; + Box, Span, &Substructure<'_>) -> BlockOrExpr + 'a>; pub(crate) fn combine_substructure<'a>( - f: impl FnMut(&ExtCtxt<'_>, Span, &Substructure<'_>) -> BlockOrExpr + 'a, -) -> RefCell> { - RefCell::new(Box::new(f)) + f: impl Fn(&ExtCtxt<'_>, Span, &Substructure<'_>) -> BlockOrExpr + 'a, +) -> CombineSubstructureFunc<'a> { + Box::new(f) } struct TypeParameter { @@ -974,8 +973,7 @@ impl<'a> MethodDef<'a> { ) -> BlockOrExpr { let span = trait_.span; let substructure = Substructure { type_ident, nonselflike_args, fields }; - let mut f = self.combine_substructure.borrow_mut(); - let f: &mut CombineSubstructureFunc<'_> = &mut *f; + let f: &CombineSubstructureFunc<'_> = &self.combine_substructure; f(cx, span, &substructure) } From 745b410130230c5d42de2f3df7639a087b4ae5d3 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 20 Aug 2026 12:30:22 +0000 Subject: [PATCH 07/49] simplify large `match` --- .../src/deriving/cmp/partial_ord.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 8abd64a6a777c..6dfe02feed1c4 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -54,29 +54,27 @@ pub(crate) fn expand_deriving_partial_ord( let simple_substructure = combine_substructure(|cx, span, _| { cs_partial_cmp_simple(cx, span, cx.expr_ident(span, Ident::new(sym::other, span))) }); - let (is_simple, substructure) = match item { + let is_simple = match item { Annotatable::Item(annitem) => match &annitem.kind { // For unit structs/zero-variant enums, the default generated code is better. - ItemKind::Struct(.., ast::VariantData::Unit(..)) => (false, default_substructure), + ItemKind::Struct(.., ast::VariantData::Unit(..)) => false, // Also for single fieldless variant enum - ItemKind::Enum(.., enum_def) if enum_def.variants.is_empty() => { - (false, default_substructure) - } + ItemKind::Enum(.., enum_def) if enum_def.variants.is_empty() => false, ItemKind::Enum(.., enum_def) if enum_def.variants.len() == 1 && matches!(enum_def.variants[0].data, ast::VariantData::Unit(..)) => { - (false, default_substructure) + false } ItemKind::Struct(_, ast::Generics { params, .. }, _) | ItemKind::Enum(_, ast::Generics { params, .. }, _) if is_simple_candidate(params) => { - (true, simple_substructure) + true } - _ => (false, default_substructure), + _ => false, }, - _ => (false, default_substructure), + _ => false, }; let partial_cmp_def = MethodDef { @@ -87,7 +85,7 @@ pub(crate) fn expand_deriving_partial_ord( ret_ty, attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, - combine_substructure: substructure, + combine_substructure: if is_simple { simple_substructure } else { default_substructure }, }; let trait_def = TraitDef { From e899f2cd8ad7134deb3942ad0d8e140c9c58488a Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 20 Aug 2026 13:42:38 +0000 Subject: [PATCH 08/49] use `SmallVec` instead of `Vec` in `TraitDef` --- .../rustc_builtin_macros/src/deriving/bounds.rs | 12 ++++++------ .../rustc_builtin_macros/src/deriving/clone.rs | 14 +++++++------- .../rustc_builtin_macros/src/deriving/cmp/eq.rs | 8 ++++---- .../rustc_builtin_macros/src/deriving/cmp/ord.rs | 8 ++++---- .../src/deriving/cmp/partial_eq.rs | 14 +++++++------- .../src/deriving/cmp/partial_ord.rs | 8 ++++---- .../rustc_builtin_macros/src/deriving/debug.rs | 8 ++++---- .../rustc_builtin_macros/src/deriving/default.rs | 8 ++++---- compiler/rustc_builtin_macros/src/deriving/from.rs | 13 +++++-------- .../src/deriving/generic/mod.rs | 9 +++++---- compiler/rustc_builtin_macros/src/deriving/hash.rs | 8 ++++---- 11 files changed, 54 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 11e4eb2c55faa..48fdb4dd39ce2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -18,10 +18,10 @@ pub(crate) fn expand_deriving_copy( path: path_std!(marker::Copy), skip_path_as_bound: false, needs_copy_as_bound_if_packed: false, - additional_bounds: Vec::new(), + additional_bounds: SmallVec::new(), supports_unions: true, - methods: Vec::new(), - associated_types: Vec::new(), + methods: SmallVec::new(), + associated_types: SmallVec::new(), is_const, safety: Safety::Default, document: true, @@ -43,10 +43,10 @@ pub(crate) fn expand_deriving_const_param_ty( path: path_std!(marker::ConstParamTy_), skip_path_as_bound: false, needs_copy_as_bound_if_packed: false, - additional_bounds: vec![ty::Ty::Path(path_std!(cmp::Eq))], + additional_bounds: smallvec![ty::Ty::Path(path_std!(cmp::Eq))], supports_unions: false, - methods: Vec::new(), - associated_types: Vec::new(), + methods: SmallVec::new(), + associated_types: SmallVec::new(), is_const, safety: Safety::Default, document: true, diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 4cc466b74f4c5..b4374e32f6051 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -38,7 +38,7 @@ pub(crate) fn expand_deriving_clone( | ItemKind::Enum(_, Generics { params, .. }, _) => { let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); let has_derive_copy = cx.resolver.has_derive_copy(container_id); - bounds = vec![]; + bounds = smallvec![]; if has_derive_copy && !params .iter() @@ -53,7 +53,7 @@ pub(crate) fn expand_deriving_clone( } } ItemKind::Union(..) => { - bounds = vec![Path(path_std!(marker::Copy))]; + bounds = smallvec![Path(path_std!(marker::Copy))]; is_simple = true; substructure = combine_substructure(|c, s, sub| cs_clone_simple(c, s, sub, true)); } @@ -73,8 +73,8 @@ pub(crate) fn expand_deriving_clone( needs_copy_as_bound_if_packed: true, additional_bounds: bounds.clone(), supports_unions: true, - methods: Vec::new(), - associated_types: Vec::new(), + methods: SmallVec::new(), + associated_types: SmallVec::new(), is_const, safety: Safety::Unsafe(DUMMY_SP), // `TrivialClone` is not part of an API guarantee, so it shouldn't @@ -92,17 +92,17 @@ pub(crate) fn expand_deriving_clone( needs_copy_as_bound_if_packed: true, additional_bounds: bounds, supports_unions: true, - methods: vec![MethodDef { + methods: smallvec![MethodDef { name: sym::clone, generics: Bounds::empty(), explicit_self: true, - nonself_args: Vec::new(), + nonself_args: SmallVec::new(), ret_ty: Self_, attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Default, combine_substructure: substructure, }], - associated_types: Vec::new(), + associated_types: SmallVec::new(), is_const, safety: Safety::Default, document: true, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index f7898a02bf11a..440360ca85d7d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -23,13 +23,13 @@ pub(crate) fn expand_deriving_eq( path: path_std!(cmp::Eq), skip_path_as_bound: false, needs_copy_as_bound_if_packed: true, - additional_bounds: Vec::new(), + additional_bounds: SmallVec::new(), supports_unions: true, - methods: vec![MethodDef { + methods: smallvec![MethodDef { name: sym::assert_fields_are_eq, generics: Bounds::empty(), explicit_self: true, - nonself_args: vec![], + nonself_args: smallvec![], ret_ty: Unit, attributes: thin_vec![ // This method will never be called, so doing codegen etc. for it is unnecessary. @@ -41,7 +41,7 @@ pub(crate) fn expand_deriving_eq( fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(cs_total_eq_assert), }], - associated_types: Vec::new(), + associated_types: SmallVec::new(), is_const, safety: Safety::Default, document: true, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index db80d1ca5fe6d..a1b38ceadb228 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -20,19 +20,19 @@ pub(crate) fn expand_deriving_ord( path: path_std!(cmp::Ord), skip_path_as_bound: false, needs_copy_as_bound_if_packed: true, - additional_bounds: Vec::new(), + additional_bounds: SmallVec::new(), supports_unions: false, - methods: vec![MethodDef { + methods: smallvec![MethodDef { name: sym::cmp, generics: Bounds::empty(), explicit_self: true, - nonself_args: vec![(self_ref(), sym::other)], + nonself_args: smallvec![(self_ref(), sym::other)], ret_ty: Path(path_std!(cmp::Ordering)), attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(cs_cmp), }], - associated_types: Vec::new(), + associated_types: SmallVec::new(), is_const, safety: Safety::Default, document: true, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 6c460cc8018c0..9ecf531438cf3 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -25,12 +25,12 @@ pub(crate) fn expand_deriving_partial_eq( // The `StructuralPartialEq` impl must have the *same* bounds as the `PartialEq` impl, // or it will apply in situations where it should not, such as in the bug // . - additional_bounds: vec![ty::Ty::Path(path_std!(cmp::PartialEq))], + additional_bounds: smallvec![ty::Ty::Path(path_std!(cmp::PartialEq))], // We really don't support unions, but that's already checked by the impl generated below; // a second check here would lead to redundant error messages. supports_unions: true, - methods: Vec::new(), - associated_types: Vec::new(), + methods: SmallVec::new(), + associated_types: SmallVec::new(), is_const: false, safety: Safety::Default, document: true, @@ -39,11 +39,11 @@ pub(crate) fn expand_deriving_partial_eq( // No need to generate `ne`, the default suffices, and not generating it is // faster. - let methods = vec![MethodDef { + let methods = smallvec![MethodDef { name: sym::eq, generics: Bounds::empty(), explicit_self: true, - nonself_args: vec![(self_ref(), sym::other)], + nonself_args: smallvec![(self_ref(), sym::other)], ret_ty: Path(path_local!(bool)), attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, @@ -57,10 +57,10 @@ pub(crate) fn expand_deriving_partial_eq( path: path_std!(cmp::PartialEq), skip_path_as_bound: false, needs_copy_as_bound_if_packed: true, - additional_bounds: Vec::new(), + additional_bounds: SmallVec::new(), supports_unions: false, methods, - associated_types: Vec::new(), + associated_types: SmallVec::new(), is_const, safety: Safety::Default, document: true, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 6dfe02feed1c4..c054a9fa26896 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -81,7 +81,7 @@ pub(crate) fn expand_deriving_partial_ord( name: sym::partial_cmp, generics: Bounds::empty(), explicit_self: true, - nonself_args: vec![(self_ref(), sym::other)], + nonself_args: smallvec![(self_ref(), sym::other)], ret_ty, attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, @@ -93,10 +93,10 @@ pub(crate) fn expand_deriving_partial_ord( path: path_std!(cmp::PartialOrd), skip_path_as_bound: false, needs_copy_as_bound_if_packed: true, - additional_bounds: vec![], + additional_bounds: smallvec![], supports_unions: false, - methods: vec![partial_cmp_def], - associated_types: Vec::new(), + methods: smallvec![partial_cmp_def], + associated_types: SmallVec::new(), is_const, safety: Safety::Default, document: true, diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 68ecc28d1855a..c09ac52e74820 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -24,20 +24,20 @@ pub(crate) fn expand_deriving_debug( path: path_std!(fmt::Debug), skip_path_as_bound: false, needs_copy_as_bound_if_packed: true, - additional_bounds: Vec::new(), + additional_bounds: SmallVec::new(), supports_unions: false, - methods: vec![MethodDef { + methods: smallvec![MethodDef { name: sym::fmt, generics: Bounds::empty(), explicit_self: true, - nonself_args: vec![(fmtr, sym::character('f'))], + nonself_args: smallvec![(fmtr, sym::character('f'))], ret_ty: Path(path_std!(fmt::Result)), attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless, combine_substructure: combine_substructure(show_substructure), }], - associated_types: Vec::new(), + associated_types: SmallVec::new(), is_const, safety: Safety::Default, document: true, diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 7821c704a3096..3e4c5f1dcfa53 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -26,13 +26,13 @@ pub(crate) fn expand_deriving_default( path: Path::new(vec![kw::Default, sym::Default]), skip_path_as_bound: has_a_default_variant(item), needs_copy_as_bound_if_packed: false, - additional_bounds: Vec::new(), + additional_bounds: SmallVec::new(), supports_unions: false, - methods: vec![MethodDef { + methods: smallvec![MethodDef { name: kw::Default, generics: Bounds::empty(), explicit_self: false, - nonself_args: Vec::new(), + nonself_args: SmallVec::new(), ret_ty: Self_, attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Default, @@ -48,7 +48,7 @@ pub(crate) fn expand_deriving_default( } }), }], - associated_types: Vec::new(), + associated_types: SmallVec::new(), is_const, safety: Safety::Default, document: true, diff --git a/compiler/rustc_builtin_macros/src/deriving/from.rs b/compiler/rustc_builtin_macros/src/deriving/from.rs index 9abd895c2235a..d3ac51582d0e9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/from.rs +++ b/compiler/rustc_builtin_macros/src/deriving/from.rs @@ -6,10 +6,7 @@ use rustc_span::{Ident, Span, kw, sym}; use thin_vec::thin_vec; use crate::deriving::generic::ty::{Bounds, Path, PathKind, Ty}; -use crate::deriving::generic::{ - BlockOrExpr, FieldlessVariantsStrategy, MethodDef, SubstructureFields, TraitDef, - combine_substructure, -}; +use crate::deriving::generic::*; use crate::deriving::pathvec_std; use crate::diagnostics; @@ -78,13 +75,13 @@ pub(crate) fn expand_deriving_from( path, skip_path_as_bound: true, needs_copy_as_bound_if_packed: false, - additional_bounds: Vec::new(), + additional_bounds: SmallVec::new(), supports_unions: false, - methods: vec![MethodDef { + methods: smallvec![MethodDef { name: sym::from, generics: Bounds { bounds: vec![] }, explicit_self: false, - nonself_args: vec![(from_type, sym::value)], + nonself_args: smallvec![(from_type, sym::value)], ret_ty: Ty::Self_, attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Default, @@ -124,7 +121,7 @@ pub(crate) fn expand_deriving_from( BlockOrExpr::new_expr(expr) }), }], - associated_types: Vec::new(), + associated_types: SmallVec::new(), is_const, safety: Safety::Default, document: true, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index f0e85a753f242..c25593a05e340 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -189,6 +189,7 @@ use rustc_attr_ir::{Attribute, AttributeKind, ReprPacked}; use rustc_attr_parsing::AttributeParser; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; +pub(crate) use smallvec::{SmallVec, smallvec}; use thin_vec::{ThinVec, thin_vec}; use ty::{Bounds, Path, Ref, Self_, Ty}; @@ -211,14 +212,14 @@ pub(crate) struct TraitDef<'a> { /// Additional bounds required of any type parameters of the type, /// other than the current trait - pub additional_bounds: Vec, + pub additional_bounds: SmallVec<[Ty; 1]>, /// Can this trait be derived for unions? pub supports_unions: bool, - pub methods: Vec>, + pub methods: SmallVec<[MethodDef<'a>; 1]>, - pub associated_types: Vec<(Ident, Ty)>, + pub associated_types: SmallVec<[(Ident, Ty); 1]>, pub is_const: bool, @@ -239,7 +240,7 @@ pub(crate) struct MethodDef<'a> { pub explicit_self: bool, /// Arguments other than the self argument. - pub nonself_args: Vec<(Ty, Symbol)>, + pub nonself_args: SmallVec<[(Ty, Symbol); 1]>, /// Returns type pub ret_ty: Ty, diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index 4d53e57417650..bdf4e0630d9d1 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -25,19 +25,19 @@ pub(crate) fn expand_deriving_hash( path, skip_path_as_bound: false, needs_copy_as_bound_if_packed: true, - additional_bounds: Vec::new(), + additional_bounds: SmallVec::new(), supports_unions: false, - methods: vec![MethodDef { + methods: smallvec![MethodDef { name: sym::hash, generics: Bounds { bounds: vec![(typaram, vec![path_std!(hash::Hasher)])] }, explicit_self: true, - nonself_args: vec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)], + nonself_args: smallvec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)], ret_ty: Unit, attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(hash_substructure), }], - associated_types: Vec::new(), + associated_types: SmallVec::new(), is_const, safety: Safety::Default, document: true, From f0cfd1d7d15a23f2093800dc8bdb0d0d5f4fdb5a Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 20 Aug 2026 20:32:10 +0000 Subject: [PATCH 09/49] misc small cleanups and inlinings --- compiler/rustc_builtin_macros/src/derive.rs | 41 ++++++++----------- .../src/deriving/cmp/partial_ord.rs | 12 +++--- .../src/deriving/generic/mod.rs | 8 +--- .../rustc_builtin_macros/src/deriving/hash.rs | 7 +--- .../rustc_builtin_macros/src/deriving/mod.rs | 5 +-- compiler/rustc_builtin_macros/src/format.rs | 15 +++---- 6 files changed, 31 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index da85a8a763b01..cf9d0aef7582b 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -50,43 +50,34 @@ impl MultiItemModifier for Expander { MetaItemKind::List(list) => { list.iter() .filter_map(|meta_item_inner| match meta_item_inner { - MetaItemInner::MetaItem(meta) => Some(meta), + MetaItemInner::MetaItem(meta) => { + // Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the + // paths. + report_path_args(sess, meta); + Some(DeriveResolution { + path: meta.path.clone(), + item: dummy_annotatable(), + exts: None, + is_const: self.is_const, + }) + } MetaItemInner::Lit(lit) => { // Reject `#[derive("Debug")]`. report_unexpected_meta_item_lit(sess, lit); None } }) - .map(|meta| { - // Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the - // paths. - report_path_args(sess, meta); - meta.path.clone() - }) - .map(|path| DeriveResolution { - path, - item: dummy_annotatable(), - exts: None, - is_const: self.is_const, - }) .collect() } _ => vec![], }; // Do not configure or clone items unless necessary. - match &mut resolutions[..] { - [] => {} - [first, others @ ..] => { - first.item = cfg_eval( - sess, - features, - item.clone(), - ecx.current_expansion.lint_node_id, - ); - for other in others { - other.item = first.item.clone(); - } + if let [first, others @ ..] = &mut resolutions { + first.item = + cfg_eval(sess, features, item.clone(), ecx.current_expansion.lint_node_id); + for other in others { + other.item = first.item.clone(); } } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index c054a9fa26896..dae067a4e8ea9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -1,7 +1,7 @@ use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind, Safety, ast}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Ident, Span, sym}; -use thin_vec::{ThinVec, thin_vec}; +use thin_vec::thin_vec; use crate::deriving::generic::ty::*; use crate::deriving::generic::*; @@ -44,11 +44,6 @@ pub(crate) fn expand_deriving_partial_ord( let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); let has_derive_ord = cx.resolver.has_derive_ord(container_id); - let is_simple_candidate = |params: &ThinVec| -> bool { - has_derive_ord - && !params.iter().any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) - }; - let default_substructure = combine_substructure(|cx, span, substr| cs_partial_cmp(cx, span, substr, discr_then_data)); let simple_substructure = combine_substructure(|cx, span, _| { @@ -68,7 +63,10 @@ pub(crate) fn expand_deriving_partial_ord( } ItemKind::Struct(_, ast::Generics { params, .. }, _) | ItemKind::Enum(_, ast::Generics { params, .. }, _) - if is_simple_candidate(params) => + if has_derive_ord + && !params + .iter() + .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) => { true } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index c25593a05e340..ee727b03e3ac0 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1230,13 +1230,7 @@ impl<'a> MethodDef<'a> { } let prefixes = iter::once("__self".to_string()) - .chain( - selflike_args - .iter() - .enumerate() - .skip(1) - .map(|(arg_count, _selflike_arg)| format!("__arg{arg_count}")), - ) + .chain((1..selflike_args.len()).map(|arg_count| format!("__arg{arg_count}"))) .collect::>(); // Build a series of let statements mapping each selflike_arg diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index bdf4e0630d9d1..d4966e7b4cb41 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -51,11 +51,8 @@ fn hash_substructure(cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<' cx.dcx().span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`"); }; let call_hash = |span, expr| { - let hash_path = { - let strs = cx.std_path(&[sym::hash, sym::Hash, sym::hash]); - - cx.expr_path(cx.path_global(span, strs)) - }; + let strs = cx.std_path(&[sym::hash, sym::Hash, sym::hash]); + let hash_path = cx.expr_path(cx.path_global(span, strs)); let expr = cx.expr_call(span, hash_path, thin_vec![expr, state_expr.clone()]); cx.stmt_expr(expr) }; diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index cef45435cb88a..f410850686c36 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -101,10 +101,7 @@ fn call_intrinsic( /// Constructs an expression that calls the `unreachable` intrinsic. fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> Box { - let span = cx.with_def_site_ctxt(span); - let path = cx.std_path(&[sym::intrinsics, sym::unreachable]); - let call = cx.expr_call_global(span, path, ThinVec::new()); - + let call = call_intrinsic(cx, span, sym::unreachable, ThinVec::new()); cx.expr_block(Box::new(ast::Block { stmts: thin_vec![cx.stmt_expr(call)], id: ast::DUMMY_NODE_ID, diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 26d223353c62e..745de4d129766 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -164,7 +164,6 @@ fn make_format_args( append_newline: bool, macro_span: Span, ) -> ExpandResult, ()> { - let msg = "format argument must be a string literal"; let unexpanded_fmt_span = input.fmtstr.span; let MacroInput { fmtstr: efmt, mut args, is_direct_literal } = input; @@ -185,7 +184,9 @@ fn make_format_args( None }; - let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, efmt.clone(), msg) else { + let ExpandResult::Ready(mac) = + expr_to_spanned_string(ecx, efmt.clone(), "format argument must be a string literal") + else { return ExpandResult::Retry(()); }; match mac { @@ -604,9 +605,6 @@ fn make_format_args( let has_unused = !unused.is_empty(); if has_unused { - // If there's a lot of unused arguments, - // let's check if this format arguments looks like another syntax (printf / shell). - let detect_foreign_fmt = unused.len() > args.explicit_args().len() / 2; let foreign_fmt_str = if append_newline { fmt_str.strip_suffix('\n').unwrap_or(fmt_str) } else { fmt_str }; report_missing_placeholders( @@ -616,7 +614,6 @@ fn make_format_args( &args, &pieces, &invalid_refs, - detect_foreign_fmt, str_style, foreign_fmt_str, uncooked_fmt_str.1.as_str(), @@ -723,7 +720,6 @@ fn report_missing_placeholders( args: &FormatArguments, pieces: &[parse::Piece<'_>], invalid_refs: &[(usize, Option, PositionUsedAs, FormatArgPositionKind)], - detect_foreign_fmt: bool, str_style: Option, fmt_str: &str, uncooked_fmt_str: &str, @@ -772,8 +768,9 @@ fn report_missing_placeholders( // Used to ensure we only report translations for *one* kind of foreign format. let mut found_foreign = false; - // Decide if we want to look for foreign formatting directives. - if detect_foreign_fmt { + // If there's a lot of unused arguments, + // let's check if this format arguments looks like another syntax (printf / shell). + if unused.len() > args.explicit_args().len() / 2 { use super::format_foreign as foreign; // The set of foreign substitutions we've explained. This prevents spamming the user From be01a09fae9c3e8b15aa5937c5c45d54c0dbf059 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 20 Aug 2026 20:38:29 +0000 Subject: [PATCH 10/49] remove `path_local!` --- .../rustc_builtin_macros/src/deriving/cmp/partial_eq.rs | 6 +++--- compiler/rustc_builtin_macros/src/deriving/mod.rs | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 9ecf531438cf3..b852e29b03ca4 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -4,8 +4,8 @@ use rustc_span::{Span, sym}; use thin_vec::thin_vec; use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::{path_local, path_std}; +use crate::deriving::generic::{self, *}; +use crate::deriving::path_std; /// Expands a `#[derive(PartialEq)]` attribute into an implementation for the /// target item. @@ -44,7 +44,7 @@ pub(crate) fn expand_deriving_partial_eq( generics: Bounds::empty(), explicit_self: true, nonself_args: smallvec![(self_ref(), sym::other)], - ret_ty: Path(path_local!(bool)), + ret_ty: Path(generic::ty::Path::new_local(sym::bool)), attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(|a, b, c| { diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index f410850686c36..4cb9649287c12 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -6,10 +6,6 @@ use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier}; use rustc_span::{Span, Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; -macro path_local($x:ident) { - generic::ty::Path::new_local(sym::$x) -} - macro pathvec_std($($rest:ident)::+) {{ vec![ $( sym::$rest ),+ ] }} From 0b5961022be9e6dc53d89f0c98af43ae34bc519a Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 20 Aug 2026 20:58:30 +0000 Subject: [PATCH 11/49] improve usage and naming of `path[vec]_std!` --- compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs | 4 ++-- compiler/rustc_builtin_macros/src/deriving/from.rs | 4 ++-- compiler/rustc_builtin_macros/src/deriving/hash.rs | 4 ++-- compiler/rustc_builtin_macros/src/deriving/mod.rs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index dae067a4e8ea9..88141224fddc2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -5,7 +5,7 @@ use thin_vec::thin_vec; use crate::deriving::generic::ty::*; use crate::deriving::generic::*; -use crate::deriving::{path_std, pathvec_std}; +use crate::deriving::{path_std, pathvec}; pub(crate) fn expand_deriving_partial_ord( cx: &ExtCtxt<'_>, @@ -17,7 +17,7 @@ pub(crate) fn expand_deriving_partial_ord( ) { let ordering_ty = Path(path_std!(cmp::Ordering)); let ret_ty = - Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std)); + Path(Path::new_(pathvec!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std)); // Order in which to perform matching let discr_then_data = if let Annotatable::Item(item) = item diff --git a/compiler/rustc_builtin_macros/src/deriving/from.rs b/compiler/rustc_builtin_macros/src/deriving/from.rs index d3ac51582d0e9..9824ab5a225b7 100644 --- a/compiler/rustc_builtin_macros/src/deriving/from.rs +++ b/compiler/rustc_builtin_macros/src/deriving/from.rs @@ -7,7 +7,7 @@ use thin_vec::thin_vec; use crate::deriving::generic::ty::{Bounds, Path, PathKind, Ty}; use crate::deriving::generic::*; -use crate::deriving::pathvec_std; +use crate::deriving::pathvec; use crate::diagnostics; /// Generate an implementation of the `From` trait, provided that `item` @@ -58,7 +58,7 @@ pub(crate) fn expand_deriving_from( }); let path = - Path::new_(pathvec_std!(convert::From), vec![Box::new(from_type.clone())], PathKind::Std); + Path::new_(pathvec!(convert::From), vec![Box::new(from_type.clone())], PathKind::Std); // Generate code like this: // diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index d4966e7b4cb41..f1931aa90a435 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -5,7 +5,7 @@ use thin_vec::thin_vec; use crate::deriving::generic::ty::*; use crate::deriving::generic::*; -use crate::deriving::{path_std, pathvec_std}; +use crate::deriving::path_std; pub(crate) fn expand_deriving_hash( cx: &ExtCtxt<'_>, @@ -15,7 +15,7 @@ pub(crate) fn expand_deriving_hash( push: &mut dyn FnMut(Annotatable), is_const: bool, ) { - let path = Path::new_(pathvec_std!(hash::Hash), vec![], PathKind::Std); + let path = path_std!(hash::Hash); let typaram = sym::__H; diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index 4cb9649287c12..602af919bd4f2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -6,12 +6,12 @@ use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier}; use rustc_span::{Span, Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; -macro pathvec_std($($rest:ident)::+) {{ +macro pathvec($($rest:ident)::+) {{ vec![ $( sym::$rest ),+ ] }} macro path_std($($x:tt)*) { - generic::ty::Path::new( pathvec_std!( $($x)* ) ) + generic::ty::Path::new( pathvec!( $($x)* ) ) } pub(crate) mod bounds; From b84ba0421c870c38bb4a9ed0c70bc5b328f2ecb5 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Fri, 21 Aug 2026 08:42:19 +0000 Subject: [PATCH 12/49] inline two trivial functions --- .../src/deriving/generic/mod.rs | 10 +++--- .../src/deriving/generic/ty.rs | 35 +++++-------------- 2 files changed, 13 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index ee727b03e3ac0..fd72007bdb643 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -183,12 +183,12 @@ use rustc_ast::token::{IdentIsRaw, LitKind, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenTree}; use rustc_ast::{ self as ast, AnonConst, AttrArgs, BindingMode, ByRef, DelimArgs, EnumDef, Expr, GenericArg, - GenericParamKind, Generics, Mutability, PatKind, Safety, VariantData, + GenericParamKind, Generics, Mutability, PatKind, Safety, SelfKind, VariantData, }; use rustc_attr_ir::{Attribute, AttributeKind, ReprPacked}; use rustc_attr_parsing::AttributeParser; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, respan, sym}; pub(crate) use smallvec::{SmallVec, smallvec}; use thin_vec::{ThinVec, thin_vec}; use ty::{Bounds, Path, Ref, Self_, Ty}; @@ -1003,9 +1003,9 @@ impl<'a> MethodDef<'a> { let span = trait_.span; let explicit_self = self.explicit_self.then(|| { - let (self_expr, explicit_self) = ty::get_explicit_self(cx, span); - selflike_args.push(self_expr); - explicit_self + // This constructs a fresh `self` path. + selflike_args.push(cx.expr_self(span)); + respan(span, SelfKind::Region(None, ast::Mutability::Not)) }); for (ty, name) in self.nonself_args.iter() { diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index a3c540de95379..6e504534ba26d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -2,9 +2,9 @@ //! when specifying impls to be derived. pub(crate) use Ty::*; -use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind, TyKind}; +use rustc_ast::{self as ast, GenericArg, GenericParamKind, Generics, TyKind}; use rustc_expand::base::ExtCtxt; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, respan}; +use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw}; use thin_vec::ThinVec; /// A path, e.g., `::std::option::Option::` (global). Has support @@ -33,15 +33,6 @@ impl Path { Path { path, params, kind } } - pub(crate) fn to_ty( - &self, - cx: &ExtCtxt<'_>, - span: Span, - self_ty: Ident, - self_generics: &Generics, - ) -> Box { - cx.ty_path(self.to_path(cx, span, self_ty, self_generics)) - } pub(crate) fn to_path( &self, cx: &ExtCtxt<'_>, @@ -49,18 +40,15 @@ impl Path { self_ty: Ident, self_generics: &Generics, ) -> ast::Path { - let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect(); + let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect::>(); let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)); let params = tys.map(GenericArg::Type).collect(); - match self.kind { - PathKind::Local => cx.path_all(span, false, idents, params), - PathKind::Std => { - let def_site = cx.with_def_site_ctxt(DUMMY_SP); - idents.insert(0, Ident::new(kw::DollarCrate, def_site)); - cx.path_all(span, false, idents, params) - } + if let PathKind::Std = self.kind { + let def_site = cx.with_def_site_ctxt(DUMMY_SP); + idents.insert(0, Ident::new(kw::DollarCrate, def_site)); } + cx.path_all(span, false, idents, params) } } @@ -96,7 +84,7 @@ impl Ty { let raw_ty = ty.to_ty(cx, span, self_ty, self_generics); cx.ty_ref(span, raw_ty, None, *mutbl) } - Path(p) => p.to_ty(cx, span, self_ty, self_generics), + Path(p) => cx.ty_path(p.to_path(cx, span, self_ty, self_generics)), Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)), Unit => { let ty = ast::TyKind::Tup(ThinVec::new()); @@ -196,10 +184,3 @@ impl Bounds { } } } - -pub(crate) fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (Box, ast::ExplicitSelf) { - // This constructs a fresh `self` path. - let self_path = cx.expr_self(span); - let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not)); - (self_path, self_ty) -} From bd72f7ac4c2b194c104b7d3ed242fb03d8bd7076 Mon Sep 17 00:00:00 2001 From: Max Dexheimer Date: Mon, 24 Aug 2026 19:19:30 +0200 Subject: [PATCH 13/49] Replace `Allocator + Clone` with `AllocatorClone` in btree --- compiler/rustc_data_structures/src/marker.rs | 4 +- library/alloc/src/collections/btree/append.rs | 10 +- library/alloc/src/collections/btree/fix.rs | 23 ++-- library/alloc/src/collections/btree/map.rs | 116 +++++++++--------- .../alloc/src/collections/btree/map/entry.rs | 26 ++-- .../alloc/src/collections/btree/navigate.rs | 18 +-- library/alloc/src/collections/btree/node.rs | 38 +++--- library/alloc/src/collections/btree/remove.rs | 8 +- library/alloc/src/collections/btree/set.rs | 92 +++++++------- .../alloc/src/collections/btree/set/entry.rs | 20 +-- library/alloc/src/collections/btree/split.rs | 6 +- 11 files changed, 176 insertions(+), 185 deletions(-) diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 2fe2a30c36751..505a7a4c9d465 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -85,7 +85,7 @@ impl_dyn_send!( [std::sync::LazyLock where T: DynSend, F: DynSend] [std::collections::HashSet where K: DynSend, S: DynSend] [std::collections::HashMap where K: DynSend, V: DynSend, S: DynSend] - [std::collections::BTreeMap where K: DynSend, V: DynSend, A: std::alloc::Allocator + Clone + DynSend] + [std::collections::BTreeMap where K: DynSend, V: DynSend, A: std::alloc::AllocatorClone + DynSend] [Vec where T: DynSend, A: std::alloc::Allocator + DynSend] [Box where T: ?Sized + DynSend, A: std::alloc::Allocator + DynSend] [crate::sync::RwLock where T: DynSend] @@ -168,7 +168,7 @@ impl_dyn_sync!( [std::sync::LazyLock where T: DynSend + DynSync, F: DynSend] [std::collections::HashSet where K: DynSync, S: DynSync] [std::collections::HashMap where K: DynSync, V: DynSync, S: DynSync] - [std::collections::BTreeMap where K: DynSync, V: DynSync, A: std::alloc::Allocator + Clone + DynSync] + [std::collections::BTreeMap where K: DynSync, V: DynSync, A: std::alloc::AllocatorClone + DynSync] [Vec where T: DynSync, A: std::alloc::Allocator + DynSync] [Box where T: ?Sized + DynSync, A: std::alloc::Allocator + DynSync] [crate::sync::RwLock where T: DynSend + DynSync] diff --git a/library/alloc/src/collections/btree/append.rs b/library/alloc/src/collections/btree/append.rs index cc8d793e98e4d..4f11b1f6ea432 100644 --- a/library/alloc/src/collections/btree/append.rs +++ b/library/alloc/src/collections/btree/append.rs @@ -1,4 +1,4 @@ -use core::alloc::Allocator; +use core::alloc::AllocatorClone; use super::node::{self, Root}; @@ -6,12 +6,8 @@ impl Root { /// Pushes all key-value pairs to the end of the tree, incrementing a /// `length` variable along the way. The latter makes it easier for the /// caller to avoid a leak when the iterator panicks. - pub(super) fn bulk_push( - &mut self, - iter: I, - length: &mut usize, - alloc: A, - ) where + pub(super) fn bulk_push(&mut self, iter: I, length: &mut usize, alloc: A) + where I: Iterator, { let mut cur_node = self.borrow_mut().last_leaf_edge().into_node(); diff --git a/library/alloc/src/collections/btree/fix.rs b/library/alloc/src/collections/btree/fix.rs index b0c6759794691..0b36c203c1170 100644 --- a/library/alloc/src/collections/btree/fix.rs +++ b/library/alloc/src/collections/btree/fix.rs @@ -1,4 +1,4 @@ -use core::alloc::Allocator; +use core::alloc::AllocatorClone; use super::map::MIN_LEN; use super::node::ForceResult::*; @@ -10,7 +10,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { /// sibling. If successful but at the cost of shrinking the parent node, /// returns that shrunk parent node. Returns an `Err` if the node is /// an empty root. - fn fix_node_through_parent( + fn fix_node_through_parent( self, alloc: A, ) -> Result, K, V, marker::Internal>>, Self> { @@ -57,10 +57,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { /// /// This method does not expect ancestors to already be underfull upon entry /// and panics if it encounters an empty ancestor. - pub(super) fn fix_node_and_affected_ancestors( - mut self, - alloc: A, - ) -> bool { + pub(super) fn fix_node_and_affected_ancestors(mut self, alloc: A) -> bool { loop { match self.fix_node_through_parent(alloc.clone()) { Ok(Some(parent)) => self = parent.forget_type(), @@ -73,7 +70,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { impl Root { /// Removes empty levels on the top, but keeps an empty leaf if the entire tree is empty. - pub(super) fn fix_top(&mut self, alloc: A) { + pub(super) fn fix_top(&mut self, alloc: A) { while self.height() > 0 && self.len() == 0 { self.pop_internal_level(alloc.clone()); } @@ -82,7 +79,7 @@ impl Root { /// Stocks up or merge away any underfull nodes on the right border of the /// tree. The other nodes, those that are not the root nor a rightmost edge, /// must already have at least MIN_LEN elements. - pub(super) fn fix_right_border(&mut self, alloc: A) { + pub(super) fn fix_right_border(&mut self, alloc: A) { self.fix_top(alloc.clone()); if self.len() > 0 { self.borrow_mut().last_kv().fix_right_border_of_right_edge(alloc.clone()); @@ -91,7 +88,7 @@ impl Root { } /// The symmetric clone of `fix_right_border`. - pub(super) fn fix_left_border(&mut self, alloc: A) { + pub(super) fn fix_left_border(&mut self, alloc: A) { self.fix_top(alloc.clone()); if self.len() > 0 { self.borrow_mut().first_kv().fix_left_border_of_left_edge(alloc.clone()); @@ -121,14 +118,14 @@ impl Root { } impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInternal>, marker::KV> { - fn fix_left_border_of_left_edge(mut self, alloc: A) { + fn fix_left_border_of_left_edge(mut self, alloc: A) { while let Internal(internal_kv) = self.force() { self = internal_kv.fix_left_child(alloc.clone()).first_kv(); debug_assert!(self.reborrow().into_node().len() > MIN_LEN); } } - fn fix_right_border_of_right_edge(mut self, alloc: A) { + fn fix_right_border_of_right_edge(mut self, alloc: A) { while let Internal(internal_kv) = self.force() { self = internal_kv.fix_right_child(alloc.clone()).last_kv(); debug_assert!(self.reborrow().into_node().len() > MIN_LEN); @@ -141,7 +138,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, /// provisions an extra element to allow merging its children in turn /// without becoming underfull. /// Returns the left child. - fn fix_left_child( + fn fix_left_child( self, alloc: A, ) -> NodeRef, K, V, marker::LeafOrInternal> { @@ -164,7 +161,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, /// provisions an extra element to allow merging its children in turn /// without becoming underfull. /// Returns wherever the right child ended up. - fn fix_right_child( + fn fix_right_child( self, alloc: A, ) -> NodeRef, K, V, marker::LeafOrInternal> { diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index d8421d3c3f70a..aed07b3a5e901 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -17,7 +17,7 @@ use super::node::{self, Handle, NodeRef, Root, marker}; use super::search::SearchBound; use super::search::SearchResult::*; use super::set_val::SetValZST; -use crate::alloc::{Allocator, Global}; +use crate::alloc::{AllocatorClone, Global}; use crate::vec::Vec; mod entry; @@ -189,7 +189,7 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; pub struct BTreeMap< K, V, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocatorClone = Global, > { root: Option>, length: usize, @@ -203,7 +203,7 @@ pub struct BTreeMap< } #[stable(feature = "btree_drop", since = "1.7.0")] -unsafe impl<#[may_dangle] K, #[may_dangle] V, A: Allocator + Clone> Drop for BTreeMap { +unsafe impl<#[may_dangle] K, #[may_dangle] V, A: AllocatorClone> Drop for BTreeMap { fn drop(&mut self) { drop(unsafe { ptr::read(self) }.into_iter()) } @@ -214,7 +214,7 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V, A: Allocator + Clone> Drop for BTr // Maybe we can fix it nonetheless with a crater run, or if the `UnwindSafe` // traits are deprecated, or disarmed (no longer causing hard errors) in the future. #[stable(feature = "btree_unwindsafe", since = "1.64.0")] -impl core::panic::UnwindSafe for BTreeMap +impl core::panic::UnwindSafe for BTreeMap where A: core::panic::UnwindSafe, K: core::panic::RefUnwindSafe, @@ -223,9 +223,9 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for BTreeMap { +impl Clone for BTreeMap { fn clone(&self) -> BTreeMap { - fn clone_subtree<'a, K: Clone, V: Clone, A: Allocator + Clone>( + fn clone_subtree<'a, K: Clone, V: Clone, A: AllocatorClone>( node: NodeRef, K, V, marker::LeafOrInternal>, alloc: A, ) -> BTreeMap @@ -309,7 +309,7 @@ impl Clone for BTreeMap { } // Internal functionality for `BTreeSet`. -impl BTreeMap { +impl BTreeMap { pub(super) fn replace(&mut self, key: K) -> Option where K: Ord, @@ -444,7 +444,7 @@ impl<'a, K: 'a, V: 'a> Default for IterMut<'a, K, V> { pub struct IntoIter< K, V, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocatorClone = Global, > { range: LazyLeafRange, length: usize, @@ -452,7 +452,7 @@ pub struct IntoIter< alloc: A, } -impl IntoIter { +impl IntoIter { /// Returns an iterator of references over the remaining items. #[inline] pub(super) fn iter(&self) -> Iter<'_, K, V> { @@ -461,7 +461,7 @@ impl IntoIter { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl Debug for IntoIter { +impl Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.iter()).finish() } @@ -470,7 +470,7 @@ impl Debug for IntoIter { #[stable(feature = "default_iters", since = "1.70.0")] impl Default for IntoIter where - A: Allocator + Default + Clone, + A: AllocatorClone + Default, { /// Creates an empty `btree_map::IntoIter`. /// @@ -552,13 +552,13 @@ impl fmt::Debug for ValuesMut<'_, K, V> { pub struct IntoKeys< K, V, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocatorClone = Global, > { inner: IntoIter, } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl fmt::Debug for IntoKeys { +impl fmt::Debug for IntoKeys { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(key, _)| key)).finish() } @@ -575,13 +575,13 @@ impl fmt::Debug for IntoKeys { pub struct IntoValues< K, V, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocatorClone = Global, > { inner: IntoIter, } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl fmt::Debug for IntoValues { +impl fmt::Debug for IntoValues { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish() } @@ -653,7 +653,7 @@ impl BTreeMap { } } -impl BTreeMap { +impl BTreeMap { /// Clears the map, removing all elements. /// /// # Examples @@ -697,7 +697,7 @@ impl BTreeMap { } } -impl BTreeMap { +impl BTreeMap { /// Returns a reference to the value corresponding to the key. /// /// The key may be any borrowed form of the map's key type, but the ordering @@ -1719,7 +1719,7 @@ impl BTreeMap { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V, A: Allocator + Clone> IntoIterator for &'a BTreeMap { +impl<'a, K, V, A: AllocatorClone> IntoIterator for &'a BTreeMap { type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V>; @@ -1797,7 +1797,7 @@ impl Clone for Iter<'_, K, V> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V, A: Allocator + Clone> IntoIterator for &'a mut BTreeMap { +impl<'a, K, V, A: AllocatorClone> IntoIterator for &'a mut BTreeMap { type Item = (&'a K, &'a mut V); type IntoIter = IterMut<'a, K, V>; @@ -1876,7 +1876,7 @@ impl<'a, K, V> IterMut<'a, K, V> { } #[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for BTreeMap { +impl IntoIterator for BTreeMap { type Item = (K, V); type IntoIter = IntoIter; @@ -1902,11 +1902,11 @@ impl IntoIterator for BTreeMap { } #[stable(feature = "btree_drop", since = "1.7.0")] -impl Drop for IntoIter { +impl Drop for IntoIter { fn drop(&mut self) { - struct DropGuard<'a, K, V, A: Allocator + Clone>(&'a mut IntoIter); + struct DropGuard<'a, K, V, A: AllocatorClone>(&'a mut IntoIter); - impl<'a, K, V, A: Allocator + Clone> Drop for DropGuard<'a, K, V, A> { + impl<'a, K, V, A: AllocatorClone> Drop for DropGuard<'a, K, V, A> { fn drop(&mut self) { // Continue the same loop we perform below. This only runs when unwinding, so we // don't have to care about panics this time (they'll abort). @@ -1926,7 +1926,7 @@ impl Drop for IntoIter { } } -impl IntoIter { +impl IntoIter { /// Core of a `next` method returning a dying KV handle, /// invalidated by further calls to this function and some others. fn dying_next( @@ -1957,7 +1957,7 @@ impl IntoIter { } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { +impl Iterator for IntoIter { type Item = (K, V); fn next(&mut self) -> Option<(K, V)> { @@ -1971,7 +1971,7 @@ impl Iterator for IntoIter { } #[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for IntoIter { +impl DoubleEndedIterator for IntoIter { fn next_back(&mut self) -> Option<(K, V)> { // SAFETY: we consume the dying handle immediately. self.dying_next_back().map(unsafe { |kv| kv.into_key_val() }) @@ -1979,17 +1979,17 @@ impl DoubleEndedIterator for IntoIter { } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter { +impl ExactSizeIterator for IntoIter { fn len(&self) -> usize { self.length } } #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for IntoIter {} +unsafe impl TrustedLen for IntoIter {} #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} +impl FusedIterator for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> Iterator for Keys<'a, K, V> { @@ -2133,7 +2133,7 @@ pub struct ExtractIf< V, R, F, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocatorClone = Global, > { pred: F, inner: ExtractIfInner<'a, K, V, R>, @@ -2163,7 +2163,7 @@ impl fmt::Debug for ExtractIf<'_, K, V, R, F, A> where K: fmt::Debug, V: fmt::Debug, - A: Allocator + Clone, + A: AllocatorClone, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ExtractIf").field("peek", &self.inner.peek()).finish_non_exhaustive() @@ -2171,7 +2171,7 @@ where } #[stable(feature = "btree_extract_if", since = "1.91.0")] -impl Iterator for ExtractIf<'_, K, V, R, F, A> +impl Iterator for ExtractIf<'_, K, V, R, F, A> where K: PartialOrd, R: RangeBounds, @@ -2196,7 +2196,7 @@ impl<'a, K, V, R> ExtractIfInner<'a, K, V, R> { } /// Implementation of a typical `ExtractIf::next` method, given the predicate. - pub(super) fn next(&mut self, pred: &mut F, alloc: A) -> Option<(K, V)> + pub(super) fn next(&mut self, pred: &mut F, alloc: A) -> Option<(K, V)> where K: PartialOrd, R: RangeBounds, @@ -2360,7 +2360,7 @@ impl Default for ValuesMut<'_, K, V> { } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl Iterator for IntoKeys { +impl Iterator for IntoKeys { type Item = K; fn next(&mut self) -> Option { @@ -2391,29 +2391,29 @@ impl Iterator for IntoKeys { } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl DoubleEndedIterator for IntoKeys { +impl DoubleEndedIterator for IntoKeys { fn next_back(&mut self) -> Option { self.inner.next_back().map(|(k, _)| k) } } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl ExactSizeIterator for IntoKeys { +impl ExactSizeIterator for IntoKeys { fn len(&self) -> usize { self.inner.len() } } #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for IntoKeys {} +unsafe impl TrustedLen for IntoKeys {} #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl FusedIterator for IntoKeys {} +impl FusedIterator for IntoKeys {} #[stable(feature = "default_iters", since = "1.70.0")] impl Default for IntoKeys where - A: Allocator + Default + Clone, + A: AllocatorClone + Default, { /// Creates an empty `btree_map::IntoKeys`. /// @@ -2428,7 +2428,7 @@ where } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl Iterator for IntoValues { +impl Iterator for IntoValues { type Item = V; fn next(&mut self) -> Option { @@ -2445,29 +2445,29 @@ impl Iterator for IntoValues { } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl DoubleEndedIterator for IntoValues { +impl DoubleEndedIterator for IntoValues { fn next_back(&mut self) -> Option { self.inner.next_back().map(|(_, v)| v) } } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl ExactSizeIterator for IntoValues { +impl ExactSizeIterator for IntoValues { fn len(&self) -> usize { self.inner.len() } } #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for IntoValues {} +unsafe impl TrustedLen for IntoValues {} #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl FusedIterator for IntoValues {} +impl FusedIterator for IntoValues {} #[stable(feature = "default_iters", since = "1.70.0")] impl Default for IntoValues where - A: Allocator + Default + Clone, + A: AllocatorClone + Default, { /// Creates an empty `btree_map::IntoValues`. /// @@ -2555,7 +2555,7 @@ impl FromIterator<(K, V)> for BTreeMap { } #[stable(feature = "rust1", since = "1.0.0")] -impl Extend<(K, V)> for BTreeMap { +impl Extend<(K, V)> for BTreeMap { #[inline] fn extend>(&mut self, iter: T) { iter.into_iter().for_each(move |(k, v)| { @@ -2570,9 +2570,7 @@ impl Extend<(K, V)> for BTreeMap { } #[stable(feature = "extend_ref", since = "1.2.0")] -impl<'a, K: Ord + Copy, V: Copy, A: Allocator + Clone> Extend<(&'a K, &'a V)> - for BTreeMap -{ +impl<'a, K: Ord + Copy, V: Copy, A: AllocatorClone> Extend<(&'a K, &'a V)> for BTreeMap { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().map(|(&key, &value)| (key, value))); } @@ -2584,7 +2582,7 @@ impl<'a, K: Ord + Copy, V: Copy, A: Allocator + Clone> Extend<(&'a K, &'a V)> } #[stable(feature = "rust1", since = "1.0.0")] -impl Hash for BTreeMap { +impl Hash for BTreeMap { fn hash(&self, state: &mut H) { state.write_length_prefix(self.len()); for elt in self { @@ -2603,17 +2601,17 @@ const impl Default for BTreeMap { } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for BTreeMap { +impl PartialEq for BTreeMap { fn eq(&self, other: &BTreeMap) -> bool { self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b) } } #[stable(feature = "rust1", since = "1.0.0")] -impl Eq for BTreeMap {} +impl Eq for BTreeMap {} #[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for BTreeMap { +impl PartialOrd for BTreeMap { #[inline] fn partial_cmp(&self, other: &BTreeMap) -> Option { self.iter().partial_cmp(other.iter()) @@ -2621,7 +2619,7 @@ impl PartialOrd for BTreeMap } #[stable(feature = "rust1", since = "1.0.0")] -impl Ord for BTreeMap { +impl Ord for BTreeMap { #[inline] fn cmp(&self, other: &BTreeMap) -> Ordering { self.iter().cmp(other.iter()) @@ -2629,14 +2627,14 @@ impl Ord for BTreeMap { } #[stable(feature = "rust1", since = "1.0.0")] -impl Debug for BTreeMap { +impl Debug for BTreeMap { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_map().entries(self.iter()).finish() } } #[stable(feature = "rust1", since = "1.0.0")] -impl Index<&Q> for BTreeMap +impl Index<&Q> for BTreeMap where K: Borrow + Ord, Q: Ord, @@ -2679,7 +2677,7 @@ impl From<[(K, V); N]> for BTreeMap { } } -impl BTreeMap { +impl BTreeMap { /// Gets an iterator over the entries of the map, sorted by key. /// /// # Examples @@ -3422,7 +3420,7 @@ impl<'a, K, V, A> CursorMutKey<'a, K, V, A> { } // Now the tree editing operations -impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> { +impl<'a, K: Ord, V, A: AllocatorClone> CursorMutKey<'a, K, V, A> { /// Inserts a new key-value pair into the map in the gap that the /// cursor is currently pointing to. /// @@ -3627,7 +3625,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> { } } -impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { +impl<'a, K: Ord, V, A: AllocatorClone> CursorMut<'a, K, V, A> { /// Inserts a new key-value pair into the map in the gap that the /// cursor is currently pointing to. /// diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index 1c2ad5c568e6a..d3a9651799ab8 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -7,7 +7,7 @@ use Entry::*; use super::super::borrow::DormantMutRef; use super::super::node::{Handle, NodeRef, marker}; use super::BTreeMap; -use crate::alloc::{Allocator, Global}; +use crate::alloc::{AllocatorClone, Global}; /// A view into a single entry in a map, which may either be vacant or occupied. /// @@ -20,7 +20,7 @@ pub enum Entry< 'a, K: 'a, V: 'a, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocatorClone = Global, > { /// A vacant entry. #[stable(feature = "rust1", since = "1.0.0")] @@ -32,7 +32,7 @@ pub enum Entry< } #[stable(feature = "debug_btree_map", since = "1.12.0")] -impl Debug for Entry<'_, K, V, A> { +impl Debug for Entry<'_, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), @@ -48,7 +48,7 @@ pub struct VacantEntry< 'a, K, V, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocatorClone = Global, > { pub(super) key: K, /// `None` for a (empty) map without root @@ -63,7 +63,7 @@ pub struct VacantEntry< } #[stable(feature = "debug_btree_map", since = "1.12.0")] -impl Debug for VacantEntry<'_, K, V, A> { +impl Debug for VacantEntry<'_, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("VacantEntry").field(self.key()).finish() } @@ -76,7 +76,7 @@ pub struct OccupiedEntry< 'a, K, V, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocatorClone = Global, > { pub(super) handle: Handle, K, V, marker::LeafOrInternal>, marker::KV>, pub(super) dormant_map: DormantMutRef<'a, BTreeMap>, @@ -89,7 +89,7 @@ pub struct OccupiedEntry< } #[stable(feature = "debug_btree_map", since = "1.12.0")] -impl Debug for OccupiedEntry<'_, K, V, A> { +impl Debug for OccupiedEntry<'_, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedEntry").field("key", self.key()).field("value", self.get()).finish() } @@ -104,7 +104,7 @@ pub struct OccupiedError< 'a, K: 'a, V: 'a, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocatorClone = Global, > { /// The entry in the map that was already occupied. pub entry: OccupiedEntry<'a, K, V, A>, @@ -115,7 +115,7 @@ pub struct OccupiedError< } #[unstable(feature = "map_try_insert", issue = "82766")] -impl Debug for OccupiedError<'_, K, V, A> { +impl Debug for OccupiedError<'_, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedError") .field("key", self.entry.key()) @@ -126,7 +126,7 @@ impl Debug for OccupiedError<'_, } } -impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> { +impl<'a, K: Ord, V, A: AllocatorClone> Entry<'a, K, V, A> { /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. /// @@ -345,7 +345,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> { } } -impl<'a, K: Ord, V: Default, A: Allocator + Clone> Entry<'a, K, V, A> { +impl<'a, K: Ord, V: Default, A: AllocatorClone> Entry<'a, K, V, A> { #[stable(feature = "entry_or_default", since = "1.28.0")] /// Ensures a value is in the entry by inserting the default value if empty, /// and returns a mutable reference to the value in the entry. @@ -368,7 +368,7 @@ impl<'a, K: Ord, V: Default, A: Allocator + Clone> Entry<'a, K, V, A> { } } -impl<'a, K: Ord, V, A: Allocator + Clone> VacantEntry<'a, K, V, A> { +impl<'a, K: Ord, V, A: AllocatorClone> VacantEntry<'a, K, V, A> { /// Gets a reference to the key that would be used when inserting a value /// through the VacantEntry. /// @@ -479,7 +479,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> VacantEntry<'a, K, V, A> { } } -impl<'a, K: Ord, V, A: Allocator + Clone> OccupiedEntry<'a, K, V, A> { +impl<'a, K: Ord, V, A: AllocatorClone> OccupiedEntry<'a, K, V, A> { /// Gets a reference to the key in the entry. /// /// # Examples diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs index b2a7de74875d9..d5b514e67e82e 100644 --- a/library/alloc/src/collections/btree/navigate.rs +++ b/library/alloc/src/collections/btree/navigate.rs @@ -5,7 +5,7 @@ use core::{hint, ptr}; use super::node::ForceResult::*; use super::node::{Handle, NodeRef, marker}; use super::search::SearchBound; -use crate::alloc::Allocator; +use crate::alloc::AllocatorClone; // `front` and `back` are always both `None` or both `Some`. pub(super) struct LeafRange { front: Option, marker::Edge>>, @@ -190,7 +190,7 @@ impl LazyLeafRange { } #[inline] - pub(super) unsafe fn deallocating_next_unchecked( + pub(super) unsafe fn deallocating_next_unchecked( &mut self, alloc: A, ) -> Handle, marker::KV> { @@ -200,7 +200,7 @@ impl LazyLeafRange { } #[inline] - pub(super) unsafe fn deallocating_next_back_unchecked( + pub(super) unsafe fn deallocating_next_back_unchecked( &mut self, alloc: A, ) -> Handle, marker::KV> { @@ -210,7 +210,7 @@ impl LazyLeafRange { } #[inline] - pub(super) fn deallocating_end(&mut self, alloc: A) { + pub(super) fn deallocating_end(&mut self, alloc: A) { if let Some(front) = self.take_front() { front.deallocating_end(alloc) } @@ -456,7 +456,7 @@ impl Handle, marker::Edge> { /// `deallocating_next_back`. /// - The returned KV handle is only valid to access the key and value, /// and only valid until the next call to a `deallocating_` method. - unsafe fn deallocating_next( + unsafe fn deallocating_next( self, alloc: A, ) -> Option<(Self, Handle, marker::KV>)> @@ -488,7 +488,7 @@ impl Handle, marker::Edge> { /// `deallocating_next`. /// - The returned KV handle is only valid to access the key and value, /// and only valid until the next call to a `deallocating_` method. - unsafe fn deallocating_next_back( + unsafe fn deallocating_next_back( self, alloc: A, ) -> Option<(Self, Handle, marker::KV>)> @@ -513,7 +513,7 @@ impl Handle, marker::Edge> { /// both sides of the tree, and have hit the same edge. As it is intended /// only to be called when all keys and values have been returned, /// no cleanup is done on any of the keys or values. - fn deallocating_end(self, alloc: A) { + fn deallocating_end(self, alloc: A) { let mut edge = self.forget_node_type(); while let Some(parent_edge) = unsafe { edge.into_node().deallocate_and_ascend(alloc.clone()) } @@ -592,7 +592,7 @@ impl Handle, marker::Edge> { /// /// The only safe way to proceed with the updated handle is to compare it, drop it, /// or call this method or counterpart `deallocating_next_back_unchecked` again. - unsafe fn deallocating_next_unchecked( + unsafe fn deallocating_next_unchecked( &mut self, alloc: A, ) -> Handle, marker::KV> { @@ -613,7 +613,7 @@ impl Handle, marker::Edge> { /// /// The only safe way to proceed with the updated handle is to compare it, drop it, /// or call this method or counterpart `deallocating_next_unchecked` again. - unsafe fn deallocating_next_back_unchecked( + unsafe fn deallocating_next_back_unchecked( &mut self, alloc: A, ) -> Handle, marker::KV> { diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 0c7afcc63b9b7..8088fec38ed6a 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -37,7 +37,7 @@ use core::num::NonZero; use core::ptr::{self, NonNull}; use core::slice::SliceIndex; -use crate::alloc::{Allocator, Layout}; +use crate::alloc::{Allocator, AllocatorClone, Layout}; use crate::boxed::Box; const B: usize = 6; @@ -83,7 +83,7 @@ impl LeafNode { } /// Creates a new boxed `LeafNode`. - fn new(alloc: A) -> Box { + fn new(alloc: A) -> Box { let mut leaf = Box::new_uninit_in(alloc); unsafe { // SAFETY: `leaf` points to a `LeafNode` @@ -117,7 +117,7 @@ impl InternalNode { /// An invariant of internal nodes is that they have at least one /// initialized and valid edge. This function does not set up /// such an edge. - unsafe fn new(alloc: A) -> Box { + unsafe fn new(alloc: A) -> Box { let mut node = Box::::new_uninit_in(alloc); unsafe { // SAFETY: argument points to the `node.data` `LeafNode` @@ -221,11 +221,11 @@ unsafe impl Send for NodeRef unsafe impl Send for NodeRef {} impl NodeRef { - pub(super) fn new_leaf(alloc: A) -> Self { + pub(super) fn new_leaf(alloc: A) -> Self { Self::from_new_leaf(LeafNode::new(alloc)) } - fn from_new_leaf(leaf: Box, A>) -> Self { + fn from_new_leaf(leaf: Box, A>) -> Self { // The allocator must be dropped, not leaked. See also `BTreeMap::alloc`. let (node, _alloc) = Box::into_non_null_with_allocator(leaf); NodeRef { height: 0, node, _marker: PhantomData } @@ -234,14 +234,14 @@ impl NodeRef { impl NodeRef { /// Creates a new internal (height > 0) `NodeRef` - fn new_internal(child: Root, alloc: A) -> Self { + fn new_internal(child: Root, alloc: A) -> Self { let mut new_node = unsafe { InternalNode::new(alloc) }; new_node.edges[0].write(child.node); NodeRef::from_new_internal(new_node, NonZero::new(child.height + 1).unwrap()) } /// Creates a new internal (height > 0) `NodeRef` from an existing internal node - fn from_new_internal( + fn from_new_internal( internal: Box, A>, height: NonZero, ) -> Self { @@ -401,7 +401,7 @@ impl NodeRef { /// Similar to `ascend`, gets a reference to a node's parent node, but also /// deallocates the current node in the process. This is unsafe because the /// current node will still be accessible despite being deallocated. - pub(super) unsafe fn deallocate_and_ascend( + pub(super) unsafe fn deallocate_and_ascend( self, alloc: A, ) -> Option, marker::Edge>> { @@ -588,14 +588,14 @@ impl NodeRef { impl NodeRef { /// Returns a new owned tree, with its own root node that is initially empty. - pub(super) fn new(alloc: A) -> Self { + pub(super) fn new(alloc: A) -> Self { NodeRef::new_leaf(alloc).forget_type() } /// Adds a new internal node with a single edge pointing to the previous root node, /// make that new node the root node, and return it. This increases the height by 1 /// and is the opposite of `pop_internal_level`. - pub(super) fn push_internal_level( + pub(super) fn push_internal_level( &mut self, alloc: A, ) -> NodeRef, K, V, marker::Internal> { @@ -614,7 +614,7 @@ impl NodeRef { /// rooted at the first child of `self`. /// /// Panics if there is no internal level, i.e., if the root node is a leaf. - pub(super) fn pop_internal_level(&mut self, alloc: A) { + pub(super) fn pop_internal_level(&mut self, alloc: A) { assert!(self.height > 0); let top = self.node; @@ -950,7 +950,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark /// /// Returns a dormant handle to the inserted node which can be reawakened /// once splitting is complete. - fn insert( + fn insert( self, key: K, val: V, @@ -1017,7 +1017,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, /// Inserts a new key-value pair and an edge that will go to the right of that new pair /// between this edge and the key-value pair to the right of this edge. This method splits /// the node if there isn't enough room. - fn insert( + fn insert( mut self, key: K, val: V, @@ -1055,7 +1055,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark /// If the returned result is some `SplitResult`, the `left` field will be the root node. /// The returned pointer points to the inserted value, which in the case of `SplitResult` /// is in the `left` or `right` tree. - pub(super) fn insert_recursing( + pub(super) fn insert_recursing( self, key: K, value: V, @@ -1250,7 +1250,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark /// - The key and value pointed to by this handle are extracted. /// - All the key-value pairs to the right of this handle are put into a newly /// allocated node. - pub(super) fn split( + pub(super) fn split( mut self, alloc: A, ) -> SplitResult<'a, K, V, marker::Leaf> { @@ -1285,7 +1285,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, /// - The key and value pointed to by this handle are extracted. /// - All the edges and key-value pairs to the right of this handle are put into /// a newly allocated node. - pub(super) fn split( + pub(super) fn split( mut self, alloc: A, ) -> SplitResult<'a, K, V, marker::Internal> { @@ -1458,7 +1458,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { /// the left child node and returns the shrunk parent node. /// /// Panics unless we `.can_merge()`. - pub(super) fn merge_tracking_parent( + pub(super) fn merge_tracking_parent( self, alloc: A, ) -> NodeRef, K, V, marker::Internal> { @@ -1469,7 +1469,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { /// the left child node and returns that child node. /// /// Panics unless we `.can_merge()`. - pub(super) fn merge_tracking_child( + pub(super) fn merge_tracking_child( self, alloc: A, ) -> NodeRef, K, V, marker::LeafOrInternal> { @@ -1481,7 +1481,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { /// where the tracked child edge ended up, /// /// Panics unless we `.can_merge()`. - pub(super) fn merge_tracking_child_edge( + pub(super) fn merge_tracking_child_edge( self, track_edge_idx: LeftOrRight, alloc: A, diff --git a/library/alloc/src/collections/btree/remove.rs b/library/alloc/src/collections/btree/remove.rs index 9d870b86f34a0..b21c7e78b5bb3 100644 --- a/library/alloc/src/collections/btree/remove.rs +++ b/library/alloc/src/collections/btree/remove.rs @@ -1,4 +1,4 @@ -use core::alloc::Allocator; +use core::alloc::AllocatorClone; use super::map::MIN_LEN; use super::node::ForceResult::*; @@ -10,7 +10,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInter /// the leaf edge corresponding to that former pair. It's possible this empties /// a root node that is internal, which the caller should pop from the map /// holding the tree. The caller should also decrement the map's length. - pub(super) fn remove_kv_tracking( + pub(super) fn remove_kv_tracking( self, handle_emptied_internal_root: F, alloc: A, @@ -23,7 +23,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInter } impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, marker::KV> { - fn remove_leaf_kv( + fn remove_leaf_kv( self, handle_emptied_internal_root: F, alloc: A, @@ -76,7 +76,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, mark } impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, marker::KV> { - fn remove_internal_kv( + fn remove_internal_kv( self, handle_emptied_internal_root: F, alloc: A, diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index d06daa7c6c1b7..78b88eafea9b9 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -10,7 +10,7 @@ use core::ops::{BitAnd, BitOr, BitXor, Bound, RangeBounds, Sub}; use super::map::{self, BTreeMap, Keys}; use super::merge_iter::MergeIterInner; use super::set_val::SetValZST; -use crate::alloc::{Allocator, Global}; +use crate::alloc::{AllocatorClone, Global}; use crate::vec::Vec; mod entry; @@ -77,44 +77,44 @@ pub use self::entry::{Entry, OccupiedEntry, VacantEntry}; #[cfg_attr(not(test), rustc_diagnostic_item = "BTreeSet")] pub struct BTreeSet< T, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocatorClone = Global, > { map: BTreeMap, } #[stable(feature = "rust1", since = "1.0.0")] -impl Hash for BTreeSet { +impl Hash for BTreeSet { fn hash(&self, state: &mut H) { self.map.hash(state) } } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for BTreeSet { +impl PartialEq for BTreeSet { fn eq(&self, other: &BTreeSet) -> bool { self.map.eq(&other.map) } } #[stable(feature = "rust1", since = "1.0.0")] -impl Eq for BTreeSet {} +impl Eq for BTreeSet {} #[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for BTreeSet { +impl PartialOrd for BTreeSet { fn partial_cmp(&self, other: &BTreeSet) -> Option { self.map.partial_cmp(&other.map) } } #[stable(feature = "rust1", since = "1.0.0")] -impl Ord for BTreeSet { +impl Ord for BTreeSet { fn cmp(&self, other: &BTreeSet) -> Ordering { self.map.cmp(&other.map) } } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for BTreeSet { +impl Clone for BTreeSet { fn clone(&self) -> Self { BTreeSet { map: self.map.clone() } } @@ -153,7 +153,7 @@ impl fmt::Debug for Iter<'_, T> { #[derive(Debug)] pub struct IntoIter< T, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocatorClone = Global, > { iter: super::map::IntoIter, } @@ -183,11 +183,11 @@ pub struct Range<'a, T: 'a> { pub struct Difference< 'a, T: 'a, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocatorClone = Global, > { inner: DifferenceInner<'a, T, A>, } -enum DifferenceInner<'a, T: 'a, A: Allocator + Clone> { +enum DifferenceInner<'a, T: 'a, A: AllocatorClone> { Stitch { // iterate all of `self` and some of `other`, spotting matches along the way self_iter: Iter<'a, T>, @@ -202,7 +202,7 @@ enum DifferenceInner<'a, T: 'a, A: Allocator + Clone> { } // Explicit Debug impl necessary because of issue #26925 -impl Debug for DifferenceInner<'_, T, A> { +impl Debug for DifferenceInner<'_, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { DifferenceInner::Stitch { self_iter, other_iter } => f @@ -221,7 +221,7 @@ impl Debug for DifferenceInner<'_, T, A> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for Difference<'_, T, A> { +impl fmt::Debug for Difference<'_, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Difference").field(&self.inner).finish() } @@ -257,11 +257,11 @@ impl fmt::Debug for SymmetricDifference<'_, T> { pub struct Intersection< 'a, T: 'a, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocatorClone = Global, > { inner: IntersectionInner<'a, T, A>, } -enum IntersectionInner<'a, T: 'a, A: Allocator + Clone> { +enum IntersectionInner<'a, T: 'a, A: AllocatorClone> { Stitch { // iterate similarly sized sets jointly, spotting matches along the way a: Iter<'a, T>, @@ -276,7 +276,7 @@ enum IntersectionInner<'a, T: 'a, A: Allocator + Clone> { } // Explicit Debug impl necessary because of issue #26925 -impl Debug for IntersectionInner<'_, T, A> { +impl Debug for IntersectionInner<'_, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { IntersectionInner::Stitch { a, b } => { @@ -293,7 +293,7 @@ impl Debug for IntersectionInner<'_, T, A> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl Debug for Intersection<'_, T, A> { +impl Debug for Intersection<'_, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Intersection").field(&self.inner).finish() } @@ -346,7 +346,7 @@ impl BTreeSet { } } -impl BTreeSet { +impl BTreeSet { /// Makes a new `BTreeSet` with a reasonable choice of B. /// /// # Examples @@ -1481,7 +1481,7 @@ impl FromIterator for BTreeSet { } } -impl BTreeSet { +impl BTreeSet { fn from_sorted_iter>(iter: I, alloc: A) -> BTreeSet { let iter = iter.map(|k| (k, SetValZST::default())); let map = BTreeMap::bulk_build_from_sorted_iter(iter, alloc); @@ -1517,7 +1517,7 @@ impl From<[T; N]> for BTreeSet { } #[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for BTreeSet { +impl IntoIterator for BTreeSet { type Item = T; type IntoIter = IntoIter; @@ -1539,7 +1539,7 @@ impl IntoIterator for BTreeSet { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, A: Allocator + Clone> IntoIterator for &'a BTreeSet { +impl<'a, T, A: AllocatorClone> IntoIterator for &'a BTreeSet { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -1559,7 +1559,7 @@ pub struct ExtractIf< T, R, F, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocatorClone = Global, > { pred: F, inner: super::map::ExtractIfInner<'a, T, SetValZST, R>, @@ -1571,7 +1571,7 @@ pub struct ExtractIf< impl fmt::Debug for ExtractIf<'_, T, R, F, A> where T: fmt::Debug, - A: Allocator + Clone, + A: AllocatorClone, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ExtractIf") @@ -1581,7 +1581,7 @@ where } #[stable(feature = "btree_extract_if", since = "1.91.0")] -impl Iterator for ExtractIf<'_, T, R, F, A> +impl Iterator for ExtractIf<'_, T, R, F, A> where T: PartialOrd, R: RangeBounds, @@ -1601,7 +1601,7 @@ where } #[stable(feature = "btree_extract_if", since = "1.91.0")] -impl FusedIterator for ExtractIf<'_, T, R, F, A> +impl FusedIterator for ExtractIf<'_, T, R, F, A> where T: PartialOrd, R: RangeBounds, @@ -1610,7 +1610,7 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Extend for BTreeSet { +impl Extend for BTreeSet { #[inline] fn extend>(&mut self, iter: Iter) { iter.into_iter().for_each(move |elem| { @@ -1625,7 +1625,7 @@ impl Extend for BTreeSet { } #[stable(feature = "extend_ref", since = "1.2.0")] -impl<'a, T: 'a + Ord + Copy, A: Allocator + Clone> Extend<&'a T> for BTreeSet { +impl<'a, T: 'a + Ord + Copy, A: AllocatorClone> Extend<&'a T> for BTreeSet { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } @@ -1645,7 +1645,7 @@ impl Default for BTreeSet { } #[stable(feature = "rust1", since = "1.0.0")] -impl Sub<&BTreeSet> for &BTreeSet { +impl Sub<&BTreeSet> for &BTreeSet { type Output = BTreeSet; /// Returns the difference of `self` and `rhs` as a new `BTreeSet`. @@ -1670,7 +1670,7 @@ impl Sub<&BTreeSet> for &BTreeSet BitXor<&BTreeSet> for &BTreeSet { +impl BitXor<&BTreeSet> for &BTreeSet { type Output = BTreeSet; /// Returns the symmetric difference of `self` and `rhs` as a new `BTreeSet`. @@ -1695,7 +1695,7 @@ impl BitXor<&BTreeSet> for &BTreeSet } #[stable(feature = "rust1", since = "1.0.0")] -impl BitAnd<&BTreeSet> for &BTreeSet { +impl BitAnd<&BTreeSet> for &BTreeSet { type Output = BTreeSet; /// Returns the intersection of `self` and `rhs` as a new `BTreeSet`. @@ -1720,7 +1720,7 @@ impl BitAnd<&BTreeSet> for &BTreeSet } #[stable(feature = "rust1", since = "1.0.0")] -impl BitOr<&BTreeSet> for &BTreeSet { +impl BitOr<&BTreeSet> for &BTreeSet { type Output = BTreeSet; /// Returns the union of `self` and `rhs` as a new `BTreeSet`. @@ -1745,7 +1745,7 @@ impl BitOr<&BTreeSet> for &BTreeSet< } #[stable(feature = "rust1", since = "1.0.0")] -impl Debug for BTreeSet { +impl Debug for BTreeSet { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_set().entries(self.iter()).finish() } @@ -1810,7 +1810,7 @@ unsafe impl TrustedLen for Iter<'_, T> {} impl FusedIterator for Iter<'_, T> {} #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { +impl Iterator for IntoIter { type Item = T; fn next(&mut self) -> Option { @@ -1837,29 +1837,29 @@ impl Default for Iter<'_, T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for IntoIter { +impl DoubleEndedIterator for IntoIter { fn next_back(&mut self) -> Option { self.iter.next_back().map(|(k, _)| k) } } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter { +impl ExactSizeIterator for IntoIter { fn len(&self) -> usize { self.iter.len() } } #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for IntoIter {} +unsafe impl TrustedLen for IntoIter {} #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} +impl FusedIterator for IntoIter {} #[stable(feature = "default_iters", since = "1.70.0")] impl Default for IntoIter where - A: Allocator + Default + Clone, + A: AllocatorClone + Default, { /// Creates an empty `btree_set::IntoIter`. /// @@ -1932,7 +1932,7 @@ impl Default for Range<'_, T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Difference<'_, T, A> { +impl Clone for Difference<'_, T, A> { fn clone(&self) -> Self { Difference { inner: match &self.inner { @@ -1949,7 +1949,7 @@ impl Clone for Difference<'_, T, A> { } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: Ord, A: Allocator + Clone> Iterator for Difference<'a, T, A> { +impl<'a, T: Ord, A: AllocatorClone> Iterator for Difference<'a, T, A> { type Item = &'a T; fn next(&mut self) -> Option<&'a T> { @@ -1996,7 +1996,7 @@ impl<'a, T: Ord, A: Allocator + Clone> Iterator for Difference<'a, T, A> { } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Difference<'_, T, A> {} +impl FusedIterator for Difference<'_, T, A> {} #[stable(feature = "rust1", since = "1.0.0")] impl Clone for SymmetricDifference<'_, T> { @@ -2034,7 +2034,7 @@ impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> { impl FusedIterator for SymmetricDifference<'_, T> {} #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Intersection<'_, T, A> { +impl Clone for Intersection<'_, T, A> { fn clone(&self) -> Self { Intersection { inner: match &self.inner { @@ -2050,7 +2050,7 @@ impl Clone for Intersection<'_, T, A> { } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: Ord, A: Allocator + Clone> Iterator for Intersection<'a, T, A> { +impl<'a, T: Ord, A: AllocatorClone> Iterator for Intersection<'a, T, A> { type Item = &'a T; fn next(&mut self) -> Option<&'a T> { @@ -2091,7 +2091,7 @@ impl<'a, T: Ord, A: Allocator + Clone> Iterator for Intersection<'a, T, A> { } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Intersection<'_, T, A> {} +impl FusedIterator for Intersection<'_, T, A> {} #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Union<'_, T> { @@ -2356,7 +2356,7 @@ impl<'a, T, A> CursorMutKey<'a, T, A> { } } -impl<'a, T: Ord, A: Allocator + Clone> CursorMut<'a, T, A> { +impl<'a, T: Ord, A: AllocatorClone> CursorMut<'a, T, A> { /// Inserts a new element into the set in the gap that the /// cursor is currently pointing to. /// @@ -2442,7 +2442,7 @@ impl<'a, T: Ord, A: Allocator + Clone> CursorMut<'a, T, A> { } } -impl<'a, T: Ord, A: Allocator + Clone> CursorMutKey<'a, T, A> { +impl<'a, T: Ord, A: AllocatorClone> CursorMutKey<'a, T, A> { /// Inserts a new element into the set in the gap that the /// cursor is currently pointing to. /// diff --git a/library/alloc/src/collections/btree/set/entry.rs b/library/alloc/src/collections/btree/set/entry.rs index a60d22f9ece71..89bc09bca2f5c 100644 --- a/library/alloc/src/collections/btree/set/entry.rs +++ b/library/alloc/src/collections/btree/set/entry.rs @@ -3,7 +3,7 @@ use core::fmt::{self, Debug}; use Entry::*; use super::{SetValZST, map}; -use crate::alloc::{Allocator, Global}; +use crate::alloc::{AllocatorClone, Global}; /// A view into a single entry in a set, which may either be vacant or occupied. /// @@ -42,7 +42,7 @@ use crate::alloc::{Allocator, Global}; pub enum Entry< 'a, T, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocatorClone = Global, > { /// An occupied entry. /// @@ -84,7 +84,7 @@ pub enum Entry< } #[unstable(feature = "btree_set_entry", issue = "133549")] -impl Debug for Entry<'_, T, A> { +impl Debug for Entry<'_, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), @@ -133,13 +133,13 @@ impl Debug for Entry<'_, T, A> { pub struct OccupiedEntry< 'a, T, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocatorClone = Global, > { pub(super) inner: map::OccupiedEntry<'a, T, SetValZST, A>, } #[unstable(feature = "btree_set_entry", issue = "133549")] -impl Debug for OccupiedEntry<'_, T, A> { +impl Debug for OccupiedEntry<'_, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedEntry").field("value", self.get()).finish() } @@ -175,19 +175,19 @@ impl Debug for OccupiedEntry<'_, T, A> { pub struct VacantEntry< 'a, T, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: AllocatorClone = Global, > { pub(super) inner: map::VacantEntry<'a, T, SetValZST, A>, } #[unstable(feature = "btree_set_entry", issue = "133549")] -impl Debug for VacantEntry<'_, T, A> { +impl Debug for VacantEntry<'_, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("VacantEntry").field(self.get()).finish() } } -impl<'a, T: Ord, A: Allocator + Clone> Entry<'a, T, A> { +impl<'a, T: Ord, A: AllocatorClone> Entry<'a, T, A> { /// Sets the value of the entry, and returns an `OccupiedEntry`. /// /// # Examples @@ -266,7 +266,7 @@ impl<'a, T: Ord, A: Allocator + Clone> Entry<'a, T, A> { } } -impl<'a, T: Ord, A: Allocator + Clone> OccupiedEntry<'a, T, A> { +impl<'a, T: Ord, A: AllocatorClone> OccupiedEntry<'a, T, A> { /// Gets a reference to the value in the entry. /// /// # Examples @@ -316,7 +316,7 @@ impl<'a, T: Ord, A: Allocator + Clone> OccupiedEntry<'a, T, A> { } } -impl<'a, T: Ord, A: Allocator + Clone> VacantEntry<'a, T, A> { +impl<'a, T: Ord, A: AllocatorClone> VacantEntry<'a, T, A> { /// Gets a reference to the value that would be used when inserting /// through the `VacantEntry`. /// diff --git a/library/alloc/src/collections/btree/split.rs b/library/alloc/src/collections/btree/split.rs index 87a79e6cf3f93..5d5f379c2da44 100644 --- a/library/alloc/src/collections/btree/split.rs +++ b/library/alloc/src/collections/btree/split.rs @@ -1,4 +1,4 @@ -use core::alloc::Allocator; +use core::alloc::AllocatorClone; use core::borrow::Borrow; use super::node::ForceResult::*; @@ -31,7 +31,7 @@ impl Root { /// and if the ordering of `Q` corresponds to that of `K`. /// If `self` respects all `BTreeMap` tree invariants, then both /// `self` and the returned tree will respect those invariants. - pub(super) fn split_off( + pub(super) fn split_off( &mut self, key: &Q, alloc: A, @@ -69,7 +69,7 @@ impl Root { } /// Creates a tree consisting of empty nodes. - fn new_pillar(height: usize, alloc: A) -> Self { + fn new_pillar(height: usize, alloc: A) -> Self { let mut root = Root::new(alloc.clone()); for _ in 0..height { root.push_internal_level(alloc.clone()); From c42b90f54a9be0a4441de8959483d649134f518c Mon Sep 17 00:00:00 2001 From: zakrad <49591476+zakrad@users.noreply.github.com> Date: Tue, 25 Aug 2026 11:20:28 +0330 Subject: [PATCH 14/49] Add codegen test for disjunction fed to unreachable_unchecked --- .../unreachable-disjunction-div-115026.rs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/codegen-llvm/issues/unreachable-disjunction-div-115026.rs diff --git a/tests/codegen-llvm/issues/unreachable-disjunction-div-115026.rs b/tests/codegen-llvm/issues/unreachable-disjunction-div-115026.rs new file mode 100644 index 0000000000000..542cd0114c3f1 --- /dev/null +++ b/tests/codegen-llvm/issues/unreachable-disjunction-div-115026.rs @@ -0,0 +1,23 @@ +// Tests that a disjunction passed to `unreachable_unchecked` still rules out +// both division operands, so neither the division-by-zero check nor the +// overflow check survives. +// See . + +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @disjunction_div( +// CHECK-NOT: panic +// CHECK-NOT: br {{.*}} +// CHECK: sdiv i64 +// CHECK: ret i64 +#[no_mangle] +pub fn disjunction_div(num: i64, x: i64) -> i64 { + unsafe { + if x == -1 || x == 0 { + std::hint::unreachable_unchecked() + } + } + num / x +} From 2686c8c0128c0cd672f5b6df5603f7743f64b846 Mon Sep 17 00:00:00 2001 From: Rani367 Date: Mon, 13 Jul 2026 18:14:29 +0300 Subject: [PATCH 15/49] Don't list escaping bound regions in nested `for<...>` binders of E0308 notes The `for<...>` prefixes in `cmp_fn_sig` are built from the region map returned by `name_all_regions`. That map also contained regions that are bound by an enclosing binder and merely escape through the binder being named, so nested binders in expected/found notes listed lifetimes they don't bind, printing invalid types such as `&mut for<'a> fn(for<'a> fn(&'a ()))` for `&mut for<'a> fn(fn(&'a ()))`. Key the folder's map by the region's binder offset and only return the regions actually bound by the binder being named. The offset in the key also fixes a latent collision between a bound and an escaping region sharing the same bound variable index. The printed text is unaffected: the `name` closure already skips escaping regions when writing to the printer, which is why diagnostic labels were already correct. --- compiler/rustc_middle/src/ty/print/pretty.rs | 44 ++++++------------- .../nested-binder-cmp-fn-sig-print.rs | 26 +++++++++++ .../nested-binder-cmp-fn-sig-print.stderr | 23 ++++++++++ .../placeholder-outlives-existential.stderr | 2 +- 4 files changed, 63 insertions(+), 32 deletions(-) create mode 100644 tests/ui/higher-ranked/nested-binder-cmp-fn-sig-print.rs create mode 100644 tests/ui/higher-ranked/nested-binder-cmp-fn-sig-print.stderr diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 03d13e6a81a6e..ee8d8659e66e1 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2692,15 +2692,10 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { struct RegionFolder<'a, 'tcx> { tcx: TyCtxt<'tcx>, current_index: ty::DebruijnIndex, + /// Regions bound by the binder being named (and placeholders) that have + /// already been named. region_map: UnordMap, ty::Region<'tcx>>, - name: &'a mut ( - dyn FnMut( - Option, // Debruijn index of the folded late-bound region - ty::DebruijnIndex, // Index corresponding to binder level - ty::BoundRegion<'tcx>, - ) -> ty::Region<'tcx> - + 'a - ), + name: &'a mut (dyn FnMut(ty::BoundRegion<'tcx>) -> ty::Region<'tcx> + 'a), } impl<'a, 'tcx> ty::TypeFolder> for RegionFolder<'a, 'tcx> { @@ -2731,8 +2726,13 @@ impl<'a, 'tcx> ty::TypeFolder> for RegionFolder<'a, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { let name = &mut self.name; let region = match r.kind() { - ty::ReBound(ty::BoundVarIndexKind::Bound(db), br) if db >= self.current_index => { - *self.region_map.entry(br).or_insert_with(|| name(Some(db), self.current_index, br)) + // Only name regions bound by the binder being named. Regions bound by an + // enclosing binder that merely escape through this one keep their name + // (they were named when that binder was folded) and their index, and must + // not end up in `region_map`, which callers use to build `for<...>` lists + // (#102392, #134410). + ty::ReBound(ty::BoundVarIndexKind::Bound(db), br) if db == self.current_index => { + *self.region_map.entry(br).or_insert_with(|| name(br)) } ty::RePlaceholder(ty::PlaceholderRegion { bound: ty::BoundRegion { kind, .. }, @@ -2745,10 +2745,7 @@ impl<'a, 'tcx> ty::TypeFolder> for RegionFolder<'a, 'tcx> { _ => { // Index doesn't matter, since this is just for naming and these never get bound let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind }; - *self - .region_map - .entry(br) - .or_insert_with(|| name(None, self.current_index, br)) + *self.region_map.entry(br).or_insert_with(|| name(br)) } } } @@ -2857,13 +2854,8 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { let trim_path = with_forced_trimmed_paths(); // Closure used in `RegionFolder` to create names for anonymous late-bound - // regions. We use two `DebruijnIndex`es (one for the currently folded - // late-bound region and the other for the binder level) to determine - // whether a name has already been created for the currently folded region, - // see issue #102392. - let mut name = |lifetime_idx: Option, - binder_level_idx: ty::DebruijnIndex, - br: ty::BoundRegion<'tcx>| { + // regions. + let mut name = |br: ty::BoundRegion<'tcx>| { let (name, kind) = if let Some(name) = br.kind.get_name(tcx) { (name, br.kind) } else { @@ -2871,16 +2863,6 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { (name, ty::BoundRegionKind::NamedForPrinting(name)) }; - if let Some(lt_idx) = lifetime_idx { - if lt_idx > binder_level_idx { - return ty::Region::new_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { var: br.var, kind }, - ); - } - } - // Unconditionally render `unsafe<>`. if !trim_path || mode == WrapBinderMode::Unsafe { start_or_continue(self, mode.start_str(), ", "); diff --git a/tests/ui/higher-ranked/nested-binder-cmp-fn-sig-print.rs b/tests/ui/higher-ranked/nested-binder-cmp-fn-sig-print.rs new file mode 100644 index 0000000000000..65620812e3f8a --- /dev/null +++ b/tests/ui/higher-ranked/nested-binder-cmp-fn-sig-print.rs @@ -0,0 +1,26 @@ +//! Regression test for and +//! . +//! +//! The expected/found notes of "one type is more general than the other" errors +//! used to leak lifetimes bound by outer binders into nested `for<...>` lists, +//! printing invalid types such as `&mut for<'a> fn(for<'a> fn(&'a ()))` or +//! `for<'o> fn(for<'a, 'o> fn(&'a (), &'o ()))`. + +type F1 = fn(fn(&'static ())); +type F2 = for<'a> fn(fn(&'a ())); + +fn issue_134410(a: &mut F1) { + let _: &mut F2 = a; //~ ERROR mismatched types +} + +type One = fn(HelperOne); +type HelperOne = for<'a> fn(&'a (), &'a ()); + +type Two = for<'o> fn(HelperTwo<'o>); +type HelperTwo<'x> = for<'a> fn(&'a (), &'x ()); + +fn issue_111365(x: One) -> Two { + x //~ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/higher-ranked/nested-binder-cmp-fn-sig-print.stderr b/tests/ui/higher-ranked/nested-binder-cmp-fn-sig-print.stderr new file mode 100644 index 0000000000000..c26b39ec5a567 --- /dev/null +++ b/tests/ui/higher-ranked/nested-binder-cmp-fn-sig-print.stderr @@ -0,0 +1,23 @@ +error[E0308]: mismatched types + --> $DIR/nested-binder-cmp-fn-sig-print.rs:23:5 + | +LL | fn issue_111365(x: One) -> Two { + | --- expected `for<'o> fn(for<'a> fn(&'a (), &'o ()))` because of return type +LL | x + | ^ one type is more general than the other + | + = note: expected fn pointer `for<'o> fn(for<'a> fn(&'a (), &'o ()))` + found fn pointer `fn(for<'a> fn(&'a (), &'a ()))` + +error[E0308]: mismatched types + --> $DIR/nested-binder-cmp-fn-sig-print.rs:13:22 + | +LL | let _: &mut F2 = a; + | ^ one type is more general than the other + | + = note: expected mutable reference `&mut for<'a> fn(fn(&'a ()))` + found mutable reference `&mut fn(fn(&()))` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/nll/relate_tys/placeholder-outlives-existential.stderr b/tests/ui/nll/relate_tys/placeholder-outlives-existential.stderr index 80ab5c8d6e9d8..05950c4d4f48a 100644 --- a/tests/ui/nll/relate_tys/placeholder-outlives-existential.stderr +++ b/tests/ui/nll/relate_tys/placeholder-outlives-existential.stderr @@ -5,7 +5,7 @@ LL | x | ^ one type is more general than the other | = note: expected fn pointer `fn(fn(fn(for<'unify> fn(Contra<'unify>, Co<'unify>))))` - found fn pointer `for<'e> fn(for<'e, 'p> fn(for<'e, 'p> fn(for<'e, 'p> fn(Contra<'e>, Co<'p>))))` + found fn pointer `for<'e> fn(for<'p> fn(fn(fn(Contra<'e>, Co<'p>))))` error: lifetime may not live long enough --> $DIR/placeholder-outlives-existential.rs:28:5 From 8432202b58569eb29b4ca2750eb7eefea94c0f04 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 12 Aug 2026 14:06:15 +0000 Subject: [PATCH 16/49] clippy::manual_is_ascii_check --- library/core/src/char/methods.rs | 2 ++ library/core/src/num/mod.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index f6930e0a60d42..f59219c09dc28 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1,5 +1,7 @@ //! impl char {} +#![expect(clippy::manual_is_ascii_check, reason = "this module implements various is_ascii checks")] + use super::*; use crate::panic::const_panic; use crate::slice; diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 3fe7b95283446..59e470800dbd3 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1,6 +1,7 @@ //! Numeric traits and functions for the built-in numeric types. #![stable(feature = "rust1", since = "1.0.0")] +#![expect(clippy::manual_is_ascii_check, reason = "this module implements various is_ascii checks")] use crate::convert::{BoundedCastFromInt, CheckedCastFromInt}; use crate::panic::const_panic; From 563b1126276b21311bea4c24eedc3095eccd3f26 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 12 Aug 2026 14:12:27 +0000 Subject: [PATCH 17/49] clippy::manual_ignore_case_cmp --- library/core/src/ascii/ascii_char.rs | 2 +- library/core/src/char/methods.rs | 1 + library/core/src/num/mod.rs | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs index de1adf9c9ec7c..801144826a2ed 100644 --- a/library/core/src/ascii/ascii_char.rs +++ b/library/core/src/ascii/ascii_char.rs @@ -635,7 +635,7 @@ impl AsciiChar { pub const fn eq_ignore_case(self, other: Self) -> bool { // FIXME(const-hack) `arg.to_u8().to_ascii_lowercase()` -> `arg.to_lowercase()` // once `PartialEq` is const for `Self`. - self.to_u8().to_ascii_lowercase() == other.to_u8().to_ascii_lowercase() + self.to_u8().eq_ignore_ascii_case(&other.to_u8()) } /// Converts this value to its upper case equivalent in-place. diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index f59219c09dc28..8009f6514945e 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1987,6 +1987,7 @@ impl char { /// [to_ascii_lowercase]: #method.to_ascii_lowercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")] + #[expect(clippy::manual_ignore_case_cmp, reason = "implements eq_ignore_ascii_case")] #[inline] pub const fn eq_ignore_ascii_case(&self, other: &char) -> bool { self.to_ascii_lowercase() == other.to_ascii_lowercase() diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 59e470800dbd3..db41d23770477 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -732,6 +732,7 @@ impl u8 { /// ``` #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")] + #[expect(clippy::manual_ignore_case_cmp, reason = "implements eq_ignore_ascii_case")] #[inline] pub const fn eq_ignore_ascii_case(&self, other: &u8) -> bool { self.to_ascii_lowercase() == other.to_ascii_lowercase() From 5fa3b601d4340277bde4e5b451b5bcd68a36ed9a Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 12 Aug 2026 15:25:02 +0000 Subject: [PATCH 18/49] clippy::manual_hash_one --- library/core/src/hash/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index c7c8d57e1010d..f1a93a880e7f4 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -691,6 +691,7 @@ pub trait BuildHasher { /// ); /// ``` #[stable(feature = "build_hasher_simple_hash_one", since = "1.71.0")] + #[expect(clippy::manual_hash_one, reason = "implements hash_one")] fn hash_one(&self, x: T) -> u64 where Self: Sized, From 7cf35bdf6354e753df13f21f53a34c8012a43ea1 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 12 Aug 2026 15:53:51 +0000 Subject: [PATCH 19/49] clippy::excessive_precision --- library/core/src/num/f32.rs | 8 ++++---- library/core/src/num/f64.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 723e64aa9ac54..3f7b33770fc08 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -438,7 +438,7 @@ impl f32 { /// [`MANTISSA_DIGITS`]: f32::MANTISSA_DIGITS #[stable(feature = "assoc_int_consts", since = "1.43.0")] #[rustc_diagnostic_item = "f32_epsilon"] - pub const EPSILON: f32 = 1.19209290e-07_f32; + pub const EPSILON: f32 = 1.1920929e-07_f32; /// Smallest finite `f32` value. /// @@ -446,14 +446,14 @@ impl f32 { /// /// [`MAX`]: f32::MAX #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MIN: f32 = -3.40282347e+38_f32; + pub const MIN: f32 = -3.4028235e+38_f32; /// Smallest positive normal `f32` value. /// /// Equal to 2[`MIN_EXP`] − 1. /// /// [`MIN_EXP`]: f32::MIN_EXP #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MIN_POSITIVE: f32 = 1.17549435e-38_f32; + pub const MIN_POSITIVE: f32 = 1.1754944e-38_f32; /// Largest finite `f32` value. /// /// Equal to @@ -462,7 +462,7 @@ impl f32 { /// [`MANTISSA_DIGITS`]: f32::MANTISSA_DIGITS /// [`MAX_EXP`]: f32::MAX_EXP #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MAX: f32 = 3.40282347e+38_f32; + pub const MAX: f32 = 3.4028235e+38_f32; /// One greater than the minimum possible *normal* power of 2 exponent /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index d23b3e5616302..5bc2f8d0feb32 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -437,7 +437,7 @@ impl f64 { /// [`MANTISSA_DIGITS`]: f64::MANTISSA_DIGITS #[stable(feature = "assoc_int_consts", since = "1.43.0")] #[rustc_diagnostic_item = "f64_epsilon"] - pub const EPSILON: f64 = 2.2204460492503131e-16_f64; + pub const EPSILON: f64 = 2.220446049250313e-16_f64; /// Smallest finite `f64` value. /// From abce09f22bac285697aba605b8bacfd2fa857172 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 12 Aug 2026 16:06:42 +0000 Subject: [PATCH 20/49] clippy::partialeq_ne_impl --- library/alloc/src/lib.rs | 1 + library/core/src/lib.rs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 2b0b1ade64087..89b15a169dce0 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -59,6 +59,7 @@ #![allow(unused_features)] #![allow(incomplete_features)] #![allow(unused_attributes)] +#![expect(clippy::partialeq_ne_impl, reason = "we need to implement ne for a lot of alloc types")] #![stable(feature = "alloc", since = "1.36.0")] #![doc( html_playground_url = "https://play.rust-lang.org/", diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 89ae9179f4e25..9af39dfc9cb55 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -186,6 +186,10 @@ #![feature(x86_amx_intrinsics)] // tidy-alphabetical-end +// tidy-alphabetical-start +#![expect(clippy::partialeq_ne_impl, reason = "we need to implement ne for a lot of core types")] +// tidy-alphabetical-end + // allow using `core::` in intra-doc links #[allow(unused_extern_crates)] extern crate self as core; From d86766756e6266ecaf13ebd26ddc8c29b782853c Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 13 Aug 2026 00:36:30 +0000 Subject: [PATCH 21/49] clippy::manual_contains --- library/core/src/slice/cmp.rs | 2 ++ library/std/src/sys/path/windows_prefix.rs | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 70d2392dfb3c6..acb74c9916dfd 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -386,6 +386,7 @@ impl SliceContains for T where T: PartialEq, { + #[expect(clippy::manual_contains, reason = "implements slice_contains")] default fn slice_contains(&self, x: &[Self]) -> bool { x.iter().any(|y| *y == *self) } @@ -393,6 +394,7 @@ where impl SliceContains for T { #[inline] + #[expect(clippy::manual_contains, reason = "implements slice_contains")] default fn slice_contains(&self, x: &[Self]) -> bool { if size_of::() == 1 { // SAFETY: `BytewiseEq` guarantees that values have no padding or provenance and diff --git a/library/std/src/sys/path/windows_prefix.rs b/library/std/src/sys/path/windows_prefix.rs index 5413269e9edee..37417b2bbc475 100644 --- a/library/std/src/sys/path/windows_prefix.rs +++ b/library/std/src/sys/path/windows_prefix.rs @@ -68,7 +68,7 @@ pub fn parse_prefix(path: &OsStr) -> Option> { // \\ // It's a POSIX path. - if cfg!(target_os = "cygwin") && !path.as_encoded_bytes().iter().any(|&x| x == b'\\') { + if cfg!(target_os = "cygwin") && !path.as_encoded_bytes().contains(&b'\\') { return None; } @@ -76,7 +76,7 @@ pub fn parse_prefix(path: &OsStr) -> Option> { // separator. if let Some(parser) = parser.strip_prefix(r"?\") // Cygwin allows `/` in verbatim paths. - && (cfg!(target_os = "cygwin") || !parser.prefix_bytes().iter().any(|&x| x == b'/')) + && (cfg!(target_os = "cygwin") || !parser.prefix_bytes().contains(&b'/')) { // \\?\ if let Some(parser) = parser.strip_prefix(r"UNC\") { From b6ef1ff96568758a41d3e81b2b818576e1ab1e93 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 13 Aug 2026 01:25:04 +0000 Subject: [PATCH 22/49] clippy::single_match --- library/core/src/intrinsics/mod.rs | 11 +++-------- library/std/src/sys/process/unix/unix.rs | 5 ++--- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 2316fc4318918..673454abaf04f 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2915,14 +2915,9 @@ pub const fn contract_check_ensures bool + Copy, Ret>( // Do nothing ret } else { - match cond { - crate::option::Option::Some(cond) => { - if !cond(&ret) { - // Emit no unwind panic in case this was a safety requirement. - crate::panicking::panic_nounwind("failed ensures check"); - } - }, - crate::option::Option::None => {}, + if let crate::option::Option::Some(cond) = cond && !cond(&ret) { + // Emit no unwind panic in case this was a safety requirement. + crate::panicking::panic_nounwind("failed ensures check"); } ret } diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index 6103fa3576f37..ba1286e0e5a09 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -928,9 +928,8 @@ impl Command { msg.msg_controllen = size_of::() as _; msg.msg_control = (&raw mut cmsg) as *mut _; - match cvt_r(|| libc::recvmsg(sock.as_raw(), &mut msg, libc::MSG_CMSG_CLOEXEC)) { - Err(_) => return -1, - Ok(_) => {} + if cvt_r(|| libc::recvmsg(sock.as_raw(), &mut msg, libc::MSG_CMSG_CLOEXEC)).is_err() { + return -1; } let hdr = CMSG_FIRSTHDR((&raw mut msg) as *mut _); From fd0a93fdd1e606fecdb7a718e5e5e9f9e6a754bf Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 13 Aug 2026 01:17:56 +0000 Subject: [PATCH 23/49] clippy::match_as_ref --- library/core/src/option.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 5d86f851dbd1d..9aaa80db055a4 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -737,6 +737,7 @@ impl Option { /// println!("still can print text: {text:?}"); /// ``` #[inline] + #[expect(clippy::match_as_ref, reason = "implements as_ref")] #[rustc_const_stable(feature = "const_option_basics", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn as_ref(&self) -> Option<&T> { @@ -759,6 +760,7 @@ impl Option { /// assert_eq!(x, Some(42)); /// ``` #[inline] + #[expect(clippy::match_as_ref, reason = "implements as_mut")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_option", since = "1.83.0")] pub const fn as_mut(&mut self) -> Option<&mut T> { From 28f78d48ee61e0925393d36e4a88b8cc629245b5 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 13 Aug 2026 13:53:55 +0000 Subject: [PATCH 24/49] clippy::default_constructed_unit_structs --- library/alloc/src/collections/btree/set.rs | 4 ++-- library/core/src/field.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index d06daa7c6c1b7..fb98c30ae5e69 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -901,7 +901,7 @@ impl BTreeSet { where T: Ord, { - self.map.insert(value, SetValZST::default()).is_none() + self.map.insert(value, SetValZST).is_none() } /// Adds a value to the set, replacing the existing element, if any, that is @@ -1483,7 +1483,7 @@ impl FromIterator for BTreeSet { impl BTreeSet { fn from_sorted_iter>(iter: I, alloc: A) -> BTreeSet { - let iter = iter.map(|k| (k, SetValZST::default())); + let iter = iter.map(|k| (k, SetValZST)); let map = BTreeMap::bulk_build_from_sorted_iter(iter, alloc); BTreeSet { map } } diff --git a/library/core/src/field.rs b/library/core/src/field.rs index 915a4c07b9e23..5a8ae7759bc1e 100644 --- a/library/core/src/field.rs +++ b/library/core/src/field.rs @@ -78,7 +78,7 @@ impl Default for FieldRepresentingType { fn default() -> Self { - Self { _phantom: PhantomData::default() } + Self { _phantom: PhantomData } } } From a7f7b19ad6f184b82a3075ac32b94c90a8594975 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 13 Aug 2026 13:56:21 +0000 Subject: [PATCH 25/49] clippy::redundant_closure --- library/alloc/src/collections/vec_deque/mod.rs | 4 ++-- library/std/src/sys/fs/unix/dir.rs | 2 +- library/std/src/sys/fs/windows.rs | 2 +- library/std/src/sys/process/unix/unix.rs | 2 +- library/std/src/thread/spawnhook.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 9095fc0d4abf4..a24e4d72fe38e 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -3312,7 +3312,7 @@ impl VecDeque { F: FnMut(&'a T) -> Ordering, { let (front, back) = self.as_slices(); - let cmp_back = back.first().map(|elem| f(elem)); + let cmp_back = back.first().map(&mut f); if let Some(Ordering::Equal) = cmp_back { Ok(front.len()) @@ -3423,7 +3423,7 @@ impl VecDeque { { let (front, back) = self.as_slices(); - if let Some(true) = back.first().map(|v| pred(v)) { + if let Some(true) = back.first().map(&mut pred) { back.partition_point(pred) + front.len() } else { front.partition_point(pred) diff --git a/library/std/src/sys/fs/unix/dir.rs b/library/std/src/sys/fs/unix/dir.rs index aad309362127b..3fe952d942927 100644 --- a/library/std/src/sys/fs/unix/dir.rs +++ b/library/std/src/sys/fs/unix/dir.rs @@ -49,7 +49,7 @@ impl Dir { pub fn open_file(&self, path: &Path, opts: &OpenOptions) -> io::Result { run_path_with_cstr(path.as_ref(), &|path| self.open_file_c(path, opts, 0)) - .map(|fd| FileDesc::from_inner(fd)) + .map(FileDesc::from_inner) .map(File) } diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index c10b266ccb726..4446a4c3e3c8f 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -1114,7 +1114,7 @@ impl FileAttr { } pub fn changed_u64(&self) -> Option { - self.change_time.as_ref().map(|c| to_u64(c)) + self.change_time.as_ref().map(to_u64) } pub fn volume_serial_number(&self) -> Option { diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index ba1286e0e5a09..8729ab65b86db 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -1316,7 +1316,7 @@ mod linux_child_ext { self.handle .pidfd .take() - .map(|fd| >::from_inner(fd)) + .map(>::from_inner) .ok_or_else(|| self) } } diff --git a/library/std/src/thread/spawnhook.rs b/library/std/src/thread/spawnhook.rs index 92fb586d39dcf..1bf22e0b0ea52 100644 --- a/library/std/src/thread/spawnhook.rs +++ b/library/std/src/thread/spawnhook.rs @@ -21,7 +21,7 @@ struct SpawnHooks { impl Drop for SpawnHooks { fn drop(&mut self) { let mut next = self.first.take(); - while let Some(SpawnHook { hook, next: n }) = next.and_then(|n| Arc::into_inner(n)) { + while let Some(SpawnHook { hook, next: n }) = next.and_then(Arc::into_inner) { drop(hook); next = n; } From 097f843c2d92ac1a4ed3464ab73b11c36f50c354 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 13 Aug 2026 14:12:28 +0000 Subject: [PATCH 26/49] clippy::derivable_impls --- library/alloc/src/bstr.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/library/alloc/src/bstr.rs b/library/alloc/src/bstr.rs index 9aa3064da886f..f48b2d52e80c1 100644 --- a/library/alloc/src/bstr.rs +++ b/library/alloc/src/bstr.rs @@ -42,7 +42,7 @@ use crate::vec::Vec; /// showing invalid UTF-8 as hex escapes or the Unicode replacement character, respectively. #[unstable(feature = "bstr", issue = "134915")] #[repr(transparent)] -#[derive(Clone)] +#[derive(Clone, Default)] #[doc(alias = "BString")] pub struct ByteString(pub Vec); @@ -187,13 +187,6 @@ impl BorrowMut for ByteString { // `impl BorrowMut for Vec` omitted to avoid inference failures -#[unstable(feature = "bstr", issue = "134915")] -impl Default for ByteString { - fn default() -> Self { - ByteString(Vec::new()) - } -} - // Omitted due to inference failures // // #[unstable(feature = "bstr", issue = "134915")] From ff47e6795324fa2592bfe2e8ac547f79a25f33ba Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 13 Aug 2026 14:14:36 +0000 Subject: [PATCH 27/49] clippy::partialeq_to_none --- library/std/src/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 3cc375b7290da..6ad20b192fa5c 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -3740,7 +3740,7 @@ impl DirBuilder { fn create_dir_all(&self, path: &Path) -> io::Result<()> { // if path's parent is None, it is "/" path, which should // return Ok immediately - if path.is_empty() || path.parent() == None { + if path.is_empty() || path.parent().is_none() { return Ok(()); } @@ -3751,7 +3751,7 @@ impl DirBuilder { // for relative paths like "foo/bar", the parent of // "foo" will be "" which there's no need to invoke // a mkdir syscall on - if ancestor.is_empty() || ancestor.parent() == None { + if ancestor.is_empty() || ancestor.parent().is_none() { break; } From 8523083b1a4b287d4c7a08018adb778a584395a0 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 13 Aug 2026 14:20:50 +0000 Subject: [PATCH 28/49] clippy::unnecessary_map_or --- library/core/src/option.rs | 2 +- library/std/src/collections/hash/map.rs | 2 +- library/std/src/sys/fs/windows.rs | 12 ++++++------ library/test/src/term/terminfo/mod.rs | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 9aaa80db055a4..f91e9ffcc4567 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1934,7 +1934,7 @@ impl Option { where P: [const] FnOnce(&mut T) -> bool + [const] Destruct, { - if self.as_mut().map_or(false, predicate) { self.take() } else { None } + if self.as_mut().is_some_and(predicate) { self.take() } else { None } } /// Replaces the actual value in the option by the value given in parameter, diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index fef0b1b4df88e..2858680a20a49 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1457,7 +1457,7 @@ where return false; } - self.iter().all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) + self.iter().all(|(key, value)| other.get(key).is_some_and(|v| *value == *v)) } } diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index 4446a4c3e3c8f..c99524375113a 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -784,9 +784,9 @@ impl File { pub fn set_times(&self, times: FileTimes) -> io::Result<()> { let is_zero = |t: c::FILETIME| t.dwLowDateTime == 0 && t.dwHighDateTime == 0; - if times.accessed.map_or(false, is_zero) - || times.modified.map_or(false, is_zero) - || times.created.map_or(false, is_zero) + if times.accessed.is_some_and(is_zero) + || times.modified.is_some_and(is_zero) + || times.created.is_some_and(is_zero) { return Err(io::const_error!( io::ErrorKind::InvalidInput, @@ -794,9 +794,9 @@ impl File { )); } let is_max = |t: c::FILETIME| t.dwLowDateTime == u32::MAX && t.dwHighDateTime == u32::MAX; - if times.accessed.map_or(false, is_max) - || times.modified.map_or(false, is_max) - || times.created.map_or(false, is_max) + if times.accessed.is_some_and(is_max) + || times.modified.is_some_and(is_max) + || times.created.is_some_and(is_max) { return Err(io::const_error!( io::ErrorKind::InvalidInput, diff --git a/library/test/src/term/terminfo/mod.rs b/library/test/src/term/terminfo/mod.rs index 75fa594908d56..6f712231e9888 100644 --- a/library/test/src/term/terminfo/mod.rs +++ b/library/test/src/term/terminfo/mod.rs @@ -67,7 +67,7 @@ impl TermInfo { Err(..) => return Err(Error::TermUnset), }; - if term.is_err() && env::var("MSYSCON").map_or(false, |s| "mintty.exe" == s) { + if term.is_err() && env::var("MSYSCON").is_ok_and(|s| "mintty.exe" == s) { // msys terminal Ok(msys_terminfo()) } else { From 64393ebfcf06c21df8bc86e9303b83103dcbccbd Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 13 Aug 2026 14:23:54 +0000 Subject: [PATCH 29/49] clippy::manual_clear --- library/alloc/src/collections/vec_deque/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index a24e4d72fe38e..b007e3054ee6a 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2049,6 +2049,7 @@ impl VecDeque { /// assert!(deque.is_empty()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[expect(clippy::manual_clear, reason = "implements clear")] #[inline] pub fn clear(&mut self) { self.truncate(0); From 30dc43130cfa218bde98f6e10ad9087558bdc5a5 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 13 Aug 2026 14:29:55 +0000 Subject: [PATCH 30/49] clippy::bind_instead_of_map --- library/core/src/slice/iter.rs | 8 ++++---- library/std/src/path.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index a054c9d742c88..1c721f2925eb5 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1892,9 +1892,9 @@ impl<'a, T> Iterator for ChunksExact<'a, T> { #[inline] fn next(&mut self) -> Option<&'a [T]> { - self.v.split_at_checked(self.chunk_size).and_then(|(chunk, rest)| { + self.v.split_at_checked(self.chunk_size).map(|(chunk, rest)| { self.v = rest; - Some(chunk) + chunk }) } @@ -2048,9 +2048,9 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> { #[inline] fn next(&mut self) -> Option<&'a mut [T]> { // SAFETY: we have `&mut self`, so are allowed to temporarily materialize a mut slice - unsafe { &mut *self.v }.split_at_mut_checked(self.chunk_size).and_then(|(chunk, rest)| { + unsafe { &mut *self.v }.split_at_mut_checked(self.chunk_size).map(|(chunk, rest)| { self.v = rest; - Some(chunk) + chunk }) } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 3052587389a91..dbfc00b2c2b47 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2933,7 +2933,7 @@ impl Path { #[stable(feature = "path_file_prefix", since = "1.91.0")] #[must_use] pub fn file_prefix(&self) -> Option<&OsStr> { - self.file_name().map(split_file_at_dot).and_then(|(before, _after)| Some(before)) + self.file_name().map(split_file_at_dot).map(|(before, _after)| before) } /// Extracts the extension (without the leading dot) of [`self.file_name`], if possible. From 5051bc382a3955e58b16b946fca8785d32111758 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 13 Aug 2026 14:57:26 +0000 Subject: [PATCH 31/49] clippy::redundant_slicing --- library/alloc/src/io/buffered/bufreader.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/io/buffered/bufreader.rs b/library/alloc/src/io/buffered/bufreader.rs index e8b3302e29b98..e8be1abc56e17 100644 --- a/library/alloc/src/io/buffered/bufreader.rs +++ b/library/alloc/src/io/buffered/bufreader.rs @@ -153,7 +153,7 @@ impl BufReader { let new = self.buf.read_more(&mut self.inner)?; if new == 0 { // end of file, no more bytes to read - return Ok(&self.buf.buffer()[..]); + return Ok(self.buf.buffer()); } debug_assert_eq!(self.buf.pos(), 0); } From 0348ed12c40d9539b5b81f63ff8d80720caa1e4b Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 13 Aug 2026 15:03:21 +0000 Subject: [PATCH 32/49] clippy::transmutes_expressible_as_ptr_casts --- library/core/src/ptr/const_ptr.rs | 1 + library/core/src/ptr/mut_ptr.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 5601621f1408e..06e7bbb91bbab 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -149,6 +149,7 @@ impl *const T { #[doc = include_str!("./docs/addr.md")] #[must_use] #[inline(always)] + #[expect(clippy::transmutes_expressible_as_ptr_casts, reason = "implements pointer cast")] #[stable(feature = "strict_provenance", since = "1.84.0")] pub fn addr(self) -> usize { // A pointer-to-integer transmute currently has exactly the right semantics: it returns the diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 76eca86612a82..31e14fce4429a 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -140,6 +140,7 @@ impl *mut T { /// [without_provenance]: without_provenance_mut #[must_use] #[inline(always)] + #[expect(clippy::transmutes_expressible_as_ptr_casts, reason = "implements pointer cast")] #[stable(feature = "strict_provenance", since = "1.84.0")] pub fn addr(self) -> usize { // A pointer-to-integer transmute currently has exactly the right semantics: it returns the From 4dae4ea28488893aa032663c03ea4bec12e77f81 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 13 Aug 2026 15:10:50 +0000 Subject: [PATCH 33/49] clippy::manual_repeat_n --- library/std/src/sys/args/windows.rs | 4 ++-- library/test/src/term/terminfo/parm.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/args/windows.rs b/library/std/src/sys/args/windows.rs index bd26db7fea553..3a86f80a76f0c 100644 --- a/library/std/src/sys/args/windows.rs +++ b/library/std/src/sys/args/windows.rs @@ -115,7 +115,7 @@ fn parse_lp_cmd_line<'a, F: Fn() -> OsString>( BACKSLASH => { let backslash_count = code_units.advance_while(|w| w == BACKSLASH) + 1; if code_units.peek() == Some(QUOTE) { - cur.extend(iter::repeat(BACKSLASH.get()).take(backslash_count / 2)); + cur.extend(iter::repeat_n(BACKSLASH.get(), backslash_count / 2)); // The quote is escaped if there are an odd number of backslashes. if backslash_count % 2 == 1 { code_units.next(); @@ -123,7 +123,7 @@ fn parse_lp_cmd_line<'a, F: Fn() -> OsString>( } } else { // If there is no quote on the end then there is no escaping. - cur.extend(iter::repeat(BACKSLASH.get()).take(backslash_count)); + cur.extend(iter::repeat_n(BACKSLASH.get(), backslash_count)); } } // If `in_quotes` and not backslash escaped (see above) then a quote either diff --git a/library/test/src/term/terminfo/parm.rs b/library/test/src/term/terminfo/parm.rs index 529ec0c36e4a5..7426c1e009f55 100644 --- a/library/test/src/term/terminfo/parm.rs +++ b/library/test/src/term/terminfo/parm.rs @@ -1,6 +1,6 @@ //! Parameterized string expansion -use std::iter::repeat; +use std::iter::repeat_n; use self::Param::*; use self::States::*; @@ -520,10 +520,10 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result, String> { if flags.width > s.len() { let n = flags.width - s.len(); if flags.left { - s.extend(repeat(b' ').take(n)); + s.extend(repeat_n(b' ', n)); } else { let mut s_ = Vec::with_capacity(flags.width); - s_.extend(repeat(b' ').take(n)); + s_.extend(repeat_n(b' ', n)); s_.extend(s); s = s_; } From d1f1aae5c46f3a0b67ff98d8d66910788fa6921b Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 18 Aug 2026 20:42:03 +0000 Subject: [PATCH 34/49] clippy::to_digit_is_some --- library/core/src/char/methods.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 8009f6514945e..ad0ae512f0f72 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -345,6 +345,7 @@ impl char { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_char_classify", since = "1.87.0")] + #[expect(clippy::to_digit_is_some, reason = "implements is_digit")] #[inline] pub const fn is_digit(self, radix: u32) -> bool { self.to_digit(radix).is_some() From 4b68669089255cf20efc700b4d6001307025c6d1 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 18 Aug 2026 20:49:51 +0000 Subject: [PATCH 35/49] clippy::double_must_use --- library/alloc/src/boxed.rs | 3 --- library/alloc/src/rc.rs | 1 - library/alloc/src/sync.rs | 1 - library/alloc/src/vec/mod.rs | 1 - library/core/src/io/error.rs | 1 - library/std/src/panicking.rs | 1 - 6 files changed, 8 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 019749c77ae66..8ef478a6aab7b 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -813,7 +813,6 @@ impl Box { /// ``` #[unstable(feature = "clone_from_ref", issue = "149075")] //#[unstable(feature = "allocator_api", issue = "32838")] - #[must_use] #[inline] pub fn try_clone_from_ref(src: &T) -> Result, AllocError> { Box::try_clone_from_ref_in(src, Global) @@ -865,7 +864,6 @@ impl Box { /// ``` #[unstable(feature = "clone_from_ref", issue = "149075")] //#[unstable(feature = "allocator_api", issue = "32838")] - #[must_use] #[inline] pub fn try_clone_from_ref_in(src: &T, alloc: A) -> Result, AllocError> { struct DeallocDropGuard<'a, A: Allocator>(Layout, &'a A, NonNull); @@ -1161,7 +1159,6 @@ impl Box<[T], A> { /// ``` #[unstable(feature = "alloc_slice_into_array", issue = "148082")] #[inline] - #[must_use] pub fn into_array(self) -> Result, Self> { if self.len() == N { let (ptr, alloc) = Self::into_raw_with_allocator(self); diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index e4a803f28e121..01de5841ba0bb 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1257,7 +1257,6 @@ impl Rc<[T], A> { /// ``` #[unstable(feature = "alloc_slice_into_array", issue = "148082")] #[inline] - #[must_use] pub fn into_array(self) -> Result, Self> { if self.len() == N { let (ptr, alloc) = Self::into_raw_with_allocator(self); diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 625a29dd9b7a0..f73792016e3d3 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1416,7 +1416,6 @@ impl Arc<[T], A> { /// ``` #[unstable(feature = "alloc_slice_into_array", issue = "148082")] #[inline] - #[must_use] pub fn into_array(self) -> Result, Self> { if self.len() == N { let (ptr, alloc) = Self::into_raw_with_allocator(self); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 94b21334c120c..bd15ec798460f 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1749,7 +1749,6 @@ impl Vec { /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "alloc_slice_into_array", issue = "148082")] - #[must_use] pub fn into_array(self) -> Result, Self> { if self.len() == N { // SAFETY: `Box::into_array` is guaranteed to return `Ok` if the diff --git a/library/core/src/io/error.rs b/library/core/src/io/error.rs index 8491a42537092..c0de8822b456b 100644 --- a/library/core/src/io/error.rs +++ b/library/core/src/io/error.rs @@ -234,7 +234,6 @@ impl Error { #[doc(hidden)] #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] - #[must_use] #[inline] pub fn into_custom_owner(self) -> result::Result { if matches!(self.repr.data(), ErrorData::Custom(..)) { diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 356b7daa293f4..5a4684a973942 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -175,7 +175,6 @@ pub fn set_hook(hook: Box) + 'static + Sync + Send>) { /// /// panic!("Normal panic"); /// ``` -#[must_use] #[stable(feature = "panic_hooks", since = "1.10.0")] pub fn take_hook() -> Box) + 'static + Sync + Send> { if thread::panicking() { From 7401901ceecc50054379ea4b22dc48ad48a01d8f Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 18 Aug 2026 21:02:04 +0000 Subject: [PATCH 36/49] clippy::seek_from_current --- library/core/src/io/seek.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/io/seek.rs b/library/core/src/io/seek.rs index 4c242c761dfe6..d24bf5ffb4024 100644 --- a/library/core/src/io/seek.rs +++ b/library/core/src/io/seek.rs @@ -142,6 +142,7 @@ pub trait Seek { /// } /// ``` #[stable(feature = "seek_convenience", since = "1.51.0")] + #[expect(clippy::seek_from_current, reason = "implements stream_position")] fn stream_position(&mut self) -> Result { self.seek(SeekFrom::Current(0)) } From 641b3e53ef215356ce598c974fec77592fbe13fe Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 18 Aug 2026 21:07:26 +0000 Subject: [PATCH 37/49] clippy::mem_replace_option_with_some --- library/core/src/option.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index f91e9ffcc4567..14b60fd6d8a64 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1825,7 +1825,7 @@ impl Option { // It could also be expressed as `unsafe { core::ptr::write(self, Some(f())) }`, but // no reason is currently known to use additional unsafe code here. - mem::forget(mem::replace(self, Some(f()))); + mem::forget(self.replace(f())); } // SAFETY: a `None` variant for `self` would have been replaced by a `Some` @@ -1957,6 +1957,7 @@ impl Option { #[inline] #[stable(feature = "option_replace", since = "1.31.0")] #[rustc_const_stable(feature = "const_option", since = "1.83.0")] + #[expect(clippy::mem_replace_option_with_some, reason = "implements Option::replace")] pub const fn replace(&mut self, value: T) -> Option { mem::replace(self, Some(value)) } From 836a20fc89ad65261fec69ded40559be9cea33c1 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 18 Aug 2026 21:12:42 +0000 Subject: [PATCH 38/49] clippy::mem_replace_option_with_none --- library/alloc/src/collections/btree/map.rs | 2 +- library/core/src/option.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index d8421d3c3f70a..b204732a673e3 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -670,7 +670,7 @@ impl BTreeMap { pub fn clear(&mut self) { // avoid moving the allocator drop(BTreeMap { - root: mem::replace(&mut self.root, None), + root: self.root.take(), length: mem::replace(&mut self.length, 0), alloc: self.alloc.clone(), _marker: PhantomData, diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 14b60fd6d8a64..f707c838a1175 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1898,6 +1898,7 @@ impl Option { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_option", since = "1.83.0")] + #[expect(clippy::mem_replace_option_with_none, reason = "implements Option::take")] pub const fn take(&mut self) -> Option { // FIXME(const-hack) replace `mem::replace` by `mem::take` when the latter is const ready mem::replace(self, None) From 3fba07bf97f329fb924da038bb5f355d3569424c Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 18 Aug 2026 21:18:21 +0000 Subject: [PATCH 39/49] clippy::map_clone --- library/core/src/option.rs | 3 ++- library/core/src/result.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index f707c838a1175..201019037148d 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2158,6 +2158,7 @@ impl Option<&T> { /// ``` #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "rust1", since = "1.0.0")] + #[expect(clippy::map_clone, reason = "implements Option::cloned")] pub fn cloned(self) -> Option where T: Clone, @@ -2210,7 +2211,7 @@ impl Option<&mut T> { where T: Clone, { - self.as_deref().map(T::clone) + self.as_deref().cloned() } } diff --git a/library/core/src/result.rs b/library/core/src/result.rs index c38008cf73d2b..544282d942148 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1736,6 +1736,7 @@ impl Result<&T, E> { /// ``` #[inline] #[stable(feature = "result_cloned", since = "1.59.0")] + #[expect(clippy::map_clone, reason = "implements Result::cloned")] pub fn cloned(self) -> Result where T: Clone, From 610a48eaa3bd4760233bacfaef1c9874105ebb35 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 18 Aug 2026 21:23:42 +0000 Subject: [PATCH 40/49] clippy::declare_interior_mutable_const --- library/core/src/sync/atomic.rs | 3 +++ library/std/src/sync/once.rs | 1 + 2 files changed, 4 insertions(+) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index e676a3851112d..12208b95307ee 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -534,6 +534,7 @@ pub enum Ordering { note = "the `new` function is now preferred", suggestion = "AtomicBool::new(false)" )] +#[expect(clippy::declare_interior_mutable_const, reason = "legacy atomic initializer")] pub const ATOMIC_BOOL_INIT: AtomicBool = AtomicBool::new(false); #[cfg(target_has_atomic_load_store = "8")] @@ -3939,6 +3940,7 @@ macro_rules! atomic_int_ptr_sized { note = "the `new` function is now preferred", suggestion = "AtomicIsize::new(0)", )] + #[expect(clippy::declare_interior_mutable_const, reason = "legacy atomic initializer")] pub const ATOMIC_ISIZE_INIT: AtomicIsize = AtomicIsize::new(0); /// An [`AtomicUsize`] initialized to `0`. @@ -3949,6 +3951,7 @@ macro_rules! atomic_int_ptr_sized { note = "the `new` function is now preferred", suggestion = "AtomicUsize::new(0)", )] + #[expect(clippy::declare_interior_mutable_const, reason = "legacy atomic initializer")] pub const ATOMIC_USIZE_INIT: AtomicUsize = AtomicUsize::new(0); )* }; } diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index 62cac6afee751..9b555c32df99d 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -72,6 +72,7 @@ pub(crate) enum OnceExclusiveState { note = "the `Once::new()` function is now preferred", suggestion = "Once::new()" )] +#[expect(clippy::declare_interior_mutable_const, reason = "legacy Once initializer")] pub const ONCE_INIT: Once = Once::new(); impl Once { From f591acd10f34ceed95d91e55cfc53c91173b11c6 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 18 Aug 2026 21:27:30 +0000 Subject: [PATCH 41/49] clippy::assign_op_pattern --- library/alloc/src/collections/linked_list.rs | 2 +- library/core/src/slice/sort/select.rs | 2 +- library/core/src/time.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 8939b2f12f49c..a0542d2b5737c 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -369,7 +369,7 @@ impl LinkedList { // Fix the head ptr of the second part self.head = Some(split_node); - self.len = self.len - at; + self.len -= at; first_part } else { diff --git a/library/core/src/slice/sort/select.rs b/library/core/src/slice/sort/select.rs index fc31013caf88c..30058f516867e 100644 --- a/library/core/src/slice/sort/select.rs +++ b/library/core/src/slice/sort/select.rs @@ -116,7 +116,7 @@ fn partition_at_index_loop<'a, T, F>( } v = &mut v[mid..]; - index = index - mid; + index -= mid; ancestor_pivot = None; continue; } diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 682a61a07d10f..816da7a2fb7f2 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -1361,7 +1361,7 @@ macro_rules! sum_durations { total_secs = total_secs .checked_add(total_nanos / NANOS_PER_SEC as u64) .expect("overflow in iter::sum over durations"); - total_nanos = total_nanos % NANOS_PER_SEC as u64; + total_nanos %= NANOS_PER_SEC as u64; Duration::new(total_secs, total_nanos as u32) }}; } From 31f7abc03b377a3e439eba74375e231e67c2b69a Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 18 Aug 2026 21:36:39 +0000 Subject: [PATCH 42/49] clippy::chunks_exact_to_as_chunks --- library/core/src/slice/ascii.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 2b6037b2ee53e..07920a36e6eda 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -666,10 +666,9 @@ const fn is_ascii(bytes: &[u8]) -> bool { } else { // For small inputs, use usize-at-a-time processing to avoid SSE2 call overhead. if bytes.len() < SIMD_MIN_LEN { - let chunks = bytes.chunks_exact(USIZE_SIZE); - let remainder = chunks.remainder(); + let (chunks, remainder) = bytes.as_chunks::(); for chunk in chunks { - let word = usize::from_ne_bytes(chunk.try_into().unwrap()); + let word = usize::from_ne_bytes(*chunk); if (word & NONASCII_MASK) != 0 { return false; } From 4bed8e25484e78b9c484e5df32934834059754a8 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 19 Aug 2026 01:26:27 +0000 Subject: [PATCH 43/49] clippy::needless_raw_string_hashes --- library/core/src/panicking.rs | 8 ++++---- library/std/src/sys/args/windows.rs | 2 +- library/test/src/formatters/json.rs | 2 +- library/test/src/test_result.rs | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 46790b620127b..04722e4e2fc10 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -445,14 +445,14 @@ fn assert_failed_inner( match args { Some(args) => panic!( - r#"assertion `left {op} right` failed: {args} + r"assertion `left {op} right` failed: {args} left: {left:?} - right: {right:?}"# + right: {right:?}" ), None => panic!( - r#"assertion `left {op} right` failed + r"assertion `left {op} right` failed left: {left:?} - right: {right:?}"# + right: {right:?}" ), } } diff --git a/library/std/src/sys/args/windows.rs b/library/std/src/sys/args/windows.rs index 3a86f80a76f0c..4a450a72cdccd 100644 --- a/library/std/src/sys/args/windows.rs +++ b/library/std/src/sys/args/windows.rs @@ -295,7 +295,7 @@ pub(crate) fn make_bat_command_line( force_quotes: bool, ) -> io::Result> { const INVALID_ARGUMENT_ERROR: io::Error = - io::const_error!(io::ErrorKind::InvalidInput, r#"batch file arguments are invalid"#); + io::const_error!(io::ErrorKind::InvalidInput, r"batch file arguments are invalid"); // Set the start of the command line to `cmd.exe /c "` // It is necessary to surround the command in an extra pair of quotes, // hence the trailing quote here. It will be closed after all arguments diff --git a/library/test/src/formatters/json.rs b/library/test/src/formatters/json.rs index 4a101f00d74b6..df62d0fd7f435 100644 --- a/library/test/src/formatters/json.rs +++ b/library/test/src/formatters/json.rs @@ -48,7 +48,7 @@ impl JsonFormatter { String::from("") }; let extra_json = - if let Some(extra) = extra { format!(r#", {extra}"#) } else { String::from("") }; + if let Some(extra) = extra { format!(r", {extra}") } else { String::from("") }; let newline = "\n"; self.writeln_message(&format!( diff --git a/library/test/src/test_result.rs b/library/test/src/test_result.rs index 4cb43fc45fd6c..b2457e031fd19 100644 --- a/library/test/src/test_result.rs +++ b/library/test/src/test_result.rs @@ -60,15 +60,15 @@ pub(crate) fn calc_result( TestResult::TrOk } else if let Some(panic_str) = maybe_panic_str { TestResult::TrFailedMsg(format!( - r#"panic did not contain expected string + r"panic did not contain expected string panic message: {panic_str:?} - expected substring: {msg:?}"# + expected substring: {msg:?}" )) } else { TestResult::TrFailedMsg(format!( - r#"expected panic with string value, + r"expected panic with string value, found non-string value: `{:?}` - expected substring: {msg:?}"#, + expected substring: {msg:?}", (*err).type_id() )) } From 428739b075d979b6464a5eb9ffdb0cd9060eb915 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 19 Aug 2026 14:30:12 +0000 Subject: [PATCH 44/49] clippy::approx_constant --- library/core/src/num/f128.rs | 1 + library/core/src/num/f16.rs | 1 + library/core/src/num/f32.rs | 1 + library/core/src/num/f64.rs | 1 + 4 files changed, 4 insertions(+) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 45b4b80e9e268..994233186a193 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -10,6 +10,7 @@ //! defined directly on the `f128` type. #![unstable(feature = "f128", issue = "116909")] +#![expect(clippy::approx_constant, reason = "this module defines f128 constants")] use crate::convert::{FloatToFloat, FloatToInt}; use crate::num::FpCategory; diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index e8f2e37f93c67..c1a64fd7fb602 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -10,6 +10,7 @@ //! defined directly on the `f16` type. #![unstable(feature = "f16", issue = "116909")] +#![expect(clippy::approx_constant, reason = "this module defines f16 constants")] use crate::convert::{FloatToFloat, FloatToInt}; use crate::num::FpCategory; diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 3f7b33770fc08..eb1da9c7c7c6e 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -10,6 +10,7 @@ //! defined directly on the `f32` type. #![stable(feature = "rust1", since = "1.0.0")] +#![expect(clippy::approx_constant, reason = "this module defines f32 constants")] use crate::convert::{FloatToFloat, FloatToInt}; use crate::num::FpCategory; diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 5bc2f8d0feb32..0a3baf039e639 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -10,6 +10,7 @@ //! defined directly on the `f64` type. #![stable(feature = "rust1", since = "1.0.0")] +#![expect(clippy::approx_constant, reason = "this module defines f64 constants")] use crate::convert::{FloatToFloat, FloatToInt}; use crate::num::FpCategory; From af533a1c64cab8742ebb88bad05d886c6ac75494 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 12 Aug 2026 15:42:04 +0000 Subject: [PATCH 45/49] clippy::neg_cmp_op_on_partial_ord --- library/core/src/num/f128.rs | 4 +++- library/core/src/num/f16.rs | 4 +++- library/core/src/num/f32.rs | 4 +++- library/core/src/num/f64.rs | 4 +++- library/core/src/ops/range.rs | 2 ++ library/core/src/range.rs | 2 ++ 6 files changed, 16 insertions(+), 4 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 994233186a193..d52e817c9e3db 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1500,6 +1500,7 @@ impl f128 { #[inline] #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] + #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "NaN is also invalid")] pub const fn clamp(mut self, min: f128, max: f128) -> f128 { const_assert!( min <= max, @@ -1544,8 +1545,9 @@ impl f128 { #[inline] #[unstable(feature = "clamp_magnitude", issue = "148519")] #[must_use = "this returns the clamped value and does not modify the original"] + #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "NaN is also invalid")] pub fn clamp_magnitude(self, limit: f128) -> f128 { - assert!(limit >= 0.0, "limit must be non-negative"); + assert!(limit >= 0.0, "limit must be non-negative and not NaN"); let limit = limit.abs(); // Canonicalises -0.0 to 0.0 self.clamp(-limit, limit) } diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index c1a64fd7fb602..186e83a9cd6b5 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1486,6 +1486,7 @@ impl f16 { #[inline] #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] + #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "NaN is also invalid")] pub const fn clamp(mut self, min: f16, max: f16) -> f16 { const_assert!( min <= max, @@ -1530,8 +1531,9 @@ impl f16 { #[inline] #[unstable(feature = "clamp_magnitude", issue = "148519")] #[must_use = "this returns the clamped value and does not modify the original"] + #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "NaN is also invalid")] pub fn clamp_magnitude(self, limit: f16) -> f16 { - assert!(limit >= 0.0, "limit must be non-negative"); + assert!(limit >= 0.0, "limit must be non-negative and not NaN"); let limit = limit.abs(); // Canonicalises -0.0 to 0.0 self.clamp(-limit, limit) } diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index eb1da9c7c7c6e..3c6b58a2b4b25 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1660,6 +1660,7 @@ impl f32 { #[stable(feature = "clamp", since = "1.50.0")] #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] + #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "Nan is also invalid")] pub const fn clamp(mut self, min: f32, max: f32) -> f32 { const_assert!( min <= max, @@ -1701,8 +1702,9 @@ impl f32 { #[must_use = "this returns the clamped value and does not modify the original"] #[unstable(feature = "clamp_magnitude", issue = "148519")] #[inline] + #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "NaN is also invalid")] pub fn clamp_magnitude(self, limit: f32) -> f32 { - assert!(limit >= 0.0, "limit must be non-negative"); + assert!(limit >= 0.0, "limit must be non-negative and not NaN"); let limit = limit.abs(); // Canonicalises -0.0 to 0.0 self.clamp(-limit, limit) } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 0a3baf039e639..8c433a5cf941d 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1638,6 +1638,7 @@ impl f64 { #[stable(feature = "clamp", since = "1.50.0")] #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] + #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "NaN is also invalid")] pub const fn clamp(mut self, min: f64, max: f64) -> f64 { const_assert!( min <= max, @@ -1679,8 +1680,9 @@ impl f64 { #[must_use = "this returns the clamped value and does not modify the original"] #[unstable(feature = "clamp_magnitude", issue = "148519")] #[inline] + #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "NaN is also invalid")] pub fn clamp_magnitude(self, limit: f64) -> f64 { - assert!(limit >= 0.0, "limit must be non-negative"); + assert!(limit >= 0.0, "limit must be non-negative and not NaN"); let limit = limit.abs(); // Canonicalises -0.0 to 0.0 self.clamp(-limit, limit) } diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index ebb6c3ddb938c..19830365faa32 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -148,6 +148,7 @@ impl> Range { #[inline] #[stable(feature = "range_is_empty", since = "1.47.0")] #[rustc_const_unstable(feature = "const_range", issue = "none")] + #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "incomparable ranges are empty")] pub const fn is_empty(&self) -> bool where Idx: [const] PartialOrd, @@ -568,6 +569,7 @@ impl> RangeInclusive { #[stable(feature = "range_is_empty", since = "1.47.0")] #[inline] #[rustc_const_unstable(feature = "const_range", issue = "none")] + #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "incomparable ranges are empty")] pub const fn is_empty(&self) -> bool where Idx: [const] PartialOrd, diff --git a/library/core/src/range.rs b/library/core/src/range.rs index 557587b4e9a88..81f4b2ce78c9c 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -162,6 +162,7 @@ impl> Range { #[inline] #[stable(feature = "new_range_api", since = "1.96.0")] #[rustc_const_unstable(feature = "const_range", issue = "none")] + #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "incomparable ranges are empty")] pub const fn is_empty(&self) -> bool where Idx: [const] PartialOrd, @@ -320,6 +321,7 @@ impl> RangeInclusive { #[stable(feature = "new_range_inclusive_api", since = "1.95.0")] #[inline] #[rustc_const_unstable(feature = "const_range", issue = "none")] + #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "incomparable ranges are empty")] pub const fn is_empty(&self) -> bool where Idx: [const] PartialOrd, From 9fa2a10dc5355ec598e6e04b3f4af976c4cd3b33 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 18 Aug 2026 21:42:25 +0000 Subject: [PATCH 46/49] Ignore clippy failures in stdarch submodule --- library/core/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 9af39dfc9cb55..4fbd3c6dc2142 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -363,7 +363,9 @@ pub mod primitive; unsafe_op_in_unsafe_fn, ambiguous_glob_reexports, deprecated_in_future, - unreachable_pub + unreachable_pub, + // FIXME: stdach is a submodule so clippy lints should be fixed (and ideally enforced) there + clippy::all, )] #[allow(rustdoc::bare_urls)] mod core_arch; From 79c0d27be0155dcaf079512dcf735f20c2fc3a92 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 18 Aug 2026 22:59:35 +0000 Subject: [PATCH 47/49] Enforce even more clippy lints in CI --- src/bootstrap/src/core/build_steps/clippy.rs | 51 +++++++++++++++----- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index dc3e3efb80ee5..9b8377f23ccd5 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -38,7 +38,6 @@ const IGNORED_RULES_FOR_STD_AND_RUSTC: &[&str] = &[ "too_many_arguments", "needless_lifetimes", // people want to keep the lifetimes "wrong_self_convention", - "approx_constant", // libcore is what defines those ]; fn lint_args(builder: &Builder<'_>, config: &LintConfig, ignored_rules: &[&str]) -> Vec { @@ -572,29 +571,57 @@ impl CommandLineStep for CI { allow: vec!["clippy::all".into()], warn: vec![], deny: vec![ + // the entire correctness group should always be enforced. "clippy::correctness".into(), + // tidy-alphabetic-start + "clippy::approx_constant".into(), + "clippy::assign_op_pattern".into(), + "clippy::bind_instead_of_map".into(), + "clippy::borrow_deref_ref".into(), "clippy::char_lit_as_u8".into(), + "clippy::chunks_exact_to_as_chunks".into(), + "clippy::declare_interior_mutable_const".into(), + "clippy::default_constructed_unit_structs".into(), + "clippy::derivable_impls".into(), + "clippy::double_must_use".into(), + "clippy::excessive_precision".into(), + "clippy::explicit_auto_deref".into(), + "clippy::filter_map_next".into(), "clippy::four_forward_slashes".into(), + "clippy::int_plus_one".into(), + "clippy::legacy_numeric_constants".into(), + "clippy::let_and_return".into(), + "clippy::manual_repeat_n".into(), + "clippy::map_clone".into(), + "clippy::match_as_ref".into(), + "clippy::mem_replace_option_with_none".into(), + "clippy::mem_replace_option_with_some".into(), + "clippy::needless_as_bytes".into(), "clippy::needless_bool".into(), "clippy::needless_bool_assign".into(), + "clippy::needless_borrow".into(), + "clippy::needless_raw_string_hashes".into(), + "clippy::needless_return".into(), + "clippy::neg_cmp_op_on_partial_ord".into(), "clippy::non_minimal_cfg".into(), + "clippy::op_ref".into(), + "clippy::partialeq_ne_impl".into(), + "clippy::partialeq_to_none".into(), "clippy::print_literal".into(), + "clippy::ptr_offset_with_cast".into(), + "clippy::redundant_closure".into(), + "clippy::redundant_pattern_matching".into(), + "clippy::redundant_slicing".into(), "clippy::same_item_push".into(), + "clippy::seek_from_current".into(), "clippy::single_char_add_str".into(), + "clippy::single_match".into(), + "clippy::to_digit_is_some".into(), "clippy::to_string_in_format_args".into(), "clippy::unconditional_recursion".into(), - "clippy::int_plus_one".into(), - "clippy::legacy_numeric_constants".into(), + "clippy::unnecessary_map_or".into(), "clippy::zero_divided_by_zero".into(), - "clippy::len_zero".into(), - "clippy::needless_as_bytes".into(), - "clippy::ptr_offset_with_cast".into(), - "clippy::let_and_return".into(), - "clippy::needless_return".into(), - "clippy::needless_borrow".into(), - "clippy::op_ref".into(), - "clippy::borrow_deref_ref".into(), - "clippy::explicit_auto_deref".into(), + // tidy-alphabetic-end ], forbid: vec![], }; From 4c8eac015edad51339ea522b1f7167cb3e3164ca Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 19 Aug 2026 02:41:43 +0000 Subject: [PATCH 48/49] Allow lints on backtrace-rs --- library/std/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index cc652cb743353..92eccc27ee05d 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -738,7 +738,7 @@ mod panicking; #[path = "../../backtrace/src/lib.rs"] #[allow(dead_code, unused_attributes, implicit_provenance_casts, unsafe_op_in_unsafe_fn)] -#[allow(clippy::len_zero, clippy::needless_borrow)] // FIXME +#[allow(clippy::len_zero, clippy::needless_borrow, clippy::filter_map_next)] // FIXME mod backtrace_rs; #[stable(feature = "cfg_select", since = "1.95.0")] From aa9fe901da30b84b5057f5cb52d0e885eb732fed Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 19 Aug 2026 11:53:24 +0000 Subject: [PATCH 49/49] ignore clippy::redundant_pattern_matching This can affect drop order --- src/bootstrap/src/core/build_steps/clippy.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 9b8377f23ccd5..99648425a8987 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -38,6 +38,7 @@ const IGNORED_RULES_FOR_STD_AND_RUSTC: &[&str] = &[ "too_many_arguments", "needless_lifetimes", // people want to keep the lifetimes "wrong_self_convention", + "redundant_pattern_matching", // can affect drop order ]; fn lint_args(builder: &Builder<'_>, config: &LintConfig, ignored_rules: &[&str]) -> Vec { @@ -610,7 +611,6 @@ impl CommandLineStep for CI { "clippy::print_literal".into(), "clippy::ptr_offset_with_cast".into(), "clippy::redundant_closure".into(), - "clippy::redundant_pattern_matching".into(), "clippy::redundant_slicing".into(), "clippy::same_item_push".into(), "clippy::seek_from_current".into(),