Skip to content

Fix false positive of borrow_deref_ref #14967

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

samueltardieu
Copy link
Contributor

@samueltardieu samueltardieu commented Jun 4, 2025

If a reborrow is itself borrowed mutably, do not propose to replace it by the original reference.

Fixes: #14934

changelog: [borrow_deref_ref]: do not propose replacing a reborrow by the original reference if the reborrow is itself mutably borrowed

@rustbot
Copy link
Collaborator

rustbot commented Jun 4, 2025

r? @y21

rustbot has assigned @y21.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Jun 4, 2025
@@ -76,6 +76,9 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
&& let e_ty = cx.typeck_results().expr_ty_adjusted(e)
// check if the reference is coercing to a mutable reference
&& (!matches!(e_ty.kind(), ty::Ref(_, _, Mutability::Mut)) || is_mutable(cx, deref_target))
// If the new borrow might be itself borrowed mutably, do not propose to use
// the original reference instead.
&& !potentially_bound_to_mutable_ref(cx, e)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe worth making an exception and still lint if deref_target is not a place expr, so it's consistent with the check for &mut &* a few lines above? That way we can still emit a warning for let ref mut x = &*"string", let ref mut x = &*foo()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, deref_target has to designate a temporary value if it is reborrowed mutably.

Comment on lines 119 to 120
matches!(expr_use_ctxt(cx, expr).use_node(cx),
ExprUseNode::LetStmt(let_stmt)
if let_stmt.pat.contains_explicit_ref_binding() == Some(Mutability::Mut))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example where walking up to the use node here would help over just checking if the direct parent hir node is a let stmt node? It feels like it's doing more work while also introducing FNs (e.g. let y = &1; let ref mut x = { &*y }; was warned before but no longer is) and not actually preventing any FPs I could think of.

AFAIK, expr_use_ctxt/walk_to_expr_usage exclusively only walks through blocks, and in those cases the &*x/x reference is always copied, so the let ref mut would always mutably borrow a temporary reference either way, regardless of whether it's &*x or x?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, I couldn't produce a counter-example where walking up would help, and using the parent removes the FN. I've added this as a test as well.

If a reborrow is itself borrowed mutably, do not propose to replace it
by the original reference.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties
Projects
None yet
Development

Successfully merging this pull request may close these issues.

FP borrow_deref_ref
3 participants