1 use crate::utils::{match_def_path, paths, span_lint};
2 use if_chain::if_chain;
3 use rustc_hir::{GenericBound, GenericParam, WhereBoundPredicate, WherePredicate};
4 use rustc_lint::LateLintPass;
5 use rustc_session::{declare_lint_pass, declare_tool_lint};
8 /// **What it does:** Checks for generics with `std::ops::Drop` as bounds.
10 /// **Why is this bad?** `Drop` bounds do not really accomplish anything.
11 /// A type may have compiler-generated drop glue without implementing the
12 /// `Drop` trait itself. The `Drop` trait also only has one method,
13 /// `Drop::drop`, and that function is by fiat not callable in user code.
14 /// So there is really no use case for using `Drop` in trait bounds.
16 /// The most likely use case of a drop bound is to distinguish between types
17 /// that have destructors and types that don't. Combined with specialization,
18 /// a naive coder would write an implementation that assumed a type could be
19 /// trivially dropped, then write a specialization for `T: Drop` that actually
20 /// calls the destructor. Except that doing so is not correct; String, for
21 /// example, doesn't actually implement Drop, but because String contains a
22 /// Vec, assuming it can be trivially dropped will leak memory.
24 /// **Known problems:** None.
28 /// fn foo<T: Drop>() {}
32 "Bounds of the form `T: Drop` are useless"
35 const DROP_BOUNDS_SUMMARY: &str = "Bounds of the form `T: Drop` are useless. \
36 Use `std::mem::needs_drop` to detect if a type has drop glue.";
38 declare_lint_pass!(DropBounds => [DROP_BOUNDS]);
40 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DropBounds {
41 fn check_generic_param(&mut self, cx: &rustc_lint::LateContext<'a, 'tcx>, p: &'tcx GenericParam<'_>) {
42 for bound in p.bounds.iter() {
43 lint_bound(cx, bound);
46 fn check_where_predicate(&mut self, cx: &rustc_lint::LateContext<'a, 'tcx>, p: &'tcx WherePredicate<'_>) {
47 if let WherePredicate::BoundPredicate(WhereBoundPredicate { bounds, .. }) = p {
48 for bound in *bounds {
49 lint_bound(cx, bound);
55 fn lint_bound<'a, 'tcx>(cx: &rustc_lint::LateContext<'a, 'tcx>, bound: &'tcx GenericBound<'_>) {
57 if let GenericBound::Trait(t, _) = bound;
58 if let Some(def_id) = t.trait_ref.path.res.opt_def_id();
59 if match_def_path(cx, def_id, &paths::DROP_TRAIT);