Skip to content

Commit c865d97

Browse files
committed
Add lint on large const arrays
1 parent e170c84 commit c865d97

File tree

8 files changed

+250
-2
lines changed

8 files changed

+250
-2
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1318,6 +1318,7 @@ Released 2018-09-13
13181318
[`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
13191319
[`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
13201320
[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
1321+
[`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays
13211322
[`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups
13221323
[`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant
13231324
[`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
77

8-
[There are 361 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
8+
[There are 362 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
99

1010
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
1111

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
use crate::rustc_target::abi::LayoutOf;
2+
use crate::utils::span_lint_and_then;
3+
use if_chain::if_chain;
4+
use rustc::mir::interpret::ConstValue;
5+
use rustc::ty::{self, ConstKind};
6+
use rustc_errors::Applicability;
7+
use rustc_hir::{Item, ItemKind};
8+
use rustc_lint::{LateContext, LateLintPass};
9+
use rustc_session::{declare_tool_lint, impl_lint_pass};
10+
use rustc_span::{BytePos, Pos, Span};
11+
use rustc_typeck::hir_ty_to_ty;
12+
13+
declare_clippy_lint! {
14+
/// **What it does:** Checks for large `const` arrays that should
15+
/// be defined as `static` instead.
16+
///
17+
/// **Why is this bad?** Performance: const variables are inlined upon use.
18+
/// Static items result in only one instance and has a fixed location in memory.
19+
///
20+
/// **Known problems:** None.
21+
///
22+
/// **Example:**
23+
/// ```rust,ignore
24+
/// // Bad
25+
/// pub const a = [0u32; 1_000_000];
26+
///
27+
/// // Good
28+
/// pub static a = [0u32; 1_000_000];
29+
/// ```
30+
pub LARGE_CONST_ARRAYS,
31+
perf,
32+
"large non-scalar const array may cause performance overhead"
33+
}
34+
35+
pub struct LargeConstArrays {
36+
maximum_allowed_size: u64,
37+
}
38+
39+
impl LargeConstArrays {
40+
#[must_use]
41+
pub fn new(maximum_allowed_size: u64) -> Self {
42+
Self { maximum_allowed_size }
43+
}
44+
}
45+
46+
impl_lint_pass!(LargeConstArrays => [LARGE_CONST_ARRAYS]);
47+
48+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeConstArrays {
49+
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item<'_>) {
50+
if_chain! {
51+
if !item.span.from_expansion();
52+
if let ItemKind::Const(hir_ty, _) = &item.kind;
53+
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
54+
if let ty::Array(element_type, cst) = ty.kind;
55+
if let ConstKind::Value(val) = cst.val;
56+
if let ConstValue::Scalar(element_count) = val;
57+
if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx);
58+
if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes());
59+
if self.maximum_allowed_size < element_count * element_size;
60+
61+
then {
62+
let hi_pos = item.ident.span.lo() - BytePos::from_usize(1);
63+
let sugg_span = Span::new(
64+
hi_pos - BytePos::from_usize("const".len()),
65+
hi_pos,
66+
item.span.ctxt(),
67+
);
68+
span_lint_and_then(
69+
cx,
70+
LARGE_CONST_ARRAYS,
71+
item.span,
72+
"large array defined as const",
73+
|db| {
74+
db.span_suggestion(
75+
sugg_span,
76+
"make this a static item",
77+
"static".to_string(),
78+
Applicability::MachineApplicable,
79+
);
80+
}
81+
);
82+
}
83+
}
84+
}
85+
}

clippy_lints/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ pub mod inline_fn_without_body;
231231
pub mod int_plus_one;
232232
pub mod integer_division;
233233
pub mod items_after_statements;
234+
pub mod large_const_arrays;
234235
pub mod large_enum_variant;
235236
pub mod large_stack_arrays;
236237
pub mod len_zero;
@@ -579,6 +580,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
579580
&int_plus_one::INT_PLUS_ONE,
580581
&integer_division::INTEGER_DIVISION,
581582
&items_after_statements::ITEMS_AFTER_STATEMENTS,
583+
&large_const_arrays::LARGE_CONST_ARRAYS,
582584
&large_enum_variant::LARGE_ENUM_VARIANT,
583585
&large_stack_arrays::LARGE_STACK_ARRAYS,
584586
&len_zero::LEN_WITHOUT_IS_EMPTY,
@@ -1013,6 +1015,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10131015
store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
10141016
let array_size_threshold = conf.array_size_threshold;
10151017
store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
1018+
store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold));
10161019
store.register_late_pass(move || box floating_point_arithmetic::FloatingPointArithmetic);
10171020
store.register_early_pass(|| box as_conversions::AsConversions);
10181021
store.register_early_pass(|| box utils::internal_lints::ProduceIce);
@@ -1204,6 +1207,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
12041207
LintId::of(&inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
12051208
LintId::of(&inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
12061209
LintId::of(&int_plus_one::INT_PLUS_ONE),
1210+
LintId::of(&large_const_arrays::LARGE_CONST_ARRAYS),
12071211
LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT),
12081212
LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY),
12091213
LintId::of(&len_zero::LEN_ZERO),
@@ -1639,6 +1643,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
16391643
LintId::of(&bytecount::NAIVE_BYTECOUNT),
16401644
LintId::of(&entry::MAP_ENTRY),
16411645
LintId::of(&escape::BOXED_LOCAL),
1646+
LintId::of(&large_const_arrays::LARGE_CONST_ARRAYS),
16421647
LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT),
16431648
LintId::of(&loops::MANUAL_MEMCPY),
16441649
LintId::of(&loops::NEEDLESS_COLLECT),

src/lintlist/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub use lint::Lint;
66
pub use lint::LINT_LEVELS;
77

88
// begin lint list, do not remove this comment, it’s used in `update_lints`
9-
pub const ALL_LINTS: [Lint; 361] = [
9+
pub const ALL_LINTS: [Lint; 362] = [
1010
Lint {
1111
name: "absurd_extreme_comparisons",
1212
group: "correctness",
@@ -931,6 +931,13 @@ pub const ALL_LINTS: [Lint; 361] = [
931931
deprecation: None,
932932
module: "non_expressive_names",
933933
},
934+
Lint {
935+
name: "large_const_arrays",
936+
group: "perf",
937+
desc: "large non-scalar const array may cause performance overhead",
938+
deprecation: None,
939+
module: "large_const_arrays",
940+
},
934941
Lint {
935942
name: "large_digit_groups",
936943
group: "pedantic",

tests/ui/large_const_arrays.fixed

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// run-rustfix
2+
3+
#![warn(clippy::large_const_arrays)]
4+
#![allow(dead_code)]
5+
6+
#[derive(Clone, Copy)]
7+
pub struct S {
8+
pub data: [u64; 32],
9+
}
10+
11+
// Should lint
12+
pub(crate) static FOO_PUB_CRATE: [u32; 1_000_000] = [0u32; 1_000_000];
13+
pub static FOO_PUB: [u32; 1_000_000] = [0u32; 1_000_000];
14+
static FOO: [u32; 1_000_000] = [0u32; 1_000_000];
15+
16+
// Good
17+
pub(crate) const G_FOO_PUB_CRATE: [u32; 1_000] = [0u32; 1_000];
18+
pub const G_FOO_PUB: [u32; 1_000] = [0u32; 1_000];
19+
const G_FOO: [u32; 1_000] = [0u32; 1_000];
20+
21+
fn main() {
22+
// Should lint
23+
pub static BAR_PUB: [u32; 1_000_000] = [0u32; 1_000_000];
24+
static BAR: [u32; 1_000_000] = [0u32; 1_000_000];
25+
pub static BAR_STRUCT_PUB: [S; 5_000] = [S { data: [0; 32] }; 5_000];
26+
static BAR_STRUCT: [S; 5_000] = [S { data: [0; 32] }; 5_000];
27+
pub static BAR_S_PUB: [Option<&str>; 200_000] = [Some("str"); 200_000];
28+
static BAR_S: [Option<&str>; 200_000] = [Some("str"); 200_000];
29+
30+
// Good
31+
pub const G_BAR_PUB: [u32; 1_000] = [0u32; 1_000];
32+
const G_BAR: [u32; 1_000] = [0u32; 1_000];
33+
pub const G_BAR_STRUCT_PUB: [S; 500] = [S { data: [0; 32] }; 500];
34+
const G_BAR_STRUCT: [S; 500] = [S { data: [0; 32] }; 500];
35+
pub const G_BAR_S_PUB: [Option<&str>; 200] = [Some("str"); 200];
36+
const G_BAR_S: [Option<&str>; 200] = [Some("str"); 200];
37+
}

tests/ui/large_const_arrays.rs

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// run-rustfix
2+
3+
#![warn(clippy::large_const_arrays)]
4+
#![allow(dead_code)]
5+
6+
#[derive(Clone, Copy)]
7+
pub struct S {
8+
pub data: [u64; 32],
9+
}
10+
11+
// Should lint
12+
pub(crate) const FOO_PUB_CRATE: [u32; 1_000_000] = [0u32; 1_000_000];
13+
pub const FOO_PUB: [u32; 1_000_000] = [0u32; 1_000_000];
14+
const FOO: [u32; 1_000_000] = [0u32; 1_000_000];
15+
16+
// Good
17+
pub(crate) const G_FOO_PUB_CRATE: [u32; 1_000] = [0u32; 1_000];
18+
pub const G_FOO_PUB: [u32; 1_000] = [0u32; 1_000];
19+
const G_FOO: [u32; 1_000] = [0u32; 1_000];
20+
21+
fn main() {
22+
// Should lint
23+
pub const BAR_PUB: [u32; 1_000_000] = [0u32; 1_000_000];
24+
const BAR: [u32; 1_000_000] = [0u32; 1_000_000];
25+
pub const BAR_STRUCT_PUB: [S; 5_000] = [S { data: [0; 32] }; 5_000];
26+
const BAR_STRUCT: [S; 5_000] = [S { data: [0; 32] }; 5_000];
27+
pub const BAR_S_PUB: [Option<&str>; 200_000] = [Some("str"); 200_000];
28+
const BAR_S: [Option<&str>; 200_000] = [Some("str"); 200_000];
29+
30+
// Good
31+
pub const G_BAR_PUB: [u32; 1_000] = [0u32; 1_000];
32+
const G_BAR: [u32; 1_000] = [0u32; 1_000];
33+
pub const G_BAR_STRUCT_PUB: [S; 500] = [S { data: [0; 32] }; 500];
34+
const G_BAR_STRUCT: [S; 500] = [S { data: [0; 32] }; 500];
35+
pub const G_BAR_S_PUB: [Option<&str>; 200] = [Some("str"); 200];
36+
const G_BAR_S: [Option<&str>; 200] = [Some("str"); 200];
37+
}

tests/ui/large_const_arrays.stderr

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
error: large array defined as const
2+
--> $DIR/large_const_arrays.rs:12:1
3+
|
4+
LL | pub(crate) const FOO_PUB_CRATE: [u32; 1_000_000] = [0u32; 1_000_000];
5+
| ^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
| |
7+
| help: make this a static item: `static`
8+
|
9+
= note: `-D clippy::large-const-arrays` implied by `-D warnings`
10+
11+
error: large array defined as const
12+
--> $DIR/large_const_arrays.rs:13:1
13+
|
14+
LL | pub const FOO_PUB: [u32; 1_000_000] = [0u32; 1_000_000];
15+
| ^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
| |
17+
| help: make this a static item: `static`
18+
19+
error: large array defined as const
20+
--> $DIR/large_const_arrays.rs:14:1
21+
|
22+
LL | const FOO: [u32; 1_000_000] = [0u32; 1_000_000];
23+
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24+
| |
25+
| help: make this a static item: `static`
26+
27+
error: large array defined as const
28+
--> $DIR/large_const_arrays.rs:23:5
29+
|
30+
LL | pub const BAR_PUB: [u32; 1_000_000] = [0u32; 1_000_000];
31+
| ^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
32+
| |
33+
| help: make this a static item: `static`
34+
35+
error: large array defined as const
36+
--> $DIR/large_const_arrays.rs:24:5
37+
|
38+
LL | const BAR: [u32; 1_000_000] = [0u32; 1_000_000];
39+
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
40+
| |
41+
| help: make this a static item: `static`
42+
43+
error: large array defined as const
44+
--> $DIR/large_const_arrays.rs:25:5
45+
|
46+
LL | pub const BAR_STRUCT_PUB: [S; 5_000] = [S { data: [0; 32] }; 5_000];
47+
| ^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
48+
| |
49+
| help: make this a static item: `static`
50+
51+
error: large array defined as const
52+
--> $DIR/large_const_arrays.rs:26:5
53+
|
54+
LL | const BAR_STRUCT: [S; 5_000] = [S { data: [0; 32] }; 5_000];
55+
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
56+
| |
57+
| help: make this a static item: `static`
58+
59+
error: large array defined as const
60+
--> $DIR/large_const_arrays.rs:27:5
61+
|
62+
LL | pub const BAR_S_PUB: [Option<&str>; 200_000] = [Some("str"); 200_000];
63+
| ^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
64+
| |
65+
| help: make this a static item: `static`
66+
67+
error: large array defined as const
68+
--> $DIR/large_const_arrays.rs:28:5
69+
|
70+
LL | const BAR_S: [Option<&str>; 200_000] = [Some("str"); 200_000];
71+
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
72+
| |
73+
| help: make this a static item: `static`
74+
75+
error: aborting due to 9 previous errors
76+

0 commit comments

Comments
 (0)