1 use crate::LateContext;
2 use crate::LateLintPass;
3 use crate::LintContext;
5 use rustc_span::symbol::sym;
8 /// The `drop_bounds` lint checks for generics with `std::ops::Drop` as
14 /// fn foo<T: Drop>() {}
21 /// `Drop` bounds do not really accomplish anything. A type may have
22 /// compiler-generated drop glue without implementing the `Drop` trait
23 /// itself. The `Drop` trait also only has one method, `Drop::drop`, and
24 /// that function is by fiat not callable in user code. So there is really
25 /// no use case for using `Drop` in trait bounds.
27 /// The most likely use case of a drop bound is to distinguish between
28 /// types that have destructors and types that don't. Combined with
29 /// specialization, a naive coder would write an implementation that
30 /// assumed a type could be trivially dropped, then write a specialization
31 /// for `T: Drop` that actually calls the destructor. Except that doing so
32 /// is not correct; String, for example, doesn't actually implement Drop,
33 /// but because String contains a Vec, assuming it can be trivially dropped
37 "bounds of the form `T: Drop` are useless"
41 /// Lint for bounds of the form `T: Drop`, which usually
42 /// indicate an attempt to emulate `std::mem::needs_drop`.
43 DropTraitConstraints => [DROP_BOUNDS]
46 impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
47 fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
48 use rustc_middle::ty::PredicateKind::*;
50 let def_id = cx.tcx.hir().local_def_id(item.hir_id);
51 let predicates = cx.tcx.explicit_predicates_of(def_id);
52 for &(predicate, span) in predicates.predicates {
53 let trait_predicate = match predicate.kind().skip_binder() {
54 Trait(trait_predicate, _constness) => trait_predicate,
57 let def_id = trait_predicate.trait_ref.def_id;
58 if cx.tcx.lang_items().drop_trait() == Some(def_id) {
59 // Explicitly allow `impl Drop`, a drop-guards-as-Voldemort-type pattern.
60 if trait_predicate.trait_ref.self_ty().is_impl_trait() {
63 cx.struct_span_lint(DROP_BOUNDS, span, |lint| {
64 let needs_drop = match cx.tcx.get_diagnostic_item(sym::needs_drop) {
65 Some(needs_drop) => needs_drop,
69 "bounds on `{}` are useless, consider instead \
70 using `{}` to detect if a type has a destructor",
72 cx.tcx.def_path_str(needs_drop)
74 lint.build(&msg).emit()