From 5a33f531cd87988e95a8e811d71b653a7ff9ffca Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Tue, 5 Jan 2021 13:54:28 -0800 Subject: [PATCH] check that first arg to `panic!()` in const is `&str` --- .../src/transform/check_consts/ops.rs | 12 +++++++++ .../src/transform/check_consts/validation.rs | 12 +++++++-- .../consts/issue-66693-panic-in-array-len.rs | 17 ++++++++++++ .../issue-66693-panic-in-array-len.stderr | 19 ++++++++++++++ src/test/ui/consts/issue-66693.rs | 24 +++++++++++++++++ src/test/ui/consts/issue-66693.stderr | 26 +++++++++++++++++++ src/test/ui/consts/issue-76064.rs | 4 ++- src/test/ui/consts/issue-76064.stderr | 6 ++--- 8 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/consts/issue-66693-panic-in-array-len.rs create mode 100644 src/test/ui/consts/issue-66693-panic-in-array-len.stderr create mode 100644 src/test/ui/consts/issue-66693.rs create mode 100644 src/test/ui/consts/issue-66693.stderr diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 9e90a7519cf..134b6d6fe07 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -360,6 +360,18 @@ impl NonConstOp for Panic { } } +/// A call to a `panic()` lang item where the first argument is _not_ a `&str`. +#[derive(Debug)] +pub struct PanicNonStr; +impl NonConstOp for PanicNonStr { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + ccx.tcx.sess.struct_span_err( + span, + "argument to `panic!()` in a const context must have type `&str`", + ) + } +} + #[derive(Debug)] pub struct RawPtrComparison; impl NonConstOp for RawPtrComparison { diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index d1c07d1051d..fea5dd3554f 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -796,7 +796,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { self.super_terminator(terminator, location); match &terminator.kind { - TerminatorKind::Call { func, .. } => { + TerminatorKind::Call { func, args, .. } => { let ConstCx { tcx, body, param_env, .. } = *self.ccx; let caller = self.def_id().to_def_id(); @@ -857,9 +857,17 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } // At this point, we are calling a function, `callee`, whose `DefId` is known... - if is_lang_panic_fn(tcx, callee) { self.check_op(ops::Panic); + + // const-eval of the `begin_panic` fn assumes the argument is `&str` + if Some(callee) == tcx.lang_items().begin_panic_fn() { + match args[0].ty(&self.ccx.body.local_decls, tcx).kind() { + ty::Ref(_, ty, _) if ty.is_str() => (), + _ => self.check_op(ops::PanicNonStr), + } + } + return; } diff --git a/src/test/ui/consts/issue-66693-panic-in-array-len.rs b/src/test/ui/consts/issue-66693-panic-in-array-len.rs new file mode 100644 index 00000000000..718a19067a6 --- /dev/null +++ b/src/test/ui/consts/issue-66693-panic-in-array-len.rs @@ -0,0 +1,17 @@ +// This is a separate test from `issue-66693.rs` because array lengths are evaluated +// in a separate stage before `const`s and `statics` and so the error below is hit and +// the compiler exits before generating errors for the others. + +#![feature(const_panic)] + +fn main() { + let _ = [0i32; panic!(2f32)]; + //~^ ERROR: argument to `panic!()` in a const context must have type `&str` + + // ensure that conforming panics are handled correctly + let _ = [false; panic!()]; + //~^ ERROR: evaluation of constant value failed + + // typechecking halts before getting to this one + let _ = ['a', panic!("panic in array len")]; +} diff --git a/src/test/ui/consts/issue-66693-panic-in-array-len.stderr b/src/test/ui/consts/issue-66693-panic-in-array-len.stderr new file mode 100644 index 00000000000..e0ca9dfde0b --- /dev/null +++ b/src/test/ui/consts/issue-66693-panic-in-array-len.stderr @@ -0,0 +1,19 @@ +error: argument to `panic!()` in a const context must have type `&str` + --> $DIR/issue-66693-panic-in-array-len.rs:8:20 + | +LL | let _ = [0i32; panic!(2f32)]; + | ^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/issue-66693-panic-in-array-len.rs:12:21 + | +LL | let _ = [false; panic!()]; + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-66693-panic-in-array-len.rs:12:21 + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/issue-66693.rs b/src/test/ui/consts/issue-66693.rs new file mode 100644 index 00000000000..77fe4417d5b --- /dev/null +++ b/src/test/ui/consts/issue-66693.rs @@ -0,0 +1,24 @@ +// Tests that the compiler does not ICE when const-evaluating a `panic!()` invocation with a +// non-`&str` argument. + +#![feature(const_panic)] + +const _: () = panic!(1); +//~^ ERROR: argument to `panic!()` in a const context must have type `&str` + +static _FOO: () = panic!(true); +//~^ ERROR: argument to `panic!()` in a const context must have type `&str` + +const fn _foo() { + panic!(&1); //~ ERROR: argument to `panic!()` in a const context must have type `&str` +} + +// ensure that conforming panics don't cause an error +const _: () = panic!(); +static _BAR: () = panic!("panic in static"); + +const fn _bar() { + panic!("panic in const fn"); +} + +fn main() {} diff --git a/src/test/ui/consts/issue-66693.stderr b/src/test/ui/consts/issue-66693.stderr new file mode 100644 index 00000000000..6bbde057ead --- /dev/null +++ b/src/test/ui/consts/issue-66693.stderr @@ -0,0 +1,26 @@ +error: argument to `panic!()` in a const context must have type `&str` + --> $DIR/issue-66693.rs:13:5 + | +LL | panic!(&1); + | ^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: argument to `panic!()` in a const context must have type `&str` + --> $DIR/issue-66693.rs:6:15 + | +LL | const _: () = panic!(1); + | ^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: argument to `panic!()` in a const context must have type `&str` + --> $DIR/issue-66693.rs:9:19 + | +LL | static _FOO: () = panic!(true); + | ^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/consts/issue-76064.rs b/src/test/ui/consts/issue-76064.rs index 2da764b47c0..d511f75df81 100644 --- a/src/test/ui/consts/issue-76064.rs +++ b/src/test/ui/consts/issue-76064.rs @@ -1,3 +1,5 @@ -struct Bug([u8; panic!(1)]); //~ ERROR panicking in constants is unstable +// Note: non-`&str` panic arguments gained a separate error in PR #80734 +// which is why this doesn't match the issue +struct Bug([u8; panic!("panic")]); //~ ERROR panicking in constants is unstable fn main() {} diff --git a/src/test/ui/consts/issue-76064.stderr b/src/test/ui/consts/issue-76064.stderr index f939ff33975..9bda1b7570d 100644 --- a/src/test/ui/consts/issue-76064.stderr +++ b/src/test/ui/consts/issue-76064.stderr @@ -1,8 +1,8 @@ error[E0658]: panicking in constants is unstable - --> $DIR/issue-76064.rs:1:17 + --> $DIR/issue-76064.rs:3:17 | -LL | struct Bug([u8; panic!(1)]); - | ^^^^^^^^^ +LL | struct Bug([u8; panic!("panic")]); + | ^^^^^^^^^^^^^^^ | = note: see issue #51999 for more information = help: add `#![feature(const_panic)]` to the crate attributes to enable