From 3c1abf4c95627092f0562d365e30cbb22705b7f0 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 20 Aug 2026 09:15:02 +0000 Subject: [PATCH 01/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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) -}