-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Description
Summary
When checking for the usages of a function argument of type &PathBuf
, the lint incorrectly considers it unlintable if it's used as an argument to a function whose parameter at that place is impl AsRef<Path>
(as is most often the case with functions that work on paths). The lint doesn't realize that &Path
would work there just as well.
I noticed this when looking into #15504, but decided not to start working on it for now, because of the feature freeze. But I've made a couple of test cases:
mod issue15505 {
use std::path::{Path, PathBuf};
fn takes_asref_path(_: &dyn AsRef<Path>) {}
fn takes_independent_asref_paths(_: impl AsRef<Path>, _: impl AsRef<Path>) {}
fn takes_same_asref_paths<P: AsRef<Path>>(_: P, _: P) {}
fn simple(p: &PathBuf) {
//~^ ptr_arg
takes_asref_path(p);
}
fn can_replace_when_independent_path(p: &PathBuf) {
//~^ ptr_arg
takes_independent_asref_paths(p, Path::new("foo"))
}
fn can_replace_when_independent_pathbuf(p: &PathBuf) {
//~^ ptr_arg
takes_independent_asref_paths(p, &PathBuf::new())
}
fn cant_replace_when_dependent(p: &PathBuf) {
// because of the second arg, the first one needs to be `&PathBuf` as well
takes_same_asref_paths(p, &PathBuf::new())
}
}
If I end up forgetting about this, feel free to pick it up.
Some hints:
The lint already works with parameters like dyn AsRef<Path>
, but that's because for those, the argument is just a bunch of trait bounds (which we check against for the deref type), whereas with impl AsRef<Path>
we see only the function instantiated for our particular type. We should probably:
- resolve its path
- see if the argument our thing is passed in is a generic
P
- make sure that
P
isn't used in any other parameters (see the last test) - check whether our deref type implements the trait bounds of
P
as well (using the logic similar to that fordyn
)
Lint Name
ptr_arg
Reproducer
I tried this code:
fn takes_asref_path(_: impl AsRef<Path>) {}
fn simple(p: &PathBuf) {
takes_asref_path(p);
}
I expected to see this happen:
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
--> tests/ui/ptr_arg.rs:451:18
|
LL | fn simple(p: &PathBuf) {
| ^^^^^^^^ help: change this to: `&Path`
Instead, this happened:
Version
rustc 1.91.0-nightly (7d82b83ed 2025-08-06)
binary: rustc
commit-hash: 7d82b83ed57d188ab3f2441a765a6419685a88a3
commit-date: 2025-08-06
host: x86_64-unknown-linux-gnu
release: 1.91.0-nightly
LLVM version: 21.1.0