Skip to content

Commit 2627db6

Browse files
Rollup merge of #86747 - FabianWolff:issue-86653, r=GuillaumeGomez
Improve wording of the `drop_bounds` lint This PR addresses #86653. The issue is sort of a false positive of the `drop_bounds` lint, but I would argue that the best solution for #86653 is simply a rewording of the warning message and lint description, because even if the lint is _technically_ wrong, it still forces the programmer to think about what they are doing, and they can always use `#[allow(drop_bounds)]` if they think that they really need the `Drop` bound. There are two issues with the current warning message and lint description: - First, it says that `Drop` bounds are "useless", which is technically incorrect because they actually do have the effect of allowing you e.g. to call methods that also have a `Drop` bound on their generic arguments for some reason. I have changed the wording to emphasize not that the bound is "useless", but that it is most likely not what was intended. - Second, it claims that `std::mem::needs_drop` detects whether a type has a destructor. But I think this is also technically wrong: The `Drop` bound says whether the type has a destructor or not, whereas `std::mem::needs_drop` also takes nested types with destructors into account, even if the top-level type does not itself have one (although I'm not 100% sure about the exact terminology here, i.e. whether the "drop glue" of the top-level type counts as a destructor or not). cc `@jonhoo,` does this solve the issue for you? r? `@GuillaumeGomez`
2 parents 7481e6d + 644529b commit 2627db6

File tree

2 files changed

+27
-23
lines changed

2 files changed

+27
-23
lines changed

compiler/rustc_lint/src/traits.rs

+20-16
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,27 @@ declare_lint! {
1818
///
1919
/// ### Explanation
2020
///
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.
21+
/// A generic trait bound of the form `T: Drop` is most likely misleading
22+
/// and not what the programmer intended (they probably should have used
23+
/// `std::mem::needs_drop` instead).
2624
///
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
34-
/// will leak memory.
25+
/// `Drop` bounds do not actually indicate whether a type can be trivially
26+
/// dropped or not, because a composite type containing `Drop` types does
27+
/// not necessarily implement `Drop` itself. Naïvely, one might be tempted
28+
/// to write an implementation that assumes that a type can be trivially
29+
/// dropped while also supplying a specialization for `T: Drop` that
30+
/// actually calls the destructor. However, this breaks down e.g. when `T`
31+
/// is `String`, which does not implement `Drop` itself but contains a
32+
/// `Vec`, which does implement `Drop`, so assuming `T` can be trivially
33+
/// dropped would lead to a memory leak here.
34+
///
35+
/// Furthermore, the `Drop` trait only contains one method, `Drop::drop`,
36+
/// which may not be called explicitly in user code (`E0040`), so there is
37+
/// really no use case for using `Drop` in trait bounds, save perhaps for
38+
/// some obscure corner cases, which can use `#[allow(drop_bounds)]`.
3539
pub DROP_BOUNDS,
3640
Warn,
37-
"bounds of the form `T: Drop` are useless"
41+
"bounds of the form `T: Drop` are most likely incorrect"
3842
}
3943

4044
declare_lint! {
@@ -102,8 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
102106
None => return,
103107
};
104108
let msg = format!(
105-
"bounds on `{}` are useless, consider instead \
106-
using `{}` to detect if a type has a destructor",
109+
"bounds on `{}` are most likely incorrect, consider instead \
110+
using `{}` to detect whether a type can be trivially dropped",
107111
predicate,
108112
cx.tcx.def_path_str(needs_drop)
109113
);

src/test/ui/drop-bounds/drop-bounds.stderr

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
1+
error: bounds on `T: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
22
--> $DIR/drop-bounds.rs:2:11
33
|
44
LL | fn foo<T: Drop>() {}
@@ -10,37 +10,37 @@ note: the lint level is defined here
1010
LL | #![deny(drop_bounds)]
1111
| ^^^^^^^^^^^
1212

13-
error: bounds on `U: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
13+
error: bounds on `U: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
1414
--> $DIR/drop-bounds.rs:5:8
1515
|
1616
LL | U: Drop,
1717
| ^^^^
1818

19-
error: bounds on `impl Drop: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
19+
error: bounds on `impl Drop: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
2020
--> $DIR/drop-bounds.rs:8:17
2121
|
2222
LL | fn baz(_x: impl Drop) {}
2323
| ^^^^
2424

25-
error: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
25+
error: bounds on `T: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
2626
--> $DIR/drop-bounds.rs:9:15
2727
|
2828
LL | struct Foo<T: Drop> {
2929
| ^^^^
3030

31-
error: bounds on `U: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
31+
error: bounds on `U: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
3232
--> $DIR/drop-bounds.rs:12:24
3333
|
3434
LL | struct Bar<U> where U: Drop {
3535
| ^^^^
3636

37-
error: bounds on `Self: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
37+
error: bounds on `Self: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
3838
--> $DIR/drop-bounds.rs:15:12
3939
|
4040
LL | trait Baz: Drop {
4141
| ^^^^
4242

43-
error: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
43+
error: bounds on `T: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
4444
--> $DIR/drop-bounds.rs:17:9
4545
|
4646
LL | impl<T: Drop> Baz for T {

0 commit comments

Comments
 (0)