diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 3cc3ea467966b..a1b6e0e4af5d0 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -109,6 +109,7 @@ #![feature(pattern)] #![feature(placement_in_syntax)] #![feature(placement_new_protocol)] +#![feature(ptr_dangling)] #![feature(rustc_attrs)] #![feature(shared)] #![feature(slice_get_slice)] diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 5aca199cf40c0..3d6da0acd5cf1 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2344,7 +2344,7 @@ impl Iterator for IntoIter { // Use a non-null pointer value // (self.ptr might be null because of wrapping) - Some(ptr::read(1 as *mut T)) + Some(ptr::read(ptr::dangling())) } else { let old = self.ptr; self.ptr = self.ptr.offset(1); @@ -2384,7 +2384,7 @@ impl DoubleEndedIterator for IntoIter { // Use a non-null pointer value // (self.end might be null because of wrapping) - Some(ptr::read(1 as *mut T)) + Some(ptr::read(ptr::dangling())) } else { self.end = self.end.offset(-1); diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 631b9f98589f6..8283c6a94b4da 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -91,6 +91,7 @@ #![feature(unboxed_closures)] #![feature(untagged_unions)] #![feature(unwind_attributes)] +#![feature(const_align_of)] #![feature(const_min_value)] #![feature(const_max_value)] #![feature(const_atomic_bool_new)] diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 126558e3025d5..0a183817e0fb3 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2083,6 +2083,24 @@ impl PartialEq for *mut T { #[stable(feature = "rust1", since = "1.0.0")] impl Eq for *mut T {} +#[unstable(feature = "ptr_dangling", issue = "45557")] +#[rustc_const_unstable(feature = "const_ptr_dangling")] +/// Returns a const raw pointer that is dangling, but well-aligned and not null. +/// +/// This is used where a non-null pointer is required. +pub const fn dangling() -> *const T { + mem::align_of::() as *const T +} + +#[unstable(feature = "ptr_dangling", issue = "45557")] +#[rustc_const_unstable(feature = "const_ptr_dangling_mut")] +/// Returns a mut raw pointer that is dangling, but well-aligned and not null. +/// +/// This is used where a non-null pointer is required. +pub const fn dangling_mut() -> *mut T { + mem::align_of::() as *mut T +} + /// Compare raw pointers for equality. /// /// This is the same as using the `==` operator, but less generic: @@ -2325,8 +2343,7 @@ impl Unique { /// `Vec::new` does. pub fn empty() -> Self { unsafe { - let ptr = mem::align_of::() as *mut T; - Unique::new_unchecked(ptr) + Unique::new_unchecked(dangling_mut()) } } } @@ -2460,8 +2477,7 @@ impl Shared { /// `Vec::new` does. pub fn empty() -> Self { unsafe { - let ptr = mem::align_of::() as *mut T; - Shared::new_unchecked(ptr) + Shared::new_unchecked(dangling_mut()) } } } diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 49c51f4f04fdc..cf6feae47ac18 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -244,7 +244,7 @@ macro_rules! make_ref { let ptr = $ptr; if size_from_ptr(ptr) == 0 { // Use a non-null pointer value - &*(1 as *mut _) + &*ptr::dangling() } else { &*ptr } @@ -257,7 +257,7 @@ macro_rules! make_ref_mut { let ptr = $ptr; if size_from_ptr(ptr) == 0 { // Use a non-null pointer value - &mut *(1 as *mut _) + &mut *(ptr::dangling_mut()) } else { &mut *ptr } @@ -279,7 +279,7 @@ impl SliceExt for [T] { fn iter(&self) -> Iter { unsafe { let p = if mem::size_of::() == 0 { - 1 as *const _ + ptr::dangling() } else { let p = self.as_ptr(); assume(!p.is_null()); @@ -443,7 +443,7 @@ impl SliceExt for [T] { fn iter_mut(&mut self) -> IterMut { unsafe { let p = if mem::size_of::() == 0 { - 1 as *mut _ + ptr::dangling_mut() } else { let p = self.as_mut_ptr(); assume(!p.is_null()); @@ -1259,7 +1259,7 @@ macro_rules! make_slice { let diff = ($end as usize).wrapping_sub(start as usize); if size_from_ptr(start) == 0 { // use a non-null pointer value - unsafe { from_raw_parts(1 as *const _, diff) } + unsafe { from_raw_parts(ptr::dangling(), diff) } } else { let len = diff / size_from_ptr(start); unsafe { from_raw_parts(start, len) } @@ -1273,7 +1273,7 @@ macro_rules! make_mut_slice { let diff = ($end as usize).wrapping_sub(start as usize); if size_from_ptr(start) == 0 { // use a non-null pointer value - unsafe { from_raw_parts_mut(1 as *mut _, diff) } + unsafe { from_raw_parts_mut(ptr::dangling_mut(), diff) } } else { let len = diff / size_from_ptr(start); unsafe { from_raw_parts_mut(start, len) } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index b59f7480476b8..a6bc80cd9fd68 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -55,6 +55,7 @@ #![feature(match_default_bindings)] #![feature(never_type)] #![feature(nonzero)] +#![feature(ptr_dangling)] #![feature(quote)] #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 48ec92a255b4c..18e82a4b1d514 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -46,6 +46,7 @@ use std::rc::Rc; use std::slice; use std::vec::IntoIter; use std::mem; +use std::ptr; use syntax::ast::{self, DUMMY_NODE_ID, Name, Ident, NodeId}; use syntax::attr; use syntax::ext::hygiene::{Mark, SyntaxContext}; @@ -572,7 +573,7 @@ impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Slice> {} impl Slice { pub fn empty<'a>() -> &'a Slice { unsafe { - mem::transmute(slice::from_raw_parts(0x1 as *const T, 0)) + mem::transmute(slice::from_raw_parts(ptr::dangling::(), 0)) } } } diff --git a/src/libstd/io/lazy.rs b/src/libstd/io/lazy.rs index 9cef4e3cdf1ca..30a4670794b4d 100644 --- a/src/libstd/io/lazy.rs +++ b/src/libstd/io/lazy.rs @@ -37,7 +37,7 @@ impl Lazy { let ptr = self.ptr.get(); let ret = if ptr.is_null() { Some(self.init()) - } else if ptr as usize == 1 { + } else if ptr == ptr::dangling_mut() { None } else { Some((*ptr).clone()) @@ -55,7 +55,7 @@ impl Lazy { let registered = sys_common::at_exit(move || { self.lock.lock(); let ptr = self.ptr.get(); - self.ptr.set(1 as *mut _); + self.ptr.set(ptr::dangling_mut()); self.lock.unlock(); drop(Box::from_raw(ptr)) }); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index ccc89ccdcf4c3..06b71d505e353 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -301,6 +301,7 @@ #![feature(placement_in_syntax)] #![feature(placement_new_protocol)] #![feature(prelude_import)] +#![feature(ptr_dangling)] #![feature(rand)] #![feature(raw)] #![feature(repr_align)] diff --git a/src/libstd/sys_common/thread_local.rs b/src/libstd/sys_common/thread_local.rs index 87ffd304e1a33..c06386269229a 100644 --- a/src/libstd/sys_common/thread_local.rs +++ b/src/libstd/sys_common/thread_local.rs @@ -36,7 +36,7 @@ //! ```ignore (cannot-doctest-private-modules) //! let key = Key::new(None); //! assert!(key.get().is_null()); -//! key.set(1 as *mut u8); +//! key.set(std::ptr::dangling_mut::()); //! assert!(!key.get().is_null()); //! //! drop(key); // deallocate this TLS slot. @@ -50,7 +50,7 @@ //! //! unsafe { //! assert!(KEY.get().is_null()); -//! KEY.set(1 as *mut u8); +//! KEY.set(std::ptr::dangling_mut::()); //! } //! ``` @@ -81,7 +81,7 @@ use sys_common::mutex::Mutex; /// /// unsafe { /// assert!(KEY.get().is_null()); -/// KEY.set(1 as *mut u8); +/// KEY.set(std::ptr::dangling_mut::()); /// } /// ``` pub struct StaticKey { @@ -110,7 +110,7 @@ pub struct StaticKey { /// /// let key = Key::new(None); /// assert!(key.get().is_null()); -/// key.set(1 as *mut u8); +/// key.set(std::ptr::dangling_mut::()); /// assert!(!key.get().is_null()); /// /// drop(key); // deallocate this TLS slot. diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index fcbca38a98f0b..8d9e164ec6efa 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -492,7 +492,7 @@ pub mod os { pub unsafe fn get(&'static self) -> Option<&'static UnsafeCell>> { let ptr = self.os.get() as *mut Value; if !ptr.is_null() { - if ptr as usize == 1 { + if ptr == ptr::dangling_mut() { return None } return Some(&(*ptr).value); @@ -520,7 +520,7 @@ pub mod os { // before we return from the destructor ourselves. let ptr = Box::from_raw(ptr as *mut Value); let key = ptr.key; - key.os.set(1 as *mut u8); + key.os.set(ptr::dangling_mut()); drop(ptr); key.os.set(ptr::null_mut()); } diff --git a/src/test/run-pass/zero-sized-by-ref-iterator.rs b/src/test/run-pass/zero-sized-by-ref-iterator.rs new file mode 100644 index 0000000000000..eef897a3f6640 --- /dev/null +++ b/src/test/run-pass/zero-sized-by-ref-iterator.rs @@ -0,0 +1,41 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![feature(repr_align, attr_literals, core_intrinsics)] + +use std::mem::align_of; +use std::intrinsics::type_name; + +fn has_aligned_refs<'a, I, T: 'a>(iterable: I) +where + I: Iterator +{ + for elt in iterable { + unsafe { + assert_eq!((elt as *const T as usize) % align_of::(), 0, + "Assertion failed for type {}", type_name::()); + } + } +} + +fn main() { + #[derive(Copy, Clone)] + struct Zst; + + #[derive(Copy, Clone)] + #[repr(align(64))] + struct Aligned; + + has_aligned_refs([Zst; 8].iter()); + has_aligned_refs([[0f64; 0]; 8].iter()); + has_aligned_refs([Aligned; 8].iter()); + has_aligned_refs([Zst; 8].iter_mut().map(|t| &*t)); + has_aligned_refs([[0f64; 0]; 8].iter_mut().map(|t| &*t)); + has_aligned_refs([Aligned; 8].iter_mut().map(|t| &*t)); +}