Skip to content

Commit c4355b4

Browse files
committed
Lint against iterator functions that panics when N is zero
1 parent 2868b2c commit c4355b4

File tree

4 files changed

+126
-4
lines changed

4 files changed

+126
-4
lines changed

compiler/rustc_mir_transform/src/errors.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,13 @@ impl AssertLintKind {
159159
}
160160
}
161161

162+
#[derive(Diagnostic)]
163+
#[diag("this operation will panic at runtime")]
164+
pub(crate) struct ConstNIsZero {
165+
#[label("const parameter `N` is zero")]
166+
pub const_param: Span,
167+
}
168+
162169
#[derive(Diagnostic)]
163170
#[diag("call to inline assembly that may unwind")]
164171
pub(crate) struct AsmUnwindCall {

compiler/rustc_mir_transform/src/known_panics_lint.rs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,22 @@ use rustc_const_eval::interpret::{
1010
ImmTy, InterpCx, InterpResult, Projectable, Scalar, format_interp_error, interp_ok,
1111
};
1212
use rustc_data_structures::fx::FxHashSet;
13-
use rustc_hir::HirId;
1413
use rustc_hir::def::DefKind;
14+
use rustc_hir::{HirId, find_attr};
1515
use rustc_index::IndexVec;
1616
use rustc_index::bit_set::DenseBitSet;
1717
use rustc_middle::bug;
1818
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
1919
use rustc_middle::mir::*;
2020
use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
21-
use rustc_middle::ty::{self, ConstInt, ScalarInt, Ty, TyCtxt, TypeVisitableExt};
21+
use rustc_middle::ty::{
22+
self, ConstInt, GenericArgKind, GenericParamDefKind, ScalarInt, Ty, TyCtxt, TypeVisitableExt,
23+
};
24+
use rustc_session::lint::builtin::UNCONDITIONAL_PANIC;
2225
use rustc_span::Span;
2326
use tracing::{debug, instrument, trace};
2427

25-
use crate::errors::{AssertLint, AssertLintKind};
28+
use crate::errors::{AssertLint, AssertLintKind, ConstNIsZero};
2629

2730
pub(super) struct KnownPanicsLint;
2831

@@ -765,6 +768,35 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
765768
}
766769
// We failed to evaluate the discriminant, fallback to visiting all successors.
767770
}
771+
TerminatorKind::Call { func, args: _, .. } => {
772+
if let Some((def_id, generic_args)) = func.const_fn_def() {
773+
for (index, arg) in generic_args.iter().enumerate() {
774+
if let GenericArgKind::Const(ct) = arg.kind() {
775+
let generics = self.tcx.generics_of(def_id);
776+
let param_def = generics.param_at(index, self.tcx);
777+
778+
if let GenericParamDefKind::Const { .. } = param_def.kind
779+
&& find_attr!(self.tcx, param_def.def_id, RustcPanicsWhenZero)
780+
&& let Some(0) = ct.try_to_target_usize(self.tcx)
781+
{
782+
// We managed to figure-out that the value of a
783+
// `#[rustc_panics_when_zero]` const-generic parameter is zero.
784+
//
785+
// Let's report it as an unconditional panic.
786+
let source_info = self.body.source_info(location);
787+
if let Some(lint_root) = self.lint_root(*source_info) {
788+
self.tcx.emit_node_span_lint(
789+
UNCONDITIONAL_PANIC,
790+
lint_root,
791+
source_info.span,
792+
ConstNIsZero { const_param: source_info.span },
793+
);
794+
}
795+
}
796+
}
797+
}
798+
}
799+
}
768800
// None of these have Operands to const-propagate.
769801
TerminatorKind::Goto { .. }
770802
| TerminatorKind::UnwindResume
@@ -777,7 +809,6 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
777809
| TerminatorKind::CoroutineDrop
778810
| TerminatorKind::FalseEdge { .. }
779811
| TerminatorKind::FalseUnwind { .. }
780-
| TerminatorKind::Call { .. }
781812
| TerminatorKind::InlineAsm { .. } => {}
782813
}
783814

tests/ui/lint/const-n-is-zero.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Test that core functions annotated with `#[rustc_panics_when_n_is_zero]` lint when `N` is zero
2+
3+
//@ build-fail
4+
5+
const ZERO: usize = 0;
6+
const ONE: usize = 1;
7+
8+
fn main() {
9+
let s = [1, 2, 3, 4];
10+
11+
let _ = s.array_windows::<0>();
12+
//~^ ERROR this operation will panic at runtime
13+
//~| NOTE `#[deny(unconditional_panic)]` on by default
14+
//~| NOTE const parameter `N` is zero
15+
16+
let _ = s.as_chunks::<{ 0 }>();
17+
//~^ ERROR this operation will panic at runtime
18+
//~| NOTE const parameter `N` is zero
19+
//
20+
let _ = s.as_rchunks::<{ 1 - 1 }>();
21+
//~^ ERROR this operation will panic at runtime
22+
//~| NOTE const parameter `N` is zero
23+
24+
let mut m = [1, 2, 3, 4];
25+
26+
let _ = m.as_chunks_mut::<ZERO>();
27+
//~^ ERROR this operation will panic at runtime
28+
//~| NOTE const parameter `N` is zero
29+
30+
let _ = m.as_rchunks_mut::<{ if ZERO == 0 { 0 } else { 1 } }>();
31+
//~^ ERROR this operation will panic at runtime
32+
//~| NOTE const parameter `N` is zero
33+
34+
let _ = s.array_windows().any(|[]| true);
35+
//~^ ERROR this operation will panic at runtime
36+
//~| NOTE const parameter `N` is zero
37+
38+
// Shouldn't lint
39+
let _ = s.array_windows::<2>();
40+
let _ = s.as_chunks::<1>();
41+
let _ = m.as_chunks_mut::<ONE>();
42+
let _ = m.as_rchunks::<{ 1 + 1 }>();
43+
let _ = m.as_rchunks_mut::<{ if ZERO == 1 { 0 } else { 5 } }>();
44+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
error: this operation will panic at runtime
2+
--> $DIR/const-n-is-zero.rs:11:13
3+
|
4+
LL | let _ = s.array_windows::<0>();
5+
| ^^^^^^^^^^^^^^^^^^^^^^ const parameter `N` is zero
6+
|
7+
= note: `#[deny(unconditional_panic)]` on by default
8+
9+
error: this operation will panic at runtime
10+
--> $DIR/const-n-is-zero.rs:16:13
11+
|
12+
LL | let _ = s.as_chunks::<{ 0 }>();
13+
| ^^^^^^^^^^^^^^^^^^^^^^ const parameter `N` is zero
14+
15+
error: this operation will panic at runtime
16+
--> $DIR/const-n-is-zero.rs:20:13
17+
|
18+
LL | let _ = s.as_rchunks::<{ 1 - 1 }>();
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ const parameter `N` is zero
20+
21+
error: this operation will panic at runtime
22+
--> $DIR/const-n-is-zero.rs:26:13
23+
|
24+
LL | let _ = m.as_chunks_mut::<ZERO>();
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ const parameter `N` is zero
26+
27+
error: this operation will panic at runtime
28+
--> $DIR/const-n-is-zero.rs:30:13
29+
|
30+
LL | let _ = m.as_rchunks_mut::<{ if ZERO == 0 { 0 } else { 1 } }>();
31+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ const parameter `N` is zero
32+
33+
error: this operation will panic at runtime
34+
--> $DIR/const-n-is-zero.rs:34:13
35+
|
36+
LL | let _ = s.array_windows().any(|[]| true);
37+
| ^^^^^^^^^^^^^^^^^ const parameter `N` is zero
38+
39+
error: aborting due to 6 previous errors
40+

0 commit comments

Comments
 (0)