diff options
Diffstat (limited to 'compiler/rustc_lint/src/multiple_supertrait_upcastable.rs')
-rw-r--r-- | compiler/rustc_lint/src/multiple_supertrait_upcastable.rs | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs new file mode 100644 index 000000000..c2ed0e19f --- /dev/null +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -0,0 +1,60 @@ +use crate::{LateContext, LateLintPass, LintContext}; + +use rustc_hir as hir; +use rustc_span::sym; + +declare_lint! { + /// The `multiple_supertrait_upcastable` lint detects when an object-safe trait has multiple + /// supertraits. + /// + /// ### Example + /// + /// ```rust + /// trait A {} + /// trait B {} + /// + /// #[warn(multiple_supertrait_upcastable)] + /// trait C: A + B {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// To support upcasting with multiple supertraits, we need to store multiple vtables and this + /// can result in extra space overhead, even if no code actually uses upcasting. + /// This lint allows users to identify when such scenarios occur and to decide whether the + /// additional overhead is justified. + pub MULTIPLE_SUPERTRAIT_UPCASTABLE, + Allow, + "detect when an object-safe trait has multiple supertraits", + @feature_gate = sym::multiple_supertrait_upcastable; +} + +declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTABLE]); + +impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { + let def_id = item.owner_id.to_def_id(); + // NOTE(nbdd0121): use `object_safety_violations` instead of `check_is_object_safe` because + // the latter will report `where_clause_object_safety` lint. + if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind + && cx.tcx.object_safety_violations(def_id).is_empty() + { + let direct_super_traits_iter = cx.tcx + .super_predicates_of(def_id) + .predicates + .into_iter() + .filter_map(|(pred, _)| pred.to_opt_poly_trait_pred()); + if direct_super_traits_iter.count() > 1 { + cx.emit_spanned_lint( + MULTIPLE_SUPERTRAIT_UPCASTABLE, + cx.tcx.def_span(def_id), + crate::lints::MultipleSupertraitUpcastable { + ident: item.ident + }, + ); + } + } + } +} |