From f6e566185eaa4675cf2791ee69e63eb20ea01edb Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 22 Mar 2017 23:35:09 +0200 Subject: [PATCH 01/21] Implement Manually Drop --- src/libcore/mem.rs | 96 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index f5cf3724d0711..f4a19af02a661 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -736,3 +736,99 @@ 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. + #[unstable(feature = "manually_drop", issue = "40673")] + pub fn new(value: T) -> ManuallyDrop { + ManuallyDrop { value: value } + } + + /// Extract the value from the ManuallyDrop container. + #[unstable(feature = "manually_drop", issue = "40673")] + pub fn into_inner(self) -> T { + unsafe { + self.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")] + 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; + fn deref(&self) -> &Self::Target { + unsafe { + &self.value + } + } +} + +#[unstable(feature = "manually_drop", issue = "40673")] +impl ::ops::DerefMut for ManuallyDrop { + 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() + } + } +} From 38713126dd8502e283aa8ec7c6b678a4c43f8c3b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 22 Mar 2017 19:11:51 +0200 Subject: [PATCH 02/21] Move away from the ad-hoc NoDrop unions --- src/libcollections/lib.rs | 1 + src/libcollections/slice.rs | 12 ++------ src/libcore/slice/sort.rs | 30 ++++++++---------- src/librustc_data_structures/array_vec.rs | 37 +++++------------------ src/librustc_data_structures/lib.rs | 1 + 5 files changed, 25 insertions(+), 56 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 248c15e96f8f6..b474bd5d91af1 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/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))] From c94b3f1266779c595e28111e39f47e5e14a34ef2 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 2 Apr 2017 11:13:31 +0300 Subject: [PATCH 03/21] Replace the `forget` intrinsic with ManuallyDrop less intrinsics = better life --- src/libcore/intrinsics.rs | 3 --- src/libcore/mem.rs | 7 ++++++- src/librustc_trans/intrinsic.rs | 2 +- src/librustc_typeck/check/intrinsic.rs | 1 - 4 files changed, 7 insertions(+), 6 deletions(-) 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 f4a19af02a661..52ccaa417bc5f 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. @@ -780,12 +780,14 @@ pub union ManuallyDrop{ value: T } impl ManuallyDrop { /// Wrap a value to be manually dropped. #[unstable(feature = "manually_drop", issue = "40673")] + #[inline] pub fn new(value: T) -> ManuallyDrop { ManuallyDrop { value: value } } /// Extract the value from the ManuallyDrop container. #[unstable(feature = "manually_drop", issue = "40673")] + #[inline] pub fn into_inner(self) -> T { unsafe { self.value @@ -800,6 +802,7 @@ impl ManuallyDrop { /// 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) } @@ -808,6 +811,7 @@ impl ManuallyDrop { #[unstable(feature = "manually_drop", issue = "40673")] impl ::ops::Deref for ManuallyDrop { type Target = T; + #[inline] fn deref(&self) -> &Self::Target { unsafe { &self.value @@ -817,6 +821,7 @@ impl ::ops::Deref for ManuallyDrop { #[unstable(feature = "manually_drop", issue = "40673")] impl ::ops::DerefMut for ManuallyDrop { + #[inline] fn deref_mut(&mut self) -> &mut Self::Target { unsafe { &mut self.value 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, From 486345551c09612aa87155304a20e6b8de492939 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 2 Apr 2017 11:15:59 +0300 Subject: [PATCH 04/21] into_inner to associated function --- src/libcore/mem.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 52ccaa417bc5f..7be927b28ed7e 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -779,6 +779,14 @@ 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 { @@ -786,11 +794,20 @@ impl ManuallyDrop { } /// 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(self) -> T { + pub fn into_inner(slot: ManuallyDrop) -> T { unsafe { - self.value + slot.value } } From c337b99f4cb0968481a03195d25358b484d7db22 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 2 Apr 2017 11:16:17 +0300 Subject: [PATCH 05/21] Fix test failures --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/manually-drop.md | 0 src/test/compile-fail/forget-init-unsafe.rs | 3 +-- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 src/doc/unstable-book/src/manually-drop.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index d86766bac02a2..90499f3ce8590 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -113,6 +113,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/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 } From d4aecf52dba643bf938a572d506995c5cad4602e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 9 Apr 2017 18:31:59 +0200 Subject: [PATCH 06/21] Fix block code headers parsing --- src/librustdoc/html/markdown.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 1e687d63f5875..dca873a85d813 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -471,20 +471,26 @@ impl LangString { for token in tokens { match token { "" => {}, - "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 == false; } + "ignore" => { data.ignore = true; seen_rust_tags = seen_other_tags == false; } + "rust" => { data.rust = true; seen_rust_tags = true; } + "test_harness" => { + data.test_harness = true; + seen_rust_tags = seen_other_tags == false || seen_rust_tags == true; + } "compile_fail" if allow_compile_fail => { data.compile_fail = true; - seen_rust_tags = true; + seen_rust_tags = seen_other_tags == false || seen_rust_tags == true; 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 == false || seen_rust_tags == true; } else { seen_other_tags = true; } @@ -670,9 +676,10 @@ 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()); } #[test] From 1c3f34dba6a8219822a48f3db7e6f50ff04e0f78 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 10 Apr 2017 20:50:42 +0000 Subject: [PATCH 07/21] Convert HashMap to BTree in build-manifest --- src/tools/build-manifest/src/main.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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); From b9d662a00026390aa7b7b5706d3c800e4d6e6fdb Mon Sep 17 00:00:00 2001 From: Nathaniel Ringo Date: Mon, 10 Apr 2017 16:12:39 -0500 Subject: [PATCH 08/21] Fixes incorrect formatting in array's documentation. --- src/libstd/primitive_docs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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] From f297767b2c262e8542a4734a3f47b0a75502c9fd Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Tue, 11 Apr 2017 00:22:26 +0100 Subject: [PATCH 09/21] Make sccache a bit quieter --- src/bootstrap/native.rs | 2 +- src/ci/docker/run.sh | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) 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 From 63ebf08be50c2716b66f14f0ab6e9885542eb0a0 Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Wed, 8 Mar 2017 16:28:47 -0500 Subject: [PATCH 10/21] Initial attempt at implementing optimization fuel and re-enabling struct field reordering. --- src/librustc/session/config.rs | 24 +++++++++ src/librustc/session/mod.rs | 52 ++++++++++++++++++++ src/librustc/ty/context.rs | 5 ++ src/librustc/ty/layout.rs | 9 +--- src/librustc/ty/mod.rs | 5 ++ src/librustc_driver/lib.rs | 8 +++ src/test/run-pass/type-sizes.rs | 13 +++++ src/test/ui/print_type_sizes/nullable.stdout | 35 ++++++------- src/test/ui/print_type_sizes/packed.stdout | 10 ++-- src/test/ui/print_type_sizes/padding.stdout | 16 +++--- 10 files changed, 138 insertions(+), 39 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index ef825a6854cec..b9a974045bced 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -643,6 +643,8 @@ macro_rules! options { Some("one of: `address`, `leak`, `memory` or `thread`"); pub const parse_linker_flavor: Option<&'static str> = Some(::rustc_back::LinkerFlavor::one_of()); + pub const parse_optimization_fuel: Option<&'static str> = + Some("crate=integer"); } #[allow(dead_code)] @@ -787,6 +789,21 @@ macro_rules! options { } true } + + fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool { + match v { + None => false, + Some(s) => { + let parts = s.split('=').collect::>(); + if parts.len() != 2 { return false; } + let crate_name = parts[0].to_string(); + let fuel = parts[1].parse::(); + if fuel.is_err() { return false; } + *slot = Some((crate_name, fuel.unwrap())); + true + } + } + } } ) } @@ -991,6 +1008,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "Use a sanitizer"), linker_flavor: Option = (None, parse_linker_flavor, [UNTRACKED], "Linker flavor"), + fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED], + "Set the optimization fuel quota for a crate."), + print_fuel: Option = (None, parse_opt_string, [TRACKED], + "Make Rustc print the total optimization fuel used by a crate."), } pub fn default_lib_output() -> CrateType { @@ -1784,11 +1805,13 @@ mod dep_tracking { impl_dep_tracking_hash_via_hash!(bool); impl_dep_tracking_hash_via_hash!(usize); + impl_dep_tracking_hash_via_hash!(u64); impl_dep_tracking_hash_via_hash!(String); impl_dep_tracking_hash_via_hash!(lint::Level); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); + impl_dep_tracking_hash_via_hash!(Option<(String, u64)>); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); @@ -1810,6 +1833,7 @@ mod dep_tracking { impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level)); impl_dep_tracking_hash_for_sortable_vec_of!((String, Option, Option)); + impl_dep_tracking_hash_for_sortable_vec_of!((String, u64)); impl DepTrackingHash for SearchPaths { fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) { let mut elems: Vec<_> = self diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 70b2809ccbed2..2d204908a521c 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -123,6 +123,20 @@ pub struct Session { pub code_stats: RefCell, next_node_id: Cell, + + /// If -zfuel=crate=n is specified, Some(crate). + optimization_fuel_crate: Option, + /// If -zfuel=crate=n is specified, initially set to n. Otherwise 0. + optimization_fuel_limit: Cell, + /// We're rejecting all further optimizations. + out_of_fuel: Cell, + + // The next two are public because the driver needs to read them. + + /// If -zprint-fuel=crate, Some(crate). + pub print_fuel_crate: Option, + /// Always set to zero and incremented so that we can print fuel expended by a crate. + pub print_fuel: Cell, } pub struct PerfStats { @@ -507,6 +521,33 @@ impl Session { println!("Total time spent decoding DefPath tables: {}", duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get())); } + + /// We want to know if we're allowed to do an optimization for crate crate. + /// This expends fuel if applicable, and records fuel if applicable. + pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { + let mut ret = true; + match self.optimization_fuel_crate { + Some(ref c) if c == crate_name => { + let fuel = self.optimization_fuel_limit.get(); + ret = fuel != 0; + if fuel == 0 && !self.out_of_fuel.get(){ + println!("optimization-fuel-exhausted: {}", msg()); + self.out_of_fuel.set(true); + } + else { + self.optimization_fuel_limit.set(fuel-1); + } + } + _ => {} + } + match self.print_fuel_crate { + Some(ref c) if c == crate_name=> { + self.print_fuel.set(self.print_fuel.get()+1); + }, + _ => {} + } + ret + } } pub fn build_session(sopts: config::Options, @@ -602,6 +643,12 @@ pub fn build_session_(sopts: config::Options, } ); + let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone()); + let optimization_fuel_limit = Cell::new(sopts.debugging_opts.fuel.as_ref() + .map(|i| i.1).unwrap_or(0)); + let print_fuel_crate = sopts.debugging_opts.print_fuel.clone(); + let print_fuel = Cell::new(0); + let sess = Session { dep_graph: dep_graph.clone(), target: target_cfg, @@ -643,6 +690,11 @@ pub fn build_session_(sopts: config::Options, decode_def_path_tables_time: Cell::new(Duration::from_secs(0)), }, code_stats: RefCell::new(CodeStats::new()), + optimization_fuel_crate: optimization_fuel_crate, + optimization_fuel_limit: optimization_fuel_limit, + print_fuel_crate: print_fuel_crate, + print_fuel: print_fuel, + out_of_fuel: Cell::new(false), }; init_llvm(&sess); diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index da56514ea82fb..8b7438c0bfad2 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -732,6 +732,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ast_ty_to_ty_cache: RefCell::new(NodeMap()), }, f) } + + pub fn consider_optimizing String>(&self, msg: T) -> bool { + let cname = self.crate_name(LOCAL_CRATE).as_str(); + self.sess.consider_optimizing(&cname, msg) + } } impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 54e5de3909086..a344f89a66830 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -580,7 +580,6 @@ enum StructKind { } impl<'a, 'gcx, 'tcx> Struct { - // FIXME(camlorn): reprs need a better representation to deal with multiple reprs on one type. fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>, repr: &ReprOptions, kind: StructKind, scapegoat: Ty<'gcx>) -> Result> { @@ -598,12 +597,8 @@ impl<'a, 'gcx, 'tcx> Struct { // Neither do 1-member and 2-member structs. // In addition, code in trans assume that 2-element structs can become pairs. // It's easier to just short-circuit here. - let mut can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind) - && ! (repr.c || repr.packed); - - // Disable field reordering until we can decide what to do. - // The odd pattern here avoids a warning about the value never being read. - if can_optimize { can_optimize = false; } + let can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind) + && ! (repr.c || repr.packed || repr.linear || repr.simd); let (optimize, sort_ascending) = match kind { StructKind::AlwaysSizedUnivariant => (can_optimize, false), diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 292e30e3d41f1..ba9c177f90483 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1411,6 +1411,8 @@ pub struct ReprOptions { pub packed: bool, pub simd: bool, pub int: Option, + // Internal only for now. If true, don't reorder fields. + pub linear: bool, } impl_stable_hash_for!(struct ReprOptions { @@ -1440,6 +1442,9 @@ impl ReprOptions { ret.simd = true; } + // This is here instead of layout because the choice must make it into metadata. + ret.linear = !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", + tcx.item_path_str(did))); ret } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index c90dde3a5f6e0..1fef97d54a141 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -517,6 +517,14 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { control.make_glob_map = resolve::MakeGlobMap::Yes; } + if sess.print_fuel_crate.is_some() { + control.compilation_done.callback = box |state| { + let sess = state.session; + println!("Fuel used by {}: {}", + sess.print_fuel_crate.as_ref().unwrap(), + sess.print_fuel.get()); + } + } control } } diff --git a/src/test/run-pass/type-sizes.rs b/src/test/run-pass/type-sizes.rs index bbb01eaaf46b9..9d1a3500a582a 100644 --- a/src/test/run-pass/type-sizes.rs +++ b/src/test/run-pass/type-sizes.rs @@ -31,6 +31,17 @@ enum e3 { a([u16; 0], u8), b } +struct ReorderedStruct { + a: u8, + b: u64, + c: u8 +} + +enum ReorderedEnum { + A(u8, u64, u8), + B(u8, u64, u8), +} + pub fn main() { assert_eq!(size_of::(), 1 as usize); assert_eq!(size_of::(), 4 as usize); @@ -54,4 +65,6 @@ pub fn main() { assert_eq!(size_of::(), 8 as usize); assert_eq!(size_of::(), 8 as usize); assert_eq!(size_of::(), 4 as usize); + assert_eq!(size_of::(), 16); + assert_eq!(size_of::(), 16); } diff --git a/src/test/ui/print_type_sizes/nullable.stdout b/src/test/ui/print_type_sizes/nullable.stdout index dd999c4a5e4c7..830678f174f88 100644 --- a/src/test/ui/print_type_sizes/nullable.stdout +++ b/src/test/ui/print_type_sizes/nullable.stdout @@ -1,25 +1,22 @@ -print-type-size type: `IndirectNonZero`: 20 bytes, alignment: 4 bytes -print-type-size field `.pre`: 1 bytes -print-type-size padding: 3 bytes -print-type-size field `.nested`: 12 bytes, alignment: 4 bytes +print-type-size type: `IndirectNonZero`: 12 bytes, alignment: 4 bytes +print-type-size field `.nested`: 8 bytes print-type-size field `.post`: 2 bytes -print-type-size end padding: 2 bytes -print-type-size type: `MyOption>`: 20 bytes, alignment: 4 bytes -print-type-size variant `Some`: 20 bytes -print-type-size field `.0`: 20 bytes -print-type-size type: `EmbeddedDiscr`: 12 bytes, alignment: 4 bytes -print-type-size variant `Record`: 10 bytes -print-type-size field `.pre`: 1 bytes -print-type-size padding: 3 bytes -print-type-size field `.val`: 4 bytes, alignment: 4 bytes -print-type-size field `.post`: 2 bytes -print-type-size end padding: 2 bytes -print-type-size type: `NestedNonZero`: 12 bytes, alignment: 4 bytes print-type-size field `.pre`: 1 bytes -print-type-size padding: 3 bytes -print-type-size field `.val`: 4 bytes, alignment: 4 bytes +print-type-size end padding: 1 bytes +print-type-size type: `MyOption>`: 12 bytes, alignment: 4 bytes +print-type-size variant `Some`: 12 bytes +print-type-size field `.0`: 12 bytes +print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes +print-type-size variant `Record`: 7 bytes +print-type-size field `.val`: 4 bytes +print-type-size field `.post`: 2 bytes +print-type-size field `.pre`: 1 bytes +print-type-size end padding: 1 bytes +print-type-size type: `NestedNonZero`: 8 bytes, alignment: 4 bytes +print-type-size field `.val`: 4 bytes print-type-size field `.post`: 2 bytes -print-type-size end padding: 2 bytes +print-type-size field `.pre`: 1 bytes +print-type-size end padding: 1 bytes print-type-size type: `MyOption>`: 4 bytes, alignment: 4 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes diff --git a/src/test/ui/print_type_sizes/packed.stdout b/src/test/ui/print_type_sizes/packed.stdout index 1278a7d7c92c6..83fd333c9c7fc 100644 --- a/src/test/ui/print_type_sizes/packed.stdout +++ b/src/test/ui/print_type_sizes/packed.stdout @@ -1,13 +1,11 @@ -print-type-size type: `Padded`: 16 bytes, alignment: 4 bytes +print-type-size type: `Padded`: 12 bytes, alignment: 4 bytes +print-type-size field `.g`: 4 bytes +print-type-size field `.h`: 2 bytes print-type-size field `.a`: 1 bytes print-type-size field `.b`: 1 bytes -print-type-size padding: 2 bytes -print-type-size field `.g`: 4 bytes, alignment: 4 bytes print-type-size field `.c`: 1 bytes -print-type-size padding: 1 bytes -print-type-size field `.h`: 2 bytes, alignment: 2 bytes print-type-size field `.d`: 1 bytes -print-type-size end padding: 3 bytes +print-type-size end padding: 2 bytes print-type-size type: `Packed`: 10 bytes, alignment: 1 bytes print-type-size field `.a`: 1 bytes print-type-size field `.b`: 1 bytes diff --git a/src/test/ui/print_type_sizes/padding.stdout b/src/test/ui/print_type_sizes/padding.stdout index bb95f790bd9e4..0eaff7118b35c 100644 --- a/src/test/ui/print_type_sizes/padding.stdout +++ b/src/test/ui/print_type_sizes/padding.stdout @@ -1,10 +1,12 @@ print-type-size type: `E1`: 12 bytes, alignment: 4 bytes -print-type-size discriminant: 4 bytes -print-type-size variant `A`: 5 bytes -print-type-size field `.0`: 4 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `A`: 7 bytes print-type-size field `.1`: 1 bytes -print-type-size variant `B`: 8 bytes -print-type-size field `.0`: 8 bytes +print-type-size padding: 2 bytes +print-type-size field `.0`: 4 bytes, alignment: 4 bytes +print-type-size variant `B`: 11 bytes +print-type-size padding: 3 bytes +print-type-size field `.0`: 8 bytes, alignment: 4 bytes print-type-size type: `E2`: 12 bytes, alignment: 4 bytes print-type-size discriminant: 1 bytes print-type-size variant `A`: 7 bytes @@ -15,7 +17,7 @@ print-type-size variant `B`: 11 bytes print-type-size padding: 3 bytes print-type-size field `.0`: 8 bytes, alignment: 4 bytes print-type-size type: `S`: 8 bytes, alignment: 4 bytes +print-type-size field `.g`: 4 bytes print-type-size field `.a`: 1 bytes print-type-size field `.b`: 1 bytes -print-type-size padding: 2 bytes -print-type-size field `.g`: 4 bytes, alignment: 4 bytes +print-type-size end padding: 2 bytes From 4db9c7a2a2ba42fb15a58f5d770294b797bd57d4 Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Wed, 8 Mar 2017 22:20:07 -0500 Subject: [PATCH 11/21] Make a comment better. --- src/librustc/session/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 2d204908a521c..4304248d158e1 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -522,7 +522,7 @@ impl Session { duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get())); } - /// We want to know if we're allowed to do an optimization for crate crate. + /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. /// This expends fuel if applicable, and records fuel if applicable. pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { let mut ret = true; From 912599944effe3ad379622c173e8f9a85dd7eaac Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Fri, 10 Mar 2017 14:13:59 -0500 Subject: [PATCH 12/21] Tests for -Z fuel=foo=n --- src/librustc/session/mod.rs | 2 +- src/test/run-pass/optimization-fuel-0.rs | 24 ++++++++++++++++++++++ src/test/run-pass/optimization-fuel-1.rs | 26 ++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/optimization-fuel-0.rs create mode 100644 src/test/run-pass/optimization-fuel-1.rs diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 4304248d158e1..1be7d1afe45a8 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -534,7 +534,7 @@ impl Session { println!("optimization-fuel-exhausted: {}", msg()); self.out_of_fuel.set(true); } - else { + else if fuel > 0{ self.optimization_fuel_limit.set(fuel-1); } } diff --git a/src/test/run-pass/optimization-fuel-0.rs b/src/test/run-pass/optimization-fuel-0.rs new file mode 100644 index 0000000000000..3832c040108f8 --- /dev/null +++ b/src/test/run-pass/optimization-fuel-0.rs @@ -0,0 +1,24 @@ +// Copyright 2012 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. + +#![crate_name="foo"] + +use std::mem::size_of; + +// compile-flags: -Z fuel=foo=0 + +struct S1(u8, u16, u8); +struct S2(u8, u16, u8); + +fn main() { + assert_eq!(size_of::(), 6); + assert_eq!(size_of::(), 6); +} + diff --git a/src/test/run-pass/optimization-fuel-1.rs b/src/test/run-pass/optimization-fuel-1.rs new file mode 100644 index 0000000000000..5f294e26aa53e --- /dev/null +++ b/src/test/run-pass/optimization-fuel-1.rs @@ -0,0 +1,26 @@ +// Copyright 2012 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. + +#![crate_name="foo"] + +use std::mem::size_of; + +// compile-flags: -Z fuel=foo=1 + +struct S1(u8, u16, u8); +struct S2(u8, u16, u8); + +fn main() { + let optimized = (size_of::() == 4) as usize + +(size_of::() == 4) as usize; + assert_eq!(optimized, 1); +} + + From 8b00837691d9757b6c607b28b42d33dd581cac3b Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Fri, 10 Mar 2017 14:24:50 -0500 Subject: [PATCH 13/21] UI test for -Z print-fuel=foo --- src/test/ui/print-fuel/print-fuel.rs | 21 +++++++++++++++++++++ src/test/ui/print-fuel/print-fuel.stdout | 1 + 2 files changed, 22 insertions(+) create mode 100644 src/test/ui/print-fuel/print-fuel.rs create mode 100644 src/test/ui/print-fuel/print-fuel.stdout diff --git a/src/test/ui/print-fuel/print-fuel.rs b/src/test/ui/print-fuel/print-fuel.rs new file mode 100644 index 0000000000000..0d9e243763f78 --- /dev/null +++ b/src/test/ui/print-fuel/print-fuel.rs @@ -0,0 +1,21 @@ +// Copyright 2016 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. + +#![crate_name="foo"] +#![allow(dead_code)] + +// compile-flags: -Z print-fuel=foo + +struct S1(u8, u16, u8); +struct S2(u8, u16, u8); +struct S3(u8, u16, u8); + +fn main() { +} diff --git a/src/test/ui/print-fuel/print-fuel.stdout b/src/test/ui/print-fuel/print-fuel.stdout new file mode 100644 index 0000000000000..cc88cc077bb21 --- /dev/null +++ b/src/test/ui/print-fuel/print-fuel.stdout @@ -0,0 +1 @@ +Fuel used by foo: 3 From 98eb121b7a748fd2668bf03ace8307be2880955f Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Mon, 20 Mar 2017 14:07:46 -0400 Subject: [PATCH 14/21] We have to use u16 to test field reordering because u64's alignment changes based on 32-bit or 64-bit architecture. --- src/test/run-pass/type-sizes.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/run-pass/type-sizes.rs b/src/test/run-pass/type-sizes.rs index 9d1a3500a582a..2f50e63153ea4 100644 --- a/src/test/run-pass/type-sizes.rs +++ b/src/test/run-pass/type-sizes.rs @@ -33,13 +33,13 @@ enum e3 { struct ReorderedStruct { a: u8, - b: u64, + b: u16, c: u8 } enum ReorderedEnum { - A(u8, u64, u8), - B(u8, u64, u8), + A(u8, u16, u8), + B(u8, u16, u8), } pub fn main() { @@ -65,6 +65,6 @@ pub fn main() { assert_eq!(size_of::(), 8 as usize); assert_eq!(size_of::(), 8 as usize); assert_eq!(size_of::(), 4 as usize); - assert_eq!(size_of::(), 16); - assert_eq!(size_of::(), 16); + assert_eq!(size_of::(), 4); + assert_eq!(size_of::(), 6); } From 0931e2006a5f8fd88032247ea543239c628cf10c Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Wed, 8 Mar 2017 16:28:47 -0500 Subject: [PATCH 15/21] Initial attempt at implementing optimization fuel and re-enabling struct field reordering. --- src/librustc/session/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 1be7d1afe45a8..b32d05971ff3b 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -522,7 +522,7 @@ impl Session { duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get())); } - /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. + /// We want to know if we're allowed to do an optimization for crate crate. /// This expends fuel if applicable, and records fuel if applicable. pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { let mut ret = true; From d821e98fd73ee16c2f2733570220b2b64d367d45 Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Wed, 8 Mar 2017 22:20:07 -0500 Subject: [PATCH 16/21] Make a comment better. --- src/librustc/session/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index b32d05971ff3b..1be7d1afe45a8 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -522,7 +522,7 @@ impl Session { duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get())); } - /// We want to know if we're allowed to do an optimization for crate crate. + /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. /// This expends fuel if applicable, and records fuel if applicable. pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { let mut ret = true; From a384f131cbb3e79154cc99ef0d025fc9ed6d9674 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 11 Apr 2017 14:31:20 +0300 Subject: [PATCH 17/21] Fix handling of closure arguments Those did not take tuple reordering into account, causing majority of the compiler test suite to fail. --- src/librustc/ty/layout.rs | 2 +- src/librustc/ty/mod.rs | 3 ++- src/librustc_trans/intrinsic.rs | 9 +++++---- src/librustc_trans/mir/mod.rs | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index a344f89a66830..d7a4b3fda63bb 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -598,7 +598,7 @@ impl<'a, 'gcx, 'tcx> Struct { // In addition, code in trans assume that 2-element structs can become pairs. // It's easier to just short-circuit here. let can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind) - && ! (repr.c || repr.packed || repr.linear || repr.simd); + && !(repr.c || repr.packed || repr.linear || repr.simd); let (optimize, sort_ascending) = match kind { StructKind::AlwaysSizedUnivariant => (can_optimize, false), diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index ba9c177f90483..a2c356c20db09 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1419,7 +1419,8 @@ impl_stable_hash_for!(struct ReprOptions { c, packed, simd, - int + int, + linear }); impl ReprOptions { diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 5e7d612d17f82..b6fbc2f5ad537 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -16,7 +16,7 @@ use llvm; use llvm::{ValueRef}; use abi::{Abi, FnType}; use adt; -use mir::lvalue::LvalueRef; +use mir::lvalue::{LvalueRef, Alignment}; use base::*; use common::*; use declare; @@ -36,8 +36,6 @@ use syntax_pos::Span; use std::cmp::Ordering; use std::iter; -use mir::lvalue::Alignment; - fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option { let llvm_name = match name { "sqrtf32" => "llvm.sqrt.f32", @@ -622,7 +620,10 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, for i in 0..elems.len() { let val = bcx.extract_value(val, i); - bcx.store(val, bcx.struct_gep(llresult, i), None); + let lval = LvalueRef::new_sized_ty(llresult, ret_ty, + Alignment::AbiAligned); + let (dest, _) = lval.trans_field_ptr(bcx, i); + bcx.store(val, dest, None); } C_nil(ccx) } diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index c8d15d28708f4..f4c9a136ace3c 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -386,7 +386,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, let lvalue = LvalueRef::alloca(bcx, arg_ty, &format!("arg{}", arg_index)); for (i, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() { - let dst = bcx.struct_gep(lvalue.llval, i); + let (dst, _) = lvalue.trans_field_ptr(bcx, i); let arg = &mircx.fn_ty.args[idx]; idx += 1; if common::type_is_fat_ptr(bcx.ccx, tupled_arg_ty) { From e18c59fd48a8387767d44fdd4d36208dfd33f762 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 11 Apr 2017 15:57:49 +0300 Subject: [PATCH 18/21] Fix some nits --- src/librustc/session/mod.rs | 5 ++--- src/librustc_driver/lib.rs | 4 +++- src/librustc_trans/intrinsic.rs | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 1be7d1afe45a8..039db3d9ee911 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -530,11 +530,10 @@ impl Session { Some(ref c) if c == crate_name => { let fuel = self.optimization_fuel_limit.get(); ret = fuel != 0; - if fuel == 0 && !self.out_of_fuel.get(){ + if fuel == 0 && !self.out_of_fuel.get() { println!("optimization-fuel-exhausted: {}", msg()); self.out_of_fuel.set(true); - } - else if fuel > 0{ + } else if fuel > 0 { self.optimization_fuel_limit.set(fuel-1); } } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 1fef97d54a141..1a892b73aa5d7 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -518,7 +518,9 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { } if sess.print_fuel_crate.is_some() { - control.compilation_done.callback = box |state| { + let old_callback = control.compilation_done.callback; + control.compilation_done.callback = box move |state| { + old_callback(state); let sess = state.session; println!("Fuel used by {}: {}", sess.print_fuel_crate.as_ref().unwrap(), diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index b6fbc2f5ad537..7cfc28622c443 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -622,8 +622,8 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, let val = bcx.extract_value(val, i); let lval = LvalueRef::new_sized_ty(llresult, ret_ty, Alignment::AbiAligned); - let (dest, _) = lval.trans_field_ptr(bcx, i); - bcx.store(val, dest, None); + let (dest, align) = lval.trans_field_ptr(bcx, i); + bcx.store(val, dest, align.to_align()); } C_nil(ccx) } From 143f7be8b65d5e1be549e1b283e8e3423bdab41c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 10 Apr 2017 14:35:28 +0200 Subject: [PATCH 19/21] Remove strings fulfilled with whitespaces in code block headers --- src/librustdoc/html/markdown.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index dca873a85d813..c59101cc77996 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -469,28 +469,28 @@ impl LangString { ); for token in tokens { - match token { + match token.trim() { "" => {}, "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 == false; } - "ignore" => { data.ignore = 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 == false || seen_rust_tags == true; + seen_rust_tags = !seen_other_tags || seen_rust_tags; } "compile_fail" if allow_compile_fail => { data.compile_fail = true; - seen_rust_tags = seen_other_tags == false || 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 = seen_other_tags == false || seen_rust_tags == true; + seen_rust_tags = !seen_other_tags || seen_rust_tags; } else { seen_other_tags = true; } @@ -680,6 +680,7 @@ mod tests { 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] From 316af6082c8c23615cc54302ee7efa0811bbabe7 Mon Sep 17 00:00:00 2001 From: Sebastian Hahn Date: Tue, 11 Apr 2017 14:51:56 +0200 Subject: [PATCH 20/21] Clarify Iterator::position doc Extend the example a little bit to show behaviour better. --- src/libcore/iter/iterator.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 618edf48abd04..8bf641e37fe46 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1532,14 +1532,18 @@ pub trait Iterator { /// Stopping at the first `true`: /// /// ``` - /// let a = [1, 2, 3]; + /// let a = [1, 2, 3, 4]; /// /// let mut iter = a.iter(); /// - /// assert_eq!(iter.position(|&x| x == 2), Some(1)); + /// assert_eq!(iter.position(|&x| x >= 2), Some(1)); /// /// // we can still use `iter`, as there are more elements. /// assert_eq!(iter.next(), Some(&3)); + /// + /// // The returned index depends on iterator state + /// assert_eq!(iter.position(|&x| x == 4), Some(0)); + /// /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] From 56503dd4adf65518a9645409e534935c2f434fe2 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Tue, 11 Apr 2017 22:53:16 +0200 Subject: [PATCH 21/21] use correct vault url --- src/ci/docker/dist-i686-linux/Dockerfile | 2 +- src/ci/docker/dist-x86_64-linux/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ci/docker/dist-i686-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile index b322f56f0d048..c25c770136f90 100644 --- a/src/ci/docker/dist-i686-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -6,7 +6,7 @@ WORKDIR /build # to http://vault.centos.org/ RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo -RUN sed -i 's/#\(baseurl.*\)mirror.centos.org/\1107.158.252.35/' /etc/yum.repos.d/*.repo +RUN sed -i 's|#\(baseurl.*\)mirror.centos.org/centos/$releasever|\1vault.centos.org/5.11|' /etc/yum.repos.d/*.repo RUN yum upgrade -y && yum install -y \ curl \ diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile index cbe5f5936a506..e835e8d2f7161 100644 --- a/src/ci/docker/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -6,7 +6,7 @@ WORKDIR /build # to http://vault.centos.org/ RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo -RUN sed -i 's/#\(baseurl.*\)mirror.centos.org/\1107.158.252.35/' /etc/yum.repos.d/*.repo +RUN sed -i 's|#\(baseurl.*\)mirror.centos.org/centos/$releasever|\1vault.centos.org/5.11|' /etc/yum.repos.d/*.repo RUN yum upgrade -y && yum install -y \ curl \