From f4115765c5ad16789e9ccdd49dca1a56d47f2b3f Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 1 Dec 2018 14:09:30 +0100 Subject: [PATCH] Intrinsic checks are just needed for `qualify_min_const_fn` --- src/librustc/ty/constness.rs | 15 +------ src/librustc_mir/build/mod.rs | 2 +- src/librustc_mir/transform/check_unsafety.rs | 18 ++++++--- .../transform/qualify_min_const_fn.rs | 40 ++++++++++++++----- .../min_const_fn/min_const_fn_unsafe.stderr | 2 + .../min_const_fn_unsafe_feature_gate.stderr | 6 +++ 6 files changed, 53 insertions(+), 30 deletions(-) diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index d86170b24f23..bc0616739953 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -5,7 +5,6 @@ use ty::TyCtxt; use syntax_pos::symbol::Symbol; use hir::map::blocks::FnLikeNode; use syntax::attr; -use rustc_target::spec::abi; impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { /// Whether the `def_id` counts as const fn in your current crate, considering all active @@ -40,18 +39,6 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { /// Returns true if this function must conform to `min_const_fn` pub fn is_min_const_fn(self, def_id: DefId) -> bool { - // some intrinsics are waved through if called inside the - // standard library. Users never need to call them directly - if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() { - match &self.item_name(def_id).as_str()[..] { - | "size_of" - | "min_align_of" - | "needs_drop" - => return true, - _ => {}, - } - } - // Bail out if the signature doesn't contain `const` if !self.is_const_fn_raw(def_id) { return false; @@ -60,7 +47,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { if self.features().staged_api { // in order for a libstd function to be considered min_const_fn // it needs to be stable and have no `rustc_const_unstable` attribute - self.is_const_fn_raw(def_id) && match self.lookup_stability(def_id) { + match self.lookup_stability(def_id) { // stable functions with unstable const fn aren't `min_const_fn` Some(&attr::Stability { const_stability: Some(_), .. }) => false, // unstable functions don't need to conform diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 1538c070f373..90a204ce00d5 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -115,7 +115,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t // As specified in #55607, a `const unsafe fn` differs // from an `unsafe fn` in that its body is still considered // safe code by default. - assert!(!implicit_argument.is_none()); + assert!(implicit_argument.is_none()); Safety::Safe }, hir::Unsafety::Unsafe => Safety::FnUnsafe, diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index b47f1957ab4c..75f8045cfae9 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -514,7 +514,7 @@ fn unsafety_check_result<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) let param_env = tcx.param_env(def_id); let mut checker = UnsafetyChecker::new( - tcx.is_const_fn(def_id) && tcx.is_min_const_fn(def_id), + tcx.is_min_const_fn(def_id), mir, source_scope_local_data, tcx, param_env); checker.visit_mir(mir); @@ -617,13 +617,19 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { // Report an error. match kind { UnsafetyViolationKind::General if tcx.is_min_const_fn(def_id) => { - tcx.sess.struct_span_err( + let mut err = 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(); + are not allowed in const fn", description)); + err.span_label(source_info.span, &description.as_str()[..]) + .note(&details.as_str()[..]); + if tcx.fn_sig(def_id).unsafety() == hir::Unsafety::Unsafe { + err.note( + "unsafe action within a `const unsafe fn` still require an `unsafe` \ + block in contrast to regular `unsafe fn`." + ); + } + err.emit(); } UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => { diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 13e134ba8592..3c1b9dbd91fa 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -2,6 +2,7 @@ use rustc::hir::def_id::DefId; use rustc::hir; use rustc::mir::*; use rustc::ty::{self, Predicate, TyCtxt}; +use rustc_target::spec::abi; use std::borrow::Cow; use syntax_pos::Span; @@ -338,19 +339,40 @@ fn check_terminator( } => { let fn_ty = func.ty(mir, tcx); if let ty::FnDef(def_id, _) = fn_ty.sty { - if tcx.is_min_const_fn(def_id) { - check_operand(tcx, mir, func, span)?; - for arg in args { - check_operand(tcx, mir, arg, span)?; - } - Ok(()) - } else { - Err(( + // some intrinsics are waved through if called inside the + // standard library. Users never need to call them directly + match tcx.fn_sig(def_id).abi() { + abi::Abi::RustIntrinsic => match &tcx.item_name(def_id).as_str()[..] { + | "size_of" + | "min_align_of" + | "needs_drop" + => {}, + _ => return Err(( + span, + "can only call a curated list of intrinsics in `min_const_fn`".into(), + )), + }, + abi::Abi::Rust if tcx.is_min_const_fn(def_id) => {}, + abi::Abi::Rust => return Err(( span, "can only call other `min_const_fn` within a `min_const_fn`".into(), - )) + )), + abi => return Err(( + span, + format!( + "cannot call functions with `{}` abi in `min_const_fn`", + abi, + ).into(), + )), } + + check_operand(tcx, mir, func, span)?; + + for arg in args { + check_operand(tcx, mir, arg, span)?; + } + Ok(()) } else { Err((span, "can only call other const fns within const fn".into())) } 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 8d885545cde5..922a7883b9f2 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 @@ -45,6 +45,7 @@ LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR no | ^^ dereference of raw pointer | = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. error: access to union field is unsafe and unsafe operations are not allowed in const fn --> $DIR/min_const_fn_unsafe.rs:38:5 @@ -53,6 +54,7 @@ LL | Foo { x: () }.y //~ ERROR not allowed in const fn | ^^^^^^^^^^^^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. error: aborting due to 7 previous errors diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr index 4336db65813b..20c75afbe638 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr @@ -37,6 +37,7 @@ LL | foo4() //~ ERROR not allowed in const fn | ^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior + = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn --> $DIR/min_const_fn_unsafe_feature_gate.rs:42:5 @@ -45,6 +46,7 @@ LL | foo5::() //~ ERROR not allowed in const fn | ^^^^^^^^^^^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior + = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn --> $DIR/min_const_fn_unsafe_feature_gate.rs:45:5 @@ -53,6 +55,7 @@ LL | foo6::>>() //~ ERROR not allowed in const fn | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior + = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn --> $DIR/min_const_fn_unsafe_feature_gate.rs:47:51 @@ -61,6 +64,7 @@ LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowe | ^^ dereference of raw pointer | = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn --> $DIR/min_const_fn_unsafe_feature_gate.rs:50:60 @@ -69,6 +73,7 @@ LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR | ^^^ dereference of raw pointer | = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn --> $DIR/min_const_fn_unsafe_feature_gate.rs:53:62 @@ -85,6 +90,7 @@ LL | Foo { x: () }.y //~ ERROR not allowed in const fn | ^^^^^^^^^^^^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. error: aborting due to 11 previous errors