Skip to content

Commit 6745434

Browse files
committed
new lint: let_arr_const
1 parent 33813eb commit 6745434

File tree

7 files changed

+196
-1
lines changed

7 files changed

+196
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5435,6 +5435,7 @@ Released 2018-09-13
54355435
[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
54365436
[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
54375437
[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
5438+
[`let_arr_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_arr_const
54385439
[`let_underscore_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_drop
54395440
[`let_underscore_future`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_future
54405441
[`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
260260
crate::len_zero::COMPARISON_TO_EMPTY_INFO,
261261
crate::len_zero::LEN_WITHOUT_IS_EMPTY_INFO,
262262
crate::len_zero::LEN_ZERO_INFO,
263+
crate::let_arr_const::LET_ARR_CONST_INFO,
263264
crate::let_if_seq::USELESS_LET_IF_SEQ_INFO,
264265
crate::let_underscore::LET_UNDERSCORE_FUTURE_INFO,
265266
crate::let_underscore::LET_UNDERSCORE_LOCK_INFO,

clippy_lints/src/let_arr_const.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
2+
use clippy_utils::source::snippet_with_applicability;
3+
use clippy_utils::ty::implements_trait;
4+
use hir::{BindingMode, ExprKind, PatKind, Stmt, StmtKind};
5+
use rustc_errors::Applicability;
6+
use rustc_hir as hir;
7+
use rustc_lint::{LateContext, LateLintPass};
8+
use rustc_session::declare_lint_pass;
9+
10+
declare_clippy_lint! {
11+
/// ### What it does
12+
/// Checks for defining of read-only arrays on stack.
13+
///
14+
/// ### Why is this bad?
15+
/// A read-only array should be declared as a `static` item or used tricks
16+
/// to made it into `.rodata` section of the compiled file.
17+
///
18+
/// ### Known problems
19+
/// `let array` puts array on the stack which might make the generated binary file
20+
/// bigger and slower.
21+
///
22+
/// ### Example
23+
/// ```no_run
24+
/// let a = [0; 64];
25+
/// ```
26+
///
27+
/// Use instead:
28+
/// ```no_run
29+
/// let a = *&[0; 64];
30+
/// // or
31+
/// static A: [u32; 64] = [0; 64];
32+
/// ```
33+
#[clippy::version = "1.80.0"]
34+
pub LET_ARR_CONST,
35+
perf,
36+
"declare a read-only array on stack"
37+
}
38+
39+
declare_lint_pass!(LetArrConst => [LET_ARR_CONST]);
40+
41+
impl LateLintPass<'_> for LetArrConst {
42+
// should lint on `let array` which non-mut and:
43+
// if let repeat:
44+
// if let expr: copy
45+
// todo: repair clippy::author
46+
fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
47+
if let StmtKind::Let(ref local) = stmt.kind
48+
&& let PatKind::Binding(BindingMode::NONE, _, _name, None) = local.pat.kind
49+
&& let Some(ref init) = local.init
50+
&& !init.span.from_expansion()
51+
{
52+
let mut applicability = Applicability::MachineApplicable;
53+
let lang_items = cx.tcx.lang_items();
54+
let Some(copy_id) = lang_items.copy_trait() else {
55+
return;
56+
};
57+
// `let arr = [<Copy type>; 42];
58+
let mut should = false;
59+
if let ExprKind::Repeat(ref value, _length) = init.kind {
60+
let ty = cx.typeck_results().expr_ty(value);
61+
if !implements_trait(cx, ty, copy_id, &[]) {
62+
span_lint_and_help(
63+
cx,
64+
LET_ARR_CONST,
65+
local.span,
66+
"declaring a read-only array on the stack",
67+
None,
68+
"using `static` to push the array to read-only section of program",
69+
);
70+
return;
71+
}
72+
should = true;
73+
}
74+
// `let arr = [1, 2, 3, 4];
75+
if let ExprKind::Array([ref expr, ..]) = init.kind
76+
&& let ty = cx.typeck_results().expr_ty(expr)
77+
&& implements_trait(cx, ty, copy_id, &[])
78+
{
79+
should = true;
80+
}
81+
82+
if should {
83+
let snippet = snippet_with_applicability(cx, init.span, "_", &mut applicability);
84+
let sugg = format!("*&{snippet}");
85+
span_lint_and_sugg(
86+
cx,
87+
LET_ARR_CONST,
88+
init.span,
89+
"declaring a read-only array on the stack",
90+
"using `static` to push the array to read-only section of program or try",
91+
sugg,
92+
applicability,
93+
);
94+
}
95+
}
96+
}
97+
}

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ mod large_stack_arrays;
187187
mod large_stack_frames;
188188
mod legacy_numeric_constants;
189189
mod len_zero;
190+
mod let_arr_const;
190191
mod let_if_seq;
191192
mod let_underscore;
192193
mod let_with_type_underscore;
@@ -1165,6 +1166,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
11651166
..Default::default()
11661167
})
11671168
});
1169+
store.register_late_pass(|_| Box::new(let_arr_const::LetArrConst));
11681170
// add lints here, do not remove this comment, it's used in `new_lint`
11691171
}
11701172

tests/ui/let_arr_const.fixed

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#![crate_type = "lib"]
2+
#![warn(clippy::let_arr_const)]
3+
4+
// <https://github.com/rust-lang/rust/issues/73825>.
5+
pub mod issue_rust_73825 {
6+
macro_rules! mac_gen_arr {
7+
() => {
8+
[0u32; 64]
9+
};
10+
}
11+
12+
pub fn do_not() {
13+
let _repeat = *&[0; 64];
14+
let _arr = *&[0, 1, 2, 3, 4];
15+
let _arr = mac_gen_arr!();
16+
let _arr = gen_array();
17+
let _arr = gen_array_non_copy();
18+
{
19+
let mut arr = [0; 32];
20+
arr[1] = 42;
21+
}
22+
{
23+
let a = String::from("a");
24+
let b = String::from("a");
25+
let _arr = [a, b];
26+
}
27+
{
28+
let mut arr = [const { String::new() }; 32];
29+
arr[1] = "a".to_owned();
30+
}
31+
}
32+
33+
const fn gen_array() -> [u32; 42] {
34+
unimplemented!()
35+
}
36+
37+
const fn gen_array_non_copy() -> [String; 42] {
38+
unimplemented!()
39+
}
40+
41+
pub fn do_it() {
42+
// Copy type
43+
let _repeat: [i32; 64] = *&[0; 64];
44+
let _arr = *&[0, 1, 3, 5, 7, 8];
45+
// Non Copy type
46+
{
47+
let _repeat_const = [const { String::new() }; 32];
48+
const EMPTY: String = String::new();
49+
let _repeat = [EMPTY; 32];
50+
}
51+
}
52+
}

tests/ui/let_arr_const.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#![crate_type = "lib"]
2-
// #![warn(clippy::let_arr_const)]
2+
#![warn(clippy::let_arr_const)]
33

44
// <https://github.com/rust-lang/rust/issues/73825>.
55
pub mod issue_rust_73825 {

tests/ui/let_arr_const.stderr

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
error: declaring a read-only array on the stack
2+
--> tests/ui/let_arr_const.rs:43:34
3+
|
4+
LL | let _repeat: [i32; 64] = [0; 64];
5+
| ^^^^^^^
6+
|
7+
= note: `-D clippy::let-arr-const` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::let_arr_const)]`
9+
help: using `static` to push the array to read-only section of program or try
10+
|
11+
LL | let _repeat: [i32; 64] = *&[0; 64];
12+
| ~~~~~~~~~
13+
14+
error: declaring a read-only array on the stack
15+
--> tests/ui/let_arr_const.rs:44:20
16+
|
17+
LL | let _arr = [0, 1, 3, 5, 7, 8];
18+
| ^^^^^^^^^^^^^^^^^^
19+
|
20+
help: using `static` to push the array to read-only section of program or try
21+
|
22+
LL | let _arr = *&[0, 1, 3, 5, 7, 8];
23+
| ~~~~~~~~~~~~~~~~~~~~
24+
25+
error: declaring a read-only array on the stack
26+
--> tests/ui/let_arr_const.rs:47:13
27+
|
28+
LL | let _repeat_const = [const { String::new() }; 32];
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30+
|
31+
= help: using `static` to push the array to read-only section of program
32+
33+
error: declaring a read-only array on the stack
34+
--> tests/ui/let_arr_const.rs:49:13
35+
|
36+
LL | let _repeat = [EMPTY; 32];
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
38+
|
39+
= help: using `static` to push the array to read-only section of program
40+
41+
error: aborting due to 4 previous errors
42+

0 commit comments

Comments
 (0)