Skip to content

Fix Issue#17414: needless_borrow do not contradict with `dangerous_implicit_aut…#17433

Open
skiefucker wants to merge 11 commits into
rust-lang:masterfrom
skiefucker:master
Open

Fix Issue#17414: needless_borrow do not contradict with `dangerous_implicit_aut…#17433
skiefucker wants to merge 11 commits into
rust-lang:masterfrom
skiefucker:master

Conversation

@skiefucker

@skiefucker skiefucker commented Jul 19, 2026

Copy link
Copy Markdown

Background

PR #14810 added a guard to clippy::needless_borrow to avoid contradicting this lint: it suppresses needless_borrow when the expression is &*rawptr in an unsafe context.
However, that guard only matches the literal &*rawptr shape and misses references taken through field or index access on a raw pointer, which is exactly what Issue#17414 reports:

unsafe fn f<T>(p: *const (i32, [T])) -> usize {
    unsafe {
        (&(*p).1).len() // rustc suggests adding &, clippy then suggests removing it
    }
}

Fix

Remove the narrow &*rawptr pattern guard with a finer-grained check, add func need_explicit_ref, which mirrors the actual trigger condition of rustc's dangerous_implicit_autorefs lint rather than pattern-matching a single expression shape.

The check has two parts:

  1. Raw pointer source: starting from the borrowed sub_expr, walk down through Field / Index / AddrOf until reaching a Unary(Deref, e), and verify that e's type is a raw pointer.

  2. #[rustc_no_implicit_autorefs] method call: starting from the outer expr, walk up through use sites (via expr_use_sites) until finding a MethodCall, then check whether the callee's DefId carries #[rustc_no_implicit_autorefs] (e.g. slice::len, slice::is_empty).

If both conditions hold, needless_borrow is skipped, since removing the & would make rustc's dangerous_implicit_autorefs fire.

Test

Added issue_17414 to tests/ui/needless_borrow.rs covering:

# Expression Expected Why
1 (&(*tuple_slice).field).method() no lint the reported case — & is mandatory
2 (&*raw_slice).len() no lint direct deref, slice::len has the attr
3 (&*nested_tuple).a.b.method() and (&(*nested_tuple).a).b.method() no lint nested field chains
4 (&*raw_array).index(0) no lint Index::index carries the attr
5 (&*dyn_trait)[0] / (&*dyn_trait).index(0) no lint trait method dispatch through raw ptr
6 (&*raw_slice)[0] lint Resolved
7 (&*nested_tuple).1.1.first() lints slice::first does NOT carry the attr — confirms we don't over-suppress
8 (&slice).1.1.len() on a non-raw reference lints positive case, lint still fires where it should

Run:
WinPS: $env:TESTNAME="needless_borrow"; cargo uibless
Linux: TESTNAME=needless_borrow cargo uibless

Open questions for reviewers

1. Over-suppression on [] indexing of slice/array (Resolved)

According to rustc_lint::autoref.rs, different Index operation have different Adjustments!

(*slice)[0] can compile, but index method of Index trait has #[rustc_no_implicit_autorefs]. Array is the same.

Index operation of slice/array not call Index::index ?

So, & in (&*slice)[0] may be needless. The test marks this case as // TODO needless, should lint.

2. Other HIR nodes in the receiver chain

Is there any other operation from deref raw pointer to method call with #[rustc_no_implicit_autorefs]?
I only handle and skip Field/Index in dereference.rs:773. I couldn't construct a counterexample but would appreciate a sanity check.

3. specail case with redundant slicing

This case will trigger both reduntdant slicing and needless borrow :

let _ = &(&*v)[..];

changelog: [needless_borrow]: do not contradict dangerous_implicit_autorefs.

…orefs`

Add Logic:
If the innermost expression of the borrow is a deref of a raw pointer, and the borrow after multiple Index/Field operations, is used to call a method with `#[rustc_no_implicit_autorefs]`, skip the lint.

Remove the narrow `&*raw_ptr` pattern check added in PR rust-lang#14810. The old guard only matched the literal `&*raw_ptr`.

Add Test `issue_17414` to `tests/ui/needless_borrow.rs` covering:
- `(&(*tuple_slice).field).method()` — the reported case
- `(&*raw_slice).len()` and `(&*raw_slice)[idx]` — direct deref
- nested tuple field access through a raw pointer
- array indexing via `Index::index` on a raw pointer
- trait method dispatch (`dyn T`) through a raw pointer

Problems Left:
- Index Op of slice/array: `(*slice)[0]` can compile, but index method of Index trait has `#[rustc_no_implicit_autorefs]`. (See codes in tests/ui/needless_borrow.rs)
- Is there any other operation between deref raw pointer and method with #[rustc_no_implicit_autorefs]?

changelog: [`needless_borrow`]: do not contradict `dangerous_implicit_autorefs`.
@rustbot rustbot added S-waiting-on-community-reviews Status: This is awaiting for positive reviews from the community before a maintainer is assigned. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties labels Jul 19, 2026
@rustbot

rustbot commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the pull request, and welcome!

You should hear from one of our reviewers after this PR gets at least 2 reviews from the community.

Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (S-waiting-on-review and S-waiting-on-author) stays updated, invoking these commands when appropriate:

  • @rustbot author: the review is finished, PR author should check the comments and take action accordingly
  • @rustbot review: the author is ready for a review, this PR will be queued again in the reviewer's queue

@rustbot

This comment has been minimized.

…orefs`

Add Logic:
If the innermost expression of the borrow is a deref of a raw pointer, and the borrow after multiple Index/Field operations, is used to call a method with `#[rustc_no_implicit_autorefs]`, skip the lint.

Remove the narrow `&*raw_ptr` pattern check added in PR rust-lang#14810. The old guard only matched the literal `&*raw_ptr`.

Add Test `issue_17414` to `tests/ui/needless_borrow.rs` covering:
- `(&(*tuple_slice).field).method()` — the reported case
- `(&*raw_slice).len()` and `(&*raw_slice)[idx]` — direct deref
- nested tuple field access through a raw pointer
- array indexing via `Index::index` on a raw pointer
- trait method dispatch (`dyn T`) through a raw pointer

Problems Left:
- Index Op of slice/array: `(*slice)[0]` can compile, but index method of Index trait has `#[rustc_no_implicit_autorefs]`. (See codes in tests/ui/needless_borrow.rs)
- Is there any other operation between deref raw pointer and method with #[rustc_no_implicit_autorefs]?

changelog: [`needless_borrow`]: do not contradict `dangerous_implicit_autorefs`.
@rustbot

rustbot commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator

⚠️ Warning ⚠️

  • There are issue links (such as #123) in the commit messages of the following commits.
    Please move them to the PR description, to avoid spamming the issues with references to the commit, and so this bot can automatically canonicalize them to avoid issues with subtree.

…orefs`

Add Logic:
If the innermost expression of the borrow is a deref of a raw pointer, and the borrow after multiple Index/Field operations, is used to call a method with `#[rustc_no_implicit_autorefs]`, skip the lint.

Remove the narrow `&*raw_ptr` pattern check added in PR14810. The old guard only matched the literal `&*raw_ptr`.

Add Test `issue_17414` to `tests/ui/needless_borrow.rs` covering:
- `(&(*tuple_slice).field).method()` — the reported case
- `(&*raw_slice).len()` and `(&*raw_slice)[idx]` — direct deref
- nested tuple field access through a raw pointer
- array indexing via `Index::index` on a raw pointer
- trait method dispatch (`dyn T`) through a raw pointer

Problems Left:
- Index Op of slice/array: `(*slice)[0]` can compile, but index method of Index trait has `#[rustc_no_implicit_autorefs]`. (See codes in tests/ui/needless_borrow.rs)
- Is there any other operation between deref raw pointer and method with #[rustc_no_implicit_autorefs]?

changelog: [`needless_borrow`]: do not contradict `dangerous_implicit_autorefs`.
@github-actions

github-actions Bot commented Jul 19, 2026

Copy link
Copy Markdown

Lintcheck changes for a74342f

Lint Added Removed Changed
clippy::multiple_crate_versions 0 0 3
clippy::needless_borrow 4 0 0

This comment will be updated if you push new changes

@poliorcetics poliorcetics left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

community review: one small code change and one question, but otherwise looks good!

EDIT: Also, it's super annoying to read LLM-written MR descriptions, they're a hundred times too long for absolutely useless content, please don't impose that on us

View changes since this review

Comment thread clippy_lints/src/dereference.rs Outdated
Comment thread tests/ui/needless_borrow.rs Outdated
skiefucker and others added 7 commits July 21, 2026 10:07
needless variable

Co-authored-by: Poliorcetics <poliorcetics@users.noreply.github.com>
One of Fix: `needless_borrow` do not contradict with `dangerous_implicit_autorefs`
1. add needless_borrow lint to a normal index operation.
2. skip this check for raw pointer because explicit borrow is necessary.
1. add needless_borrow lint to a normal index operation.
2. skip this check for raw pointer because explicit borrow is necessary.
1. add needless_borrow lint to a normal index operation.
2. skip this check for raw pointer because explicit borrow is necessary.
1. add needless_borrow lint to a normal index operation.
2. skip this check for raw pointer because explicit borrow is necessary.
1. add needless_borrow lint to a normal index operation.
2. skip this check for raw pointer because explicit borrow is necessary.

@poliorcetics poliorcetics left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

community review: Some small nits but nothing big now, good work on resolving the indexing issue!

View changes since this review

Comment thread clippy_lints/src/dereference.rs Outdated
Comment on lines 2 to +3
#![expect(clippy::deref_by_slicing)]
#![allow(clippy::needless_borrow)]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
#![expect(clippy::deref_by_slicing)]
#![allow(clippy::needless_borrow)]
#![expect(clippy::deref_by_slicing, clippy::needless_borrow)]

To follow the existing pattern and avoid cruft longer term

@@ -1,5 +1,6 @@
#![warn(clippy::redundant_slicing)]
#![expect(clippy::deref_by_slicing)]
#![allow(clippy::needless_borrow)]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

same here

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

If change to #![expect(clippy::deref_by_slicing, clippy::needless_borrow)] happens:

error: test got exit code: 1, but expected 0
 --> tests/ui/redundant_slicing.fixed:2:37
  |
2 | #![expect(clippy::deref_by_slicing, clippy::needless_borrow)]
  |                                     ^^^^^^^^^^^^^^^^^^^^^^^ after rustfix is applied, all errors should be gone, but weren't
  |

full stderr:
error: this lint expectation is unfulfilled
  --> tests\ui\redundant_slicing.fixed:2:37
   |
LL | #![expect(clippy::deref_by_slicing, clippy::needless_borrow)]
   |                                     ^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: `-D unfulfilled-lint-expectations` implied by `-D warnings`
   = help: to override `-D warnings` add `#[allow(unfulfilled_lint_expectations)]`

error: aborting due to 1 previous error

My opinion:
let _ = &(&*v)[..]; will trigger both redundant_slicing and needless_borrow.

redundant_slicing suggest: let _ = &(&*v)[..]; -> let _ = (&*v);
needless_borrow suggest: let _ = &(&*v)[..]; -> let _ = &(*v)[..];

When redundant_slicing.fixed accept first suggest, code change to let _ = (&*v);, and needless_borrow will not trigger but expect it, then error came.

I tried many times, putting needless_borrow in warn or expect all failed (only putting it in allow worked, of course!!). Or there are other better way I don't know??

Comment thread clippy_lints/src/dereference.rs
Comment thread clippy_lints/src/dereference.rs Outdated
@viliml

viliml commented Jul 22, 2026

Copy link
Copy Markdown

Also, it's super annoying to read LLM-written MR descriptions, they're a hundred times too long for absolutely useless content, please don't impose that on us

The formatting initially made me think of LLMs, but the tone made me reconsider. If that really was written by an LLM, I'll have to recalibrate my radar.

@skiefucker

Copy link
Copy Markdown
Author

Also, it's super annoying to read LLM-written MR descriptions, they're a hundred times too long for absolutely useless content, please don't impose that on us

The formatting initially made me think of LLMs, but the tone made me reconsider. If that really was written by an LLM, I'll have to recalibrate my radar.

Sorry about this, I'm not a native English Speaker, And this is also my first PR. I can type some simple words, but if things go harder, I have to use LLM to translate and optimize. With reading and writing more in community, maybe I can do it by myself.

Thanks for all these suggestions !!! :)

@Jarcho

Jarcho commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Sorry about this, I'm not a native English Speaker, And this is also my first PR. I can type some simple words, but if things go harder, I have to use LLM to translate and optimize. With reading and writing more in community, maybe I can do it by myself.

We will have a policy on LLM use (see rust-lang/rust-forge#1040) of which the relevant part can be summed up as "don't llm generate PR descriptions/comments". Translation is one thing and fine (though it should be noted), but using it to "improve"/expand the writing significantly less so.

@skiefucker

Copy link
Copy Markdown
Author

Sorry about this, I'm not a native English Speaker, And this is also my first PR. I can type some simple words, but if things go harder, I have to use LLM to translate and optimize. With reading and writing more in community, maybe I can do it by myself.

We will have a policy on LLM use (see rust-lang/rust-forge#1040) of which the relevant part can be summed up as "don't llm generate PR descriptions/comments". Translation is one thing and fine (though it should be noted), but using it to "improve"/expand the writing significantly less so.

Copy that !!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-community-reviews Status: This is awaiting for positive reviews from the community before a maintainer is assigned. 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.

6 participants