From 4497ff37627d860690613249a31cf3ee4c4195ef Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 5 Nov 2018 18:06:26 +0100 Subject: [PATCH] Emit feature gate suggestion --- src/librustc/ich/impls_mir.rs | 3 +- src/librustc/mir/mod.rs | 8 +- src/librustc_mir/transform/check_unsafety.rs | 74 +++++++++++++------ .../min_const_fn/min_const_fn_unsafe.rs | 6 +- .../min_const_fn/min_const_fn_unsafe.stderr | 24 +++--- 5 files changed, 75 insertions(+), 40 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index d98bb82aaba..3b9c8ae2d3c 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -46,7 +46,8 @@ impl_stable_hash_for!(enum mir::UnsafetyViolationKind { General, - MinConstFn, + GeneralAndConstFn, + GatedConstFnCall, ExternStatic(lint_node_id), BorrowPacked(lint_node_id), }); diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 549e13bad64..09b344cd38d 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2770,9 +2770,11 @@ pub fn dominates(&self, other: Location, dominators: &Dominators) -> #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum UnsafetyViolationKind { General, - /// Right now function calls to `const unsafe fn` are the only permitted unsafe operation in - /// const fn. Also, even `const unsafe fn` need an `unsafe` block to do the allowed operations - MinConstFn, + /// Right now function calls to `const unsafe fn` are only permitted behind a feature gate + /// Also, even `const unsafe fn` need an `unsafe` block to do the allowed operations. + GatedConstFnCall, + /// Permitted in const fn and regular fns + GeneralAndConstFn, ExternStatic(ast::NodeId), BorrowPacked(ast::NodeId), } diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 671ca355dbf..25dbd160d19 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -23,6 +23,7 @@ use syntax::ast; use syntax::symbol::Symbol; +use syntax::feature_gate::{emit_feature_err, GateIssue}; use std::ops::Bound; @@ -96,7 +97,7 @@ fn visit_terminator(&mut self, if let hir::Unsafety::Unsafe = sig.unsafety() { self.require_unsafe("call to unsafe function", "consult the function's documentation for information on how to avoid \ - undefined behavior", UnsafetyViolationKind::MinConstFn) + undefined behavior", UnsafetyViolationKind::GatedConstFnCall) } } } @@ -146,7 +147,7 @@ fn visit_rvalue(&mut self, "initializing type with `rustc_layout_scalar_valid_range` attr", "initializing a layout restricted type's field with a value outside \ the valid range is undefined behavior", - UnsafetyViolationKind::MinConstFn, + UnsafetyViolationKind::GeneralAndConstFn, ), } } @@ -319,12 +320,21 @@ fn register_violations(&mut self, (Safety::Safe, _) => { for violation in violations { let mut violation = violation.clone(); - if self.min_const_fn { - // overwrite unsafety violation in const fn with a single hard error kind - violation.kind = UnsafetyViolationKind::MinConstFn; - } else if let UnsafetyViolationKind::MinConstFn = violation.kind { - // outside of const fns we treat `MinConstFn` and `General` the same - violation.kind = UnsafetyViolationKind::General; + match violation.kind { + UnsafetyViolationKind::GeneralAndConstFn | + UnsafetyViolationKind::General => {}, + UnsafetyViolationKind::BorrowPacked(_) | + UnsafetyViolationKind::ExternStatic(_) => if self.min_const_fn { + // const fns don't need to be backwards compatible and can + // emit these violations as a hard error instead of a backwards + // compat lint + violation.kind = UnsafetyViolationKind::General; + }, + UnsafetyViolationKind::GatedConstFnCall => { + // safe code can't call unsafe const fns, this `UnsafetyViolationKind` + // is only relevant for `Safety::ExplicitUnsafe` in `unsafe const fn`s + violation.kind = UnsafetyViolationKind::General; + } } if !self.violations.contains(&violation) { self.violations.push(violation) @@ -344,13 +354,24 @@ fn register_violations(&mut self, for violation in violations { match violation.kind { // these are allowed - UnsafetyViolationKind::MinConstFn + UnsafetyViolationKind::GatedConstFnCall => { // if `#![feature(min_const_unsafe_fn)]` is active - if self.tcx.sess.features_untracked().min_const_unsafe_fn => {}, - _ => { + if !self.tcx.sess.features_untracked().min_const_unsafe_fn { + if !self.violations.contains(&violation) { + self.violations.push(violation.clone()) + } + } + } + // these unsafe things are stable in const fn + UnsafetyViolationKind::GeneralAndConstFn => {}, + UnsafetyViolationKind::General | + UnsafetyViolationKind::BorrowPacked(_) | + UnsafetyViolationKind::ExternStatic(_) => { let mut violation = violation.clone(); - // overwrite unsafety violation in const fn with a hard error - violation.kind = UnsafetyViolationKind::MinConstFn; + // const fns don't need to be backwards compatible and can + // emit these violations as a hard error instead of a backwards + // compat lint + violation.kind = UnsafetyViolationKind::General; if !self.violations.contains(&violation) { self.violations.push(violation) } @@ -400,7 +421,7 @@ fn check_mut_borrowing_layout_constrained_field( source_info, description: Symbol::intern(description).as_interned_str(), details: Symbol::intern(details).as_interned_str(), - kind: UnsafetyViolationKind::MinConstFn, + kind: UnsafetyViolationKind::GeneralAndConstFn, }], &[]); } }, @@ -592,6 +613,16 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { } in violations.iter() { // Report an error. match kind { + UnsafetyViolationKind::General if tcx.is_min_const_fn(def_id) => { + tcx.sess.struct_span_err( + source_info.span, + &format!("{} is unsafe and unsafe operations \ + are not allowed in const fn", description)) + .span_label(source_info.span, &description.as_str()[..]) + .note(&details.as_str()[..]) + .emit(); + } + UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => { struct_span_err!( tcx.sess, source_info.span, E0133, @@ -600,14 +631,15 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { .note(&details.as_str()[..]) .emit(); } - UnsafetyViolationKind::MinConstFn => { - tcx.sess.struct_span_err( + UnsafetyViolationKind::GatedConstFnCall => { + emit_feature_err( + &tcx.sess.parse_sess, + "min_const_unsafe_fn", source_info.span, - &format!("{} is unsafe and unsafe operations \ - are not allowed in const fn", description)) - .span_label(source_info.span, &description.as_str()[..]) - .note(&details.as_str()[..]) - .emit(); + GateIssue::Language, + "calls to `const unsafe fn` in const fns are unstable", + ); + } UnsafetyViolationKind::ExternStatic(lint_node_id) => { tcx.lint_node_note(SAFE_EXTERN_STATICS, diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs index 7a84992e14b..02a357551df 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs @@ -18,13 +18,13 @@ const fn no_unsafe() { unsafe {} } // not ok const fn foo8() -> i32 { - unsafe { foo4() } //~ ERROR unsafe operations are not allowed in const fn + unsafe { foo4() } //~ ERROR calls to `const unsafe fn` in const fns are unstable } const fn foo9() -> *const String { - unsafe { foo5::() } //~ ERROR unsafe operations are not allowed in const fn + unsafe { foo5::() } //~ ERROR calls to `const unsafe fn` in const fns are unstable } const fn foo10() -> *const Vec> { - unsafe { foo6::>>() } //~ ERROR not allowed in const fn + unsafe { foo6::>>() } //~ ERROR calls to `const unsafe fn` in const fns } const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn //~^ dereferencing raw pointers in constant functions diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr index 17cba8569c1..0b8ff4717c1 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr @@ -14,29 +14,29 @@ LL | Foo { x: () }.y //~ ERROR not allowed in const fn | = help: add #![feature(const_fn_union)] to the crate attributes to enable -error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn +error[E0658]: calls to `const unsafe fn` in const fns are unstable (see issue #55607) --> $DIR/min_const_fn_unsafe.rs:21:14 | -LL | unsafe { foo4() } //~ ERROR unsafe operations are not allowed in const fn - | ^^^^^^ call to unsafe function +LL | unsafe { foo4() } //~ ERROR calls to `const unsafe fn` in const fns are unstable + | ^^^^^^ | - = note: consult the function's documentation for information on how to avoid undefined behavior + = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable -error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn +error[E0658]: calls to `const unsafe fn` in const fns are unstable (see issue #55607) --> $DIR/min_const_fn_unsafe.rs:24:14 | -LL | unsafe { foo5::() } //~ ERROR unsafe operations are not allowed in const fn - | ^^^^^^^^^^^^^^^^ call to unsafe function +LL | unsafe { foo5::() } //~ ERROR calls to `const unsafe fn` in const fns are unstable + | ^^^^^^^^^^^^^^^^ | - = note: consult the function's documentation for information on how to avoid undefined behavior + = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable -error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn +error[E0658]: calls to `const unsafe fn` in const fns are unstable (see issue #55607) --> $DIR/min_const_fn_unsafe.rs:27:14 | -LL | unsafe { foo6::>>() } //~ ERROR not allowed in const fn - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function +LL | unsafe { foo6::>>() } //~ ERROR calls to `const unsafe fn` in const fns + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: consult the function's documentation for information on how to avoid undefined behavior + = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn --> $DIR/min_const_fn_unsafe.rs:29:51 -- 2.44.0