From 5599679015cc73b57368e0023b56ed3017b945fb Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Wed, 4 Nov 2026 15:00:00 +0100 Subject: [PATCH 01/16] Move `hir::Param`s from `Body` of functions to `FnDecl`. This commit is by far the biggest one, and achieves the goal of this PR but leaves the code ugly in a lot of places. The next commits will be a lot of cleanup. --- .../rustc_ast_lowering/src/delegation/mod.rs | 57 +++-- compiler/rustc_ast_lowering/src/expr.rs | 19 +- .../rustc_ast_lowering/src/expr/closure.rs | 15 +- compiler/rustc_ast_lowering/src/item.rs | 102 +++++---- compiler/rustc_ast_lowering/src/lib.rs | 194 ++++++++++-------- compiler/rustc_ast_lowering/src/pat.rs | 6 +- .../src/diagnostics/conflict_errors.rs | 22 +- .../src/diagnostics/move_errors.rs | 3 +- .../src/diagnostics/mutability_errors.rs | 30 ++- .../src/diagnostics/region_errors.rs | 4 +- .../src/diagnostics/region_name.rs | 7 +- compiler/rustc_hir/src/hir.rs | 17 +- compiler/rustc_hir/src/intravisit.rs | 15 +- .../src/check/compare_eii.rs | 16 +- .../src/check/compare_impl_item.rs | 38 ++-- compiler/rustc_hir_analysis/src/check/mod.rs | 2 +- .../rustc_hir_analysis/src/check/region.rs | 5 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 14 +- .../src/coherence/builtin/coerce_shared.rs | 1 + compiler/rustc_hir_analysis/src/collect.rs | 19 +- .../src/collect/resolve_bound_vars.rs | 32 ++- .../wrong_number_of_generic_args.rs | 4 +- .../src/hir_ty_lowering/cmse.rs | 8 +- .../src/hir_ty_lowering/dyn_trait.rs | 4 +- .../src/hir_ty_lowering/mod.rs | 4 + .../rustc_hir_analysis/src/hir_wf_check.rs | 4 +- compiler/rustc_hir_pretty/src/lib.rs | 48 +++-- compiler/rustc_hir_typeck/src/check.rs | 16 +- compiler/rustc_hir_typeck/src/closure.rs | 10 +- compiler/rustc_hir_typeck/src/demand.rs | 4 +- .../rustc_hir_typeck/src/expr_use_visitor.rs | 8 +- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 52 ++--- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 7 +- .../src/fn_ctxt/suggestions.rs | 4 +- compiler/rustc_hir_typeck/src/lib.rs | 11 +- .../rustc_hir_typeck/src/method/suggest.rs | 29 ++- .../rustc_hir_typeck/src/naked_functions.rs | 13 +- compiler/rustc_hir_typeck/src/upvar.rs | 22 +- compiler/rustc_hir_typeck/src/writeback.rs | 21 +- compiler/rustc_lint/src/gpukernel_abi.rs | 2 +- compiler/rustc_lint/src/lifetime_syntax.rs | 2 +- compiler/rustc_lint/src/nonstandard_style.rs | 31 ++- .../rustc_lint/src/types/improper_ctypes.rs | 4 +- compiler/rustc_middle/src/hir/map.rs | 10 +- compiler/rustc_middle/src/hir/mod.rs | 4 +- compiler/rustc_mir_build/src/thir/cx/mod.rs | 17 +- compiler/rustc_mir_transform/src/liveness.rs | 5 +- compiler/rustc_passes/src/check_attr.rs | 14 +- compiler/rustc_passes/src/check_export.rs | 2 +- compiler/rustc_passes/src/dead.rs | 16 +- compiler/rustc_passes/src/input_stats.rs | 1 + compiler/rustc_passes/src/upvars.rs | 3 + compiler/rustc_privacy/src/lib.rs | 13 +- .../error_reporting/infer/need_type_info.rs | 10 +- .../infer/nice_region_error/find_anon_type.rs | 2 +- .../nice_region_error/placeholder_error.rs | 6 +- .../infer/nice_region_error/util.rs | 14 +- .../src/error_reporting/infer/region.rs | 2 +- .../src/error_reporting/infer/suggest.rs | 26 ++- .../traits/fulfillment_errors.rs | 19 +- .../src/error_reporting/traits/mod.rs | 5 +- .../src/error_reporting/traits/suggestions.rs | 42 ++-- .../src/traits/dyn_compatibility.rs | 17 +- compiler/rustc_ty_utils/src/implied_bounds.rs | 6 +- compiler/rustc_ty_walk/src/lib.rs | 2 +- src/librustdoc/clean/mod.rs | 38 ++-- src/tools/clippy/clippy_lints/src/booleans.rs | 7 +- .../src/collection_is_never_read.rs | 3 +- .../clippy/clippy_lints/src/dereference.rs | 1 + src/tools/clippy/clippy_lints/src/escape.rs | 8 +- .../clippy/clippy_lints/src/eta_reduction.rs | 12 +- .../clippy_lints/src/excessive_bools.rs | 2 +- .../clippy/clippy_lints/src/format_impl.rs | 8 +- .../clippy/clippy_lints/src/from_over_into.rs | 4 +- .../clippy_lints/src/functions/must_use.rs | 6 +- .../src/functions/not_unsafe_ptr_arg_deref.rs | 2 +- .../clippy_lints/src/functions/ref_option.rs | 4 +- .../src/functions/renamed_function_params.rs | 4 +- .../clippy_lints/src/implicit_hasher.rs | 6 +- .../clippy/clippy_lints/src/lifetimes.rs | 13 +- .../src/loops/unused_enumerate_index.rs | 13 +- .../clippy_lints/src/manual_is_ascii_check.rs | 4 +- .../clippy/clippy_lints/src/manual_pop_if.rs | 6 +- .../clippy/clippy_lints/src/manual_retain.rs | 6 +- .../clippy/clippy_lints/src/map_unit_fn.rs | 10 +- .../clippy_lints/src/matches/manual_filter.rs | 2 +- .../src/matches/match_single_binding.rs | 2 +- .../clippy_lints/src/methods/bytecount.rs | 4 +- .../clippy_lints/src/methods/filter_map.rs | 14 +- .../src/methods/filter_map_bool_then.rs | 9 +- .../clippy_lints/src/methods/iter_filter.rs | 4 +- .../clippy_lints/src/methods/iter_kv_map.rs | 2 +- .../src/methods/iter_overeager_cloned.rs | 7 +- .../src/methods/lines_filter_map_ok.rs | 11 +- .../src/methods/manual_contains.rs | 6 +- .../src/methods/manual_inspect.rs | 4 +- .../clippy_lints/src/methods/manual_ok_or.rs | 2 +- .../src/methods/manual_option_zip.rs | 10 +- .../clippy_lints/src/methods/map_clone.rs | 4 +- .../src/methods/map_err_ignore.rs | 6 +- .../map_with_unused_argument_over_ranges.rs | 9 +- .../clippy/clippy_lints/src/methods/mod.rs | 10 +- .../methods/needless_character_iteration.rs | 5 +- .../src/methods/option_as_ref_deref.rs | 6 +- .../clippy_lints/src/methods/or_fun_call.rs | 4 +- .../src/methods/range_zip_with_len.rs | 3 +- .../src/methods/return_and_then.rs | 2 +- .../src/methods/search_is_some.rs | 5 +- .../clippy_lints/src/methods/some_filter.rs | 6 +- .../src/methods/unnecessary_filter_map.rs | 8 +- .../src/methods/unnecessary_fold.rs | 8 +- .../src/methods/unnecessary_lazy_eval.rs | 14 +- .../src/methods/unnecessary_map_or.rs | 6 +- .../src/methods/unnecessary_sort_by.rs | 4 +- .../methods/unnecessary_unwrap_unchecked.rs | 10 +- .../clippy_lints/src/methods/useless_asref.rs | 7 +- .../clippy_lints/src/min_ident_chars.rs | 13 +- src/tools/clippy/clippy_lints/src/mut_key.rs | 4 +- .../clippy_lints/src/needless_for_each.rs | 4 +- .../src/needless_pass_by_ref_mut.rs | 34 ++- .../src/needless_pass_by_value.rs | 31 +-- .../clippy_lints/src/non_canonical_impls.rs | 18 +- .../src/only_used_in_recursion.rs | 12 +- .../clippy_lints/src/pass_by_ref_or_value.rs | 17 +- .../clippy_lints/src/pattern_type_mismatch.rs | 6 +- .../clippy_lints/src/ptr/mut_from_ref.rs | 2 +- .../clippy/clippy_lints/src/ptr/ptr_arg.rs | 26 ++- .../src/redundant_closure_call.rs | 7 +- .../clippy/clippy_lints/src/replace_box.rs | 5 +- src/tools/clippy/clippy_lints/src/shadow.rs | 12 +- .../clippy_lints/src/single_option_map.rs | 2 +- .../clippy_lints/src/string_patterns.rs | 2 +- .../clippy_lints/src/toplevel_ref_arg.rs | 6 +- .../src/try_from_instead_of_from_str.rs | 11 +- .../clippy/clippy_lints/src/types/mod.rs | 4 +- .../clippy/clippy_lints/src/unused_self.rs | 6 +- src/tools/clippy/clippy_lints/src/use_self.rs | 2 +- .../clippy_utils/src/check_proc_macro.rs | 4 +- .../clippy/clippy_utils/src/hir_utils.rs | 5 +- src/tools/clippy/clippy_utils/src/lib.rs | 14 +- src/tools/clippy/clippy_utils/src/sugg.rs | 6 +- src/tools/clippy/clippy_utils/src/ty/mod.rs | 2 +- .../clippy_utils/src/ty/type_certainty/mod.rs | 8 +- src/tools/clippy/clippy_utils/src/usage.rs | 8 +- .../min_ident_chars.stderr | 8 +- .../clippy/tests/ui/min_ident_chars.stderr | 16 +- tests/ui/stats/input-stats.stderr | 12 +- tests/ui/thir-print/c-variadic.stdout | 2 +- 148 files changed, 995 insertions(+), 827 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/delegation/mod.rs b/compiler/rustc_ast_lowering/src/delegation/mod.rs index eb980d31ce1ef..105e5cf1d4345 100644 --- a/compiler/rustc_ast_lowering/src/delegation/mod.rs +++ b/compiler/rustc_ast_lowering/src/delegation/mod.rs @@ -56,6 +56,7 @@ use rustc_span::{Ident, Span, Symbol}; use crate::delegation::generics::{GenericsGenerationResults, GenericsPosition}; use crate::delegation::resolution::resolver::DelegationResolver; use crate::delegation::resolution::{DelegationResolution, ParamInfo}; +use crate::item::PartialParam; use crate::{ AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, }; @@ -82,10 +83,11 @@ impl<'hir> LoweringContext<'_, 'hir> { self.add_attrs_if_needed(&res); - let (body_id, call_expr_id, unused_target_expr) = + let (body_id, params, call_expr_id, unused_target_expr) = self.lower_delegation_body(delegation, &res, &mut generics); - let decl = self.lower_delegation_decl(&res, &generics, call_expr_id, unused_target_expr); + let decl = + self.lower_delegation_decl(&res, params, &generics, call_expr_id, unused_target_expr); let sig = self.lower_delegation_sig(res.sig_id, decl, span); @@ -105,6 +107,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_delegation_decl( &mut self, res: &DelegationResolution, + params: Vec>, generics: &GenericsGenerationResults<'hir>, call_expr_id: HirId, unused_target_expr: bool, @@ -115,14 +118,23 @@ impl<'hir> LoweringContext<'_, 'hir> { // The last parameter in C variadic functions is skipped in the signature, // like during regular lowering. let decl_param_count = param_count - c_variadic as usize; - let inputs = self.arena.alloc_from_iter((0..decl_param_count).map(|arg| hir::Ty { - hir_id: self.next_id(), - kind: hir::TyKind::InferDelegation(hir::InferDelegation::Sig( - sig_id, - hir::InferDelegationSig::Input(arg), - )), - span, - })); + let inputs = + self.arena.alloc_from_iter((0..decl_param_count).zip(params).map(|(arg, param)| { + hir::Param { + hir_id: param.hir_id, + pat: param.pat, + ty: self.arena.alloc(hir::Ty { + hir_id: self.next_id(), + kind: hir::TyKind::InferDelegation(hir::InferDelegation::Sig( + sig_id, + hir::InferDelegationSig::Input(arg), + )), + span, + }), + ty_span: param.ty_span, + param_span: param.param_span, + } + })); let output = self.arena.alloc(hir::Ty { hir_id: self.next_id(), @@ -162,6 +174,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .set_c_variadic(c_variadic) .set_splatted(splatted, inputs.len()) .unwrap(), + fn_has_body: true, }) } @@ -196,7 +209,7 @@ impl<'hir> LoweringContext<'_, 'hir> { is_method: bool, idx: usize, span: Span, - ) -> (hir::Param<'hir>, NodeId) { + ) -> (PartialParam<'hir>, NodeId) { let pat_node_id = self.next_node_id(); let pat_id = self.lower_node_id(pat_node_id); // FIXME(cjgillot) AssocItem currently relies on self parameter being exactly named `self`. @@ -213,7 +226,8 @@ impl<'hir> LoweringContext<'_, 'hir> { default_binding_modes: false, }); - (hir::Param { hir_id: self.next_id(), pat, ty_span: span, span }, pat_node_id) + let hir_id = self.next_id(); + (PartialParam { hir_id, pat, ty_span: span, param_span: span }, pat_node_id) } fn generate_arg( @@ -248,17 +262,18 @@ impl<'hir> LoweringContext<'_, 'hir> { delegation: &Delegation, res: &DelegationResolution, generics: &mut GenericsGenerationResults<'hir>, - ) -> (hir::BodyId, HirId, bool) { + ) -> (hir::BodyId, Vec>, HirId, bool) { let block = delegation.body.as_deref(); let mut call_expr_id = HirId::INVALID; let mut unused_target_expr = false; - let block_id = self.lower_body(|this| { + let (params, block_id) = self.lower_body(|this| { let &DelegationResolution { param_info, span, is_method, .. } = res; - let ParamInfo { param_count, .. } = param_info; + let ParamInfo { param_count, c_variadic, .. } = param_info; + let param_count = param_count - c_variadic as usize; let arguments_to_map = &res.sig_mapping.arguments_to_map; - let mut parameters: Vec> = Vec::with_capacity(param_count); + let mut parameters: Vec> = Vec::with_capacity(param_count); let mut args: Vec> = Vec::with_capacity(param_count); let mut stmts = vec![]; @@ -270,7 +285,7 @@ impl<'hir> LoweringContext<'_, 'hir> { for idx in 0..param_count { let (param, pat_node_id) = this.generate_param(is_method, idx, span); - parameters.push(param); + parameters.push(param.clone()); let generate_arg = |this: &mut Self| this.generate_arg(is_method, idx, param.pat.hir_id, span); @@ -310,12 +325,12 @@ impl<'hir> LoweringContext<'_, 'hir> { call_expr_id = hir_id; - (this.arena.alloc_from_iter(parameters), final_expr) + (parameters, final_expr) }); debug_assert_ne!(call_expr_id, HirId::INVALID); - (block_id, call_expr_id, unused_target_expr) + (block_id, params, call_expr_id, unused_target_expr) } fn lower_block_maybe_more_than_once( @@ -571,7 +586,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ident = self.lower_ident(delegation.ident); - let body_id = self.lower_body(|this| { + let (_params, body_id) = self.lower_body(|this| { let path = this.lower_qpath( delegation.id, &delegation.qself, @@ -600,7 +615,7 @@ impl<'hir> LoweringContext<'_, 'hir> { targeted_by_break: false, }); - (&[], this.mk_expr(hir::ExprKind::Block(block, None), span)) + (Vec::new(), this.mk_expr(hir::ExprKind::Block(block, None), span)) }); let generics = hir::Generics::empty(); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 470813615ae0b..bc5b28d3bcaf5 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -878,7 +878,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // The `async` desugaring takes a resume argument and maintains a `task_context`, // whereas a generator does not. - let (inputs, params, task_context): (&[_], &[_], _) = match desugaring_kind { + let (inputs, task_context): (&[_], _) = match desugaring_kind { hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen => { // Resume argument type: `ResumeTy` let unstable_span = self.mark_span_with_reason( @@ -887,12 +887,11 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(Arc::clone(self.allow_gen_future())), ); let resume_ty = self.make_lang_item_qpath(LangItem::ResumeTy, unstable_span, None); - let input_ty = hir::Ty { + let input_ty = self.arena.alloc(hir::Ty { hir_id: self.next_id(), kind: hir::TyKind::Path(resume_ty), span: unstable_span, - }; - let inputs = arena_vec![self; input_ty]; + }); // Lower the argument pattern/ident. The ident is used again in the `.await` lowering. let (pat, task_context_hid) = self.pat_ident_binding_mode( @@ -903,14 +902,15 @@ impl<'hir> LoweringContext<'_, 'hir> { let param = hir::Param { hir_id: self.next_id(), pat, + ty: input_ty, ty_span: self.lower_span(span), - span: self.lower_span(span), + param_span: self.lower_span(span), }; let params = arena_vec![self; param]; - (inputs, params, Some(task_context_hid)) + (params, Some(task_context_hid)) } - hir::CoroutineDesugaring::Gen => (&[], &[], None), + hir::CoroutineDesugaring::Gen => (&[], None), }; let output = @@ -920,9 +920,10 @@ impl<'hir> LoweringContext<'_, 'hir> { inputs, output, fn_decl_kind: hir::FnDeclFlags::default(), + fn_has_body: true, }); - let body = self.lower_body(move |this| { + let (_, body) = self.lower_body(move |this| { this.coroutine_kind = Some(coroutine_kind); let old_ctx = this.task_context; @@ -932,7 +933,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let res = body(this); this.task_context = old_ctx; - (params, res) + (Vec::new(), res) }); let explicit_captures: &'hir [hir::ExplicitCapture] = match coroutine_source { diff --git a/compiler/rustc_ast_lowering/src/expr/closure.rs b/compiler/rustc_ast_lowering/src/expr/closure.rs index 71f7a9364fd5d..392d895140b4c 100644 --- a/compiler/rustc_ast_lowering/src/expr/closure.rs +++ b/compiler/rustc_ast_lowering/src/expr/closure.rs @@ -133,7 +133,6 @@ impl<'hir> LoweringContext<'_, 'hir> { binder, capture_clause, closure_id, - expr_hir_id, constness, movability, decl, @@ -160,7 +159,6 @@ impl<'hir> LoweringContext<'_, 'hir> { binder: &ClosureBinder, capture_clause: CaptureBy, closure_id: NodeId, - closure_hir_id: HirId, constness: Const, movability: Movability, decl: &FnDecl, @@ -171,7 +169,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let closure_def_id = self.local_def_id(closure_id); let (binder_clause, generic_params) = self.lower_closure_binder(binder); - let ((body_id, closure_kind), move_expr_state) = + let (((params, body_id), closure_kind), move_expr_state) = self.with_new_scopes(fn_decl_span, move |this| { let mut coroutine_kind = find_attr!( attrs, @@ -210,10 +208,10 @@ impl<'hir> LoweringContext<'_, 'hir> { let fn_decl = self.lower_fn_decl( decl, closure_id, - closure_hir_id, FnDeclKind::Closure, None, DiscardParams::No, + params, ); let c = self.arena.alloc(hir::Closure { @@ -310,15 +308,12 @@ impl<'hir> LoweringContext<'_, 'hir> { } }; - let body = self.with_new_scopes(fn_decl_span, |this| { - let inner_decl = - FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; - + let (parameters, body) = self.with_new_scopes(fn_decl_span, |this| { // Transform `async |x: u8| -> X { ... }` into // `|x: u8| || -> X { ... }`. let body_id = this.lower_body(|this| { let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( - &inner_decl, + &decl, |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)), fn_decl_span, body.span, @@ -340,10 +335,10 @@ impl<'hir> LoweringContext<'_, 'hir> { let fn_decl = self.lower_fn_decl( &decl, closure_id, - closure_hir_id, FnDeclKind::Closure, None, DiscardParams::No, + parameters, ); if let Const::Yes(span) = constness { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a7f138c992517..93c49af0f1e60 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -246,7 +246,7 @@ impl<'hir> LoweringContext<'_, 'hir> { kind: hir::ExprKind::Block(self.lower_block(block, false), None), span: self.lower_span(*span), }; - self.record_body(&[], body) + self.record_body(body) }), ), ItemKind::Fn(Fn { @@ -264,7 +264,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // only cares about the input argument patterns in the function // declaration (decl), not the return types. let coroutine_marker = header.coroutine_marker; - let body_id = this.lower_maybe_coroutine_body( + let (params, body_id) = this.lower_maybe_coroutine_body( *fn_sig_span, span, hir_id, @@ -280,10 +280,10 @@ impl<'hir> LoweringContext<'_, 'hir> { this.lower_fn_decl( decl, id, - hir_id, FnDeclKind::Fn, coroutine_marker, if body.is_none() { DiscardParams::Yes } else { DiscardParams::No }, + params, ) }); let sig = hir::FnSig { @@ -319,8 +319,9 @@ impl<'hir> LoweringContext<'_, 'hir> { }, ItemKind::GlobalAsm(asm) => { let asm = self.lower_inline_asm(span, asm); - let fake_body = - self.lower_body(|this| (&[], this.expr(span, hir::ExprKind::InlineAsm(asm)))); + let (_, fake_body) = self.lower_body(|this| { + (Vec::new(), this.expr(span, hir::ExprKind::InlineAsm(asm))) + }); hir::ItemKind::GlobalAsm { asm, fake_body } } ItemKind::TyAlias(TyAlias { ident, generics, after_where_clause, ty, .. }) => { @@ -620,16 +621,22 @@ impl<'hir> LoweringContext<'_, 'hir> { let fdec = &sig.decl; let itctx = ImplTraitContext::Universal; let (generics, (decl, fn_args)) = self.lower_generics(generics, itctx, |this| { + let params = fdec + .inputs + .iter() + .filter(|p| !p.is_const_param()) + .map(|x| this.lower_param(x)) + .collect(); ( // Disallow `impl Trait` in foreign items. // Parameters are discarded because foreign functions don't have a body this.lower_fn_decl( fdec, i.id, - hir_id, FnDeclKind::ExternFn, None, DiscardParams::Yes, + params, ), this.lower_fn_params_to_idents(fdec), ) @@ -848,16 +855,23 @@ impl<'hir> LoweringContext<'_, 'hir> { // FIXME(contracts): Deny contract here since it won't apply to // any impl method or callees. let idents = self.lower_fn_params_to_idents(&sig.decl); + let params = sig + .decl + .inputs + .iter() + .filter(|p| !p.is_const_param()) + .map(|x| self.lower_param(x)) + .collect(); let (generics, sig) = self.lower_method_sig( generics, sig, i.id, - hir_id, FnDeclKind::Trait, sig.header.coroutine_marker, attrs, // Parameters are discarded for functions without a body DiscardParams::Yes, + params, ); if define_opaque.is_some() { self.dcx().span_err( @@ -881,7 +895,7 @@ impl<'hir> LoweringContext<'_, 'hir> { define_opaque, .. }) => { - let body_id = self.lower_maybe_coroutine_body( + let (params, body_id) = self.lower_maybe_coroutine_body( sig.span, i.span, hir_id, @@ -895,11 +909,11 @@ impl<'hir> LoweringContext<'_, 'hir> { generics, sig, i.id, - hir_id, FnDeclKind::Trait, sig.header.coroutine_marker, attrs, DiscardParams::No, + params, ); self.lower_define_opaque(hir_id, &define_opaque); ( @@ -1096,7 +1110,7 @@ impl<'hir> LoweringContext<'_, 'hir> { AssocItemKind::Fn(Fn { sig, ident, generics, body, contract, define_opaque, .. }) => { - let body_id = self.lower_maybe_coroutine_body( + let (params, body_id) = self.lower_maybe_coroutine_body( sig.span, i.span, hir_id, @@ -1110,11 +1124,11 @@ impl<'hir> LoweringContext<'_, 'hir> { generics, sig, i.id, - hir_id, if is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent }, sig.header.coroutine_marker, attrs, if body.is_none() { DiscardParams::Yes } else { DiscardParams::No }, + params, ); self.lower_define_opaque(hir_id, &define_opaque); @@ -1213,12 +1227,8 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn record_body( - &mut self, - params: &'hir [hir::Param<'hir>], - value: hir::Expr<'hir>, - ) -> hir::BodyId { - let body = hir::Body { params, value: self.arena.alloc(value) }; + fn record_body(&mut self, value: hir::Expr<'hir>) -> hir::BodyId { + let body = hir::Body { value: self.arena.alloc(value) }; let id = body.id(); assert_eq!(id.hir_id.owner, self.curr_owner.owner_id()); self.curr_owner.bodies.push((id.hir_id.local_id, self.arena.alloc(body))); @@ -1227,25 +1237,25 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_body( &mut self, - f: impl FnOnce(&mut Self) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>), - ) -> hir::BodyId { + f: impl FnOnce(&mut Self) -> (Vec>, hir::Expr<'hir>), + ) -> (Vec>, hir::BodyId) { let prev_coroutine_kind = self.coroutine_kind.take(); let task_context = self.task_context.take(); let (parameters, result) = f(self); - let body_id = self.record_body(parameters, result); + let body_id = self.record_body(result); self.task_context = task_context; self.coroutine_kind = prev_coroutine_kind; - body_id + (parameters, body_id) } - fn lower_param(&mut self, param: &Param) -> hir::Param<'hir> { + pub(super) fn lower_param(&mut self, param: &Param) -> PartialParam<'hir> { let hir_id = self.lower_node_id(param.id); self.lower_attrs(hir_id, ¶m.attrs, param.span, AstTarget::Param(param)); - hir::Param { + PartialParam { hir_id, pat: self.lower_pat(¶m.pat), ty_span: self.lower_span(param.ty.span), - span: self.lower_span(param.span), + param_span: self.lower_span(param.span), } } @@ -1254,14 +1264,14 @@ impl<'hir> LoweringContext<'_, 'hir> { decl: &FnDecl, contract: Option<&FnContract>, body: impl FnOnce(&mut Self) -> hir::Expr<'hir>, - ) -> hir::BodyId { + ) -> (Vec>, hir::BodyId) { self.lower_body(|this| { - let params = this.arena.alloc_from_iter( - decl.inputs - .iter() - .filter(|param| !param.is_const_param()) - .map(|x| this.lower_param(x)), - ); + let params = decl + .inputs + .iter() + .filter(|param| !param.is_const_param()) + .map(|x| this.lower_param(x)) + .collect(); // Optionally lower the fn contract if let Some(contract) = contract { @@ -1277,20 +1287,21 @@ impl<'hir> LoweringContext<'_, 'hir> { decl: &FnDecl, body: &Block, contract: Option<&FnContract>, - ) -> hir::BodyId { + ) -> (Vec>, hir::BodyId) { self.lower_fn_body(decl, contract, |this| this.lower_block_expr(body)) } pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId { self.lower_body(|this| { ( - &[], + Vec::new(), match expr { Some(expr) => this.lower_expr_mut(expr), None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")), }, ) }) + .1 } /// Takes what may be the body of an `async fn` or a `gen fn` and wraps it in an `async {}` or @@ -1305,7 +1316,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body: Option<&Block>, attrs: &'hir [rustc_attr_ir::Attribute], contract: Option<&FnContract>, - ) -> hir::BodyId { + ) -> (Vec>, hir::BodyId) { let Some(body) = body else { // Functions without a body are an error, except if this is an intrinsic. For those we // create a fake body so that the entire rest of the compiler doesn't have to deal with @@ -1368,8 +1379,8 @@ impl<'hir> LoweringContext<'_, 'hir> { body_span: Span, coroutine_marker: CoroutineMarker, coroutine_source: hir::CoroutineSource, - ) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>) { - let mut parameters: Vec> = Vec::new(); + ) -> (Vec>, hir::Expr<'hir>) { + let mut parameters: Vec> = Vec::new(); let mut statements: Vec> = Vec::new(); // Async function parameters are lowered into the closure body so that they are @@ -1437,11 +1448,11 @@ impl<'hir> LoweringContext<'_, 'hir> { // original parameter, but with a different pattern id. let stmt_attrs = self.curr_owner.attrs.get(¶meter.hir_id.local_id).copied(); let (new_parameter_pat, new_parameter_id) = self.pat_ident(desugared_span, ident); - let new_parameter = hir::Param { + let new_parameter = PartialParam { hir_id: parameter.hir_id, pat: new_parameter_pat, ty_span: self.lower_span(parameter.ty_span), - span: self.lower_span(parameter.span), + param_span: self.lower_span(parameter.param_span), }; if is_simple_parameter { @@ -1556,7 +1567,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span: self.lower_span(body_span), }; - (self.arena.alloc_from_iter(parameters), expr) + (parameters, expr) } fn lower_method_sig( @@ -1564,16 +1575,16 @@ impl<'hir> LoweringContext<'_, 'hir> { generics: &Generics, sig: &FnSig, node_id: NodeId, - hir_id: HirId, kind: FnDeclKind, coroutine_marker: Option, attrs: &[rustc_attr_ir::Attribute], discard_params: DiscardParams, + inputs: Vec>, ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { let header = self.lower_fn_header(sig.header, hir::Safety::Safe, attrs); let itctx = ImplTraitContext::Universal; let (generics, decl) = self.lower_generics(generics, itctx, |this| { - this.lower_fn_decl(&sig.decl, node_id, hir_id, kind, coroutine_marker, discard_params) + this.lower_fn_decl(&sig.decl, node_id, kind, coroutine_marker, discard_params, inputs) }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } @@ -2153,3 +2164,12 @@ impl<'hir> LoweringContext<'_, 'hir> { } } } + +/// A `hir::Param` without a `ty`, which exists after the `Param` is lowered, before the corresponding `ty` is lowered. +#[derive(Clone, Debug)] +pub(crate) struct PartialParam<'hir> { + pub hir_id: HirId, + pub pat: &'hir rustc_hir::Pat<'hir>, + pub param_span: Span, + pub ty_span: Span, +} diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 6b4240b666532..a921ddf66cf1e 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -79,6 +79,7 @@ use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; use crate::diagnostics::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait}; +use crate::item::PartialParam; macro_rules! arena_vec { ($this:expr; $($x:expr),*) => ( @@ -1558,6 +1559,13 @@ impl<'hir> LoweringContext<'_, 'hir> { TyKind::FnPtr(f) => { let hir_id = self.lower_node_id(t.id); let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params); + let params = f + .decl + .inputs + .iter() + .filter(|p| !p.is_const_param()) + .map(|x| self.lower_param(x)) + .collect(); let kind = hir::TyKind::FnPtr(self.arena.alloc(hir::FnPtrTy { generic_params, safety: self.lower_safety(f.safety, hir::Safety::Safe), @@ -1565,10 +1573,10 @@ impl<'hir> LoweringContext<'_, 'hir> { decl: self.lower_fn_decl( &f.decl, t.id, - hir_id, FnDeclKind::Pointer, None, DiscardParams::Yes, + params, ), param_idents: self.lower_fn_params_to_idents(&f.decl), })); @@ -1732,13 +1740,7 @@ impl<'hir> LoweringContext<'_, 'hir> { TyKind::MacCall(_) => { span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now") } - TyKind::CVarArgs => { - let guar = self.dcx().span_delayed_bug( - t.span, - "`TyKind::CVarArgs` should have been handled elsewhere", - ); - hir::TyKind::Err(guar) - } + TyKind::CVarArgs => hir::TyKind::CVarArgs, TyKind::View(ty, fields) => { let ty = self.lower_ty_alloc(ty, itctx); let fields = self.arena.alloc_slice(fields); @@ -1928,18 +1930,18 @@ impl<'hir> LoweringContext<'_, 'hir> { /// /// `coro`: If the function is a coroutine, information about the coroutine. /// - /// `discard_params`: if `DiscardParams::Yes`, the parameters are lowered and then discarded. Set this to `DiscardParams::Yes` - /// for functions without bodies, as attributes on parameters are otherwise not validated. - /// Set this to `DiscardParams::No` for functions with bodies, as lowering of the parameters is done by `lower_body`. + /// `has_body`: Whether the function has a body. + /// + /// `hir_inputs`: The partial parameters which were lowered together with the body. #[instrument(level = "debug", skip(self))] fn lower_fn_decl( &mut self, decl: &FnDecl, fn_node_id: NodeId, - fn_hir_id: HirId, kind: FnDeclKind, coro: Option, discard_params: DiscardParams, + hir_inputs: Vec>, ) -> &'hir hir::FnDecl<'hir> { let c_variadic = decl.c_variadic(); let mut splatted = decl.splatted(); @@ -1947,93 +1949,106 @@ impl<'hir> LoweringContext<'_, 'hir> { // Skip the `...` (`CVarArgs`) trailing arguments from the AST, // as they are not explicit in HIR/Ty function signatures. // (instead, the `c_variadic` flag is set to `true`) - let input_count = if decl.c_variadic() { + if decl.c_variadic() { // Splat + variadic errors in AST validation, so just ignore one of them here. splatted = None; - decl.inputs.len() - 1 - } else { - decl.inputs.len() }; - let inputs = decl.inputs.iter().enumerate().take(input_count); // Function argument const params are moved from `inputs` into the function's // generics. Their position is taken from the original `decl.inputs` (before // removing `...`), so it matches the argument position at the call site. - let inputs = self.arena.alloc_from_iter(inputs.filter_map(|(param_idx, param)| { - if let Some(ident) = param.const_param_ident() { - if !matches!( - kind, - FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait - ) { - self.dcx().span_delayed_bug( + let mut hir_inputs = hir_inputs.iter(); + let inputs = self.arena.alloc_from_iter(decl.inputs.iter().enumerate().filter_map( + |(param_idx, param)| { + if let Some(ident) = param.const_param_ident() { + if !matches!( + kind, + FnDeclKind::Fn + | FnDeclKind::Inherent + | FnDeclKind::Impl + | FnDeclKind::Trait + ) { + self.dcx().span_delayed_bug( + param.span, + "Const args only allowed for Free/Inherent/Impl/Trait methods", + ); + return None; + } + let ty = self.lower_ty_alloc( + ¶m.ty, + ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault), + ); + let hir_id = self.lower_node_id(param.id); + let generic_param = hir::GenericParam { + hir_id, + def_id: self.local_def_id(param.id), + name: ParamName::Plain(self.lower_ident(ident)), + span: self.lower_span(param.span), + pure_wrt_drop: false, + kind: hir::GenericParamKind::Const { + ty, + default: None, + arg_pos: Some(param_idx as u16), + }, + colon_span: None, + source: hir::GenericParamSource::Generics, + }; + let ast_generic_param = ast::GenericParam { + id: param.id, + ident, + attrs: param.attrs.clone(), + bounds: Default::default(), + is_placeholder: false, + kind: ast::GenericParamKind::Const { + ty: param.ty.clone(), + span: param.span, + default: None, + }, + colon_span: None, + }; + self.lower_attrs( + hir_id, + ¶m.attrs, param.span, - "Const args only allowed for Free/Inherent/Impl/Trait methods", + AstTarget::GenericParam(&ast_generic_param), ); + self.curr_owner.const_defs.push(generic_param); return None; } - let ty = self.lower_ty_alloc( - ¶m.ty, - ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault), - ); - let hir_id = self.lower_node_id(param.id); - let generic_param = hir::GenericParam { - hir_id, - def_id: self.local_def_id(param.id), - name: ParamName::Plain(self.lower_ident(ident)), - span: self.lower_span(param.span), - pure_wrt_drop: false, - kind: hir::GenericParamKind::Const { - ty, - default: None, - arg_pos: Some(param_idx as u16), - }, - colon_span: None, - source: hir::GenericParamSource::Generics, - }; - let ast_generic_param = ast::GenericParam { - id: param.id, - ident, - attrs: param.attrs.clone(), - bounds: Default::default(), - is_placeholder: false, - kind: ast::GenericParamKind::Const { - ty: param.ty.clone(), - span: param.span, - default: None, - }, - colon_span: None, + let hir_param = hir_inputs.next().unwrap(); + let itctx = match kind { + FnDeclKind::Fn + | FnDeclKind::Inherent + | FnDeclKind::Impl + | FnDeclKind::Trait => ImplTraitContext::Universal, + FnDeclKind::ExternFn => { + ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnParam) + } + FnDeclKind::Closure => { + ImplTraitContext::Disallowed(ImplTraitPosition::ClosureParam) + } + FnDeclKind::Pointer => { + ImplTraitContext::Disallowed(ImplTraitPosition::PointerParam) + } }; - self.lower_attrs( - hir_id, - ¶m.attrs, - param.span, - AstTarget::GenericParam(&ast_generic_param), - ); - self.curr_owner.const_defs.push(generic_param); - return None; - } - if let DiscardParams::Yes = discard_params { - // FIXME This uses `fn_hir_id`, which is not correct, it should use the parameter hir id instead - // The parameter is currently not lowered for functions without bodies, so there is no place to store the lowered hir id - // This should be fixed by storing function parameters in the `hir::FnSig` instead of `hir::Body` - self.lower_attrs(fn_hir_id, ¶m.attrs, param.span, AstTarget::Param(param)); - } - let itctx = match kind { - FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait => { - ImplTraitContext::Universal - } - FnDeclKind::ExternFn => { - ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnParam) - } - FnDeclKind::Closure => { - ImplTraitContext::Disallowed(ImplTraitPosition::ClosureParam) - } - FnDeclKind::Pointer => { - ImplTraitContext::Disallowed(ImplTraitPosition::PointerParam) + + let mut ty = self.lower_ty(¶m.ty, itctx); + // So code using the HIR can assume `CVarArgs` are always the last parameter + if matches!(ty.kind, hir::TyKind::CVarArgs) && param_idx != decl.inputs.len() - 1 { + ty.kind = hir::TyKind::Err( + self.dcx().span_delayed_bug(param.span, "CVarArgs not in final position"), + ); } - }; - Some(self.lower_ty(¶m.ty, itctx)) - })); + + Some(hir::Param { + hir_id: hir_param.hir_id, + pat: hir_param.pat, + ty: self.arena.alloc(ty), + ty_span: hir_param.ty_span, + param_span: hir_param.param_span, + }) + }, + )); let output = match coro { Some(coro) => { @@ -2109,7 +2124,12 @@ impl<'hir> LoweringContext<'_, 'hir> { .set_splatted(splatted, inputs.len()) .unwrap(); - self.arena.alloc(hir::FnDecl { inputs, output, fn_decl_kind }) + self.arena.alloc(hir::FnDecl { + inputs, + output, + fn_decl_kind, + fn_has_body: matches!(discard_params, DiscardParams::No), + }) } // Transforms `-> T` for `async fn` into `-> OpaqueTy { .. }` diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 3ba713531d666..013557a66aac7 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -488,7 +488,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let anon_const = self.with_new_scopes(span, |this| { let def_id = this.local_def_id(e.id); let hir_id = this.lower_node_id(e.id); - let body = this.lower_body(|this| { + let (_, body) = this.lower_body(|this| { // Need to use a custom function as we can't just subtract `1` from a `char`. let kind = hir::ExprKind::Path(this.make_lang_item_qpath( LangItem::RangeSub, @@ -498,7 +498,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let fn_def = this.arena.alloc(hir::Expr { hir_id: this.next_id(), kind, span }); let args = this.arena.alloc([this.lower_expr_mut(&e.value)]); ( - &[], + Vec::new(), hir::Expr { hir_id: this.next_id(), kind: hir::ExprKind::Call(fn_def, args), @@ -550,7 +550,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(hir::AnonConst { def_id, hir_id, - body: this.lower_body(|_this| (&[], path_expr)), + body: this.lower_body(|_this| (Vec::new(), path_expr)).1, span, }) }); diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index e759fd6618276..2916dc1430da8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -512,13 +512,13 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { && let node = self.infcx.tcx.hir_node_by_def_id(local_def_id) && let Some(fn_decl) = node.fn_decl() && let Some(ident) = node.ident() - && let Some(arg) = fn_decl.inputs.get(pos + offset) + && let Some(param) = fn_decl.inputs.get(pos + offset) { // If we can't suggest borrowing in the call, but the function definition // is local, instead offer changing the function to borrow that argument. - let mut span: MultiSpan = arg.span.into(); + let mut span: MultiSpan = param.ty.span.into(); span.push_span_label( - arg.span, + param.ty.span, "this parameter takes ownership of the value".to_string(), ); let descr = match node.fn_kind() { @@ -2774,12 +2774,14 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { let ty::Tuple(params) = tupled_params.kind() else { return }; // Find the first argument with a matching type and get its identifier. - let Some(this_name) = params.iter().zip(tcx.hir_body_param_idents(closure.body)).find_map( - |(param_ty, ident)| { + let Some(this_name) = params + .iter() + .zip(tcx.hir_body_param_idents(closure.fn_decl)) + .find_map(|(param_ty, ident)| { // FIXME: also support deref for stuff like `Rc` arguments if param_ty.peel_refs() == local_ty { ident } else { None } - }, - ) else { + }) + else { return; }; @@ -4602,7 +4604,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { // Need to use the `rustc_middle::ty` types to compare against the // `return_region`. Then use the `rustc_hir` type to get only // the lifetime span. - match &fn_decl.inputs[index].kind { + match &fn_decl.inputs[index].ty.kind { hir::TyKind::Ref(lifetime, ..) => { // With access to the lifetime, we can get // the span of it. @@ -4655,7 +4657,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { // This is case 2 from above but only for closures, return type is anonymous // reference so we select // the first argument. - let argument_span = fn_decl.inputs.first()?.span; + let argument_span = fn_decl.inputs.first()?.ty.span; let argument_ty = sig.inputs().skip_binder().first()?; // Closure arguments are wrapped in a tuple, so we need to get the first @@ -4675,7 +4677,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { ty::Ref(_, _, _) => { // This is also case 2 from above but for functions, return type is still an // anonymous reference so we select the first argument. - let argument_span = fn_decl.inputs.first()?.span; + let argument_span = fn_decl.inputs.first()?.ty.span; let argument_ty = *sig.inputs().skip_binder().first()?; let return_span = fn_decl.output.span(); diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 4d65410455118..6db001e8334f5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -1,7 +1,7 @@ use rustc_abi::FieldIdx; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diag}; -use rustc_hir::intravisit::Visitor; +use rustc_hir::intravisit::{HirTyCtxt, Visitor}; use rustc_hir::{self as hir, CaptureBy, ExprKind, HirId, Node}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -1188,6 +1188,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { cannot_remove: FxHashSet::default(), desugar_binding_spans: Vec::new(), }; + finder.visit_fn_decl(tcx.hir_fn_decl(self.mir_hir_id())); finder.visit_body(body); let mut suggestions = Vec::new(); diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 30d6ecc017b42..09cbb39f1ef0e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -7,7 +7,7 @@ use rustc_attr_ir::lang_items::LangItem; use rustc_errors::{Applicability, Diag}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; -use rustc_hir::{self as hir, BindingMode, ByRef, Expr, Node}; +use rustc_hir::{self as hir, BindingMode, ByRef, Expr, Node, intravisit}; use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::visit::PlaceContext; use rustc_middle::mir::{ @@ -926,11 +926,11 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { let f_in_trait = f_in_trait.as_local()?; if let Node::TraitItem(ti) = self.infcx.tcx.hir_node_by_def_id(f_in_trait) && let hir::TraitItemKind::Fn(sig, _) = ti.kind - && let Some(ty) = sig.decl.inputs.get(local.index() - 1) - && let hir::TyKind::Ref(_, _, hir::Mutability::Not) = ty.kind + && let Some(param) = sig.decl.inputs.get(local.index() - 1) + && let hir::TyKind::Ref(_, _, hir::Mutability::Not) = param.ty.kind && sig.decl.implicit_self().has_implicit_self() { - Some(ty.span) + Some(param.ty.span) } else { None } @@ -965,7 +965,9 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { let def_id = self.body.source.def_id(); if let Some(local_def_id) = def_id.as_local() && let Some(body) = self.infcx.tcx.hir_maybe_body_owned_by(local_def_id) - && let Some(hir_id) = (BindingFinder { span: pat_span }).visit_body(&body).break_value() + && let Some(hir_id) = (BindingFinder { tcx: self.infcx.tcx, span: pat_span }) + .visit_body(&body) + .break_value() && let node = self.infcx.tcx.hir_node(hir_id) && let hir::Node::LetStmt(hir::LetStmt { pat: hir::Pat { kind: hir::PatKind::Ref(_, _, _), .. }, @@ -1308,7 +1310,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { arg_pos + if sig.decl.implicit_self().has_implicit_self() { 1 } else { 0 }, ) - .map(|arg| arg.span) + .map(|param| param.ty.span) .unwrap_or(ident.span), ), _ => None, @@ -1613,7 +1615,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { let hir_id = if let Some(local_def_id) = def_id.as_local() && let Some(body) = self.infcx.tcx.hir_maybe_body_owned_by(local_def_id) { - BindingFinder { span: sugg_span }.visit_body(&body).break_value() + BindingFinder { tcx: self.infcx.tcx, span: sugg_span }.visit_body(&body).break_value() } else { None }; @@ -1788,12 +1790,14 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { } } -struct BindingFinder { +struct BindingFinder<'tcx> { + tcx: TyCtxt<'tcx>, span: Span, } -impl<'tcx> Visitor<'tcx> for BindingFinder { +impl<'tcx> Visitor<'tcx> for BindingFinder<'tcx> { type Result = ControlFlow; + fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) -> Self::Result { if let hir::StmtKind::Let(local) = s.kind && local.pat.span == self.span @@ -1813,6 +1817,14 @@ impl<'tcx> Visitor<'tcx> for BindingFinder { ControlFlow::Continue(()) } } + + fn visit_body(&mut self, b: &rustc_hir::Body<'tcx>) -> Self::Result { + // Also visit the parameter patterns + if let Some(decl) = self.tcx.hir_fn_decl_by_hir_id(self.tcx.hir_body_owner(b.id())) { + intravisit::walk_fn_decl(self, decl)?; + } + hir::intravisit::walk_body(self, b) + } } fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option) -> bool { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 35815bc91645e..2fbbb040e6ec7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -489,10 +489,10 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { if let Some(def_id) = def_id.as_local() && let owner = tcx.expect_hir_owner_node(def_id) && let Some(decl) = owner.fn_decl() - && let Some(ty) = decl.inputs.get(0) + && let Some(param) = decl.inputs.get(0) { // Point at the `&'static self` receiver. - bounds.push(ty.span); + bounds.push(param.ty.span); } else if !bounds.iter().any(|sp| sp.overlaps(def_span)) { // The method is not defined on the local crate, point at the signature instead of // just the receiver as an approximation. We don't add it if there are already diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index eb896526173b1..5a496a79c1825 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -430,9 +430,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { let captured_place = self.upvars.get(upvar_index)?; let upvar_hir_id = captured_place.get_root_variable(); let parent_local_def_id = parent_def_id.as_local()?; - let parent_body = tcx.hir_body_owned_by(parent_local_def_id); + let parent_sig = + tcx.hir_fn_sig_by_hir_id(tcx.local_def_id_to_hir_id(parent_local_def_id)).unwrap(); let param_index = - parent_body.params.iter().position(|param| param.pat.hir_id == upvar_hir_id)?; + parent_sig.decl.inputs.iter().position(|param| param.pat.hir_id == upvar_hir_id)?; // Get the parent fn's signature with liberated late-bound regions, // so we have `ReLateParam` instead of `ReBound`. @@ -550,7 +551,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { ) -> Option<&hir::Ty<'tcx>> { let fn_decl = self.infcx.tcx.hir_fn_decl_by_hir_id(self.mir_hir_id())?; // Closures don't have implicit self arguments in HIR, so use `user_arg_index` directly. - let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(user_arg_index)?; + let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(user_arg_index)?.ty; match argument_hir_ty.kind { // This indicates a variable with no type annotation, like // `|x|`... in that case, we can't highlight the type but diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index cc4fea22b819a..2493a79881982 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1959,7 +1959,6 @@ pub struct BodyId { /// map using `body_owner_def_id()`. #[derive(Debug, Clone, Copy, StableHash)] pub struct Body<'hir> { - pub params: &'hir [Param<'hir>], pub value: &'hir Expr<'hir>, } @@ -3701,6 +3700,8 @@ pub enum TyKind<'hir, Unambig = ()> { /// This variant is not always used to represent inference types, sometimes /// [`GenericArg::Infer`] is used instead. Infer(Unambig), + /// Only used as the type of C-variadic (...) parameters + CVarArgs, } /// Stores explicit register name from source @@ -3822,8 +3823,9 @@ pub struct Param<'hir> { #[stable_hash(ignore)] pub hir_id: HirId, pub pat: &'hir Pat<'hir>, + pub ty: &'hir Ty<'hir>, pub ty_span: Span, - pub span: Span, + pub param_span: Span, } /// Error type for splatted argument index errors. @@ -4007,13 +4009,11 @@ impl FnDeclFlags { /// Represents the header (not the body) of a function declaration. #[derive(Debug, Clone, Copy, StableHash)] pub struct FnDecl<'hir> { - /// The types of the function's parameters. - /// - /// Additional argument data is stored in the function's [body](Body::params). - pub inputs: &'hir [Ty<'hir>], + pub inputs: &'hir [Param<'hir>], pub output: FnRetTy<'hir>, /// The packed function declaration attributes. pub fn_decl_kind: FnDeclFlags, + pub fn_has_body: bool, } impl<'hir> FnDecl<'hir> { @@ -4058,6 +4058,7 @@ impl<'hir> FnDecl<'hir> { inputs: &[], output: FnRetTy::DefaultReturn(span), fn_decl_kind: FnDeclFlags::default().set_lifetime_elision_allowed(true), + fn_has_body: true, } } } @@ -5374,7 +5375,7 @@ mod size_asserts { use super::*; // tidy-alphabetical-start static_assert_size!(Block<'_>, 48); - static_assert_size!(Body<'_>, 24); + static_assert_size!(Body<'_>, 8); static_assert_size!(Expr<'_>, 64); static_assert_size!(ExprKind<'_>, 48); static_assert_size!(FnDecl<'_>, 40); @@ -5389,7 +5390,7 @@ mod size_asserts { static_assert_size!(Item<'_>, 88); static_assert_size!(ItemKind<'_>, 64); static_assert_size!(LetStmt<'_>, 64); - static_assert_size!(Param<'_>, 32); + static_assert_size!(Param<'_>, 40); static_assert_size!(Pat<'_>, 80); static_assert_size!(PatKind<'_>, 56); static_assert_size!(Path<'_>, 40); diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index bac88ad43ac30..d9c6081b58b4b 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -109,6 +109,7 @@ impl<'a> FnKind<'a> { pub trait HirTyCtxt<'hir> { /// Retrieves the `Node` corresponding to `id`. fn hir_node(&self, hir_id: HirId) -> Node<'hir>; + fn hir_fn_decl(&self, hir_id: HirId) -> &'hir FnDecl<'hir>; fn hir_body(&self, id: BodyId) -> &'hir Body<'hir>; fn hir_item(&self, id: ItemId) -> &'hir Item<'hir>; fn hir_trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir>; @@ -121,6 +122,9 @@ impl<'hir> HirTyCtxt<'hir> for ! { fn hir_node(&self, _: HirId) -> Node<'hir> { *self } + fn hir_fn_decl(&self, _: HirId) -> &'hir FnDecl<'hir> { + *self + } fn hir_body(&self, _: BodyId) -> &'hir Body<'hir> { *self } @@ -545,7 +549,8 @@ pub trait Visitor<'v>: Sized { } pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) -> V::Result { - let Param { hir_id, pat, ty_span: _, span: _ } = param; + let Param { hir_id, pat, ty, ty_span: _, param_span: _ } = param; + try_visit!(visitor.visit_ty_unambig(*ty)); try_visit!(visitor.visit_id(*hir_id)); visitor.visit_pat(pat) } @@ -666,8 +671,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: } pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &Body<'v>) -> V::Result { - let Body { params, value } = body; - walk_list!(visitor, visit_param, *params); + let Body { value } = body; visitor.visit_expr(*value) } @@ -1082,6 +1086,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) - try_visit!(visitor.visit_ident(*field)); } } + TyKind::CVarArgs => {} } V::Result::output() } @@ -1236,8 +1241,8 @@ pub fn walk_fn_decl<'v, V: Visitor<'v>>( visitor: &mut V, function_declaration: &'v FnDecl<'v>, ) -> V::Result { - let FnDecl { inputs, output, fn_decl_kind: _ } = function_declaration; - walk_list!(visitor, visit_ty_unambig, *inputs); + let FnDecl { inputs, output, fn_decl_kind: _, fn_has_body: _ } = function_declaration; + walk_list!(visitor, visit_param, *inputs); visitor.visit_fn_ret_ty(output) } diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 663a506eb427b..0795774dbeb0b 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -405,11 +405,11 @@ fn report_number_of_arguments_mismatch<'tcx>( .and_then(|def_id| { let declaration_sig = get_declaration_sig(tcx, def_id).expect("foreign item sig"); let pos = declaration_number_args.saturating_sub(1); - declaration_sig.decl.inputs.get(pos).map(|arg| { + declaration_sig.decl.inputs.get(pos).map(|param| { if pos == 0 { - arg.span + param.ty.span } else { - arg.span.with_lo(declaration_sig.decl.inputs[0].span.lo()) + param.ty.span.with_lo(declaration_sig.decl.inputs[0].ty.span.lo()) } }) }) @@ -422,11 +422,11 @@ fn report_number_of_arguments_mismatch<'tcx>( .decl .inputs .get(pos) - .map(|arg| { + .map(|param| { if pos == 0 { - arg.span + param.ty.span } else { - arg.span.with_lo(external_impl_sig.decl.inputs[0].span.lo()) + param.ty.span.with_lo(external_impl_sig.decl.inputs[0].ty.span.lo()) } }) .unwrap_or_else(|| tcx.def_span(external_impl)); @@ -545,12 +545,12 @@ fn extract_spans_for_error_reporting<'tcx>( let (mut external_impl_args, external_impl_name) = { let item = tcx.hir_expect_item(external_impl); let (ident, sig, _, _) = item.expect_fn(); - (sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())), ident) + (sig.decl.inputs.iter().map(|p| p.ty.span).chain(iter::once(sig.decl.output.span())), ident) }; let declaration_args = declaration.as_local().map(|def_id| { if let Some(sig) = get_declaration_sig(tcx, def_id) { - sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) + sig.decl.inputs.iter().map(|p| p.ty.span).chain(iter::once(sig.decl.output.span())) } else { panic!("expected {def_id:?} to be a foreign function"); } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 1e08e9b3ddf36..1ae6ab92139d4 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1029,15 +1029,15 @@ fn report_trait_method_mismatch<'tcx>( // When the `impl` receiver is an arbitrary self type, like `self: Box`, the // span points only at the type `Box, but we want to cover the whole // argument pattern and type. - let (sig, body) = tcx.hir_expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); + let (sig, _) = tcx.hir_expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); let span = tcx - .hir_body_param_idents(body) + .hir_body_param_idents(sig.decl) .zip(sig.decl.inputs.iter()) - .map(|(param_ident, ty)| { + .map(|(param_ident, param)| { if let Some(param_ident) = param_ident { - param_ident.span.to(ty.span) + param_ident.span.to(param.ty.span) } else { - ty.span + param.ty.span } }) .next() @@ -1520,12 +1520,12 @@ fn extract_spans_for_error_reporting<'tcx>( let tcx = infcx.tcx; let mut impl_args = { let (sig, _) = tcx.hir_expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); - sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) + sig.decl.inputs.iter().map(|p| p.ty.span).chain(iter::once(sig.decl.output.span())) }; let trait_args = trait_m.def_id.as_local().map(|def_id| { let (sig, _) = tcx.hir_expect_trait_item(def_id).expect_fn(); - sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) + sig.decl.inputs.iter().map(|p| p.ty.span).chain(iter::once(sig.decl.output.span())) }); match terr { @@ -1794,11 +1794,11 @@ fn compare_number_of_method_arguments<'tcx>( .and_then(|def_id| { let (trait_m_sig, _) = &tcx.hir_expect_trait_item(def_id).expect_fn(); let pos = trait_number_args.saturating_sub(1); - trait_m_sig.decl.inputs.get(pos).map(|arg| { + trait_m_sig.decl.inputs.get(pos).map(|param| { if pos == 0 { - arg.span + param.ty.span } else { - arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo()) + param.ty.span.with_lo(trait_m_sig.decl.inputs[0].ty.span.lo()) } }) }) @@ -1810,11 +1810,11 @@ fn compare_number_of_method_arguments<'tcx>( .decl .inputs .get(pos) - .map(|arg| { + .map(|param| { if pos == 0 { - arg.span + param.ty.span } else { - arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo()) + param.ty.span.with_lo(impl_m_sig.decl.inputs[0].ty.span.lo()) } }) .unwrap_or_else(|| tcx.def_span(impl_m.def_id)); @@ -1869,8 +1869,8 @@ fn compare_number_of_method_arguments<'tcx>( let first_lo = arg_idents .get(0) .and_then(|id| id.map(|id| id.span.lo())) - .unwrap_or(first.span.lo()); - Some(impl_m_sig.span.with_lo(first_lo).with_hi(last.span.hi())) + .unwrap_or(first.ty.span.lo()); + Some(impl_m_sig.span.with_lo(first_lo).with_hi(last.ty.span.hi())) } else { // We have no inputs; construct the span to the left of the last parenthesis // fn foo( ) {} @@ -1931,7 +1931,7 @@ fn compare_number_of_method_arguments<'tcx>( .decl .inputs .get(trait_number_args - 1) - .map(|arg| arg.span.hi())? + .map(|param| param.ty.span.hi())? }; let span = full.with_lo(lo); Some(( @@ -2057,9 +2057,9 @@ fn compare_synthetic_generics<'tcx>( } } - let span = input_tys - .iter() - .find_map(|ty| Visitor(impl_def_id).visit_ty_unambig(ty).break_value())?; + let span = input_tys.iter().find_map(|param| { + Visitor(impl_def_id).visit_ty_unambig(param.ty).break_value() + })?; let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.bounds; let bounds = bounds.first()?.span().to(bounds.last()?.span()); diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 02acd8dc58918..dd0ee2b2a7a44 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -668,7 +668,7 @@ pub fn check_function_signature<'tcx>( let mut args = { let node = tcx.expect_hir_owner_node(fn_id); let decl = node.fn_decl().unwrap_or_else(|| bug!("expected fn decl, found {:?}", node)); - decl.inputs.iter().map(|t| t.span).chain(std::iter::once(decl.output.span())) + decl.inputs.iter().map(|p| p.ty.span).chain(std::iter::once(decl.output.span())) }; match err { diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 96acfd2f97177..bbc4926452fb3 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -778,7 +778,10 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> { if this.tcx.hir_body_owner_kind(owner_id).is_fn_or_closure() { // The arguments and `self` are parented to the fn. this.cx.var_parent = this.cx.parent; - for param in body.params { + + let decl = + this.tcx.hir_fn_decl_by_hir_id(this.tcx.hir_body_owner(body_id)).unwrap(); + for param in decl.inputs { this.visit_pat(param.pat); } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 62df20baa9265..36e3e2055bf3e 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1665,8 +1665,12 @@ fn check_fn_or_method<'tcx>( // on the entire `FnSig`, since this would use the same `WellFormedLoc` // for each type, preventing the HIR wf check from generating // a nice error message. - let arg_span = - |idx| hir_decl.inputs.get(idx).map_or(hir_decl.output.span(), |arg: &hir::Ty<'_>| arg.span); + let arg_span = |idx| { + hir_decl + .inputs + .get(idx) + .map_or(hir_decl.output.span(), |param: &hir::Param<'_>| param.ty.span) + }; sig.inputs_and_output = tcx.mk_type_list_from_iter(sig.inputs_and_output.iter().enumerate().map(|(idx, ty)| { @@ -1712,14 +1716,14 @@ fn check_fn_or_method<'tcx>( ); } else { tcx.dcx().span_err( - hir_decl.inputs.last().map_or(span, |input| input.span), + hir_decl.inputs.last().map_or(span, |input| input.ty.span), "functions with the \"rust-call\" ABI must take a single non-self tuple argument", ); } // No more inputs other than the `self` type and the tuple type if inputs.next().is_some() { tcx.dcx().span_err( - hir_decl.inputs.last().map_or(span, |input| input.span), + hir_decl.inputs.last().map_or(span, |input| input.ty.span), "functions with the \"rust-call\" ABI must take a single non-self tuple argument", ); } @@ -1761,7 +1765,7 @@ fn check_method_receiver<'tcx>( return Ok(()); } - let span = fn_sig.decl.inputs[0].span; + let span = fn_sig.decl.inputs[0].ty.span; let loc = WellFormedLoc::Param { function: method.def_id.expect_local(), param_idx: 0 }; let sig = tcx.fn_sig(method.def_id).instantiate_identity().skip_norm_wip(); diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin/coerce_shared.rs b/compiler/rustc_hir_analysis/src/coherence/builtin/coerce_shared.rs index 46bd5086a9dc8..b9d5d6562a628 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin/coerce_shared.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin/coerce_shared.rs @@ -171,6 +171,7 @@ fn first_explicit_lifetime_span_in_ty(ty: &hir::Ty<'_>) -> Option { hir::TyKind::InferDelegation(_) | hir::TyKind::Never | hir::TyKind::Infer(()) + | hir::TyKind::CVarArgs | hir::TyKind::Err(_) => None, } } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 62b0e4d23dc43..8f329dfd84e97 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -748,17 +748,22 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { let input_tys = decl .inputs .iter() + .filter(|param| !matches!(param.ty.kind, hir::TyKind::CVarArgs)) .enumerate() - .map(|(i, a)| { - if let hir::TyKind::Infer(()) = a.kind + .map(|(i, param)| { + if let hir::TyKind::Infer(()) = param.ty.kind && let Some(suggested_ty) = self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i)) { - infer_replacements.push((a.span, suggested_ty.to_string())); - return Ty::new_error_with_message(tcx, a.span, suggested_ty.to_string()); + infer_replacements.push((param.ty.span, suggested_ty.to_string())); + return Ty::new_error_with_message( + tcx, + param.ty.span, + suggested_ty.to_string(), + ); } - self.lowerer().lower_ty(a) + self.lowerer().lower_ty(param.ty) }) .collect(); @@ -1699,8 +1704,8 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( .emit_err(diagnostics::SIMDFFIHighlyExperimental { span: hir_ty.span, snip }); } }; - for (input, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) { - check(input, *ty) + for (param, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) { + check(param.ty, *ty) } if let hir::FnRetTy::Return(ty) = decl.output { check(ty, fty.output().skip_binder()) diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 1dc6c1c96e93e..fd3315a3fafa1 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -18,7 +18,8 @@ use rustc_hir::def_id::LocalDefIdMap; use rustc_hir::definitions::{DefPathData, PerParentDisambiguatorsMap}; use rustc_hir::intravisit::{self, InferKind, Visitor}; use rustc_hir::{ - self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeKind, Node, + self as hir, AmbigArg, FnDecl, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeKind, + Node, }; use rustc_macros::extension; use rustc_middle::hir::nested_filter; @@ -434,9 +435,21 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { self.tcx } + fn visit_fn_decl(&mut self, decl: &'tcx FnDecl<'tcx>) -> Self::Result { + // Declarations of functions with a body are visited from `visit_nested_body` + if !decl.fn_has_body { + intravisit::walk_fn_decl(self, decl); + } + } + fn visit_nested_body(&mut self, body: hir::BodyId) { let body = self.tcx.hir_body(body); self.with(Scope::Body { id: body.id(), s: self.scope }, |this| { + if let Some(decl) = this.tcx.hir_fn_decl_by_hir_id(this.tcx.hir_body_owner(body.id())) { + for input in decl.inputs { + intravisit::walk_pat(this, input.pat); + } + } this.visit_body(body); }); } @@ -474,6 +487,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let infer_spans = fn_decl .inputs .into_iter() + .map(|param| param.ty) .filter_map(span_of_infer) .chain(infer_in_rt_sp) .collect::>(); @@ -976,7 +990,11 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let hir_id = self.tcx.local_def_id_to_hir_id(def_id); self.rbv.late_bound_vars.insert(hir_id.local_id, bound_vars); } - self.visit_fn_like_elision(fd.inputs, output, matches!(fk, intravisit::FnKind::Closure)); + self.visit_fn_like_elision( + fd.inputs.iter().map(|p| p.ty), + output, + matches!(fk, intravisit::FnKind::Closure), + ); intravisit::walk_fn_kind(self, fk); self.visit_nested_body(body_id) } @@ -1811,7 +1829,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { path: &hir::Path<'tcx>, ) { if let Some((inputs, output)) = generic_args.paren_sugar_inputs_output() { - self.visit_fn_like_elision(inputs, Some(output), false); + self.visit_fn_like_elision(inputs.iter(), Some(output), false); return; } @@ -2260,10 +2278,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } } - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self, inputs))] fn visit_fn_like_elision( &mut self, - inputs: &'tcx [hir::Ty<'tcx>], + inputs: impl Iterator>, output: Option<&'tcx hir::Ty<'tcx>>, in_closure: bool, ) { @@ -2594,8 +2612,8 @@ fn is_late_bound_map( let mut late_bound = FxIndexSet::default(); let mut constrained_by_input = ConstrainedCollector { regions: Default::default(), tcx }; - for arg_ty in sig.decl.inputs { - constrained_by_input.visit_ty_unambig(arg_ty); + for param in sig.decl.inputs { + constrained_by_input.visit_ty_unambig(param.ty); } let mut appears_in_output = diff --git a/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs index 4d131b73f9cf1..eb1b9dee337f4 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs @@ -359,7 +359,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { if let Some(fn_decl) = node.fn_decl() && let Some(ty_id) = ty_id { - let in_arg = fn_decl.inputs.iter().any(|t| t.hir_id == ty_id); + let in_arg = fn_decl.inputs.iter().any(|p| p.ty.hir_id == ty_id); let in_ret = matches!(fn_decl.output, hir::FnRetTy::Return(ty) if ty.hir_id == ty_id); @@ -460,7 +460,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { let fn_sig = self.tcx.hir_get_if_local(self.def_id).and_then(hir::Node::fn_sig); let is_used_in_input = |def_id| { fn_sig.is_some_and(|fn_sig| { - fn_sig.decl.inputs.iter().any(|ty| match ty.kind { + fn_sig.decl.inputs.iter().any(|param| match param.ty.kind { hir::TyKind::Path(hir::QPath::Resolved( None, hir::Path { res: hir::def::Res::Def(_, id), .. }, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index 530706b0653db..b5229b500e062 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -84,15 +84,15 @@ fn is_valid_cmse_inputs<'tcx>( let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig); let fn_sig = tcx.erase_and_anonymize_regions(fn_sig); - for (ty, hir_ty) in fn_sig.inputs().iter().zip(fn_decl.inputs) { + for (ty, hir_param) in fn_sig.inputs().iter().zip(fn_decl.inputs) { if ty.has_infer_types() { let err = LayoutError::Unknown(*ty); - return Err((hir_ty.span, tcx.arena.alloc(err))); + return Err((hir_param.ty.span, tcx.arena.alloc(err))); } let layout = tcx .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*ty)) - .map_err(|e| (hir_ty.span, e))?; + .map_err(|e| (hir_param.ty.span, e))?; let align = layout.layout.align().bytes(); let size = layout.layout.size().bytes(); @@ -102,7 +102,7 @@ fn is_valid_cmse_inputs<'tcx>( // i.e. exceeds 4 32-bit registers if accum > 16 { - excess_argument_spans.push(hir_ty.span); + excess_argument_spans.push(hir_param.ty.span); } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index 4a763e5b89316..e04a8eb559aeb 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -951,8 +951,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } // Suggestions for function parameters. - for ty in sig.decl.inputs { - if ty.peel_refs().hir_id != hir_id { + for param in sig.decl.inputs { + if param.ty.peel_refs().hir_id != hir_id { continue; } let sugg = self.add_generic_param_suggestion(generics, span, &trait_name); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index f15b8c81c51d2..fc9a66c606449 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -3477,6 +3477,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::TyKind::View(ty, fields) => { self.lower_view(self.lower_ty(ty), fields, hir_ty.span) } + hir::TyKind::CVarArgs => Ty::new_error( + tcx, + self.dcx().delayed_bug("This is only reachable if errors previously occurred"), + ), hir::TyKind::Err(guar) => Ty::new_error(tcx, *guar), }; diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 9806b7b873918..d4ab8fe53e28b 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -195,14 +195,14 @@ pub(super) fn diagnostic_hir_wf_check<'tcx>( WellFormedLoc::Param { param_idx, .. } => { let fn_decl = tcx.hir_fn_decl_by_hir_id(hir_id).unwrap(); // Get return type - if param_idx as usize == fn_decl.inputs.len() { + if param_idx == fn_decl.inputs.len() { match fn_decl.output { hir::FnRetTy::Return(ty) => vec![ty], // The unit type `()` is always well-formed hir::FnRetTy::DefaultReturn(_span) => vec![], } } else { - vec![&fn_decl.inputs[param_idx as usize]] + vec![fn_decl.inputs[param_idx].ty] } } WellFormedLoc::HirId(_) | WellFormedLoc::None => return None, diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 9bb2b89bfe6bf..679e7a212064a 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -47,7 +47,7 @@ pub enum Nested { ImplItem(hir::ImplItemId), ForeignItem(hir::ForeignItemId), Body(hir::BodyId), - BodyParamPat(hir::BodyId, usize), + BodyParamPat(hir::HirId, usize), } pub trait PpAnn { @@ -64,7 +64,7 @@ impl PpAnn for &dyn rustc_hir::intravisit::HirTyCtxt<'_> { Nested::ImplItem(id) => state.print_impl_item(self.hir_impl_item(id)), Nested::ForeignItem(id) => state.print_foreign_item(self.hir_foreign_item(id)), Nested::Body(id) => state.print_expr(self.hir_body(id).value), - Nested::BodyParamPat(id, i) => state.print_pat(self.hir_body(id).params[i].pat), + Nested::BodyParamPat(id, i) => state.print_pat(self.hir_fn_decl(id).inputs[i].pat), } } } @@ -501,6 +501,7 @@ impl<'a> State<'a> { } self.word("})"); } + hir::TyKind::CVarArgs => unreachable!("Filtered out before calling `print_type`"), } self.end(ib) } @@ -660,7 +661,14 @@ impl<'a> State<'a> { } hir::ItemKind::Fn { ident, sig, generics, body, .. } => { let (cb, ib) = self.head(""); - self.print_fn(sig.header, Some(ident.name), generics, sig.decl, &[], Some(body)); + self.print_fn( + sig.header, + Some(ident.name), + generics, + sig.decl, + &[], + Some(item.hir_id()), + ); self.word(" "); self.end(ib); self.end(cb); @@ -982,7 +990,7 @@ impl<'a> State<'a> { m: &hir::FnSig<'_>, generics: &hir::Generics<'_>, arg_idents: &[Option], - body_id: Option, + body_id: Option, ) { self.print_fn(m.header, Some(ident.name), generics, m.decl, arg_idents, body_id); } @@ -1002,7 +1010,7 @@ impl<'a> State<'a> { } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { let (cb, ib) = self.head(""); - self.print_method_sig(ti.ident, sig, ti.generics, &[], Some(body)); + self.print_method_sig(ti.ident, sig, ti.generics, &[], Some(ti.hir_id())); self.nbsp(); self.end(ib); self.end(cb); @@ -1027,7 +1035,7 @@ impl<'a> State<'a> { } hir::ImplItemKind::Fn(ref sig, body) => { let (cb, ib) = self.head(""); - self.print_method_sig(ii.ident, sig, ii.generics, &[], Some(body)); + self.print_method_sig(ii.ident, sig, ii.generics, &[], Some(ii.hir_id())); self.nbsp(); self.end(ib); self.end(cb); @@ -1693,7 +1701,7 @@ impl<'a> State<'a> { self.print_constness(constness); self.print_capture_clause(capture_clause); - self.print_closure_params(fn_decl, body); + self.print_closure_params(fn_decl, expr.hir_id); self.space(); // This is a bare expression. @@ -2281,7 +2289,7 @@ impl<'a> State<'a> { generics: &hir::Generics<'_>, decl: &hir::FnDecl<'_>, arg_idents: &[Option], - body_id: Option, + body_id: Option, ) { self.print_fn_header_info(header); @@ -2319,13 +2327,17 @@ impl<'a> State<'a> { } i += 1; }; - self.commasep(Inconsistent, decl.inputs, |s, ty| { - let ib = s.ibox(INDENT_UNIT); - print_arg(s, Some(ty)); - s.end(ib); - }); + self.commasep( + Inconsistent, + decl.inputs.iter().filter(|param| !matches!(param.ty.kind, hir::TyKind::CVarArgs)), + |s, param| { + let ib = s.ibox(INDENT_UNIT); + print_arg(s, Some(param.ty)); + s.end(ib); + }, + ); if decl.c_variadic() { - if !decl.inputs.is_empty() { + if decl.inputs.len() != 1 { self.word(", "); } print_arg(self, None); @@ -2337,21 +2349,21 @@ impl<'a> State<'a> { self.print_where_clause(generics) } - fn print_closure_params(&mut self, decl: &hir::FnDecl<'_>, body_id: hir::BodyId) { + fn print_closure_params(&mut self, decl: &hir::FnDecl<'_>, body_id: hir::HirId) { self.word("|"); let mut i = 0; - self.commasep(Inconsistent, decl.inputs, |s, ty| { + self.commasep(Inconsistent, decl.inputs, |s, param| { let ib = s.ibox(INDENT_UNIT); s.ann.nested(s, Nested::BodyParamPat(body_id, i)); i += 1; - if let hir::TyKind::Infer(()) = ty.kind { + if let hir::TyKind::Infer(()) = param.ty.kind { // Print nothing. } else { s.word(":"); s.space(); - s.print_type(ty); + s.print_type(param.ty); } s.end(ib); }); diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 8061e522f43aa..759f1a581afb8 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -50,14 +50,14 @@ pub(super) fn check_fn<'a, 'tcx>( let span = body.value.span; - for param in body.params { + for param in decl.inputs { GatherLocalsVisitor::gather_from_param(fcx, param); } // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` // (as it's created inside the body itself, not passed in from outside). let maybe_va_list = fn_sig.c_variadic().then(|| { - let span = body.params.last().unwrap().span; + let span = decl.inputs.last().unwrap().ty.span; let va_list_did = tcx.require_lang_item(LangItem::VaList, span); let region = fcx.next_region_var(RegionVariableOrigin::Misc(span)); @@ -66,12 +66,12 @@ pub(super) fn check_fn<'a, 'tcx>( // Add formal parameters. let inputs_fn = fn_sig.inputs().iter().copied(); - for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { + for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(decl.inputs).enumerate() { // We checked the root's signature during wfcheck, but not the child. if fcx.tcx.is_typeck_child(fn_def_id.to_def_id()) { fcx.register_wf_obligation( param_ty.into(), - param.span, + param.param_span, ObligationCauseCode::WellFormed(WellFormedLoc::Param { function: fn_def_id, param_idx: idx, @@ -80,9 +80,7 @@ pub(super) fn check_fn<'a, 'tcx>( } // Check the pattern. - let ty: Option<&hir::Ty<'_>> = decl.inputs.get(idx); - let ty_span = ty.map(|ty| ty.span); - fcx.check_pat_top(param.pat, param_ty, ty_span, None, None); + fcx.check_pat_top(param.pat, param_ty, Some(param.ty.span), None, None); if param.pat.is_never_pattern() { fcx.function_diverges_because_of_empty_arguments.set(Diverges::Always { span: param.pat.span, @@ -98,10 +96,10 @@ pub(super) fn check_fn<'a, 'tcx>( // ty.span == binding_span iff this is a closure parameter with no type ascription, // or if it's an implicit `self` parameter ObligationCauseCode::SizedArgumentType( - if ty_span == Some(param.span) && tcx.is_closure_like(fn_def_id.into()) { + if param.ty.span == param.param_span && tcx.is_closure_like(fn_def_id.into()) { None } else { - ty.map(|ty| ty.hir_id) + Some(param.ty.hir_id) }, ), ); diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 07ce529f9174d..5cea8dcb179f8 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -806,12 +806,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // The liberated version of this signature should be a subtype // of the liberated form of the expectation. - for ((hir_ty, &supplied_ty), expected_ty) in iter::zip( + for ((hir_pram, &supplied_ty), expected_ty) in iter::zip( iter::zip(decl.inputs, supplied_sig.inputs()), expected_sigs.liberated_sig.inputs(), // `liberated_sig` is E'. ) { // Check that E' = S'. - let cause = self.misc(hir_ty.span); + let cause = self.misc(hir_pram.ty.span); let InferOk { value: (), obligations } = self.at(&cause, self.param_env).eq( DefineOpaqueTypes::Yes, *expected_ty, @@ -865,7 +865,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let bound_vars = self.tcx.late_bound_vars(hir_id); // First, convert the types that the user supplied (if any). - let supplied_arguments = decl.inputs.iter().map(|a| lowerer.lower_ty(a)); + let supplied_arguments = decl.inputs.iter().map(|p| lowerer.lower_ty(p.ty)); let supplied_return = match decl.output { hir::FnRetTy::Return(ref output) => lowerer.lower_ty(output), hir::FnRetTy::DefaultReturn(_) => match closure_kind { @@ -1061,9 +1061,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let lowerer = self.lowerer(); let err_ty = Ty::new_error(self.tcx, guar); - let supplied_arguments = decl.inputs.iter().map(|a| { + let supplied_arguments = decl.inputs.iter().map(|p| { // Convert the types that the user supplied (if any), but ignore them. - lowerer.lower_ty(a); + lowerer.lower_ty(p.ty); err_ty }); diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 03981e6edff09..b2c238e800055 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -892,8 +892,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Some(ty_ref) = fn_decl .inputs .iter() - .filter_map(|ty| match ty.kind { - hir::TyKind::Ref(lt, inner_ty, mutbl) if ty.span == *ty_span => Some((lt, inner_ty, mutbl)), + .filter_map(|param| match param.ty.kind { + hir::TyKind::Ref(lt, inner_ty, mutbl) if param.ty.span == *ty_span => Some((lt, inner_ty, mutbl)), _ => None, }) .next() diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 3bcd96711e655..9f4b94809b05f 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -305,8 +305,12 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } } - pub fn consume_body(&self, body: &hir::Body<'_>) -> Result<(), Cx::Error> { - for param in body.params { + pub fn consume_body( + &self, + decl: &hir::FnDecl<'_>, + body: &hir::Body<'_>, + ) -> Result<(), Cx::Error> { + for param in decl.inputs { let param_ty = self.pat_ty_adjusted(param.pat)?; debug!("consume_body: param_ty = {:?}", param_ty); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 3183f4101fdd3..7038baece8165 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -759,9 +759,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let spans = if let SplatLoweringInfo::FnDef(def_id) = fn_id && let Some(hir_node) = self.tcx.hir_get_if_local(def_id) && let Some(fn_decl) = hir_node.fn_decl() - && let Some(arg_ty) = fn_decl.inputs.get(first_tupled_arg_index_usz) + && let Some(param) = fn_decl.inputs.get(first_tupled_arg_index_usz) { - let arg_def_span = arg_ty.span; + let arg_def_span = param.ty.span; vec![call_span, arg_def_span] } else { vec![call_span] @@ -2001,10 +2001,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } else if let Some(hir::Node::Expr(e)) = self.tcx.hir_get_if_local(def_id) - && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind + && let hir::ExprKind::Closure(hir::Closure { fn_decl, .. }) = &e.kind { - let param = expected_idx - .and_then(|expected_idx| self.tcx.hir_body(*body).params.get(expected_idx)); + let param = expected_idx.and_then(|expected_idx| fn_decl.inputs.get(expected_idx)); let (kind, span) = if let Some(param) = param { // Try to find earlier invocations of this closure to find if the type mismatch // is because of inference. If we find one, point at them. @@ -2045,7 +2044,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - ("closure parameter", param.span) + ("closure parameter", param.param_span) } else { ("closure", self.tcx.def_span(def_id)) }; @@ -2171,25 +2170,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Make sure to remove both the receiver and variadic argument. Both are removed // when matching parameter types. - let fn_inputs = sig.decl.inputs.get(is_method as usize..)?.iter().map(|param| { - if let hir::TyKind::Path(QPath::Resolved( - _, - &hir::Path { res: Res::Def(_, res_def_id), .. }, - )) = param.kind - { - generics - .params - .iter() - .position(|param| param.def_id.to_def_id() == res_def_id) - .map(GenericIdx::from_usize) - } else { - None - } - }); + let fn_inputs = sig + .decl + .inputs + .get(is_method as usize..(sig.decl.inputs.len() - sig.decl.c_variadic() as usize))? + .iter() + .map(|param| { + if let hir::TyKind::Path(QPath::Resolved( + _, + &hir::Path { res: Res::Def(_, res_def_id), .. }, + )) = param.ty.kind + { + generics + .params + .iter() + .position(|param| param.def_id.to_def_id() == res_def_id) + .map(GenericIdx::from_usize) + } else { + None + } + }); let mut params_with_generics: IndexVec = match (body_id, params) { (Some(_), Some(_)) | (None, None) => unreachable!(), - (Some(body), None) => { - let params = self.tcx.hir_body(body).params; + (Some(_body), None) => { + let params = sig.decl.inputs; let params = params .get(is_method as usize..params.len() - sig.decl.c_variadic() as usize)?; debug_assert_eq!(params.len(), fn_inputs.len()); @@ -2244,7 +2248,7 @@ enum FnParam<'hir> { impl FnParam<'_> { fn span(&self) -> Span { match self { - Self::Param(param) => param.span, + Self::Param(param) => param.param_span, Self::Ident(ident) => { if let Some(ident) = ident { ident.span diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 7db3c4a4d6eea..cfa7cf6e2b72a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -455,7 +455,12 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { _hir_id: rustc_hir::HirId, _hir_ty: Option<&hir::Ty<'_>>, ) -> (Vec>, Ty<'tcx>) { - let input_tys = decl.inputs.iter().map(|a| self.lowerer().lower_ty(a)).collect(); + let input_tys = decl + .inputs + .iter() + .filter(|p| !matches!(p.ty.kind, hir::TyKind::CVarArgs)) + .map(|p| self.lowerer().lower_ty(p.ty)) + .collect(); let output_ty = match decl.output { hir::FnRetTy::Return(output) => self.lowerer().lower_ty(output), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 40f48898ec658..315f9abddbb97 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -718,7 +718,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let hir::FnDecl { inputs, output, .. } = fn_ptr_ty.decl; let inputs_str = - inputs.iter().map(|ty| rustc_hir_pretty::ty_to_string(self, ty)).join(", "); + inputs.iter().map(|param| rustc_hir_pretty::ty_to_string(self, param.ty)).join(", "); let output_str = match output { hir::FnRetTy::DefaultReturn(_) => String::new(), @@ -1284,7 +1284,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let all_bounds_str = all_matching_bounds_strs.join(" + "); let ty_param_used_in_fn_params = fn_parameters.iter().any(|param| { - let ty = self.lowerer().lower_ty( param); + let ty = self.lowerer().lower_ty(param.ty); matches!(ty.kind(), ty::Param(fn_param_ty_param) if expected_ty_as_param == fn_param_ty_param) }); diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 2945a6b3b5136..a3044b133c6a6 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -147,19 +147,18 @@ fn typeck_with_inspect<'tcx>( }; check_abi(tcx, id, span, fn_sig.abi()); - loops::check(tcx, def_id, body); // Compute the function signature from point of view of inside the fn. let mut fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); - // Normalize the input and output types one at a time, using a different // `WellFormedLoc` for each. We cannot call `normalize_associated_types` // on the entire `FnSig`, since this would use the same `WellFormedLoc` // for each type, preventing the HIR wf check from generating // a nice error message. - let arg_span = - |idx| decl.inputs.get(idx).map_or(decl.output.span(), |arg: &hir::Ty<'_>| arg.span); + let arg_span = |idx| { + decl.inputs.get(idx).map_or(decl.output.span(), |param: &hir::Param<'_>| param.ty.span) + }; fn_sig.inputs_and_output = tcx.mk_type_list_from_iter( fn_sig @@ -170,7 +169,7 @@ fn typeck_with_inspect<'tcx>( ); if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NAKED) { - naked_functions::typeck_naked_fn(tcx, def_id, body); + naked_functions::typeck_naked_fn(tcx, def_id, decl, body); } check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params()); @@ -265,7 +264,7 @@ fn typeck_with_inspect<'tcx>( fcx.check_asms(); - let typeck_results = fcx.resolve_type_vars_in_body(body); + let typeck_results = fcx.resolve_type_vars_in_body(node, body); fcx.detect_opaque_types_added_during_writeback(); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index d4487bfaea67c..ebd026741d1ff 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -453,10 +453,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = kind && let hir::def::Res::Local(hir_id) = path.res && let hir::Node::Pat(b) = self.tcx.hir_node(hir_id) - && let hir::Node::Param(p) = self.tcx.parent_hir_node(b.hir_id) - && let Some(decl) = self.tcx.parent_hir_node(p.hir_id).fn_decl() - && let Some(ty) = decl.inputs.iter().find(|ty| ty.span == p.ty_span) - && let hir::TyKind::Ref(_, inner_ty, hir::Mutability::Not) = &ty.kind + && let hir::Node::Param(param) = self.tcx.parent_hir_node(b.hir_id) + && let hir::TyKind::Ref(_, inner_ty, hir::Mutability::Not) = + ¶m.ty.kind { err.span_suggestion_verbose( inner_ty.span.shrink_to_lo(), @@ -4474,16 +4473,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::TraitFn::Required([ident, ..]) => { matches!(ident, Some(Ident { name: kw::SelfLower, .. })) } - hir::TraitFn::Provided(body_id) => { - self.tcx.hir_body(*body_id).params.first().is_some_and( - |param| { - matches!( - param.pat.kind, - hir::PatKind::Binding(_, _, ident, _) - if ident.name == kw::SelfLower - ) - }, - ) + hir::TraitFn::Provided(_body_id) => { + fn_sig.decl.inputs.first().is_some_and(|param| { + matches!( + param.pat.kind, + hir::PatKind::Binding(_, _, ident, _) + if ident.name == kw::SelfLower + ) + }) } _ => false, }; @@ -4491,8 +4488,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !fn_sig.decl.implicit_self().has_implicit_self() && self_first_arg { - if let Some(ty) = fn_sig.decl.inputs.get(0) { - arbitrary_rcvr.push(ty.span); + if let Some(param) = fn_sig.decl.inputs.get(0) { + arbitrary_rcvr.push(param.ty.span); } return false; } diff --git a/compiler/rustc_hir_typeck/src/naked_functions.rs b/compiler/rustc_hir_typeck/src/naked_functions.rs index ce4893ce94b1f..60cf9bd2a7d6a 100644 --- a/compiler/rustc_hir_typeck/src/naked_functions.rs +++ b/compiler/rustc_hir_typeck/src/naked_functions.rs @@ -18,11 +18,12 @@ use crate::diagnostics::{ pub(crate) fn typeck_naked_fn<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, + decl: &'tcx hir::FnDecl<'tcx>, body: &'tcx hir::Body<'tcx>, ) { debug_assert!(find_attr!(tcx, def_id, Naked(..))); - check_no_patterns(tcx, body.params); - check_no_parameters_use(tcx, body); + check_no_patterns(tcx, decl.inputs); + check_no_parameters_use(tcx, decl, body); check_asm(tcx, def_id, body); } @@ -39,9 +40,13 @@ fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) { } /// Checks that function parameters aren't used in the function body. -fn check_no_parameters_use<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>) { +fn check_no_parameters_use<'tcx>( + tcx: TyCtxt<'tcx>, + decl: &'tcx hir::FnDecl<'tcx>, + body: &'tcx hir::Body<'tcx>, +) { let mut params = HirIdSet::default(); - for param in body.params { + for param in decl.inputs { param.pat.each_binding(|_binding_mode, hir_id, _span, _ident| { params.insert(hir_id); }); diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 3c59017c78d85..9205333f42606 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -94,6 +94,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { capture_clause, body: body_id, explicit_captures, + fn_decl, .. }) = expr.kind else { @@ -128,7 +129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fake_reads: Default::default(), }; - let _ = euv::ExprUseVisitor::new(&closure_fcx, &mut delegate).consume_body(body); + let _ = euv::ExprUseVisitor::new(&closure_fcx, &mut delegate).consume_body(fn_decl, body); for capture in explicit_captures { let place = closure_fcx.place_for_root_variable(closure_def_id, capture.var_hir_id); @@ -220,10 +221,22 @@ struct InferBorrowKindVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { match expr.kind { - hir::ExprKind::Closure(&hir::Closure { capture_clause, body: body_id, .. }) => { + hir::ExprKind::Closure(&hir::Closure { + capture_clause, + body: body_id, + fn_decl, + .. + }) => { let body = self.fcx.tcx.hir_body(body_id); self.visit_body(body); - self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause); + self.fcx.analyze_closure( + expr.hir_id, + expr.span, + fn_decl, + body_id, + body, + capture_clause, + ); } _ => {} } @@ -244,6 +257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, closure_hir_id: HirId, span: Span, + fn_decl: &'tcx hir::FnDecl<'tcx>, body_id: hir::BodyId, body: &'tcx hir::Body<'tcx>, mut capture_clause: hir::CaptureBy, @@ -288,7 +302,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // First collect the captures implied by the operations in the closure // body. This records how each place is actually used: borrowed, modified, // moved, and so on. - let _ = euv::ExprUseVisitor::new(&closure_fcx, &mut delegate).consume_body(body); + let _ = euv::ExprUseVisitor::new(&closure_fcx, &mut delegate).consume_body(fn_decl, body); // Save the captures that must be upgraded to by-value after inferring // the closure kind from the operations in the body. diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 923c0d49936c8..8faf4b1247acf 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -17,7 +17,7 @@ use rustc_data_structures::unord::ExtendUnord; use rustc_errors::{E0720, ErrorGuaranteed}; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, InferKind, Visitor}; -use rustc_hir::{self as hir, AmbigArg, HirId}; +use rustc_hir::{self as hir, AmbigArg, FnDecl, HirId}; use rustc_infer::traits::solve::Goal; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; @@ -40,6 +40,7 @@ use crate::FnCtxt; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn resolve_type_vars_in_body( &self, + node: hir::Node<'tcx>, body: &'tcx hir::Body<'tcx>, ) -> &'tcx ty::TypeckResults<'tcx> { let item_def_id = self.tcx.hir_body_owner_def_id(body.id()); @@ -50,8 +51,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.has_rustc_attrs && find_attr!(self.tcx, item_def_id, RustcDumpUserArgs); let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_args); - for param in body.params { - wbcx.visit_node_id(param.pat.span, param.hir_id); + if let Some(decl) = node.fn_decl() { + for param in decl.inputs { + wbcx.visit_node_id(param.pat.span, param.hir_id); + wbcx.visit_param(param); + } } match self.tcx.hir_body_owner_kind(item_def_id) { // Visit the type of a const or static, which is used during THIR building. @@ -260,10 +264,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { match e.kind { - hir::ExprKind::Closure(&hir::Closure { body, .. }) => { + hir::ExprKind::Closure(&hir::Closure { body, fn_decl, .. }) => { let body = self.fcx.tcx.hir_body(body); - for param in body.params { + for param in fn_decl.inputs { self.visit_node_id(e.span, param.hir_id); + self.visit_param(param); } self.visit_body(body); @@ -373,6 +378,12 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { self.write_ty_to_typeck_results(inf_id, ty); } } + + fn visit_fn_decl(&mut self, fd: &'tcx FnDecl<'tcx>) -> Self::Result { + if fd.fn_has_body { + intravisit::walk_fn_decl(self, fd); + } + } } impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { diff --git a/compiler/rustc_lint/src/gpukernel_abi.rs b/compiler/rustc_lint/src/gpukernel_abi.rs index 05f41cd6fdf48..1d9f009087134 100644 --- a/compiler/rustc_lint/src/gpukernel_abi.rs +++ b/compiler/rustc_lint/src/gpukernel_abi.rs @@ -177,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperGpuKernelLint { cx.tcx.emit_node_span_lint( IMPROPER_GPU_KERNEL_ARG, input_hir.hir_id, - input_hir.span, + input_hir.ty.span, ImproperGpuKernelArg { ty: *input_ty }, ); } diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs index ea09ce79fd49d..5f747fdd63b34 100644 --- a/compiler/rustc_lint/src/lifetime_syntax.rs +++ b/compiler/rustc_lint/src/lifetime_syntax.rs @@ -126,7 +126,7 @@ fn check_fn_like<'tcx>(cx: &LateContext<'tcx>, fd: &'tcx hir::FnDecl<'tcx>) { } for input in fd.inputs { - LifetimeInfoCollector::collect(input, |info| { + LifetimeInfoCollector::collect(input.ty, |info| { if let Some(group) = map.get_mut(&info.lifetime.kind) { group.inputs.push(info); } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 66478f052d68b..5202ae61cedac 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -7,7 +7,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{FnKind, Visitor}; -use rustc_hir::{GenericParamKind, PatExprKind, PatKind}; +use rustc_hir::{GenericParamKind, Node, PatExprKind, PatKind}; use rustc_lint_defs::{declare_lint, declare_lint_pass}; use rustc_middle::hir::nested_filter::All; use rustc_middle::ty::AssocContainer; @@ -417,28 +417,25 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { } } - fn check_ty(&mut self, cx: &LateContext<'_>, ty: &hir::Ty<'_, hir::AmbigArg>) { - if let hir::TyKind::FnPtr(hir::FnPtrTy { param_idents, .. }) = &ty.kind { - for param_ident in *param_idents { - if let Some(param_ident) = param_ident { - self.check_snake_case(cx, "variable", param_ident); - } - } - } - } - fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &hir::TraitItem<'_>) { - if let hir::TraitItemKind::Fn(_, hir::TraitFn::Required(param_idents)) = item.kind { + if let hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_)) = item.kind { self.check_snake_case(cx, "trait method", &item.ident); - for param_ident in param_idents { - if let Some(param_ident) = param_ident { - self.check_snake_case(cx, "variable", param_ident); - } - } } } fn check_pat(&mut self, cx: &LateContext<'_>, p: &hir::Pat<'_>) { + // Ignore patterns in foreign items for now + // FIXME(#33995) remove this check + if let Node::ForeignItem(_) = cx + .tcx + .hir_parent_iter(p.hir_id) + .find(|(_, n)| !matches!(n, Node::Pat(_) | Node::Param(_))) + .unwrap() + .1 + { + return; + } + if let PatKind::Binding(_, hid, ident, _) = p.kind { if let hir::Node::PatField(field) = cx.tcx.parent_hir_node(hid) { if !field.is_shorthand { diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs index 646824c00d5b5..7ace026a28ce3 100644 --- a/compiler/rustc_lint/src/types/improper_ctypes.rs +++ b/compiler/rustc_lint/src/types/improper_ctypes.rs @@ -1117,7 +1117,7 @@ impl<'tcx> ImproperCTypesLint { for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) { let state = VisitorState::fn_entry_point(fn_mode, FnPos::Arg); - self.check_type_for_external_abi_fnptr(cx, state, input_hir, *input_ty, fn_mode); + self.check_type_for_external_abi_fnptr(cx, state, input_hir.ty, *input_ty, fn_mode); } if let hir::FnRetTy::Return(ret_hir) = decl.output { @@ -1165,7 +1165,7 @@ impl<'tcx> ImproperCTypesLint { for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) { let state = VisitorState::fn_entry_point(fn_mode, FnPos::Arg); - self.check_ffi_type(cx, *input_ty, state, input_hir.span, fn_mode, || { + self.check_ffi_type(cx, *input_ty, state, input_hir.ty.span, fn_mode, || { let input_ty = Unnormalized::new_wip(*input_ty); let mut visitor = ImproperCTypesVisitor::new(cx, input_ty, fn_mode); visitor.check_type(state, input_ty) diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index a1f931290f827..682e235016d9a 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -309,8 +309,8 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn hir_body_param_idents(self, id: BodyId) -> impl Iterator> { - self.hir_body(id).params.iter().map(|param| match param.pat.kind { + pub fn hir_body_param_idents(self, decl: &FnDecl<'_>) -> impl Iterator> { + decl.inputs.iter().map(|param| match param.pat.kind { PatKind::Binding(_, _, ident, _) => Some(ident), PatKind::Wild => Some(Ident::new(kw::Underscore, param.pat.span)), _ => None, @@ -1053,7 +1053,7 @@ impl<'tcx> TyCtxt<'tcx> { /// (instead of just the item header) pub fn hir_span_with_body(self, hir_id: HirId) -> Span { match self.hir_node(hir_id) { - Node::Param(param) => param.span, + Node::Param(param) => param.param_span, Node::Item(item) => item.span, Node::ForeignItem(foreign_item) => foreign_item.span, Node::TraitItem(trait_item) => trait_item.span, @@ -1158,6 +1158,10 @@ impl<'tcx> intravisit::HirTyCtxt<'tcx> for TyCtxt<'tcx> { (*self).hir_node(hir_id) } + fn hir_fn_decl(&self, hir_id: HirId) -> &'tcx FnDecl<'tcx> { + (*self).hir_fn_decl_by_hir_id(hir_id).unwrap() + } + fn hir_body(&self, id: BodyId) -> &'tcx Body<'tcx> { (*self).hir_body(id) } diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 18272069be5e7..8a5088a386ecd 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -477,8 +477,8 @@ pub fn provide(providers: &mut Providers) { }; providers.fn_arg_idents = |tcx, def_id| { let node = tcx.hir_node_by_def_id(def_id); - if let Some(body_id) = node.body_id() { - tcx.arena.alloc_from_iter(tcx.hir_body_param_idents(body_id)) + if let Some(decl) = node.fn_decl() { + tcx.arena.alloc_from_iter(tcx.hir_body_param_idents(decl)) } else if let Node::TraitItem(&TraitItem { kind: TraitItemKind::Fn(_, TraitFn::Required(idents)), .. diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index c2a8fa9c31cea..41310e6f40fbf 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -37,12 +37,12 @@ pub(crate) fn thir_body<'tcx>( let owner_id = tcx.local_def_id_to_hir_id(owner_def); if let Some(fn_decl) = tcx.hir_fn_decl_by_hir_id(owner_id) { let closure_env_param = cx.closure_env_param(owner_def, owner_id); - let explicit_params = cx.explicit_params(owner_id, fn_decl, &body); + let explicit_params = cx.explicit_params(owner_id, fn_decl); cx.thir.params = closure_env_param.into_iter().chain(explicit_params).collect(); // The resume argument may be missing, in that case we need to provide it here. // It will always be `()` in this case. - if tcx.is_coroutine(owner_def.to_def_id()) && body.params.is_empty() { + if tcx.is_coroutine(owner_def.to_def_id()) && fn_decl.inputs.is_empty() { cx.thir.params.push(Param { ty: tcx.types.unit, pat: None, @@ -179,16 +179,11 @@ impl<'tcx> ThirBuildCx<'tcx> { &mut self, owner_id: HirId, fn_decl: &'tcx hir::FnDecl<'tcx>, - body: &'tcx hir::Body<'tcx>, ) -> impl Iterator> { let fn_sig = self.typeck_results.liberated_fn_sigs()[owner_id]; - body.params.iter().enumerate().map(move |(index, param)| { - let ty_span = fn_decl - .inputs - .get(index) - // Make sure that inferred closure args have no type span - .and_then(|ty| if param.pat.span != ty.span { Some(ty.span) } else { None }); + fn_decl.inputs.iter().enumerate().map(move |(index, param)| { + let ty_span = if param.ty.span != param.pat.span { Some(param.ty.span) } else { None }; let self_kind = if index == 0 && fn_decl.implicit_self().has_implicit_self() { Some(fn_decl.implicit_self()) @@ -198,8 +193,8 @@ impl<'tcx> ThirBuildCx<'tcx> { // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` // (as it's created inside the body itself, not passed in from outside). - let ty = if fn_decl.c_variadic() && index == fn_decl.inputs.len() { - let va_list_did = self.tcx.require_lang_item(LangItem::VaList, param.span); + let ty = if fn_decl.c_variadic() && index == fn_decl.inputs.len() - 1 { + let va_list_did = self.tcx.require_lang_item(LangItem::VaList, param.ty.span); self.tcx .type_of(va_list_did) diff --git a/compiler/rustc_mir_transform/src/liveness.rs b/compiler/rustc_mir_transform/src/liveness.rs index 887e5179f5c4b..821959e49496e 100644 --- a/compiler/rustc_mir_transform/src/liveness.rs +++ b/compiler/rustc_mir_transform/src/liveness.rs @@ -292,12 +292,11 @@ fn annotate_mut_binding_to_immutable_binding<'tcx>( let hir_param_index = local.as_usize() - if tcx.is_closure_like(body_def_id.to_def_id()) { 2 } else { 1 }; let fn_decl = tcx.hir_node_by_def_id(body_def_id).fn_decl()?; - let ty = fn_decl.inputs[hir_param_index]; - let hir::TyKind::Ref(lt, inner_ty, mutbl) = ty.kind else { return None }; + let param = fn_decl.inputs[hir_param_index]; + let hir::TyKind::Ref(lt, inner_ty, mutbl) = param.ty.kind else { return None }; // ... as a binding pattern. let hir_body = tcx.hir_maybe_body_owned_by(body_def_id)?; - let param = hir_body.params[hir_param_index]; let hir::PatKind::Binding(hir::BindingMode::MUT, _hir_id, ident, _) = param.pat.kind else { return None; }; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 41bc7b0a1539f..35a0ccb6e7a4f 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1136,9 +1136,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if let Some(hir_sig) = hir_sig { match terr { TypeError::ArgumentMutability(idx) | TypeError::ArgumentSorts(_, idx) => { - if let Some(ty) = hir_sig.decl.inputs.get(idx) { - diag.span(ty.span); - cause.span = ty.span; + if let Some(param) = hir_sig.decl.inputs.get(idx) { + diag.span(param.ty.span); + cause.span = param.ty.span; } else if idx == hir_sig.decl.inputs.len() { let span = hir_sig.decl.output.span(); diag.span(span); @@ -1146,9 +1146,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } TypeError::ArgCount => { - if let Some(ty) = hir_sig.decl.inputs.get(expected_sig.inputs().len()) { - diag.span(ty.span); - cause.span = ty.span; + if let Some(param) = hir_sig.decl.inputs.get(expected_sig.inputs().len()) { + diag.span(param.ty.span); + cause.span = param.ty.span; } } TypeError::SafetyMismatch(_) => { @@ -1479,7 +1479,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { - self.check_attributes(param.hir_id, param.span, Target::Param, None); + self.check_attributes(param.hir_id, param.param_span, Target::Param, None); intravisit::walk_param(self, param); } diff --git a/compiler/rustc_passes/src/check_export.rs b/compiler/rustc_passes/src/check_export.rs index dbb6d4b72d432..e065b92acb1c7 100644 --- a/compiler/rustc_passes/src/check_export.rs +++ b/compiler/rustc_passes/src/check_export.rs @@ -225,7 +225,7 @@ impl<'tcx, 'a> ExportableItemsChecker<'tcx, 'a> { let decl = self.tcx.hir_fn_decl_by_hir_id(hir_id).unwrap(); for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) { - self.check_nested_types_are_exportable(*input_ty, input_hir.span); + self.check_nested_types_are_exportable(*input_ty, input_hir.ty.span); } if let hir::FnRetTy::Return(ret_hir) = decl.output { diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index ffa3a7443ecc4..74957ff332d87 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -15,7 +15,7 @@ use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModId}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, ForeignItemId, ItemId, Node, PatKind, QPath}; +use rustc_hir::{self as hir, BodyId, FnDecl, ForeignItemId, ItemId, Node, PatKind, QPath}; use rustc_lint_defs::builtin::{DEAD_CODE, DEAD_CODE_PUB_IN_BINARY}; use rustc_lint_defs::{self as lint, Lint, StableLintExpectationId}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -691,7 +691,15 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { type Result = ControlFlow; - fn visit_nested_body(&mut self, body: hir::BodyId) -> Self::Result { + fn visit_fn_decl(&mut self, decl: &'tcx FnDecl<'tcx>) -> Self::Result { + // Declarations of functions with a body are visited from `visit_nested_body` + if !decl.fn_has_body { + intravisit::walk_fn_decl(self, decl)?; + } + ControlFlow::Continue(()) + } + + fn visit_nested_body(&mut self, body: BodyId) -> Self::Result { let typeck_results = self.tcx.typeck_body(body); // The result shouldn't be tainted, otherwise it will cause ICE. @@ -700,6 +708,10 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { } let old_maybe_typeck_results = self.maybe_typeck_results.replace(typeck_results); + // Also visit the parameter patterns + if let Some(decl) = self.tcx.hir_fn_decl_by_hir_id(self.tcx.hir_body_owner(body)) { + intravisit::walk_fn_decl(self, decl)?; + } let body = self.tcx.hir_body(body); let result = self.visit_body(body); self.maybe_typeck_results = old_maybe_typeck_results; diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index bdd300aee372a..54a892bd95b1a 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -412,6 +412,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { Pat, FieldOf, View, + CVarArgs, Err ] ); diff --git a/compiler/rustc_passes/src/upvars.rs b/compiler/rustc_passes/src/upvars.rs index 88f202919bb59..f9552d24b44d3 100644 --- a/compiler/rustc_passes/src/upvars.rs +++ b/compiler/rustc_passes/src/upvars.rs @@ -16,9 +16,11 @@ pub(crate) fn provide(providers: &mut Providers) { } let local_def_id = def_id.expect_local(); + let fn_decl = tcx.hir_fn_decl_by_hir_id(tcx.local_def_id_to_hir_id(local_def_id))?; let body = tcx.hir_maybe_body_owned_by(local_def_id)?; let mut local_collector = LocalCollector::default(); + local_collector.visit_fn_decl(fn_decl); local_collector.visit_body(&body); let mut capture_collector = CaptureCollector { @@ -26,6 +28,7 @@ pub(crate) fn provide(providers: &mut Providers) { locals: &local_collector.locals, upvars: FxIndexMap::default(), }; + capture_collector.visit_fn_decl(fn_decl); capture_collector.visit_body(&body); if !capture_collector.upvars.is_empty() { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 926efb9ccd7c0..326e62708107f 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -24,7 +24,7 @@ use rustc_errors::{MultiSpan, listify}; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModId}; use rustc_hir::intravisit::{self, InferKind, Visitor}; -use rustc_hir::{self as hir, AmbigArg, ForeignItemId, ItemId, OwnerId, PatKind}; +use rustc_hir::{self as hir, AmbigArg, FnDecl, ForeignItemId, ItemId, OwnerId, PatKind}; use rustc_lint_defs::builtin::{ EXPORTED_PRIVATE_DEPENDENCIES, PRIVATE_BOUNDS, PRIVATE_INTERFACES, UNNAMEABLE_TYPES, }; @@ -1046,6 +1046,8 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { } impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { + fn visit_fn_decl(&mut self, _fd: &'tcx FnDecl<'tcx>) -> Self::Result {} + fn visit_nested_body(&mut self, body_id: hir::BodyId) { let new_typeck_results = self.tcx.typeck_body(body_id); // Do not try reporting privacy violations if we failed to infer types. @@ -1178,9 +1180,18 @@ impl<'tcx> rustc_ty_walk::SpannedTypeVisitor<'tcx> for TypePrivacyVisitor<'tcx> } impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { + fn visit_fn_decl(&mut self, _fd: &'tcx FnDecl<'tcx>) -> Self::Result { + // Handled in `visit_nested_body` + } + fn visit_nested_body(&mut self, body_id: hir::BodyId) { let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.tcx.typeck_body(body_id)); + if let Some(decl) = self.tcx.hir_fn_decl_by_hir_id(self.tcx.hir_body_owner(body_id)) { + for param in decl.inputs { + self.visit_pat(param.pat); + } + } self.visit_body(self.tcx.hir_body(body_id)); self.maybe_typeck_results = old_maybe_typeck_results; } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 07859f505e8f3..2b57a0989c538 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -8,7 +8,7 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ - self as hir, Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource, PatKind, + self as hir, Closure, Expr, ExprKind, FnDecl, FnRetTy, HirId, LetStmt, LocalSource, PatKind, }; use rustc_middle::hir::nested_filter; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, DerefAdjustKind}; @@ -1381,11 +1381,11 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { /// For closures, we first visit the parameters and then the content, /// as we prefer those. - fn visit_body(&mut self, body: &Body<'tcx>) { - for param in body.params { + fn visit_fn_decl(&mut self, decl: &'tcx FnDecl<'tcx>) { + for param in decl.inputs { debug!( "param: span {:?}, ty_span {:?}, pat.span {:?}", - param.span, param.ty_span, param.pat.span + param.param_span, param.ty_span, param.pat.span ); if param.ty_span != param.pat.span { debug!("skipping param: has explicit type"); @@ -1405,7 +1405,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { }) } } - intravisit::walk_body(self, body); + intravisit::walk_fn_decl(self, decl); } #[instrument(level = "debug", skip(self))] diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs index 7079dd39fe64d..4fbe24364817d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs @@ -35,7 +35,7 @@ pub fn find_anon_type<'tcx>( .decl .inputs .iter() - .find_map(|arg| find_component_for_bound_region(tcx, arg, anon_reg.region_def_id)) + .find_map(|param| find_component_for_bound_region(tcx, param.ty, anon_reg.region_def_id)) .map(|ty| (ty, fn_sig)) } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index 93309c916d71c..c537c040a52b5 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -464,12 +464,12 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) = self.tcx().hir_node_by_def_id(local_def_id) { - let body = self.tcx().hir_body(closure.body); // For Fn traits, args[1] is the tupled input types (e.g. `(&mut [u8],)`). let expected_input_tys = expected_args.type_at(1); if let ty::Tuple(input_tys) = *expected_input_tys.kind() { - let suggestions: Vec<_> = body - .params + let suggestions: Vec<_> = closure + .fn_decl + .inputs .iter() .zip(input_tys.iter()) .filter_map(|(param, ty)| { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs index c51016e779c4b..ee82b160ab336 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs @@ -64,20 +64,19 @@ pub fn find_param_with_region<'tcx>( _ => {} } - let body = tcx.hir_maybe_body_owned_by(def_id)?; - - let owner_id = tcx.hir_body_owner(body.id()); + let owner_id = tcx.local_def_id_to_hir_id(def_id); let fn_decl = tcx.hir_fn_decl_by_hir_id(owner_id)?; let poly_fn_sig = tcx.fn_sig(id).instantiate_identity().skip_norm_wip(); let fn_sig = tcx.liberate_late_bound_regions(id, poly_fn_sig); - body.params + fn_decl + .inputs .iter() .take(if fn_sig.c_variadic() { fn_sig.inputs().len() } else { - assert_eq!(fn_sig.inputs().len(), body.params.len()); - body.params.len() + assert_eq!(fn_sig.inputs().len(), fn_decl.inputs.len()); + fn_decl.inputs.len() }) .enumerate() .find_map(|(index, param)| { @@ -93,8 +92,7 @@ pub fn find_param_with_region<'tcx>( } }); found_anon_region.then(|| { - let ty_hir_id = fn_decl.inputs[index].hir_id; - let param_ty_span = tcx.hir_span(ty_hir_id); + let param_ty_span = fn_decl.inputs[index].ty.span; let is_first = index == 0; AnonymousParamInfo { param, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index a7367e9b39604..3382afde1ec53 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -1648,7 +1648,7 @@ fn name_anon_lifetimes_suggestion<'tcx>( let mut collector = AnonLifetimeCollector { tcx, anon_lifetimes: Default::default() }; for input in fn_sig.decl.inputs { - collector.visit_ty_unambig(input); + collector.visit_ty_unambig(input.ty); } // With a single anonymous lifetime in the signature `'_` resolves to it, so leave that case // to the caller. diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index 32ac72708c339..f2871cd59fb91 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -726,13 +726,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) { // 0. Extract fn_decl from hir let hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(hir::Closure { body, fn_decl, .. }), + kind: hir::ExprKind::Closure(hir::Closure { fn_decl, .. }), .. }) = hir else { return; }; - let hir::Body { params, .. } = self.tcx.hir_body(*body); // 1. Get the args of the closure. // 2. Assume exp_found is FnOnce / FnMut / Fn, we can extract function parameters from [1]. @@ -755,8 +754,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let mut is_first = true; let mut has_suggestion = false; - for (((expected, found), param_hir), arg_hir) in - expected.iter().zip(found.iter()).zip(params.iter()).zip(fn_decl.inputs.iter()) + for ((expected, found), param_hir) in + expected.iter().zip(found.iter()).zip(fn_decl.inputs.iter()) { if is_first { is_first = false; @@ -768,7 +767,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && let ty::Ref(found_region, _, _) = found.kind() && expected_region.is_bound() && !found_region.is_bound() - && let hir::TyKind::Infer(()) = arg_hir.kind + && let hir::TyKind::Infer(()) = param_hir.ty.kind { // If the expected region is late bound, the found region is not, and users are asking compiler // to infer the type, we can suggest adding `: &_`. @@ -795,7 +794,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } has_suggestion = true; } else { - let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(param_hir.span) else { + let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(param_hir.param_span) + else { return; }; // Otherwise, keep it as-is. @@ -951,19 +951,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { pat.walk(&mut find_compatible_candidates); } - hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { body, .. }, .. }) + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn { sig: hir::FnSig { decl, .. }, .. }, + .. + }) | hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Fn(_, body), .. + kind: hir::ImplItemKind::Fn(hir::FnSig { decl, .. }, _), + .. }) | hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)), + kind: hir::TraitItemKind::Fn(hir::FnSig { decl, .. }, _), .. }) | hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(hir::Closure { body, .. }), + kind: hir::ExprKind::Closure(hir::Closure { fn_decl: decl, .. }), .. }) => { - for param in self.tcx.hir_body(*body).params { + for param in decl.inputs { param.pat.walk(&mut find_compatible_candidates); } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 10e2ba18f3d7c..0cd3c0f4f18bf 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -3866,17 +3866,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let sm = self.tcx.sess.source_map(); Some(match node { Node::Expr(&hir::Expr { - kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, fn_arg_span, .. }), + kind: + hir::ExprKind::Closure(&hir::Closure { fn_decl, fn_decl_span, fn_arg_span, .. }), .. }) => ( fn_decl_span, fn_arg_span, - self.tcx - .hir_body(body) - .params + fn_decl + .inputs .iter() - .map(|arg| { - if let hir::Pat { kind: hir::PatKind::Tuple(args, _), span, .. } = *arg.pat + .map(|param| { + if let hir::Pat { kind: hir::PatKind::Tuple(args, _), span, .. } = + *param.pat { Some(ArgKind::Tuple( Some(span), @@ -3889,7 +3890,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .collect::>>()?, )) } else { - let name = sm.span_to_snippet(arg.pat.span).ok()?; + let name = sm.span_to_snippet(param.pat.span).ok()?; Some(ArgKind::Arg(name, "_".to_owned())) } }) @@ -3909,9 +3910,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { sig.decl .inputs .iter() - .map(|arg| match arg.kind { + .map(|param| match param.ty.kind { hir::TyKind::Tup(tys) => ArgKind::Tuple( - Some(arg.span), + Some(param.ty.span), vec![("_".to_owned(), "_".to_owned()); tys.len()], ), _ => ArgKind::empty(), diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 1a661270a5d5d..91c029858c5ef 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -862,8 +862,9 @@ fn attempt_dyn_to_impl_suggestion(tcx: TyCtxt<'_>, hir_id: Option, e // This ensures that we don't suggest converting e.g. // `type Alias = Box;` to // `type Alias = Box;` - let Some((_id, first_non_type_parent_node)) = - tcx.hir_parent_iter(hir_id).find(|(_id, node)| !matches!(node, hir::Node::Ty(_))) + let Some((_id, first_non_type_parent_node)) = tcx + .hir_parent_iter(hir_id) + .find(|(_id, node)| !matches!(node, hir::Node::Ty(_) | hir::Node::Param(_))) else { return; }; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 1724db1966038..31e973c486531 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -180,7 +180,7 @@ pub fn suggest_restriction<'tcx>( let mut ty_spans = vec![]; for input in fn_sig.decl.inputs { ReplaceImplTraitVisitor { ty_spans: &mut ty_spans, param_did: param.def_id } - .visit_ty_unambig(input); + .visit_ty_unambig(input.ty); } // The type param `T: Trait` we will suggest to introduce. let type_param = format!("{type_param_name}: {bound_str}"); @@ -2313,11 +2313,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// Suggest removing `&` from a function parameter type like `&impl Future`. fn suggest_remove_ref_from_param(&self, param: &hir::Param<'_>, err: &mut Diag<'_>) -> bool { - if let Some(decl) = self.tcx.parent_hir_node(param.hir_id).fn_decl() - && let Some(input_ty) = decl.inputs.iter().find(|t| param.ty_span.contains(t.span)) - && let hir::TyKind::Ref(_, ty, _) = input_ty.kind - { - let ref_span = input_ty.span.until(ty.span); + if let hir::TyKind::Ref(_, ty, _) = param.ty.kind { + let ref_span = param.ty.span.until(ty.span); match self.tcx.sess.source_map().span_to_snippet(ref_span) { Ok(snippet) if snippet.starts_with("&") => { err.span_suggestion_verbose( @@ -4247,17 +4244,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { types always have a known size"; if let Some(hir_id) = hir_id && let hir::Node::Param(param) = self.tcx.hir_node(hir_id) - && let Some(decl) = self.tcx.parent_hir_node(hir_id).fn_decl() - && let Some(t) = decl.inputs.iter().find(|t| param.ty_span.contains(t.span)) { - // We use `contains` because the type might be surrounded by parentheses, - // which makes `ty_span` and `t.span` disagree with each other, but one - // fully contains the other: `foo: (dyn Foo + Bar)` - // ^-------------^ - // || - // |t.span - // param._ty_span - ty = Some(t); + ty = Some(param.ty); } else if let Some(hir_id) = hir_id && let hir::Node::Ty(t) = self.tcx.hir_node(hir_id) { @@ -4277,13 +4265,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let needs_parens = traits.len() != 1; // Don't recommend impl Trait as a closure argument if let Some(hir_id) = hir_id - && matches!( + && (matches!( self.tcx.parent_hir_node(hir_id), hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { .. }, .. }) - ) + ) || matches!( + self.tcx.parent_hir_node(hir_id), + // If this is the `ty` of a `Param`, get the item which is the parent of the `Param` + hir::Node::Param(_) + ) && matches!( + self.tcx.parent_hir_node(self.tcx.parent_hir_id(hir_id)), + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn { .. }, + .. + }) + )) { err.span_suggestion_verbose( span, @@ -6834,7 +6832,7 @@ fn hint_missing_borrow<'tcx>( let mut to_borrow = Vec::new(); let mut remove_borrow = Vec::new(); - for ((found_arg, expected_arg), arg) in found_args.zip(expected_args).zip(args) { + for ((found_arg, expected_arg), param) in found_args.zip(expected_args).zip(args) { let (found_ty, found_refs) = get_deref_type_and_refs(*found_arg); let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg); @@ -6844,7 +6842,7 @@ fn hint_missing_borrow<'tcx>( && found_refs[..] == expected_refs[expected_refs.len() - found_refs.len()..] { to_borrow.push(( - arg.span.shrink_to_lo(), + param.ty.span.shrink_to_lo(), expected_refs[..expected_refs.len() - found_refs.len()] .iter() .map(|mutbl| format!("&{}", mutbl.prefix_str())) @@ -6852,9 +6850,9 @@ fn hint_missing_borrow<'tcx>( .join(""), )); } else if found_refs.len() > expected_refs.len() { - let mut span = arg.span.shrink_to_lo(); + let mut span = param.ty.span.shrink_to_lo(); let mut left = found_refs.len() - expected_refs.len(); - let mut ty = arg; + let mut ty = param.ty; while let hir::TyKind::Ref(_, inner_ty, _) = &ty.kind && left > 0 { diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 38bfeb04fbce4..8065fbd75c36a 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -483,7 +483,7 @@ fn virtual_call_violations_for_method<'tcx>( .. })) = tcx.hir_get_if_local(method.def_id).as_ref() { - Some(sig.decl.inputs[i].span) + Some(sig.decl.inputs[i].ty.span) } else { None }; @@ -525,7 +525,7 @@ fn virtual_call_violations_for_method<'tcx>( })) = tcx.hir_get_if_local(method.def_id).as_ref() { // If we have `self: &'a Ty`, get `'a`, so that we can suggest `&'a self`. - let lt = match sig.decl.inputs[0].kind { + let lt = match sig.decl.inputs[0].ty.kind { hir::TyKind::Ref(lt, ..) if lt.ident.name == kw::UnderscoreLifetime => { sym::empty } @@ -535,16 +535,15 @@ fn virtual_call_violations_for_method<'tcx>( // Get the `Span` for all of `self: Ty`, not just `Ty`. match trait_fn { hir::TraitFn::Required([Some(name), ..]) - if name.span.ctxt() == sig.decl.inputs[0].span.ctxt() => + if name.span.ctxt() == sig.decl.inputs[0].ty.span.ctxt() => { - Some(name.span.to(sig.decl.inputs[0].span)) + Some(name.span.to(sig.decl.inputs[0].ty.span)) } - hir::TraitFn::Provided(body_id) - if let body = tcx.hir_body(*body_id) - && let Some(p) = body.params.get(0) - && p.span.ctxt() == p.ty_span.ctxt() => + hir::TraitFn::Provided(_body_id) + if let Some(p) = sig.decl.inputs.get(0) + && p.param_span.ctxt() == p.ty_span.ctxt() => { - Some(p.span.to(p.ty_span)) + Some(p.param_span.to(p.ty_span)) } _ => None, } diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 88d08aa355407..2076720591d40 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -162,7 +162,11 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' fn fn_sig_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator { let node = tcx.hir_node_by_def_id(def_id); if let Some(decl) = node.fn_decl() { - decl.inputs.iter().map(|ty| ty.span).chain(iter::once(decl.output.span())) + decl.inputs + .iter() + .filter(|param| !matches!(param.ty.kind, hir::TyKind::CVarArgs)) + .map(|param| param.ty.span) + .chain(iter::once(decl.output.span())) } else { bug!("unexpected item for fn {def_id:?}: {node:?}") } diff --git a/compiler/rustc_ty_walk/src/lib.rs b/compiler/rustc_ty_walk/src/lib.rs index 06c1fc8c27c07..aad9d5e0f9871 100644 --- a/compiler/rustc_ty_walk/src/lib.rs +++ b/compiler/rustc_ty_walk/src/lib.rs @@ -56,7 +56,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( // Walk over the inputs and outputs manually in order to get good spans for them. try_visit!(visitor.visit(hir_sig.output.span(), ty_sig.output())); for (hir, ty) in hir_sig.inputs.iter().zip(ty_sig.inputs().iter()) { - try_visit!(visitor.visit(hir.span, ty.map_bound(|x| *x))); + try_visit!(visitor.visit(hir.ty.span, ty.map_bound(|x| *x))); } for (clause, span) in tcx.explicit_clauses_of(item).instantiate_identity(tcx) { try_visit!(visitor.visit(span, clause.skip_norm_wip())); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b8e9d8a3f4633..c6fae82f3dec2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1090,7 +1090,6 @@ fn clean_fn_or_proc_macro<'tcx>( item: &hir::Item<'tcx>, sig: &hir::FnSig<'tcx>, generics: &hir::Generics<'tcx>, - body_id: hir::BodyId, name: &mut Symbol, cx: &mut DocContext<'tcx>, ) -> ItemKind { @@ -1108,13 +1107,8 @@ fn clean_fn_or_proc_macro<'tcx>( match macro_kind { Some(kind) => clean_proc_macro(item, name, kind, cx.tcx), None => { - let (generics, decl) = clean_function( - cx, - sig, - generics, - ParamsSrc::Body(body_id), - item.owner_id.to_def_id(), - ); + let (generics, decl) = + clean_function(cx, sig, generics, ParamsSrc::Body, item.owner_id.to_def_id()); let mut func = Function { generics, decl }; clean_fn_decl_legacy_const_generics(&mut func, attrs); ItemKind::Function(Box::new(func)) @@ -1145,7 +1139,7 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[rustc_attr_ } enum ParamsSrc<'tcx> { - Body(hir::BodyId), + Body, Idents(&'tcx [Option]), } @@ -1170,7 +1164,7 @@ fn clean_function<'tcx>( clean_poly_fn_sig(cx, Some(def_id), sig) } else { let params = match params { - ParamsSrc::Body(body_id) => clean_params_via_body(cx, sig.decl, body_id), + ParamsSrc::Body => clean_params_via_body(cx, sig.decl), // Let's not perpetuate anon params from Rust 2015; use `_` for them. ParamsSrc::Idents(idents) => clean_params(cx, sig.decl, idents, |ident| { Some(ident.map_or(kw::Underscore, |ident| ident.name)) @@ -1190,10 +1184,11 @@ fn clean_params<'tcx>( ) -> Vec { decl.inputs .iter() + .filter(|param| !matches!(param.ty.kind, hir::TyKind::CVarArgs)) .enumerate() - .map(|(i, ty)| Parameter { + .map(|(i, param)| Parameter { name: postprocess(idents[i]), - type_: clean_ty(ty, cx), + type_: clean_ty(param.ty, cx), is_const: false, is_splat: decl.splatted().is_some_and(|j| j as usize == i), }) @@ -1203,15 +1198,13 @@ fn clean_params<'tcx>( fn clean_params_via_body<'tcx>( cx: &mut DocContext<'tcx>, decl: &hir::FnDecl<'tcx>, - body_id: hir::BodyId, ) -> Vec { decl.inputs .iter() - .zip(cx.tcx.hir_body(body_id).params) .enumerate() - .map(|(i, (ty, param))| Parameter { + .map(|(i, param)| Parameter { name: Some(name_from_pat(param.pat)), - type_: clean_ty(ty, cx), + type_: clean_ty(param.ty, cx), is_const: false, is_splat: decl.splatted().is_some_and(|j| j as usize == i), }) @@ -1310,8 +1303,8 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext } hir::TraitItemKind::Fn(ref sig, body) => { let (params, body) = match body { - hir::TraitFn::Provided(body) => ( - ParamsSrc::Body(body), + hir::TraitFn::Provided(_) => ( + ParamsSrc::Body, Some(Defaultness::from_trait_item(trait_item.defaultness)), ), hir::TraitFn::Required(idents) => (ParamsSrc::Idents(idents), None), @@ -1354,9 +1347,9 @@ pub(crate) fn clean_impl_item<'tcx>( body: Some(clean_const_item_rhs(expr, local_did)), })) } - hir::ImplItemKind::Fn(ref sig, body) => { + hir::ImplItemKind::Fn(ref sig, _) => { let (generics, decl) = - clean_function(cx, sig, impl_.generics, ParamsSrc::Body(body), local_did); + clean_function(cx, sig, impl_.generics, ParamsSrc::Body, local_did); ItemKind::AssocFunction(Box::new(AssocFunction { generics, decl, @@ -1955,6 +1948,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'_>, cx: &mut DocContext<'tcx>) -> Typ // FIXME(scrabsha): propagate view types to `rustdoc`. clean_ty(ty, cx) } + TyKind::CVarArgs => unreachable!("Var args should be filtered out before reaching this"), // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s. TyKind::Infer(()) | TyKind::Err(_) @@ -2993,8 +2987,8 @@ fn clean_maybe_renamed_item<'tcx>( ), }, // proc macros can have a name set by attributes - hir::ItemKind::Fn { ref sig, generics, body: body_id, .. } => { - clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) + hir::ItemKind::Fn { ref sig, generics, .. } => { + clean_fn_or_proc_macro(item, sig, generics, &mut name, cx) } hir::ItemKind::Trait { generics, bounds, items: item_ids, .. } => { let items = item_ids diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index b2c21377a0a3f..73c1ee71c670f 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -453,10 +453,11 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio }, ExprKind::Closure(closure) => { let body = cx.tcx.hir_body(closure.body); - let params = body - .params + let params = closure + .fn_decl + .inputs .iter() - .map(|param| param.span.get_text(cx).map(|t| t.to_string())) + .map(|param| param.param_span.get_text(cx).map(|t| t.to_string())) .collect::>>()? .join(", "); let negated = simplify_not(cx, curr_msrv, body.value)?; diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs index 099100bf9d1f6..a7ca1f01ac72f 100644 --- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs +++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs @@ -118,7 +118,8 @@ fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirI let is_read_in_closure_arg = args.iter().any(|arg| { if let ExprKind::Closure(closure) = arg.kind // To keep things simple, we only check the first param to see if its read. - && let Body { params: [param, ..], value } = cx.tcx.hir_body(closure.body) + && let [param, ..] = closure.fn_decl.inputs + && let Body { value } = cx.tcx.hir_body(closure.body) { !has_no_read_access(cx, param.hir_id, *value) } else { diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index d61a39b02172a..8929f4f83e114 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -907,6 +907,7 @@ impl TyCoercionStability { Self::for_hir_ty(ty) }, TyKind::UnsafeBinder(..) => Self::None, + TyKind::CVarArgs => unreachable!(), // Removed before type checking }; } } diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 63c7855f5f4b1..0c4e7975a7bd9 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { &mut self, cx: &LateContext<'tcx>, fn_kind: intravisit::FnKind<'tcx>, - _: &'tcx FnDecl<'_>, + decl: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, _: Span, fn_def_id: LocalDefId, @@ -106,8 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { // Seed the set with the `Box` parameters that could be unboxed. The `ExprUseVisitor` walk // below then removes any that escape by being moved or borrowed. - let set: HirIdSet = body - .params + let set: HirIdSet = decl + .inputs .iter() .filter_map(|param| { // Only simple bindings (`x: Box<_>`) bind a local that the walk can track and report. @@ -140,7 +140,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { let mut v = EscapeDelegate { set }; ExprUseVisitor::for_clippy(cx, fn_def_id, &mut v) - .consume_body(body) + .consume_body(decl, body) .into_ok(); for node in v.set { diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index 6ebca6342b24e..964165ca0640a 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -88,18 +88,18 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { #[expect(clippy::too_many_lines)] fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx>>, expr: &Expr<'tcx>) { - let body = if let ExprKind::Closure(c) = expr.kind - && c.fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer(()))) + let (hir_closure, body) = if let ExprKind::Closure(c) = expr.kind + && c.fn_decl.inputs.iter().all(|param| matches!(param.ty.kind, TyKind::Infer(()))) && matches!(c.fn_decl.output, FnRetTy::DefaultReturn(_)) && !expr.span.from_expansion() { - cx.tcx.hir_body(c.body) + (c, cx.tcx.hir_body(c.body)) } else { return; }; if body.value.span.from_expansion() { - if body.params.is_empty() + if hir_closure.fn_decl.inputs.is_empty() && let Some(VecArgs::Vec(&[])) = VecArgs::hir(cx, body.value) { let vec_crate = if is_no_std_crate(cx) { "alloc" } else { "std" }; @@ -145,7 +145,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx let callee_ty_raw = typeck.expr_ty(callee); let callee_ty = callee_ty_raw.peel_refs(); if matches!(callee_ty.opt_diag_name(cx), Some(sym::Arc | sym::Rc)) - || !check_inputs(typeck, body.params, None, args) + || !check_inputs(typeck, hir_closure.fn_decl.inputs, None, args) { return; } @@ -262,7 +262,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx ); } }, - ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => { + ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, hir_closure.fn_decl.inputs, Some(self_), args) => { if let Some(method_def_id) = typeck.type_dependent_def_id(body.value.hir_id) && !find_attr!(cx.tcx, method_def_id, TrackCaller(..)) && check_sig(closure_sig, cx.tcx.fn_sig(method_def_id).skip_binder().skip_binder()) diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs index a64f9db2fd88c..5ea0c2dbf5e61 100644 --- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs +++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs @@ -131,7 +131,7 @@ fn has_n_bools<'tcx>(iter: impl Iterator>, mut count: u64) } fn check_fn_decl(cx: &LateContext<'_>, decl: &FnDecl<'_>, sp: Span, max: u64) { - if has_n_bools(decl.inputs.iter(), max) && !sp.from_expansion() { + if has_n_bools(decl.inputs.iter().map(|p| p.ty), max) && !sp.from_expansion() { span_lint_and_help( cx, FN_PARAMS_EXCESSIVE_BOOLS, diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs index 38661ebf5eb83..b9204b813d087 100644 --- a/src/tools/clippy/clippy_lints/src/format_impl.rs +++ b/src/tools/clippy/clippy_lints/src/format_impl.rs @@ -256,7 +256,7 @@ impl FormatImplExpr<'_, '_> { fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Option { if impl_item.ident.name == sym::fmt - && let ImplItemKind::Fn(_, body_id) = impl_item.kind + && let ImplItemKind::Fn(sig, _) = impl_item.kind && let Some(Impl { of_trait: Some(of_trait), .. @@ -265,9 +265,9 @@ fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Optio && let Some(name) = cx.tcx.get_diagnostic_name(did) && matches!(name, sym::Debug | sym::Display) { - let body = cx.tcx.hir_body(body_id); - let formatter_name = body - .params + let formatter_name = sig + .decl + .inputs .get(1) .and_then(|param| param.pat.simple_ident()) .map(|ident| ident.name); diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs index ed936e7f14aec..00c02bc6db93e 100644 --- a/src/tools/clippy/clippy_lints/src/from_over_into.rs +++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs @@ -193,8 +193,7 @@ fn convert_to_from( let ImplItemKind::Fn(ref sig, body_id) = impl_item.kind else { return None; }; - let body = cx.tcx.hir_body(body_id); - let [self_param] = body.params else { return None }; + let [self_param] = sig.decl.inputs else { return None }; let PatKind::Binding(.., self_ident, None) = self_param.pat.kind else { return None; }; @@ -232,6 +231,7 @@ fn convert_to_from( lower: Vec::new(), }; + let body = cx.tcx.hir_body(body_id); if finder.visit_expr(body.value).is_break() { return None; } diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index 0ac33f56317f7..fb9f556e45bd2 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -244,7 +244,7 @@ fn check_must_use_candidate<'tcx>( item_id: hir::OwnerId, msg: &'static str, ) { - if has_mutable_arg(cx, body) + if has_mutable_arg(cx, decl) || mutates_static(cx, body) || returns_unit(decl) || !cx.effective_visibilities.is_exported(item_id.def_id) @@ -281,9 +281,9 @@ fn returns_unit(decl: &hir::FnDecl<'_>) -> bool { } } -fn has_mutable_arg(cx: &LateContext<'_>, body: &hir::Body<'_>) -> bool { +fn has_mutable_arg(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>,) -> bool { let mut tys = DefIdSet::default(); - body.params.iter().any(|param| is_mutable_pat(cx, param.pat, &mut tys)) + decl.inputs.iter().any(|param| is_mutable_pat(cx, param.pat, &mut tys)) } fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index 7555a6719b6de..f1680f94ab17a 100644 --- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -44,7 +44,7 @@ fn check_raw_ptr<'tcx>( def_id: LocalDefId, ) { if safety.is_safe() && cx.effective_visibilities.is_exported(def_id) { - let raw_ptrs = iter_input_pats(decl, body) + let raw_ptrs = iter_input_pats(decl) .filter_map(|arg| raw_ptr_arg(cx, arg)) .collect::(); diff --git a/src/tools/clippy/clippy_lints/src/functions/ref_option.rs b/src/tools/clippy/clippy_lints/src/functions/ref_option.rs index 733f10b3506f8..2e17752f8985e 100644 --- a/src/tools/clippy/clippy_lints/src/functions/ref_option.rs +++ b/src/tools/clippy/clippy_lints/src/functions/ref_option.rs @@ -43,7 +43,7 @@ fn check_fn_sig<'a>(cx: &LateContext<'a>, decl: &FnDecl<'a>, span: Span, sig: ty let mut fixes = Vec::new(); // Check function arguments' types for (param, param_ty) in decl.inputs.iter().zip(sig.inputs()) { - check_ty(cx, param, *param_ty, &mut fixes); + check_ty(cx, param.ty, *param_ty, &mut fixes); } // Check return type if let hir::FnRetTy::Return(ty) = &decl.output { @@ -89,7 +89,7 @@ pub(crate) fn check_fn<'a>( span.with_hi(out_ty.span.hi()) } } else if let (Some(first), Some(last)) = (decl.inputs.first(), decl.inputs.last()) { - first.span.to(last.span) + first.ty.span.to(last.ty.span) } else { // No parameters - no point in checking return; diff --git a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs index 2d330835a037a..baa26e7a4d7a3 100644 --- a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs +++ b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs @@ -11,7 +11,7 @@ use super::RENAMED_FUNCTION_PARAMS; pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &ImplItem<'_>, ignored_traits: &DefIdSet) { if !item.span.from_expansion() - && let ImplItemKind::Fn(_, body_id) = item.kind + && let ImplItemKind::Fn(sig, _) = item.kind && let parent_node = cx.tcx.parent_hir_node(item.hir_id()) && let Node::Item(parent_item) = parent_node && let ItemKind::Impl(Impl { @@ -21,7 +21,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &ImplItem<'_>, ignored && let Some(did) = cx.tcx.trait_item_of(item.owner_id) && !is_from_ignored_trait(&of_trait.trait_ref, ignored_traits) { - let mut param_idents_iter = cx.tcx.hir_body_param_idents(body_id); + let mut param_idents_iter = cx.tcx.hir_body_param_idents(sig.decl); let mut default_param_idents_iter = cx.tcx.fn_arg_idents(did).iter().copied(); let renames = RenamedFnArgs::new(&mut default_param_idents_iter, &mut param_idents_iter); diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index fb365fa15418a..7c1db13914035 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -155,9 +155,9 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { } => { let body = cx.tcx.hir_body(body_id); - for ty in sig.decl.inputs { + for param in sig.decl.inputs { let mut vis = ImplicitHasherTypeVisitor::new(cx); - vis.visit_ty_unambig(ty); + vis.visit_ty_unambig(param.ty); for target in &vis.found { if generics.span.from_expansion() { @@ -165,7 +165,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { } let generics_suggestion_span = generics.span.substitute_dummy({ let range = - (item.span.lo()..body.params[0].pat.span.lo()).map_range(cx, |_, src, range| { + (item.span.lo()..sig.decl.inputs[0].pat.span.lo()).map_range(cx, |_, src, range| { let (pre, post) = src.get(range.clone())?.split_once("fn")?; let pos = post.find('(')? + pre.len() + 2; Some(pos..pos) diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 214e68c612cea..5bb73e4cc5048 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -313,7 +313,7 @@ fn could_use_elision<'tcx>( // extract lifetimes in input argument types for arg in func.inputs { - input_visitor.visit_ty_unambig(arg); + input_visitor.visit_ty_unambig(arg.ty); } // extract lifetimes in output type if let Return(ty) = func.output { @@ -337,14 +337,13 @@ fn could_use_elision<'tcx>( } if let Some(body_id) = body { - let body = cx.tcx.hir_body(body_id); - - let first_ident = body.params.first().and_then(|param| param.pat.simple_ident()); + let first_ident = func.inputs.first().and_then(|param| param.pat.simple_ident()); if non_elidable_self_type(cx, func, first_ident, msrv) { return None; } let mut checker = BodyLifetimeChecker::new(cx); + let body = cx.tcx.hir_body(body_id); if checker.visit_expr(body.value).is_break() { return None; } @@ -418,11 +417,11 @@ fn non_elidable_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ide if let Some(ident) = ident && ident.name == kw::SelfLower && !func.implicit_self().has_implicit_self() - && let Some(self_ty) = func.inputs.first() + && let Some(self_param) = func.inputs.first() && !msrv.meets(cx, msrvs::EXPLICIT_SELF_TYPE_ELISION) { let mut visitor = RefVisitor::new(cx); - visitor.visit_ty_unambig(self_ty); + visitor.visit_ty_unambig(self_param.ty); !visitor.all_lts().is_empty() } else { @@ -706,7 +705,7 @@ fn is_candidate_for_elision(fd: &FnDecl<'_>) -> bool { // The first encountered input lifetime will either be one on `self`, or will be the only lifetime. fd.inputs .iter() - .find_map(|ty| walk_unambig_ty(&mut V, ty).break_value()) + .find_map(|param| walk_unambig_ty(&mut V, param.ty).break_value()) .unwrap() } else { false diff --git a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs index 3d46991d1c224..3ecf3245f4cfa 100644 --- a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs +++ b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs @@ -64,22 +64,21 @@ pub(super) fn check_method<'tcx>( arg: &'tcx Expr<'tcx>, closure: &'tcx Closure<'tcx>, ) { - let body = cx.tcx.hir_body(closure.body); - if let [param] = body.params - && let [input] = closure.fn_decl.inputs + if let [param] = closure.fn_decl.inputs && !arg.span.from_expansion() - && !input.span.from_expansion() + && !param.ty.span.from_expansion() && !recv.span.from_expansion() - && !param.span.from_expansion() + && !param.param_span.from_expansion() { - let ty_spans = if let TyKind::Tup([_, inner]) = input.kind { + let ty_spans = if let TyKind::Tup([_, inner]) = param.ty.kind { let Some(inner) = walk_span_to_context(inner.span, SyntaxContext::root()) else { return; }; - Some((input.span, inner)) + Some((param.ty.span, inner)) } else { None }; + let body = cx.tcx.hir_body(closure.body); check(cx, recv, param.pat, ty_spans, body.value); } } diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs index bd84fe48708d3..7451706fcfe5c 100644 --- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs +++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs @@ -132,9 +132,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { fn get_ty_sugg<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'_>) -> Option<(Span, Ty<'tcx>)> { let local_hid = arg.res_local_id()?; - if let Node::Param(Param { ty_span, span, .. }) = cx.tcx.parent_hir_node(local_hid) + if let Node::Param(Param { ty_span, param_span, .. }) = cx.tcx.parent_hir_node(local_hid) // `ty_span` and `span` are the same for inferred type, thus a type suggestion must be given - && ty_span == span + && ty_span == param_span { let arg_type = cx.typeck_results().expr_ty(arg); return Some((*ty_span, arg_type)); diff --git a/src/tools/clippy/clippy_lints/src/manual_pop_if.rs b/src/tools/clippy/clippy_lints/src/manual_pop_if.rs index afafe25f8ffd0..625ef763bc7af 100644 --- a/src/tools/clippy/clippy_lints/src/manual_pop_if.rs +++ b/src/tools/clippy/clippy_lints/src/manual_pop_if.rs @@ -210,12 +210,12 @@ fn check_is_some_and_pattern<'tcx>( && check_path.ident.name == peek_method && kind.is_diag_item(cx, collection_expr) && let ExprKind::Closure(closure) = closure_arg.kind - && let body = cx.tcx.hir_body(closure.body) && let Some((pop_collection, pop_span, suggestable)) = check_pop_unwrap(cx, then_block, pop_method) && eq_expr_value(cx, if_expr_span.ctxt(), collection_expr, pop_collection) - && let Some(param) = body.params.first() + && let Some(param) = closure.fn_decl.inputs.first() && let Some(ident) = param.pat.simple_ident() { + let body = cx.tcx.hir_body(closure.body); return Some(ManualPopIfPattern { kind, collection_expr, @@ -373,7 +373,7 @@ fn check_map_unwrap_or_pattern<'tcx>( && cx.typeck_results().expr_ty(body.value).is_bool() && let Some((pop_collection, pop_span, suggestable)) = check_pop_unwrap(cx, then_block, pop_method) && eq_expr_value(cx, if_expr_span.ctxt(), collection_expr, pop_collection) - && let Some(param) = body.params.first() + && let Some(param) = closure.fn_decl.inputs.first() && let Some(ident) = param.pat.simple_ident() { return Some(ManualPopIfPattern { diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs index d00d91be2fbde..47e4d9a200b26 100644 --- a/src/tools/clippy/clippy_lints/src/manual_retain.rs +++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs @@ -89,7 +89,7 @@ fn check_into_iter( && let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = target_expr.kind && let hir::ExprKind::Closure(closure) = closure_expr.kind && let filter_body = cx.tcx.hir_body(closure.body) - && let [filter_params] = filter_body.params + && let [filter_params] = closure.fn_decl.inputs { if match_map_type(cx, left_expr) { if let hir::PatKind::Tuple([key_pat, value_pat], _) = filter_params.pat.kind @@ -136,7 +136,7 @@ fn check_iter( && let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = filter_expr.kind && let hir::ExprKind::Closure(closure) = closure_expr.kind && let filter_body = cx.tcx.hir_body(closure.body) - && let [filter_params] = filter_body.params + && let [filter_params] = closure.fn_decl.inputs { match filter_params.pat.kind { // hir::PatKind::Binding(_, _, _, None) => { @@ -194,7 +194,7 @@ fn check_to_owned( && let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = filter_expr.kind && let hir::ExprKind::Closure(closure) = closure_expr.kind && let filter_body = cx.tcx.hir_body(closure.body) - && let [filter_params] = filter_body.params + && let [filter_params] = closure.fn_decl.inputs && msrv.meets(cx, msrvs::STRING_RETAIN) && let hir::PatKind::Ref(pat, _, _) = filter_params.pat.kind { diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index 9187cb6fc98c2..78c294b323574 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -161,16 +161,16 @@ fn reduce_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option< } } -fn unit_closure<'tcx>( - cx: &LateContext<'tcx>, - expr: &hir::Expr<'_>, -) -> Option<(&'tcx hir::Param<'tcx>, &'tcx hir::Expr<'tcx>)> { +fn unit_closure<'a, 'b>( + cx: &LateContext<'a>, + expr: &hir::Expr<'b>, +) -> Option<(&'b hir::Param<'b>, &'a hir::Expr<'a>)> { if let hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) = expr.kind && let body = cx.tcx.hir_body(body) && let body_expr = &body.value && fn_decl.inputs.len() == 1 && is_unit_expression(cx, body_expr) - && let Some(binding) = iter_input_pats(fn_decl, body).next() + && let Some(binding) = iter_input_pats(fn_decl).next() { return Some((binding, body_expr)); } diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs index e5a89230781b6..b4a5c89301c4d 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs @@ -108,7 +108,7 @@ pub(crate) fn check_and_then_method<'tcx>( && let ExprKind::Closure(closure) = arg.kind && let body = cx.tcx.hir_body(closure.body) && let Some(fn_arg_span) = closure.fn_arg_span - && let [param] = body.params + && let [param] = closure.fn_decl.inputs && let expr_span_ctxt = expr.span.ctxt() && let Some(some_expr) = get_cond_expr(cx, param.pat, body.value, expr_span_ctxt) { diff --git a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs index 555f86ad7b5ab..c4251bec783b4 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs @@ -222,7 +222,7 @@ impl<'tcx> Visitor<'tcx> for VarBindingVisitor<'_, 'tcx> { ExprKind::Closure(closure) => { let body = self.cx.tcx.hir_body(closure.body); let before = self.identifiers.clone(); - for param in body.params { + for param in closure.fn_decl.inputs { param.pat.each_binding(|_, _, _, ident| { self.identifiers.remove(&ident.name); }); diff --git a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs index 2a81abac4896a..61efb0cbd2456 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs @@ -16,9 +16,9 @@ pub(super) fn check<'tcx>( filter_recv: &'tcx Expr<'_>, filter_arg: &'tcx Expr<'_>, ) { - if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind + if let ExprKind::Closure(&Closure { fn_decl, body, .. }) = filter_arg.kind && let body = cx.tcx.hir_body(body) - && let [param] = body.params + && let [param] = fn_decl.inputs && let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind && let ExprKind::Binary(ref op, l, r) = body.value.kind && op.node == BinOpKind::Eq diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs index f42b73fce6bdc..0545ab5b9b318 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -21,7 +21,7 @@ fn is_method(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol) -> bool ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name, ExprKind::Path(QPath::Resolved(_, segments)) => segments.segments.last().unwrap().ident.name == method_name, ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name, - ExprKind::Closure(Closure { body, .. }) => { + ExprKind::Closure(Closure { fn_decl, body, .. }) => { let body = cx.tcx.hir_body(*body); let closure_expr = peel_blocks(body.value); match closure_expr.kind { @@ -29,9 +29,9 @@ fn is_method(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol) -> bool if ident.name == method_name && let ExprKind::Path(path) = &receiver.kind && let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id) - && !body.params.is_empty() + && !fn_decl.inputs.is_empty() { - let arg_id = body.params[0].pat.hir_id; + let arg_id = fn_decl.inputs[0].pat.hir_id; return arg_id == *local; } false @@ -407,9 +407,9 @@ fn is_find_or_filter<'a>( ) -> Option<(Ident, CheckResult<'a>)> { if cx.ty_based_def(map_recv).opt_parent(cx).is_diag_item(cx, sym::Iterator) // filter(|x| ...is_some())... - && let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind + && let ExprKind::Closure(&Closure { fn_decl, body: filter_body_id, .. }) = filter_arg.kind && let filter_body = cx.tcx.hir_body(filter_body_id) - && let [filter_param] = filter_body.params + && let [filter_param] = fn_decl.inputs // optional ref pattern: `filter(|&x| ..)` && let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _, _) = filter_param.pat.kind { (ref_pat, true) @@ -420,9 +420,9 @@ fn is_find_or_filter<'a>( && let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind && let Some(offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id) - && let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind + && let ExprKind::Closure(&Closure { fn_decl, body: map_body_id, .. }) = map_arg.kind && let map_body = cx.tcx.hir_body(map_body_id) - && let [map_param] = map_body.params + && let [map_param] = fn_decl.inputs && let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind && let Some(check_result) = diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs index 00c7ca82d10dd..e021c581c26e5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs @@ -13,20 +13,19 @@ use rustc_middle::ty::Binder; use rustc_middle::ty::adjustment::Adjust; use rustc_span::Span; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &'tcx Expr<'tcx>, call_span: Span) { if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator) && let ExprKind::Closure(closure) = arg.kind && let body = cx.tcx.hir_body(closure.body) && let value = peel_blocks(body.value) // Indexing should be fine as `filter_map` always has 1 input, we unfortunately need both // `inputs` and `params` here as we need both the type and the span - && let param_ty = closure.fn_decl.inputs[0] - && let param = body.params[0] + && let param = closure.fn_decl.inputs[0] // Issue #11309 && let param_ty = cx.tcx.liberate_late_bound_regions( closure.def_id.to_def_id(), Binder::bind_with_vars( - cx.typeck_results().node_type(param_ty.hir_id), + cx.typeck_results().node_type(param.ty.hir_id), cx.tcx.late_bound_vars(cx.tcx.local_def_id_to_hir_id(closure.def_id)), ), ) @@ -43,7 +42,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & .iter() .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) .count() - && let Some(param_snippet) = param.span.get_text(cx) + && let Some(param_snippet) = param.param_span.get_text(cx) { let mut applicability = Applicability::MachineApplicable; let (filter, _) = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut applicability); diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs index 1f5b48a6f78f2..e8b8a3b757641 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs @@ -94,10 +94,10 @@ fn is_method( } false }, - ExprKind::Closure(&hir::Closure { body, .. }) => { + ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) => { let body = cx.tcx.hir_body(body); let closure_expr = peel_blocks(body.value); - let params = body.params.iter().map(|param| param.pat).collect::>(); + let params = fn_decl.inputs.iter().map(|param| param.pat).collect::>(); is_method(cx, closure_expr, type_symbol, method_name, params.as_slice()) }, _ => false, diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs index f8a8277d82d71..a2173e0f08520 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs @@ -28,8 +28,8 @@ pub(super) fn check<'tcx>( } if !expr.span.from_expansion() && let ExprKind::Closure(c) = m_arg.kind + && let [p] = c.fn_decl.inputs && let Body { - params: [p], value: body_expr, } = cx.tcx.hir_body(c.body) && let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs index 241791e57c8e6..12a51310ed92c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -5,7 +5,7 @@ use clippy_utils::visitors::for_each_expr_without_closures; use core::ops::ControlFlow; use rustc_ast::BindingMode; use rustc_errors::Applicability; -use rustc_hir::{Body, CaptureBy, Closure, Expr, ExprKind, HirId, HirIdSet, Param, PatKind}; +use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, HirId, HirIdSet, Param, PatKind}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use rustc_lint::LateContext; use rustc_middle::mir::{FakeReadCause, Mutability}; @@ -63,9 +63,10 @@ pub(super) fn check<'tcx>( let ExprKind::Closure(closure) = expr.kind else { return; }; - let body @ Body { params: [p], .. } = cx.tcx.hir_body(closure.body) else { + let [p] = closure.fn_decl.inputs else { return; }; + let body = cx.tcx.hir_body(closure.body); if param_captured_by_move_block(cx, body.value, p) { return; @@ -76,7 +77,7 @@ pub(super) fn check<'tcx>( }; ExprUseVisitor::for_clippy(cx, closure.def_id, &mut delegate) - .consume_body(body) + .consume_body(closure.fn_decl, body) .into_ok(); let mut to_be_discarded = false; diff --git a/src/tools/clippy/clippy_lints/src/methods/lines_filter_map_ok.rs b/src/tools/clippy/clippy_lints/src/methods/lines_filter_map_ok.rs index 607979719f894..fdbe95d753520 100644 --- a/src/tools/clippy/clippy_lints/src/methods/lines_filter_map_ok.rs +++ b/src/tools/clippy/clippy_lints/src/methods/lines_filter_map_ok.rs @@ -3,7 +3,7 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::{MaybeDef as _, MaybeResPath as _, MaybeTypeckRes as _}; use clippy_utils::sym; use rustc_errors::Applicability; -use rustc_hir::{Body, Closure, Expr, ExprKind}; +use rustc_hir::{Closure, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_span::Span; @@ -41,15 +41,14 @@ pub(super) fn check_filter_or_flat_map( .qpath_res(qpath, method_arg.hir_id) .is_diag_item(cx, sym::result_ok_method), // Detect `|x| x.ok()` - ExprKind::Closure(&Closure { body, .. }) => { - if let Body { - params: [param], value, .. - } = cx.tcx.hir_body(body) + ExprKind::Closure(&Closure { fn_decl, body, .. }) => { + let value = cx.tcx.hir_body(body).value; + if let [param] = fn_decl.inputs && let ExprKind::MethodCall(method, receiver, [], _) = value.kind { method.ident.name == sym::ok && receiver.res_local_id() == Some(param.pat.hir_id) - && cx.ty_based_def(*value).is_diag_item(cx, sym::result_ok_method) + && cx.ty_based_def(value).is_diag_item(cx, sym::result_ok_method) } else { false } diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_contains.rs b/src/tools/clippy/clippy_lints/src/methods/manual_contains.rs index 58453a3c08774..58681b944326c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_contains.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_contains.rs @@ -7,7 +7,7 @@ use clippy_utils::usage::local_used_in; use rustc_ast::UnOp; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::{BinOpKind, Body, Expr, ExprKind, HirId, QPath}; +use rustc_hir::{BinOpKind, Expr, ExprKind, HirId, QPath}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::Spanned; @@ -20,8 +20,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, clos if !expr.span.from_expansion() // check if `iter().any()` can be replaced with `contains()` && let ExprKind::Closure(closure) = closure_arg.kind - && let Body{params: [param],value} = cx.tcx.hir_body(closure.body) - && let ExprKind::Binary(op, lhs, rhs) = value.kind + && let [param] = closure.fn_decl.inputs + && let ExprKind::Binary(op, lhs, rhs) = cx.tcx.hir_body(closure.body).value.kind && let (peeled_ref_pat, _) = peel_hir_pat_refs(param.pat) && let Some((snip,snip_expr)) = can_replace_with_contains(cx, op, lhs, rhs, peeled_ref_pat.hir_id, &mut app) && let ref_type = cx.typeck_results().expr_ty_adjusted(recv) diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs index 82ee862eb602a..048ba21c2086f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs @@ -26,7 +26,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: || fn_def.opt_parent(cx).opt_impl_ty(cx).is_diag_item(cx, sym::Result)) && msrv.meets(cx, msrvs::OPTION_RESULT_INSPECT))) && let body = cx.tcx.hir_body(c.body) - && let [param] = body.params + && let [param] = c.fn_decl.inputs && let PatKind::Binding(BindingMode(ByRef::No, Mutability::Not), arg_id, _, None) = param.pat.kind && let arg_ty = typeck.node_type(arg_id) && let ExprKind::Block(block, _) = body.value.kind @@ -167,7 +167,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: && !is_potentially_mutated(arg_id, body.value, cx) { if requires_deref { - edits.push((param.span.shrink_to_lo(), "&".into())); + edits.push((param.param_span.shrink_to_lo(), "&".into())); } else { edits.extend(addr_of_edits); } diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs index 5b6506b853b5f..ac8a4044a80fc 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs @@ -56,7 +56,7 @@ fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { }, ExprKind::Closure(closure) => { let body = cx.tcx.hir_body(closure.body); - if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind + if let PatKind::Binding(_, param_id, ..) = closure.fn_decl.inputs[0].pat.kind && let ExprKind::Call(callee, [ok_arg]) = body.value.kind && callee.res(cx).ctor_parent(cx).is_lang_item(cx, ResultOk) { diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_option_zip.rs b/src/tools/clippy/clippy_lints/src/methods/manual_option_zip.rs index e168beddf57b6..82e3b13e9c05e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_option_zip.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_option_zip.rs @@ -22,8 +22,9 @@ pub(super) fn check<'tcx>( ) { // Looking for: `a.and_then(|a| b.map(|b| (a, b)))`. // `and_then(|a| ...)` - if let ExprKind::Closure(&hir::Closure { body: outer_body_id, .. }) = arg.kind - && let hir::Body { params: [outer_param], value: outer_value, .. } = cx.tcx.hir_body(outer_body_id) + if let ExprKind::Closure(&hir::Closure { fn_decl: outer_fn_decl, body: outer_body_id, .. }) = arg.kind + && let [outer_param] = outer_fn_decl.inputs + && let outer_value = cx.tcx.hir_body(outer_body_id).value && let PatKind::Binding(_, outer_param_id, _, None) = outer_param.pat.kind && cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Option) // `b.map(|b| ...)` @@ -35,8 +36,9 @@ pub(super) fn check<'tcx>( // `b` does not reference the outer closure parameter `a`. && !local_used_in(cx, outer_param_id, map_recv) // `|b| (a, b)` - && let ExprKind::Closure(&hir::Closure { body: inner_body_id, .. }) = map_arg.kind - && let hir::Body { params: [inner_param], value: inner_value, .. } = cx.tcx.hir_body(inner_body_id) + && let ExprKind::Closure(&hir::Closure { fn_decl: inner_fn_decl, body: inner_body_id, .. }) = map_arg.kind + && let [inner_param] = inner_fn_decl.inputs + && let inner_value = cx.tcx.hir_body(inner_body_id).value && let PatKind::Binding(_, inner_param_id, _, None) = inner_param.pat.kind // `(a, b)` or `(b, a)` — tuple of outer and inner param in either order. && let ExprKind::Tup([first, second]) = peel_blocks(inner_value).kind diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs index 072f56b897014..51c765e18235f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs @@ -47,10 +47,10 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_ && should_run_lint(cx, e, parent_id) { match arg.kind { - hir::ExprKind::Closure(&hir::Closure { body, .. }) => { + hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) => { let closure_body = cx.tcx.hir_body(body); let closure_expr = peel_blocks(closure_body.value); - match closure_body.params[0].pat.kind { + match fn_decl.inputs[0].pat.kind { hir::PatKind::Ref(inner, Pinnedness::Not, Mutability::Not) => { if let hir::PatKind::Binding(hir::BindingMode::NONE, .., name, None) = inner.kind && ident_eq(name, closure_expr) diff --git a/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs index 9868d1a60d0a8..fa756b97f5a87 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeDef as _; -use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind}; +use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind, FnDecl}; use rustc_lint::LateContext; use rustc_span::sym; @@ -17,12 +17,10 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, arg: &Expr<'_>) { .is_diag_item(cx, sym::Result) && let ExprKind::Closure(&Closure { capture_clause: CaptureBy::Ref, - body, + fn_decl: FnDecl { inputs: [param], .. }, fn_decl_span, .. }) = arg.kind - && let closure_body = cx.tcx.hir_body(body) - && let [param] = closure_body.params && let PatKind::Wild = param.pat.kind { // span the area of the closure capture and warn that the diff --git a/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs b/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs index aca065bbc65a5..866337a47602e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs @@ -8,7 +8,7 @@ use rustc_ast::LitKind; use rustc_ast::ast::RangeLimits; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; -use rustc_hir::{Body, Closure, Expr, ExprKind}; +use rustc_hir::{Body, Closure, Expr, ExprKind, FnDecl}; use rustc_lint::LateContext; use rustc_span::{Span, SyntaxContext}; @@ -68,13 +68,12 @@ pub(super) fn check( ) { let mut applicability = Applicability::MaybeIncorrect; if let Some(range) = higher::Range::hir(cx, receiver) - && let ExprKind::Closure(Closure { body, .. }) = arg.kind + && let ExprKind::Closure(Closure { fn_decl: decl@FnDecl { inputs: [param], .. }, body, .. }) = arg.kind && let body_hir = cx.tcx.hir_body(*body) && let Body { - params: [param], value: body_expr, } = body_hir - && !usage::BindingUsageFinder::are_params_used(cx, body_hir) + && !usage::BindingUsageFinder::are_params_used(cx, decl, body_hir) && let ctxt = ex.span.ctxt() && let Some(count) = extract_count_with_applicability(cx, range, &mut applicability, ctxt) && let Some(exec_context) = std_or_core(cx) @@ -88,7 +87,7 @@ pub(super) fn check( ("repeat", (arg.span, body_snippet.to_string()), true) } } else if msrv.meets(cx, msrvs::REPEAT_WITH) { - ("repeat_with", (param.span, String::new()), true) + ("repeat_with", (param.param_span, String::new()), true) } else { return; }; diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index b4796c6da0a83..fea54ebb5dd90 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -5368,7 +5368,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { return; } - if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind { + if let hir::ImplItemKind::Fn(ref sig, _id) = impl_item.kind { let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id; let item = cx.tcx.hir_expect_item(parent); let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity().skip_norm_wip(); @@ -5382,7 +5382,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if sig.decl.implicit_self().has_implicit_self() && !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id)) - && let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir_body(id)).next() + && let Some(first_arg) = iter_input_pats(sig.decl).next() && let Some(first_arg_ty) = first_arg_ty_opt { wrong_self_convention::check( @@ -5405,7 +5405,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { && !item.span.in_external_macro(cx.tcx.sess.source_map()) { if sig.decl.implicit_self().has_implicit_self() - && let Some(first_arg_hir_ty) = sig.decl.inputs.first() + && let Some(first_arg_hir) = sig.decl.inputs.first() && let Some(&first_arg_ty) = cx .tcx .fn_sig(item.owner_id) @@ -5421,7 +5421,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { item.ident.name, self_ty, first_arg_ty, - first_arg_hir_ty.span, + first_arg_hir.ty.span, false, true, ); @@ -5490,7 +5490,7 @@ impl Methods { Some((sym::chars, recv, _, _, _)) if let ExprKind::Closure(arg) = arg.kind && let body = cx.tcx.hir_body(arg.body) - && let [param] = body.params => + && let [param] = arg.fn_decl.inputs => { string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), self.msrv); }, diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs index aac4a344f5f99..e3792cf50a45c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs @@ -1,6 +1,6 @@ use clippy_utils::res::{MaybeDef as _, MaybeQPath as _, MaybeResPath as _}; use rustc_errors::Applicability; -use rustc_hir::{Closure, Expr, ExprKind, HirId, StmtKind, UnOp}; +use rustc_hir::{Closure, Expr, ExprKind, HirId, StmtKind, UnOp, FnDecl}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::Span; @@ -96,9 +96,8 @@ fn handle_expr( } pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>, is_all: bool) { - if let ExprKind::Closure(&Closure { body, .. }) = closure_arg.kind + if let ExprKind::Closure(&Closure { fn_decl: FnDecl { inputs: [first_param], .. }, body, .. }) = closure_arg.kind && let body = cx.tcx.hir_body(body) - && let Some(first_param) = body.params.first() && let ExprKind::MethodCall(method, mut recv, [], _) = recv.kind && method.ident.name == sym::chars && let str_ty = cx.typeck_results().expr_ty_adjusted(recv).peel_refs() diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs index 31f294ff27d37..bf5f7ba2c9e9b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs @@ -45,13 +45,13 @@ pub(super) fn check( .is_some_and(|fun_name| { matches!(fun_name, sym::deref_method | sym::deref_mut_method) || deref_aliases.contains(&fun_name) }), - hir::ExprKind::Closure(&hir::Closure { body, .. }) => { + hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) => { let closure_body = cx.tcx.hir_body(body); let closure_expr = peel_blocks(closure_body.value); match &closure_expr.kind { hir::ExprKind::MethodCall(_, receiver, [], _) => { - if receiver.res_local_id() == Some(closure_body.params[0].pat.hir_id) + if receiver.res_local_id() == Some(fn_decl.inputs[0].pat.hir_id) && let adj = cx .typeck_results() .expr_adjustments(receiver) @@ -75,7 +75,7 @@ pub(super) fn check( if let hir::ExprKind::Unary(hir::UnOp::Deref, inner1) = inner.kind && let hir::ExprKind::Unary(hir::UnOp::Deref, inner2) = inner1.kind { - inner2.res_local_id() == Some(closure_body.params[0].pat.hir_id) + inner2.res_local_id() == Some(fn_decl.inputs[0].pat.hir_id) } else { false } diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs index bf9c89e43de01..a01c58c5a1f05 100644 --- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs @@ -317,10 +317,10 @@ fn check_or_fn_call<'tcx>( } fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool { - if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind { + if let hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) = e.kind { let body = cx.tcx.hir_body(body); - if body.params.is_empty() + if fn_decl.inputs.is_empty() && let hir::Expr { kind, .. } = &body.value && let hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, self_arg, [], _) = kind && ident.name == sym::to_string diff --git a/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs index d779a00da4a52..994f04435f3cb 100644 --- a/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs +++ b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs @@ -103,8 +103,7 @@ fn methods_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option | sym::try_for_each ) && let ExprKind::Closure(closure) = arg.kind - && let body = cx.tcx.hir_body(closure.body) - && let [param] = body.params + && let [param] = closure.fn_decl.inputs { Some(param.pat) } else { diff --git a/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs b/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs index 09c26bcdf2847..79db2fb18f4e9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs +++ b/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs @@ -47,7 +47,7 @@ pub(super) fn check<'tcx>( let closure_expr = peel_blocks(cx.tcx.hir_body(body).value); let mut applicability = Applicability::MachineApplicable; - let arg_snip = snippet_with_applicability(cx, closure_arg.span, "_", &mut applicability); + let arg_snip = snippet_with_applicability(cx, closure_arg.ty.span, "_", &mut applicability); let recv_snip = snippet_with_applicability(cx, recv.span, "_", &mut applicability); let body_snip = snippet_with_applicability(cx, closure_expr.span, "..", &mut applicability); let inner = match body_snip.strip_prefix('{').and_then(|s| s.strip_suffix('}')) { diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs index 7c7211e971c8a..983a992b87fb5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs @@ -39,9 +39,8 @@ pub(super) fn check<'tcx>( // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()` let mut applicability = Applicability::MachineApplicable; let any_search_snippet = if search_method == sym::find - && let ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind - && let closure_body = cx.tcx.hir_body(body) - && let Some(closure_arg) = closure_body.params.first() + && let ExprKind::Closure(&hir::Closure { fn_decl, .. }) = search_arg.kind + && let Some(closure_arg) = fn_decl.inputs.first() { if let PatKind::Ref(..) = closure_arg.pat.kind { Some(search_snippet.replacen('&', "", 1)) diff --git a/src/tools/clippy/clippy_lints/src/methods/some_filter.rs b/src/tools/clippy/clippy_lints/src/methods/some_filter.rs index f3db0fa165af3..b468195890c81 100644 --- a/src/tools/clippy/clippy_lints/src/methods/some_filter.rs +++ b/src/tools/clippy/clippy_lints/src/methods/some_filter.rs @@ -18,10 +18,8 @@ pub(super) fn check<'tcx>( ) { let (condition, value) = if let Some(value) = as_some_expr(cx, recv) && let ExprKind::Closure(c) = arg.kind - && let Body { - params: [p], - value: condition, - } = cx.tcx.hir_body(c.body) + && let [p] = c.fn_decl.inputs + && let Body { value: condition } = cx.tcx.hir_body(c.body) && pat_is_wild(cx, &p.pat.kind, arg) && msrv.meets(cx, msrvs::BOOL_THEN_SOME) { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs index 31f21492dfedd..31f09cdd93fe5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -24,11 +24,11 @@ pub(super) fn check<'tcx>( return; } - if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind { + if let hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) = arg.kind { let body = cx.tcx.hir_body(body); - let arg_id = body.params[0].pat.hir_id; + let arg_id = fn_decl.inputs[0].pat.hir_id; let mutates_arg = mutated_variables(body.value, cx).is_none_or(|used_mutably| used_mutably.contains(&arg_id)); - let (clone_or_copy_needed, _) = clone_or_copy_needed(cx, body.params[0].pat, body.value); + let (clone_or_copy_needed, _) = clone_or_copy_needed(cx, fn_decl.inputs[0].pat, body.value); let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, body.value); @@ -42,7 +42,7 @@ pub(super) fn check<'tcx>( ControlFlow::Continue(Descend::Yes) } }); - let in_ty = cx.typeck_results().node_type(body.params[0].hir_id); + let in_ty = cx.typeck_results().node_type(fn_decl.inputs[0].hir_id); let sugg = if !found_filtering { // Check if the closure is .filter_map(|x| Some(x)) if kind.is_filter_map() diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs index c7207bb4dd4bc..aedf84c471b5c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs @@ -123,7 +123,7 @@ fn check_fold_with_op( op: hir::BinOpKind, replacement: Replacement, ) -> bool { - if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind + if let hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) = acc.kind // Extract the body of the closure passed to fold && let closure_body = cx.tcx.hir_body(body) && let closure_expr = peel_blocks(closure_body.value) @@ -133,7 +133,7 @@ fn check_fold_with_op( && bin_op.node == op // Extract the names of the two arguments to the closure - && let [param_a, param_b] = closure_body.params + && let [param_a, param_b] = fn_decl.inputs && let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(param_a.pat).kind && let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(param_b.pat).kind @@ -333,9 +333,9 @@ fn check_option_fold<'tcx>( _ => return, } && cx.typeck_results().expr_ty(option_expr).is_diag_item(cx, sym::Option) - && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind + && let hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) = acc.kind && let closure_body = cx.tcx.hir_body(body) - && let [param_acc, param_item] = closure_body.params + && let [param_acc, param_item] = fn_decl.inputs // The suggestion rewrites source spans, so bail out when any part // comes from a different syntax context. && recv.span.ctxt() == ctxt diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 99b650e1ebfbb..997907ecd39b1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>( let body = cx.tcx.hir_body(body); let body_expr = &body.value; - if usage::BindingUsageFinder::are_params_used(cx, body) || is_from_proc_macro(cx, expr) { + if usage::BindingUsageFinder::are_params_used(cx, fn_decl, body) || is_from_proc_macro(cx, expr) { return false; } @@ -49,8 +49,8 @@ pub(super) fn check<'tcx>( }; let mut applicability = Applicability::MachineApplicable; - if body - .params + if fn_decl + .inputs .iter() // bindings are checked to be unused above .any(|param| !matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild)) @@ -132,14 +132,14 @@ pub(super) fn check_map_or_else<'tcx>( }) = def_arg.kind && let body = cx.tcx.hir_body(body) && let body_expr = body.value - && !usage::BindingUsageFinder::are_params_used(cx, body) + && !usage::BindingUsageFinder::are_params_used(cx, fn_decl, body) && eager_or_lazy::switch_to_eager_eval(cx, body_expr) && !is_from_proc_macro(cx, expr) && !is_from_proc_macro(cx, map_arg) && !is_from_proc_macro(cx, body_expr) { - let mut applicability = if body - .params + let mut applicability = if fn_decl + .inputs .iter() .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild)) && matches!( @@ -153,7 +153,7 @@ pub(super) fn check_map_or_else<'tcx>( && fn_decl .inputs .iter() - .all(|ty| matches!(ty.kind, hir::TyKind::Infer(()))) + .all(|param| matches!(param.ty.kind, hir::TyKind::Infer(()))) { Applicability::MachineApplicable } else { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs index 1c519d50785eb..bc0946a89bebd 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs @@ -50,10 +50,10 @@ fn closure_bool_constant(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option let ExprKind::Closure(closure) = expr.kind else { return None; }; - let body = cx.tcx.hir_body(closure.body); - let [_] = body.params else { + let [_] = closure.fn_decl.inputs else { return None; }; + let body = cx.tcx.hir_body(closure.body); bool_constant(cx, body.value) } @@ -158,7 +158,7 @@ pub(super) fn check<'tcx>( && let closure_body = cx.tcx.hir_body(map_closure.body) && let closure_body_value = closure_body.value.peel_blocks() && let ExprKind::Binary(op, l, r) = closure_body_value.kind - && let [param] = closure_body.params + && let [param] = map_closure.fn_decl.inputs && let PatKind::Binding(_, hir_id, _, _) = param.pat.kind // checking that map_or is one of the following: // .map_or(false, |x| x == y) diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs index 48333cd2d85f3..dbbaeee13835b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -249,9 +249,9 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>) -> Option< .instantiate_identity() .skip_norm_wip() .is_slice() - && let ExprKind::Closure(&Closure { body, .. }) = arg.kind + && let ExprKind::Closure(&Closure { fn_decl, body, .. }) = arg.kind && let closure_body = cx.tcx.hir_body(body) - && let &[Param { pat: l_pat, .. }, Param { pat: r_pat, .. }] = closure_body.params + && let &[Param { pat: l_pat, .. }, Param { pat: r_pat, .. }] = fn_decl.inputs && let Some(binding_map) = mapping_of_mirrored_pats(l_pat, r_pat) && let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind && method_path.ident.name == sym::cmp diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_unwrap_unchecked.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_unwrap_unchecked.rs index af7fd4d7bce14..c02218a5684aa 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_unwrap_unchecked.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_unwrap_unchecked.rs @@ -5,7 +5,7 @@ use clippy_utils::{is_from_proc_macro, last_path_segment, over}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Namespace, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::{Body, Expr, ExprKind, PatKind, Safety}; +use rustc_hir::{Expr, ExprKind, PatKind, Safety, FnDecl}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; use rustc_span::Span; @@ -134,14 +134,14 @@ fn same_functions_modulo_safety<'tcx>( unchecked_def_id: DefId, unwrapped_ret_ty: Ty<'tcx>, ) -> bool { - let hir_body = |def_id: DefId| -> Option<&'tcx Body<'tcx>> { cx.tcx.hir_maybe_body_owned_by(def_id.as_local()?) }; + let hir_decl = |def_id: DefId| -> Option<&'tcx FnDecl<'tcx>> { cx.tcx.hir_fn_decl_by_hir_id(cx.tcx.local_def_id_to_hir_id(def_id.as_local()?)) }; let fn_sig = |def_id| cx.tcx.fn_sig(def_id).skip_binder().skip_binder(); - if match (hir_body(checked_def_id), hir_body(unchecked_def_id)) { + if match (hir_decl(checked_def_id), hir_decl(unchecked_def_id)) { // For local functions, we can get the parameter names. In that case, we want to make sure // that the latter are equal between the checked and unchecked versions. - (Some(checked_body), Some(unchecked_body)) => { - over(checked_body.params, unchecked_body.params, |p1, p2| { + (Some(checked_decl), Some(unchecked_decl)) => { + over(checked_decl.inputs, unchecked_decl.inputs, |p1, p2| { // We only allow simple params (plain bindings) for now, to stay on the safer side. if let PatKind::Binding(bm1, _, ident1, None) = p1.pat.kind && let PatKind::Binding(bm2, _, ident2, None) = p2.pat.kind diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs index 057bb3a3a538d..e08fa259365fa 100644 --- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs @@ -146,13 +146,12 @@ fn check_qpath(cx: &LateContext<'_>, qpath: hir::QPath<'_>, hir_id: hir::HirId) fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { match arg.kind { - hir::ExprKind::Closure(&hir::Closure { body, .. }) + hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) // If it's a closure, we need to check what is called. - if let closure_body = cx.tcx.hir_body(body) - && let [param] = closure_body.params + if let [param] = fn_decl.inputs && let hir::PatKind::Binding(_, local_id, ..) = strip_pat_refs(param.pat).kind => { - let closure_expr = peel_blocks(closure_body.value); + let closure_expr = peel_blocks(cx.tcx.hir_body(body).value); match closure_expr.kind { hir::ExprKind::MethodCall(method, obj, [], _) => { if method.ident.name == sym::clone diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs index ee546528020ac..6f5d7bc11a023 100644 --- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs +++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs @@ -173,15 +173,6 @@ impl LateLintPass<'_> for MinIdentChars { if self.min_chars_threshold == 0 { return; } - if let TraitItemKind::Fn(_, TraitFn::Required(idents)) = i.kind { - for &ident in idents { - if let Some(ident) = ident - && let Some(missing) = self.check_sym(ident.name) - { - self.emit(cx, ident, missing); - } - } - } if let Some(missing) = self.check_sym(i.ident.name) && !(matches!(i.kind, TraitItemKind::Fn(_, TraitFn::Provided(_))) && cx.tcx.codegen_fn_attrs(i.owner_id.def_id).contains_extern_indicator()) @@ -200,10 +191,10 @@ impl LateLintPass<'_> for MinIdentChars { trait_item_def_id: Ok(trait_item), .. } = i.impl_kind - && let ImplItemKind::Fn(_, body) = i.kind + && let ImplItemKind::Fn(sig, _) = i.kind { let mut named_params_count = 0; - for (trait_ident, param) in iter::zip(cx.tcx.fn_arg_idents(trait_item), cx.tcx.hir_body(body).params) { + for (trait_ident, param) in iter::zip(cx.tcx.fn_arg_idents(trait_item), sig.decl.inputs) { if let PatKind::Binding(_, _, ident, _) = param.pat.kind { named_params_count += 1; if trait_ident.is_none_or(|trait_ident| ident.name != trait_ident.name || self.lint_trait_impl) diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs index 7e413f8b6a35b..c20cf5775ebe4 100644 --- a/src/tools/clippy/clippy_lints/src/mut_key.rs +++ b/src/tools/clippy/clippy_lints/src/mut_key.rs @@ -110,8 +110,8 @@ impl<'tcx> MutableKeyType<'tcx> { fn check_sig(&mut self, cx: &LateContext<'tcx>, fn_def_id: LocalDefId, decl: &hir::FnDecl<'tcx>) { let fn_sig = cx.tcx.fn_sig(fn_def_id).instantiate_identity().skip_norm_wip(); - for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) { - self.check_ty_(cx, hir_ty.span, *ty); + for (hir_param, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) { + self.check_ty_(cx, hir_param.ty.span, *ty); } self.check_ty_( cx, diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs index 13a3c99274d5f..4ace73b37dee5 100644 --- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs @@ -95,7 +95,7 @@ fn check_expr(cx: &LateContext<'_>, expr: &Expr<'_>, outer_span: Span) { if fn_decl .inputs .iter() - .any(|input| matches!(input.kind, TyKind::Infer(..))) + .any(|input| matches!(input.ty.kind, TyKind::Infer(..))) { applicability = Applicability::MaybeIncorrect; } @@ -121,7 +121,7 @@ fn check_expr(cx: &LateContext<'_>, expr: &Expr<'_>, outer_span: Span) { ) }; - let body_param_sugg = snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability); + let body_param_sugg = snippet_with_applicability(cx, fn_decl.inputs[0].pat.span, "..", &mut applicability); let for_each_rev_sugg = snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability); let (body_value_sugg, is_macro_call) = snippet_with_context(cx, body.value.span, for_each_recv.span.ctxt(), "..", &mut applicability); diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs index b2c7d56d792dc..0195924fa2f0e 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -68,22 +68,21 @@ impl NeedlessPassByRefMut<'_> { fn should_skip<'tcx>( cx: &LateContext<'tcx>, - input: rustc_hir::Ty<'tcx>, + input: &rustc_hir::Param<'tcx>, ty: Ty<'_>, - arg: &rustc_hir::Param<'_>, ) -> bool { // We check if this a `&mut`. `ref_mutability` returns `None` if it's not a reference. if !matches!(ty.ref_mutability(), Some(Mutability::Mut)) { return true; } - if is_self(arg) { + if is_self(input) { // Interestingly enough, `self` arguments make `is_from_proc_macro` return `true`, hence why // we return early here. return false; } - if let PatKind::Binding(.., name, _) = arg.pat.kind + if let PatKind::Binding(.., name, _) = input.pat.kind // If it's a potentially unused variable, we don't check it. && (name.name == kw::Underscore || name.as_str().starts_with('_')) { @@ -91,7 +90,7 @@ fn should_skip<'tcx>( } // All spans generated from a proc-macro invocation are the same... - is_from_proc_macro(cx, &input) + is_from_proc_macro(cx, input.ty) } fn check_closures<'tcx>( @@ -100,20 +99,18 @@ fn check_closures<'tcx>( checked_closures: &mut FxHashSet, closures: FxIndexSet, ) { - for closure in closures { - if !checked_closures.insert(closure) { + for id in closures { + if !checked_closures.insert(id) { continue; } ctx.prev_bind = None; ctx.prev_move_to_closure.clear(); - if let Some(body) = cx + if let Node::Expr(Expr { kind: ExprKind::Closure(closure), .. }) = cx .tcx - .hir_node_by_def_id(closure) - .associated_body() - .map(|(_, body_id)| cx.tcx.hir_body(body_id)) + .hir_node_by_def_id(id) { - euv::ExprUseVisitor::for_clippy(cx, closure, &mut *ctx) - .consume_body(body) + euv::ExprUseVisitor::for_clippy(cx, id, &mut *ctx) + .consume_body(closure.fn_decl, cx.tcx.hir_body(closure.body)) .into_ok(); } } @@ -178,8 +175,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { .inputs .iter() .zip(fn_sig.inputs()) - .zip(body.params) - .filter(|&((&input, &ty), arg)| !should_skip(cx, input, ty, arg)) + .filter(|&(input, &ty)| !should_skip(cx, &input, ty)) .peekable(); if it.peek().is_none() { return; @@ -196,7 +192,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { tcx: cx.tcx, }; euv::ExprUseVisitor::for_clippy(cx, fn_def_id, &mut ctx) - .consume_body(body) + .consume_body(decl, body) .into_ok(); let mut checked_closures = FxHashSet::default(); @@ -221,15 +217,15 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { } ctx.generate_mutably_used_ids_from_aliases() }; - for ((&input, &_), arg) in it { + for (input, &_) in it { // Only take `&mut` arguments. - if let PatKind::Binding(_, canonical_id, ..) = arg.pat.kind + if let PatKind::Binding(_, canonical_id, ..) = input.pat.kind && !mutably_used_vars.contains(&canonical_id) { self.fn_def_ids_to_maybe_unused_mut .entry(fn_def_id) .or_default() - .push(input); + .push(*input.ty); } } } diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 7669a844fe518..e0ead61655a10 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -142,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { let MovedVariablesCtxt { moved_vars } = { let mut ctx = MovedVariablesCtxt::default(); euv::ExprUseVisitor::for_clippy(cx, fn_def_id, &mut ctx) - .consume_body(body) + .consume_body(decl, body) .into_ok(); ctx }; @@ -150,14 +150,14 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { let fn_sig = cx.tcx.fn_sig(fn_def_id).instantiate_identity().skip_norm_wip(); let fn_sig = cx.tcx.liberate_late_bound_regions(fn_def_id.to_def_id(), fn_sig); - for (idx, ((input, &ty), arg)) in decl.inputs.iter().zip(fn_sig.inputs()).zip(body.params).enumerate() { + for (idx, (input, &ty)) in decl.inputs.iter().zip(fn_sig.inputs()).enumerate() { // All spans generated from a proc-macro invocation are the same... - if span == input.span { + if span == input.ty.span { return; } // Ignore `self`s and params whose variable name starts with an underscore - if let PatKind::Binding(.., ident, _) = arg.pat.kind { + if let PatKind::Binding(.., ident, _) = input.pat.kind { if idx == 0 && ident.name == kw::SelfLower { continue; } @@ -185,7 +185,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { ) }; - if !is_self(arg) + if !is_self(input) && !ty.is_mutable_ptr() && !is_copy(cx, ty) && ty.is_sized(cx.tcx, cx.typing_env()) @@ -201,7 +201,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { }) && !implements_borrow_trait && !all_borrowable_trait - && let PatKind::Binding(BindingMode(_, Mutability::Not), canonical_id, ..) = arg.pat.kind + && let PatKind::Binding(BindingMode(_, Mutability::Not), canonical_id, ..) = input.pat.kind && !moved_vars.contains(&canonical_id) { // Dereference suggestion @@ -221,8 +221,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } if ty.is_diag_item(cx, sym::Vec) - && let Some(clone_spans) = get_spans(cx, body, idx, &[(sym::clone, ".to_owned()")]) - && let TyKind::Path(QPath::Resolved(_, path)) = input.kind + && let Some(clone_spans) = get_spans(cx, decl, body, idx, &[(sym::clone, ".to_owned()")]) + && let TyKind::Path(QPath::Resolved(_, path)) = input.ty.kind && let Some(elem_ty) = path .segments .iter() @@ -241,7 +241,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { { let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_")); diag.span_suggestion( - input.span, + input.ty.span, "consider changing the type to", slice_ty, Applicability::Unspecified, @@ -265,10 +265,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { if ty.is_lang_item(cx, LangItem::String) && let Some(clone_spans) = - get_spans(cx, body, idx, &[(sym::clone, ".to_string()"), (sym::as_str, "")]) + get_spans(cx, decl, body, idx, &[(sym::clone, ".to_string()"), (sym::as_str, "")]) { diag.span_suggestion( - input.span, + input.ty.span, "consider changing the type to", "&str", Applicability::Unspecified, @@ -290,7 +290,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } diag.span_suggestion_verbose( - peel_hir_ty_options(cx, input).span.shrink_to_lo(), + peel_hir_ty_options(cx, input.ty).span.shrink_to_lo(), "consider taking a reference instead", '&', Applicability::MaybeIncorrect, @@ -300,8 +300,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { span_lint_hir_and_then( cx, NEEDLESS_PASS_BY_VALUE, - arg.hir_id, - input.span, + input.ty.hir_id, + input.ty.span, "this argument is passed by value, but not consumed in the function body", sugg, ); @@ -339,11 +339,12 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt { fn get_spans<'tcx>( cx: &LateContext<'tcx>, + decl: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, idx: usize, replacements: &[(Symbol, &'static str)], ) -> Option)>> { - if let PatKind::Binding(_, binding_id, _, _) = strip_pat_refs(body.params[idx].pat).kind { + if let PatKind::Binding(_, binding_id, _, _) = strip_pat_refs(decl.inputs[idx].pat).kind { extract_clone_suggestions(cx, binding_id, replacements, body) } else { Some(vec![]) diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs index 32cf04908911f..1e686c58d53a3 100644 --- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs +++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs @@ -6,7 +6,7 @@ use clippy_utils::{is_from_proc_macro, is_lint_allowed, last_path_segment, std_o use rustc_attr_ir::lang_items::LangItem; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; -use rustc_hir::{Block, Body, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Stmt, StmtKind, UnOp}; +use rustc_hir::{Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Stmt, StmtKind, UnOp, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext as _, impl_lint_pass}; use rustc_middle::ty::{TyCtxt, TypeckResults}; use rustc_span::sym; @@ -168,12 +168,12 @@ impl LateLintPass<'_> for NonCanonicalImpls { .iter() .map(|id| cx.tcx.hir_impl_item(*id)) .filter_map(|assoc| { - if let ImplItemKind::Fn(_, body_id) = assoc.kind + if let ImplItemKind::Fn(sig, body_id) = assoc.kind && let body = cx.tcx.hir_body(body_id) && let ExprKind::Block(block, ..) = body.value.kind && !block.span.in_external_macro(cx.sess().source_map()) { - Some((assoc, body, block)) + Some((assoc, sig.decl, body, block)) } else { None } @@ -186,7 +186,7 @@ impl LateLintPass<'_> for NonCanonicalImpls { if let Some(copy_trait) = self.copy_trait && implements_trait(cx, trait_impl.self_ty(), copy_trait, &[]) { - for (assoc, body, _) in assoc_fns { + for (assoc, _, body, _) in assoc_fns { check_clone_on_copy(cx, assoc, body.value); } } @@ -198,10 +198,10 @@ impl LateLintPass<'_> for NonCanonicalImpls { && lhs == rhs && let Some(ord_trait) = self.ord_trait && implements_trait(cx, trait_impl.self_ty(), ord_trait, &[]) - && let Some((assoc, body, block)) = - assoc_fns.find(|(assoc, _, _)| assoc.ident.name == sym::partial_cmp) + && let Some((assoc, decl, _, block)) = + assoc_fns.find(|(assoc, _, _, _)| assoc.ident.name == sym::partial_cmp) { - check_partial_ord_on_ord(cx, assoc, item, body, block); + check_partial_ord_on_ord(cx, assoc, item, decl, block); } }, } @@ -292,7 +292,7 @@ fn check_partial_ord_on_ord<'tcx>( cx: &LateContext<'tcx>, impl_item: &ImplItem<'_>, item: &Item<'_>, - body: &Body<'_>, + decl: &FnDecl<'_>, block: &Block<'tcx>, ) { // If the `cmp` call likely needs to be fully qualified in the suggestion @@ -326,7 +326,7 @@ fn check_partial_ord_on_ord<'tcx>( item.span, "non-canonical implementation of `partial_cmp` on an `Ord` type", |diag| { - let [_, other] = body.params else { + let [_, other] = decl.inputs else { return; }; let Some(std_or_core) = std_or_core(cx) else { diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs index 167944cb21c68..3f4004a7fdb56 100644 --- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{ Body, Expr, ExprKind, HirId, HirIdMap, ImplItem, ImplItemImplKind, ImplItemKind, Node, PatKind, TraitItem, - TraitItemKind, + TraitItemKind, Item, ItemKind, }; use rustc_lint::{LateContext, LateLintPass, impl_lint_pass}; use rustc_middle::ty::{self, ConstKind, GenericArgKind, GenericArgs}; @@ -311,8 +311,8 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { } // `skip_params` is either `0` or `1` to skip the `self` parameter in trait functions. // It can't be renamed, and it can't be removed without removing it from multiple functions. - let (fn_id, fn_kind, skip_params) = match cx.tcx.parent_hir_node(body.value.hir_id) { - Node::Item(i) => (i.owner_id.to_def_id(), FnKind::Fn, 0), + let (fn_id, fn_kind, skip_params, decl) = match cx.tcx.parent_hir_node(body.value.hir_id) { + Node::Item(Item { owner_id, kind: ItemKind::Fn { sig, ..}, .. }) => (owner_id.to_def_id(), FnKind::Fn, 0, sig.decl), Node::TraitItem(&TraitItem { kind: TraitItemKind::Fn(ref sig, _), owner_id, @@ -321,6 +321,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { owner_id.to_def_id(), FnKind::TraitFn, usize::from(sig.decl.implicit_self().has_implicit_self()), + sig.decl ), Node::ImplItem(&ImplItem { kind: ImplItemKind::Fn(ref sig, _), @@ -341,14 +342,15 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { as usize, ), usize::from(sig.decl.implicit_self().has_implicit_self()), + sig.decl, ) } else { - (owner_id.to_def_id(), FnKind::Fn, 0) + (owner_id.to_def_id(), FnKind::Fn, 0, sig.decl) } }, _ => return, }; - body.params + decl.inputs .iter() .enumerate() .skip(skip_params) diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 883aeb4498298..b52026d1b04bb 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -131,7 +131,6 @@ impl PassByRefOrValue { } let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip(); - let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir_body(id)); // Gather all the lifetimes found in the output type which may affect whether // `TRIVIALLY_COPY_PASS_BY_REF` should be linted. @@ -149,7 +148,7 @@ impl PassByRefOrValue { { // All spans generated from a proc-macro invocation are the same... match span { - Some(s) if s == input.span => continue, + Some(s) if s == input.ty.span => continue, _ => (), } @@ -171,7 +170,7 @@ impl PassByRefOrValue { if is_copy(cx, ty) && let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes()) && size <= self.ref_min_size - && let hir::TyKind::Ref(_, decl_ty, ..) = input.kind + && let hir::TyKind::Ref(_, decl_ty, ..) = input.ty.kind { if let Some(typeck) = cx.typeck_results // Don't lint if a raw pointer is created. @@ -186,7 +185,7 @@ impl PassByRefOrValue { { continue; } - let value_type = if fn_body.and_then(|body| body.params.get(index)).is_some_and(is_self) { + let value_type = if decl.inputs.get(index).is_some_and(is_self) { "self".into() } else { snippet(cx, decl_ty.span, "_").into() @@ -194,7 +193,7 @@ impl PassByRefOrValue { span_lint_and_sugg( cx, TRIVIALLY_COPY_PASS_BY_REF, - input.span, + input.ty.span, format!( "this argument ({size} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", self.ref_min_size @@ -208,7 +207,7 @@ impl PassByRefOrValue { ty::Adt(_, _) | ty::Array(_, _) | ty::Tuple(_) => { // if function has a body and parameter is annotated with mut, ignore - if let Some(param) = fn_body.and_then(|body| body.params.get(index)) { + if let Some(param) = decl.inputs.get(index) { match param.pat.kind { PatKind::Binding(BindingMode::NONE, _, _, _) => {}, _ => continue, @@ -217,20 +216,20 @@ impl PassByRefOrValue { let ty = cx.tcx.instantiate_bound_regions_with_erased(ty); if is_copy(cx, ty) - && !is_self_ty(input) + && !is_self_ty(input.ty) && let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes()) && size > self.value_max_size { span_lint_and_sugg( cx, LARGE_TYPES_PASSED_BY_VALUE, - input.span, + input.ty.span, format!( "this argument ({size} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", self.value_max_size ), "consider passing by reference instead", - format!("&{}", snippet(cx, input.span, "_")), + format!("&{}", snippet(cx, input.ty.span, "_")), Applicability::MaybeIncorrect, ); } diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs index 84a3cd7816500..ac01ccacec405 100644 --- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs @@ -117,12 +117,12 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch { &mut self, cx: &LateContext<'tcx>, _: intravisit::FnKind<'tcx>, - _: &'tcx FnDecl<'_>, - body: &'tcx Body<'_>, + decl: &'tcx FnDecl<'_>, + _: &'tcx Body<'_>, _: Span, _: LocalDefId, ) { - for param in body.params { + for param in decl.inputs { apply_lint(cx, param.pat, DerefPossible::Impossible); } } diff --git a/src/tools/clippy/clippy_lints/src/ptr/mut_from_ref.rs b/src/tools/clippy/clippy_lints/src/ptr/mut_from_ref.rs index bc0fac8684cf1..c013cc092d1dd 100644 --- a/src/tools/clippy/clippy_lints/src/ptr/mut_from_ref.rs +++ b/src/tools/clippy/clippy_lints/src/ptr/mut_from_ref.rs @@ -20,7 +20,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Option< .decl .inputs .iter() - .flat_map(get_lifetimes) + .flat_map(|p| get_lifetimes(&p.ty)) .filter(|&(lt, _, _)| cx.tcx.named_bound_var(lt.hir_id) == out_region) .map(|(_, mutability, span)| (mutability == Some(Mutability::Not)).then_some(span)) .collect(); diff --git a/src/tools/clippy/clippy_lints/src/ptr/ptr_arg.rs b/src/tools/clippy/clippy_lints/src/ptr/ptr_arg.rs index 6c3189cc00c81..6f2ef24d850bf 100644 --- a/src/tools/clippy/clippy_lints/src/ptr/ptr_arg.rs +++ b/src/tools/clippy/clippy_lints/src/ptr/ptr_arg.rs @@ -9,7 +9,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{ self as hir, AnonConst, BindingMode, Body, Expr, ExprKind, FnSig, GenericArg, HirId, HirIdMap, Lifetime, - Mutability, Node, OwnerId, Param, PatKind, QPath, TyKind, + Mutability, Node, OwnerId, Param, PatKind, QPath, TyKind, FnDecl, }; use rustc_infer::infer::TyCtxtInferExt as _; use rustc_infer::traits::{Obligation, ObligationCause}; @@ -41,10 +41,10 @@ pub(super) fn check_body<'tcx>( .instantiate_identity() .skip_norm_wip() .skip_binder(); - let lint_args: Vec<_> = check_fn_args(cx, sig, decl.inputs, body.params) + let lint_args: Vec<_> = check_fn_args(cx, sig, decl.inputs) .filter(|arg| !is_trait_item || arg.mutability() == Mutability::Not) .collect(); - let results = check_ptr_arg_usage(cx, body, &lint_args); + let results = check_ptr_arg_usage(cx, decl, body, &lint_args); for (result, args) in iter::zip(&results, &lint_args).filter(|(r, _)| !r.skip) { span_lint_hir_and_then(cx, PTR_ARG, args.emission_id, args.span, args.build_msg(), |diag| { @@ -78,7 +78,6 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item_id: OwnerId, s .skip_norm_wip() .skip_binder(), sig.decl.inputs, - &[], ) .filter(|arg| arg.mutability() == Mutability::Not) { @@ -199,22 +198,21 @@ impl<'tcx> DerefTy<'tcx> { fn check_fn_args<'cx, 'tcx: 'cx>( cx: &'cx LateContext<'tcx>, fn_sig: ty::FnSig<'tcx>, - hir_tys: &'tcx [hir::Ty<'tcx>], params: &'tcx [Param<'tcx>], ) -> impl Iterator> + 'cx { - iter::zip(fn_sig.inputs(), hir_tys) + iter::zip(fn_sig.inputs(), params) .enumerate() - .filter_map(move |(i, (ty, hir_ty))| { + .filter_map(move |(i, (ty, param))| { if let ty::Ref(_, ty, mutability) = *ty.kind() && let ty::Adt(adt, args) = *ty.kind() - && let TyKind::Ref(lt, inner_ty, _) = hir_ty.kind + && let TyKind::Ref(lt, inner_ty, _) = param.ty.kind && let TyKind::Path(QPath::Resolved(None, path)) = inner_ty.kind // Check that the name as typed matches the actual name of the type. // e.g. `fn foo(_: &Foo)` shouldn't trigger the lint when `Foo` is an alias for `Vec` && let [.., name] = path.segments && cx.tcx.item_name(adt.did()) == name.ident.name { - let emission_id = params.get(i).map_or(hir_ty.hir_id, |param| param.hir_id); + let emission_id = params.get(i).map_or(param.ty.hir_id, |param| param.hir_id); let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) { Some(sym::Vec) => ( [(sym::clone, ".to_owned()")].as_slice(), @@ -272,11 +270,11 @@ fn check_fn_args<'cx, 'tcx: 'cx>( cx, PTR_ARG, emission_id, - hir_ty.span, + param.ty.span, "using a reference to `Cow` is not recommended", |diag| { diag.span_suggestion( - hir_ty.span, + param.ty.span, "change this to", match ty.span().get_text(cx) { Some(s) => format!("&{}{s}", mutability.prefix_str()), @@ -294,7 +292,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( return Some(PtrArg { idx: i, emission_id, - span: hir_ty.span, + span: param.ty.span, ty_name: name.ident.name, method_renames, ref_prefix: RefPrefix { lt: *lt, mutability }, @@ -306,7 +304,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( } #[expect(clippy::too_many_lines)] -fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, args: &[PtrArg<'tcx>]) -> Vec { +fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, decl: &FnDecl<'tcx>, body: &Body<'tcx>, args: &[PtrArg<'tcx>]) -> Vec { struct V<'cx, 'tcx> { cx: &'cx LateContext<'tcx>, /// Map from a local id to which argument it came from (index into `Self::args` and @@ -425,7 +423,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, args: &[ .iter() .enumerate() .filter_map(|(i, arg)| { - let param = &body.params[arg.idx]; + let param = &decl.inputs[arg.idx]; match param.pat.kind { PatKind::Binding(BindingMode::NONE, id, ident, None) if !is_lint_allowed(cx, PTR_ARG, param.hir_id) diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index 25c137dec7375..247b99c1fef9a 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir}; use clippy_utils::get_parent_expr; use clippy_utils::sugg::Sugg; -use hir::Param; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; @@ -87,7 +86,6 @@ fn find_innermost_closure<'tcx>( &'tcx hir::Expr<'tcx>, &'tcx hir::FnDecl<'tcx>, ty::Asyncness, - &'tcx [Param<'tcx>], CaptureBy, )> { let mut data = None; @@ -121,7 +119,6 @@ fn find_innermost_closure<'tcx>( unwrapped_body_value, closure.fn_decl, asyncness, - body.params, capture_clause, )); steps -= 1; @@ -181,10 +178,10 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { // We don't want to suggest replacing `x!()()` with `x!()`. && recv.span.ctxt().outer_expn() == expr.span.ctxt().outer_expn() && let (full_expr, call_depth) = get_parent_call_exprs(cx, expr) - && let Some((mut body, fn_decl, coroutine_kind, params, capture_clause)) = + && let Some((mut body, fn_decl, coroutine_kind, capture_clause)) = find_innermost_closure(cx, recv, call_depth) // outside macros we lint properly. Inside macros, we lint only ||() style closures. - && (!matches!(expr.span.ctxt().outer_expn_data().kind, ExpnKind::Macro(_, _)) || params.is_empty()) + && (!matches!(expr.span.ctxt().outer_expn_data().kind, ExpnKind::Macro(_, _)) || fn_decl.inputs.is_empty()) { span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/replace_box.rs b/src/tools/clippy/clippy_lints/src/replace_box.rs index c07aeec804f57..f7705b0b9b04d 100644 --- a/src/tools/clippy/clippy_lints/src/replace_box.rs +++ b/src/tools/clippy/clippy_lints/src/replace_box.rs @@ -61,7 +61,10 @@ impl ReplaceBox { consumed_locals: &mut self.consumed_locals, }, ) - .consume_body(cx.tcx.hir_body(body_id)) + .consume_body( + cx.tcx.hir_fn_decl_by_hir_id(cx.tcx.hir_body_owner(body_id)).unwrap(), + cx.tcx.hir_body(body_id) + ) .into_ok(); } diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index 427cf180adf2c..82730019b1ab0 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -139,7 +139,9 @@ impl<'tcx> LateLintPass<'tcx> for Shadow { let HirId { owner, local_id } = id; // get (or insert) the list of items for this owner and symbol - let (ref mut data, scope_owner) = *self.bindings.last_mut().unwrap(); + let Some((data, scope_owner)) = self.bindings.last_mut() else { + return + }; let items_with_name = data.entry(ident.name).or_default(); // check other bindings with the same name, most recently seen first @@ -149,7 +151,7 @@ impl<'tcx> LateLintPass<'tcx> for Shadow { return; } - if is_shadow(cx, scope_owner, prev, local_id) { + if is_shadow(cx, *scope_owner, prev, local_id) { let prev_hir_id = HirId { owner, local_id: prev }; lint_shadow(cx, pat, prev_hir_id, ident.span); // only lint against the "nearest" shadowed binding @@ -164,6 +166,12 @@ impl<'tcx> LateLintPass<'tcx> for Shadow { let owner_id = cx.tcx.hir_body_owner_def_id(body.id()); if !matches!(cx.tcx.hir_body_owner_kind(owner_id), BodyOwnerKind::Closure) { self.bindings.push((FxHashMap::default(), owner_id)); + + if let Some(decl) = cx.tcx.hir_fn_decl_by_hir_id(cx.tcx.hir_body_owner(body.id())) { + for input in decl.inputs { + self.check_pat(cx, input.pat); + } + } } } diff --git a/src/tools/clippy/clippy_lints/src/single_option_map.rs b/src/tools/clippy/clippy_lints/src/single_option_map.rs index 3ecb389fec896..39379744fee64 100644 --- a/src/tools/clippy/clippy_lints/src/single_option_map.rs +++ b/src/tools/clippy/clippy_lints/src/single_option_map.rs @@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for SingleOptionMap { && !matches!(args[0].kind, ExprKind::Path(_)) { if let ExprKind::Closure(closure) = args[0].kind { - let Body { params: [..], value } = cx.tcx.hir_body(closure.body); + let Body { value } = cx.tcx.hir_body(closure.body); if let ExprKind::Call(func, f_args) = value.kind && matches!(func.kind, ExprKind::Path(_)) && f_args.iter().all(|arg| matches!(arg.kind, ExprKind::Path(_))) diff --git a/src/tools/clippy/clippy_lints/src/string_patterns.rs b/src/tools/clippy/clippy_lints/src/string_patterns.rs index 5f29ea35beaf1..4003d4d829c17 100644 --- a/src/tools/clippy/clippy_lints/src/string_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/string_patterns.rs @@ -140,7 +140,7 @@ fn get_char_span<'tcx>(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Optio fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<'_>, msrv: Msrv) { if let ExprKind::Closure(closure) = method_arg.kind && let body = cx.tcx.hir_body(closure.body) - && let Some(PatKind::Binding(_, binding, ..)) = body.params.first().map(|p| p.pat.kind) + && let Some(PatKind::Binding(_, binding, ..)) = closure.fn_decl.inputs.first().map(|p| p.pat.kind) { let mut set_char_spans: Vec = Vec::new(); diff --git a/src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs b/src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs index d4a91de3af047..1b9081e65b40e 100644 --- a/src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs +++ b/src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs @@ -54,15 +54,15 @@ impl<'tcx> LateLintPass<'tcx> for ToplevelRefArg { cx: &LateContext<'tcx>, k: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, - body: &'tcx Body<'_>, + _: &'tcx Body<'_>, _: Span, _: LocalDefId, ) { if !matches!(k, FnKind::Closure) { - for arg in iter_input_pats(decl, body) { + for arg in iter_input_pats(decl) { if let PatKind::Binding(BindingMode(ByRef::Yes(..), _), ..) = arg.pat.kind && is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id) - && !arg.span.in_external_macro(cx.tcx.sess.source_map()) + && !arg.ty.span.in_external_macro(cx.tcx.sess.source_map()) { span_lint_hir( cx, diff --git a/src/tools/clippy/clippy_lints/src/try_from_instead_of_from_str.rs b/src/tools/clippy/clippy_lints/src/try_from_instead_of_from_str.rs index 0fc63e7617b5f..49cb2e7b2954a 100644 --- a/src/tools/clippy/clippy_lints/src/try_from_instead_of_from_str.rs +++ b/src/tools/clippy/clippy_lints/src/try_from_instead_of_from_str.rs @@ -9,6 +9,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::{BodyId, GenericArg, Impl, ImplItemKind, Item, ItemKind, LifetimeKind, TraitRef, Ty}; use rustc_lint::{LateContext, LateLintPass, LintContext as _, impl_lint_pass}; use rustc_span::symbol::kw; +use rustc_hir::FnSig; use core::ops::ControlFlow; @@ -131,14 +132,14 @@ fn check_lifetimes(ty: &Ty<'_>, imp: &Impl<'_>, trait_ref: &TraitRef<'_>) -> boo .all(|pred| rustc_hir::intravisit::walk_where_predicate(&mut visitor, pred).is_continue()) } -fn get_impl_items<'tcx>(cx: &LateContext<'tcx>, imp: &Impl<'_>) -> Option<(&'tcx Ty<'tcx>, BodyId)> { +fn get_impl_items<'tcx>(cx: &LateContext<'tcx>, imp: &Impl<'_>) -> Option<(&'tcx Ty<'tcx>, FnSig<'tcx>, BodyId)> { let &[item1, item2] = &imp.items else { return None }; match ( cx.tcx.hir_expect_impl_item(item1.owner_id.def_id).kind, cx.tcx.hir_expect_impl_item(item2.owner_id.def_id).kind, ) { - (ImplItemKind::Type(ty), ImplItemKind::Fn(_, body_id)) - | (ImplItemKind::Fn(_, body_id), ImplItemKind::Type(ty)) => Some((ty, body_id)), + (ImplItemKind::Type(ty), ImplItemKind::Fn(sig, body_id)) + | (ImplItemKind::Fn(sig, body_id), ImplItemKind::Type(ty)) => Some((ty, sig, body_id)), _ => None, } } @@ -167,7 +168,7 @@ impl<'tcx> LateLintPass<'tcx> for TryFromInsteadOfFromStr { && !item.span.in_external_macro(cx.sess().source_map()) && let Some(of_trait) = imp.of_trait // It should only have an associated type (`Error`) and a method (`try_from`). - && let Some((err_ty, fn_body)) = get_impl_items(cx, imp) + && let Some((err_ty, fn_sig, fn_body)) = get_impl_items(cx, imp) && let Some(trait_def_id) = of_trait.trait_ref.trait_def_id() && let impl_def_id = item.owner_id.to_def_id() && let trait_ref = cx.tcx.impl_trait_ref(impl_def_id) @@ -189,7 +190,7 @@ impl<'tcx> LateLintPass<'tcx> for TryFromInsteadOfFromStr { }) // We check that the lifetime used by `TryFrom::Error` is not used anywhere else. && check_lifetimes(err_ty, imp, &of_trait.trait_ref) - && let [param] = cx.tcx.hir_body(fn_body).params + && let [param] = fn_sig.decl.inputs // We retrieve all snippets for lint suggestion. // Only capture the pattern's span: the type is already guaranteed to be `&str`. && let Some(fn_arg) = snippet_opt(cx, param.pat.span) diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index d493ceae0e9b0..949b9de7d311f 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -559,8 +559,8 @@ impl Types { return; } - for input in decl.inputs { - self.check_ty(cx, input, context); + for param in decl.inputs { + self.check_ty(cx, param.ty, context); } if let FnRetTy::Return(ty) = decl.output { diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs index 1e2d9ab27c3e6..f2a172cf7683c 100644 --- a/src/tools/clippy/clippy_lints/src/unused_self.rs +++ b/src/tools/clippy/clippy_lints/src/unused_self.rs @@ -59,17 +59,17 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { let assoc_item = cx.tcx.associated_item(impl_item.owner_id); if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind && assoc_item.is_method() - && let ImplItemKind::Fn(.., body_id) = &impl_item.kind + && let ImplItemKind::Fn(sig, body_id) = &impl_item.kind && (!cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) || !self.avoid_breaking_exported_api) + && let [self_param, ..] = sig.decl.inputs && let body = cx.tcx.hir_body(*body_id) - && let [self_param, ..] = body.params && !is_local_used(cx, body, self_param.pat.hir_id) && !is_todo_unimplemented_stub(cx, body.value) { span_lint_and_help( cx, UNUSED_SELF, - self_param.span, + self_param.param_span, "unused `self` argument", None, "consider refactoring to an associated function", diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index 7b4250c6078f2..cc8c9ec821ba7 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -170,7 +170,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } else { None }; - let impl_inputs_outputs = decl.inputs.iter().chain(output_hir_ty); + let impl_inputs_outputs = decl.inputs.iter().map(|p| p.ty).chain(output_hir_ty); // `impl_hir_ty` (of type `hir::Ty`) represents the type written in the signature. // diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 63e83f4a7a75b..856cc7b493500 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -403,8 +403,8 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) { }, match fn_ptr.decl.output { FnRetTy::DefaultReturn(_) => { - if let [.., ty] = fn_ptr.decl.inputs { - ty_search_pat(ty).1 + if let [.., p] = fn_ptr.decl.inputs { + ty_search_pat(p.ty).1 } else { Pat::Str("(") } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 51155cfab7680..e48ead8053049 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -278,7 +278,7 @@ impl HirEqInterExpr<'_, '_, '_> { } fn eq_fn_decl(&mut self, left: &FnDecl<'_>, right: &FnDecl<'_>) -> bool { - over(left.inputs, right.inputs, |l, r| self.eq_ty(l, r)) + over(left.inputs, right.inputs, |l, r| self.eq_ty(l.ty, r.ty)) && (match (left.output, right.output) { (FnRetTy::DefaultReturn(_), FnRetTy::DefaultReturn(_)) => true, (FnRetTy::Return(l_ty), FnRetTy::Return(r_ty)) => self.eq_ty(l_ty, r_ty), @@ -1631,7 +1631,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { fn_ptr.safety.hash(&mut self.s); fn_ptr.abi.hash(&mut self.s); for arg in fn_ptr.decl.inputs { - self.hash_ty(arg); + self.hash_ty(arg.ty); } mem::discriminant(&fn_ptr.decl.output).hash(&mut self.s); match fn_ptr.decl.output { @@ -1663,6 +1663,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { | TyKind::Never | TyKind::InferDelegation(..) | TyKind::OpaqueDef(_) + | TyKind::CVarArgs | TyKind::TraitAscription(_) => {}, } } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index eb5befb52c3e4..abac039ed078b 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1551,8 +1551,8 @@ pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool { false } -pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl Iterator> { - (0..decl.inputs.len()).map(move |i| &body.params[i]) +pub fn iter_input_pats<'tcx>(decl: &FnDecl<'tcx>) -> impl Iterator> { + decl.inputs.into_iter() } /// Checks if a given expression is a match expression expanded from the `?` @@ -1791,8 +1791,8 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// * `|x| { let y = x; ...; let z = y; return z }` /// /// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead. -fn is_body_identity_function<'hir>(cx: &LateContext<'_>, func: &Body<'hir>) -> bool { - let [param] = func.params else { +fn is_body_identity_function<'hir>(cx: &LateContext<'_>, decl: &FnDecl<'hir>, func: &Body<'hir>) -> bool { + let [param] = decl.inputs else { return false; }; @@ -1950,9 +1950,9 @@ pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr< pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match expr.kind { ExprKind::Closure(&Closure { body, fn_decl, .. }) - if fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer(()))) => + if fn_decl.inputs.iter().all(|param| matches!(param.ty.kind, TyKind::Infer(()))) => { - is_body_identity_function(cx, cx.tcx.hir_body(body)) + is_body_identity_function(cx, fn_decl, cx.tcx.hir_body(body)) }, ExprKind::Path(QPath::Resolved(_, path)) if path.segments.iter().all(|seg| seg.infer_args) @@ -1974,7 +1974,7 @@ pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) /// errors. pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match expr.kind { - ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir_body(body)), + ExprKind::Closure(&Closure { fn_decl, body, .. }) => is_body_identity_function(cx, fn_decl, cx.tcx.hir_body(body)), _ => expr.basic_res().is_diag_item(cx, sym::convert_identity), } } diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index f725d2d7c2103..33c073fa4d9da 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -816,7 +816,7 @@ pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Opti let closure_body = cx.tcx.hir_body(body); // is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`) // a type annotation is present if param `kind` is different from `TyKind::Infer` - let closure_arg_is_type_annotated_double_ref = if let TyKind::Ref(_, ty, ..) = fn_decl.inputs[0].kind { + let closure_arg_is_type_annotated_double_ref = if let TyKind::Ref(_, ty, ..) = fn_decl.inputs[0].ty.kind { matches!(ty.kind, TyKind::Ref(..)) } else { false @@ -825,7 +825,7 @@ pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Opti let mut visitor = DerefDelegate { cx, closure_span: closure.span, - closure_arg_id: closure_body.params[0].pat.hir_id, + closure_arg_id: fn_decl.inputs[0].pat.hir_id, closure_arg_is_type_annotated_double_ref, next_pos: closure.span.lo(), checked_borrows: FxHashSet::default(), @@ -834,7 +834,7 @@ pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Opti }; ExprUseVisitor::for_clippy(cx, def_id, &mut visitor) - .consume_body(closure_body) + .consume_body(fn_decl, closure_body) .into_ok(); if !visitor.suggestion_start.is_empty() { diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index 358f961f9097b..0a612882b885b 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -725,7 +725,7 @@ impl<'tcx> ExprFnSig<'tcx> { } }, Self::Closure(decl, sig) => Some(( - decl.and_then(|decl| decl.inputs.get(i)), + decl.and_then(|decl| decl.inputs.get(i).map(|p| p.ty)), sig.input(0).map_bound(|ty| ty.tuple_fields()[i]), )), Self::Trait(inputs, _, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))), diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs index 0cb4faadda628..71026fb8a8c80 100644 --- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs @@ -209,10 +209,10 @@ fn param_certainty(cx: &LateContext<'_>, param: &Param<'_>) -> Certainty { return Certainty::Uncertain; }; let inputs = fn_decl.inputs; - let body_params = cx.tcx.hir_body_owned_by(owner_did).params; - std::iter::zip(body_params, inputs) - .find(|(p, _)| p.hir_id == param.hir_id) - .map_or(Certainty::Uncertain, |(_, ty)| type_certainty(cx, ty).clear_def_id()) + inputs + .iter() + .find(|p| p.hir_id == param.hir_id) + .map_or(Certainty::Uncertain, |p| type_certainty(cx, p.ty).clear_def_id()) } fn path_segment_certainty( diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index 4752f6e07c7f1..8a73adf3e5e63 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -92,9 +92,9 @@ pub struct ParamBindingIdCollector { pub binding_hir_ids: Vec, } impl<'tcx> ParamBindingIdCollector { - fn collect_binding_hir_ids(body: &'tcx hir::Body<'tcx>) -> Vec { + fn collect_binding_hir_ids(decl: &'tcx hir::FnDecl<'tcx>) -> Vec { let mut hir_ids: Vec = Vec::new(); - for param in body.params { + for param in decl.inputs { let mut finder = ParamBindingIdCollector { binding_hir_ids: Vec::new(), }; @@ -123,10 +123,10 @@ pub struct BindingUsageFinder<'a, 'tcx> { } impl<'a, 'tcx> BindingUsageFinder<'a, 'tcx> { /// Checks whether the parameter bindings of the given [`Body`](hir::Body) are used within it. - pub fn are_params_used(cx: &'a LateContext<'tcx>, body: &'tcx hir::Body<'tcx>) -> bool { + pub fn are_params_used(cx: &'a LateContext<'tcx>, decl: &hir::FnDecl<'_>, body: &'tcx hir::Body<'tcx>) -> bool { let mut finder = BindingUsageFinder { cx, - binding_ids: ParamBindingIdCollector::collect_binding_hir_ids(body), + binding_ids: ParamBindingIdCollector::collect_binding_hir_ids(decl), }; finder.visit_body(body).is_break() } diff --git a/src/tools/clippy/tests/ui-toml/min_ident_chars_trait_impl/min_ident_chars.stderr b/src/tools/clippy/tests/ui-toml/min_ident_chars_trait_impl/min_ident_chars.stderr index b483a21f37b47..d0b5ac04da8ef 100644 --- a/src/tools/clippy/tests/ui-toml/min_ident_chars_trait_impl/min_ident_chars.stderr +++ b/src/tools/clippy/tests/ui-toml/min_ident_chars_trait_impl/min_ident_chars.stderr @@ -1,17 +1,17 @@ error: this identifier consists of only a single character - --> tests/ui-toml/min_ident_chars_trait_impl/min_ident_chars.rs:4:10 + --> tests/ui-toml/min_ident_chars_trait_impl/min_ident_chars.rs:4:8 | LL | fn f(g: i32); - | ^ + | ^ | = note: `-D clippy::min-ident-chars` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::min_ident_chars)]` error: this identifier consists of only a single character - --> tests/ui-toml/min_ident_chars_trait_impl/min_ident_chars.rs:4:8 + --> tests/ui-toml/min_ident_chars_trait_impl/min_ident_chars.rs:4:10 | LL | fn f(g: i32); - | ^ + | ^ error: this identifier consists of only a single character --> tests/ui-toml/min_ident_chars_trait_impl/min_ident_chars.rs:12:10 diff --git a/src/tools/clippy/tests/ui/min_ident_chars.stderr b/src/tools/clippy/tests/ui/min_ident_chars.stderr index 07082bbc82936..bfa2113d62a24 100644 --- a/src/tools/clippy/tests/ui/min_ident_chars.stderr +++ b/src/tools/clippy/tests/ui/min_ident_chars.stderr @@ -220,16 +220,16 @@ LL | trait D { | ^ error: this identifier consists of only a single character - --> tests/ui/min_ident_chars.rs:151:10 + --> tests/ui/min_ident_chars.rs:151:8 | LL | fn f(g: i32); - | ^ + | ^ error: this identifier consists of only a single character - --> tests/ui/min_ident_chars.rs:151:8 + --> tests/ui/min_ident_chars.rs:151:10 | LL | fn f(g: i32); - | ^ + | ^ error: this identifier consists of only a single character --> tests/ui/min_ident_chars.rs:156:8 @@ -280,16 +280,16 @@ LL | trait A { | ^ error: this identifier consists of only a single character - --> tests/ui/min_ident_chars.rs:180:14 + --> tests/ui/min_ident_chars.rs:180:12 | LL | fn f(h: [u32; 0]); - | ^ + | ^ error: this identifier consists of only a single character - --> tests/ui/min_ident_chars.rs:180:12 + --> tests/ui/min_ident_chars.rs:180:14 | LL | fn f(h: [u32; 0]); - | ^ + | ^ error: this identifier consists of only a single character --> tests/ui/min_ident_chars.rs:192:41 diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index 420b01102e41e..571a9ff920040 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -85,15 +85,16 @@ hir-stats Ty 720 (NN.N%) 15 48 hir-stats - Ptr 48 (NN.N%) 1 hir-stats - Ref 48 (NN.N%) 1 hir-stats - Path 624 (NN.N%) 13 -hir-stats Generics 560 (NN.N%) 10 56 -hir-stats Pat 400 (NN.N%) 5 80 +hir-stats Pat 560 (NN.N%) 7 80 hir-stats - Struct 80 (NN.N%) 1 hir-stats - Wild 80 (NN.N%) 1 -hir-stats - Binding 240 (NN.N%) 3 +hir-stats - Binding 400 (NN.N%) 5 +hir-stats Generics 560 (NN.N%) 10 56 hir-stats GenericParam 400 (NN.N%) 5 80 hir-stats Block 288 (NN.N%) 6 48 hir-stats GenericBound 256 (NN.N%) 4 64 hir-stats - Trait 256 (NN.N%) 4 +hir-stats Param 160 (NN.N%) 4 40 hir-stats Attribute 160 (NN.N%) 4 40 hir-stats Variant 144 (NN.N%) 2 72 hir-stats GenericArgs 144 (NN.N%) 3 48 @@ -107,8 +108,6 @@ hir-stats Arm 80 (NN.N%) 2 40 hir-stats WherePredicate 72 (NN.N%) 3 24 hir-stats - BoundPredicate 72 (NN.N%) 3 hir-stats InlineAsm 72 (NN.N%) 1 72 -hir-stats Body 72 (NN.N%) 3 24 -hir-stats Param 64 (NN.N%) 2 32 hir-stats Local 64 (NN.N%) 1 64 hir-stats GenericArg 64 (NN.N%) 4 16 hir-stats - Type 16 (NN.N%) 1 @@ -116,9 +115,10 @@ hir-stats - Lifetime 48 (NN.N%) 3 hir-stats ExprField 40 (NN.N%) 1 40 hir-stats Mod 32 (NN.N%) 1 32 hir-stats Lifetime 28 (NN.N%) 1 28 +hir-stats Body 24 (NN.N%) 3 8 hir-stats TraitItemId 8 (NN.N%) 2 4 hir-stats ImplItemId 8 (NN.N%) 2 4 hir-stats ForeignItemId 4 (NN.N%) 1 4 hir-stats ---------------------------------------------------------------- -hir-stats Total 8_592 172 +hir-stats Total 8_800 176 hir-stats ================================================================ diff --git a/tests/ui/thir-print/c-variadic.stdout b/tests/ui/thir-print/c-variadic.stdout index 466825e4dc116..b7e431e761a56 100644 --- a/tests/ui/thir-print/c-variadic.stdout +++ b/tests/ui/thir-print/c-variadic.stdout @@ -17,7 +17,7 @@ params: [ } Param { ty: std::ffi::VaList<'{erased}> - ty_span: None + ty_span: Some($DIR/c-variadic.rs:4:37: 4:40 (#0)) self_kind: None hir_id: Some(HirId(DefId(0:3 ~ c_variadic[a5de]::foo).3)) param: Some( From 5f4013cd1f060cbd30c93edfcd7fb759c79e4895 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 9 Oct 2026 10:29:55 +0200 Subject: [PATCH 02/16] Remove `Param::ty_span` field The field is now a duplicate of `Param::ty`'s span --- compiler/rustc_ast_lowering/src/delegation/mod.rs | 6 ++++-- compiler/rustc_ast_lowering/src/expr.rs | 1 - compiler/rustc_ast_lowering/src/item.rs | 3 --- compiler/rustc_ast_lowering/src/lib.rs | 1 - compiler/rustc_borrowck/src/diagnostics/move_errors.rs | 2 +- compiler/rustc_hir/src/hir.rs | 3 +-- compiler/rustc_hir/src/intravisit.rs | 2 +- compiler/rustc_hir_typeck/src/check.rs | 2 +- compiler/rustc_hir_typeck/src/demand.rs | 8 ++++---- compiler/rustc_hir_typeck/src/gather_locals.rs | 2 +- compiler/rustc_hir_typeck/src/pat.rs | 8 ++++---- .../src/error_reporting/infer/need_type_info.rs | 4 ++-- .../infer/nice_region_error/placeholder_error.rs | 2 +- .../src/error_reporting/infer/suggest.rs | 4 ++-- .../src/error_reporting/traits/suggestions.rs | 4 ++-- .../rustc_trait_selection/src/traits/dyn_compatibility.rs | 4 ++-- src/tools/clippy/clippy_lints/src/from_over_into.rs | 2 +- .../clippy/clippy_lints/src/manual_is_ascii_check.rs | 6 +++--- tests/ui/stats/input-stats.stderr | 4 ++-- tests/ui/traits/bound/not-on-bare-trait.stderr | 4 ++-- 20 files changed, 34 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/delegation/mod.rs b/compiler/rustc_ast_lowering/src/delegation/mod.rs index 105e5cf1d4345..a4d458359d884 100644 --- a/compiler/rustc_ast_lowering/src/delegation/mod.rs +++ b/compiler/rustc_ast_lowering/src/delegation/mod.rs @@ -131,7 +131,6 @@ impl<'hir> LoweringContext<'_, 'hir> { )), span, }), - ty_span: param.ty_span, param_span: param.param_span, } })); @@ -227,7 +226,10 @@ impl<'hir> LoweringContext<'_, 'hir> { }); let hir_id = self.next_id(); - (PartialParam { hir_id, pat, ty_span: span, param_span: span }, pat_node_id) + (PartialParam { + hir_id, + pat, + param_span: span}, pat_node_id) } fn generate_arg( diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index bc5b28d3bcaf5..e0c0b52c92923 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -903,7 +903,6 @@ impl<'hir> LoweringContext<'_, 'hir> { hir_id: self.next_id(), pat, ty: input_ty, - ty_span: self.lower_span(span), param_span: self.lower_span(span), }; let params = arena_vec![self; param]; diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 93c49af0f1e60..eaddaeb194467 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1254,7 +1254,6 @@ impl<'hir> LoweringContext<'_, 'hir> { PartialParam { hir_id, pat: self.lower_pat(¶m.pat), - ty_span: self.lower_span(param.ty.span), param_span: self.lower_span(param.span), } } @@ -1451,7 +1450,6 @@ impl<'hir> LoweringContext<'_, 'hir> { let new_parameter = PartialParam { hir_id: parameter.hir_id, pat: new_parameter_pat, - ty_span: self.lower_span(parameter.ty_span), param_span: self.lower_span(parameter.param_span), }; @@ -2171,5 +2169,4 @@ pub(crate) struct PartialParam<'hir> { pub hir_id: HirId, pub pat: &'hir rustc_hir::Pat<'hir>, pub param_span: Span, - pub ty_span: Span, } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a921ddf66cf1e..088902f5ae419 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2044,7 +2044,6 @@ impl<'hir> LoweringContext<'_, 'hir> { hir_id: hir_param.hir_id, pat: hir_param.pat, ty: self.arena.alloc(ty), - ty_span: hir_param.ty_span, param_span: hir_param.param_span, }) }, diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 6db001e8334f5..563c33e750606 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -847,7 +847,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { hir::Node::Param(param) => { // Instead of pointing at the path where we access the value within a // closure, we point at the type of the outer `fn` argument. - param.ty_span + param.ty.span } hir::Node::LetStmt(stmt) => match (stmt.ty, stmt.init) { // We point at the type of the outer let-binding. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2493a79881982..2c1028e0aeab9 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3824,7 +3824,6 @@ pub struct Param<'hir> { pub hir_id: HirId, pub pat: &'hir Pat<'hir>, pub ty: &'hir Ty<'hir>, - pub ty_span: Span, pub param_span: Span, } @@ -5390,7 +5389,7 @@ mod size_asserts { static_assert_size!(Item<'_>, 88); static_assert_size!(ItemKind<'_>, 64); static_assert_size!(LetStmt<'_>, 64); - static_assert_size!(Param<'_>, 40); + static_assert_size!(Param<'_>, 32); static_assert_size!(Pat<'_>, 80); static_assert_size!(PatKind<'_>, 56); static_assert_size!(Path<'_>, 40); diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index d9c6081b58b4b..f7d5d45184e3f 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -549,7 +549,7 @@ pub trait Visitor<'v>: Sized { } pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) -> V::Result { - let Param { hir_id, pat, ty, ty_span: _, param_span: _ } = param; + let Param { hir_id, pat, ty, param_span: _ } = param; try_visit!(visitor.visit_ty_unambig(*ty)); try_visit!(visitor.visit_id(*hir_id)); visitor.visit_pat(pat) diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 759f1a581afb8..36933939d6813 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -92,7 +92,7 @@ pub(super) fn check_fn<'a, 'tcx>( if !params_can_be_unsized || fn_sig.abi() == rustc_abi::ExternAbi::RustTail { fcx.require_type_is_sized( param_ty, - param.ty_span, + param.ty.span, // ty.span == binding_span iff this is a closure parameter with no type ascription, // or if it's an implicit `self` parameter ObligationCauseCode::SizedArgumentType( diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index b2c238e800055..cfc00189e1959 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -784,8 +784,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { primary_span = init.span; post_message = " value"; } - hir::Node::Param(hir::Param { ty_span, .. }) => { - primary_span = *ty_span; + hir::Node::Param(hir::Param { ty, .. }) => { + primary_span = ty.span; post_message = " parameter type"; } _ => {} @@ -879,7 +879,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let hir::Node::Pat(pat) = self.tcx.hir_node(*hir_id) // The pattern we have is an fn argument. - && let hir::Node::Param(hir::Param { ty_span, .. }) = + && let hir::Node::Param(hir::Param { ty, .. }) = self.tcx.parent_hir_node(pat.hir_id) && let item = self.tcx.hir_get_parent_item(pat.hir_id) && let item = self.tcx.hir_owner_node(item) @@ -893,7 +893,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .inputs .iter() .filter_map(|param| match param.ty.kind { - hir::TyKind::Ref(lt, inner_ty, mutbl) if param.ty.span == *ty_span => Some((lt, inner_ty, mutbl)), + hir::TyKind::Ref(lt, inner_ty, mutbl) if param.ty.span == ty.span => Some((lt, inner_ty, mutbl)), _ => None, }) .next() diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 21954203a705a..8ff3a1935e422 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -94,7 +94,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { pub(crate) fn gather_from_param(fcx: &'a FnCtxt<'a, 'tcx>, param: &'tcx hir::Param<'tcx>) { let mut visitor = GatherLocalsVisitor { fcx, - outermost_fn_param_pat: Some((param.ty_span, param.hir_id)), + outermost_fn_param_pat: Some((param.ty.span, param.hir_id)), }; visitor.visit_pat(param.pat); } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 0ebb418c7f2ac..5470613aa1fd3 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1424,8 +1424,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; match binding_parent { - hir::Node::Param(hir::Param { ty_span, pat, .. }) - if pat.span != *ty_span + hir::Node::Param(hir::Param { ty, pat, .. }) + if pat.span != ty.span && pinned.is_pinned() && !tcx.features().pin_ergonomics() => { @@ -1434,12 +1434,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Check that there is explicit type (ie this is not a closure param with inferred type) // so we don't suggest moving something to the type that does not exist - hir::Node::Param(hir::Param { ty_span, pat, .. }) if pat.span != *ty_span => { + hir::Node::Param(hir::Param { ty, pat, .. }) if pat.span != ty.span => { err.multipart_suggestion( format!("to take parameter `{binding}` by reference, move `&{pin_and_mut}` to the type"), vec![ (pat.span.until(inner.span), "".to_owned()), - (ty_span.shrink_to_lo(), format!("&{}", pinned.prefix_str(mutbl))), + (ty.span.shrink_to_lo(), format!("&{}", pinned.prefix_str(mutbl))), ], Applicability::MachineApplicable ); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 2b57a0989c538..9021709f8370a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -1385,9 +1385,9 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { for param in decl.inputs { debug!( "param: span {:?}, ty_span {:?}, pat.span {:?}", - param.param_span, param.ty_span, param.pat.span + param.param_span, param.ty.span, param.pat.span ); - if param.ty_span != param.pat.span { + if param.ty.span != param.pat.span { debug!("skipping param: has explicit type"); continue; } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index c537c040a52b5..a6c27dbbf5815 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -474,7 +474,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { .zip(input_tys.iter()) .filter_map(|(param, ty)| { // ty_span == pat.span means no explicit type annotation was written. - if param.ty_span == param.pat.span + if param.ty.span == param.pat.span && ty.is_suggestable(self.tcx(), false) { Some((param.pat.span.shrink_to_hi(), format!(": {ty}"))) diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index f2871cd59fb91..5581f9fdaef73 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -771,7 +771,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { { // If the expected region is late bound, the found region is not, and users are asking compiler // to infer the type, we can suggest adding `: &_`. - if param_hir.pat.span == param_hir.ty_span { + if param_hir.pat.span == param_hir.ty.span { // for `|x|`, `|_|`, `|x: impl Foo|` let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) @@ -786,7 +786,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { else { return; }; - let Ok(ty) = self.tcx.sess.source_map().span_to_snippet(param_hir.ty_span) + let Ok(ty) = self.tcx.sess.source_map().span_to_snippet(param_hir.ty.span) else { return; }; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 31e973c486531..f18df72fc2b4d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4224,7 +4224,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } Node::Param(param) => { err.span_suggestion_verbose( - param.ty_span.shrink_to_lo(), + param.ty.span.shrink_to_lo(), "function arguments must have a statically known size, borrowed types \ always have a known size", "&", @@ -5781,7 +5781,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); let assocs_in_this_method = self.probe_assoc_types_at_expr( &type_diffs, - param.ty_span, + param.ty.span, prev_ty, param.hir_id, param_env, diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 8065fbd75c36a..096ac9fe0cc29 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -541,9 +541,9 @@ fn virtual_call_violations_for_method<'tcx>( } hir::TraitFn::Provided(_body_id) if let Some(p) = sig.decl.inputs.get(0) - && p.param_span.ctxt() == p.ty_span.ctxt() => + && p.param_span.ctxt() == p.ty.span.ctxt() => { - Some(p.param_span.to(p.ty_span)) + Some(p.param_span.to(p.ty.span)) } _ => None, } diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs index 00c02bc6db93e..79fa04a032ee6 100644 --- a/src/tools/clippy/clippy_lints/src/from_over_into.rs +++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs @@ -216,7 +216,7 @@ fn convert_to_from( (impl_item.ident.span, String::from("from")), // fn into([mut] self: U) -> T -> fn into([mut] val: T) -> T // ~~~~~~~ ~~~~~~ - (self_ident.span.to(self_param.ty_span), format!("val: {from}")), + (self_ident.span.to(self_param.ty.span), format!("val: {from}")), ]; if let FnRetTy::Return(_) = sig.decl.output { diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs index 7451706fcfe5c..e2ec62b84b752 100644 --- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs +++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs @@ -132,12 +132,12 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { fn get_ty_sugg<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'_>) -> Option<(Span, Ty<'tcx>)> { let local_hid = arg.res_local_id()?; - if let Node::Param(Param { ty_span, param_span, .. }) = cx.tcx.parent_hir_node(local_hid) + if let Node::Param(Param { ty, param_span, .. }) = cx.tcx.parent_hir_node(local_hid) // `ty_span` and `span` are the same for inferred type, thus a type suggestion must be given - && ty_span == param_span + && ty.span == *param_span { let arg_type = cx.typeck_results().expr_ty(arg); - return Some((*ty_span, arg_type)); + return Some((ty.span, arg_type)); } None } diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index 571a9ff920040..79b14585939bc 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -94,11 +94,11 @@ hir-stats GenericParam 400 (NN.N%) 5 80 hir-stats Block 288 (NN.N%) 6 48 hir-stats GenericBound 256 (NN.N%) 4 64 hir-stats - Trait 256 (NN.N%) 4 -hir-stats Param 160 (NN.N%) 4 40 hir-stats Attribute 160 (NN.N%) 4 40 hir-stats Variant 144 (NN.N%) 2 72 hir-stats GenericArgs 144 (NN.N%) 3 48 hir-stats FieldDef 144 (NN.N%) 2 72 +hir-stats Param 128 (NN.N%) 4 32 hir-stats FnDecl 120 (NN.N%) 3 40 hir-stats Stmt 96 (NN.N%) 3 32 hir-stats - Expr 32 (NN.N%) 1 @@ -120,5 +120,5 @@ hir-stats TraitItemId 8 (NN.N%) 2 4 hir-stats ImplItemId 8 (NN.N%) 2 4 hir-stats ForeignItemId 4 (NN.N%) 1 4 hir-stats ---------------------------------------------------------------- -hir-stats Total 8_800 176 +hir-stats Total 8_768 176 hir-stats ================================================================ diff --git a/tests/ui/traits/bound/not-on-bare-trait.stderr b/tests/ui/traits/bound/not-on-bare-trait.stderr index 72226391f583d..f05c7c36ca70a 100644 --- a/tests/ui/traits/bound/not-on-bare-trait.stderr +++ b/tests/ui/traits/bound/not-on-bare-trait.stderr @@ -30,10 +30,10 @@ LL | fn foo(_x: &(dyn Foo + Send)) { | +++++ + error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time - --> $DIR/not-on-bare-trait.rs:13:12 + --> $DIR/not-on-bare-trait.rs:13:13 | LL | fn bar(_x: (dyn Foo + Send)) { - | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Foo + Send + 'static)` = help: unsized fn params are gated as an unstable feature From 53750cd9ab9c81e9196f5f1bef749a843bc2ba20 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 9 Oct 2026 12:40:06 +0200 Subject: [PATCH 03/16] Simplify pretty printing of parameters --- compiler/rustc_hir_pretty/src/lib.rs | 88 +++++++------------------ tests/pretty/hir-fn-params.pp | 4 +- tests/pretty/hir-fn-variadic.pp | 4 +- tests/ui/unpretty/exhaustive.hir.stdout | 4 +- 4 files changed, 28 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 679e7a212064a..7b54784442404 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -47,7 +47,6 @@ pub enum Nested { ImplItem(hir::ImplItemId), ForeignItem(hir::ForeignItemId), Body(hir::BodyId), - BodyParamPat(hir::HirId, usize), } pub trait PpAnn { @@ -64,7 +63,6 @@ impl PpAnn for &dyn rustc_hir::intravisit::HirTyCtxt<'_> { Nested::ImplItem(id) => state.print_impl_item(self.hir_impl_item(id)), Nested::ForeignItem(id) => state.print_foreign_item(self.hir_foreign_item(id)), Nested::Body(id) => state.print_expr(self.hir_body(id).value), - Nested::BodyParamPat(id, i) => state.print_pat(self.hir_fn_decl(id).inputs[i].pat), } } } @@ -427,7 +425,7 @@ impl<'a> State<'a> { self.pclose(); } hir::TyKind::FnPtr(f) => { - self.print_ty_fn(f.abi, f.safety, f.decl, None, f.generic_params, f.param_idents); + self.print_ty_fn(f.abi, f.safety, f.decl, None, f.generic_params); } hir::TyKind::UnsafeBinder(unsafe_binder) => { self.print_unsafe_binder(unsafe_binder); @@ -501,7 +499,7 @@ impl<'a> State<'a> { } self.word("})"); } - hir::TyKind::CVarArgs => unreachable!("Filtered out before calling `print_type`"), + hir::TyKind::CVarArgs => {} } self.end(ib) } @@ -520,16 +518,9 @@ impl<'a> State<'a> { self.maybe_print_comment(item.span.lo()); self.print_attrs(self.attrs(item.hir_id())); match item.kind { - hir::ForeignItemKind::Fn(sig, arg_idents, generics) => { + hir::ForeignItemKind::Fn(sig, _, generics) => { let (cb, ib) = self.head(""); - self.print_fn( - sig.header, - Some(item.ident.name), - generics, - sig.decl, - arg_idents, - None, - ); + self.print_fn(sig.header, Some(item.ident.name), generics, sig.decl); self.end(ib); self.word(";"); self.end(cb) @@ -661,14 +652,7 @@ impl<'a> State<'a> { } hir::ItemKind::Fn { ident, sig, generics, body, .. } => { let (cb, ib) = self.head(""); - self.print_fn( - sig.header, - Some(ident.name), - generics, - sig.decl, - &[], - Some(item.hir_id()), - ); + self.print_fn(sig.header, Some(ident.name), generics, sig.decl); self.word(" "); self.end(ib); self.end(cb); @@ -984,15 +968,8 @@ impl<'a> State<'a> { } } - fn print_method_sig( - &mut self, - ident: Ident, - m: &hir::FnSig<'_>, - generics: &hir::Generics<'_>, - arg_idents: &[Option], - body_id: Option, - ) { - self.print_fn(m.header, Some(ident.name), generics, m.decl, arg_idents, body_id); + fn print_method_sig(&mut self, ident: Ident, m: &hir::FnSig<'_>, generics: &hir::Generics<'_>) { + self.print_fn(m.header, Some(ident.name), generics, m.decl); } fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) { @@ -1004,13 +981,13 @@ impl<'a> State<'a> { hir::TraitItemKind::Const(ty, default) => { self.print_associated_const(ti.ident, ti.generics, ty, default); } - hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(arg_idents)) => { - self.print_method_sig(ti.ident, sig, ti.generics, arg_idents, None); + hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(_)) => { + self.print_method_sig(ti.ident, sig, ti.generics); self.word(";"); } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { let (cb, ib) = self.head(""); - self.print_method_sig(ti.ident, sig, ti.generics, &[], Some(ti.hir_id())); + self.print_method_sig(ti.ident, sig, ti.generics); self.nbsp(); self.end(ib); self.end(cb); @@ -1035,7 +1012,7 @@ impl<'a> State<'a> { } hir::ImplItemKind::Fn(ref sig, body) => { let (cb, ib) = self.head(""); - self.print_method_sig(ii.ident, sig, ii.generics, &[], Some(ii.hir_id())); + self.print_method_sig(ii.ident, sig, ii.generics); self.nbsp(); self.end(ib); self.end(cb); @@ -1701,7 +1678,7 @@ impl<'a> State<'a> { self.print_constness(constness); self.print_capture_clause(capture_clause); - self.print_closure_params(fn_decl, expr.hir_id); + self.print_closure_params(fn_decl); self.space(); // This is a bare expression. @@ -2288,8 +2265,6 @@ impl<'a> State<'a> { name: Option, generics: &hir::Generics<'_>, decl: &hir::FnDecl<'_>, - arg_idents: &[Option], - body_id: Option, ) { self.print_fn_header_info(header); @@ -2300,30 +2275,16 @@ impl<'a> State<'a> { self.print_generic_params(generics.params); self.popen(); - // Make sure we aren't supplied *both* `arg_idents` and `body_id`. - assert!(arg_idents.is_empty() || body_id.is_none()); let mut i = 0; - let mut print_arg = |s: &mut Self, ty: Option<&hir::Ty<'_>>| { - if Some(i) == decl.splatted().map(usize::from) { - s.word("#[rustc_splat]"); - } + let mut print_arg = |s: &mut Self, param: &hir::Param<'_>| { + s.print_attrs(s.attrs(param.hir_id)); if i == 0 && decl.implicit_self().has_implicit_self() { s.print_implicit_self(&decl.implicit_self()); } else { - if let Some(arg_ident) = arg_idents.get(i) { - if let Some(arg_ident) = arg_ident { - s.word(arg_ident.to_string()); - s.word(":"); - s.space(); - } - } else if let Some(body_id) = body_id { - s.ann.nested(s, Nested::BodyParamPat(body_id, i)); - s.word(":"); - s.space(); - } - if let Some(ty) = ty { - s.print_type(ty); - } + s.print_pat(param.pat); + s.word(":"); + s.space(); + s.print_type(param.ty); } i += 1; }; @@ -2332,7 +2293,7 @@ impl<'a> State<'a> { decl.inputs.iter().filter(|param| !matches!(param.ty.kind, hir::TyKind::CVarArgs)), |s, param| { let ib = s.ibox(INDENT_UNIT); - print_arg(s, Some(param.ty)); + print_arg(s, param); s.end(ib); }, ); @@ -2340,7 +2301,7 @@ impl<'a> State<'a> { if decl.inputs.len() != 1 { self.word(", "); } - print_arg(self, None); + print_arg(self, decl.inputs.last().unwrap()); self.word("..."); } self.pclose(); @@ -2349,14 +2310,12 @@ impl<'a> State<'a> { self.print_where_clause(generics) } - fn print_closure_params(&mut self, decl: &hir::FnDecl<'_>, body_id: hir::HirId) { + fn print_closure_params(&mut self, decl: &hir::FnDecl<'_>) { self.word("|"); - let mut i = 0; self.commasep(Inconsistent, decl.inputs, |s, param| { let ib = s.ibox(INDENT_UNIT); - s.ann.nested(s, Nested::BodyParamPat(body_id, i)); - i += 1; + s.print_pat(param.pat); if let hir::TyKind::Infer(()) = param.ty.kind { // Print nothing. @@ -2614,7 +2573,6 @@ impl<'a> State<'a> { decl: &hir::FnDecl<'_>, name: Option, generic_params: &[hir::GenericParam<'_>], - arg_idents: &[Option], ) { let ib = self.ibox(INDENT_UNIT); self.print_formal_generic_params(generic_params); @@ -2629,8 +2587,6 @@ impl<'a> State<'a> { name, generics, decl, - arg_idents, - None, ); self.end(ib); } diff --git a/tests/pretty/hir-fn-params.pp b/tests/pretty/hir-fn-params.pp index 15373bba24d3f..82ecb09f61f72 100644 --- a/tests/pretty/hir-fn-params.pp +++ b/tests/pretty/hir-fn-params.pp @@ -26,12 +26,12 @@ // because they had similar problems. But the pretty-printing tests currently // can't contain compile errors. -fn bare_fn(x: fn(u32, _: u32, a: u32)) { } +fn bare_fn(x: fn(_: u32, _: u32, a: u32)) { } extern "C" { unsafe fn foreign_fn(_: u32, a: u32); } trait T { - fn trait_fn(u32, _: u32, a: u32); + fn trait_fn(_: u32, _: u32, a: u32); } diff --git a/tests/pretty/hir-fn-variadic.pp b/tests/pretty/hir-fn-variadic.pp index cdf61d0cb1158..d7860d24da31c 100644 --- a/tests/pretty/hir-fn-variadic.pp +++ b/tests/pretty/hir-fn-variadic.pp @@ -15,8 +15,8 @@ fn main() { fn g1(_: extern "C" fn(_: u8, va: ...)) { } fn g2(_: extern "C" fn(_: u8, _: ...)) { } - fn g3(_: extern "C" fn(u8, va: ...)) { } - fn g4(_: extern "C" fn(u8, _: ...)) { } + fn g3(_: extern "C" fn(_: u8, va: ...)) { } + fn g4(_: extern "C" fn(_: u8, _: ...)) { } fn g5(_: extern "C" fn(va: ...)) { } fn g6(_: extern "C" fn(_: ...)) { } diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 6af4d3b5b81de..b6e39df548b4a 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -511,7 +511,7 @@ mod items { } mod patterns { /// PatKind::Missing - fn pat_missing() { let _: for fn(u32, T, &'_ str); } + fn pat_missing() { let _: for fn(_: u32, _: T, _: &'_ str); } /// PatKind::Wild fn pat_wild() { let _; } /// PatKind::Ident @@ -618,7 +618,7 @@ mod types { fn ty_bare_fn() { let _: fn(); let _: fn() -> (); - let _: fn(T); + let _: fn(_: T); let _: fn(t: T); let _: fn(); let _: for<'a> fn(); From 32cca48f8316587028c6b348f0dfb4fd2d00904c Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 9 Oct 2026 13:19:00 +0200 Subject: [PATCH 04/16] Simplify cleaning of parameters in rustdoc --- src/librustdoc/clean/mod.rs | 82 +++++--------------- tests/rustdoc-html/constant/assoc-consts.rs | 2 +- tests/rustdoc-html/fn/fn-pointer-arg-name.rs | 4 +- 3 files changed, 24 insertions(+), 64 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c6fae82f3dec2..399b75fb06e21 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -48,7 +48,7 @@ use rustc_middle::middle::resolve::Reexport; use rustc_middle::middle::resolve_bound_vars as rbv; use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized}; use rustc_span::hygiene::{AstPass, MacroKind}; -use rustc_span::symbol::{Ident, Symbol, kw}; +use rustc_span::symbol::{Symbol, kw}; use rustc_span::{ExpnKind, bug, span_bug}; use rustc_trait_selection::traits::wf::object_region_bounds; use tracing::{debug, instrument}; @@ -1107,8 +1107,7 @@ fn clean_fn_or_proc_macro<'tcx>( match macro_kind { Some(kind) => clean_proc_macro(item, name, kind, cx.tcx), None => { - let (generics, decl) = - clean_function(cx, sig, generics, ParamsSrc::Body, item.owner_id.to_def_id()); + let (generics, decl) = clean_function(cx, sig, generics, item.owner_id.to_def_id()); let mut func = Function { generics, decl }; clean_fn_decl_legacy_const_generics(&mut func, attrs); ItemKind::Function(Box::new(func)) @@ -1138,16 +1137,10 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[rustc_attr_ } } -enum ParamsSrc<'tcx> { - Body, - Idents(&'tcx [Option]), -} - fn clean_function<'tcx>( cx: &mut DocContext<'tcx>, sig: &hir::FnSig<'tcx>, generics: &hir::Generics<'tcx>, - params: ParamsSrc<'tcx>, def_id: DefId, ) -> (Generics, FnDecl) { enter_impl_trait(cx, |cx| { @@ -1163,47 +1156,28 @@ fn clean_function<'tcx>( let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip(); clean_poly_fn_sig(cx, Some(def_id), sig) } else { - let params = match params { - ParamsSrc::Body => clean_params_via_body(cx, sig.decl), - // Let's not perpetuate anon params from Rust 2015; use `_` for them. - ParamsSrc::Idents(idents) => clean_params(cx, sig.decl, idents, |ident| { - Some(ident.map_or(kw::Underscore, |ident| ident.name)) - }), - }; + let params = clean_params(cx, sig.decl, false); clean_fn_decl_with_params(cx, sig.decl, Some(&sig.header), params) }; (generics, decl) }) } -fn clean_params<'tcx>( - cx: &mut DocContext<'tcx>, +fn clean_params( + cx: &mut DocContext<'_>, decl: &hir::FnDecl<'_>, - idents: &[Option], - postprocess: impl Fn(Option) -> Option, + remove_missing: bool, ) -> Vec { decl.inputs .iter() .filter(|param| !matches!(param.ty.kind, hir::TyKind::CVarArgs)) .enumerate() .map(|(i, param)| Parameter { - name: postprocess(idents[i]), - type_: clean_ty(param.ty, cx), - is_const: false, - is_splat: decl.splatted().is_some_and(|j| j as usize == i), - }) - .collect() -} - -fn clean_params_via_body<'tcx>( - cx: &mut DocContext<'tcx>, - decl: &hir::FnDecl<'tcx>, -) -> Vec { - decl.inputs - .iter() - .enumerate() - .map(|(i, param)| Parameter { - name: Some(name_from_pat(param.pat)), + name: if remove_missing && matches!(param.pat.kind, hir::PatKind::Missing) { + None + } else { + Some(name_from_pat(param.pat)) + }, type_: clean_ty(param.ty, cx), is_const: false, is_splat: decl.splatted().is_some_and(|j| j as usize == i), @@ -1302,15 +1276,13 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext })) } hir::TraitItemKind::Fn(ref sig, body) => { - let (params, body) = match body { - hir::TraitFn::Provided(_) => ( - ParamsSrc::Body, - Some(Defaultness::from_trait_item(trait_item.defaultness)), - ), - hir::TraitFn::Required(idents) => (ParamsSrc::Idents(idents), None), + let body = match body { + hir::TraitFn::Provided(_) => { + Some(Defaultness::from_trait_item(trait_item.defaultness)) + } + hir::TraitFn::Required(_) => None, }; - let (generics, decl) = - clean_function(cx, sig, trait_item.generics, params, local_did); + let (generics, decl) = clean_function(cx, sig, trait_item.generics, local_did); ItemKind::AssocFunction(Box::new(AssocFunction { generics, decl, body })) } hir::TraitItemKind::Type(bounds, ty) => { @@ -1348,8 +1320,7 @@ pub(crate) fn clean_impl_item<'tcx>( })) } hir::ImplItemKind::Fn(ref sig, _) => { - let (generics, decl) = - clean_function(cx, sig, impl_.generics, ParamsSrc::Body, local_did); + let (generics, decl) = clean_function(cx, sig, impl_.generics, local_did); ItemKind::AssocFunction(Box::new(AssocFunction { generics, decl, @@ -2713,17 +2684,7 @@ fn clean_bare_fn_ty<'tcx>( .filter(|p| !is_elided_lifetime(p)) .map(|x| clean_generic_param(cx, None, x)) .collect(); - // Since it's more conventional stylistically, elide the name of all params called `_` - // unless there's at least one interestingly named param in which case don't elide any - // name since mixing named and unnamed params is less legible. - let filter = |ident: Option| { - ident.map(|ident| ident.name).filter(|&ident| ident != kw::Underscore) - }; - let fallback = - bare_fn.param_idents.iter().copied().find_map(filter).map(|_| kw::Underscore); - let params = clean_params(cx, bare_fn.decl, bare_fn.param_idents, |ident| { - filter(ident).or(fallback) - }); + let params = clean_params(cx, bare_fn.decl, true); let decl = clean_fn_decl_with_params(cx, bare_fn.decl, None, params); (generic_params, decl) }); @@ -3352,9 +3313,8 @@ fn clean_maybe_renamed_foreign_item<'tcx>( let def_id = item.owner_id.to_def_id(); cx.with_param_env(def_id, |cx| { let kind = match item.kind { - hir::ForeignItemKind::Fn(sig, idents, generics) => { - let (generics, decl) = - clean_function(cx, &sig, generics, ParamsSrc::Idents(idents), def_id); + hir::ForeignItemKind::Fn(sig, _, generics) => { + let (generics, decl) = clean_function(cx, &sig, generics, def_id); ItemKind::ForeignFunction( Box::new(Function { generics, decl }), sig.header.safety(), diff --git a/tests/rustdoc-html/constant/assoc-consts.rs b/tests/rustdoc-html/constant/assoc-consts.rs index 0994ec7517e3e..a52835068bf3e 100644 --- a/tests/rustdoc-html/constant/assoc-consts.rs +++ b/tests/rustdoc-html/constant/assoc-consts.rs @@ -45,7 +45,7 @@ pub fn f(_: &(ToString + 'static)) {} impl Bar { //@ has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.F"]' \ - // "const F: fn(&(dyn ToString + 'static))" + // "const F: fn(_: &(dyn ToString + 'static))" pub const F: fn(_: &(ToString + 'static)) = f; } diff --git a/tests/rustdoc-html/fn/fn-pointer-arg-name.rs b/tests/rustdoc-html/fn/fn-pointer-arg-name.rs index 0ee1964511a1d..6bf35472d66a5 100644 --- a/tests/rustdoc-html/fn/fn-pointer-arg-name.rs +++ b/tests/rustdoc-html/fn/fn-pointer-arg-name.rs @@ -5,9 +5,9 @@ pub fn f(callback: fn(len: usize, foo: u32)) {} //@ has foo/fn.g.html -//@ has - '//pre[@class="rust item-decl"]' 'pub fn g(_: fn(usize, u32))' +//@ has - '//pre[@class="rust item-decl"]' 'pub fn g(_: fn(usize, _: u32))' pub fn g(_: fn(usize, _: u32)) {} //@ has foo/fn.mixed.html -//@ has - '//pre[@class="rust item-decl"]' 'pub fn mixed(_: fn(_: usize, foo: u32))' +//@ has - '//pre[@class="rust item-decl"]' 'pub fn mixed(_: fn(usize, foo: u32))' pub fn mixed(_: fn(usize, foo: u32)) {} From df68a8099a33a7b0546045a80b6845867a23a467 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 9 Oct 2026 13:20:25 +0200 Subject: [PATCH 05/16] Remove the now unused `FnPtrTy::param_idents` --- compiler/rustc_ast_lowering/src/lib.rs | 1 - compiler/rustc_hir/src/hir.rs | 3 --- 2 files changed, 4 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 088902f5ae419..384542a6199fc 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1578,7 +1578,6 @@ impl<'hir> LoweringContext<'_, 'hir> { DiscardParams::Yes, params, ), - param_idents: self.lower_fn_params_to_idents(&f.decl), })); return hir::Ty { kind, span: self.lower_span(t.span), hir_id }; } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2c1028e0aeab9..b20541623451a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3501,9 +3501,6 @@ pub struct FnPtrTy<'hir> { pub abi: ExternAbi, pub generic_params: &'hir [GenericParam<'hir>], pub decl: &'hir FnDecl<'hir>, - // `Option` because bare fn parameter identifiers are optional. We also end up - // with `None` in some error cases, e.g. invalid parameter patterns. - pub param_idents: &'hir [Option], } #[derive(Debug, Clone, Copy, StableHash)] From 3e41fedc730359e0d9d0e7a12fd619046cd0bb12 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 9 Oct 2026 13:40:54 +0200 Subject: [PATCH 06/16] Simplify parameter span in `virtual_call_violations_for_method` --- .../src/traits/dyn_compatibility.rs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 096ac9fe0cc29..c74fc9a313a80 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -520,7 +520,7 @@ fn virtual_call_violations_for_method<'tcx>( if receiver_ty != tcx.types.self_param { if !receiver_is_dispatchable(tcx, method, receiver_ty) { let span_n_lt = if let Some(hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(sig, trait_fn), + kind: hir::TraitItemKind::Fn(sig, _), .. })) = tcx.hir_get_if_local(method.def_id).as_ref() { @@ -533,21 +533,7 @@ fn virtual_call_violations_for_method<'tcx>( _ => sym::empty, }; // Get the `Span` for all of `self: Ty`, not just `Ty`. - match trait_fn { - hir::TraitFn::Required([Some(name), ..]) - if name.span.ctxt() == sig.decl.inputs[0].ty.span.ctxt() => - { - Some(name.span.to(sig.decl.inputs[0].ty.span)) - } - hir::TraitFn::Provided(_body_id) - if let Some(p) = sig.decl.inputs.get(0) - && p.param_span.ctxt() == p.ty.span.ctxt() => - { - Some(p.param_span.to(p.ty.span)) - } - _ => None, - } - .map(|sp| (sp, lt)) + sig.decl.inputs.get(0).map(|p| (p.param_span.to(p.ty.span), lt)) } else { None }; From 0ea19db47f8cca07cbbdb388f86a9a2cc8fcf468 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 9 Oct 2026 13:45:18 +0200 Subject: [PATCH 07/16] Remove now unreachable branches in `fn_arg_idents` --- compiler/rustc_middle/src/hir/mod.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 8a5088a386ecd..29d2a31358a98 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -479,16 +479,6 @@ pub fn provide(providers: &mut Providers) { let node = tcx.hir_node_by_def_id(def_id); if let Some(decl) = node.fn_decl() { tcx.arena.alloc_from_iter(tcx.hir_body_param_idents(decl)) - } else if let Node::TraitItem(&TraitItem { - kind: TraitItemKind::Fn(_, TraitFn::Required(idents)), - .. - }) - | Node::ForeignItem(&ForeignItem { - kind: ForeignItemKind::Fn(_, idents, _), - .. - }) = node - { - idents } else { span_bug!( tcx.hir_span(tcx.local_def_id_to_hir_id(def_id)), From 4d3053f9d0972bec02069dc29a96a0a3714a76d3 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Wed, 4 Nov 2026 15:19:47 +0100 Subject: [PATCH 08/16] Simplify `get_hir_param_info` This makes the span of parameters point to the entire parameter, for functions without bodies. This matches the behaviour of functions with bodies. --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 76 +++++-------------- .../extern-fn-arg-names.stderr | 2 +- tests/ui/c-variadic/variadic-ffi-1.stderr | 4 +- .../typeck-errors.stderr | 2 +- tests/ui/delegation/glob-glob-conflict.stderr | 4 +- .../self-mapping-arguments-errors.stderr | 4 +- .../ui/delegation/self-mapping-output.stderr | 12 +-- tests/ui/error-codes/E0060.stderr | 2 +- tests/ui/fn/param-mismatch-foreign.stderr | 2 +- tests/ui/fn/param-mismatch-trait-fn.stderr | 2 +- .../relate-bound-region-ice-144033.stderr | 2 +- tests/ui/methods/issues/issue-61525.stderr | 2 +- tests/ui/mismatched_types/issue-26480.stderr | 2 +- tests/ui/suggestions/suggest-null-ptr.stderr | 8 +- ...missing-associated-type-restriction.stderr | 2 +- tests/ui/traits/issue-52893.stderr | 2 +- 16 files changed, 44 insertions(+), 84 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 7038baece8165..acaed66387374 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2135,38 +2135,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Returns the parameters of a function, with their generic parameters if those are the full /// type of that parameter. - /// - /// Returns `None` if the body is not a named function (e.g. a closure). fn get_hir_param_info( &self, def_id: DefId, is_method: bool, ) -> Option<(IndexVec, FnParam<'_>)>, &hir::Generics<'_>)> { - let (sig, generics, body_id, params) = match self.tcx.hir_get_if_local(def_id)? { - hir::Node::TraitItem(&hir::TraitItem { - generics, - kind: hir::TraitItemKind::Fn(sig, trait_fn), - .. - }) => match trait_fn { - hir::TraitFn::Required(params) => (sig, generics, None, Some(params)), - hir::TraitFn::Provided(body) => (sig, generics, Some(body), None), - }, - hir::Node::ImplItem(&hir::ImplItem { - generics, - kind: hir::ImplItemKind::Fn(sig, body), - .. - }) - | hir::Node::Item(&hir::Item { - kind: hir::ItemKind::Fn { sig, generics, body, .. }, - .. - }) => (sig, generics, Some(body), None), - hir::Node::ForeignItem(&hir::ForeignItem { - kind: hir::ForeignItemKind::Fn(sig, params, generics), - .. - }) => (sig, generics, None, Some(params)), - _ => return None, - }; + let local_def_id = def_id.as_local()?; + let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id); + let sig = self.tcx.hir_fn_sig_by_hir_id(hir_id)?; + let generics = self.tcx.hir_get_generics(local_def_id)?; // Make sure to remove both the receiver and variadic argument. Both are removed // when matching parameter types. @@ -2190,29 +2168,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None } }); - let mut params_with_generics: IndexVec = match (body_id, params) { - (Some(_), Some(_)) | (None, None) => unreachable!(), - (Some(_body), None) => { - let params = sig.decl.inputs; - let params = params - .get(is_method as usize..params.len() - sig.decl.c_variadic() as usize)?; - debug_assert_eq!(params.len(), fn_inputs.len()); - fn_inputs.zip(params.iter().map(FnParam::Param)).collect() - } - (None, Some(params)) => { - let params = params - .get(is_method as usize..params.len() - sig.decl.c_variadic() as usize)?; - debug_assert_eq!(params.len(), fn_inputs.len()); - fn_inputs.zip(params.iter().map(|&ident| FnParam::Ident(ident))).collect() - } - }; + + let mut params_with_generics = + fn_inputs + .zip(sig.decl.inputs.get( + is_method as usize..sig.decl.inputs.len() - sig.decl.c_variadic() as usize, + )?) + .map(|(idx, param)| (idx, FnParam::Param(param))) + .collect::>(); for param in generics.params { if let hir::GenericParamKind::Const { arg_pos: Some(pos), .. } = param.kind && let Some(idx) = (pos as usize).checked_sub(is_method as usize) { - params_with_generics - .raw - .insert(idx, (None, FnParam::Ident(Some(param.name.ident())))); + params_with_generics.raw.insert(idx, (None, FnParam::GenericParam(param))); } } Some((params_with_generics, generics)) @@ -2242,20 +2210,15 @@ impl<'tcx> Visitor<'tcx> for FindClosureArg<'tcx> { #[derive(Clone, Copy)] enum FnParam<'hir> { Param(&'hir hir::Param<'hir>), - Ident(Option), + // For function args const generics + GenericParam(&'hir hir::GenericParam<'hir>), } impl FnParam<'_> { fn span(&self) -> Span { match self { Self::Param(param) => param.param_span, - Self::Ident(ident) => { - if let Some(ident) = ident { - ident.span - } else { - DUMMY_SP - } - } + Self::GenericParam(param) => param.span, } } @@ -2271,11 +2234,8 @@ impl FnParam<'_> { { Some(ident.name) } - FnParam::Ident(ident) - if let Some(ident) = ident - && ident.name != kw::Underscore => - { - Some(ident.name) + FnParam::GenericParam(param) if param.name.ident().name != kw::Underscore => { + Some(param.name.ident().name) } _ => None, }; diff --git a/tests/ui/argument-suggestions/extern-fn-arg-names.stderr b/tests/ui/argument-suggestions/extern-fn-arg-names.stderr index e4183e6d519ef..8204d53733aad 100644 --- a/tests/ui/argument-suggestions/extern-fn-arg-names.stderr +++ b/tests/ui/argument-suggestions/extern-fn-arg-names.stderr @@ -14,7 +14,7 @@ note: function defined here --> $DIR/extern-fn-arg-names.rs:2:8 | LL | fn dstfn(src: i32, dst: err); - | ^^^^^ --- + | ^^^^^ -------- help: provide the argument | LL | dstfn(1, /* dst */); diff --git a/tests/ui/c-variadic/variadic-ffi-1.stderr b/tests/ui/c-variadic/variadic-ffi-1.stderr index b7182887cfb78..e600bea41246e 100644 --- a/tests/ui/c-variadic/variadic-ffi-1.stderr +++ b/tests/ui/c-variadic/variadic-ffi-1.stderr @@ -20,7 +20,7 @@ note: function defined here --> $DIR/variadic-ffi-1.rs:22:8 | LL | fn foo(f: isize, x: u8, ...); - | ^^^ - - + | ^^^ -------- ----- help: provide the arguments | LL | foo(/* isize */, /* u8 */); @@ -36,7 +36,7 @@ note: function defined here --> $DIR/variadic-ffi-1.rs:22:8 | LL | fn foo(f: isize, x: u8, ...); - | ^^^ - + | ^^^ ----- help: provide the argument | LL | foo(1, /* u8 */); diff --git a/tests/ui/const-generics/function_arg_const_generics/typeck-errors.stderr b/tests/ui/const-generics/function_arg_const_generics/typeck-errors.stderr index 7ee6c024a7b07..2dfa7902c59da 100644 --- a/tests/ui/const-generics/function_arg_const_generics/typeck-errors.stderr +++ b/tests/ui/const-generics/function_arg_const_generics/typeck-errors.stderr @@ -54,7 +54,7 @@ note: function defined here --> $DIR/typeck-errors.rs:3:4 | LL | fn foo(const N: usize) -> [u8; N] { - | ^^^ - + | ^^^ -------------- error: aborting due to 5 previous errors diff --git a/tests/ui/delegation/glob-glob-conflict.stderr b/tests/ui/delegation/glob-glob-conflict.stderr index f5629bb14e9a9..e1f5ea6cd0245 100644 --- a/tests/ui/delegation/glob-glob-conflict.stderr +++ b/tests/ui/delegation/glob-glob-conflict.stderr @@ -35,7 +35,7 @@ note: method defined here | LL | trait Trait2 { LL | fn method(&self) -> u8; - | ^^^^^^ ---- + | ^^^^^^ ----- help: provide the argument | LL | reuse Trait2::*(/* value */); @@ -61,7 +61,7 @@ note: method defined here | LL | trait Trait1 { LL | fn method(&self) -> u8; - | ^^^^^^ ---- + | ^^^^^^ ----- help: provide the argument | LL | reuse Trait1::*(/* value */); diff --git a/tests/ui/delegation/self-mapping-arguments-errors.stderr b/tests/ui/delegation/self-mapping-arguments-errors.stderr index 032561ddd8816..8807283249057 100644 --- a/tests/ui/delegation/self-mapping-arguments-errors.stderr +++ b/tests/ui/delegation/self-mapping-arguments-errors.stderr @@ -59,7 +59,7 @@ note: method defined here | LL | trait MyAdd { LL | fn add(self, other: Self) -> Self; - | ^^^ ----- + | ^^^ ----------- help: provide the argument | LL ~ }({ @@ -112,7 +112,7 @@ note: method defined here | LL | trait MyAdd { LL | fn add(self, other: Box) -> Self; - | ^^^ ----- + | ^^^ ---------------- note: method provided through this `impl` --> $DIR/self-mapping-arguments-errors.rs:37:5 | diff --git a/tests/ui/delegation/self-mapping-output.stderr b/tests/ui/delegation/self-mapping-output.stderr index 90155fa62e1aa..f7c17fc76696c 100644 --- a/tests/ui/delegation/self-mapping-output.stderr +++ b/tests/ui/delegation/self-mapping-output.stderr @@ -145,7 +145,7 @@ note: method defined here | LL | trait Trait { LL | fn method(&self) -> (); - | ^^^^^^ ---- + | ^^^^^^ ----- help: consider borrowing here | LL | reuse Trait::method { &self.0 } @@ -204,7 +204,7 @@ note: method defined here | LL | trait Trait { LL | fn method(&self) -> (); - | ^^^^^^ ---- + | ^^^^^^ ----- help: consider borrowing here | LL | reuse Trait::method { &self.0 } @@ -264,7 +264,7 @@ note: method defined here | LL | trait Trait { LL | fn method(&self) -> Self; - | ^^^^^^ ---- + | ^^^^^^ ----- note: method provided through this `impl` --> $DIR/self-mapping-output.rs:242:5 | @@ -322,7 +322,7 @@ note: method defined here | LL | trait Trait { LL | fn method(&self) -> Self; - | ^^^^^^ ---- + | ^^^^^^ ----- note: method provided through this `impl` --> $DIR/self-mapping-output.rs:242:5 | @@ -380,7 +380,7 @@ note: method defined here | LL | trait Trait { LL | fn method(&self) -> Self; - | ^^^^^^ ---- + | ^^^^^^ ----- error[E0308]: mismatched types --> $DIR/self-mapping-output.rs:308:31 @@ -398,7 +398,7 @@ note: method defined here | LL | trait Trait { LL | fn method(&self) -> Self; - | ^^^^^^ ---- + | ^^^^^^ ----- error[E0616]: field `0` of struct `private::W` is private --> $DIR/self-mapping-output.rs:334:36 diff --git a/tests/ui/error-codes/E0060.stderr b/tests/ui/error-codes/E0060.stderr index 7065b623ad325..9bb5e6edbfef6 100644 --- a/tests/ui/error-codes/E0060.stderr +++ b/tests/ui/error-codes/E0060.stderr @@ -8,7 +8,7 @@ note: function defined here --> $DIR/E0060.rs:2:8 | LL | fn printf(_: *const u8, ...) -> u32; - | ^^^^^^ - + | ^^^^^^ ------------ help: provide the argument | LL | unsafe { printf(/* *const u8 */); } diff --git a/tests/ui/fn/param-mismatch-foreign.stderr b/tests/ui/fn/param-mismatch-foreign.stderr index 835e0a3343e9a..ae994bb658f25 100644 --- a/tests/ui/fn/param-mismatch-foreign.stderr +++ b/tests/ui/fn/param-mismatch-foreign.stderr @@ -8,7 +8,7 @@ note: function defined here --> $DIR/param-mismatch-foreign.rs:2:8 | LL | fn foo(x: i32, y: u32, z: i32); - | ^^^ - + | ^^^ ------ help: provide the argument | LL | foo(1i32, /* u32 */, 2i32); diff --git a/tests/ui/fn/param-mismatch-trait-fn.stderr b/tests/ui/fn/param-mismatch-trait-fn.stderr index b96c83e1bd6f4..5c5c6089f3d4d 100644 --- a/tests/ui/fn/param-mismatch-trait-fn.stderr +++ b/tests/ui/fn/param-mismatch-trait-fn.stderr @@ -14,7 +14,7 @@ note: associated function defined here | LL | trait Foo { LL | fn same_type(_: T, _: T); - | ^^^^^^^^^ - - - this parameter needs to match the `[X; 1]` type of parameter #1 + | ^^^^^^^^^ - ---- ---- this parameter needs to match the `[X; 1]` type of parameter #1 | | | | | parameter #2 needs to match the `[X; 1]` type of this parameter | parameter #1 and parameter #2 both reference this parameter `T` diff --git a/tests/ui/higher-ranked/relate-bound-region-ice-144033.stderr b/tests/ui/higher-ranked/relate-bound-region-ice-144033.stderr index 6f6c2c4feb33f..f175d99b1dcda 100644 --- a/tests/ui/higher-ranked/relate-bound-region-ice-144033.stderr +++ b/tests/ui/higher-ranked/relate-bound-region-ice-144033.stderr @@ -46,7 +46,7 @@ note: method defined here | LL | trait FooMut { LL | fn bar(self, _: I) - | ^^^ - + | ^^^ ---- error: aborting due to 2 previous errors diff --git a/tests/ui/methods/issues/issue-61525.stderr b/tests/ui/methods/issues/issue-61525.stderr index 3a3e103098ccf..d1c5e8adfcc9e 100644 --- a/tests/ui/methods/issues/issue-61525.stderr +++ b/tests/ui/methods/issues/issue-61525.stderr @@ -34,7 +34,7 @@ note: method defined here | LL | pub trait Example { LL | fn query(self, q: Q); - | ^^^^^ - + | ^^^^^ ---- error: aborting due to 2 previous errors diff --git a/tests/ui/mismatched_types/issue-26480.stderr b/tests/ui/mismatched_types/issue-26480.stderr index ec91caed5e940..8e2683850c5f1 100644 --- a/tests/ui/mismatched_types/issue-26480.stderr +++ b/tests/ui/mismatched_types/issue-26480.stderr @@ -15,7 +15,7 @@ note: function defined here --> $DIR/issue-26480.rs:2:8 | LL | fn write(fildes: i32, buf: *const i8, nbyte: u64) -> i64; - | ^^^^^ ----- + | ^^^^^ ---------- help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit | LL | ($arr.len() * size_of($arr[0])).try_into().unwrap()); diff --git a/tests/ui/suggestions/suggest-null-ptr.stderr b/tests/ui/suggestions/suggest-null-ptr.stderr index 5be33d47237d2..bdc625c49c5b1 100644 --- a/tests/ui/suggestions/suggest-null-ptr.stderr +++ b/tests/ui/suggestions/suggest-null-ptr.stderr @@ -12,7 +12,7 @@ note: function defined here --> $DIR/suggest-null-ptr.rs:7:8 | LL | fn foo(ptr: *const u8); - | ^^^ --- + | ^^^ -------------- help: if you meant to create a null pointer, use `std::ptr::null()` | LL - foo(0); @@ -33,7 +33,7 @@ note: function defined here --> $DIR/suggest-null-ptr.rs:9:8 | LL | fn foo_mut(ptr: *mut u8); - | ^^^^^^^ --- + | ^^^^^^^ ------------ help: if you meant to create a null pointer, use `std::ptr::null_mut()` | LL - foo_mut(0); @@ -54,7 +54,7 @@ note: function defined here --> $DIR/suggest-null-ptr.rs:11:8 | LL | fn usize(ptr: *const usize); - | ^^^^^ --- + | ^^^^^ ----------------- help: if you meant to create a null pointer, use `std::ptr::null()` | LL - usize(0); @@ -75,7 +75,7 @@ note: function defined here --> $DIR/suggest-null-ptr.rs:13:8 | LL | fn usize_mut(ptr: *mut usize); - | ^^^^^^^^^ --- + | ^^^^^^^^^ --------------- help: if you meant to create a null pointer, use `std::ptr::null_mut()` | LL - usize_mut(0); diff --git a/tests/ui/suggestions/trait-with-missing-associated-type-restriction.stderr b/tests/ui/suggestions/trait-with-missing-associated-type-restriction.stderr index 196eafa5bba68..71befa7023745 100644 --- a/tests/ui/suggestions/trait-with-missing-associated-type-restriction.stderr +++ b/tests/ui/suggestions/trait-with-missing-associated-type-restriction.stderr @@ -100,7 +100,7 @@ note: method defined here LL | trait Trait { ... LL | fn funk(&self, _: Self::A); - | ^^^^ - + | ^^^^ ---------- help: consider constraining the associated type `>::A` to `{integer}` | LL | fn bar2>(x: T) { diff --git a/tests/ui/traits/issue-52893.stderr b/tests/ui/traits/issue-52893.stderr index 565a9fbc788af..6ce265a8c2a18 100644 --- a/tests/ui/traits/issue-52893.stderr +++ b/tests/ui/traits/issue-52893.stderr @@ -24,7 +24,7 @@ note: method defined here LL | trait Push { LL | type PushRes; LL | fn push(self, other: T) -> Self::PushRes; - | ^^^^ ----- + | ^^^^ -------- error: aborting due to 1 previous error From b162fd22044f456754e7230da4c1f5c2859d3cce Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 9 Oct 2026 14:37:17 +0200 Subject: [PATCH 09/16] Remove idents argument from `TraitFn::Required` --- compiler/rustc_ast_lowering/src/item.rs | 8 +----- compiler/rustc_hir/src/hir.rs | 12 ++++----- compiler/rustc_hir/src/intravisit.rs | 5 +--- compiler/rustc_hir/src/target_impls.rs | 2 +- .../rustc_hir_analysis/src/check/check.rs | 2 +- .../rustc_hir_analysis/src/collect/dump.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 2 +- .../rustc_hir_typeck/src/method/suggest.rs | 25 +++++++------------ compiler/rustc_lint/src/nonstandard_style.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_passes/src/reachable.rs | 4 +-- compiler/rustc_privacy/src/lib.rs | 2 +- .../src/error_reporting/traits/suggestions.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- .../clippy/clippy_lints/src/attrs/mod.rs | 2 +- .../clippy_lints/src/excessive_bools.rs | 2 +- .../src/inline_fn_without_body.rs | 2 +- .../clippy/clippy_lints/src/lifetimes.rs | 24 ++++++------------ .../clippy/clippy_lints/src/types/mod.rs | 2 +- 19 files changed, 39 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index eaddaeb194467..9605ed86cce60 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -854,7 +854,6 @@ impl<'hir> LoweringContext<'_, 'hir> { AssocItemKind::Fn(Fn { sig, ident, generics, body: None, define_opaque, .. }) => { // FIXME(contracts): Deny contract here since it won't apply to // any impl method or callees. - let idents = self.lower_fn_params_to_idents(&sig.decl); let params = sig .decl .inputs @@ -879,12 +878,7 @@ impl<'hir> LoweringContext<'_, 'hir> { "only trait methods with default bodies can define opaque types", ); } - ( - *ident, - generics, - hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(idents)), - false, - ) + (*ident, generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required), false) } AssocItemKind::Fn(Fn { sig, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index b20541623451a..3826e3b6302a3 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3068,7 +3068,7 @@ impl<'hir> TraitItem<'hir> { expect_const, (&'hir Ty<'hir>, Option>), TraitItemKind::Const(ty, rhs), (ty, *rhs); - expect_fn, (&FnSig<'hir>, &TraitFn<'hir>), + expect_fn, (&FnSig<'hir>, &TraitFn), TraitItemKind::Fn(ty, trfn), (ty, trfn); expect_type, (GenericBounds<'hir>, Option<&'hir Ty<'hir>>), @@ -3078,9 +3078,9 @@ impl<'hir> TraitItem<'hir> { /// Represents a trait method's body (or just argument names). #[derive(Debug, Clone, Copy, StableHash)] -pub enum TraitFn<'hir> { +pub enum TraitFn { /// No default body in the trait, just a signature. - Required(&'hir [Option]), + Required, /// Both signature and body are provided in the trait. Provided(BodyId), @@ -3092,7 +3092,7 @@ pub enum TraitItemKind<'hir> { /// An associated constant with an optional value (otherwise `impl`s must contain a value). Const(&'hir Ty<'hir>, Option>), /// An associated function with an optional body. - Fn(FnSig<'hir>, TraitFn<'hir>), + Fn(FnSig<'hir>, TraitFn), /// An associated type with (possibly empty) bounds and optional concrete /// type. Type(GenericBounds<'hir>, Option<&'hir Ty<'hir>>), @@ -5396,8 +5396,8 @@ mod size_asserts { static_assert_size!(Stmt<'_>, 32); static_assert_size!(StmtKind<'_>, 16); static_assert_size!(TraitImplHeader<'_>, 48); - static_assert_size!(TraitItem<'_>, 88); - static_assert_size!(TraitItemKind<'_>, 48); + static_assert_size!(TraitItem<'_>, 80); + static_assert_size!(TraitItemKind<'_>, 40); static_assert_size!(Ty<'_>, 48); static_assert_size!(TyKind<'_>, 32); // tidy-alphabetical-end diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index f7d5d45184e3f..ff73bd8ada8df 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1314,11 +1314,8 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>( try_visit!(visitor.visit_ty_unambig(ty)); visit_opt!(visitor, visit_const_item_rhs, default); } - TraitItemKind::Fn(ref sig, TraitFn::Required(param_idents)) => { + TraitItemKind::Fn(ref sig, TraitFn::Required) => { try_visit!(visitor.visit_fn_decl(sig.decl)); - for ident in param_idents.iter().copied() { - visit_opt!(visitor, visit_ident, ident); - } } TraitItemKind::Fn(ref sig, TraitFn::Provided(body_id)) => { try_visit!(visitor.visit_fn( diff --git a/compiler/rustc_hir/src/target_impls.rs b/compiler/rustc_hir/src/target_impls.rs index f98a6caaa5e66..87e7a443de622 100644 --- a/compiler/rustc_hir/src/target_impls.rs +++ b/compiler/rustc_hir/src/target_impls.rs @@ -29,7 +29,7 @@ impl From<&hir::TraitItem<'_>> for Target { fn from(trait_item: &hir::TraitItem<'_>) -> Target { match trait_item.kind { TraitItemKind::Const(..) => Target::AssocConst(AssocCtxt::Trait), - TraitItemKind::Fn(_, hir::TraitFn::Required(_)) => { + TraitItemKind::Fn(_, hir::TraitFn::Required) => { Target::Method(MethodKind::Trait { body: false }) } TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => { diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index ea0840ff1e893..9643025f6a61a 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -935,7 +935,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. } = origin && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id) - && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() + && let (_, hir::TraitFn::Required) = trait_item.expect_fn() { // Skip opaques from RPIT in traits with no default body. } else { diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index 9bf62e2846b9d..23560c5a4d1ca 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -60,7 +60,7 @@ pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) { | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. } = tcx.hir_expect_opaque_ty(id).origin && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id) - && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() + && let (_, hir::TraitFn::Required) = trait_item.expect_fn() { continue; } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 7b54784442404..57c636936b0b3 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -981,7 +981,7 @@ impl<'a> State<'a> { hir::TraitItemKind::Const(ty, default) => { self.print_associated_const(ti.ident, ti.generics, ty, default); } - hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(_)) => { + hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required) => { self.print_method_sig(ti.ident, sig, ti.generics); self.word(";"); } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index ebd026741d1ff..5d845431148eb 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -4465,25 +4465,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .as_local() .map(|def_id| self.tcx.hir_node_by_def_id(def_id)); if let Some(hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(fn_sig, method), + kind: hir::TraitItemKind::Fn(fn_sig, _), .. })) = id { - let self_first_arg = match method { - hir::TraitFn::Required([ident, ..]) => { - matches!(ident, Some(Ident { name: kw::SelfLower, .. })) - } - hir::TraitFn::Provided(_body_id) => { - fn_sig.decl.inputs.first().is_some_and(|param| { - matches!( - param.pat.kind, - hir::PatKind::Binding(_, _, ident, _) - if ident.name == kw::SelfLower - ) - }) - } - _ => false, - }; + let self_first_arg = + fn_sig.decl.inputs.first().is_some_and(|param| { + matches!( + param.pat.kind, + hir::PatKind::Binding(_, _, ident, _) + if ident.name == kw::SelfLower + ) + }); if !fn_sig.decl.implicit_self().has_implicit_self() && self_first_arg diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 5202ae61cedac..0f915aca524fd 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -418,7 +418,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { } fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &hir::TraitItem<'_>) { - if let hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_)) = item.kind { + if let hir::TraitItemKind::Fn(_, hir::TraitFn::Required) = item.kind { self.check_snake_case(cx, "trait method", &item.ident); } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index c92b26e5c5b21..4f19d686880af 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1303,7 +1303,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> if let hir::OpaqueTyOrigin::FnReturn { parent, .. } | hir::OpaqueTyOrigin::AsyncFn { parent, .. } = origin && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(parent) - && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() + && let (_, hir::TraitFn::Required) = trait_item.expect_fn() { false } else { diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 1bd2ca7792e7e..16eaaefb75262 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -146,7 +146,7 @@ impl<'tcx> ReachableContext<'tcx> { Node::TraitItem(trait_method) => match trait_method.kind { hir::TraitItemKind::Const(_, ref default) => default.is_some(), hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => true, - hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_)) + hir::TraitItemKind::Fn(_, hir::TraitFn::Required) | hir::TraitItemKind::Type(..) => false, }, Node::ImplItem(impl_item) => match impl_item.kind { @@ -267,7 +267,7 @@ impl<'tcx> ReachableContext<'tcx> { Node::TraitItem(trait_method) => { match trait_method.kind { hir::TraitItemKind::Const(_, None) - | hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_)) => { + | hir::TraitItemKind::Fn(_, hir::TraitFn::Required) => { // Keep going, nothing to get exported } hir::TraitItemKind::Const(_, Some(rhs)) => self.visit_const_item_rhs(rhs), diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 326e62708107f..44e128a34dad1 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1819,7 +1819,7 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities { parent, in_trait_or_impl: Some(hir::RpitContext::Trait), } => match tcx.hir_node_by_def_id(parent).expect_trait_item().expect_fn().1 { - hir::TraitFn::Required(_) => false, + hir::TraitFn::Required => false, hir::TraitFn::Provided(..) => true, }, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index f18df72fc2b4d..f388c1193b420 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -7096,7 +7096,7 @@ impl<'tcx> TypeFolder> for ReplaceImplTraitFolder<'tcx> { pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>( tcx: TyCtxt<'tcx>, sig: hir::FnSig<'tcx>, - body: hir::TraitFn<'tcx>, + body: hir::TraitFn, opaque_def_id: LocalDefId, add_bounds: &str, ) -> Option> { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 399b75fb06e21..69e6e7d28bad2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1280,7 +1280,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext hir::TraitFn::Provided(_) => { Some(Defaultness::from_trait_item(trait_item.defaultness)) } - hir::TraitFn::Required(_) => None, + hir::TraitFn::Required => None, }; let (generics, decl) = clean_function(cx, sig, trait_item.generics, local_did); ItemKind::AssocFunction(Box::new(AssocFunction { generics, decl, body })) diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index aa0fa3117d535..3c5a022def403 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -614,7 +614,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { if let TraitItemKind::Fn(_, kind) = item.kind { let body = match kind { - TraitFn::Required(_) => None, + TraitFn::Required => None, TraitFn::Provided(body) => Some(body), }; inline_always::check(cx, item.span, item.ident.name, cx.tcx.hir_attrs(item.hir_id()), body); diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs index 5ea0c2dbf5e61..da365eb53a20b 100644 --- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs +++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs @@ -167,7 +167,7 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'tcx>) { // functions with a body are already checked by `check_fn` - if let TraitItemKind::Fn(fn_sig, TraitFn::Required(_)) = &trait_item.kind + if let TraitItemKind::Fn(fn_sig, TraitFn::Required) = &trait_item.kind && fn_sig.header.abi == ExternAbi::Rust && fn_sig.decl.inputs.len() as u64 > self.max_fn_params_bools { diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs index 9ae34010f927e..9a5ee87f333b9 100644 --- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs +++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs @@ -30,7 +30,7 @@ declare_lint_pass!(InlineFnWithoutBody => [INLINE_FN_WITHOUT_BODY]); impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { - if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind + if let TraitItemKind::Fn(_, TraitFn::Required) = item.kind && let Some(attr_span) = find_attr!(cx .tcx .hir_attrs(item.hir_id()), diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 5bb73e4cc5048..9ea3cec958335 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -149,7 +149,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { .. } = item.kind { - check_fn_inner(cx, sig, Some(id), None, generics, item.span, true, self.msrv, || { + check_fn_inner(cx, sig, Some(id), generics, item.span, true, self.msrv, || { is_from_proc_macro(cx, item) }); } else if let ItemKind::Impl(impl_) = &item.kind @@ -173,7 +173,6 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { cx, sig, Some(id), - None, item.generics, item.span, report_extra_lifetimes, @@ -185,15 +184,14 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { if let TraitItemKind::Fn(ref sig, ref body) = item.kind { - let (body, trait_sig) = match *body { - TraitFn::Required(sig) => (None, Some(sig)), - TraitFn::Provided(id) => (Some(id), None), + let body = match *body { + TraitFn::Required => None, + TraitFn::Provided(id) => Some(id), }; check_fn_inner( cx, sig, body, - trait_sig, item.generics, item.span, true, @@ -209,7 +207,6 @@ fn check_fn_inner<'tcx>( cx: &LateContext<'tcx>, sig: &'tcx FnSig<'_>, body: Option, - trait_sig: Option<&[Option]>, generics: &'tcx Generics<'_>, span: Span, report_extra_lifetimes: bool, @@ -266,7 +263,7 @@ fn check_fn_inner<'tcx>( } } - let elidable = could_use_elision(cx, sig.decl, body, trait_sig, generics.params, msrv); + let elidable = could_use_elision(cx, sig.decl, body, generics.params, msrv); let has_elidable_lts = elidable .as_ref() .is_some_and(|(_, usages)| !usages.iter().any(|usage| usage.ident.span.ctxt() != span.ctxt())); @@ -294,7 +291,6 @@ fn could_use_elision<'tcx>( cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, body: Option, - trait_sig: Option<&[Option]>, named_generics: &'tcx [GenericParam<'_>], msrv: Msrv, ) -> Option<(Vec, Vec)> { @@ -330,18 +326,12 @@ fn could_use_elision<'tcx>( let input_lts = input_visitor.lts; let output_lts = output_visitor.lts; - if let Some(&[trait_sig]) = trait_sig - && non_elidable_self_type(cx, func, trait_sig, msrv) - { + let first_ident = func.inputs.first().and_then(|param| param.pat.simple_ident()); + if non_elidable_self_type(cx, func, first_ident, msrv) { return None; } if let Some(body_id) = body { - let first_ident = func.inputs.first().and_then(|param| param.pat.simple_ident()); - if non_elidable_self_type(cx, func, first_ident, msrv) { - return None; - } - let mut checker = BodyLifetimeChecker::new(cx); let body = cx.tcx.hir_body(body_id); if checker.visit_expr(body.value).is_break() { diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index 949b9de7d311f..e4d2a3409d5c6 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -519,7 +519,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { TraitItemKind::Fn(ref sig, trait_method) => { // Check only methods without body // Methods with body are covered by check_fn. - if let TraitFn::Required(_) = trait_method { + if let TraitFn::Required = trait_method { self.check_fn_decl(cx, sig.decl, context); } }, From 0e49a04b3455f70a8533eeca598b2d7cc3ee6944 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 9 Oct 2026 14:42:05 +0200 Subject: [PATCH 10/16] Remove idents argument from `ForeignItemKind::Fn` --- compiler/rustc_ast_lowering/src/item.rs | 26 +++++++------------ compiler/rustc_ast_lowering/src/lib.rs | 17 ------------ compiler/rustc_hir/src/hir.rs | 18 ++++++------- compiler/rustc_hir/src/intravisit.rs | 5 +--- compiler/rustc_hir_analysis/src/collect.rs | 2 +- .../src/collect/clauses_of.rs | 2 +- .../src/collect/resolve_bound_vars.rs | 2 +- .../rustc_hir_analysis/src/collect/type_of.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 2 +- compiler/rustc_lint/src/lifetime_syntax.rs | 2 +- compiler/rustc_lint/src/runtime_symbols.rs | 2 +- .../rustc_lint/src/types/improper_ctypes.rs | 2 +- .../traits/fulfillment_errors.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- 14 files changed, 29 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 9605ed86cce60..b1318505c8afa 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -620,25 +620,20 @@ impl<'hir> LoweringContext<'_, 'hir> { ForeignItemKind::Fn(Fn { sig, ident, generics, define_opaque, .. }) => { let fdec = &sig.decl; let itctx = ImplTraitContext::Universal; - let (generics, (decl, fn_args)) = self.lower_generics(generics, itctx, |this| { + let (generics, decl) = self.lower_generics(generics, itctx, |this| { let params = fdec .inputs .iter() .filter(|p| !p.is_const_param()) - .map(|x| this.lower_param(x)) - .collect(); - ( - // Disallow `impl Trait` in foreign items. - // Parameters are discarded because foreign functions don't have a body - this.lower_fn_decl( - fdec, - i.id, - FnDeclKind::ExternFn, - None, - DiscardParams::Yes, - params, - ), - this.lower_fn_params_to_idents(fdec), + .map(|x| this.lower_param(x)).collect(); + // Disallow `impl Trait` in foreign items. + this.lower_fn_decl( + fdec, + i.id, + FnDeclKind::ExternFn, + None, + DiscardParams::Yes, + params, ) }); @@ -653,7 +648,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ident, hir::ForeignItemKind::Fn( hir::FnSig { header, decl, span: self.lower_span(sig.span) }, - fn_args, generics, ), ) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 384542a6199fc..cedae167bded3 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1900,23 +1900,6 @@ impl<'hir> LoweringContext<'_, 'hir> { })) } - fn lower_fn_params_to_idents(&mut self, decl: &FnDecl) -> &'hir [Option] { - self.arena.alloc_from_iter(decl.inputs.iter().filter(|param| !param.is_const_param()).map( - |param| match param.pat.kind { - PatKind::Missing => None, - PatKind::Ident(_, ident, _) => Some(self.lower_ident(ident)), - PatKind::Wild => Some(Ident::new(kw::Underscore, self.lower_span(param.pat.span))), - _ => { - self.dcx().span_delayed_bug( - param.pat.span, - "non-missing/ident/wild param pat must trigger an error", - ); - None - } - }, - )) - } - /// Lowers a function declaration. /// /// `decl`: the unlowered (AST) function declaration. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 3826e3b6302a3..8608b8adf1b9a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4878,7 +4878,7 @@ pub enum ForeignItemKind<'hir> { /// `&[Option]` is used because of code paths shared with `TraitFn` /// and `FnPtrTy`. The sharing is due to all of these cases not allowing /// arbitrary patterns for parameters. - Fn(FnSig<'hir>, &'hir [Option], &'hir Generics<'hir>), + Fn(FnSig<'hir>, &'hir Generics<'hir>), /// A foreign static item (`static ext: u8`). Static(&'hir Ty<'hir>, Mutability, Safety), /// A foreign type. @@ -4934,7 +4934,7 @@ impl<'hir> OwnerNode<'hir> { | OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) | OwnerNode::Item(Item { kind: ItemKind::Fn { sig: fn_sig, .. }, .. }) | OwnerNode::ForeignItem(ForeignItem { - kind: ForeignItemKind::Fn(fn_sig, _, _), .. + kind: ForeignItemKind::Fn(fn_sig, _), .. }) => Some(fn_sig), _ => None, } @@ -4946,7 +4946,7 @@ impl<'hir> OwnerNode<'hir> { | OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) | OwnerNode::Item(Item { kind: ItemKind::Fn { sig: fn_sig, .. }, .. }) | OwnerNode::ForeignItem(ForeignItem { - kind: ForeignItemKind::Fn(fn_sig, _, _), .. + kind: ForeignItemKind::Fn(fn_sig, _), .. }) => Some(fn_sig.decl), _ => None, } @@ -5154,7 +5154,7 @@ impl<'hir> Node<'hir> { Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. }) | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) | Node::Item(Item { kind: ItemKind::Fn { sig: fn_sig, .. }, .. }) - | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_sig, _, _), .. }) => { + | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_sig, _), .. }) => { Some(fn_sig.decl) } Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl, .. }), .. }) => { @@ -5182,7 +5182,7 @@ impl<'hir> Node<'hir> { Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. }) | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) | Node::Item(Item { kind: ItemKind::Fn { sig: fn_sig, .. }, .. }) - | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_sig, _, _), .. }) => { + | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_sig, _), .. }) => { Some(fn_sig) } _ => None, @@ -5275,9 +5275,7 @@ impl<'hir> Node<'hir> { pub fn generics(self) -> Option<&'hir Generics<'hir>> { match self { - Node::ForeignItem(ForeignItem { - kind: ForeignItemKind::Fn(_, _, generics), .. - }) + Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(_, generics), .. }) | Node::TraitItem(TraitItem { generics, .. }) | Node::ImplItem(ImplItem { generics, .. }) => Some(generics), Node::Item(item) => item.kind.generics(), @@ -5375,8 +5373,8 @@ mod size_asserts { static_assert_size!(Expr<'_>, 64); static_assert_size!(ExprKind<'_>, 48); static_assert_size!(FnDecl<'_>, 40); - static_assert_size!(ForeignItem<'_>, 88); - static_assert_size!(ForeignItemKind<'_>, 56); + static_assert_size!(ForeignItem<'_>, 72); + static_assert_size!(ForeignItemKind<'_>, 40); static_assert_size!(GenericArg<'_>, 16); static_assert_size!(GenericBound<'_>, 64); static_assert_size!(Generics<'_>, 56); diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index ff73bd8ada8df..8ef3aa5b48e53 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -694,12 +694,9 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>( try_visit!(visitor.visit_ident(*ident)); match *kind { - ForeignItemKind::Fn(ref sig, param_idents, ref generics) => { + ForeignItemKind::Fn(ref sig, ref generics) => { try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_fn_decl(sig.decl)); - for ident in param_idents.iter().copied() { - visit_opt!(visitor, visit_ident, ident); - } } ForeignItemKind::Static(ref typ, _, _) => { try_visit!(visitor.visit_ty_unambig(typ)); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 8f329dfd84e97..94b2d8f9e075a 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1245,7 +1245,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn None, ), - ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(sig, _, _), .. }) => { + ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(sig, _), .. }) => { let abi = tcx.hir_get_foreign_abi(hir_id); compute_sig_of_foreign_fn_decl(tcx, def_id, sig.decl, abi, sig.header.safety()) } diff --git a/compiler/rustc_hir_analysis/src/collect/clauses_of.rs b/compiler/rustc_hir_analysis/src/collect/clauses_of.rs index ba1c1197bee92..8c1442e64542c 100644 --- a/compiler/rustc_hir_analysis/src/collect/clauses_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/clauses_of.rs @@ -1074,7 +1074,7 @@ pub(super) fn const_conditions<'tcx>( _ => bug!("const_conditions called on wrong item: {def_id:?}"), }, Node::ForeignItem(item) => match item.kind { - hir::ForeignItemKind::Fn(_, _, generics) => (generics, None, false), + hir::ForeignItemKind::Fn(_, generics) => (generics, None, false), _ => bug!("const_conditions called on wrong item: {def_id:?}"), }, Node::OpaqueTy(opaque) => match opaque.origin { diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index fd3315a3fafa1..dbff232f22c5b 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -714,7 +714,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { match item.kind { - hir::ForeignItemKind::Fn(_, _, generics) => { + hir::ForeignItemKind::Fn(_, generics) => { self.visit_early_late(item.hir_id(), generics, |this| { intravisit::walk_foreign_item(this, item); }) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 6439a3fb36b4d..89dde36bb62b8 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -225,7 +225,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ Node::OpaqueTy(..) => tcx.type_of_opaque(def_id).instantiate_identity().skip_norm_wip(), Node::ForeignItem(foreign_item) => match foreign_item.kind { - ForeignItemKind::Fn(_, _, _generics) => { + ForeignItemKind::Fn(_, _generics) => { new_bound_fn_def(foreign_item.hir_id(), def_id.to_def_id()) } ForeignItemKind::Static(ty, _, _) => { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 57c636936b0b3..ab86a0ea5faa9 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -518,7 +518,7 @@ impl<'a> State<'a> { self.maybe_print_comment(item.span.lo()); self.print_attrs(self.attrs(item.hir_id())); match item.kind { - hir::ForeignItemKind::Fn(sig, _, generics) => { + hir::ForeignItemKind::Fn(sig, generics) => { let (cb, ib) = self.head(""); self.print_fn(sig.header, Some(item.ident.name), generics, sig.decl); self.end(ib); diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs index 5f747fdd63b34..74c6755384166 100644 --- a/compiler/rustc_lint/src/lifetime_syntax.rs +++ b/compiler/rustc_lint/src/lifetime_syntax.rs @@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for LifetimeSyntax { #[instrument(skip_all)] fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, fi: &'tcx hir::ForeignItem<'tcx>) { match fi.kind { - hir::ForeignItemKind::Fn(fn_sig, _idents, _generics) => check_fn_like(cx, fn_sig.decl), + hir::ForeignItemKind::Fn(fn_sig, _generics) => check_fn_like(cx, fn_sig.decl), hir::ForeignItemKind::Static(..) => {} hir::ForeignItemKind::Type => {} } diff --git a/compiler/rustc_lint/src/runtime_symbols.rs b/compiler/rustc_lint/src/runtime_symbols.rs index a49a69ceb8d26..462403e48553b 100644 --- a/compiler/rustc_lint/src/runtime_symbols.rs +++ b/compiler/rustc_lint/src/runtime_symbols.rs @@ -122,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for RuntimeSymbols { let symbol_name = cx.tcx.symbol_name(instance); match item.kind { - ForeignItemKind::Fn(fn_sig, _idents, _generics) => { + ForeignItemKind::Fn(fn_sig, _generics) => { check_fn(cx, &symbol_name.name, fn_sig, did); } ForeignItemKind::Static(..) => { diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs index 7ace026a28ce3..df3c082d424f5 100644 --- a/compiler/rustc_lint/src/types/improper_ctypes.rs +++ b/compiler/rustc_lint/src/types/improper_ctypes.rs @@ -1247,7 +1247,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint { let abi = cx.tcx.hir_get_foreign_abi(it.hir_id()); match it.kind { - hir::ForeignItemKind::Fn(sig, _, _) => { + hir::ForeignItemKind::Fn(sig, _) => { // fnptrs are a special case, they always need to be treated as // "the element rendered unsafe" because their unsafety doesn't affect // their surroundings, and their type is often declared inline diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 0cd3c0f4f18bf..7cf734cce66cb 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -3902,7 +3902,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { kind: hir::TraitItemKind::Fn(ref sig, _), .. }) | Node::ForeignItem(&hir::ForeignItem { - kind: hir::ForeignItemKind::Fn(ref sig, _, _), + kind: hir::ForeignItemKind::Fn(ref sig, _), .. }) => ( sig.span, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 69e6e7d28bad2..1a92abc894940 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -3313,7 +3313,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>( let def_id = item.owner_id.to_def_id(); cx.with_param_env(def_id, |cx| { let kind = match item.kind { - hir::ForeignItemKind::Fn(sig, _, generics) => { + hir::ForeignItemKind::Fn(sig, generics) => { let (generics, decl) = clean_function(cx, &sig, generics, def_id); ItemKind::ForeignFunction( Box::new(Function { generics, decl }), From 8f4e22c95ee451a3bcd4287874b0f1bb2d15c05c Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 9 Oct 2026 16:16:43 +0200 Subject: [PATCH 11/16] Move `fn_has_body` to `FnDeclFlags` This improves performance :) --- .../rustc_ast_lowering/src/delegation/mod.rs | 6 ++--- compiler/rustc_ast_lowering/src/expr.rs | 3 +-- .../rustc_ast_lowering/src/expr/closure.rs | 21 +++------------ compiler/rustc_ast_lowering/src/item.rs | 25 +++++++---------- compiler/rustc_ast_lowering/src/lib.rs | 22 ++++----------- compiler/rustc_hir/src/hir.rs | 27 ++++++++++++++++--- compiler/rustc_hir/src/intravisit.rs | 2 +- .../src/collect/resolve_bound_vars.rs | 2 +- compiler/rustc_hir_typeck/src/writeback.rs | 2 +- compiler/rustc_passes/src/dead.rs | 2 +- 10 files changed, 49 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/delegation/mod.rs b/compiler/rustc_ast_lowering/src/delegation/mod.rs index a4d458359d884..869199eb4d5ee 100644 --- a/compiler/rustc_ast_lowering/src/delegation/mod.rs +++ b/compiler/rustc_ast_lowering/src/delegation/mod.rs @@ -172,8 +172,8 @@ impl<'hir> LoweringContext<'_, 'hir> { .set_lifetime_elision_allowed(true) .set_c_variadic(c_variadic) .set_splatted(splatted, inputs.len()) - .unwrap(), - fn_has_body: true, + .unwrap() + .set_has_body(true), }) } @@ -581,7 +581,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, delegation: &Delegation, ) -> DelegationResults<'hir> { - let decl = self.arena.alloc(hir::FnDecl::dummy(span)); + let decl = self.arena.alloc(hir::FnDecl::dummy(span, true)); let header = self.generate_header_error(); let sig = hir::FnSig { decl, header, span }; diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index e0c0b52c92923..e2c94f5f1f782 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -918,8 +918,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let fn_decl = self.arena.alloc(hir::FnDecl { inputs, output, - fn_decl_kind: hir::FnDeclFlags::default(), - fn_has_body: true, + fn_decl_kind: hir::FnDeclFlags::default().set_has_body(true), }); let (_, body) = self.lower_body(move |this| { diff --git a/compiler/rustc_ast_lowering/src/expr/closure.rs b/compiler/rustc_ast_lowering/src/expr/closure.rs index 392d895140b4c..b8c97bbf9099a 100644 --- a/compiler/rustc_ast_lowering/src/expr/closure.rs +++ b/compiler/rustc_ast_lowering/src/expr/closure.rs @@ -6,8 +6,8 @@ use rustc_hir::HirId; use rustc_span::{Span, span_bug}; use super::{LoweringContext, MoveExprState}; +use crate::FnDeclKind; use crate::diagnostics::{ClosureCannotBeStatic, CoroutineTooManyParameters}; -use crate::{DiscardParams, FnDeclKind}; impl<'hir> LoweringContext<'_, 'hir> { // Entry point for `ExprKind::Closure`. Plain closures go through @@ -205,14 +205,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params); // Lower outside new scope to preserve `is_in_loop_condition`. - let fn_decl = self.lower_fn_decl( - decl, - closure_id, - FnDeclKind::Closure, - None, - DiscardParams::No, - params, - ); + let fn_decl = self.lower_fn_decl(decl, closure_id, FnDeclKind::Closure, None, true, params); let c = self.arena.alloc(hir::Closure { def_id: closure_def_id, @@ -332,14 +325,8 @@ impl<'hir> LoweringContext<'_, 'hir> { // We need to lower the declaration outside the new scope, because we // have to conserve the state of being inside a loop condition for the // closure argument types. - let fn_decl = self.lower_fn_decl( - &decl, - closure_id, - FnDeclKind::Closure, - None, - DiscardParams::No, - parameters, - ); + let fn_decl = + self.lower_fn_decl(&decl, closure_id, FnDeclKind::Closure, None, true, parameters); if let Const::Yes(span) = constness { self.dcx().span_err(span, "const coroutines are not supported"); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index b1318505c8afa..2bb69dc10c239 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -19,8 +19,8 @@ use super::diagnostics::{ }; use super::stability::{enabled_names, gate_unstable_abi}; use super::{ - DiscardParams, FnDeclKind, GenericArgsMode, ImplTraitContext, ImplTraitPosition, - LoweringContext, ParamMode, RelaxedBoundForbiddenReason, RelaxedBoundPolicy, + FnDeclKind, GenericArgsMode, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, + RelaxedBoundForbiddenReason, RelaxedBoundPolicy, }; use crate::diagnostics::{ConstComptimeFn, ResolvingRestrictionKind, RestrictionAncestorOnly}; @@ -282,7 +282,7 @@ impl<'hir> LoweringContext<'_, 'hir> { id, FnDeclKind::Fn, coroutine_marker, - if body.is_none() { DiscardParams::Yes } else { DiscardParams::No }, + body.is_some(), params, ) }); @@ -627,14 +627,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .filter(|p| !p.is_const_param()) .map(|x| this.lower_param(x)).collect(); // Disallow `impl Trait` in foreign items. - this.lower_fn_decl( - fdec, - i.id, - FnDeclKind::ExternFn, - None, - DiscardParams::Yes, - params, - ) + this.lower_fn_decl(fdec, i.id, FnDeclKind::ExternFn, None, false, params) }); // Unmarked safety in unsafe block defaults to unsafe. @@ -863,7 +856,7 @@ impl<'hir> LoweringContext<'_, 'hir> { sig.header.coroutine_marker, attrs, // Parameters are discarded for functions without a body - DiscardParams::Yes, + false, params, ); if define_opaque.is_some() { @@ -900,7 +893,7 @@ impl<'hir> LoweringContext<'_, 'hir> { FnDeclKind::Trait, sig.header.coroutine_marker, attrs, - DiscardParams::No, + true, params, ); self.lower_define_opaque(hir_id, &define_opaque); @@ -1115,7 +1108,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent }, sig.header.coroutine_marker, attrs, - if body.is_none() { DiscardParams::Yes } else { DiscardParams::No }, + body.is_some(), params, ); self.lower_define_opaque(hir_id, &define_opaque); @@ -1564,13 +1557,13 @@ impl<'hir> LoweringContext<'_, 'hir> { kind: FnDeclKind, coroutine_marker: Option, attrs: &[rustc_attr_ir::Attribute], - discard_params: DiscardParams, + has_body: bool, inputs: Vec>, ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { let header = self.lower_fn_header(sig.header, hir::Safety::Safe, attrs); let itctx = ImplTraitContext::Universal; let (generics, decl) = self.lower_generics(generics, itctx, |this| { - this.lower_fn_decl(&sig.decl, node_id, kind, coroutine_marker, discard_params, inputs) + this.lower_fn_decl(&sig.decl, node_id, kind, coroutine_marker, has_body, inputs) }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index cedae167bded3..22412ed7c0d80 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -812,14 +812,6 @@ enum GenericArgsMode { Silence, } -#[derive(Debug, Copy, Clone)] -enum DiscardParams { - /// Should be used for functions without a body. Lowers the attributes on the parameter and then discards them. - Yes, - /// Should be used for functions with a body. Does not lower the attributes, as lowering of the parameters is done by `lower_body`. - No, -} - impl<'hir> LoweringContext<'_, 'hir> { fn create_def( &mut self, @@ -1575,7 +1567,7 @@ impl<'hir> LoweringContext<'_, 'hir> { t.id, FnDeclKind::Pointer, None, - DiscardParams::Yes, + false, params, ), })); @@ -1922,7 +1914,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_node_id: NodeId, kind: FnDeclKind, coro: Option, - discard_params: DiscardParams, + has_body: bool, hir_inputs: Vec>, ) -> &'hir hir::FnDecl<'hir> { let c_variadic = decl.c_variadic(); @@ -2103,14 +2095,10 @@ impl<'hir> LoweringContext<'_, 'hir> { ) .set_c_variadic(c_variadic) .set_splatted(splatted, inputs.len()) - .unwrap(); + .unwrap() + .set_has_body(has_body); - self.arena.alloc(hir::FnDecl { - inputs, - output, - fn_decl_kind, - fn_has_body: matches!(discard_params, DiscardParams::No), - }) + self.arena.alloc(hir::FnDecl { inputs, output, fn_decl_kind }) } // Transforms `-> T` for `async fn` into `-> OpaqueTy { .. }` diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 8608b8adf1b9a..168234ac2703e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3882,6 +3882,9 @@ impl FnDeclFlags { /// Bitflag for lifetime elision. const LIFETIME_ELISION_ALLOWED_FLAG: u8 = 1 << 4; + /// Bitflag for whether there is a body associated with this function + const HAS_BODY: u8 = 1 << 5; + /// Marker index for "no splatted argument". /// Must have the same value as `FnSigKind::NO_SPLATTED_ARG_INDEX` and `rustc_ast::FnDecl::NO_SPLATTED_ARG_INDEX`. const NO_SPLATTED_ARG_INDEX: u8 = u8::MAX; @@ -4000,6 +4003,22 @@ impl FnDeclFlags { pub fn splatted(self) -> Option { if self.splatted == Self::NO_SPLATTED_ARG_INDEX { None } else { Some(self.splatted) } } + + pub fn has_body(self) -> bool { + (self.flags & Self::HAS_BODY) != 0 + } + + /// Set whether this fn decl is associated with a body + #[must_use = "this method does not modify the receiver"] + pub fn set_has_body(mut self, allowed: bool) -> Self { + if allowed { + self.flags |= Self::HAS_BODY; + } else { + self.flags &= !Self::HAS_BODY; + } + + self + } } /// Represents the header (not the body) of a function declaration. @@ -4009,7 +4028,6 @@ pub struct FnDecl<'hir> { pub output: FnRetTy<'hir>, /// The packed function declaration attributes. pub fn_decl_kind: FnDeclFlags, - pub fn_has_body: bool, } impl<'hir> FnDecl<'hir> { @@ -4049,12 +4067,13 @@ impl<'hir> FnDecl<'hir> { self.fn_decl_kind.splatted() } - pub fn dummy(span: Span) -> Self { + pub fn dummy(span: Span, has_body: bool) -> Self { Self { inputs: &[], output: FnRetTy::DefaultReturn(span), - fn_decl_kind: FnDeclFlags::default().set_lifetime_elision_allowed(true), - fn_has_body: true, + fn_decl_kind: FnDeclFlags::default() + .set_lifetime_elision_allowed(true) + .set_has_body(has_body), } } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 8ef3aa5b48e53..8adc3646fa652 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1238,7 +1238,7 @@ pub fn walk_fn_decl<'v, V: Visitor<'v>>( visitor: &mut V, function_declaration: &'v FnDecl<'v>, ) -> V::Result { - let FnDecl { inputs, output, fn_decl_kind: _, fn_has_body: _ } = function_declaration; + let FnDecl { inputs, output, fn_decl_kind: _ } = function_declaration; walk_list!(visitor, visit_param, *inputs); visitor.visit_fn_ret_ty(output) } diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index dbff232f22c5b..5483c83677bae 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -437,7 +437,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { fn visit_fn_decl(&mut self, decl: &'tcx FnDecl<'tcx>) -> Self::Result { // Declarations of functions with a body are visited from `visit_nested_body` - if !decl.fn_has_body { + if !decl.fn_decl_kind.has_body() { intravisit::walk_fn_decl(self, decl); } } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 8faf4b1247acf..3c1a9e3841583 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -380,7 +380,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { } fn visit_fn_decl(&mut self, fd: &'tcx FnDecl<'tcx>) -> Self::Result { - if fd.fn_has_body { + if fd.fn_decl_kind.has_body() { intravisit::walk_fn_decl(self, fd); } } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 74957ff332d87..f5207da6bf748 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -693,7 +693,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { fn visit_fn_decl(&mut self, decl: &'tcx FnDecl<'tcx>) -> Self::Result { // Declarations of functions with a body are visited from `visit_nested_body` - if !decl.fn_has_body { + if !decl.fn_decl_kind.has_body() { intravisit::walk_fn_decl(self, decl)?; } ControlFlow::Continue(()) From 43a9bfc20fe5fa43f445815fc5b3166124114adc Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 9 Oct 2026 17:14:57 +0200 Subject: [PATCH 12/16] Specialize `lower_body` into `lower_body_with_params` --- .../rustc_ast_lowering/src/delegation/mod.rs | 11 +++---- compiler/rustc_ast_lowering/src/expr.rs | 4 +-- .../rustc_ast_lowering/src/expr/closure.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 31 ++++++++++--------- compiler/rustc_ast_lowering/src/pat.rs | 13 ++------ 5 files changed, 26 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/delegation/mod.rs b/compiler/rustc_ast_lowering/src/delegation/mod.rs index 869199eb4d5ee..35a160abedc34 100644 --- a/compiler/rustc_ast_lowering/src/delegation/mod.rs +++ b/compiler/rustc_ast_lowering/src/delegation/mod.rs @@ -226,10 +226,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }); let hir_id = self.next_id(); - (PartialParam { - hir_id, - pat, - param_span: span}, pat_node_id) + (PartialParam { hir_id, pat, param_span: span }, pat_node_id) } fn generate_arg( @@ -269,7 +266,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut call_expr_id = HirId::INVALID; let mut unused_target_expr = false; - let (params, block_id) = self.lower_body(|this| { + let (params, block_id) = self.lower_body_with_params(|this| { let &DelegationResolution { param_info, span, is_method, .. } = res; let ParamInfo { param_count, c_variadic, .. } = param_info; let param_count = param_count - c_variadic as usize; @@ -588,7 +585,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ident = self.lower_ident(delegation.ident); - let (_params, body_id) = self.lower_body(|this| { + let body_id = self.lower_body(|this| { let path = this.lower_qpath( delegation.id, &delegation.qself, @@ -617,7 +614,7 @@ impl<'hir> LoweringContext<'_, 'hir> { targeted_by_break: false, }); - (Vec::new(), this.mk_expr(hir::ExprKind::Block(block, None), span)) + this.mk_expr(hir::ExprKind::Block(block, None), span) }); let generics = hir::Generics::empty(); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index e2c94f5f1f782..56ef905da29de 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -921,7 +921,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl_kind: hir::FnDeclFlags::default().set_has_body(true), }); - let (_, body) = self.lower_body(move |this| { + let body = self.lower_body(move |this| { this.coroutine_kind = Some(coroutine_kind); let old_ctx = this.task_context; @@ -931,7 +931,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let res = body(this); this.task_context = old_ctx; - (Vec::new(), res) + res }); let explicit_captures: &'hir [hir::ExplicitCapture] = match coroutine_source { diff --git a/compiler/rustc_ast_lowering/src/expr/closure.rs b/compiler/rustc_ast_lowering/src/expr/closure.rs index b8c97bbf9099a..da359b670cea2 100644 --- a/compiler/rustc_ast_lowering/src/expr/closure.rs +++ b/compiler/rustc_ast_lowering/src/expr/closure.rs @@ -304,7 +304,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (parameters, body) = self.with_new_scopes(fn_decl_span, |this| { // Transform `async |x: u8| -> X { ... }` into // `|x: u8| || -> X { ... }`. - let body_id = this.lower_body(|this| { + let body_id = this.lower_body_with_params(|this| { let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( &decl, |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)), diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 2bb69dc10c239..cf07c849d2971 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -319,9 +319,8 @@ impl<'hir> LoweringContext<'_, 'hir> { }, ItemKind::GlobalAsm(asm) => { let asm = self.lower_inline_asm(span, asm); - let (_, fake_body) = self.lower_body(|this| { - (Vec::new(), this.expr(span, hir::ExprKind::InlineAsm(asm))) - }); + let fake_body = + self.lower_body(|this| this.expr(span, hir::ExprKind::InlineAsm(asm))); hir::ItemKind::GlobalAsm { asm, fake_body } } ItemKind::TyAlias(TyAlias { ident, generics, after_where_clause, ty, .. }) => { @@ -625,7 +624,8 @@ impl<'hir> LoweringContext<'_, 'hir> { .inputs .iter() .filter(|p| !p.is_const_param()) - .map(|x| this.lower_param(x)).collect(); + .map(|x| this.lower_param(x)) + .collect(); // Disallow `impl Trait` in foreign items. this.lower_fn_decl(fdec, i.id, FnDeclKind::ExternFn, None, false, params) }); @@ -1217,6 +1217,13 @@ impl<'hir> LoweringContext<'_, 'hir> { } pub(super) fn lower_body( + &mut self, + f: impl FnOnce(&mut Self) -> hir::Expr<'hir>, + ) -> hir::BodyId { + self.lower_body_with_params(|c| (Vec::new(), f(c))).1 + } + + pub(super) fn lower_body_with_params( &mut self, f: impl FnOnce(&mut Self) -> (Vec>, hir::Expr<'hir>), ) -> (Vec>, hir::BodyId) { @@ -1245,7 +1252,7 @@ impl<'hir> LoweringContext<'_, 'hir> { contract: Option<&FnContract>, body: impl FnOnce(&mut Self) -> hir::Expr<'hir>, ) -> (Vec>, hir::BodyId) { - self.lower_body(|this| { + self.lower_body_with_params(|this| { let params = decl .inputs .iter() @@ -1272,16 +1279,10 @@ impl<'hir> LoweringContext<'_, 'hir> { } pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId { - self.lower_body(|this| { - ( - Vec::new(), - match expr { - Some(expr) => this.lower_expr_mut(expr), - None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")), - }, - ) + self.lower_body(|this| match expr { + Some(expr) => this.lower_expr_mut(expr), + None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")), }) - .1 } /// Takes what may be the body of an `async fn` or a `gen fn` and wraps it in an `async {}` or @@ -1329,7 +1330,7 @@ impl<'hir> LoweringContext<'_, 'hir> { return self.lower_fn_body_block(decl, body, contract); }; // FIXME(contracts): Support contracts on async fn. - self.lower_body(|this| { + self.lower_body_with_params(|this| { let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( decl, |this| this.lower_block_expr(body), diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 013557a66aac7..823c61e612e89 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -488,7 +488,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let anon_const = self.with_new_scopes(span, |this| { let def_id = this.local_def_id(e.id); let hir_id = this.lower_node_id(e.id); - let (_, body) = this.lower_body(|this| { + let body = this.lower_body(|this| { // Need to use a custom function as we can't just subtract `1` from a `char`. let kind = hir::ExprKind::Path(this.make_lang_item_qpath( LangItem::RangeSub, @@ -497,14 +497,7 @@ impl<'hir> LoweringContext<'_, 'hir> { )); let fn_def = this.arena.alloc(hir::Expr { hir_id: this.next_id(), kind, span }); let args = this.arena.alloc([this.lower_expr_mut(&e.value)]); - ( - Vec::new(), - hir::Expr { - hir_id: this.next_id(), - kind: hir::ExprKind::Call(fn_def, args), - span, - }, - ) + hir::Expr { hir_id: this.next_id(), kind: hir::ExprKind::Call(fn_def, args), span } }); hir::AnonConst { def_id, hir_id, body, span } }); @@ -550,7 +543,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(hir::AnonConst { def_id, hir_id, - body: this.lower_body(|_this| (Vec::new(), path_expr)).1, + body: this.lower_body(|_this| path_expr), span, }) }); From 476d2921a1874ce4ae0cb659736f105edd4c180a Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 7 Nov 2026 13:09:13 +0100 Subject: [PATCH 13/16] Fix obligation spans of c-variadics --- .../rustc_hir_analysis/src/check/wfcheck.rs | 11 +++-- tests/ui/c-variadic/obligation-span.rs | 15 +++++++ tests/ui/c-variadic/obligation-span.stderr | 45 +++++++++++++++++++ 3 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 tests/ui/c-variadic/obligation-span.rs create mode 100644 tests/ui/c-variadic/obligation-span.stderr diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 36e3e2055bf3e..efadd78206e08 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1666,10 +1666,13 @@ fn check_fn_or_method<'tcx>( // for each type, preventing the HIR wf check from generating // a nice error message. let arg_span = |idx| { - hir_decl - .inputs - .get(idx) - .map_or(hir_decl.output.span(), |param: &hir::Param<'_>| param.ty.span) + let mut inputs = hir_decl.inputs; + // C-variadics are filtered out of the input parameters in the THIR, + // so to be consistent we should also filter them out here + if inputs.last().is_some_and(|input| matches!(input.ty.kind, hir::TyKind::CVarArgs)) { + inputs = &inputs[..inputs.len() - 1]; + } + inputs.get(idx).map_or(hir_decl.output.span(), |param: &hir::Param<'_>| param.ty.span) }; sig.inputs_and_output = diff --git a/tests/ui/c-variadic/obligation-span.rs b/tests/ui/c-variadic/obligation-span.rs new file mode 100644 index 0000000000000..b14d645444fbd --- /dev/null +++ b/tests/ui/c-variadic/obligation-span.rs @@ -0,0 +1,15 @@ +// This test checks that the span of c-variadics is handled correctly when creating obligations + +struct NeedsCopy(T); + +extern "C" { + fn f1(...) -> NeedsCopy; + //~^ ERROR the trait bound `String: Copy` is not satisfied + fn f2(x: i32, ...) -> NeedsCopy; + //~^ ERROR the trait bound `String: Copy` is not satisfied + fn f3(..., x: i32) -> NeedsCopy; + //~^ ERROR `...` must be the last argument of a C-variadic function + //~| ERROR the trait bound `String: Copy` is not satisfied +} + +fn main() { } diff --git a/tests/ui/c-variadic/obligation-span.stderr b/tests/ui/c-variadic/obligation-span.stderr new file mode 100644 index 0000000000000..aaa329d70e3ee --- /dev/null +++ b/tests/ui/c-variadic/obligation-span.stderr @@ -0,0 +1,45 @@ +error: `...` must be the last argument of a C-variadic function + --> $DIR/obligation-span.rs:10:11 + | +LL | fn f3(..., x: i32) -> NeedsCopy; + | ^^^ + +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/obligation-span.rs:6:19 + | +LL | fn f1(...) -> NeedsCopy; + | ^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | +note: required by a bound in `NeedsCopy` + --> $DIR/obligation-span.rs:3:21 + | +LL | struct NeedsCopy(T); + | ^^^^ required by this bound in `NeedsCopy` + +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/obligation-span.rs:8:27 + | +LL | fn f2(x: i32, ...) -> NeedsCopy; + | ^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | +note: required by a bound in `NeedsCopy` + --> $DIR/obligation-span.rs:3:21 + | +LL | struct NeedsCopy(T); + | ^^^^ required by this bound in `NeedsCopy` + +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/obligation-span.rs:10:27 + | +LL | fn f3(..., x: i32) -> NeedsCopy; + | ^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | +note: required by a bound in `NeedsCopy` + --> $DIR/obligation-span.rs:3:21 + | +LL | struct NeedsCopy(T); + | ^^^^ required by this bound in `NeedsCopy` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. From 8c5daf03d44aca9f0cfd2bd08988b5ac139d0383 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 8 Nov 2026 11:13:16 +0100 Subject: [PATCH 14/16] Clippy cleanup --- compiler/rustc_middle/src/hir/map.rs | 1 + .../src/functions/not_unsafe_ptr_arg_deref.rs | 3 +- .../clippy_lints/src/manual_is_ascii_check.rs | 2 +- .../clippy/clippy_lints/src/manual_retain.rs | 4 +-- .../clippy/clippy_lints/src/map_unit_fn.rs | 32 +++++++++---------- .../clippy_lints/src/matches/manual_filter.rs | 2 +- .../clippy_lints/src/methods/bytecount.rs | 2 +- .../clippy_lints/src/methods/filter_map.rs | 4 +-- .../src/methods/filter_map_bool_then.rs | 7 ++-- .../clippy_lints/src/methods/iter_kv_map.rs | 10 +++--- .../src/methods/lines_filter_map_ok.rs | 2 +- .../src/methods/manual_inspect.rs | 2 +- .../clippy_lints/src/methods/manual_ok_or.rs | 2 +- .../map_with_unused_argument_over_ranges.rs | 11 +++---- .../clippy/clippy_lints/src/methods/mod.rs | 8 ++--- .../methods/needless_character_iteration.rs | 8 ++--- .../clippy_lints/src/methods/some_filter.rs | 4 +-- .../src/methods/unnecessary_fold.rs | 15 ++++----- .../src/methods/unnecessary_lazy_eval.rs | 9 +++--- .../src/methods/unnecessary_map_or.rs | 4 +-- .../src/methods/unnecessary_sort_by.rs | 2 +- .../clippy_lints/src/needless_for_each.rs | 4 +-- .../src/needless_pass_by_ref_mut.rs | 6 ++-- .../clippy_lints/src/pass_by_ref_or_value.rs | 15 ++++----- .../clippy/clippy_lints/src/ptr/ptr_arg.rs | 14 ++++---- src/tools/clippy/clippy_lints/src/shadow.rs | 3 ++ .../clippy_lints/src/single_option_map.rs | 2 +- .../clippy_lints/src/string_patterns.rs | 3 +- .../clippy_lints/src/toplevel_ref_arg.rs | 4 +-- .../clippy/clippy_utils/src/hir_utils.rs | 2 ++ src/tools/clippy/clippy_utils/src/lib.rs | 4 --- .../clippy_utils/src/ty/type_certainty/mod.rs | 3 +- src/tools/clippy/clippy_utils/src/usage.rs | 2 +- 33 files changed, 91 insertions(+), 105 deletions(-) diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 682e235016d9a..360f5c1fea347 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -309,6 +309,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } + // FIXME: Rename this since it doesn't operate on bodies anymore pub fn hir_body_param_idents(self, decl: &FnDecl<'_>) -> impl Iterator> { decl.inputs.iter().map(|param| match param.pat.kind { PatKind::Binding(_, _, ident, _) => Some(ident), diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index f1680f94ab17a..517cdc782ab8e 100644 --- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -5,7 +5,6 @@ use rustc_middle::ty; use rustc_span::def_id::LocalDefId; use clippy_utils::diagnostics::span_lint; -use clippy_utils::iter_input_pats; use clippy_utils::ty::is_unsafe_fn; use clippy_utils::visitors::for_each_expr; @@ -44,7 +43,7 @@ fn check_raw_ptr<'tcx>( def_id: LocalDefId, ) { if safety.is_safe() && cx.effective_visibilities.is_exported(def_id) { - let raw_ptrs = iter_input_pats(decl) + let raw_ptrs = decl.inputs.into_iter() .filter_map(|arg| raw_ptr_arg(cx, arg)) .collect::(); diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs index e2ec62b84b752..030b3271e6284 100644 --- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs +++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs @@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { fn get_ty_sugg<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'_>) -> Option<(Span, Ty<'tcx>)> { let local_hid = arg.res_local_id()?; if let Node::Param(Param { ty, param_span, .. }) = cx.tcx.parent_hir_node(local_hid) - // `ty_span` and `span` are the same for inferred type, thus a type suggestion must be given + // `ty.span` and `param_span` are the same for inferred type, thus a type suggestion must be given && ty.span == *param_span { let arg_type = cx.typeck_results().expr_ty(arg); diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs index 47e4d9a200b26..9436fd5ae7478 100644 --- a/src/tools/clippy/clippy_lints/src/manual_retain.rs +++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs @@ -88,8 +88,8 @@ fn check_into_iter( && SpanlessEq::new(cx).eq_expr(parent_expr_span.ctxt(), left_expr, struct_expr) && let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = target_expr.kind && let hir::ExprKind::Closure(closure) = closure_expr.kind - && let filter_body = cx.tcx.hir_body(closure.body) && let [filter_params] = closure.fn_decl.inputs + && let filter_body = cx.tcx.hir_body(closure.body) { if match_map_type(cx, left_expr) { if let hir::PatKind::Tuple([key_pat, value_pat], _) = filter_params.pat.kind @@ -135,8 +135,8 @@ fn check_iter( && SpanlessEq::new(cx).eq_expr(parent_expr_span.ctxt(), left_expr, struct_expr) && let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = filter_expr.kind && let hir::ExprKind::Closure(closure) = closure_expr.kind - && let filter_body = cx.tcx.hir_body(closure.body) && let [filter_params] = closure.fn_decl.inputs + && let filter_body = cx.tcx.hir_body(closure.body) { match filter_params.pat.kind { // hir::PatKind::Binding(_, _, _, None) => { diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index 78c294b323574..c9b6980c0dc5b 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeDef as _; use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context}; -use clippy_utils::{iter_input_pats, method_chain_args}; +use clippy_utils::{method_chain_args}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, declare_lint_pass}; @@ -161,18 +161,16 @@ fn reduce_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option< } } -fn unit_closure<'a, 'b>( - cx: &LateContext<'a>, - expr: &hir::Expr<'b>, -) -> Option<(&'b hir::Param<'b>, &'a hir::Expr<'a>)> { +fn unit_closure<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, +) -> Option<(&'tcx hir::Param<'tcx>, &'tcx hir::Expr<'tcx>)> { if let hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) = expr.kind + && let [binding] = fn_decl.inputs && let body = cx.tcx.hir_body(body) - && let body_expr = &body.value - && fn_decl.inputs.len() == 1 - && is_unit_expression(cx, body_expr) - && let Some(binding) = iter_input_pats(fn_decl).next() + && is_unit_expression(cx, body.value) { - return Some((binding, body_expr)); + return Some((binding, body.value)); } None } @@ -198,11 +196,11 @@ fn suggestion_msg(function_type: &str, article: &str, map_type: &str) -> String ) } -fn lint_map_unit_fn( - cx: &LateContext<'_>, - stmt: &hir::Stmt<'_>, - expr: &hir::Expr<'_>, - map_args: (&hir::Expr<'_>, &[hir::Expr<'_>]), +fn lint_map_unit_fn<'tcx>( + cx: &LateContext<'tcx>, + stmt: &'tcx hir::Stmt<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + map_args: (&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>]), ) { let var_arg = &map_args.0; @@ -260,8 +258,8 @@ fn lint_map_unit_fn( } } -impl LateLintPass<'_> for MapUnit { - fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) { +impl<'tcx> LateLintPass<'tcx> for MapUnit { + fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'tcx>) { if let hir::StmtKind::Semi(expr) = stmt.kind && !stmt.span.from_expansion() && let Some(arglists) = method_chain_args(expr, &[sym::map]) diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs index b4a5c89301c4d..856c8438f15aa 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs @@ -106,10 +106,10 @@ pub(crate) fn check_and_then_method<'tcx>( let ty = cx.typeck_results().expr_ty(scrutinee); if ty.is_diag_item(cx, sym::Option) && let ExprKind::Closure(closure) = arg.kind - && let body = cx.tcx.hir_body(closure.body) && let Some(fn_arg_span) = closure.fn_arg_span && let [param] = closure.fn_decl.inputs && let expr_span_ctxt = expr.span.ctxt() + && let body = cx.tcx.hir_body(closure.body) && let Some(some_expr) = get_cond_expr(cx, param.pat, body.value, expr_span_ctxt) { span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs index 61efb0cbd2456..eac06a9d07b2b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs @@ -17,9 +17,9 @@ pub(super) fn check<'tcx>( filter_arg: &'tcx Expr<'_>, ) { if let ExprKind::Closure(&Closure { fn_decl, body, .. }) = filter_arg.kind - && let body = cx.tcx.hir_body(body) && let [param] = fn_decl.inputs && let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind + && let body = cx.tcx.hir_body(body) && let ExprKind::Binary(ref op, l, r) = body.value.kind && op.node == BinOpKind::Eq && cx diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs index 0545ab5b9b318..7c6a8cd1b923b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -408,7 +408,6 @@ fn is_find_or_filter<'a>( if cx.ty_based_def(map_recv).opt_parent(cx).is_diag_item(cx, sym::Iterator) // filter(|x| ...is_some())... && let ExprKind::Closure(&Closure { fn_decl, body: filter_body_id, .. }) = filter_arg.kind - && let filter_body = cx.tcx.hir_body(filter_body_id) && let [filter_param] = fn_decl.inputs // optional ref pattern: `filter(|&x| ..)` && let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _, _) = filter_param.pat.kind { @@ -418,12 +417,13 @@ fn is_find_or_filter<'a>( } && let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind + && let filter_body = cx.tcx.hir_body(filter_body_id) && let Some(offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id) && let ExprKind::Closure(&Closure { fn_decl, body: map_body_id, .. }) = map_arg.kind - && let map_body = cx.tcx.hir_body(map_body_id) && let [map_param] = fn_decl.inputs && let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind + && let map_body = cx.tcx.hir_body(map_body_id) && let Some(check_result) = offending_expr.check_map_call(cx, ctxt, map_body, map_param_id, filter_param_id, is_filter_param_ref) diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs index e021c581c26e5..ab333d821504a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs @@ -16,10 +16,7 @@ use rustc_span::Span; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &'tcx Expr<'tcx>, call_span: Span) { if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator) && let ExprKind::Closure(closure) = arg.kind - && let body = cx.tcx.hir_body(closure.body) - && let value = peel_blocks(body.value) - // Indexing should be fine as `filter_map` always has 1 input, we unfortunately need both - // `inputs` and `params` here as we need both the type and the span + // Indexing should be fine as `filter_map` always has 1 input && let param = closure.fn_decl.inputs[0] // Issue #11309 && let param_ty = cx.tcx.liberate_late_bound_regions( @@ -30,6 +27,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & ), ) && is_copy(cx, param_ty) + && let body = cx.tcx.hir_body(closure.body) + && let value = peel_blocks(body.value) && let ExprKind::MethodCall(_, recv, [then_arg], _) = value.kind && let ExprKind::Closure(then_closure) = then_arg.kind && let then_body = peel_blocks(cx.tcx.hir_body(then_closure.body).value) diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs index a2173e0f08520..329d4fb4c55c6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs @@ -4,7 +4,7 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef as _; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::{pat_is_wild, sym}; -use rustc_hir::{Body, Expr, ExprKind, PatKind}; +use rustc_hir::{Expr, ExprKind, PatKind}; use rustc_lint::LateContext; use rustc_span::Symbol; @@ -29,9 +29,6 @@ pub(super) fn check<'tcx>( if !expr.span.from_expansion() && let ExprKind::Closure(c) = m_arg.kind && let [p] = c.fn_decl.inputs - && let Body { - value: body_expr, - } = cx.tcx.hir_body(c.body) && let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind && let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) { (key, PatKind::Binding(ann, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", ann, value), @@ -40,12 +37,13 @@ pub(super) fn check<'tcx>( } && let ty = cx.typeck_results().expr_ty_adjusted(recv).peel_refs() && matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) + && let body = cx.tcx.hir_body(c.body) { let mut applicability = rustc_errors::Applicability::MachineApplicable; let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability); let into_prefix = if map_type == sym::into_iter { "into_" } else { "" }; - if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind + if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body.value.kind && let [local_ident] = path.segments && local_ident.ident.name == bound_ident.name && [sym::map, sym::flat_map].contains(&method_name) @@ -66,7 +64,7 @@ pub(super) fn check<'tcx>( ); } else { let (body_snippet, _) = - snippet_with_context(cx, body_expr.span, expr.span.ctxt(), "..", &mut applicability); + snippet_with_context(cx, body.value.span, expr.span.ctxt(), "..", &mut applicability); span_lint_and_sugg( cx, ITER_KV_MAP, diff --git a/src/tools/clippy/clippy_lints/src/methods/lines_filter_map_ok.rs b/src/tools/clippy/clippy_lints/src/methods/lines_filter_map_ok.rs index fdbe95d753520..2d9a884b89565 100644 --- a/src/tools/clippy/clippy_lints/src/methods/lines_filter_map_ok.rs +++ b/src/tools/clippy/clippy_lints/src/methods/lines_filter_map_ok.rs @@ -42,8 +42,8 @@ pub(super) fn check_filter_or_flat_map( .is_diag_item(cx, sym::result_ok_method), // Detect `|x| x.ok()` ExprKind::Closure(&Closure { fn_decl, body, .. }) => { - let value = cx.tcx.hir_body(body).value; if let [param] = fn_decl.inputs + && let value = cx.tcx.hir_body(body).value && let ExprKind::MethodCall(method, receiver, [], _) = value.kind { method.ident.name == sym::ok diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs index 048ba21c2086f..e6c337cf6b0a6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs @@ -25,10 +25,10 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: || ((fn_def.opt_parent(cx).opt_impl_ty(cx).is_diag_item(cx, sym::Option) || fn_def.opt_parent(cx).opt_impl_ty(cx).is_diag_item(cx, sym::Result)) && msrv.meets(cx, msrvs::OPTION_RESULT_INSPECT))) - && let body = cx.tcx.hir_body(c.body) && let [param] = c.fn_decl.inputs && let PatKind::Binding(BindingMode(ByRef::No, Mutability::Not), arg_id, _, None) = param.pat.kind && let arg_ty = typeck.node_type(arg_id) + && let body = cx.tcx.hir_body(c.body) && let ExprKind::Block(block, _) = body.value.kind && let Some(final_expr) = block.expr && !block.stmts.is_empty() diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs index ac8a4044a80fc..76c769351f009 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs @@ -55,8 +55,8 @@ fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { true }, ExprKind::Closure(closure) => { - let body = cx.tcx.hir_body(closure.body); if let PatKind::Binding(_, param_id, ..) = closure.fn_decl.inputs[0].pat.kind + && let body = cx.tcx.hir_body(closure.body) && let ExprKind::Call(callee, [ok_arg]) = body.value.kind && callee.res(cx).ctor_parent(cx).is_lang_item(cx, ResultOk) { diff --git a/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs b/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs index 866337a47602e..3dbbcda1a2955 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs @@ -8,7 +8,7 @@ use rustc_ast::LitKind; use rustc_ast::ast::RangeLimits; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; -use rustc_hir::{Body, Closure, Expr, ExprKind, FnDecl}; +use rustc_hir::{Closure, Expr, ExprKind, FnDecl}; use rustc_lint::LateContext; use rustc_span::{Span, SyntaxContext}; @@ -70,20 +70,17 @@ pub(super) fn check( if let Some(range) = higher::Range::hir(cx, receiver) && let ExprKind::Closure(Closure { fn_decl: decl@FnDecl { inputs: [param], .. }, body, .. }) = arg.kind && let body_hir = cx.tcx.hir_body(*body) - && let Body { - value: body_expr, - } = body_hir && !usage::BindingUsageFinder::are_params_used(cx, decl, body_hir) && let ctxt = ex.span.ctxt() && let Some(count) = extract_count_with_applicability(cx, range, &mut applicability, ctxt) && let Some(exec_context) = std_or_core(cx) { - let (method_to_use_name, new_span, use_take) = if eager_or_lazy::switch_to_eager_eval(cx, body_expr) { + let (method_to_use_name, new_span, use_take) = if eager_or_lazy::switch_to_eager_eval(cx, body_hir.value) { if msrv.meets(cx, msrvs::REPEAT_N) { - let (body_snippet, _) = snippet_with_context(cx, body_expr.span, ctxt, "..", &mut applicability); + let (body_snippet, _) = snippet_with_context(cx, body_hir.value.span, ctxt, "..", &mut applicability); ("repeat_n", (arg.span, format!("{body_snippet}, {count}")), false) } else { - let (body_snippet, _) = snippet_with_context(cx, body_expr.span, ctxt, "..", &mut applicability); + let (body_snippet, _) = snippet_with_context(cx, body_hir.value.span, ctxt, "..", &mut applicability); ("repeat", (arg.span, body_snippet.to_string()), true) } } else if msrv.meets(cx, msrvs::REPEAT_WITH) { diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index fea54ebb5dd90..fd86658c35f95 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -165,7 +165,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::macros::FormatArgsStorage; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::{MaybeDef as _, MaybeTypeckRes as _}; -use clippy_utils::{contains_return, iter_input_pats, peel_blocks, sym}; +use clippy_utils::{contains_return, peel_blocks, sym}; use rustc_data_structures::fx::FxHashSet; use rustc_hir::{self as hir, Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext as _, impl_lint_pass}; @@ -5368,7 +5368,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { return; } - if let hir::ImplItemKind::Fn(ref sig, _id) = impl_item.kind { + if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind { let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id; let item = cx.tcx.hir_expect_item(parent); let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity().skip_norm_wip(); @@ -5382,7 +5382,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if sig.decl.implicit_self().has_implicit_self() && !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id)) - && let Some(first_arg) = iter_input_pats(sig.decl).next() + && let Some(first_arg) = sig.decl.inputs.into_iter().next() && let Some(first_arg_ty) = first_arg_ty_opt { wrong_self_convention::check( @@ -5489,9 +5489,9 @@ impl Methods { ), Some((sym::chars, recv, _, _, _)) if let ExprKind::Closure(arg) = arg.kind - && let body = cx.tcx.hir_body(arg.body) && let [param] = arg.fn_decl.inputs => { + let body = cx.tcx.hir_body(arg.body); string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), self.msrv); }, Some((sym::map, _, [map_arg], _, map_call_span)) => { diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs index e3792cf50a45c..f878438df6db3 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs @@ -1,6 +1,6 @@ use clippy_utils::res::{MaybeDef as _, MaybeQPath as _, MaybeResPath as _}; use rustc_errors::Applicability; -use rustc_hir::{Closure, Expr, ExprKind, HirId, StmtKind, UnOp, FnDecl}; +use rustc_hir::{Closure, Expr, ExprKind, HirId, StmtKind, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::Span; @@ -96,8 +96,8 @@ fn handle_expr( } pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>, is_all: bool) { - if let ExprKind::Closure(&Closure { fn_decl: FnDecl { inputs: [first_param], .. }, body, .. }) = closure_arg.kind - && let body = cx.tcx.hir_body(body) + if let ExprKind::Closure(&Closure { fn_decl, body, .. }) = closure_arg.kind + && let [first_param] = fn_decl.inputs && let ExprKind::MethodCall(method, mut recv, [], _) = recv.kind && method.ident.name == sym::chars && let str_ty = cx.typeck_results().expr_ty_adjusted(recv).peel_refs() @@ -107,7 +107,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, while let ExprKind::MethodCall(_, new_recv, _, _) = recv.kind { recv = new_recv; } - let body_expr = peel_blocks(body.value); + let body_expr = peel_blocks(cx.tcx.hir_body(body).value); handle_expr( cx, diff --git a/src/tools/clippy/clippy_lints/src/methods/some_filter.rs b/src/tools/clippy/clippy_lints/src/methods/some_filter.rs index b468195890c81..f6cf3b5c2015e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/some_filter.rs +++ b/src/tools/clippy/clippy_lints/src/methods/some_filter.rs @@ -4,7 +4,7 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::{as_some_expr, pat_is_wild, peel_blocks, span_contains_comment}; use rustc_ast::util::parser::ExprPrecedence; use rustc_errors::Applicability; -use rustc_hir::{Body, Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use super::SOME_FILTER; @@ -19,10 +19,10 @@ pub(super) fn check<'tcx>( let (condition, value) = if let Some(value) = as_some_expr(cx, recv) && let ExprKind::Closure(c) = arg.kind && let [p] = c.fn_decl.inputs - && let Body { value: condition } = cx.tcx.hir_body(c.body) && pat_is_wild(cx, &p.pat.kind, arg) && msrv.meets(cx, msrvs::BOOL_THEN_SOME) { + let condition = cx.tcx.hir_body(c.body).value; (condition, value) } else { return; diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs index aedf84c471b5c..ca9739162d79e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs @@ -124,7 +124,12 @@ fn check_fold_with_op( replacement: Replacement, ) -> bool { if let hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) = acc.kind - // Extract the body of the closure passed to fold + // Extract the names of the two arguments to the closure passed to fold + && let [param_a, param_b] = fn_decl.inputs + && let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(param_a.pat).kind + && let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(param_b.pat).kind + + // Extract the body of the closure && let closure_body = cx.tcx.hir_body(body) && let closure_expr = peel_blocks(closure_body.value) @@ -132,11 +137,6 @@ fn check_fold_with_op( && let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind && bin_op.node == op - // Extract the names of the two arguments to the closure - && let [param_a, param_b] = fn_decl.inputs - && let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(param_a.pat).kind - && let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(param_b.pat).kind - && let Some(triggered_expr_span) = get_triggered_expr_span( left_expr, right_expr, @@ -334,7 +334,6 @@ fn check_option_fold<'tcx>( } && cx.typeck_results().expr_ty(option_expr).is_diag_item(cx, sym::Option) && let hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) = acc.kind - && let closure_body = cx.tcx.hir_body(body) && let [param_acc, param_item] = fn_decl.inputs // The suggestion rewrites source spans, so bail out when any part // comes from a different syntax context. @@ -353,7 +352,7 @@ fn check_option_fold<'tcx>( let mut acc_uses: Vec = Vec::new(); let mut acc_uses_ok = true; if let Some(acc_id) = acc_id { - for_each_expr(cx.tcx, closure_body.value, |sub_expr| { + for_each_expr(cx.tcx, cx.tcx.hir_body(body).value, |sub_expr| { if sub_expr.res_local_id() == Some(acc_id) { if sub_expr.span.ctxt() == ctxt { acc_uses.push(sub_expr.span); diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 997907ecd39b1..fb0a6304738fd 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -141,7 +141,10 @@ pub(super) fn check_map_or_else<'tcx>( let mut applicability = if fn_decl .inputs .iter() - .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild)) + .all(|param| + matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild) + && matches!(param.ty.kind, hir::TyKind::Infer(())) + ) && matches!( fn_decl.output, FnRetTy::DefaultReturn(_) @@ -150,10 +153,6 @@ pub(super) fn check_map_or_else<'tcx>( .. }) ) - && fn_decl - .inputs - .iter() - .all(|param| matches!(param.ty.kind, hir::TyKind::Infer(()))) { Applicability::MachineApplicable } else { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs index bc0946a89bebd..4e72f49568017 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs @@ -155,11 +155,11 @@ pub(super) fn check<'tcx>( let (sugg, method, applicability): (_, Cow<'_, _>, _) = if typeck.expr_adjustments(recv).is_empty() && let ExprKind::Closure(map_closure) = map.kind + && let [param] = map_closure.fn_decl.inputs + && let PatKind::Binding(_, hir_id, _, _) = param.pat.kind && let closure_body = cx.tcx.hir_body(map_closure.body) && let closure_body_value = closure_body.value.peel_blocks() && let ExprKind::Binary(op, l, r) = closure_body_value.kind - && let [param] = map_closure.fn_decl.inputs - && let PatKind::Binding(_, hir_id, _, _) = param.pat.kind // checking that map_or is one of the following: // .map_or(false, |x| x == y) // .map_or(false, |x| y == x) - swapped comparison diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs index dbbaeee13835b..9ea9de996c04d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -250,9 +250,9 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>) -> Option< .skip_norm_wip() .is_slice() && let ExprKind::Closure(&Closure { fn_decl, body, .. }) = arg.kind - && let closure_body = cx.tcx.hir_body(body) && let &[Param { pat: l_pat, .. }, Param { pat: r_pat, .. }] = fn_decl.inputs && let Some(binding_map) = mapping_of_mirrored_pats(l_pat, r_pat) + && let closure_body = cx.tcx.hir_body(body) && let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind && method_path.ident.name == sym::cmp && let Some(ord_trait) = cx.tcx.get_diagnostic_item(sym::Ord) diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs index 4ace73b37dee5..9e7e2d8373e00 100644 --- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs @@ -121,14 +121,14 @@ fn check_expr(cx: &LateContext<'_>, expr: &Expr<'_>, outer_span: Span) { ) }; - let body_param_sugg = snippet_with_applicability(cx, fn_decl.inputs[0].pat.span, "..", &mut applicability); + let param_sugg = snippet_with_applicability(cx, fn_decl.inputs[0].pat.span, "..", &mut applicability); let for_each_rev_sugg = snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability); let (body_value_sugg, is_macro_call) = snippet_with_context(cx, body.value.span, for_each_recv.span.ctxt(), "..", &mut applicability); let sugg = format!( "for {} in {} {}", - body_param_sugg, + param_sugg, for_each_rev_sugg, if is_macro_call { format!("{{ {body_value_sugg}; }}") diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs index 0195924fa2f0e..69f604dbc0915 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -105,9 +105,9 @@ fn check_closures<'tcx>( } ctx.prev_bind = None; ctx.prev_move_to_closure.clear(); - if let Node::Expr(Expr { kind: ExprKind::Closure(closure), .. }) = cx - .tcx - .hir_node_by_def_id(id) + + if let Node::Expr(expr) = cx.tcx.hir_node_by_def_id(id) + && let ExprKind::Closure(closure) = expr.kind { euv::ExprUseVisitor::for_clippy(cx, id, &mut *ctx) .consume_body(closure.fn_decl, cx.tcx.hir_body(closure.body)) diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index b52026d1b04bb..910a6f9fffc75 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -140,11 +140,10 @@ impl PassByRefOrValue { ControlFlow::Continue(()) }); - for (index, (input, ty)) in iter::zip( + for (input, ty) in iter::zip( decl.inputs, fn_sig.skip_binder().inputs().iter().map(|&ty| fn_sig.rebind(ty)), ) - .enumerate() { // All spans generated from a proc-macro invocation are the same... match span { @@ -185,7 +184,7 @@ impl PassByRefOrValue { { continue; } - let value_type = if decl.inputs.get(index).is_some_and(is_self) { + let value_type = if is_self(input) { "self".into() } else { snippet(cx, decl_ty.span, "_").into() @@ -206,12 +205,10 @@ impl PassByRefOrValue { }, ty::Adt(_, _) | ty::Array(_, _) | ty::Tuple(_) => { - // if function has a body and parameter is annotated with mut, ignore - if let Some(param) = decl.inputs.get(index) { - match param.pat.kind { - PatKind::Binding(BindingMode::NONE, _, _, _) => {}, - _ => continue, - } + // if the parameter is annotated with mut, ignore + match input.pat.kind { + PatKind::Binding(BindingMode::NONE, _, _, _) => {}, + _ => continue, } let ty = cx.tcx.instantiate_bound_regions_with_erased(ty); diff --git a/src/tools/clippy/clippy_lints/src/ptr/ptr_arg.rs b/src/tools/clippy/clippy_lints/src/ptr/ptr_arg.rs index 6f2ef24d850bf..f9c665450955f 100644 --- a/src/tools/clippy/clippy_lints/src/ptr/ptr_arg.rs +++ b/src/tools/clippy/clippy_lints/src/ptr/ptr_arg.rs @@ -200,19 +200,19 @@ fn check_fn_args<'cx, 'tcx: 'cx>( fn_sig: ty::FnSig<'tcx>, params: &'tcx [Param<'tcx>], ) -> impl Iterator> + 'cx { - iter::zip(fn_sig.inputs(), params) + iter::zip(fn_sig.inputs(), params.iter().map(|p| p.ty)) .enumerate() - .filter_map(move |(i, (ty, param))| { + .filter_map(move |(i, (ty, hir_ty))| { if let ty::Ref(_, ty, mutability) = *ty.kind() && let ty::Adt(adt, args) = *ty.kind() - && let TyKind::Ref(lt, inner_ty, _) = param.ty.kind + && let TyKind::Ref(lt, inner_ty, _) = hir_ty.kind && let TyKind::Path(QPath::Resolved(None, path)) = inner_ty.kind // Check that the name as typed matches the actual name of the type. // e.g. `fn foo(_: &Foo)` shouldn't trigger the lint when `Foo` is an alias for `Vec` && let [.., name] = path.segments && cx.tcx.item_name(adt.did()) == name.ident.name { - let emission_id = params.get(i).map_or(param.ty.hir_id, |param| param.hir_id); + let emission_id = params.get(i).map_or(hir_ty.hir_id, |param| param.hir_id); let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) { Some(sym::Vec) => ( [(sym::clone, ".to_owned()")].as_slice(), @@ -270,11 +270,11 @@ fn check_fn_args<'cx, 'tcx: 'cx>( cx, PTR_ARG, emission_id, - param.ty.span, + hir_ty.span, "using a reference to `Cow` is not recommended", |diag| { diag.span_suggestion( - param.ty.span, + hir_ty.span, "change this to", match ty.span().get_text(cx) { Some(s) => format!("&{}{s}", mutability.prefix_str()), @@ -292,7 +292,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( return Some(PtrArg { idx: i, emission_id, - span: param.ty.span, + span: hir_ty.span, ty_name: name.ident.name, method_renames, ref_prefix: RefPrefix { lt: *lt, mutability }, diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index 82730019b1ab0..288ecf4c191f9 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -140,6 +140,7 @@ impl<'tcx> LateLintPass<'tcx> for Shadow { let HirId { owner, local_id } = id; // get (or insert) the list of items for this owner and symbol let Some((data, scope_owner)) = self.bindings.last_mut() else { + // If this `pat` is in a param, return early so we can visit it from the body return }; let items_with_name = data.entry(ident.name).or_default(); @@ -167,6 +168,8 @@ impl<'tcx> LateLintPass<'tcx> for Shadow { if !matches!(cx.tcx.hir_body_owner_kind(owner_id), BodyOwnerKind::Closure) { self.bindings.push((FxHashMap::default(), owner_id)); + // Visit the patterns of the param belonging to the body + // FIXME: This would be a lot cleaner if we used `check_fn` instead if let Some(decl) = cx.tcx.hir_fn_decl_by_hir_id(cx.tcx.hir_body_owner(body.id())) { for input in decl.inputs { self.check_pat(cx, input.pat); diff --git a/src/tools/clippy/clippy_lints/src/single_option_map.rs b/src/tools/clippy/clippy_lints/src/single_option_map.rs index 39379744fee64..486610e3e427e 100644 --- a/src/tools/clippy/clippy_lints/src/single_option_map.rs +++ b/src/tools/clippy/clippy_lints/src/single_option_map.rs @@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for SingleOptionMap { && !matches!(args[0].kind, ExprKind::Path(_)) { if let ExprKind::Closure(closure) = args[0].kind { - let Body { value } = cx.tcx.hir_body(closure.body); + let value = cx.tcx.hir_body(closure.body).value; if let ExprKind::Call(func, f_args) = value.kind && matches!(func.kind, ExprKind::Path(_)) && f_args.iter().all(|arg| matches!(arg.kind, ExprKind::Path(_))) diff --git a/src/tools/clippy/clippy_lints/src/string_patterns.rs b/src/tools/clippy/clippy_lints/src/string_patterns.rs index 4003d4d829c17..90f912149418f 100644 --- a/src/tools/clippy/clippy_lints/src/string_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/string_patterns.rs @@ -139,14 +139,13 @@ fn get_char_span<'tcx>(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Optio fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<'_>, msrv: Msrv) { if let ExprKind::Closure(closure) = method_arg.kind - && let body = cx.tcx.hir_body(closure.body) && let Some(PatKind::Binding(_, binding, ..)) = closure.fn_decl.inputs.first().map(|p| p.pat.kind) { let mut set_char_spans: Vec = Vec::new(); // We want to retrieve all the comparisons done. // They are ordered in a nested way and so we need to traverse the AST to collect them all. - if for_each_expr(cx.tcx, body.value, |sub_expr| -> ControlFlow<(), Descend> { + if for_each_expr(cx.tcx, cx.tcx.hir_body(closure.body).value, |sub_expr| -> ControlFlow<(), Descend> { match sub_expr.kind { ExprKind::Binary(op, left, right) if op.node == BinOpKind::Eq => { if left.res_local_id() == Some(binding) diff --git a/src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs b/src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs index 1b9081e65b40e..28dc2f5220b05 100644 --- a/src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs +++ b/src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::sugg::Sugg; -use clippy_utils::{is_lint_allowed, iter_input_pats}; +use clippy_utils::is_lint_allowed; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{BindingMode, Body, ByRef, FnDecl, Mutability, PatKind, Stmt, StmtKind}; @@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for ToplevelRefArg { _: LocalDefId, ) { if !matches!(k, FnKind::Closure) { - for arg in iter_input_pats(decl) { + for arg in decl.inputs { if let PatKind::Binding(BindingMode(ByRef::Yes(..), _), ..) = arg.pat.kind && is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id) && !arg.ty.span.in_external_macro(cx.tcx.sess.source_map()) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index e48ead8053049..9f106a7a03402 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -278,6 +278,7 @@ impl HirEqInterExpr<'_, '_, '_> { } fn eq_fn_decl(&mut self, left: &FnDecl<'_>, right: &FnDecl<'_>) -> bool { + // FIXME this should check the params' patterns as well, we should introduce a `eq_param` method for this over(left.inputs, right.inputs, |l, r| self.eq_ty(l.ty, r.ty)) && (match (left.output, right.output) { (FnRetTy::DefaultReturn(_), FnRetTy::DefaultReturn(_)) => true, @@ -1631,6 +1632,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { fn_ptr.safety.hash(&mut self.s); fn_ptr.abi.hash(&mut self.s); for arg in fn_ptr.decl.inputs { + // FIXME this should hash the params' patterns as well, we should introduce a `hash_param` method for this self.hash_ty(arg.ty); } mem::discriminant(&fn_ptr.decl.output).hash(&mut self.s); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index abac039ed078b..9d3550eda0681 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1551,10 +1551,6 @@ pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool { false } -pub fn iter_input_pats<'tcx>(decl: &FnDecl<'tcx>) -> impl Iterator> { - decl.inputs.into_iter() -} - /// Checks if a given expression is a match expression expanded from the `?` /// operator or the `try` macro. pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs index 71026fb8a8c80..80493469798d6 100644 --- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs @@ -208,8 +208,7 @@ fn param_certainty(cx: &LateContext<'_>, param: &Param<'_>) -> Certainty { let Some(fn_decl) = cx.tcx.hir_fn_decl_by_hir_id(cx.tcx.local_def_id_to_hir_id(owner_did)) else { return Certainty::Uncertain; }; - let inputs = fn_decl.inputs; - inputs + fn_decl.inputs .iter() .find(|p| p.hir_id == param.hir_id) .map_or(Certainty::Uncertain, |p| type_certainty(cx, p.ty).clear_def_id()) diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index 8a73adf3e5e63..e762e929054bd 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -122,7 +122,7 @@ pub struct BindingUsageFinder<'a, 'tcx> { binding_ids: Vec, } impl<'a, 'tcx> BindingUsageFinder<'a, 'tcx> { - /// Checks whether the parameter bindings of the given [`Body`](hir::Body) are used within it. + /// Checks whether the parameter bindings of the given [`hir::FnDecl`](hir::FnDecl) are used within the corresponding [`hir::Body`](hir::Body). pub fn are_params_used(cx: &'a LateContext<'tcx>, decl: &hir::FnDecl<'_>, body: &'tcx hir::Body<'tcx>) -> bool { let mut finder = BindingUsageFinder { cx, From ab2652c247e476b2a72a4f163d0070a1c37131a4 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 8 Nov 2026 12:07:42 +0100 Subject: [PATCH 15/16] Fix ICE when a move error is generated in a const --- .../src/diagnostics/move_errors.rs | 6 ++++-- .../ui/borrowck/const-cannot-move-shared-ref.rs | 8 ++++++++ .../const-cannot-move-shared-ref.stderr | 17 +++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 tests/ui/borrowck/const-cannot-move-shared-ref.rs create mode 100644 tests/ui/borrowck/const-cannot-move-shared-ref.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 563c33e750606..b917258871ae5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -1,7 +1,7 @@ use rustc_abi::FieldIdx; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diag}; -use rustc_hir::intravisit::{HirTyCtxt, Visitor}; +use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, CaptureBy, ExprKind, HirId, Node}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -1188,7 +1188,9 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { cannot_remove: FxHashSet::default(), desugar_binding_spans: Vec::new(), }; - finder.visit_fn_decl(tcx.hir_fn_decl(self.mir_hir_id())); + if let Some(fn_decl) = tcx.hir_fn_decl_by_hir_id(self.mir_hir_id()) { + finder.visit_fn_decl(fn_decl); + } finder.visit_body(body); let mut suggestions = Vec::new(); diff --git a/tests/ui/borrowck/const-cannot-move-shared-ref.rs b/tests/ui/borrowck/const-cannot-move-shared-ref.rs new file mode 100644 index 0000000000000..5aea5da5d21ba --- /dev/null +++ b/tests/ui/borrowck/const-cannot-move-shared-ref.rs @@ -0,0 +1,8 @@ +struct NonCopy(u8); + +const C: () = { + let &moved = &NonCopy(0); + //~^ ERROR cannot move out of a shared reference +}; + +fn main() { } diff --git a/tests/ui/borrowck/const-cannot-move-shared-ref.stderr b/tests/ui/borrowck/const-cannot-move-shared-ref.stderr new file mode 100644 index 0000000000000..8cf447c6025ac --- /dev/null +++ b/tests/ui/borrowck/const-cannot-move-shared-ref.stderr @@ -0,0 +1,17 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/const-cannot-move-shared-ref.rs:4:18 + | +LL | let &moved = &NonCopy(0); + | ----- ^^^^^^^^^^^ + | | + | data moved here because `moved` has type `NonCopy`, which does not implement the `Copy` trait + | +help: consider removing the borrow + | +LL - let &moved = &NonCopy(0); +LL + let moved = &NonCopy(0); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0507`. From 6d9f63c80556db322302162e22853f33869f2b57 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 8 Nov 2026 12:15:01 +0100 Subject: [PATCH 16/16] Fix privacy not visiting parameters --- compiler/rustc_privacy/src/lib.rs | 10 +++++++++- tests/ui/privacy/privacy-in-params.rs | 20 ++++++++++++++++++++ tests/ui/privacy/privacy-in-params.stderr | 21 +++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 tests/ui/privacy/privacy-in-params.rs create mode 100644 tests/ui/privacy/privacy-in-params.stderr diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 44e128a34dad1..467cb8a3adc66 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1046,7 +1046,12 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { } impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { - fn visit_fn_decl(&mut self, _fd: &'tcx FnDecl<'tcx>) -> Self::Result {} + fn visit_fn_decl(&mut self, fd: &'tcx FnDecl<'tcx>) -> Self::Result { + if fd.fn_decl_kind.has_body() { + return; + } // Covered by the param walk in `visit_nested_body` + intravisit::walk_fn_decl(self, fd); + } fn visit_nested_body(&mut self, body_id: hir::BodyId) { let new_typeck_results = self.tcx.typeck_body(body_id); @@ -1055,6 +1060,9 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { return; } let old_maybe_typeck_results = self.maybe_typeck_results.replace(new_typeck_results); + if let Some(decl) = self.tcx.hir_fn_decl_by_hir_id(self.tcx.hir_body_owner(body_id)) { + intravisit::walk_fn_decl(self, decl); + } self.visit_body(self.tcx.hir_body(body_id)); self.maybe_typeck_results = old_maybe_typeck_results; } diff --git a/tests/ui/privacy/privacy-in-params.rs b/tests/ui/privacy/privacy-in-params.rs new file mode 100644 index 0000000000000..ba4bf97d6f3d9 --- /dev/null +++ b/tests/ui/privacy/privacy-in-params.rs @@ -0,0 +1,20 @@ +mod hidden { + pub struct Record { secret: u8 } +} + +fn leak(hidden::Record { secret }: hidden::Record) -> u8 { + //~^ ERROR field `secret` of struct `Record` is private + secret +} + +fn f() -> [u8; { let _ = hidden::Record { secret: 1 }; 0 }] { + //~^ ERROR field `secret` of struct `Record` is private + [] +} + +trait Test { + fn trait_method() -> [u8; { let _ = hidden::Record { secret: 1 }; 0 }]; + //~^ ERROR field `secret` of struct `Record` is private +} + +fn main() {} diff --git a/tests/ui/privacy/privacy-in-params.stderr b/tests/ui/privacy/privacy-in-params.stderr new file mode 100644 index 0000000000000..38196888d1b17 --- /dev/null +++ b/tests/ui/privacy/privacy-in-params.stderr @@ -0,0 +1,21 @@ +error[E0451]: field `secret` of struct `Record` is private + --> $DIR/privacy-in-params.rs:5:26 + | +LL | fn leak(hidden::Record { secret }: hidden::Record) -> u8 { + | ^^^^^^ private field + +error[E0451]: field `secret` of struct `Record` is private + --> $DIR/privacy-in-params.rs:10:43 + | +LL | fn f() -> [u8; { let _ = hidden::Record { secret: 1 }; 0 }] { + | ^^^^^^ private field + +error[E0451]: field `secret` of struct `Record` is private + --> $DIR/privacy-in-params.rs:16:58 + | +LL | fn trait_method() -> [u8; { let _ = hidden::Record { secret: 1 }; 0 }]; + | ^^^^^^ private field + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0451`.