Make sure the initialization of constrained int range newtypes is unsafe
This commit is contained in:
parent
cc3470ce3b
commit
02b22323f1
@ -93,6 +93,7 @@
|
||||
#![feature(never_type)]
|
||||
#![feature(nll)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![cfg_attr(not(stage0), feature(min_const_unsafe_fn))]
|
||||
#![feature(no_core)]
|
||||
#![feature(on_unimplemented)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
|
@ -15,10 +15,18 @@ use ops::{CoerceUnsized, DispatchFromDyn};
|
||||
/// 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);
|
||||
|
||||
// Do not call `T::clone` as theoretically it could turn the field into `0`
|
||||
// invalidating `NonZero`'s invariant.
|
||||
impl<T: Copy> Clone for NonZero<T> {
|
||||
fn clone(&self) -> Self {
|
||||
unsafe { NonZero(self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CoerceUnsized<U>, U> CoerceUnsized<NonZero<U>> for NonZero<T> {}
|
||||
|
||||
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<NonZero<U>> for NonZero<T> {}
|
||||
|
@ -70,7 +70,7 @@ 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.
|
||||
@ -78,7 +78,7 @@ assert_eq!(size_of::<Option<std::num::", stringify!($Ty), ">>(), size_of::<", st
|
||||
#[inline]
|
||||
pub fn new(n: $Int) -> Option<Self> {
|
||||
if n != 0 {
|
||||
Some($Ty(NonZero(n)))
|
||||
Some($Ty(unsafe { NonZero(n) }))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
@ -2895,7 +2895,7 @@ 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.
|
||||
@ -2903,7 +2903,7 @@ impl<T: ?Sized> NonNull<T> {
|
||||
#[inline]
|
||||
pub fn new(ptr: *mut T) -> Option<Self> {
|
||||
if !ptr.is_null() {
|
||||
Some(NonNull { pointer: NonZero(ptr as _) })
|
||||
Some(NonNull { pointer: unsafe { NonZero(ptr as _) } })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -3025,7 +3025,7 @@ 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 _) } }
|
||||
}
|
||||
}
|
||||
|
||||
@ -3033,6 +3033,6 @@ impl<'a, T: ?Sized> From<&'a mut T> for NonNull<T> {
|
||||
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 _) } }
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext};
|
||||
use syntax::ast;
|
||||
use syntax::symbol::Symbol;
|
||||
|
||||
use std::ops::Bound;
|
||||
|
||||
use util;
|
||||
|
||||
pub struct UnsafetyChecker<'a, 'tcx: 'a> {
|
||||
@ -136,8 +138,18 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
||||
if let &Rvalue::Aggregate(box ref aggregate, _) = rvalue {
|
||||
match aggregate {
|
||||
&AggregateKind::Array(..) |
|
||||
&AggregateKind::Tuple |
|
||||
&AggregateKind::Adt(..) => {}
|
||||
&AggregateKind::Tuple => {}
|
||||
&AggregateKind::Adt(ref def, ..) => {
|
||||
match self.tcx.layout_scalar_valid_range(def.did) {
|
||||
(Bound::Unbounded, Bound::Unbounded) => {},
|
||||
_ => self.require_unsafe(
|
||||
"initializing type with `rustc_layout_scalar_valid_range` attr",
|
||||
"initializing `NonZero` with a `0` violates layout constraints \
|
||||
and is undefined behavior",
|
||||
UnsafetyViolationKind::MinConstFn,
|
||||
),
|
||||
}
|
||||
}
|
||||
&AggregateKind::Closure(def_id, _) |
|
||||
&AggregateKind::Generator(def_id, _, _) => {
|
||||
let UnsafetyCheckResult {
|
||||
|
@ -0,0 +1,47 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![unstable(feature = "humans",
|
||||
reason = "who ever let humans program computers,
|
||||
we're apparently really bad at it",
|
||||
issue = "0")]
|
||||
|
||||
#![feature(rustc_const_unstable, const_fn, foo, foo2)]
|
||||
#![feature(min_const_unsafe_fn)]
|
||||
#![feature(staged_api)]
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_unstable(feature="foo")]
|
||||
const unsafe fn foo() -> u32 { 42 }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// can't call non-min_const_fn
|
||||
const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `min_const_fn`
|
||||
|
||||
#[unstable(feature = "rust1", issue="0")]
|
||||
const unsafe fn foo2() -> u32 { 42 }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// can't call non-min_const_fn
|
||||
const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `min_const_fn`
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// conformity is required, even with `const_fn` feature gate
|
||||
const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op
|
||||
|
||||
// check whether this function cannot be called even with the feature gate active
|
||||
#[unstable(feature = "foo2", issue="0")]
|
||||
const unsafe fn foo2_gated() -> u32 { 42 }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// can't call non-min_const_fn
|
||||
const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } //~ ERROR can only call other
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,26 @@
|
||||
error: can only call other `min_const_fn` within a `min_const_fn`
|
||||
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:26:41
|
||||
|
|
||||
LL | const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `min_const_fn`
|
||||
| ^^^^^
|
||||
|
||||
error: can only call other `min_const_fn` within a `min_const_fn`
|
||||
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:33:42
|
||||
|
|
||||
LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `min_const_fn`
|
||||
| ^^^^^^
|
||||
|
||||
error: only int, `bool` and `char` operations are stable in const fn
|
||||
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:37:33
|
||||
|
|
||||
LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: can only call other `min_const_fn` within a `min_const_fn`
|
||||
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:45:48
|
||||
|
|
||||
LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } //~ ERROR can only call other
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
@ -0,0 +1,43 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![unstable(feature = "humans",
|
||||
reason = "who ever let humans program computers,
|
||||
we're apparently really bad at it",
|
||||
issue = "0")]
|
||||
|
||||
#![feature(rustc_const_unstable, const_fn, foo, foo2)]
|
||||
#![feature(min_const_unsafe_fn)]
|
||||
#![feature(staged_api)]
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_unstable(feature="foo")]
|
||||
const fn foo() -> u32 { 42 }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// can't call non-min_const_fn
|
||||
const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn`
|
||||
|
||||
#[unstable(feature = "rust1", issue="0")]
|
||||
const fn foo2() -> u32 { 42 }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// can't call non-min_const_fn
|
||||
const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn`
|
||||
|
||||
// check whether this function cannot be called even with the feature gate active
|
||||
#[unstable(feature = "foo2", issue="0")]
|
||||
const fn foo2_gated() -> u32 { 42 }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// can't call non-min_const_fn
|
||||
const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn`
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,20 @@
|
||||
error: can only call other `min_const_fn` within a `min_const_fn`
|
||||
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:26:32
|
||||
|
|
||||
LL | const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn`
|
||||
| ^^^^^
|
||||
|
||||
error: can only call other `min_const_fn` within a `min_const_fn`
|
||||
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:33
|
||||
|
|
||||
LL | const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn`
|
||||
| ^^^^^^
|
||||
|
||||
error: can only call other `min_const_fn` within a `min_const_fn`
|
||||
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:41:39
|
||||
|
|
||||
LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn`
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
Loading…
x
Reference in New Issue
Block a user