From 507381ed0367f27e8804a1da33f8565c96a260ce Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 13 Oct 2018 23:38:31 +0200 Subject: [PATCH 1/5] Fix ICE and report a human readable error --- src/librustc/ty/cast.rs | 2 ++ src/librustc_mir/transform/qualify_min_const_fn.rs | 13 ++++++++++--- .../ui/consts/min_const_fn/bad_const_fn_body_ice.rs | 5 +++++ .../min_const_fn/bad_const_fn_body_ice.stderr | 10 ++++++++++ 4 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs create mode 100644 src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr diff --git a/src/librustc/ty/cast.rs b/src/librustc/ty/cast.rs index c0861abb774de..ab82f28c8bff4 100644 --- a/src/librustc/ty/cast.rs +++ b/src/librustc/ty/cast.rs @@ -58,6 +58,8 @@ pub enum CastKind { } impl<'tcx> CastTy<'tcx> { + /// Returns `Some` for integral/pointer casts. + /// casts like unsizing casts will return `None` pub fn from_ty(t: Ty<'tcx>) -> Option> { match t.sty { ty::Bool => Some(CastTy::Int(IntTy::Bool)), diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index aa559c96ec668..edcae4648b72c 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -148,7 +148,7 @@ fn check_rvalue( Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) => { check_place(tcx, mir, place, span, PlaceMode::Read) } - Rvalue::Cast(_, operand, cast_ty) => { + Rvalue::Cast(CastKind::Misc, operand, cast_ty) => { use rustc::ty::cast::CastTy; let cast_in = CastTy::from_ty(operand.ty(mir, tcx)).expect("bad input type for cast"); let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); @@ -163,6 +163,10 @@ fn check_rvalue( _ => check_operand(tcx, mir, operand, span), } } + Rvalue::Cast(_, _, _) => Err(( + span, + "only int casts are allowed in const fn".into(), + )), // binops are fine on integers Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { check_operand(tcx, mir, lhs, span)?; @@ -177,8 +181,11 @@ fn check_rvalue( )) } } - // checked by regular const fn checks - Rvalue::NullaryOp(..) => Ok(()), + Rvalue::NullaryOp(NullOp::SizeOf, _) => Ok(()), + Rvalue::NullaryOp(NullOp::Box, _) => Err(( + span, + "heap allocations are not allowed in const fn".into(), + )), Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(mir, tcx); if ty.is_integral() || ty.is_bool() { diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs new file mode 100644 index 0000000000000..3e42cb8c1b074 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs @@ -0,0 +1,5 @@ +const fn foo(a: i32) -> Vec { + vec![1, 2, 3] //~ ERROR heap allocations are not allowed in const fn +} + +fn main() {} diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr new file mode 100644 index 0000000000000..f6b704370b6f2 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr @@ -0,0 +1,10 @@ +error: heap allocations are not allowed in const fn + --> $DIR/bad_const_fn_body_ice.rs:2:5 + | +LL | vec![1, 2, 3] //~ ERROR heap allocations are not allowed in const fn + | ^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to previous error + From 34052047cf7cc30ccc8fbd947db56822d3d71423 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 15 Oct 2018 19:58:21 +0200 Subject: [PATCH 2/5] Explain all casts in detail --- src/librustc_mir/transform/qualify_min_const_fn.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index edcae4648b72c..c9d48f5f6adb2 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -163,9 +163,18 @@ fn check_rvalue( _ => check_operand(tcx, mir, operand, span), } } - Rvalue::Cast(_, _, _) => Err(( + Rvalue::Cast(CastKind::UnsafeFnPointer, _, _) | + Rvalue::Cast(CastKind::ReifyFnPointer, _, _) => Err(( span, - "only int casts are allowed in const fn".into(), + "function pointer casts are not allowed in const fn".into(), + )), + Rvalue::Cast(CastKind::ClosureFnPointer, _, _) => Err(( + span, + "closures are not allowed in const fn".into(), + )), + Rvalue::Cast(CastKind::Unsize, _, _) => Err(( + span, + "unsizing casts are not allowed in const fn".into(), )), // binops are fine on integers Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { From 2456f330d508b223d8cfcada8652ad37b647996a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 15 Oct 2018 20:10:16 +0200 Subject: [PATCH 3/5] Try to trigger some error cases --- .../ui/consts/min_const_fn/cast_errors.rs | 14 ++++++++ .../ui/consts/min_const_fn/cast_errors.stderr | 32 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 src/test/ui/consts/min_const_fn/cast_errors.rs create mode 100644 src/test/ui/consts/min_const_fn/cast_errors.stderr diff --git a/src/test/ui/consts/min_const_fn/cast_errors.rs b/src/test/ui/consts/min_const_fn/cast_errors.rs new file mode 100644 index 0000000000000..36827b1b6b0e2 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/cast_errors.rs @@ -0,0 +1,14 @@ +fn main() {} + +const fn unsize(x: &[u8; 3]) -> &[u8] { x } +//~^ ERROR unsizing casts are not allowed in const fn +const fn closure() -> fn() { || {} } +//~^ ERROR function pointers in const fn are unstable +const fn closure2() { + (|| {}) as fn(); +//~^ ERROR function pointers in const fn are unstable +} +const fn reify(f: fn()) -> unsafe fn() { f } +//~^ ERROR function pointers in const fn are unstable +const fn reify2() { main as unsafe fn(); } +//~^ ERROR function pointers in const fn are unstable \ No newline at end of file diff --git a/src/test/ui/consts/min_const_fn/cast_errors.stderr b/src/test/ui/consts/min_const_fn/cast_errors.stderr new file mode 100644 index 0000000000000..ba980b7aacb6c --- /dev/null +++ b/src/test/ui/consts/min_const_fn/cast_errors.stderr @@ -0,0 +1,32 @@ +error: unsizing casts are not allowed in const fn + --> $DIR/cast_errors.rs:3:41 + | +LL | const fn unsize(x: &[u8; 3]) -> &[u8] { x } + | ^ + +error: function pointers in const fn are unstable + --> $DIR/cast_errors.rs:5:23 + | +LL | const fn closure() -> fn() { || {} } + | ^^^^ + +error: function pointers in const fn are unstable + --> $DIR/cast_errors.rs:8:5 + | +LL | (|| {}) as fn(); + | ^^^^^^^^^^^^^^^ + +error: function pointers in const fn are unstable + --> $DIR/cast_errors.rs:11:28 + | +LL | const fn reify(f: fn()) -> unsafe fn() { f } + | ^^^^^^^^^^^ + +error: function pointers in const fn are unstable + --> $DIR/cast_errors.rs:13:21 + | +LL | const fn reify2() { main as unsafe fn(); } + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + From 007390c21cc5e5e8705d455d20fba1df13bd7362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20S=CC=B6c=CC=B6h=CC=B6n=CC=B6e=CC=B6i=CC=B6d=CC=B6?= =?UTF-8?q?e=CC=B6r=20Scherer?= Date: Mon, 15 Oct 2018 20:30:11 +0200 Subject: [PATCH 4/5] Add trailing newline to satisfy tidy --- src/test/ui/consts/min_const_fn/cast_errors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/consts/min_const_fn/cast_errors.rs b/src/test/ui/consts/min_const_fn/cast_errors.rs index 36827b1b6b0e2..8648cd35387ce 100644 --- a/src/test/ui/consts/min_const_fn/cast_errors.rs +++ b/src/test/ui/consts/min_const_fn/cast_errors.rs @@ -11,4 +11,4 @@ const fn closure2() { const fn reify(f: fn()) -> unsafe fn() { f } //~^ ERROR function pointers in const fn are unstable const fn reify2() { main as unsafe fn(); } -//~^ ERROR function pointers in const fn are unstable \ No newline at end of file +//~^ ERROR function pointers in const fn are unstable From 38f3ad41c0bbf6ed7c389a070afb60a465b3afe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20S=CC=B6c=CC=B6h=CC=B6n=CC=B6e=CC=B6i=CC=B6d=CC=B6?= =?UTF-8?q?e=CC=B6r=20Scherer?= Date: Wed, 17 Oct 2018 09:04:10 +0200 Subject: [PATCH 5/5] Squash closure cast error into fn ptr cast error --- src/librustc_mir/transform/qualify_min_const_fn.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index c9d48f5f6adb2..52c557b83d591 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -164,14 +164,11 @@ fn check_rvalue( } } Rvalue::Cast(CastKind::UnsafeFnPointer, _, _) | + Rvalue::Cast(CastKind::ClosureFnPointer, _, _) | Rvalue::Cast(CastKind::ReifyFnPointer, _, _) => Err(( span, "function pointer casts are not allowed in const fn".into(), )), - Rvalue::Cast(CastKind::ClosureFnPointer, _, _) => Err(( - span, - "closures are not allowed in const fn".into(), - )), Rvalue::Cast(CastKind::Unsize, _, _) => Err(( span, "unsizing casts are not allowed in const fn".into(),