diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 62eed8be3ccb7..726e94e49a19e 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -147,7 +147,7 @@ pub fn llvm(build: &Build, target: &str) { } if env::var_os("SCCACHE_ERROR_LOG").is_some() { - cfg.env("RUST_LOG", "sccache=debug"); + cfg.env("RUST_LOG", "sccache=info"); } // FIXME: we don't actually need to build all LLVM tools and all LLVM diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 71a4bfae3caf9..59b93b784b2f6 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -38,7 +38,6 @@ if [ "$SCCACHE_BUCKET" != "" ]; then args="$args --env AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID" args="$args --env AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY" args="$args --env SCCACHE_ERROR_LOG=/tmp/sccache/sccache.log" - args="$args --env SCCACHE_LOG_LEVEL=debug" args="$args --volume $objdir/tmp:/tmp/sccache" else mkdir -p $HOME/.cache/sccache diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 81c75e1326e41..54e602a81db73 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -114,6 +114,7 @@ - [loop_break_value](loop-break-value.md) - [macro_reexport](macro-reexport.md) - [main](main.md) +- [manually_drop](manually-drop.md) - [map_entry_recover_keys](map-entry-recover-keys.md) - [mpsc_select](mpsc-select.md) - [n16](n16.md) diff --git a/src/doc/unstable-book/src/manually-drop.md b/src/doc/unstable-book/src/manually-drop.md new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 5360804f9e1d7..99afd08e81183 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -44,6 +44,7 @@ #![feature(heap_api)] #![feature(inclusive_range)] #![feature(lang_items)] +#![feature(manually_drop)] #![feature(nonzero)] #![feature(pattern)] #![feature(placement_in)] diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 6cff315a6ccd9..3069adb12e92c 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1558,7 +1558,7 @@ fn insert_head(v: &mut [T], is_less: &mut F) // performance than with the 2nd method. // // All methods were benchmarked, and the 3rd showed best results. So we chose that one. - let mut tmp = NoDrop { value: ptr::read(&v[0]) }; + let mut tmp = mem::ManuallyDrop::new(ptr::read(&v[0])); // Intermediate state of the insertion process is always tracked by `hole`, which // serves two purposes: @@ -1571,13 +1571,13 @@ fn insert_head(v: &mut [T], is_less: &mut F) // fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it // initially held exactly once. let mut hole = InsertionHole { - src: &mut tmp.value, + src: &mut *tmp, dest: &mut v[1], }; ptr::copy_nonoverlapping(&v[1], &mut v[0], 1); for i in 2..v.len() { - if !is_less(&v[i], &tmp.value) { + if !is_less(&v[i], &*tmp) { break; } ptr::copy_nonoverlapping(&v[i], &mut v[i - 1], 1); @@ -1587,12 +1587,6 @@ fn insert_head(v: &mut [T], is_less: &mut F) } } - // Holds a value, but never drops it. - #[allow(unions_with_drop_fields)] - union NoDrop { - value: T - } - // When dropped, copies from `src` into `dest`. struct InsertionHole { src: *mut T, diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index e0a4707ff665f..b028763158512 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -691,9 +691,6 @@ extern "rust-intrinsic" { /// initialize memory previous set to the result of `uninit`. pub fn uninit() -> T; - /// Moves a value out of scope without running drop glue. - pub fn forget(_: T) -> (); - /// Reinterprets the bits of a value of one type as another type. /// /// Both types must have the same size. Neither the original, nor the result, diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index f5cf3724d0711..7be927b28ed7e 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -171,7 +171,7 @@ pub use intrinsics::transmute; #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn forget(t: T) { - unsafe { intrinsics::forget(t) } + ManuallyDrop::new(t); } /// Returns the size of a type in bytes. @@ -736,3 +736,121 @@ pub fn discriminant(v: &T) -> Discriminant { } } + +/// A wrapper to inhibit compiler from automatically calling `T`’s destructor. +/// +/// This wrapper is 0-cost. +/// +/// # Examples +/// +/// This wrapper helps with explicitly documenting the drop order dependencies between fields of +/// the type: +/// +/// ```rust +/// # #![feature(manually_drop)] +/// use std::mem::ManuallyDrop; +/// struct Peach; +/// struct Banana; +/// struct Melon; +/// struct FruitBox { +/// // Immediately clear there’s something non-trivial going on with these fields. +/// peach: ManuallyDrop, +/// melon: Melon, // Field that’s independent of the other two. +/// banana: ManuallyDrop, +/// } +/// +/// impl Drop for FruitBox { +/// fn drop(&mut self) { +/// unsafe { +/// // Explicit ordering in which field destructors are run specified in the intuitive +/// // location – the destructor of the structure containing the fields. +/// // Moreover, one can now reorder fields within the struct however much they want. +/// ManuallyDrop::drop(&mut self.peach); +/// ManuallyDrop::drop(&mut self.banana); +/// } +/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets +/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`. +/// } +/// } +/// ``` +#[unstable(feature = "manually_drop", issue = "40673")] +#[allow(unions_with_drop_fields)] +pub union ManuallyDrop{ value: T } + +impl ManuallyDrop { + /// Wrap a value to be manually dropped. + /// + /// # Examples + /// + /// ```rust + /// # #![feature(manually_drop)] + /// use std::mem::ManuallyDrop; + /// ManuallyDrop::new(Box::new(())); + /// ``` + #[unstable(feature = "manually_drop", issue = "40673")] + #[inline] + pub fn new(value: T) -> ManuallyDrop { + ManuallyDrop { value: value } + } + + /// Extract the value from the ManuallyDrop container. + /// + /// # Examples + /// + /// ```rust + /// # #![feature(manually_drop)] + /// use std::mem::ManuallyDrop; + /// let x = ManuallyDrop::new(Box::new(())); + /// let _: Box<()> = ManuallyDrop::into_inner(x); + /// ``` + #[unstable(feature = "manually_drop", issue = "40673")] + #[inline] + pub fn into_inner(slot: ManuallyDrop) -> T { + unsafe { + slot.value + } + } + + /// Manually drops the contained value. + /// + /// # Unsafety + /// + /// This function runs the destructor of the contained value and thus the wrapped value + /// now represents uninitialized data. It is up to the user of this method to ensure the + /// uninitialized data is not actually used. + #[unstable(feature = "manually_drop", issue = "40673")] + #[inline] + pub unsafe fn drop(slot: &mut ManuallyDrop) { + ptr::drop_in_place(&mut slot.value) + } +} + +#[unstable(feature = "manually_drop", issue = "40673")] +impl ::ops::Deref for ManuallyDrop { + type Target = T; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { + &self.value + } + } +} + +#[unstable(feature = "manually_drop", issue = "40673")] +impl ::ops::DerefMut for ManuallyDrop { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + &mut self.value + } + } +} + +#[unstable(feature = "manually_drop", issue = "40673")] +impl ::fmt::Debug for ManuallyDrop { + fn fmt(&self, fmt: &mut ::fmt::Formatter) -> ::fmt::Result { + unsafe { + fmt.debug_tuple("ManuallyDrop").field(&self.value).finish() + } + } +} diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 7065fdb79fc40..6f9f2915dfe10 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -20,12 +20,6 @@ use cmp; use mem; use ptr; -/// Holds a value, but never drops it. -#[allow(unions_with_drop_fields)] -union NoDrop { - value: T -} - /// When dropped, copies from `src` into `dest`. struct CopyOnDrop { src: *mut T, @@ -49,15 +43,15 @@ fn shift_head(v: &mut [T], is_less: &mut F) // Read the first element into a stack-allocated variable. If a following comparison // operation panics, `hole` will get dropped and automatically write the element back // into the slice. - let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(0)) }; + let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(0))); let mut hole = CopyOnDrop { - src: &mut tmp.value, + src: &mut *tmp, dest: v.get_unchecked_mut(1), }; ptr::copy_nonoverlapping(v.get_unchecked(1), v.get_unchecked_mut(0), 1); for i in 2..len { - if !is_less(v.get_unchecked(i), &tmp.value) { + if !is_less(v.get_unchecked(i), &*tmp) { break; } @@ -81,15 +75,15 @@ fn shift_tail(v: &mut [T], is_less: &mut F) // Read the last element into a stack-allocated variable. If a following comparison // operation panics, `hole` will get dropped and automatically write the element back // into the slice. - let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(len - 1)) }; + let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(len - 1))); let mut hole = CopyOnDrop { - src: &mut tmp.value, + src: &mut *tmp, dest: v.get_unchecked_mut(len - 2), }; ptr::copy_nonoverlapping(v.get_unchecked(len - 2), v.get_unchecked_mut(len - 1), 1); for i in (0..len-2).rev() { - if !is_less(&tmp.value, v.get_unchecked(i)) { + if !is_less(&*tmp, v.get_unchecked(i)) { break; } @@ -403,12 +397,12 @@ fn partition(v: &mut [T], pivot: usize, is_less: &mut F) -> (usize, bool) // Read the pivot into a stack-allocated variable for efficiency. If a following comparison // operation panics, the pivot will be automatically written back into the slice. - let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } }; + let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) }); let _pivot_guard = CopyOnDrop { - src: unsafe { &mut tmp.value }, + src: &mut *tmp, dest: pivot, }; - let pivot = unsafe { &tmp.value }; + let pivot = &*tmp; // Find the first pair of out-of-order elements. let mut l = 0; @@ -452,12 +446,12 @@ fn partition_equal(v: &mut [T], pivot: usize, is_less: &mut F) -> usize // Read the pivot into a stack-allocated variable for efficiency. If a following comparison // operation panics, the pivot will be automatically written back into the slice. - let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } }; + let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) }); let _pivot_guard = CopyOnDrop { - src: unsafe { &mut tmp.value }, + src: &mut *tmp, dest: pivot, }; - let pivot = unsafe { &tmp.value }; + let pivot = &*tmp; // Now partition the slice. let mut l = 0; diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index 29fbcb70756ba..adb2219722602 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -20,10 +20,11 @@ use std::fmt; use std::mem; use std::collections::range::RangeArgument; use std::collections::Bound::{Excluded, Included, Unbounded}; +use std::mem::ManuallyDrop; pub unsafe trait Array { type Element; - type PartialStorage: Default + Unsize<[ManuallyDrop]>; + type PartialStorage: Unsize<[ManuallyDrop]>; const LEN: usize; } @@ -66,7 +67,7 @@ impl ArrayVec { pub fn new() -> Self { ArrayVec { count: 0, - values: Default::default(), + values: unsafe { ::std::mem::uninitialized() }, } } @@ -81,7 +82,7 @@ impl ArrayVec { /// Panics when the stack vector is full. pub fn push(&mut self, el: A::Element) { let arr = &mut self.values as &mut [ManuallyDrop<_>]; - arr[self.count] = ManuallyDrop { value: el }; + arr[self.count] = ManuallyDrop::new(el); self.count += 1; } @@ -90,8 +91,8 @@ impl ArrayVec { let arr = &mut self.values as &mut [ManuallyDrop<_>]; self.count -= 1; unsafe { - let value = ptr::read(&arr[self.count]); - Some(value.value) + let value = ptr::read(&*arr[self.count]); + Some(value) } } else { None @@ -210,7 +211,7 @@ impl Iterator for Iter { fn next(&mut self) -> Option { let arr = &self.store as &[ManuallyDrop<_>]; unsafe { - self.indices.next().map(|i| ptr::read(&arr[i]).value) + self.indices.next().map(|i| ptr::read(&*arr[i])) } } @@ -233,7 +234,7 @@ impl<'a, A: Array> Iterator for Drain<'a, A> { #[inline] fn next(&mut self) -> Option { - self.iter.next().map(|elt| unsafe { ptr::read(elt as *const ManuallyDrop<_>).value }) + self.iter.next().map(|elt| unsafe { ptr::read(&**elt) }) } fn size_hint(&self) -> (usize, Option) { @@ -295,25 +296,3 @@ impl<'a, A: Array> IntoIterator for &'a mut ArrayVec { self.iter_mut() } } - -// FIXME: This should use repr(transparent) from rust-lang/rfcs#1758. -#[allow(unions_with_drop_fields)] -pub union ManuallyDrop { - value: T, - #[allow(dead_code)] - empty: (), -} - -impl ManuallyDrop { - fn new() -> ManuallyDrop { - ManuallyDrop { - empty: () - } - } -} - -impl Default for ManuallyDrop { - fn default() -> Self { - ManuallyDrop::new() - } -} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index c1735b4a4ec9a..72c533a74618b 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -39,6 +39,7 @@ #![feature(conservative_impl_trait)] #![feature(discriminant_value)] #![feature(specialization)] +#![feature(manually_drop)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 5e7d612d17f82..0cbc103994ad9 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -188,7 +188,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, C_nil(ccx) } // Effectively no-ops - "uninit" | "forget" => { + "uninit" => { C_nil(ccx) } "needs_drop" => { diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 2861fd288326b..cd58fcd4806da 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -124,7 +124,6 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "rustc_peek" => (1, vec![param(0)], param(0)), "init" => (1, Vec::new(), param(0)), "uninit" => (1, Vec::new(), param(0)), - "forget" => (1, vec![ param(0) ], tcx.mk_nil()), "transmute" => (2, vec![ param(0) ], param(1)), "move_val_init" => { (1, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 1e687d63f5875..c59101cc77996 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -469,22 +469,28 @@ impl LangString { ); for token in tokens { - match token { + match token.trim() { "" => {}, - "should_panic" => { data.should_panic = true; seen_rust_tags = true; }, - "no_run" => { data.no_run = true; seen_rust_tags = true; }, - "ignore" => { data.ignore = true; seen_rust_tags = true; }, - "rust" => { data.rust = true; seen_rust_tags = true; }, - "test_harness" => { data.test_harness = true; seen_rust_tags = true; }, + "should_panic" => { + data.should_panic = true; + seen_rust_tags = seen_other_tags == false; + } + "no_run" => { data.no_run = true; seen_rust_tags = !seen_other_tags; } + "ignore" => { data.ignore = true; seen_rust_tags = !seen_other_tags; } + "rust" => { data.rust = true; seen_rust_tags = true; } + "test_harness" => { + data.test_harness = true; + seen_rust_tags = !seen_other_tags || seen_rust_tags; + } "compile_fail" if allow_compile_fail => { data.compile_fail = true; - seen_rust_tags = true; + seen_rust_tags = !seen_other_tags || seen_rust_tags; data.no_run = true; } x if allow_error_code_check && x.starts_with("E") && x.len() == 5 => { if let Ok(_) = x[1..].parse::() { data.error_codes.push(x.to_owned()); - seen_rust_tags = true; + seen_rust_tags = !seen_other_tags || seen_rust_tags; } else { seen_other_tags = true; } @@ -670,9 +676,11 @@ mod tests { t("test_harness", false, false, false, true, true, false, Vec::new()); t("compile_fail", false, true, false, true, false, true, Vec::new()); t("{.no_run .example}", false, true, false, true, false, false, Vec::new()); - t("{.sh .should_panic}", true, false, false, true, false, false, Vec::new()); + t("{.sh .should_panic}", true, false, false, false, false, false, Vec::new()); t("{.example .rust}", false, false, false, true, false, false, Vec::new()); t("{.test_harness .rust}", false, false, false, true, true, false, Vec::new()); + t("text, no_run", false, true, false, false, false, false, Vec::new()); + t("text,no_run", false, true, false, false, false, false, Vec::new()); } #[test] diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 5b2053e929a10..052340a0f253a 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -277,7 +277,7 @@ mod prim_pointer { } /// Arrays of sizes from 0 to 32 (inclusive) implement the following traits if /// the element type allows it: /// -/// - [`Clone`][clone] (only if `T: [Copy][copy]`) +/// - [`Clone`][clone] (only if `T: `[`Copy`][copy]) /// - [`Debug`][debug] /// - [`IntoIterator`][intoiterator] (implemented for `&[T; N]` and `&mut [T; N]`) /// - [`PartialEq`][partialeq], [`PartialOrd`][partialord], [`Eq`][eq], [`Ord`][ord] diff --git a/src/test/compile-fail/forget-init-unsafe.rs b/src/test/compile-fail/forget-init-unsafe.rs index 521f122f8af0b..48c9fda31e8c8 100644 --- a/src/test/compile-fail/forget-init-unsafe.rs +++ b/src/test/compile-fail/forget-init-unsafe.rs @@ -10,10 +10,9 @@ #![feature(core_intrinsics)] -use std::intrinsics::{init, forget}; +use std::intrinsics::{init}; // Test that the `forget` and `init` intrinsics are really unsafe pub fn main() { let stuff = init::(); //~ ERROR call to unsafe function requires unsafe - forget(stuff); //~ ERROR call to unsafe function requires unsafe } diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index adddd7b7e89b0..a7a43e6858ef9 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -11,7 +11,7 @@ extern crate toml; extern crate rustc_serialize; -use std::collections::{BTreeMap, HashMap}; +use std::collections::BTreeMap; use std::env; use std::fs::File; use std::io::{self, Read, Write}; @@ -101,13 +101,13 @@ static MINGW: &'static [&'static str] = &[ struct Manifest { manifest_version: String, date: String, - pkg: HashMap, + pkg: BTreeMap, } #[derive(RustcEncodable)] struct Package { version: String, - target: HashMap, + target: BTreeMap, } #[derive(RustcEncodable)] @@ -138,7 +138,7 @@ struct Builder { input: PathBuf, output: PathBuf, gpg_passphrase: String, - digests: HashMap, + digests: BTreeMap, s3_address: String, date: String, rust_version: String, @@ -162,7 +162,7 @@ fn main() { input: input, output: output, gpg_passphrase: passphrase, - digests: HashMap::new(), + digests: BTreeMap::new(), s3_address: s3_address, date: date, rust_version: String::new(), @@ -214,7 +214,7 @@ impl Builder { let mut manifest = Manifest { manifest_version: "2".to_string(), date: self.date.to_string(), - pkg: HashMap::new(), + pkg: BTreeMap::new(), }; self.package("rustc", &mut manifest.pkg, HOSTS); @@ -230,7 +230,7 @@ impl Builder { let mut pkg = Package { version: self.cached_version("rust").to_string(), - target: HashMap::new(), + target: BTreeMap::new(), }; for host in HOSTS { let filename = self.filename("rust", host); @@ -299,7 +299,7 @@ impl Builder { fn package(&mut self, pkgname: &str, - dst: &mut HashMap, + dst: &mut BTreeMap, targets: &[&str]) { let targets = targets.iter().map(|name| { let filename = self.filename(pkgname, name);