rustc_lint/
multiple_supertrait_upcastable.rs1use rustc_hir as hir;
2use rustc_hir::attrs::lang_items::LangItem;
3use rustc_middle::ty::Unnormalized;
4use rustc_session::{declare_lint, declare_lint_pass};
5
6use crate::{LateContext, LateLintPass, LintContext};
7
8#[doc =
r" The `multiple_supertrait_upcastable` lint detects when a dyn-compatible trait has multiple"]
#[doc = r" supertraits."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r" #![feature(multiple_supertrait_upcastable)]"]
#[doc = r" trait A {}"]
#[doc = r" trait B {}"]
#[doc = r""]
#[doc = r" #[warn(multiple_supertrait_upcastable)]"]
#[doc = r" trait C: A + B {}"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc =
r" To support upcasting with multiple supertraits, we need to store multiple vtables and this"]
#[doc =
r" can result in extra space overhead, even if no code actually uses upcasting."]
#[doc =
r" This lint allows users to identify when such scenarios occur and to decide whether the"]
#[doc = r" additional overhead is justified."]
pub static MULTIPLE_SUPERTRAIT_UPCASTABLE: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: "MULTIPLE_SUPERTRAIT_UPCASTABLE",
default_level: ::rustc_lint_defs::Allow,
desc: "detect when a dyn-compatible trait has multiple supertraits",
is_externally_loaded: false,
feature_gate: Some(rustc_span::sym::multiple_supertrait_upcastable),
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_lint! {
9 pub MULTIPLE_SUPERTRAIT_UPCASTABLE,
32 Allow,
33 "detect when a dyn-compatible trait has multiple supertraits",
34 @feature_gate = multiple_supertrait_upcastable;
35}
36
37pub struct MultipleSupertraitUpcastable;
#[automatically_derived]
impl ::core::marker::Copy for MultipleSupertraitUpcastable { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for MultipleSupertraitUpcastable { }
#[automatically_derived]
impl ::core::clone::Clone for MultipleSupertraitUpcastable {
#[inline]
fn clone(&self) -> MultipleSupertraitUpcastable { *self }
}
impl ::rustc_lint_defs::LintPass for MultipleSupertraitUpcastable {
fn name(&self) -> &'static str { "MultipleSupertraitUpcastable" }
fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[MULTIPLE_SUPERTRAIT_UPCASTABLE]))
}
}
impl MultipleSupertraitUpcastable {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[MULTIPLE_SUPERTRAIT_UPCASTABLE]))
}
}declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTABLE]);
38
39impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
40 fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
41 let def_id = item.owner_id.to_def_id();
42 if let hir::ItemKind::Trait { ident, .. } = item.kind
45 && cx.tcx.is_dyn_compatible(def_id)
46 {
47 let direct_super_traits_iter = cx
48 .tcx
49 .explicit_super_clauses_of(def_id)
50 .iter_identity_copied()
51 .map(Unnormalized::skip_norm_wip)
52 .filter_map(|(clause, _)| clause.as_trait_clause())
53 .filter(|pred| !cx.tcx.is_lang_item(pred.def_id(), LangItem::MetaSized))
54 .filter(|pred| !cx.tcx.is_default_trait(pred.def_id()));
55 if direct_super_traits_iter.count() > 1 {
56 cx.emit_span_lint(
57 MULTIPLE_SUPERTRAIT_UPCASTABLE,
58 cx.tcx.def_span(def_id),
59 crate::diagnostics::MultipleSupertraitUpcastable { ident },
60 );
61 }
62 }
63 }
64}