mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +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;
|
||||
pub mod builtin;
|
||||
mod context;
|
||||
mod deref_into_dyn_supertrait;
|
||||
mod early;
|
||||
mod enum_intrinsics_non_enums;
|
||||
mod errors;
|
||||
@ -87,6 +88,7 @@ use rustc_span::Span;
|
||||
|
||||
use array_into_iter::ArrayIntoIter;
|
||||
use builtin::*;
|
||||
use deref_into_dyn_supertrait::*;
|
||||
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
|
||||
use for_loops_over_fallibles::*;
|
||||
use hidden_unicode_codepoints::*;
|
||||
@ -192,6 +194,7 @@ macro_rules! late_lint_mod_passes {
|
||||
$args,
|
||||
[
|
||||
ForLoopsOverFallibles: ForLoopsOverFallibles,
|
||||
DerefIntoDynSupertrait: DerefIntoDynSupertrait,
|
||||
HardwiredLints: HardwiredLints,
|
||||
ImproperCTypesDeclarations: ImproperCTypesDeclarations,
|
||||
ImproperCTypesDefinitions: ImproperCTypesDefinitions,
|
||||
|
@ -3262,7 +3262,6 @@ declare_lint_pass! {
|
||||
UNUSED_TUPLE_STRUCT_FIELDS,
|
||||
NON_EXHAUSTIVE_OMITTED_PATTERNS,
|
||||
TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
|
||||
DEREF_INTO_DYN_SUPERTRAIT,
|
||||
DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
|
||||
DUPLICATE_MACRO_ATTRIBUTES,
|
||||
SUSPICIOUS_AUTO_TRAIT_IMPLS,
|
||||
@ -3764,51 +3763,6 @@ declare_lint! {
|
||||
"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! {
|
||||
/// 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`
|
||||
|
@ -6,11 +6,9 @@
|
||||
//!
|
||||
//! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
|
||||
use hir::LangItem;
|
||||
use rustc_errors::DelayDm;
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
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::{self, Ty, TypeVisitable};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
@ -811,16 +809,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
&obligation.cause,
|
||||
) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,11 @@ use core::ops::Deref;
|
||||
// issue 89190
|
||||
trait A {}
|
||||
trait B: A {}
|
||||
|
||||
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;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
todo!()
|
||||
@ -18,8 +22,6 @@ fn take_a(_: &dyn A) {}
|
||||
|
||||
fn whoops(b: &dyn 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() {}
|
||||
|
@ -1,8 +1,14 @@
|
||||
error: `dyn B` implements `Deref` with supertrait `A` as output
|
||||
--> $DIR/migrate-lint-deny.rs:20:12
|
||||
error: `(dyn B + 'a)` implements `Deref` with supertrait `A` as output
|
||||
--> $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!
|
||||
= note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
|
||||
|
Loading…
Reference in New Issue
Block a user