Skip to content

Commit

Permalink
Auto merge of #55635 - oli-obk:min_const_unsafe_fn, r=nikomatsakis
Browse files Browse the repository at this point in the history
Allow calling `const unsafe fn` in `const fn` behind a feature gate

cc #55607

r? @Centril
  • Loading branch information
bors committed Dec 4, 2018
2 parents 431e0ab + cb71752 commit 2ba23a2
Show file tree
Hide file tree
Showing 38 changed files with 868 additions and 137 deletions.
2 changes: 1 addition & 1 deletion src/libcore/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@ mod impls {
/// This affects, for example, whether a `static` of that type is
/// placed in read-only static memory or writable static memory.
#[lang = "freeze"]
unsafe auto trait Freeze {}
pub(crate) unsafe auto trait Freeze {}

impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
Expand Down
17 changes: 13 additions & 4 deletions src/libcore/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,23 @@
//! Exposes the NonZero lang item which provides optimization hints.

use ops::{CoerceUnsized, DispatchFromDyn};
use marker::Freeze;

/// A wrapper type for raw pointers and integers that will never be
/// NULL or 0 that might allow certain optimizations.
#[rustc_layout_scalar_valid_range_start(1)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(transparent)]
pub(crate) struct NonZero<T>(pub(crate) T);
pub(crate) struct NonZero<T: Freeze>(pub(crate) T);

impl<T: CoerceUnsized<U>, U> CoerceUnsized<NonZero<U>> for NonZero<T> {}
// Do not call `T::clone` as theoretically it could turn the field into `0`
// invalidating `NonZero`'s invariant.
impl<T: Copy + Freeze> Clone for NonZero<T> {
fn clone(&self) -> Self {
unsafe { NonZero(self.0) }
}
}

impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<NonZero<U>> for NonZero<T> {}
impl<T: CoerceUnsized<U> + Freeze, U: Freeze> CoerceUnsized<NonZero<U>> for NonZero<T> {}

impl<T: DispatchFromDyn<U> + Freeze, U: Freeze> DispatchFromDyn<NonZero<U>> for NonZero<T> {}
4 changes: 2 additions & 2 deletions src/libcore/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ assert_eq!(size_of::<Option<std::num::", stringify!($Ty), ">>(), size_of::<", st
#[stable(feature = "nonzero", since = "1.28.0")]
#[inline]
pub const unsafe fn new_unchecked(n: $Int) -> Self {
$Ty(NonZero(n))
$Ty(unsafe { NonZero(n) })
}

/// Create a non-zero if the given value is not zero.
#[stable(feature = "nonzero", since = "1.28.0")]
#[inline]
pub fn new(n: $Int) -> Option<Self> {
if n != 0 {
Some($Ty(NonZero(n)))
Some($Ty(unsafe { NonZero(n) }))
} else {
None
}
Expand Down
14 changes: 7 additions & 7 deletions src/libcore/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2759,7 +2759,7 @@ impl<T: ?Sized> Unique<T> {
/// Creates a new `Unique` if `ptr` is non-null.
pub fn new(ptr: *mut T) -> Option<Self> {
if !ptr.is_null() {
Some(Unique { pointer: NonZero(ptr as _), _marker: PhantomData })
Some(Unique { pointer: unsafe { NonZero(ptr as _) }, _marker: PhantomData })
} else {
None
}
Expand Down Expand Up @@ -2815,14 +2815,14 @@ impl<T: ?Sized> fmt::Pointer for Unique<T> {
#[unstable(feature = "ptr_internals", issue = "0")]
impl<'a, T: ?Sized> From<&'a mut T> for Unique<T> {
fn from(reference: &'a mut T) -> Self {
Unique { pointer: NonZero(reference as _), _marker: PhantomData }
Unique { pointer: unsafe { NonZero(reference as _) }, _marker: PhantomData }
}
}

#[unstable(feature = "ptr_internals", issue = "0")]
impl<'a, T: ?Sized> From<&'a T> for Unique<T> {
fn from(reference: &'a T) -> Self {
Unique { pointer: NonZero(reference as _), _marker: PhantomData }
Unique { pointer: unsafe { NonZero(reference as _) }, _marker: PhantomData }
}
}

Expand Down Expand Up @@ -2895,15 +2895,15 @@ impl<T: ?Sized> NonNull<T> {
#[stable(feature = "nonnull", since = "1.25.0")]
#[inline]
pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
NonNull { pointer: NonZero(ptr as _) }
NonNull { pointer: unsafe { NonZero(ptr as _) } }
}

/// Creates a new `NonNull` if `ptr` is non-null.
#[stable(feature = "nonnull", since = "1.25.0")]
#[inline]
pub fn new(ptr: *mut T) -> Option<Self> {
if !ptr.is_null() {
Some(NonNull { pointer: NonZero(ptr as _) })
Some(unsafe { Self::new_unchecked(ptr) })
} else {
None
}
Expand Down Expand Up @@ -3025,14 +3025,14 @@ impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
impl<'a, T: ?Sized> From<&'a mut T> for NonNull<T> {
#[inline]
fn from(reference: &'a mut T) -> Self {
NonNull { pointer: NonZero(reference as _) }
NonNull { pointer: unsafe { NonZero(reference as _) } }
}
}

#[stable(feature = "nonnull", since = "1.25.0")]
impl<'a, T: ?Sized> From<&'a T> for NonNull<T> {
#[inline]
fn from(reference: &'a T) -> Self {
NonNull { pointer: NonZero(reference as _) }
NonNull { pointer: unsafe { NonZero(reference as _) } }
}
}
3 changes: 2 additions & 1 deletion src/librustc/ich/impls_mir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ impl_stable_hash_for!(enum mir::BorrowKind {

impl_stable_hash_for!(enum mir::UnsafetyViolationKind {
General,
MinConstFn,
GeneralAndConstFn,
GatedConstFnCall,
ExternStatic(lint_node_id),
BorrowPacked(lint_node_id),
});
Expand Down
9 changes: 6 additions & 3 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::sync::MappedReadGuard;
use rustc_serialize as serialize;
use rustc_serialize::{self as serialize};
use smallvec::SmallVec;
use std::borrow::Cow;
use std::fmt::{self, Debug, Formatter, Write};
Expand Down Expand Up @@ -2770,8 +2770,11 @@ impl Location {
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum UnsafetyViolationKind {
General,
/// unsafety is not allowed at all in min const fn
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),
}
Expand Down
18 changes: 5 additions & 13 deletions src/librustc/ty/constness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -40,19 +39,12 @@ 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 {
// Bail out if the signature doesn't contain `const`
if !self.is_const_fn_raw(def_id) {
return false;
}

if self.features().staged_api {
// 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() {
assert!(!self.is_const_fn(def_id));
match &self.item_name(def_id).as_str()[..] {
| "size_of"
| "min_align_of"
| "needs_drop"
=> return true,
_ => {},
}
}
// in order for a libstd function to be considered min_const_fn
// it needs to be stable and have no `rustc_const_unstable` attribute
match self.lookup_stability(def_id) {
Expand Down
32 changes: 28 additions & 4 deletions src/librustc_data_structures/indexed_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,18 @@ macro_rules! newtype_index {
@max [$max:expr]
@vis [$v:vis]
@debug_format [$debug_format:tt]) => (
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)]
#[derive(Copy, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)]
#[rustc_layout_scalar_valid_range_end($max)]
$v struct $type {
private: u32
}

impl Clone for $type {
fn clone(&self) -> Self {
*self
}
}

impl $type {
$v const MAX_AS_U32: u32 = $max;

Expand Down Expand Up @@ -145,7 +151,7 @@ macro_rules! newtype_index {

#[inline]
$v const unsafe fn from_u32_unchecked(value: u32) -> Self {
$type { private: value }
unsafe { $type { private: value } }
}

/// Extract value of this index as an integer.
Expand Down Expand Up @@ -328,12 +334,13 @@ macro_rules! newtype_index {
derive [$($derives:ident,)+]
$($tokens:tt)*) => (
newtype_index!(
@derives [$($derives,)+ RustcDecodable, RustcEncodable,]
@derives [$($derives,)+ RustcEncodable,]
@type [$type]
@max [$max]
@vis [$v]
@debug_format [$debug_format]
$($tokens)*);
newtype_index!(@decodable $type);
);

// The case where no derives are added, but encodable is overridden. Don't
Expand All @@ -360,12 +367,29 @@ macro_rules! newtype_index {
@debug_format [$debug_format:tt]
$($tokens:tt)*) => (
newtype_index!(
@derives [RustcDecodable, RustcEncodable,]
@derives [RustcEncodable,]
@type [$type]
@max [$max]
@vis [$v]
@debug_format [$debug_format]
$($tokens)*);
newtype_index!(@decodable $type);
);

(@decodable $type:ident) => (
impl $type {
fn __decodable__impl__hack() {
mod __more_hacks_because__self_doesnt_work_in_functions {
extern crate serialize;
use self::serialize::{Decodable, Decoder};
impl Decodable for super::$type {
fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
d.read_u32().map(Self::from)
}
}
}
}
}
);

// Rewrite final without comma to one that includes comma
Expand Down
11 changes: 9 additions & 2 deletions src/librustc_mir/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,9 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
// types/lifetimes replaced)
let fn_hir_id = tcx.hir.node_to_hir_id(id);
let fn_sig = cx.tables().liberated_fn_sigs()[fn_hir_id].clone();
let fn_def_id = tcx.hir.local_def_id(id);

let ty = tcx.type_of(tcx.hir.local_def_id(id));
let ty = tcx.type_of(fn_def_id);
let mut abi = fn_sig.abi;
let implicit_argument = match ty.sty {
ty::Closure(..) => {
Expand All @@ -108,9 +109,15 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
_ => None,
};

// FIXME: safety in closures
let safety = match fn_sig.unsafety {
hir::Unsafety::Normal => Safety::Safe,
hir::Unsafety::Unsafe if tcx.is_min_const_fn(fn_def_id) => {
// 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());
Safety::Safe
},
hir::Unsafety::Unsafe => Safety::FnUnsafe,
};

Expand Down
Loading

0 comments on commit 2ba23a2

Please sign in to comment.