Skip to content

Commit 9c1ba16

Browse files
committed
Auto merge of #9920 - naosense:suppress_lint_in_const, r=xFrednet
add `suppress_restriction_lint_in_const` config According to #9808 , add a new lint `suppress_lint_in_const` to report even in const context. BTW, i am not good at naming either, if anyone have a better idea, i am happy to change it. This PR is still in progress, so i keep it draft. - \[x] Followed [lint naming conventions][lint_naming] - \[x] Added passing UI tests (including committed `.stderr` file) - \[x] `cargo test` passes locally - \[x] Executed `cargo dev update_lints` - \[x] Added lint documentation - \[x] Run `cargo dev fmt` changelog: Enhancement: [`indexing_slicing`]: add new config `suppress-restriction-lint-in-const` to enable restriction lints, even if the suggestion might not be applicable r? `@xFrendet`
2 parents cb8df45 + eec5039 commit 9c1ba16

File tree

9 files changed

+221
-21
lines changed

9 files changed

+221
-21
lines changed

clippy_lints/src/indexing_slicing.rs

+32-13
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
//! lint on indexing and slicing operations
22
33
use clippy_utils::consts::{constant, Constant};
4-
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
4+
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
55
use clippy_utils::higher;
66
use rustc_ast::ast::RangeLimits;
77
use rustc_hir::{Expr, ExprKind};
88
use rustc_lint::{LateContext, LateLintPass};
99
use rustc_middle::ty;
10-
use rustc_session::{declare_lint_pass, declare_tool_lint};
10+
use rustc_session::{declare_tool_lint, impl_lint_pass};
1111

1212
declare_clippy_lint! {
1313
/// ### What it does
@@ -82,15 +82,29 @@ declare_clippy_lint! {
8282
"indexing/slicing usage"
8383
}
8484

85-
declare_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]);
85+
impl_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]);
86+
87+
#[derive(Copy, Clone)]
88+
pub struct IndexingSlicing {
89+
suppress_restriction_lint_in_const: bool,
90+
}
91+
92+
impl IndexingSlicing {
93+
pub fn new(suppress_restriction_lint_in_const: bool) -> Self {
94+
Self {
95+
suppress_restriction_lint_in_const,
96+
}
97+
}
98+
}
8699

87100
impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
88101
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
89-
if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
102+
if self.suppress_restriction_lint_in_const && cx.tcx.hir().is_inside_const_context(expr.hir_id) {
90103
return;
91104
}
92105

93106
if let ExprKind::Index(array, index) = &expr.kind {
107+
let note = "the suggestion might not be applicable in constant blocks";
94108
let ty = cx.typeck_results().expr_ty(array).peel_refs();
95109
if let Some(range) = higher::Range::hir(index) {
96110
// Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
@@ -141,7 +155,13 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
141155
(None, None) => return, // [..] is ok.
142156
};
143157

144-
span_lint_and_help(cx, INDEXING_SLICING, expr.span, "slicing may panic", None, help_msg);
158+
span_lint_and_then(cx, INDEXING_SLICING, expr.span, "slicing may panic", |diag| {
159+
diag.help(help_msg);
160+
161+
if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
162+
diag.note(note);
163+
}
164+
});
145165
} else {
146166
// Catchall non-range index, i.e., [n] or [n << m]
147167
if let ty::Array(..) = ty.kind() {
@@ -156,14 +176,13 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
156176
}
157177
}
158178

159-
span_lint_and_help(
160-
cx,
161-
INDEXING_SLICING,
162-
expr.span,
163-
"indexing may panic",
164-
None,
165-
"consider using `.get(n)` or `.get_mut(n)` instead",
166-
);
179+
span_lint_and_then(cx, INDEXING_SLICING, expr.span, "indexing may panic", |diag| {
180+
diag.help("consider using `.get(n)` or `.get_mut(n)` instead");
181+
182+
if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
183+
diag.note(note);
184+
}
185+
});
167186
}
168187
}
169188
}

clippy_lints/src/lib.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
561561
let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
562562
let allow_expect_in_tests = conf.allow_expect_in_tests;
563563
let allow_unwrap_in_tests = conf.allow_unwrap_in_tests;
564+
let suppress_restriction_lint_in_const = conf.suppress_restriction_lint_in_const;
564565
store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv())));
565566
store.register_late_pass(move |_| {
566567
Box::new(methods::Methods::new(
@@ -682,7 +683,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
682683
store.register_late_pass(|_| Box::new(inherent_impl::MultipleInherentImpl));
683684
store.register_late_pass(|_| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd));
684685
store.register_late_pass(|_| Box::new(unwrap::Unwrap));
685-
store.register_late_pass(|_| Box::new(indexing_slicing::IndexingSlicing));
686+
store.register_late_pass(move |_| {
687+
Box::new(indexing_slicing::IndexingSlicing::new(
688+
suppress_restriction_lint_in_const,
689+
))
690+
});
686691
store.register_late_pass(|_| Box::new(non_copy_const::NonCopyConst));
687692
store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
688693
store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone));

clippy_lints/src/utils/conf.rs

+8
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,14 @@ define_Conf! {
406406
///
407407
/// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
408408
(allow_mixed_uninlined_format_args: bool = true),
409+
/// Lint: INDEXING_SLICING
410+
///
411+
/// Whether to suppress a restriction lint in constant code. In same
412+
/// cases the restructured operation might not be unavoidable, as the
413+
/// suggested counterparts are unavailable in constant code. This
414+
/// configuration will cause restriction lints to trigger even
415+
/// if no suggestion can be made.
416+
(suppress_restriction_lint_in_const: bool = false),
409417
}
410418

411419
/// Search for the configuration file.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
suppress-restriction-lint-in-const = true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#![feature(inline_const)]
2+
#![warn(clippy::indexing_slicing)]
3+
// We also check the out_of_bounds_indexing lint here, because it lints similar things and
4+
// we want to avoid false positives.
5+
#![warn(clippy::out_of_bounds_indexing)]
6+
#![allow(unconditional_panic, clippy::no_effect, clippy::unnecessary_operation)]
7+
8+
const ARR: [i32; 2] = [1, 2];
9+
const REF: &i32 = &ARR[idx()]; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
10+
const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
11+
12+
const fn idx() -> usize {
13+
1
14+
}
15+
const fn idx4() -> usize {
16+
4
17+
}
18+
19+
fn main() {
20+
let x = [1, 2, 3, 4];
21+
let index: usize = 1;
22+
x[index];
23+
x[4]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
24+
x[1 << 3]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
25+
26+
x[0]; // Ok, should not produce stderr.
27+
x[3]; // Ok, should not produce stderr.
28+
x[const { idx() }]; // Ok, should not produce stderr.
29+
x[const { idx4() }]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
30+
const { &ARR[idx()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
31+
const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
32+
33+
let y = &x;
34+
y[0]; // Ok, referencing shouldn't affect this lint. See the issue 6021
35+
y[4]; // Ok, rustc will handle references too.
36+
37+
let v = vec![0; 5];
38+
v[0];
39+
v[10];
40+
v[1 << 3];
41+
42+
const N: usize = 15; // Out of bounds
43+
const M: usize = 3; // In bounds
44+
x[N]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
45+
x[M]; // Ok, should not produce stderr.
46+
v[N];
47+
v[M];
48+
}
49+
50+
/// An opaque integer representation
51+
pub struct Integer<'a> {
52+
/// The underlying data
53+
value: &'a [u8],
54+
}
55+
impl<'a> Integer<'a> {
56+
// Check whether `self` holds a negative number or not
57+
pub const fn is_negative(&self) -> bool {
58+
self.value[0] & 0b1000_0000 != 0
59+
}
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
error[E0080]: evaluation of `main::{constant#3}` failed
2+
--> $DIR/test.rs:31:14
3+
|
4+
LL | const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
5+
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
6+
7+
note: erroneous constant used
8+
--> $DIR/test.rs:31:5
9+
|
10+
LL | const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
11+
| ^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error: indexing may panic
14+
--> $DIR/test.rs:22:5
15+
|
16+
LL | x[index];
17+
| ^^^^^^^^
18+
|
19+
= help: consider using `.get(n)` or `.get_mut(n)` instead
20+
= note: `-D clippy::indexing-slicing` implied by `-D warnings`
21+
22+
error: indexing may panic
23+
--> $DIR/test.rs:38:5
24+
|
25+
LL | v[0];
26+
| ^^^^
27+
|
28+
= help: consider using `.get(n)` or `.get_mut(n)` instead
29+
30+
error: indexing may panic
31+
--> $DIR/test.rs:39:5
32+
|
33+
LL | v[10];
34+
| ^^^^^
35+
|
36+
= help: consider using `.get(n)` or `.get_mut(n)` instead
37+
38+
error: indexing may panic
39+
--> $DIR/test.rs:40:5
40+
|
41+
LL | v[1 << 3];
42+
| ^^^^^^^^^
43+
|
44+
= help: consider using `.get(n)` or `.get_mut(n)` instead
45+
46+
error: indexing may panic
47+
--> $DIR/test.rs:46:5
48+
|
49+
LL | v[N];
50+
| ^^^^
51+
|
52+
= help: consider using `.get(n)` or `.get_mut(n)` instead
53+
54+
error: indexing may panic
55+
--> $DIR/test.rs:47:5
56+
|
57+
LL | v[M];
58+
| ^^^^
59+
|
60+
= help: consider using `.get(n)` or `.get_mut(n)` instead
61+
62+
error[E0080]: evaluation of constant value failed
63+
--> $DIR/test.rs:10:24
64+
|
65+
LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
66+
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
67+
68+
error: aborting due to 8 previous errors
69+
70+
For more information about this error, try `rustc --explain E0080`.

tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
3535
pass-by-value-size-limit
3636
single-char-binding-names-threshold
3737
standard-macro-braces
38+
suppress-restriction-lint-in-const
3839
third-party
3940
too-large-for-stack
4041
too-many-arguments-threshold

tests/ui/indexing_slicing_index.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#![allow(unconditional_panic, clippy::no_effect, clippy::unnecessary_operation)]
77

88
const ARR: [i32; 2] = [1, 2];
9-
const REF: &i32 = &ARR[idx()]; // Ok, should not produce stderr.
9+
const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
1010
const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
1111

1212
const fn idx() -> usize {
@@ -27,8 +27,8 @@ fn main() {
2727
x[3]; // Ok, should not produce stderr.
2828
x[const { idx() }]; // Ok, should not produce stderr.
2929
x[const { idx4() }]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
30-
const { &ARR[idx()] }; // Ok, should not produce stderr.
31-
const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.
30+
const { &ARR[idx()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
31+
const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
3232

3333
let y = &x;
3434
y[0]; // Ok, referencing shouldn't affect this lint. See the issue 6021

tests/ui/indexing_slicing_index.stderr

+40-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,32 @@
1+
error: indexing may panic
2+
--> $DIR/indexing_slicing_index.rs:9:20
3+
|
4+
LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
5+
| ^^^^^^^^^^
6+
|
7+
= help: consider using `.get(n)` or `.get_mut(n)` instead
8+
= note: the suggestion might not be applicable in constant blocks
9+
= note: `-D clippy::indexing-slicing` implied by `-D warnings`
10+
11+
error: indexing may panic
12+
--> $DIR/indexing_slicing_index.rs:10:24
13+
|
14+
LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
15+
| ^^^^^^^^^^^
16+
|
17+
= help: consider using `.get(n)` or `.get_mut(n)` instead
18+
= note: the suggestion might not be applicable in constant blocks
19+
120
error[E0080]: evaluation of `main::{constant#3}` failed
221
--> $DIR/indexing_slicing_index.rs:31:14
322
|
4-
LL | const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.
23+
LL | const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
524
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
625

726
note: erroneous constant used
827
--> $DIR/indexing_slicing_index.rs:31:5
928
|
10-
LL | const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.
29+
LL | const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
1130
| ^^^^^^^^^^^^^^^^^^^^^^
1231

1332
error: indexing may panic
@@ -17,7 +36,24 @@ LL | x[index];
1736
| ^^^^^^^^
1837
|
1938
= help: consider using `.get(n)` or `.get_mut(n)` instead
20-
= note: `-D clippy::indexing-slicing` implied by `-D warnings`
39+
40+
error: indexing may panic
41+
--> $DIR/indexing_slicing_index.rs:30:14
42+
|
43+
LL | const { &ARR[idx()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
44+
| ^^^^^^^^^^
45+
|
46+
= help: consider using `.get(n)` or `.get_mut(n)` instead
47+
= note: the suggestion might not be applicable in constant blocks
48+
49+
error: indexing may panic
50+
--> $DIR/indexing_slicing_index.rs:31:14
51+
|
52+
LL | const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
53+
| ^^^^^^^^^^^
54+
|
55+
= help: consider using `.get(n)` or `.get_mut(n)` instead
56+
= note: the suggestion might not be applicable in constant blocks
2157

2258
error: indexing may panic
2359
--> $DIR/indexing_slicing_index.rs:38:5
@@ -65,6 +101,6 @@ error[E0080]: evaluation of constant value failed
65101
LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
66102
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
67103

68-
error: aborting due to 8 previous errors
104+
error: aborting due to 12 previous errors
69105

70106
For more information about this error, try `rustc --explain E0080`.

0 commit comments

Comments
 (0)