Skip to content

Commit 128a1fa

Browse files
committed
Auto merge of #55635 - oli-obk:min_const_unsafe_fn, r=nikomatsakis
Allow calling `const unsafe fn` in `const fn` behind a feature gate cc #55607 r? @Centril
2 parents 77a6a61 + cb71752 commit 128a1fa

38 files changed

+868
-137
lines changed

src/libcore/marker.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,7 @@ mod impls {
596596
/// This affects, for example, whether a `static` of that type is
597597
/// placed in read-only static memory or writable static memory.
598598
#[lang = "freeze"]
599-
unsafe auto trait Freeze {}
599+
pub(crate) unsafe auto trait Freeze {}
600600

601601
impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
602602
unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}

src/libcore/nonzero.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,23 @@
1111
//! Exposes the NonZero lang item which provides optimization hints.
1212
1313
use ops::{CoerceUnsized, DispatchFromDyn};
14+
use marker::Freeze;
1415

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

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

24-
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<NonZero<U>> for NonZero<T> {}
31+
impl<T: CoerceUnsized<U> + Freeze, U: Freeze> CoerceUnsized<NonZero<U>> for NonZero<T> {}
32+
33+
impl<T: DispatchFromDyn<U> + Freeze, U: Freeze> DispatchFromDyn<NonZero<U>> for NonZero<T> {}

src/libcore/num/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,15 @@ assert_eq!(size_of::<Option<std::num::", stringify!($Ty), ">>(), size_of::<", st
7070
#[stable(feature = "nonzero", since = "1.28.0")]
7171
#[inline]
7272
pub const unsafe fn new_unchecked(n: $Int) -> Self {
73-
$Ty(NonZero(n))
73+
$Ty(unsafe { NonZero(n) })
7474
}
7575

7676
/// Create a non-zero if the given value is not zero.
7777
#[stable(feature = "nonzero", since = "1.28.0")]
7878
#[inline]
7979
pub fn new(n: $Int) -> Option<Self> {
8080
if n != 0 {
81-
Some($Ty(NonZero(n)))
81+
Some($Ty(unsafe { NonZero(n) }))
8282
} else {
8383
None
8484
}

src/libcore/ptr.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -2759,7 +2759,7 @@ impl<T: ?Sized> Unique<T> {
27592759
/// Creates a new `Unique` if `ptr` is non-null.
27602760
pub fn new(ptr: *mut T) -> Option<Self> {
27612761
if !ptr.is_null() {
2762-
Some(Unique { pointer: NonZero(ptr as _), _marker: PhantomData })
2762+
Some(Unique { pointer: unsafe { NonZero(ptr as _) }, _marker: PhantomData })
27632763
} else {
27642764
None
27652765
}
@@ -2815,14 +2815,14 @@ impl<T: ?Sized> fmt::Pointer for Unique<T> {
28152815
#[unstable(feature = "ptr_internals", issue = "0")]
28162816
impl<'a, T: ?Sized> From<&'a mut T> for Unique<T> {
28172817
fn from(reference: &'a mut T) -> Self {
2818-
Unique { pointer: NonZero(reference as _), _marker: PhantomData }
2818+
Unique { pointer: unsafe { NonZero(reference as _) }, _marker: PhantomData }
28192819
}
28202820
}
28212821

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

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

29012901
/// Creates a new `NonNull` if `ptr` is non-null.
29022902
#[stable(feature = "nonnull", since = "1.25.0")]
29032903
#[inline]
29042904
pub fn new(ptr: *mut T) -> Option<Self> {
29052905
if !ptr.is_null() {
2906-
Some(NonNull { pointer: NonZero(ptr as _) })
2906+
Some(unsafe { Self::new_unchecked(ptr) })
29072907
} else {
29082908
None
29092909
}
@@ -3025,14 +3025,14 @@ impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
30253025
impl<'a, T: ?Sized> From<&'a mut T> for NonNull<T> {
30263026
#[inline]
30273027
fn from(reference: &'a mut T) -> Self {
3028-
NonNull { pointer: NonZero(reference as _) }
3028+
NonNull { pointer: unsafe { NonZero(reference as _) } }
30293029
}
30303030
}
30313031

30323032
#[stable(feature = "nonnull", since = "1.25.0")]
30333033
impl<'a, T: ?Sized> From<&'a T> for NonNull<T> {
30343034
#[inline]
30353035
fn from(reference: &'a T) -> Self {
3036-
NonNull { pointer: NonZero(reference as _) }
3036+
NonNull { pointer: unsafe { NonZero(reference as _) } }
30373037
}
30383038
}

src/librustc/ich/impls_mir.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ impl_stable_hash_for!(enum mir::BorrowKind {
4646

4747
impl_stable_hash_for!(enum mir::UnsafetyViolationKind {
4848
General,
49-
MinConstFn,
49+
GeneralAndConstFn,
50+
GatedConstFnCall,
5051
ExternStatic(lint_node_id),
5152
BorrowPacked(lint_node_id),
5253
});

src/librustc/mir/mod.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
2525
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
2626
use rustc_data_structures::sync::Lrc;
2727
use rustc_data_structures::sync::MappedReadGuard;
28-
use rustc_serialize as serialize;
28+
use rustc_serialize::{self as serialize};
2929
use smallvec::SmallVec;
3030
use std::borrow::Cow;
3131
use std::fmt::{self, Debug, Formatter, Write};
@@ -2778,8 +2778,11 @@ impl Location {
27782778
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
27792779
pub enum UnsafetyViolationKind {
27802780
General,
2781-
/// unsafety is not allowed at all in min const fn
2782-
MinConstFn,
2781+
/// Right now function calls to `const unsafe fn` are only permitted behind a feature gate
2782+
/// Also, even `const unsafe fn` need an `unsafe` block to do the allowed operations.
2783+
GatedConstFnCall,
2784+
/// Permitted in const fn and regular fns
2785+
GeneralAndConstFn,
27832786
ExternStatic(ast::NodeId),
27842787
BorrowPacked(ast::NodeId),
27852788
}

src/librustc/ty/constness.rs

+5-13
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use ty::TyCtxt;
55
use syntax_pos::symbol::Symbol;
66
use hir::map::blocks::FnLikeNode;
77
use syntax::attr;
8-
use rustc_target::spec::abi;
98

109
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
1110
/// Whether the `def_id` counts as const fn in your current crate, considering all active
@@ -40,19 +39,12 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
4039

4140
/// Returns true if this function must conform to `min_const_fn`
4241
pub fn is_min_const_fn(self, def_id: DefId) -> bool {
42+
// Bail out if the signature doesn't contain `const`
43+
if !self.is_const_fn_raw(def_id) {
44+
return false;
45+
}
46+
4347
if self.features().staged_api {
44-
// some intrinsics are waved through if called inside the
45-
// standard library. Users never need to call them directly
46-
if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
47-
assert!(!self.is_const_fn(def_id));
48-
match &self.item_name(def_id).as_str()[..] {
49-
| "size_of"
50-
| "min_align_of"
51-
| "needs_drop"
52-
=> return true,
53-
_ => {},
54-
}
55-
}
5648
// in order for a libstd function to be considered min_const_fn
5749
// it needs to be stable and have no `rustc_const_unstable` attribute
5850
match self.lookup_stability(def_id) {

src/librustc_data_structures/indexed_vec.rs

+28-4
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,18 @@ macro_rules! newtype_index {
9898
@max [$max:expr]
9999
@vis [$v:vis]
100100
@debug_format [$debug_format:tt]) => (
101-
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)]
101+
#[derive(Copy, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)]
102102
#[rustc_layout_scalar_valid_range_end($max)]
103103
$v struct $type {
104104
private: u32
105105
}
106106

107+
impl Clone for $type {
108+
fn clone(&self) -> Self {
109+
*self
110+
}
111+
}
112+
107113
impl $type {
108114
$v const MAX_AS_U32: u32 = $max;
109115

@@ -145,7 +151,7 @@ macro_rules! newtype_index {
145151

146152
#[inline]
147153
$v const unsafe fn from_u32_unchecked(value: u32) -> Self {
148-
$type { private: value }
154+
unsafe { $type { private: value } }
149155
}
150156

151157
/// Extract value of this index as an integer.
@@ -328,12 +334,13 @@ macro_rules! newtype_index {
328334
derive [$($derives:ident,)+]
329335
$($tokens:tt)*) => (
330336
newtype_index!(
331-
@derives [$($derives,)+ RustcDecodable, RustcEncodable,]
337+
@derives [$($derives,)+ RustcEncodable,]
332338
@type [$type]
333339
@max [$max]
334340
@vis [$v]
335341
@debug_format [$debug_format]
336342
$($tokens)*);
343+
newtype_index!(@decodable $type);
337344
);
338345

339346
// The case where no derives are added, but encodable is overridden. Don't
@@ -360,12 +367,29 @@ macro_rules! newtype_index {
360367
@debug_format [$debug_format:tt]
361368
$($tokens:tt)*) => (
362369
newtype_index!(
363-
@derives [RustcDecodable, RustcEncodable,]
370+
@derives [RustcEncodable,]
364371
@type [$type]
365372
@max [$max]
366373
@vis [$v]
367374
@debug_format [$debug_format]
368375
$($tokens)*);
376+
newtype_index!(@decodable $type);
377+
);
378+
379+
(@decodable $type:ident) => (
380+
impl $type {
381+
fn __decodable__impl__hack() {
382+
mod __more_hacks_because__self_doesnt_work_in_functions {
383+
extern crate serialize;
384+
use self::serialize::{Decodable, Decoder};
385+
impl Decodable for super::$type {
386+
fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
387+
d.read_u32().map(Self::from)
388+
}
389+
}
390+
}
391+
}
392+
}
369393
);
370394

371395
// Rewrite final without comma to one that includes comma

src/librustc_mir/build/mod.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,9 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
9191
// types/lifetimes replaced)
9292
let fn_hir_id = tcx.hir.node_to_hir_id(id);
9393
let fn_sig = cx.tables().liberated_fn_sigs()[fn_hir_id].clone();
94+
let fn_def_id = tcx.hir.local_def_id(id);
9495

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

111-
// FIXME: safety in closures
112112
let safety = match fn_sig.unsafety {
113113
hir::Unsafety::Normal => Safety::Safe,
114+
hir::Unsafety::Unsafe if tcx.is_min_const_fn(fn_def_id) => {
115+
// As specified in #55607, a `const unsafe fn` differs
116+
// from an `unsafe fn` in that its body is still considered
117+
// safe code by default.
118+
assert!(implicit_argument.is_none());
119+
Safety::Safe
120+
},
114121
hir::Unsafety::Unsafe => Safety::FnUnsafe,
115122
};
116123

0 commit comments

Comments
 (0)