Skip to content

Commit 44380ea

Browse files
committed
Lint against iterator functions that panics when N is zero
1 parent 2b6660d commit 44380ea

8 files changed

Lines changed: 110 additions & 6 deletions

File tree

compiler/rustc_const_eval/src/const_eval/machine.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
687687
found: eval_to_int(found)?,
688688
},
689689
NullPointerDereference => NullPointerDereference,
690+
ConstNIsZero => ConstNIsZero,
690691
InvalidEnumConstruction(source) => InvalidEnumConstruction(eval_to_int(source)?),
691692
};
692693
Err(ConstEvalErrKind::AssertFailure(err)).into()

compiler/rustc_middle/src/mir/syntax.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,7 @@ pub enum AssertKind<O> {
10751075
MisalignedPointerDereference { required: O, found: O },
10761076
NullPointerDereference,
10771077
InvalidEnumConstruction(O),
1078+
ConstNIsZero,
10781079
}
10791080

10801081
#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]

compiler/rustc_middle/src/mir/terminator.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ impl<O> AssertKind<O> {
220220
LangItem::PanicGenFnNoneDrop
221221
}
222222

223-
BoundsCheck { .. } | MisalignedPointerDereference { .. } => {
223+
ConstNIsZero | BoundsCheck { .. } | MisalignedPointerDereference { .. } => {
224224
bug!("Unexpected AssertKind")
225225
}
226226
}
@@ -285,6 +285,7 @@ impl<O> AssertKind<O> {
285285
)
286286
}
287287
NullPointerDereference => write!(f, "\"null pointer dereference occurred\""),
288+
ConstNIsZero => write!(f, "\"const parameter `N` is 0\""),
288289
InvalidEnumConstruction(source) => {
289290
write!(f, "\"trying to construct an enum from an invalid value {{}}\", {source:?}")
290291
}
@@ -394,10 +395,10 @@ impl<O> AssertKind<O> {
394395
ResumedAfterDrop(CoroutineKind::Coroutine(_)) => {
395396
msg!("coroutine resumed after async drop")
396397
}
397-
398398
MisalignedPointerDereference { .. } => msg!(
399399
"misaligned pointer dereference: address must be a multiple of {$required} but is {$found}"
400400
),
401+
ConstNIsZero => msg!("const parameter `N` is zero"),
401402
}
402403
}
403404

@@ -432,6 +433,7 @@ impl<O> AssertKind<O> {
432433
ResumedAfterReturn(_)
433434
| ResumedAfterPanic(_)
434435
| NullPointerDereference
436+
| ConstNIsZero
435437
| ResumedAfterDrop(_) => {}
436438
MisalignedPointerDereference { required, found } => {
437439
add!("required", format!("{required:#?}"));

compiler/rustc_middle/src/mir/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ macro_rules! make_mir_visitor {
688688
OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) | InvalidEnumConstruction(op) => {
689689
self.visit_operand(op, location);
690690
}
691-
ResumedAfterReturn(_) | ResumedAfterPanic(_) | NullPointerDereference | ResumedAfterDrop(_) => {
691+
ResumedAfterReturn(_) | ResumedAfterPanic(_) | NullPointerDereference | ConstNIsZero | ResumedAfterDrop(_) => {
692692
// Nothing to visit
693693
}
694694
MisalignedPointerDereference { required, found } => {

compiler/rustc_mir_transform/src/known_panics_lint.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ 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::{self, ConstInt, GenericArgKind, ScalarInt, Ty, TyCtxt, TypeVisitableExt};
2222
use rustc_span::Span;
2323
use tracing::{debug, instrument, trace};
2424

@@ -765,6 +765,22 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
765765
}
766766
// We failed to evaluate the discriminant, fallback to visiting all successors.
767767
}
768+
TerminatorKind::Call { func, args: _, .. } => {
769+
if let Some((def_id, generic_args)) = func.const_fn_def() {
770+
for arg in generic_args {
771+
if let GenericArgKind::Const(ct) = arg.kind()
772+
&& find_attr!(self.tcx, def_id, RustcPanicsWhenNIsZero)
773+
&& let Some(0) = ct.try_to_target_usize(self.tcx)
774+
{
775+
self.report_assert_as_lint(
776+
location,
777+
AssertLintKind::UnconditionalPanic,
778+
AssertKind::<()>::ConstNIsZero,
779+
);
780+
}
781+
}
782+
}
783+
}
768784
// None of these have Operands to const-propagate.
769785
TerminatorKind::Goto { .. }
770786
| TerminatorKind::UnwindResume
@@ -777,7 +793,6 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
777793
| TerminatorKind::CoroutineDrop
778794
| TerminatorKind::FalseEdge { .. }
779795
| TerminatorKind::FalseUnwind { .. }
780-
| TerminatorKind::Call { .. }
781796
| TerminatorKind::InlineAsm { .. } => {}
782797
}
783798

compiler/rustc_public/src/unstable/convert/stable/mir.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,7 @@ impl<'tcx> Stable<'tcx> for mir::AssertMessage<'tcx> {
557557
}
558558
}
559559
AssertKind::NullPointerDereference => crate::mir::AssertMessage::NullPointerDereference,
560+
AssertKind::ConstNIsZero => unreachable!("only used for linting"),
560561
AssertKind::InvalidEnumConstruction(source) => {
561562
crate::mir::AssertMessage::InvalidEnumConstruction(source.stable(tables, cx))
562563
}

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)