rustc_lint/
multiple_supertrait_upcastable.rs

1use rustc_hir as hir;
2use rustc_session::{declare_lint, declare_lint_pass};
3
4use crate::{LateContext, LateLintPass, LintContext};
5
6declare_lint! {
7    /// The `multiple_supertrait_upcastable` lint detects when a dyn-compatible trait has multiple
8    /// supertraits.
9    ///
10    /// ### Example
11    ///
12    /// ```rust
13    /// #![feature(multiple_supertrait_upcastable)]
14    /// trait A {}
15    /// trait B {}
16    ///
17    /// #[warn(multiple_supertrait_upcastable)]
18    /// trait C: A + B {}
19    /// ```
20    ///
21    /// {{produces}}
22    ///
23    /// ### Explanation
24    ///
25    /// To support upcasting with multiple supertraits, we need to store multiple vtables and this
26    /// can result in extra space overhead, even if no code actually uses upcasting.
27    /// This lint allows users to identify when such scenarios occur and to decide whether the
28    /// additional overhead is justified.
29    pub MULTIPLE_SUPERTRAIT_UPCASTABLE,
30    Allow,
31    "detect when a dyn-compatible trait has multiple supertraits",
32    @feature_gate = multiple_supertrait_upcastable;
33}
34
35declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTABLE]);
36
37impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
38    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
39        let def_id = item.owner_id.to_def_id();
40        // NOTE(nbdd0121): use `dyn_compatibility_violations` instead of `is_dyn_compatible` because
41        // the latter will report `where_clause_object_safety` lint.
42        if let hir::ItemKind::Trait(_, _, ident, ..) = item.kind
43            && cx.tcx.is_dyn_compatible(def_id)
44        {
45            let direct_super_traits_iter = cx
46                .tcx
47                .explicit_super_predicates_of(def_id)
48                .iter_identity_copied()
49                .filter_map(|(pred, _)| pred.as_trait_clause());
50            if direct_super_traits_iter.count() > 1 {
51                cx.emit_span_lint(
52                    MULTIPLE_SUPERTRAIT_UPCASTABLE,
53                    cx.tcx.def_span(def_id),
54                    crate::lints::MultipleSupertraitUpcastable { ident },
55                );
56            }
57        }
58    }
59}