Skip to content

Commit 6be0f74

Browse files
committed
Auto merge of #11780 - Jacherr:vec-allocator-nolint, r=xFrednet
Disable `vec_box` when using different allocators Fixes #7114 This PR disables the `vec_box` lint when the `Box` and `Vec` use different allocators (but not when they use the same - custom - allocator). For example - `Vec<Box<i32, DummyAllocator>>` will disable the lint, and `Vec<Box<i32, DummyAllocator>, DummyAllocator>` will not disable the lint. In addition, the applicability of this lint has been changed to `Unspecified` due to the automatic fixes potentially breaking code such as the following: ```rs fn foo() -> Vec<Box<i32>> { // -> Vec<i32> vec![Box::new(1)] } ``` It should be noted that the `if_chain->let-chains` fix has also been applied to this lint, so the diff does contain many changes. changelog: disable `vec_box` lint when using nonstandard allocators
2 parents 34b7d15 + eabc64f commit 6be0f74

File tree

5 files changed

+110
-101
lines changed

5 files changed

+110
-101
lines changed

Diff for: clippy_lints/src/types/vec_box.rs

+49-35
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::last_path_segment;
2+
use clippy_utils::paths::ALLOCATOR_GLOBAL;
33
use clippy_utils::source::snippet;
4-
use if_chain::if_chain;
4+
use clippy_utils::{last_path_segment, match_def_path};
55
use rustc_errors::Applicability;
66
use rustc_hir::def_id::DefId;
77
use rustc_hir::{self as hir, GenericArg, QPath, TyKind};
@@ -21,43 +21,57 @@ pub(super) fn check(
2121
box_size_threshold: u64,
2222
) -> bool {
2323
if cx.tcx.is_diagnostic_item(sym::Vec, def_id) {
24-
if_chain! {
24+
if let Some(last) = last_path_segment(qpath).args
2525
// Get the _ part of Vec<_>
26-
if let Some(last) = last_path_segment(qpath).args;
27-
if let Some(ty) = last.args.iter().find_map(|arg| match arg {
28-
GenericArg::Type(ty) => Some(ty),
29-
_ => None,
30-
});
26+
&& let Some(GenericArg::Type(ty)) = last.args.first()
27+
// extract allocator from the Vec for later
28+
&& let vec_alloc_ty = last.args.get(1)
3129
// ty is now _ at this point
32-
if let TyKind::Path(ref ty_qpath) = ty.kind;
33-
let res = cx.qpath_res(ty_qpath, ty.hir_id);
34-
if let Some(def_id) = res.opt_def_id();
35-
if Some(def_id) == cx.tcx.lang_items().owned_box();
30+
&& let TyKind::Path(ref ty_qpath) = ty.kind
31+
&& let res = cx.qpath_res(ty_qpath, ty.hir_id)
32+
&& let Some(def_id) = res.opt_def_id()
33+
&& Some(def_id) == cx.tcx.lang_items().owned_box()
3634
// At this point, we know ty is Box<T>, now get T
37-
if let Some(last) = last_path_segment(ty_qpath).args;
38-
if let Some(boxed_ty) = last.args.iter().find_map(|arg| match arg {
39-
GenericArg::Type(ty) => Some(ty),
40-
_ => None,
41-
});
42-
let ty_ty = hir_ty_to_ty(cx.tcx, boxed_ty);
43-
if !ty_ty.has_escaping_bound_vars();
44-
if ty_ty.is_sized(cx.tcx, cx.param_env);
45-
if let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes());
46-
if ty_ty_size < box_size_threshold;
47-
then {
48-
span_lint_and_sugg(
49-
cx,
50-
VEC_BOX,
51-
hir_ty.span,
52-
"`Vec<T>` is already on the heap, the boxing is unnecessary",
53-
"try",
54-
format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")),
55-
Applicability::MachineApplicable,
56-
);
57-
true
58-
} else {
59-
false
35+
&& let Some(last) = last_path_segment(ty_qpath).args
36+
&& let Some(GenericArg::Type(boxed_ty)) = last.args.first()
37+
// extract allocator from the Box for later
38+
&& let boxed_alloc_ty = last.args.get(1)
39+
&& let ty_ty = hir_ty_to_ty(cx.tcx, boxed_ty)
40+
&& !ty_ty.has_escaping_bound_vars()
41+
&& ty_ty.is_sized(cx.tcx, cx.param_env)
42+
&& let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes())
43+
&& ty_ty_size < box_size_threshold
44+
// https://github.com/rust-lang/rust-clippy/issues/7114
45+
&& match (vec_alloc_ty, boxed_alloc_ty) {
46+
(None, None) => true,
47+
// this is in the event that we have something like
48+
// Vec<_, Global>, in which case is equivalent to
49+
// Vec<_>
50+
(None, Some(GenericArg::Type(inner))) | (Some(GenericArg::Type(inner)), None) => {
51+
if let TyKind::Path(path) = inner.kind
52+
&& let Some(did) = cx.qpath_res(&path, inner.hir_id).opt_def_id() {
53+
match_def_path(cx, did, &ALLOCATOR_GLOBAL)
54+
} else {
55+
false
56+
}
57+
},
58+
(Some(GenericArg::Type(l)), Some(GenericArg::Type(r))) =>
59+
hir_ty_to_ty(cx.tcx, l) == hir_ty_to_ty(cx.tcx, r),
60+
_ => false
6061
}
62+
{
63+
span_lint_and_sugg(
64+
cx,
65+
VEC_BOX,
66+
hir_ty.span,
67+
"`Vec<T>` is already on the heap, the boxing is unnecessary",
68+
"try",
69+
format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")),
70+
Applicability::Unspecified,
71+
);
72+
true
73+
} else {
74+
false
6175
}
6276
} else {
6377
false

Diff for: clippy_utils/src/paths.rs

+1
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,4 @@ pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"];
9999
pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"];
100100
#[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so
101101
pub const BOOL_THEN: [&str; 4] = ["core", "bool", "<impl bool>", "then"];
102+
pub const ALLOCATOR_GLOBAL: [&str; 3] = ["alloc", "alloc", "Global"];

Diff for: tests/ui/vec_box_sized.fixed

-57
This file was deleted.

Diff for: tests/ui/vec_box_sized.rs

+35-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
1+
//@no-rustfix
2+
13
#![allow(dead_code)]
4+
#![feature(allocator_api)]
5+
6+
use std::alloc::{AllocError, Allocator, Layout};
7+
use std::ptr::NonNull;
28

39
struct SizedStruct(i32);
410
struct UnsizedStruct([i32]);
511
struct BigStruct([i32; 10000]);
612

13+
struct DummyAllocator;
14+
unsafe impl Allocator for DummyAllocator {
15+
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
16+
todo!()
17+
}
18+
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
19+
todo!()
20+
}
21+
}
22+
723
/// The following should trigger the lint
824
mod should_trigger {
9-
use super::SizedStruct;
25+
use super::{DummyAllocator, SizedStruct};
1026
const C: Vec<Box<i32>> = Vec::new();
1127
static S: Vec<Box<i32>> = Vec::new();
1228

@@ -16,11 +32,21 @@ mod should_trigger {
1632

1733
struct A(Vec<Box<SizedStruct>>);
1834
struct B(Vec<Vec<Box<(u32)>>>);
35+
36+
fn allocator_global_defined_vec() -> Vec<Box<i32>, std::alloc::Global> {
37+
Vec::new()
38+
}
39+
fn allocator_global_defined_box() -> Vec<Box<i32, std::alloc::Global>> {
40+
Vec::new()
41+
}
42+
fn allocator_match() -> Vec<Box<i32, DummyAllocator>, DummyAllocator> {
43+
Vec::new_in(DummyAllocator)
44+
}
1945
}
2046

2147
/// The following should not trigger the lint
2248
mod should_not_trigger {
23-
use super::{BigStruct, UnsizedStruct};
49+
use super::{BigStruct, DummyAllocator, UnsizedStruct};
2450

2551
struct C(Vec<Box<UnsizedStruct>>);
2652
struct D(Vec<Box<BigStruct>>);
@@ -33,6 +59,13 @@ mod should_not_trigger {
3359
// Regression test for #3720. This was causing an ICE.
3460
inner: Vec<Box<T>>,
3561
}
62+
63+
fn allocator_mismatch() -> Vec<Box<i32, DummyAllocator>> {
64+
Vec::new()
65+
}
66+
fn allocator_mismatch_2() -> Vec<Box<i32>, DummyAllocator> {
67+
Vec::new_in(DummyAllocator)
68+
}
3669
}
3770

3871
mod inner_mod {

Diff for: tests/ui/vec_box_sized.stderr

+25-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: `Vec<T>` is already on the heap, the boxing is unnecessary
2-
--> $DIR/vec_box_sized.rs:10:14
2+
--> $DIR/vec_box_sized.rs:26:14
33
|
44
LL | const C: Vec<Box<i32>> = Vec::new();
55
| ^^^^^^^^^^^^^ help: try: `Vec<i32>`
@@ -8,34 +8,52 @@ LL | const C: Vec<Box<i32>> = Vec::new();
88
= help: to override `-D warnings` add `#[allow(clippy::vec_box)]`
99

1010
error: `Vec<T>` is already on the heap, the boxing is unnecessary
11-
--> $DIR/vec_box_sized.rs:11:15
11+
--> $DIR/vec_box_sized.rs:27:15
1212
|
1313
LL | static S: Vec<Box<i32>> = Vec::new();
1414
| ^^^^^^^^^^^^^ help: try: `Vec<i32>`
1515

1616
error: `Vec<T>` is already on the heap, the boxing is unnecessary
17-
--> $DIR/vec_box_sized.rs:14:21
17+
--> $DIR/vec_box_sized.rs:30:21
1818
|
1919
LL | sized_type: Vec<Box<SizedStruct>>,
2020
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec<SizedStruct>`
2121

2222
error: `Vec<T>` is already on the heap, the boxing is unnecessary
23-
--> $DIR/vec_box_sized.rs:17:14
23+
--> $DIR/vec_box_sized.rs:33:14
2424
|
2525
LL | struct A(Vec<Box<SizedStruct>>);
2626
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec<SizedStruct>`
2727

2828
error: `Vec<T>` is already on the heap, the boxing is unnecessary
29-
--> $DIR/vec_box_sized.rs:18:18
29+
--> $DIR/vec_box_sized.rs:34:18
3030
|
3131
LL | struct B(Vec<Vec<Box<(u32)>>>);
3232
| ^^^^^^^^^^^^^^^ help: try: `Vec<u32>`
3333

3434
error: `Vec<T>` is already on the heap, the boxing is unnecessary
35-
--> $DIR/vec_box_sized.rs:46:23
35+
--> $DIR/vec_box_sized.rs:36:42
36+
|
37+
LL | fn allocator_global_defined_vec() -> Vec<Box<i32>, std::alloc::Global> {
38+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec<i32>`
39+
40+
error: `Vec<T>` is already on the heap, the boxing is unnecessary
41+
--> $DIR/vec_box_sized.rs:39:42
42+
|
43+
LL | fn allocator_global_defined_box() -> Vec<Box<i32, std::alloc::Global>> {
44+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec<i32>`
45+
46+
error: `Vec<T>` is already on the heap, the boxing is unnecessary
47+
--> $DIR/vec_box_sized.rs:42:29
48+
|
49+
LL | fn allocator_match() -> Vec<Box<i32, DummyAllocator>, DummyAllocator> {
50+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec<i32>`
51+
52+
error: `Vec<T>` is already on the heap, the boxing is unnecessary
53+
--> $DIR/vec_box_sized.rs:79:23
3654
|
3755
LL | pub fn f() -> Vec<Box<S>> {
3856
| ^^^^^^^^^^^ help: try: `Vec<S>`
3957

40-
error: aborting due to 6 previous errors
58+
error: aborting due to 9 previous errors
4159

0 commit comments

Comments
 (0)