///
/// ### 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.
+ /// A generic trait bound of the form `T: Drop` is most likely misleading
+ /// and not what the programmer intended (they probably should have used
+ /// `std::mem::needs_drop` instead).
///
- /// 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.
+ /// `Drop` bounds do not actually indicate whether a type can be trivially
+ /// dropped or not, because a composite type containing `Drop` types does
+ /// not necessarily implement `Drop` itself. Naïvely, one might be tempted
+ /// to write an implementation that assumes that a type can be trivially
+ /// dropped while also supplying a specialization for `T: Drop` that
+ /// actually calls the destructor. However, this breaks down e.g. when `T`
+ /// is `String`, which does not implement `Drop` itself but contains a
+ /// `Vec`, which does implement `Drop`, so assuming `T` can be trivially
+ /// dropped would lead to a memory leak here.
+ ///
+ /// Furthermore, the `Drop` trait only contains one method, `Drop::drop`,
+ /// which may not be called explicitly in user code (`E0040`), so there is
+ /// really no use case for using `Drop` in trait bounds, save perhaps for
+ /// some obscure corner cases, which can use `#[allow(drop_bounds)]`.
pub DROP_BOUNDS,
Warn,
- "bounds of the form `T: Drop` are useless"
+ "bounds of the form `T: Drop` are most likely incorrect"
}
declare_lint! {
let predicates = cx.tcx.explicit_predicates_of(item.def_id);
for &(predicate, span) in predicates.predicates {
let trait_predicate = match predicate.kind().skip_binder() {
- Trait(trait_predicate, _constness) => trait_predicate,
+ Trait(trait_predicate) => trait_predicate,
_ => continue,
};
let def_id = trait_predicate.trait_ref.def_id;
None => return,
};
let msg = format!(
- "bounds on `{}` are useless, consider instead \
- using `{}` to detect if a type has a destructor",
+ "bounds on `{}` are most likely incorrect, consider instead \
+ using `{}` to detect whether a type can be trivially dropped",
predicate,
cx.tcx.def_path_str(needs_drop)
);