use crate::LateContext; use crate::LateLintPass; use crate::LintContext; use rustc_hir as hir; use rustc_span::symbol::sym; declare_lint! { /// The `drop_bounds` lint checks for generics with `std::ops::Drop` as /// bounds. /// /// ### Example /// /// ```rust /// fn foo() {} /// ``` /// /// {{produces}} /// /// ### Explanation /// /// `Drop` bounds do not really accomplish anything. A type may have /// compiler-generated drop glue without implementing the `Drop` trait /// itself. The `Drop` trait also only has one method, `Drop::drop`, and /// that function is by fiat not callable in user code. So there is really /// no use case for using `Drop` in trait bounds. /// /// The most likely use case of a drop bound is to distinguish between /// types that have destructors and types that don't. Combined with /// specialization, a naive coder would write an implementation that /// assumed a type could be trivially dropped, then write a specialization /// for `T: Drop` that actually calls the destructor. Except that doing so /// is not correct; String, for example, doesn't actually implement Drop, /// but because String contains a Vec, assuming it can be trivially dropped /// will leak memory. pub DROP_BOUNDS, Warn, "bounds of the form `T: Drop` are useless" } declare_lint_pass!( /// Lint for bounds of the form `T: Drop`, which usually /// indicate an attempt to emulate `std::mem::needs_drop`. DropTraitConstraints => [DROP_BOUNDS] ); impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { use rustc_middle::ty::PredicateAtom::*; let def_id = cx.tcx.hir().local_def_id(item.hir_id); let predicates = cx.tcx.explicit_predicates_of(def_id); for &(predicate, span) in predicates.predicates { let trait_predicate = match predicate.skip_binders() { Trait(trait_predicate, _constness) => trait_predicate, _ => continue, }; let def_id = trait_predicate.trait_ref.def_id; if cx.tcx.lang_items().drop_trait() == Some(def_id) { // Explicitly allow `impl Drop`, a drop-guards-as-Voldemort-type pattern. if trait_predicate.trait_ref.self_ty().is_impl_trait() { continue; } cx.struct_span_lint(DROP_BOUNDS, span, |lint| { let needs_drop = match cx.tcx.get_diagnostic_item(sym::needs_drop) { Some(needs_drop) => needs_drop, None => return, }; let msg = format!( "bounds on `{}` are useless, consider instead \ using `{}` to detect if a type has a destructor", predicate, cx.tcx.def_path_str(needs_drop) ); lint.build(&msg).emit() }); } } } }