diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2022-11-24 08:42:34 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-11-24 08:42:34 +0100 |
| commit | c08c57e856e0536accad812d43f458004c439613 (patch) | |
| tree | f5e14b2990eec64f4f180f95e740421725fd963d /compiler | |
| parent | b43c2e7cd9ffd4f7249adfd09f6df841ed902924 (diff) | |
| parent | 20f3de5ab1151e68e727b5e1c22bcafca738bb7e (diff) | |
| download | rust-c08c57e856e0536accad812d43f458004c439613.tar.gz rust-c08c57e856e0536accad812d43f458004c439613.zip | |
Rollup merge of #104742 - WaffleLapkin:forbidden-SUPER-deref, r=compiler-errors
Make `deref_into_dyn_supertrait` lint the impl and not the usage Proposed by ``@compiler-errors`` in https://github.com/rust-lang/rust/issues/89460#issuecomment-1320806785 r? ``@crlf0710``
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_lint/src/context.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/deref_into_dyn_supertrait.rs | 92 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/lib.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_lint_defs/src/builtin.rs | 46 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs | 12 |
5 files changed, 112 insertions, 58 deletions
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 589b4d6a10f..67cf66f4708 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -1245,6 +1245,23 @@ impl<'tcx> LateContext<'tcx> { AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]).unwrap() } + + /// Returns the associated type `name` for `self_ty` as an implementation of `trait_id`. + /// Do not invoke without first verifying that the type implements the trait. + pub fn get_associated_type( + &self, + self_ty: Ty<'tcx>, + trait_id: DefId, + name: &str, + ) -> Option<Ty<'tcx>> { + let tcx = self.tcx; + tcx.associated_items(trait_id) + .find_by_name_and_kind(tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id) + .and_then(|assoc| { + let proj = tcx.mk_projection(assoc.def_id, tcx.mk_substs_trait(self_ty, [])); + tcx.try_normalize_erasing_regions(self.param_env, proj).ok() + }) + } } impl<'tcx> abi::HasDataLayout for LateContext<'tcx> { diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs new file mode 100644 index 00000000000..1d29a234a3c --- /dev/null +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -0,0 +1,92 @@ +use crate::{LateContext, LateLintPass, LintContext}; + +use rustc_errors::DelayDm; +use rustc_hir as hir; +use rustc_middle::{traits::util::supertraits, ty}; +use rustc_span::sym; + +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, + cx.tcx.def_span(item.owner_id.def_id), + DelayDm(|| { + format!( + "`{t}` implements `Deref` with supertrait `{target_principal}` as target" + ) + }), + |lint| { + if let Some(target_span) = impl_.items.iter().find_map(|i| (i.ident.name == sym::Target).then_some(i.span)) { + lint.span_label(target_span, "target type is set here"); + } + + lint + }, + ) + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index ebb7de70e05..b6027476adf 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -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, diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index b80facb1759..df0e17dea3c 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -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, @@ -3765,51 +3764,6 @@ declare_lint! { } 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` /// and `test_case`. diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 9d899da9bba..cd4a0447391 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -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; @@ -809,16 +807,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; } } |
