Skip to content

Commit 0d4a5c7

Browse files
committed
Make deref_into_dyn_supertrait lint the impl and not the usage
1 parent 11a5386 commit 0d4a5c7

File tree

6 files changed

+102
-64
lines changed

6 files changed

+102
-64
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
use crate::{LateContext, LateLintPass, LintContext};
2+
3+
use rustc_errors::DelayDm;
4+
use rustc_hir as hir;
5+
use rustc_middle::{traits::util::supertraits, ty};
6+
7+
declare_lint! {
8+
/// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the
9+
/// `Deref` implementation with a `dyn SuperTrait` type as `Output`.
10+
///
11+
/// These implementations will become shadowed when the `trait_upcasting` feature is stabilized.
12+
/// The `deref` functions will no longer be called implicitly, so there might be behavior change.
13+
///
14+
/// ### Example
15+
///
16+
/// ```rust,compile_fail
17+
/// #![deny(deref_into_dyn_supertrait)]
18+
/// #![allow(dead_code)]
19+
///
20+
/// use core::ops::Deref;
21+
///
22+
/// trait A {}
23+
/// trait B: A {}
24+
/// impl<'a> Deref for dyn 'a + B {
25+
/// type Target = dyn A;
26+
/// fn deref(&self) -> &Self::Target {
27+
/// todo!()
28+
/// }
29+
/// }
30+
///
31+
/// fn take_a(_: &dyn A) { }
32+
///
33+
/// fn take_b(b: &dyn B) {
34+
/// take_a(b);
35+
/// }
36+
/// ```
37+
///
38+
/// {{produces}}
39+
///
40+
/// ### Explanation
41+
///
42+
/// The dyn upcasting coercion feature adds new coercion rules, taking priority
43+
/// over certain other coercion rules, which will cause some behavior change.
44+
pub DEREF_INTO_DYN_SUPERTRAIT,
45+
Warn,
46+
"`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future",
47+
@future_incompatible = FutureIncompatibleInfo {
48+
reference: "issue #89460 <https://github.com/rust-lang/rust/issues/89460>",
49+
};
50+
}
51+
52+
declare_lint_pass!(DerefIntoDynSupertrait => [DEREF_INTO_DYN_SUPERTRAIT]);
53+
54+
impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
55+
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
56+
// `Deref` is being implemented for `t`
57+
if let hir::ItemKind::Impl(impl_) = item.kind
58+
&& let Some(trait_) = &impl_.of_trait
59+
&& let t = cx.tcx.type_of(item.owner_id)
60+
&& let opt_did @ Some(did) = trait_.trait_def_id()
61+
&& opt_did == cx.tcx.lang_items().deref_trait()
62+
// `t` is `dyn t_principal`
63+
&& let ty::Dynamic(data, _, ty::Dyn) = t.kind()
64+
&& let Some(t_principal) = data.principal()
65+
// `<T as Deref>::Target` is `dyn target_principal`
66+
&& let Some(target) = cx.get_associated_type(t, did, "Target")
67+
&& let ty::Dynamic(data, _, ty::Dyn) = target.kind()
68+
&& let Some(target_principal) = data.principal()
69+
// `target_principal` is a supertrait of `t_principal`
70+
&& supertraits(cx.tcx, t_principal.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self))
71+
.any(|sup| sup.map_bound(|x| ty::ExistentialTraitRef::erase_self_ty(cx.tcx, x)) == target_principal)
72+
{
73+
cx.struct_span_lint(
74+
DEREF_INTO_DYN_SUPERTRAIT,
75+
item.span,
76+
DelayDm(|| {
77+
format!(
78+
"`{t}` implements `Deref` with supertrait `{target_principal}` as output"
79+
)
80+
}),
81+
|lint| lint,
82+
)
83+
}
84+
}
85+
}

compiler/rustc_lint/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ extern crate tracing;
4949
mod array_into_iter;
5050
pub mod builtin;
5151
mod context;
52+
mod deref_into_dyn_supertrait;
5253
mod early;
5354
mod enum_intrinsics_non_enums;
5455
mod errors;
@@ -87,6 +88,7 @@ use rustc_span::Span;
8788

8889
use array_into_iter::ArrayIntoIter;
8990
use builtin::*;
91+
use deref_into_dyn_supertrait::*;
9092
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
9193
use for_loops_over_fallibles::*;
9294
use hidden_unicode_codepoints::*;
@@ -192,6 +194,7 @@ macro_rules! late_lint_mod_passes {
192194
$args,
193195
[
194196
ForLoopsOverFallibles: ForLoopsOverFallibles,
197+
DerefIntoDynSupertrait: DerefIntoDynSupertrait,
195198
HardwiredLints: HardwiredLints,
196199
ImproperCTypesDeclarations: ImproperCTypesDeclarations,
197200
ImproperCTypesDefinitions: ImproperCTypesDefinitions,

compiler/rustc_lint_defs/src/builtin.rs

-46
Original file line numberDiff line numberDiff line change
@@ -3262,7 +3262,6 @@ declare_lint_pass! {
32623262
UNUSED_TUPLE_STRUCT_FIELDS,
32633263
NON_EXHAUSTIVE_OMITTED_PATTERNS,
32643264
TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
3265-
DEREF_INTO_DYN_SUPERTRAIT,
32663265
DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
32673266
DUPLICATE_MACRO_ATTRIBUTES,
32683267
SUSPICIOUS_AUTO_TRAIT_IMPLS,
@@ -3764,51 +3763,6 @@ declare_lint! {
37643763
"invisible directionality-changing codepoints in comment"
37653764
}
37663765

3767-
declare_lint! {
3768-
/// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the
3769-
/// `Deref` implementation with a `dyn SuperTrait` type as `Output`.
3770-
///
3771-
/// These implementations will become shadowed when the `trait_upcasting` feature is stabilized.
3772-
/// The `deref` functions will no longer be called implicitly, so there might be behavior change.
3773-
///
3774-
/// ### Example
3775-
///
3776-
/// ```rust,compile_fail
3777-
/// #![deny(deref_into_dyn_supertrait)]
3778-
/// #![allow(dead_code)]
3779-
///
3780-
/// use core::ops::Deref;
3781-
///
3782-
/// trait A {}
3783-
/// trait B: A {}
3784-
/// impl<'a> Deref for dyn 'a + B {
3785-
/// type Target = dyn A;
3786-
/// fn deref(&self) -> &Self::Target {
3787-
/// todo!()
3788-
/// }
3789-
/// }
3790-
///
3791-
/// fn take_a(_: &dyn A) { }
3792-
///
3793-
/// fn take_b(b: &dyn B) {
3794-
/// take_a(b);
3795-
/// }
3796-
/// ```
3797-
///
3798-
/// {{produces}}
3799-
///
3800-
/// ### Explanation
3801-
///
3802-
/// The dyn upcasting coercion feature adds new coercion rules, taking priority
3803-
/// over certain other coercion rules, which will cause some behavior change.
3804-
pub DEREF_INTO_DYN_SUPERTRAIT,
3805-
Warn,
3806-
"`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future",
3807-
@future_incompatible = FutureIncompatibleInfo {
3808-
reference: "issue #89460 <https://github.com/rust-lang/rust/issues/89460>",
3809-
};
3810-
}
3811-
38123766
declare_lint! {
38133767
/// The `duplicate_macro_attributes` lint detects when a `#[test]`-like built-in macro
38143768
/// attribute is duplicated on an item. This lint may trigger on `bench`, `cfg_eval`, `test`

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

-12
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@
66
//!
77
//! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
88
use hir::LangItem;
9-
use rustc_errors::DelayDm;
109
use rustc_hir as hir;
1110
use rustc_infer::traits::ObligationCause;
1211
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
13-
use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT;
1412
use rustc_middle::ty::print::with_no_trimmed_paths;
1513
use rustc_middle::ty::{self, Ty, TypeVisitable};
1614
use rustc_target::spec::abi::Abi;
@@ -811,16 +809,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
811809
&obligation.cause,
812810
) {
813811
if deref_trait_ref.def_id() == target_trait_did {
814-
self.tcx().struct_span_lint_hir(
815-
DEREF_INTO_DYN_SUPERTRAIT,
816-
obligation.cause.body_id,
817-
obligation.cause.span,
818-
DelayDm(|| format!(
819-
"`{}` implements `Deref` with supertrait `{}` as output",
820-
source, deref_trait_ref
821-
)),
822-
|lint| lint,
823-
);
824812
return;
825813
}
826814
}

src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ use core::ops::Deref;
77
// issue 89190
88
trait A {}
99
trait B: A {}
10+
1011
impl<'a> Deref for dyn 'a + B {
12+
//~^ ERROR `(dyn B + 'a)` implements `Deref` with supertrait `A` as output
13+
//~| WARN this was previously accepted by the compiler but is being phased out;
14+
1115
type Target = dyn A;
1216
fn deref(&self) -> &Self::Target {
1317
todo!()
@@ -18,8 +22,6 @@ fn take_a(_: &dyn A) {}
1822

1923
fn whoops(b: &dyn B) {
2024
take_a(b)
21-
//~^ ERROR `dyn B` implements `Deref` with supertrait `A` as output
22-
//~^^ WARN this was previously accepted by the compiler but is being phased out;
2325
}
2426

2527
fn main() {}

src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
error: `dyn B` implements `Deref` with supertrait `A` as output
2-
--> $DIR/migrate-lint-deny.rs:20:12
1+
error: `(dyn B + 'a)` implements `Deref` with supertrait `A` as output
2+
--> $DIR/migrate-lint-deny.rs:11:1
33
|
4-
LL | take_a(b)
5-
| ^
4+
LL | / impl<'a> Deref for dyn 'a + B {
5+
LL | |
6+
LL | |
7+
LL | |
8+
... |
9+
LL | | }
10+
LL | | }
11+
| |_^
612
|
713
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
814
= note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>

0 commit comments

Comments
 (0)