Skip to content

Commit 12b534c

Browse files
committed
Add lint on large non scalar const
1 parent 3d0f0e3 commit 12b534c

File tree

7 files changed

+200
-2
lines changed

7 files changed

+200
-2
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,7 @@ Released 2018-09-13
12741274
[`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
12751275
[`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
12761276
[`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
1277+
[`non_scalar_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_scalar_const
12771278
[`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool
12781279
[`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options
12791280
[`not_unsafe_ptr_arg_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref

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 360 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
8+
[There are 361 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

clippy_lints/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ pub mod new_without_default;
268268
pub mod no_effect;
269269
pub mod non_copy_const;
270270
pub mod non_expressive_names;
271+
pub mod non_scalar_const;
271272
pub mod open_options;
272273
pub mod option_env_unwrap;
273274
pub mod overflow_check_conditional;
@@ -719,6 +720,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
719720
&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS,
720721
&non_expressive_names::MANY_SINGLE_CHAR_NAMES,
721722
&non_expressive_names::SIMILAR_NAMES,
723+
&non_scalar_const::NON_SCALAR_CONST,
722724
&open_options::NONSENSICAL_OPEN_OPTIONS,
723725
&option_env_unwrap::OPTION_ENV_UNWRAP,
724726
&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
@@ -1003,6 +1005,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10031005
store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
10041006
let array_size_threshold = conf.array_size_threshold;
10051007
store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
1008+
store.register_late_pass(move || box non_scalar_const::NonScalarConst::new(array_size_threshold));
10061009
store.register_late_pass(move || box floating_point_arithmetic::FloatingPointArithmetic);
10071010
store.register_early_pass(|| box as_conversions::AsConversions);
10081011
store.register_early_pass(|| box utils::internal_lints::ProduceIce);
@@ -1300,6 +1303,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
13001303
LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
13011304
LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
13021305
LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES),
1306+
LintId::of(&non_scalar_const::NON_SCALAR_CONST),
13031307
LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
13041308
LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
13051309
LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
@@ -1639,6 +1643,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
16391643
LintId::of(&methods::SINGLE_CHAR_PATTERN),
16401644
LintId::of(&misc::CMP_OWNED),
16411645
LintId::of(&mutex_atomic::MUTEX_ATOMIC),
1646+
LintId::of(&non_scalar_const::NON_SCALAR_CONST),
16421647
LintId::of(&redundant_clone::REDUNDANT_CLONE),
16431648
LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
16441649
LintId::of(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF),

clippy_lints/src/non_scalar_const.rs

+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` non-scalar types (ie: array) 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 NON_SCALAR_CONST,
31+
perf,
32+
"large non-scalar const variable may cause performance overhead"
33+
}
34+
35+
pub struct NonScalarConst {
36+
maximum_allowed_size: u64,
37+
}
38+
39+
impl NonScalarConst {
40+
#[must_use]
41+
pub fn new(maximum_allowed_size: u64) -> Self {
42+
Self { maximum_allowed_size }
43+
}
44+
}
45+
46+
impl_lint_pass!(NonScalarConst => [NON_SCALAR_CONST]);
47+
48+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonScalarConst {
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+
NON_SCALAR_CONST,
71+
sugg_span,
72+
"large array defined as const",
73+
|db| {
74+
db.span_suggestion(
75+
item.span,
76+
"make this a static item",
77+
"static".to_string(),
78+
Applicability::MachineApplicable,
79+
);
80+
}
81+
);
82+
}
83+
}
84+
}
85+
}

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; 360] = [
9+
pub const ALL_LINTS: [Lint; 361] = [
1010
Lint {
1111
name: "absurd_extreme_comparisons",
1212
group: "correctness",
@@ -1463,6 +1463,13 @@ pub const ALL_LINTS: [Lint; 360] = [
14631463
deprecation: None,
14641464
module: "unicode",
14651465
},
1466+
Lint {
1467+
name: "non_scalar_const",
1468+
group: "perf",
1469+
desc: "large non-scalar const variable may cause performance overhead",
1470+
deprecation: None,
1471+
module: "non_scalar_const",
1472+
},
14661473
Lint {
14671474
name: "nonminimal_bool",
14681475
group: "complexity",

tests/ui/non_scalar_const.rs

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

tests/ui/non_scalar_const.stderr

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

0 commit comments

Comments
 (0)