diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index df1a1411cf5..238e4a992a9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -937,56 +937,81 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let node = self.infcx.tcx.hir_node(fn_call_id); let def_id = hir.enclosing_body_owner(fn_call_id); let mut look_at_return = true; - // If we can detect the expression to be an `fn` call where the closure was an argument, - // we point at the `fn` definition argument... - if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Call(func, args), .. }) = node { - let arg_pos = args + + // If the HIR node is a function or method call gets the def ID + // of the called function or method and the span and args of the call expr + let get_call_details = || { + let hir::Node::Expr(hir::Expr { hir_id, kind, .. }) = node else { + return None; + }; + + let typeck_results = self.infcx.tcx.typeck(def_id); + + match kind { + hir::ExprKind::Call(expr, args) => { + if let Some(ty::FnDef(def_id, _)) = + typeck_results.node_type_opt(expr.hir_id).as_ref().map(|ty| ty.kind()) + { + Some((*def_id, expr.span, *args)) + } else { + None + } + } + hir::ExprKind::MethodCall(_, _, args, span) => { + if let Some(def_id) = typeck_results.type_dependent_def_id(*hir_id) { + Some((def_id, *span, *args)) + } else { + None + } + } + _ => None, + } + }; + + // If we can detect the expression to be an function or method call where the closure was an argument, + // we point at the function or method definition argument... + if let Some((callee_def_id, call_span, call_args)) = get_call_details() { + let arg_pos = call_args .iter() .enumerate() .filter(|(_, arg)| arg.hir_id == closure_id) .map(|(pos, _)| pos) .next(); - let tables = self.infcx.tcx.typeck(def_id); - if let Some(ty::FnDef(def_id, _)) = - tables.node_type_opt(func.hir_id).as_ref().map(|ty| ty.kind()) - { - let arg = match hir.get_if_local(*def_id) { - Some( - hir::Node::Item(hir::Item { - ident, kind: hir::ItemKind::Fn(sig, ..), .. + + let arg = match hir.get_if_local(callee_def_id) { + Some( + hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(sig, ..), .. }) + | hir::Node::TraitItem(hir::TraitItem { + ident, + kind: hir::TraitItemKind::Fn(sig, _), + .. + }) + | hir::Node::ImplItem(hir::ImplItem { + ident, + kind: hir::ImplItemKind::Fn(sig, _), + .. + }), + ) => Some( + arg_pos + .and_then(|pos| { + sig.decl.inputs.get( + pos + if sig.decl.implicit_self.has_implicit_self() { + 1 + } else { + 0 + }, + ) }) - | hir::Node::TraitItem(hir::TraitItem { - ident, - kind: hir::TraitItemKind::Fn(sig, _), - .. - }) - | hir::Node::ImplItem(hir::ImplItem { - ident, - kind: hir::ImplItemKind::Fn(sig, _), - .. - }), - ) => Some( - arg_pos - .and_then(|pos| { - sig.decl.inputs.get( - pos + if sig.decl.implicit_self.has_implicit_self() { - 1 - } else { - 0 - }, - ) - }) - .map(|arg| arg.span) - .unwrap_or(ident.span), - ), - _ => None, - }; - if let Some(span) = arg { - err.span_label(span, "change this to accept `FnMut` instead of `Fn`"); - err.span_label(func.span, "expects `Fn` instead of `FnMut`"); - err.span_label(closure_span, "in this closure"); - look_at_return = false; - } + .map(|arg| arg.span) + .unwrap_or(ident.span), + ), + _ => None, + }; + if let Some(span) = arg { + err.span_label(span, "change this to accept `FnMut` instead of `Fn`"); + err.span_label(call_span, "expects `Fn` instead of `FnMut`"); + err.span_label(closure_span, "in this closure"); + look_at_return = false; } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 2cf548e28b1..77fb9fb4315 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -628,9 +628,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { | GenericArgKind::Const(_), _, ) => { - // This was previously a `span_delayed_bug` and could be - // reached by the test for #82126, but no longer. - self.dcx().span_bug( + self.dcx().span_delayed_bug( hir_arg.span(), format!("unmatched arg and hir arg: found {kind:?} vs {hir_arg:?}"), ); diff --git a/tests/crashes/126385.rs b/tests/crashes/126385.rs deleted file mode 100644 index 9e74e88c1ff..00000000000 --- a/tests/crashes/126385.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: rust-lang/rust#126385 -pub struct MyStruct<'field> { - field: &'_ [u32], -} - -impl MyStruct<'_> { - pub fn _<'a>(field: &'a[u32]) -> Self { - Self{field} - } -} diff --git a/tests/run-make/const_fn_mir/rmake.rs b/tests/run-make/const_fn_mir/rmake.rs index a4cc4299b1b..1ba93421855 100644 --- a/tests/run-make/const_fn_mir/rmake.rs +++ b/tests/run-make/const_fn_mir/rmake.rs @@ -1,5 +1,7 @@ // The `needs-unwind -Cpanic=abort` gives a different MIR output. +//@ needs-unwind + use run_make_support::{cwd, diff, rustc}; fn main() { diff --git a/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.rs b/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.rs new file mode 100644 index 00000000000..637c47f2939 --- /dev/null +++ b/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.rs @@ -0,0 +1,14 @@ +// This test was triggering a `span_bug` crash, which was then fixed by +// downgrading it to a `span_delayed_bug`. + +pub struct MyStruct<'field> { + field: &'field [u32], +} + +impl MyStruct<'_> { + pub fn f(field: &[u32]) -> Self { //~ ERROR type arguments are not allowed on self type + Self { field } //~ ERROR lifetime may not live long enough + } +} + +fn main() {} diff --git a/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.stderr b/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.stderr new file mode 100644 index 00000000000..0ae301b2090 --- /dev/null +++ b/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.stderr @@ -0,0 +1,34 @@ +error[E0109]: type arguments are not allowed on self type + --> $DIR/unmatched-arg-and-hir-arg-issue-126385.rs:9:37 + | +LL | pub fn f(field: &[u32]) -> Self { + | ---- ^^^ type argument not allowed + | | + | not allowed on self type + | +note: `Self` is of type `MyStruct<'_>` + --> $DIR/unmatched-arg-and-hir-arg-issue-126385.rs:4:12 + | +LL | pub struct MyStruct<'field> { + | ^^^^^^^^ `Self` corresponds to this type +... +LL | impl MyStruct<'_> { + | ----------------- `Self` is on type `MyStruct` in this `impl` +help: the `Self` type doesn't accept type parameters, use the concrete type's name `MyStruct` instead if you want to specify its type parameters + | +LL | pub fn f(field: &[u32]) -> MyStruct { + | ~~~~~~~~ + +error: lifetime may not live long enough + --> $DIR/unmatched-arg-and-hir-arg-issue-126385.rs:10:9 + | +LL | pub fn f(field: &[u32]) -> Self { + | - --------- return type is MyStruct<'2> + | | + | let's call the lifetime of this reference `'1` +LL | Self { field } + | ^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0109`. diff --git a/tests/ui/closures/wrong-closure-arg-suggestion-125325.rs b/tests/ui/closures/wrong-closure-arg-suggestion-125325.rs new file mode 100644 index 00000000000..ce575697cf6 --- /dev/null +++ b/tests/ui/closures/wrong-closure-arg-suggestion-125325.rs @@ -0,0 +1,29 @@ +// Regression test for #125325 + +// Tests that we suggest changing an `impl Fn` param +// to `impl FnMut` when the provided closure arg +// is trying to mutate the closure env. +// Ensures that it works that way for both +// functions and methods + +struct S; + +impl S { + fn assoc_func(&self, _f: impl Fn()) -> usize { + 0 + } +} + +fn func(_f: impl Fn()) -> usize { + 0 +} + +fn test_func(s: &S) -> usize { + let mut x = (); + s.assoc_func(|| x = ()); + //~^ cannot assign to `x`, as it is a captured variable in a `Fn` closure + func(|| x = ()) + //~^ cannot assign to `x`, as it is a captured variable in a `Fn` closure +} + +fn main() {} diff --git a/tests/ui/closures/wrong-closure-arg-suggestion-125325.stderr b/tests/ui/closures/wrong-closure-arg-suggestion-125325.stderr new file mode 100644 index 00000000000..e0cce8c4b31 --- /dev/null +++ b/tests/ui/closures/wrong-closure-arg-suggestion-125325.stderr @@ -0,0 +1,28 @@ +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure + --> $DIR/wrong-closure-arg-suggestion-125325.rs:23:21 + | +LL | fn assoc_func(&self, _f: impl Fn()) -> usize { + | --------- change this to accept `FnMut` instead of `Fn` +... +LL | s.assoc_func(|| x = ()); + | --------------^^^^^^- + | | | | + | | | cannot assign + | | in this closure + | expects `Fn` instead of `FnMut` + +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure + --> $DIR/wrong-closure-arg-suggestion-125325.rs:25:13 + | +LL | fn func(_f: impl Fn()) -> usize { + | --------- change this to accept `FnMut` instead of `Fn` +... +LL | func(|| x = ()) + | ---- -- ^^^^^^ cannot assign + | | | + | | in this closure + | expects `Fn` instead of `FnMut` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0594`.