Skip to content

Commit b510557

Browse files
committed
Auto merge of #9645 - Jarcho:ptr_arg_9542, r=llogiq
Don't lint `ptr_arg` when used as an incompatible trait object fixes #9542 changelog: [`ptr_arg`](https://rust-lang.github.io/rust-clippy/master/#ptr_arg): Don't lint when used as an incompatible trait object
2 parents efa361b + 344b7bc commit b510557

File tree

3 files changed

+93
-3
lines changed

3 files changed

+93
-3
lines changed

clippy_lints/src/ptr.rs

+45-1
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,17 @@ use rustc_hir::{
1515
ImplItemKind, ItemKind, Lifetime, LifetimeName, Mutability, Node, Param, ParamName, PatKind, QPath, TraitFn,
1616
TraitItem, TraitItemKind, TyKind, Unsafety,
1717
};
18+
use rustc_infer::infer::TyCtxtInferExt;
19+
use rustc_infer::traits::{Obligation, ObligationCause};
1820
use rustc_lint::{LateContext, LateLintPass};
1921
use rustc_middle::hir::nested_filter;
20-
use rustc_middle::ty::{self, Ty};
22+
use rustc_middle::ty::{self, Binder, ExistentialPredicate, List, PredicateKind, Ty};
2123
use rustc_session::{declare_lint_pass, declare_tool_lint};
2224
use rustc_span::source_map::Span;
2325
use rustc_span::sym;
2426
use rustc_span::symbol::Symbol;
27+
use rustc_trait_selection::infer::InferCtxtExt as _;
28+
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
2529
use std::fmt;
2630
use std::iter;
2731

@@ -384,6 +388,17 @@ enum DerefTy<'tcx> {
384388
Slice(Option<Span>, Ty<'tcx>),
385389
}
386390
impl<'tcx> DerefTy<'tcx> {
391+
fn ty(&self, cx: &LateContext<'tcx>) -> Ty<'tcx> {
392+
match *self {
393+
Self::Str => cx.tcx.types.str_,
394+
Self::Path => cx.tcx.mk_adt(
395+
cx.tcx.adt_def(cx.tcx.get_diagnostic_item(sym::Path).unwrap()),
396+
List::empty(),
397+
),
398+
Self::Slice(_, ty) => cx.tcx.mk_slice(ty),
399+
}
400+
}
401+
387402
fn argless_str(&self) -> &'static str {
388403
match *self {
389404
Self::Str => "str",
@@ -581,6 +596,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
581596
let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0);
582597
if expr_sig(self.cx, f).and_then(|sig| sig.input(i)).map_or(true, |ty| {
583598
match *ty.skip_binder().peel_refs().kind() {
599+
ty::Dynamic(preds, _, _) => !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds),
584600
ty::Param(_) => true,
585601
ty::Adt(def, _) => def.did() == args.ty_did,
586602
_ => false,
@@ -614,6 +630,9 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
614630
};
615631

616632
match *self.cx.tcx.fn_sig(id).skip_binder().inputs()[i].peel_refs().kind() {
633+
ty::Dynamic(preds, _, _) if !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds) => {
634+
set_skip_flag();
635+
},
617636
ty::Param(_) => {
618637
set_skip_flag();
619638
},
@@ -665,6 +684,31 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
665684
v.results
666685
}
667686

687+
fn matches_preds<'tcx>(
688+
cx: &LateContext<'tcx>,
689+
ty: Ty<'tcx>,
690+
preds: &'tcx [Binder<'tcx, ExistentialPredicate<'tcx>>],
691+
) -> bool {
692+
cx.tcx.infer_ctxt().enter(|infcx| {
693+
preds.iter().all(|&p| match cx.tcx.erase_late_bound_regions(p) {
694+
ExistentialPredicate::Trait(p) => infcx
695+
.type_implements_trait(p.def_id, ty, p.substs, cx.param_env)
696+
.must_apply_modulo_regions(),
697+
ExistentialPredicate::Projection(p) => infcx.predicate_must_hold_modulo_regions(&Obligation::new(
698+
ObligationCause::dummy(),
699+
cx.param_env,
700+
cx.tcx.mk_predicate(Binder::bind_with_vars(
701+
PredicateKind::Projection(p.with_self_ty(cx.tcx, ty)),
702+
List::empty(),
703+
)),
704+
)),
705+
ExistentialPredicate::AutoTrait(p) => infcx
706+
.type_implements_trait(p, ty, List::empty(), cx.param_env)
707+
.must_apply_modulo_regions(),
708+
})
709+
})
710+
}
711+
668712
fn get_rptr_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
669713
if let TyKind::Rptr(lt, ref m) = ty.kind {
670714
Some((lt, m.mutbl, ty.span))

tests/ui/ptr_arg.rs

+29-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#![warn(clippy::ptr_arg)]
44

55
use std::borrow::Cow;
6-
use std::path::PathBuf;
6+
use std::path::{Path, PathBuf};
77

88
fn do_vec(x: &Vec<i64>) {
99
//Nothing here
@@ -207,3 +207,31 @@ fn cow_conditional_to_mut(a: &mut Cow<str>) {
207207
a.to_mut().push_str("foo");
208208
}
209209
}
210+
211+
// Issue #9542
212+
fn dyn_trait_ok(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
213+
trait T {}
214+
impl<U> T for Vec<U> {}
215+
impl T for String {}
216+
impl T for PathBuf {}
217+
fn takes_dyn(_: &mut dyn T) {}
218+
219+
takes_dyn(a);
220+
takes_dyn(b);
221+
takes_dyn(c);
222+
}
223+
224+
fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
225+
trait T {}
226+
impl<U> T for Vec<U> {}
227+
impl<U> T for [U] {}
228+
impl T for String {}
229+
impl T for str {}
230+
impl T for PathBuf {}
231+
impl T for Path {}
232+
fn takes_dyn(_: &mut dyn T) {}
233+
234+
takes_dyn(a);
235+
takes_dyn(b);
236+
takes_dyn(c);
237+
}

tests/ui/ptr_arg.stderr

+19-1
Original file line numberDiff line numberDiff line change
@@ -162,5 +162,23 @@ error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a sl
162162
LL | fn mut_vec_slice_methods(v: &mut Vec<u32>) {
163163
| ^^^^^^^^^^^^^ help: change this to: `&mut [u32]`
164164

165-
error: aborting due to 17 previous errors
165+
error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do
166+
--> $DIR/ptr_arg.rs:224:17
167+
|
168+
LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
169+
| ^^^^^^^^^^^^^ help: change this to: `&mut [u32]`
170+
171+
error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do
172+
--> $DIR/ptr_arg.rs:224:35
173+
|
174+
LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
175+
| ^^^^^^^^^^^ help: change this to: `&mut str`
176+
177+
error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do
178+
--> $DIR/ptr_arg.rs:224:51
179+
|
180+
LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
181+
| ^^^^^^^^^^^^ help: change this to: `&mut Path`
182+
183+
error: aborting due to 20 previous errors
166184

0 commit comments

Comments
 (0)