Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 22 additions & 7 deletions compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,18 +410,18 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
let typeck = self.infcx.tcx.typeck(self.mir_def_id());
let parent = self.infcx.tcx.parent_hir_node(expr.hir_id);
let (def_id, call_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
&& let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
{
let def_id = typeck.type_dependent_def_id(parent_expr.hir_id);
(def_id, Some(parent_expr.hir_id), args, 1)
(def_id, args, 1)
} else if let hir::Node::Expr(parent_expr) = parent
&& let hir::ExprKind::Call(call, args) = parent_expr.kind
&& let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind()
{
(Some(*def_id), Some(call.hir_id), args, 0)
(Some(*def_id), args, 0)
} else {
(None, None, &[][..], 0)
(None, &[][..], 0)
};
let ty = place.ty(self.body, self.infcx.tcx).ty;

Expand Down Expand Up @@ -459,11 +459,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
// If the moved place is used generically by the callee and a reference to it
// would still satisfy any bounds on its type, suggest borrowing.
if let Some(&param) = arg_param
&& let Some(generic_args) = call_id.and_then(|id| typeck.node_args_opt(id))
&& let hir::Node::Expr(call_expr) = parent
&& let Some(ref_mutability) = self.suggest_borrow_generic_arg(
err,
typeck,
call_expr,
def_id,
generic_args,
param,
moved_place,
pos + offset,
Expand Down Expand Up @@ -627,8 +628,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
fn suggest_borrow_generic_arg(
&self,
err: &mut Diag<'_>,
typeck: &ty::TypeckResults<'tcx>,
call_expr: &hir::Expr<'tcx>,
callee_did: DefId,
generic_args: ty::GenericArgsRef<'tcx>,
param: ty::ParamTy,
moved_place: PlaceRef<'tcx>,
moved_arg_pos: usize,
Expand All @@ -639,6 +641,19 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let sig = tcx.fn_sig(callee_did).instantiate_identity().skip_binder();
let clauses = tcx.predicates_of(callee_did);

let generic_args = match call_expr.kind {
// For method calls, generic arguments are attached to the call node.
hir::ExprKind::MethodCall(..) => typeck.node_args_opt(call_expr.hir_id)?,
// For normal calls, generic arguments are in the callee's type.
// This diagnostic is only run for `FnDef` callees.
hir::ExprKind::Call(callee, _)
if let &ty::FnDef(_, args) = typeck.node_type(callee.hir_id).kind() =>
{
args
}
_ => return None,
};

// First, is there at least one method on one of `param`'s trait bounds?
// This keeps us from suggesting borrowing the argument to `mem::drop`, e.g.
if !clauses.instantiate_identity(tcx).predicates.iter().any(|clause| {
Expand Down
13 changes: 13 additions & 0 deletions tests/ui/moves/use-correct-generic-args-in-borrow-suggest.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//! Regression test for #145164: For normal calls, make sure the suggestion to borrow generic inputs
//! uses the generic args from the callee's type rather than those attached to the callee's HIR
//! node. In cases where the callee isn't an identifier expression, its HIR node won't have its
//! generic arguments attached, which could lead to ICE when it had other generic args. In this
//! case, the callee expression is `run.clone()`, to which `clone`'s generic arguments are attached.

fn main() {
let value = String::new();
run.clone()(value, ());
run(value, ());
//~^ ERROR use of moved value: `value`
}
fn run<F, T: Clone>(value: T, f: F) {}
18 changes: 18 additions & 0 deletions tests/ui/moves/use-correct-generic-args-in-borrow-suggest.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error[E0382]: use of moved value: `value`
--> $DIR/use-correct-generic-args-in-borrow-suggest.rs:10:9
|
LL | let value = String::new();
| ----- move occurs because `value` has type `String`, which does not implement the `Copy` trait
LL | run.clone()(value, ());
| ----- value moved here
LL | run(value, ());
| ^^^^^ value used here after move
|
help: consider borrowing `value`
|
LL | run.clone()(&value, ());
| +

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0382`.
Loading