mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Make deref_into_dyn_supertrait
lint the impl and not the usage
This commit is contained in:
parent
11a5386256
commit
0d4a5c725a
85
compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
Normal file
85
compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
use crate::{LateContext, LateLintPass, LintContext};
|
||||||
|
|
||||||
|
use rustc_errors::DelayDm;
|
||||||
|
use rustc_hir as hir;
|
||||||
|
use rustc_middle::{traits::util::supertraits, ty};
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the
|
||||||
|
/// `Deref` implementation with a `dyn SuperTrait` type as `Output`.
|
||||||
|
///
|
||||||
|
/// These implementations will become shadowed when the `trait_upcasting` feature is stabilized.
|
||||||
|
/// The `deref` functions will no longer be called implicitly, so there might be behavior change.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust,compile_fail
|
||||||
|
/// #![deny(deref_into_dyn_supertrait)]
|
||||||
|
/// #![allow(dead_code)]
|
||||||
|
///
|
||||||
|
/// use core::ops::Deref;
|
||||||
|
///
|
||||||
|
/// trait A {}
|
||||||
|
/// trait B: A {}
|
||||||
|
/// impl<'a> Deref for dyn 'a + B {
|
||||||
|
/// type Target = dyn A;
|
||||||
|
/// fn deref(&self) -> &Self::Target {
|
||||||
|
/// todo!()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn take_a(_: &dyn A) { }
|
||||||
|
///
|
||||||
|
/// fn take_b(b: &dyn B) {
|
||||||
|
/// take_a(b);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// {{produces}}
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// The dyn upcasting coercion feature adds new coercion rules, taking priority
|
||||||
|
/// over certain other coercion rules, which will cause some behavior change.
|
||||||
|
pub DEREF_INTO_DYN_SUPERTRAIT,
|
||||||
|
Warn,
|
||||||
|
"`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future",
|
||||||
|
@future_incompatible = FutureIncompatibleInfo {
|
||||||
|
reference: "issue #89460 <https://github.com/rust-lang/rust/issues/89460>",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(DerefIntoDynSupertrait => [DEREF_INTO_DYN_SUPERTRAIT]);
|
||||||
|
|
||||||
|
impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
|
||||||
|
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||||
|
// `Deref` is being implemented for `t`
|
||||||
|
if let hir::ItemKind::Impl(impl_) = item.kind
|
||||||
|
&& let Some(trait_) = &impl_.of_trait
|
||||||
|
&& let t = cx.tcx.type_of(item.owner_id)
|
||||||
|
&& let opt_did @ Some(did) = trait_.trait_def_id()
|
||||||
|
&& opt_did == cx.tcx.lang_items().deref_trait()
|
||||||
|
// `t` is `dyn t_principal`
|
||||||
|
&& let ty::Dynamic(data, _, ty::Dyn) = t.kind()
|
||||||
|
&& let Some(t_principal) = data.principal()
|
||||||
|
// `<T as Deref>::Target` is `dyn target_principal`
|
||||||
|
&& let Some(target) = cx.get_associated_type(t, did, "Target")
|
||||||
|
&& let ty::Dynamic(data, _, ty::Dyn) = target.kind()
|
||||||
|
&& let Some(target_principal) = data.principal()
|
||||||
|
// `target_principal` is a supertrait of `t_principal`
|
||||||
|
&& supertraits(cx.tcx, t_principal.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self))
|
||||||
|
.any(|sup| sup.map_bound(|x| ty::ExistentialTraitRef::erase_self_ty(cx.tcx, x)) == target_principal)
|
||||||
|
{
|
||||||
|
cx.struct_span_lint(
|
||||||
|
DEREF_INTO_DYN_SUPERTRAIT,
|
||||||
|
item.span,
|
||||||
|
DelayDm(|| {
|
||||||
|
format!(
|
||||||
|
"`{t}` implements `Deref` with supertrait `{target_principal}` as output"
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
|lint| lint,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -49,6 +49,7 @@ extern crate tracing;
|
|||||||
mod array_into_iter;
|
mod array_into_iter;
|
||||||
pub mod builtin;
|
pub mod builtin;
|
||||||
mod context;
|
mod context;
|
||||||
|
mod deref_into_dyn_supertrait;
|
||||||
mod early;
|
mod early;
|
||||||
mod enum_intrinsics_non_enums;
|
mod enum_intrinsics_non_enums;
|
||||||
mod errors;
|
mod errors;
|
||||||
@ -87,6 +88,7 @@ use rustc_span::Span;
|
|||||||
|
|
||||||
use array_into_iter::ArrayIntoIter;
|
use array_into_iter::ArrayIntoIter;
|
||||||
use builtin::*;
|
use builtin::*;
|
||||||
|
use deref_into_dyn_supertrait::*;
|
||||||
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
|
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
|
||||||
use for_loops_over_fallibles::*;
|
use for_loops_over_fallibles::*;
|
||||||
use hidden_unicode_codepoints::*;
|
use hidden_unicode_codepoints::*;
|
||||||
@ -192,6 +194,7 @@ macro_rules! late_lint_mod_passes {
|
|||||||
$args,
|
$args,
|
||||||
[
|
[
|
||||||
ForLoopsOverFallibles: ForLoopsOverFallibles,
|
ForLoopsOverFallibles: ForLoopsOverFallibles,
|
||||||
|
DerefIntoDynSupertrait: DerefIntoDynSupertrait,
|
||||||
HardwiredLints: HardwiredLints,
|
HardwiredLints: HardwiredLints,
|
||||||
ImproperCTypesDeclarations: ImproperCTypesDeclarations,
|
ImproperCTypesDeclarations: ImproperCTypesDeclarations,
|
||||||
ImproperCTypesDefinitions: ImproperCTypesDefinitions,
|
ImproperCTypesDefinitions: ImproperCTypesDefinitions,
|
||||||
|
@ -3262,7 +3262,6 @@ declare_lint_pass! {
|
|||||||
UNUSED_TUPLE_STRUCT_FIELDS,
|
UNUSED_TUPLE_STRUCT_FIELDS,
|
||||||
NON_EXHAUSTIVE_OMITTED_PATTERNS,
|
NON_EXHAUSTIVE_OMITTED_PATTERNS,
|
||||||
TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
|
TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
|
||||||
DEREF_INTO_DYN_SUPERTRAIT,
|
|
||||||
DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
|
DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
|
||||||
DUPLICATE_MACRO_ATTRIBUTES,
|
DUPLICATE_MACRO_ATTRIBUTES,
|
||||||
SUSPICIOUS_AUTO_TRAIT_IMPLS,
|
SUSPICIOUS_AUTO_TRAIT_IMPLS,
|
||||||
@ -3764,51 +3763,6 @@ declare_lint! {
|
|||||||
"invisible directionality-changing codepoints in comment"
|
"invisible directionality-changing codepoints in comment"
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint! {
|
|
||||||
/// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the
|
|
||||||
/// `Deref` implementation with a `dyn SuperTrait` type as `Output`.
|
|
||||||
///
|
|
||||||
/// These implementations will become shadowed when the `trait_upcasting` feature is stabilized.
|
|
||||||
/// The `deref` functions will no longer be called implicitly, so there might be behavior change.
|
|
||||||
///
|
|
||||||
/// ### Example
|
|
||||||
///
|
|
||||||
/// ```rust,compile_fail
|
|
||||||
/// #![deny(deref_into_dyn_supertrait)]
|
|
||||||
/// #![allow(dead_code)]
|
|
||||||
///
|
|
||||||
/// use core::ops::Deref;
|
|
||||||
///
|
|
||||||
/// trait A {}
|
|
||||||
/// trait B: A {}
|
|
||||||
/// impl<'a> Deref for dyn 'a + B {
|
|
||||||
/// type Target = dyn A;
|
|
||||||
/// fn deref(&self) -> &Self::Target {
|
|
||||||
/// todo!()
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn take_a(_: &dyn A) { }
|
|
||||||
///
|
|
||||||
/// fn take_b(b: &dyn B) {
|
|
||||||
/// take_a(b);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// {{produces}}
|
|
||||||
///
|
|
||||||
/// ### Explanation
|
|
||||||
///
|
|
||||||
/// The dyn upcasting coercion feature adds new coercion rules, taking priority
|
|
||||||
/// over certain other coercion rules, which will cause some behavior change.
|
|
||||||
pub DEREF_INTO_DYN_SUPERTRAIT,
|
|
||||||
Warn,
|
|
||||||
"`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future",
|
|
||||||
@future_incompatible = FutureIncompatibleInfo {
|
|
||||||
reference: "issue #89460 <https://github.com/rust-lang/rust/issues/89460>",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `duplicate_macro_attributes` lint detects when a `#[test]`-like built-in macro
|
/// The `duplicate_macro_attributes` lint detects when a `#[test]`-like built-in macro
|
||||||
/// attribute is duplicated on an item. This lint may trigger on `bench`, `cfg_eval`, `test`
|
/// attribute is duplicated on an item. This lint may trigger on `bench`, `cfg_eval`, `test`
|
||||||
|
@ -6,11 +6,9 @@
|
|||||||
//!
|
//!
|
||||||
//! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
|
//! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
|
||||||
use hir::LangItem;
|
use hir::LangItem;
|
||||||
use rustc_errors::DelayDm;
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_infer::traits::ObligationCause;
|
use rustc_infer::traits::ObligationCause;
|
||||||
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
|
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
|
||||||
use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT;
|
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_middle::ty::{self, Ty, TypeVisitable};
|
use rustc_middle::ty::{self, Ty, TypeVisitable};
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
@ -811,16 +809,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
&obligation.cause,
|
&obligation.cause,
|
||||||
) {
|
) {
|
||||||
if deref_trait_ref.def_id() == target_trait_did {
|
if deref_trait_ref.def_id() == target_trait_did {
|
||||||
self.tcx().struct_span_lint_hir(
|
|
||||||
DEREF_INTO_DYN_SUPERTRAIT,
|
|
||||||
obligation.cause.body_id,
|
|
||||||
obligation.cause.span,
|
|
||||||
DelayDm(|| format!(
|
|
||||||
"`{}` implements `Deref` with supertrait `{}` as output",
|
|
||||||
source, deref_trait_ref
|
|
||||||
)),
|
|
||||||
|lint| lint,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,11 @@ use core::ops::Deref;
|
|||||||
// issue 89190
|
// issue 89190
|
||||||
trait A {}
|
trait A {}
|
||||||
trait B: A {}
|
trait B: A {}
|
||||||
|
|
||||||
impl<'a> Deref for dyn 'a + B {
|
impl<'a> Deref for dyn 'a + B {
|
||||||
|
//~^ ERROR `(dyn B + 'a)` implements `Deref` with supertrait `A` as output
|
||||||
|
//~| WARN this was previously accepted by the compiler but is being phased out;
|
||||||
|
|
||||||
type Target = dyn A;
|
type Target = dyn A;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
todo!()
|
todo!()
|
||||||
@ -18,8 +22,6 @@ fn take_a(_: &dyn A) {}
|
|||||||
|
|
||||||
fn whoops(b: &dyn B) {
|
fn whoops(b: &dyn B) {
|
||||||
take_a(b)
|
take_a(b)
|
||||||
//~^ ERROR `dyn B` implements `Deref` with supertrait `A` as output
|
|
||||||
//~^^ WARN this was previously accepted by the compiler but is being phased out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
error: `dyn B` implements `Deref` with supertrait `A` as output
|
error: `(dyn B + 'a)` implements `Deref` with supertrait `A` as output
|
||||||
--> $DIR/migrate-lint-deny.rs:20:12
|
--> $DIR/migrate-lint-deny.rs:11:1
|
||||||
|
|
|
|
||||||
LL | take_a(b)
|
LL | / impl<'a> Deref for dyn 'a + B {
|
||||||
| ^
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
... |
|
||||||
|
LL | | }
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
|
|
||||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
= note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
|
= note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
|
||||||
|
Loading…
Reference in New Issue
Block a user