Skip to content

Commit a167b6e

Browse files
committed
Add lint on large non scalar const
1 parent 610bcea commit a167b6e

File tree

7 files changed

+204
-2
lines changed

7 files changed

+204
-2
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1273,6 +1273,7 @@ Released 2018-09-13
12731273
[`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
12741274
[`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
12751275
[`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
1276+
[`non_scalar_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_scalar_const
12761277
[`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool
12771278
[`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options
12781279
[`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 358 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
8+
[There are 359 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
@@ -267,6 +267,7 @@ pub mod new_without_default;
267267
pub mod no_effect;
268268
pub mod non_copy_const;
269269
pub mod non_expressive_names;
270+
pub mod non_scalar_const;
270271
pub mod open_options;
271272
pub mod option_env_unwrap;
272273
pub mod overflow_check_conditional;
@@ -716,6 +717,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
716717
&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS,
717718
&non_expressive_names::MANY_SINGLE_CHAR_NAMES,
718719
&non_expressive_names::SIMILAR_NAMES,
720+
&non_scalar_const::NON_SCALAR_CONST,
719721
&open_options::NONSENSICAL_OPEN_OPTIONS,
720722
&option_env_unwrap::OPTION_ENV_UNWRAP,
721723
&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
@@ -1000,6 +1002,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10001002
store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
10011003
let array_size_threshold = conf.array_size_threshold;
10021004
store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
1005+
store.register_late_pass(move || box non_scalar_const::NonScalarConst::new(array_size_threshold));
10031006
store.register_late_pass(move || box floating_point_arithmetic::FloatingPointArithmetic);
10041007
store.register_early_pass(|| box as_conversions::AsConversions);
10051008
store.register_early_pass(|| box utils::internal_lints::ProduceIce);
@@ -1294,6 +1297,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
12941297
LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
12951298
LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
12961299
LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES),
1300+
LintId::of(&non_scalar_const::NON_SCALAR_CONST),
12971301
LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
12981302
LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
12991303
LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
@@ -1633,6 +1637,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
16331637
LintId::of(&methods::SINGLE_CHAR_PATTERN),
16341638
LintId::of(&misc::CMP_OWNED),
16351639
LintId::of(&mutex_atomic::MUTEX_ATOMIC),
1640+
LintId::of(&non_scalar_const::NON_SCALAR_CONST),
16361641
LintId::of(&redundant_clone::REDUNDANT_CLONE),
16371642
LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
16381643
LintId::of(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF),

clippy_lints/src/non_scalar_const.rs

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
use crate::rustc_target::abi::LayoutOf;
2+
use crate::utils::{snippet_opt, 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_hir::{Item, ItemKind};
7+
use rustc_lint::{LateContext, LateLintPass};
8+
use rustc_session::{declare_tool_lint, impl_lint_pass};
9+
use rustc_span::InnerSpan;
10+
use rustc_typeck::hir_ty_to_ty;
11+
12+
declare_clippy_lint! {
13+
/// **What it does:** Checks for large `const` non-scalar types (ie: array) that should
14+
/// be defined as `static` instead.
15+
///
16+
/// **Why is this bad?** Performance: const variables are inlined upon use.
17+
/// Static items result in only one instance and has a fixed location in memory.
18+
///
19+
/// **Known problems:** None.
20+
///
21+
/// **Example:**
22+
/// ```rust,ignore
23+
/// // Bad code
24+
/// pub const a = [0u32; 1_000_000];
25+
///
26+
/// // Good code
27+
/// pub static a = [0u32; 1_000_000];
28+
/// ```
29+
pub NON_SCALAR_CONST,
30+
perf,
31+
"large non-scalar const variable may cause performance overhead"
32+
}
33+
34+
pub struct NonScalarConst {
35+
maximum_allowed_size: u64,
36+
}
37+
38+
impl NonScalarConst {
39+
#[must_use]
40+
pub fn new(maximum_allowed_size: u64) -> Self {
41+
Self { maximum_allowed_size }
42+
}
43+
}
44+
45+
impl_lint_pass!(NonScalarConst => [NON_SCALAR_CONST]);
46+
47+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonScalarConst {
48+
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx Item<'_>) {
49+
// No suggestion in macros
50+
if it.span.from_expansion() {
51+
return;
52+
}
53+
if_chain! {
54+
if let ItemKind::Const(hir_ty, _) = &it.kind;
55+
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
56+
if let ty::Array(element_type, cst) = ty.kind;
57+
if let ConstKind::Value(val) = cst.val;
58+
if let ConstValue::Scalar(element_count) = val;
59+
if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx);
60+
if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes());
61+
if self.maximum_allowed_size < element_count * element_size;
62+
then {
63+
// We need to take care about the right "const" position inside the span
64+
let mut start_sugg = 0;
65+
if let Some(visi) = snippet_opt(cx, it.vis.span) {
66+
let len_visi = visi.len();
67+
if len_visi > 0 {
68+
start_sugg = len_visi + 1;
69+
}
70+
}
71+
let sugg_span = it.span.from_inner(
72+
InnerSpan::new(start_sugg, start_sugg + "const".len())
73+
);
74+
span_lint_and_then(
75+
cx,
76+
NON_SCALAR_CONST,
77+
sugg_span,
78+
"large array defined as const",
79+
|db| {
80+
db.span_label(
81+
it.span,
82+
"make this item static"
83+
);
84+
}
85+
);
86+
}
87+
}
88+
}
89+
}

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; 358] = [
9+
pub const ALL_LINTS: [Lint; 359] = [
1010
Lint {
1111
name: "absurd_extreme_comparisons",
1212
group: "correctness",
@@ -1456,6 +1456,13 @@ pub const ALL_LINTS: [Lint; 358] = [
14561456
deprecation: None,
14571457
module: "unicode",
14581458
},
1459+
Lint {
1460+
name: "non_scalar_const",
1461+
group: "perf",
1462+
desc: "large non-scalar const variable may cause performance overhead",
1463+
deprecation: None,
1464+
module: "non_scalar_const",
1465+
},
14591466
Lint {
14601467
name: "nonminimal_bool",
14611468
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+
| -----------^^^^^----------------------------------------------------- make this 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+
| ----^^^^^----------------------------------------------- make this 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+
| make this 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+
| ----^^^^^----------------------------------------------- make this 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+
| make this 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+
| ----^^^^^----------------------------------------------------------- make this 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+
| make this 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+
| ----^^^^^------------------------------------------------------------- make this 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+
| make this item static
64+
65+
error: aborting due to 9 previous errors
66+

0 commit comments

Comments
 (0)