Skip to content

Commit 4ddb621

Browse files
committed
fix: large_stack_frames FP on compiler generated targets
1 parent 7e2d26f commit 4ddb621

File tree

10 files changed

+214
-5
lines changed

10 files changed

+214
-5
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6643,6 +6643,8 @@ Released 2018-09-13
66436643
[`single-char-binding-names-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#single-char-binding-names-threshold
66446644
[`source-item-ordering`]: https://doc.rust-lang.org/clippy/lint_configuration.html#source-item-ordering
66456645
[`stack-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#stack-size-threshold
6646+
[`lint-macro-generated-functions`]: https://doc.rust-lang.org/clippy/lint_configuration.html#lint-macro-generated-functions
6647+
[`lint-inside-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#lint-inside-tests
66466648
[`standard-macro-braces`]: https://doc.rust-lang.org/clippy/lint_configuration.html#standard-macro-braces
66476649
[`struct-field-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#struct-field-name-threshold
66486650
[`suppress-restriction-lint-in-const`]: https://doc.rust-lang.org/clippy/lint_configuration.html#suppress-restriction-lint-in-const

book/src/lint_configuration.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,26 @@ The maximum allowed stack size for functions in bytes
966966
* [`large_stack_frames`](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_frames)
967967

968968

969+
## `lint-macro-generated-functions`
970+
Whether functions generated by macros should be checked.
971+
972+
**Default Value:** `true`
973+
974+
---
975+
**Affected lints:**
976+
* [`large_stack_frames`](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_frames)
977+
978+
979+
## `lint-inside-tests`
980+
Whether functions inside `#[cfg(test)]` modules or test functions should be checked.
981+
982+
**Default Value:** `false`
983+
984+
---
985+
**Affected lints:**
986+
* [`large_stack_frames`](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_frames)
987+
988+
969989
## `standard-macro-braces`
970990
Enforce the named macros always use the braces specified.
971991

clippy_config/src/conf.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,12 @@ define_Conf! {
672672
/// Use the `check-inconsistent-struct-field-initializers` configuration instead.
673673
#[conf_deprecated("Please use `check-inconsistent-struct-field-initializers` instead", check_inconsistent_struct_field_initializers)]
674674
lint_inconsistent_struct_field_initializers: bool = false,
675+
/// Whether functions inside `#[cfg(test)]` modules or test functions should be checked.
676+
#[lints(large_stack_frames)]
677+
lint_inside_tests: bool = false,
678+
/// Whether functions generated by macros should be checked.
679+
#[lints(large_stack_frames)]
680+
lint_macro_generated_functions: bool = false,
675681
/// The lower bound for linting decimal literals
676682
#[lints(decimal_literal_representation)]
677683
literal_representation_threshold: u64 = 16384,

clippy_lints/src/large_stack_frames.rs

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use std::{fmt, ops};
22

33
use clippy_config::Conf;
44
use clippy_utils::diagnostics::span_lint_and_then;
5-
use clippy_utils::fn_has_unsatisfiable_preds;
65
use clippy_utils::source::SpanRangeExt;
6+
use clippy_utils::{fn_has_unsatisfiable_preds, is_in_test};
77
use rustc_hir::def_id::LocalDefId;
88
use rustc_hir::intravisit::FnKind;
99
use rustc_hir::{Body, FnDecl};
@@ -83,12 +83,16 @@ declare_clippy_lint! {
8383

8484
pub struct LargeStackFrames {
8585
maximum_allowed_size: u64,
86+
lint_macro_generated_functions: bool,
87+
lint_inside_tests: bool,
8688
}
8789

8890
impl LargeStackFrames {
8991
pub fn new(conf: &'static Conf) -> Self {
9092
Self {
9193
maximum_allowed_size: conf.stack_size_threshold,
94+
lint_macro_generated_functions: conf.lint_macro_generated_functions,
95+
lint_inside_tests: conf.lint_inside_tests,
9296
}
9397
}
9498
}
@@ -170,16 +174,45 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames {
170174
FnKind::Closure => entire_fn_span,
171175
};
172176

177+
// Don't lint inside tests if configured to not do so.
178+
if !self.lint_inside_tests && is_in_test(cx.tcx, cx.tcx.local_def_id_to_hir_id(local_def_id)) {
179+
return;
180+
}
181+
182+
let mut is_from_expansion = false;
183+
if fn_span.from_expansion() {
184+
// Don't lint functions that are generated by special compiling targets, like `--test`.
185+
if fn_span.is_dummy() && fn_span.source_callsite().is_dummy() {
186+
return;
187+
}
188+
189+
// Don't lint functions generated by macros if configured to not do so.
190+
if !self.lint_macro_generated_functions {
191+
return;
192+
}
193+
194+
is_from_expansion = true;
195+
}
196+
173197
span_lint_and_then(
174198
cx,
175199
LARGE_STACK_FRAMES,
176-
fn_span,
177-
format!("this function may allocate {frame_size} on the stack"),
200+
fn_span.source_callsite(),
201+
if is_from_expansion {
202+
"function generated by this macro may allocate a lot of stack space".to_owned()
203+
} else {
204+
format!("this function may allocate {frame_size} on the stack")
205+
},
178206
|diag| {
207+
if is_from_expansion {
208+
diag.note(format!("this function has a stack frame size of {frame_size}"));
209+
}
179210
// Point out the largest individual contribution to this size, because
180211
// it is the most likely to be unintentionally large.
181-
if let Some((local, size)) = sizes_of_locals().max_by_key(|&(_, size)| size) {
182-
let local_span: Span = local.source_info.span;
212+
else if let Some((local, size)) = sizes_of_locals().max_by_key(|&(_, size)| size)
213+
&& let local_span = local.source_info.span
214+
&& !local_span.from_expansion()
215+
{
183216
let size = Space::Used(size); // pluralizes for us
184217
let ty = local.ty;
185218

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
stack-size-threshold = 0
2+
lint-macro-generated-functions = true
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//@ normalize-stderr-test: "\b10000(08|16|32)\b" -> "100$$PTR"
2+
//@ normalize-stderr-test: "\b2500(060|120)\b" -> "250$$PTR"
3+
4+
#![warn(clippy::large_stack_frames)]
5+
6+
extern crate serde;
7+
8+
use serde::{Deserialize, Serialize};
9+
10+
struct ArrayDefault<const N: usize>([u8; N]);
11+
12+
macro_rules! mac {
13+
($name:ident) => {
14+
fn foo(x: ArrayDefault<1_000_000>) {
15+
let $name = 1;
16+
println!("macro_name called");
17+
}
18+
};
19+
}
20+
21+
mac!(something);
22+
//~^ large_stack_frames
23+
24+
#[derive(Deserialize, Serialize)]
25+
//~^ large_stack_frames
26+
//~| large_stack_frames
27+
//~| large_stack_frames
28+
//~| large_stack_frames
29+
//~| large_stack_frames
30+
//~| large_stack_frames
31+
//~| large_stack_frames
32+
//~| large_stack_frames
33+
34+
struct S {
35+
a: [u128; 31],
36+
}
37+
38+
fn main() {}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
error: function generated by this macro may allocate a lot of stack space
2+
--> tests/ui-toml/large_stack_frames_for_macro_generated_fns/large_stack_frames.rs:21:1
3+
|
4+
LL | mac!(something);
5+
| ^^^^^^^^^^^^^^^
6+
|
7+
= note: this function has a stack frame size of 1000092 bytes
8+
= note: 1000092 bytes is larger than Clippy's configured `stack-size-threshold` of 0
9+
= note: allocating large amounts of stack space can overflow the stack and cause the program to abort
10+
= note: `-D clippy::large-stack-frames` implied by `-D warnings`
11+
= help: to override `-D warnings` add `#[allow(clippy::large_stack_frames)]`
12+
13+
error: function generated by this macro may allocate a lot of stack space
14+
--> tests/ui-toml/large_stack_frames_for_macro_generated_fns/large_stack_frames.rs:24:10
15+
|
16+
LL | #[derive(Deserialize, Serialize)]
17+
| ^^^^^^^^^^^
18+
|
19+
= note: this function has a stack frame size of 57 bytes
20+
= note: 57 bytes is larger than Clippy's configured `stack-size-threshold` of 0
21+
22+
error: function generated by this macro may allocate a lot of stack space
23+
--> tests/ui-toml/large_stack_frames_for_macro_generated_fns/large_stack_frames.rs:24:10
24+
|
25+
LL | #[derive(Deserialize, Serialize)]
26+
| ^^^^^^^^^^^
27+
|
28+
= note: this function has a stack frame size of 10 bytes
29+
= note: 10 bytes is larger than Clippy's configured `stack-size-threshold` of 0
30+
31+
error: function generated by this macro may allocate a lot of stack space
32+
--> tests/ui-toml/large_stack_frames_for_macro_generated_fns/large_stack_frames.rs:24:10
33+
|
34+
LL | #[derive(Deserialize, Serialize)]
35+
| ^^^^^^^^^^^
36+
|
37+
= note: this function has a stack frame size of 19 bytes
38+
= note: 19 bytes is larger than Clippy's configured `stack-size-threshold` of 0
39+
40+
error: function generated by this macro may allocate a lot of stack space
41+
--> tests/ui-toml/large_stack_frames_for_macro_generated_fns/large_stack_frames.rs:24:10
42+
|
43+
LL | #[derive(Deserialize, Serialize)]
44+
| ^^^^^^^^^^^
45+
|
46+
= note: this function has a stack frame size of 35 bytes
47+
= note: 35 bytes is larger than Clippy's configured `stack-size-threshold` of 0
48+
49+
error: function generated by this macro may allocate a lot of stack space
50+
--> tests/ui-toml/large_stack_frames_for_macro_generated_fns/large_stack_frames.rs:24:10
51+
|
52+
LL | #[derive(Deserialize, Serialize)]
53+
| ^^^^^^^^^^^
54+
|
55+
= note: this function has a stack frame size of 57 bytes
56+
= note: 57 bytes is larger than Clippy's configured `stack-size-threshold` of 0
57+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
58+
59+
error: function generated by this macro may allocate a lot of stack space
60+
--> tests/ui-toml/large_stack_frames_for_macro_generated_fns/large_stack_frames.rs:24:10
61+
|
62+
LL | #[derive(Deserialize, Serialize)]
63+
| ^^^^^^^^^^^
64+
|
65+
= note: this function has a stack frame size of 3137 bytes
66+
= note: 3137 bytes is larger than Clippy's configured `stack-size-threshold` of 0
67+
68+
error: function generated by this macro may allocate a lot of stack space
69+
--> tests/ui-toml/large_stack_frames_for_macro_generated_fns/large_stack_frames.rs:24:10
70+
|
71+
LL | #[derive(Deserialize, Serialize)]
72+
| ^^^^^^^^^^^
73+
|
74+
= note: this function has a stack frame size of 4798 bytes
75+
= note: 4798 bytes is larger than Clippy's configured `stack-size-threshold` of 0
76+
77+
error: function generated by this macro may allocate a lot of stack space
78+
--> tests/ui-toml/large_stack_frames_for_macro_generated_fns/large_stack_frames.rs:24:23
79+
|
80+
LL | #[derive(Deserialize, Serialize)]
81+
| ^^^^^^^^^
82+
|
83+
= note: this function has a stack frame size of 170 bytes
84+
= note: 170 bytes is larger than Clippy's configured `stack-size-threshold` of 0
85+
86+
error: aborting due to 9 previous errors
87+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
stack-size-threshold = 0
2+
lint-inside-tests = true
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// This test checks if `clippy::large_stack_frames` is working correctly when encountering functions
2+
// generated by special compiling targets like `--test`.
3+
//@compile-flags: --test
4+
//@check-pass
5+
6+
#![warn(clippy::large_stack_frames)]
7+
8+
#[cfg(test)]
9+
#[allow(clippy::large_stack_frames)]
10+
mod test {
11+
#[test]
12+
fn main_test() {}
13+
}

tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
5050
ignore-interior-mutability
5151
large-error-threshold
5252
lint-commented-code
53+
lint-inside-tests
54+
lint-macro-generated-functions
5355
literal-representation-threshold
5456
matches-for-let-else
5557
max-fn-params-bools
@@ -144,6 +146,8 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
144146
ignore-interior-mutability
145147
large-error-threshold
146148
lint-commented-code
149+
lint-inside-tests
150+
lint-macro-generated-functions
147151
literal-representation-threshold
148152
matches-for-let-else
149153
max-fn-params-bools
@@ -238,6 +242,8 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
238242
ignore-interior-mutability
239243
large-error-threshold
240244
lint-commented-code
245+
lint-inside-tests
246+
lint-macro-generated-functions
241247
literal-representation-threshold
242248
matches-for-let-else
243249
max-fn-params-bools

0 commit comments

Comments
 (0)