From 7f6a53e746a91b7e8383021fef09d8a9fe5cdde8 Mon Sep 17 00:00:00 2001 From: Pramod Bisht Date: Sat, 27 Jan 2018 20:00:59 +0530 Subject: [PATCH 01/52] Changed color of struct link from #ff794d to #2dbfb8 --- src/librustdoc/html/static/themes/dark.css | 2 +- src/librustdoc/html/static/themes/main.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 4c6bcab72b7c9..97a4dba6328f1 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -127,7 +127,7 @@ pre { .content .highlighted.primitive { background-color: #00708a; } .content span.enum, .content a.enum, .block a.current.enum { color: #82b089; } -.content span.struct, .content a.struct, .block a.current.struct { color: #ff794d; } +.content span.struct, .content a.struct, .block a.current.struct { color: #2dbfb8; } .content span.type, .content a.type, .block a.current.type { color: #ff7f00; } .content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #dd7de8; } .content span.macro, .content a.macro, .block a.current.macro { color: #09bd00; } diff --git a/src/librustdoc/html/static/themes/main.css b/src/librustdoc/html/static/themes/main.css index e0764640e9165..a346439da6e6c 100644 --- a/src/librustdoc/html/static/themes/main.css +++ b/src/librustdoc/html/static/themes/main.css @@ -130,7 +130,7 @@ pre { .content .highlighted.primitive { background-color: #9aecff; } .content span.enum, .content a.enum, .block a.current.enum { color: #508157; } -.content span.struct, .content a.struct, .block a.current.struct { color: #df3600; } +.content span.struct, .content a.struct, .block a.current.struct { color: #2dbfb8; } .content span.type, .content a.type, .block a.current.type { color: #ba5d00; } .content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #cd00e2; } .content span.macro, .content a.macro, .block a.current.macro { color: #068000; } From c04d86deeb6d23d8ee4b31abda92bb84c1d17897 Mon Sep 17 00:00:00 2001 From: roblabla Date: Mon, 29 Jan 2018 11:07:11 +0100 Subject: [PATCH 02/52] Work around LLVM OCAML binding installation failure --- src/bootstrap/native.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 3f30756a568ce..bb482813a23fe 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -155,6 +155,7 @@ impl Step for Llvm { .define("WITH_POLLY", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") + .define("LLVM_OCAML_INSTALL_PATH", "usr/lib/ocaml") .define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string()) .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) .define("LLVM_DEFAULT_TARGET_TRIPLE", target); From 434bfb17b4286422b5e3177650aabfd2567b4a19 Mon Sep 17 00:00:00 2001 From: Pramod Bisht Date: Wed, 31 Jan 2018 21:51:27 +0530 Subject: [PATCH 03/52] Changed of `struct` url to `#ad448e` in rust docs --- src/librustdoc/html/static/themes/main.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/themes/main.css b/src/librustdoc/html/static/themes/main.css index a346439da6e6c..2334a2728554e 100644 --- a/src/librustdoc/html/static/themes/main.css +++ b/src/librustdoc/html/static/themes/main.css @@ -130,7 +130,7 @@ pre { .content .highlighted.primitive { background-color: #9aecff; } .content span.enum, .content a.enum, .block a.current.enum { color: #508157; } -.content span.struct, .content a.struct, .block a.current.struct { color: #2dbfb8; } +.content span.struct, .content a.struct, .block a.current.struct { color: #ad448e; } .content span.type, .content a.type, .block a.current.type { color: #ba5d00; } .content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #cd00e2; } .content span.macro, .content a.macro, .block a.current.macro { color: #068000; } From b439632a759447eb56a0190f6c838934bad1e3c7 Mon Sep 17 00:00:00 2001 From: panicbit Date: Sun, 4 Feb 2018 20:40:39 +0100 Subject: [PATCH 04/52] Unimplement Send/Sync for ::env::{Args,ArgsOs,Vars,VarsOs} --- src/libstd/env.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 27bf326631fb0..c4946b6b2824d 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -723,6 +723,12 @@ pub fn args_os() -> ArgsOs { ArgsOs { inner: sys::args::args() } } +#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +impl !Send for Args {} + +#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +impl !Sync for Args {} + #[stable(feature = "env", since = "1.0.0")] impl Iterator for Args { type Item = String; @@ -754,6 +760,12 @@ impl fmt::Debug for Args { } } +#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +impl !Send for ArgsOs {} + +#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +impl !Sync for ArgsOs {} + #[stable(feature = "env", since = "1.0.0")] impl Iterator for ArgsOs { type Item = OsString; From 9bc59865f1042b8c6f3a7c69f0d2643b37a41d75 Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Tue, 6 Feb 2018 08:56:27 +0000 Subject: [PATCH 05/52] 38880 don't compute hash when searching an empty HashMap This addresses issue #38880 --- src/libstd/collections/hash/map.rs | 40 ++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 82a687ae5e493..74c4382f16a5d 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -397,9 +397,21 @@ pub struct HashMap { resize_policy: DefaultResizePolicy, } +/// Search for a pre-hashed key when the hash map is known to be non-empty. +#[inline] +fn search_hashed_nonempty(table: M, hash: SafeHash, is_match: F) + -> InternalEntry + where M: Deref>, + F: FnMut(&K) -> bool +{ + // Do not check the capacity as an extra branch could slow the lookup. + search_hashed_body(table, hash, is_match) +} + /// Search for a pre-hashed key. +/// If you don't already know the hash, use search or search_mut instead #[inline] -fn search_hashed(table: M, hash: SafeHash, mut is_match: F) -> InternalEntry +fn search_hashed(table: M, hash: SafeHash, is_match: F) -> InternalEntry where M: Deref>, F: FnMut(&K) -> bool { @@ -410,6 +422,16 @@ fn search_hashed(table: M, hash: SafeHash, mut is_match: F) -> Inter return InternalEntry::TableIsEmpty; } + search_hashed_body(table, hash, is_match) +} + +/// The body of the search_hashed[_nonempty] functions +#[inline] +fn search_hashed_body(table: M, hash: SafeHash, mut is_match: F) + -> InternalEntry + where M: Deref>, + F: FnMut(&K) -> bool +{ let size = table.size(); let mut probe = Bucket::new(table, hash); let mut displacement = 0; @@ -550,8 +572,12 @@ impl HashMap where K: Borrow, Q: Eq + Hash { - let hash = self.make_hash(q); - search_hashed(&self.table, hash, |k| q.eq(k.borrow())) + if self.table.capacity() != 0 { + let hash = self.make_hash(q); + search_hashed_nonempty(&self.table, hash, |k| q.eq(k.borrow())) + } else { + InternalEntry::TableIsEmpty + } } #[inline] @@ -559,8 +585,12 @@ impl HashMap where K: Borrow, Q: Eq + Hash { - let hash = self.make_hash(q); - search_hashed(&mut self.table, hash, |k| q.eq(k.borrow())) + if self.table.capacity() != 0 { + let hash = self.make_hash(q); + search_hashed_nonempty(&mut self.table, hash, |k| q.eq(k.borrow())) + } else { + InternalEntry::TableIsEmpty + } } // The caller should ensure that invariants by Robin Hood Hashing hold From dcdd2c42d3c7f6125583bcdf0c5ed7e1ef7086db Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Tue, 6 Feb 2018 14:16:54 +0000 Subject: [PATCH 06/52] 38880 use search_mut function rather than search_hashed --- src/libstd/collections/hash/map.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 74c4382f16a5d..04c9f617d019f 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1039,9 +1039,7 @@ impl HashMap pub fn entry(&mut self, key: K) -> Entry { // Gotta resize now. self.reserve(1); - let hash = self.make_hash(&key); - search_hashed(&mut self.table, hash, |q| q.eq(&key)) - .into_entry(key).expect("unreachable") + self.search_mut(&key).into_entry(key).expect("unreachable") } /// Returns the number of elements in the map. From 2a4c0185187dd40683697932c57af608062cb320 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Wed, 7 Feb 2018 12:35:52 -0700 Subject: [PATCH 07/52] Apply optimization from #44355 to retain --- src/liballoc/vec.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index b26979c7f6d8c..a906628dbc734 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -813,14 +813,19 @@ impl Vec { for i in 0..len { if !f(&v[i]) { del += 1; + unsafe { + ptr::read(&v[i]); + } } else if del > 0 { - v.swap(i - del, i); + let src: *const T = &v[i]; + let dst: *mut T = &mut v[i - del]; + unsafe { + ptr::copy_nonoverlapping(src, dst, 1); + } } } } - if del > 0 { - self.truncate(len - del); - } + self.len = len - del; } /// Removes all but the first of consecutive elements in the vector that resolve to the same From a67749ae87b1c873ed09fca2a204beff2fe5e7ea Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Thu, 8 Feb 2018 08:27:53 -0700 Subject: [PATCH 08/52] Swap `ptr::read` for `ptr::drop_in_place` --- src/liballoc/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index a906628dbc734..41ba8e12105bb 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -814,7 +814,7 @@ impl Vec { if !f(&v[i]) { del += 1; unsafe { - ptr::read(&v[i]); + ptr::drop_in_place(&mut v[i]); } } else if del > 0 { let src: *const T = &v[i]; From 4f8049a2b00c46cb1ac77cabaaf716895f185afe Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 9 Feb 2018 01:47:18 -0800 Subject: [PATCH 09/52] Add Range[Inclusive]::is_empty During the RFC, it was discussed that figuring out whether a range is empty was subtle, and thus there should be a clear and obvious way to do it. It can't just be ExactSizeIterator::is_empty (also unstable) because not all ranges are ExactSize -- not even Range or RangeInclusive. --- src/libcore/iter/traits.rs | 2 +- src/libcore/ops/range.rs | 36 ++++++++++++++++++++++++++++++++++-- src/libcore/tests/iter.rs | 4 ++-- src/libcore/tests/lib.rs | 1 + src/libcore/tests/ops.rs | 24 ++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index be4889f24877c..860742d9eab60 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -706,7 +706,7 @@ pub trait ExactSizeIterator: Iterator { /// ``` /// #![feature(exact_size_is_empty)] /// - /// let mut one_element = 0..1; + /// let mut one_element = std::iter::once(0); /// assert!(!one_element.is_empty()); /// /// assert_eq!(one_element.next(), Some(0)); diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 3f573f7c7eb69..102e08362cb4c 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -92,7 +92,6 @@ impl fmt::Debug for Range { } } -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> Range { /// Returns `true` if `item` is contained in the range. /// @@ -109,9 +108,26 @@ impl> Range { /// assert!(!(3..3).contains(3)); /// assert!(!(3..2).contains(3)); /// ``` + #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: Idx) -> bool { (self.start <= item) && (item < self.end) } + + /// Returns `true` if the range contains no items. + /// + /// # Examples + /// + /// ``` + /// #![feature(range_is_empty)] + /// + /// assert!(!(3..5).is_empty()); + /// assert!( (3..3).is_empty()); + /// assert!( (3..2).is_empty()); + /// ``` + #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] + pub fn is_empty(&self) -> bool { + !(self.start < self.end) + } } /// A range only bounded inclusively below (`start..`). @@ -280,7 +296,6 @@ impl fmt::Debug for RangeInclusive { } } -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> RangeInclusive { /// Returns `true` if `item` is contained in the range. /// @@ -298,9 +313,26 @@ impl> RangeInclusive { /// assert!( (3..=3).contains(3)); /// assert!(!(3..=2).contains(3)); /// ``` + #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: Idx) -> bool { self.start <= item && item <= self.end } + + /// Returns `true` if the range contains no items. + /// + /// # Examples + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// assert!(!(3..=5).is_empty()); + /// assert!(!(3..=3).is_empty()); + /// assert!( (3..=2).is_empty()); + /// ``` + #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] + pub fn is_empty(&self) -> bool { + !(self.start <= self.end) + } } /// A range only bounded inclusively above (`..=end`). diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index b2a5243d5e67b..062b6d4126e2c 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1427,9 +1427,9 @@ fn test_range_inclusive_nth() { assert_eq!(r, 13..=20); assert_eq!(r.nth(2), Some(15)); assert_eq!(r, 16..=20); - assert_eq!(r.is_empty(), false); + assert_eq!(ExactSizeIterator::is_empty(&r), false); assert_eq!(r.nth(10), None); - assert_eq!(r.is_empty(), true); + assert_eq!(ExactSizeIterator::is_empty(&r), true); assert_eq!(r, 1..=0); // We may not want to document/promise this detail } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 1c32452f84635..91b4f02594bc3 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -29,6 +29,7 @@ #![feature(iter_rfold)] #![feature(nonzero)] #![feature(pattern)] +#![feature(range_is_empty)] #![feature(raw)] #![feature(refcell_replace_swap)] #![feature(sip_hash_13)] diff --git a/src/libcore/tests/ops.rs b/src/libcore/tests/ops.rs index 9d2fa1abff658..68a692b24a3fb 100644 --- a/src/libcore/tests/ops.rs +++ b/src/libcore/tests/ops.rs @@ -68,3 +68,27 @@ fn test_range_inclusive() { assert_eq!(r.size_hint(), (0, Some(0))); assert_eq!(r.next(), None); } + + +#[test] +fn test_range_is_empty() { + use core::f32::*; + + assert!(!(0.0 .. 10.0).is_empty()); + assert!( (-0.0 .. 0.0).is_empty()); + assert!( (10.0 .. 0.0).is_empty()); + + assert!(!(NEG_INFINITY .. INFINITY).is_empty()); + assert!( (EPSILON .. NAN).is_empty()); + assert!( (NAN .. EPSILON).is_empty()); + assert!( (NAN .. NAN).is_empty()); + + assert!(!(0.0 ..= 10.0).is_empty()); + assert!(!(-0.0 ..= 0.0).is_empty()); + assert!( (10.0 ..= 0.0).is_empty()); + + assert!(!(NEG_INFINITY ..= INFINITY).is_empty()); + assert!( (EPSILON ..= NAN).is_empty()); + assert!( (NAN ..= EPSILON).is_empty()); + assert!( (NAN ..= NAN).is_empty()); +} \ No newline at end of file From 7fe182fdfe01e01dd899962cc8dbaea63f422c9c Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 9 Feb 2018 02:11:04 -0800 Subject: [PATCH 10/52] Fix tidy --- src/libcore/tests/ops.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/tests/ops.rs b/src/libcore/tests/ops.rs index 68a692b24a3fb..bed08f86d72c1 100644 --- a/src/libcore/tests/ops.rs +++ b/src/libcore/tests/ops.rs @@ -91,4 +91,4 @@ fn test_range_is_empty() { assert!( (EPSILON ..= NAN).is_empty()); assert!( (NAN ..= EPSILON).is_empty()); assert!( (NAN ..= NAN).is_empty()); -} \ No newline at end of file +} From b5cb393cf5b4a65fb99d8b1e43450fb87567788b Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 9 Feb 2018 17:54:27 -0800 Subject: [PATCH 11/52] Use is_empty in range iteration exhaustion tests --- src/libcore/ops/range.rs | 18 ++++++++++++ src/libcore/tests/iter.rs | 61 +++++++++++++++++++++++++++++++++------ 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 102e08362cb4c..cce593ee208b6 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -262,6 +262,13 @@ impl> RangeTo { /// The `RangeInclusive` `start..=end` contains all values with `x >= start` /// and `x <= end`. /// +/// This iterator is [fused], but the specific values of `start` and `end` after +/// iteration has finished are **unspecified** other than that [`.is_empty()`] +/// will return `true` once no more values will be produced. +/// +/// [fused]: ../iter/trait.FusedIterator.html +/// [`.is_empty()`]: #method.is_empty +/// /// # Examples /// /// ``` @@ -329,6 +336,17 @@ impl> RangeInclusive { /// assert!(!(3..=3).is_empty()); /// assert!( (3..=2).is_empty()); /// ``` + /// + /// This method returns `true` after iteration has finished: + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// let mut r = 3..=5; + /// for _ in r.by_ref() {} + /// // Precise field values are unspecified here + /// assert!(r.is_empty()); + /// ``` #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] pub fn is_empty(&self) -> bool { !(self.start <= self.end) diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 062b6d4126e2c..d8c9dcd866486 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1322,42 +1322,84 @@ fn test_range() { (isize::MAX as usize + 2, Some(isize::MAX as usize + 2))); } +#[test] +fn test_range_exhaustion() { + let mut r = 10..10; + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next_back(), None); + assert_eq!(r, 10..10); + + let mut r = 10..12; + assert_eq!(r.next(), Some(10)); + assert_eq!(r.next(), Some(11)); + assert!(r.is_empty()); + assert_eq!(r, 12..12); + assert_eq!(r.next(), None); + + let mut r = 10..12; + assert_eq!(r.next_back(), Some(11)); + assert_eq!(r.next_back(), Some(10)); + assert!(r.is_empty()); + assert_eq!(r, 10..10); + assert_eq!(r.next_back(), None); + + let mut r = 100..10; + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next_back(), None); + assert_eq!(r, 100..10); +} + #[test] fn test_range_inclusive_exhaustion() { let mut r = 10..=10; assert_eq!(r.next(), Some(10)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next(), None); let mut r = 10..=10; assert_eq!(r.next_back(), Some(10)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); let mut r = 10..=12; assert_eq!(r.next(), Some(10)); assert_eq!(r.next(), Some(11)); assert_eq!(r.next(), Some(12)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); let mut r = 10..=12; assert_eq!(r.next_back(), Some(12)); assert_eq!(r.next_back(), Some(11)); assert_eq!(r.next_back(), Some(10)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); let mut r = 10..=12; assert_eq!(r.nth(2), Some(12)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); let mut r = 10..=12; assert_eq!(r.nth(5), None); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); let mut r = 100..=10; assert_eq!(r.next(), None); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next(), None); assert_eq!(r, 100..=10); let mut r = 100..=10; assert_eq!(r.next_back(), None); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); + assert_eq!(r.next_back(), None); assert_eq!(r, 100..=10); } @@ -1427,10 +1469,11 @@ fn test_range_inclusive_nth() { assert_eq!(r, 13..=20); assert_eq!(r.nth(2), Some(15)); assert_eq!(r, 16..=20); + assert_eq!(r.is_empty(), false); assert_eq!(ExactSizeIterator::is_empty(&r), false); assert_eq!(r.nth(10), None); + assert_eq!(r.is_empty(), true); assert_eq!(ExactSizeIterator::is_empty(&r), true); - assert_eq!(r, 1..=0); // We may not want to document/promise this detail } #[test] @@ -1514,11 +1557,11 @@ fn test_range_inclusive_folds() { let mut it = 10..=20; assert_eq!(it.try_fold(0, |a,b| Some(a+b)), Some(165)); - assert_eq!(it, 1..=0); + assert!(it.is_empty()); let mut it = 10..=20; assert_eq!(it.try_rfold(0, |a,b| Some(a+b)), Some(165)); - assert_eq!(it, 1..=0); + assert!(it.is_empty()); } #[test] From 6f70a11a831992fe86a935a0d649d3aa6b16dc50 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 9 Feb 2018 18:01:12 -0800 Subject: [PATCH 12/52] range_is_empty tracking issue is #48111 --- src/libcore/ops/range.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index cce593ee208b6..4e4d334752370 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -124,7 +124,7 @@ impl> Range { /// assert!( (3..3).is_empty()); /// assert!( (3..2).is_empty()); /// ``` - #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] + #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] pub fn is_empty(&self) -> bool { !(self.start < self.end) } @@ -347,7 +347,7 @@ impl> RangeInclusive { /// // Precise field values are unspecified here /// assert!(r.is_empty()); /// ``` - #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] + #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] pub fn is_empty(&self) -> bool { !(self.start <= self.end) } From 0cccd9aca51e3fe2952633b34c4c877539d1113d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 6 Feb 2018 14:57:08 +0100 Subject: [PATCH 13/52] Show better warning for trying to cast non-u8 scalar to char --- src/librustc_lint/types.rs | 17 +++++++++++++++++ src/test/ui/cast_char.rs | 20 ++++++++++++++++++++ src/test/ui/cast_char.stderr | 20 ++++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 src/test/ui/cast_char.rs create mode 100644 src/test/ui/cast_char.stderr diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index e7e4119b9999b..f734f3182a931 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -11,6 +11,7 @@ #![allow(non_snake_case)] use rustc::hir::def_id::DefId; +use rustc::hir::map as hir_map; use rustc::ty::subst::Substs; use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::ty::layout::{self, LayoutOf}; @@ -176,6 +177,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { _ => bug!(), }; if lit_val < min || lit_val > max { + let parent_id = cx.tcx.hir.get_parent_node(e.id); + if let hir_map::NodeExpr(parent_expr) = cx.tcx.hir.get(parent_id) { + if let hir::ExprCast(..) = parent_expr.node { + if let ty::TyChar = cx.tables.expr_ty(parent_expr).sty { + let mut err = cx.struct_span_lint( + OVERFLOWING_LITERALS, + parent_expr.span, + "only u8 can be casted into char"); + err.span_suggestion(parent_expr.span, + &"use a char literal instead", + format!("'\\u{{{:X}}}'", lit_val)); + err.emit(); + return + } + } + } cx.span_lint(OVERFLOWING_LITERALS, e.span, &format!("literal out of range for {:?}", t)); diff --git a/src/test/ui/cast_char.rs b/src/test/ui/cast_char.rs new file mode 100644 index 0000000000000..cd8ade5e51a1b --- /dev/null +++ b/src/test/ui/cast_char.rs @@ -0,0 +1,20 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(overflowing_literals)] + +fn main() { + const XYZ: char = 0x1F888 as char; + //~^ ERROR only u8 can be casted into char + const XY: char = 129160 as char; + //~^ ERROR only u8 can be casted into char + const ZYX: char = '\u{01F888}'; + println!("{}", XYZ); +} diff --git a/src/test/ui/cast_char.stderr b/src/test/ui/cast_char.stderr new file mode 100644 index 0000000000000..e42a38dace9d2 --- /dev/null +++ b/src/test/ui/cast_char.stderr @@ -0,0 +1,20 @@ +error: only u8 can be casted into char + --> $DIR/cast_char.rs:14:23 + | +14 | const XYZ: char = 0x1F888 as char; + | ^^^^^^^^^^^^^^^ help: use a char literal instead: `'/u{1F888}'` + | +note: lint level defined here + --> $DIR/cast_char.rs:11:9 + | +11 | #![deny(overflowing_literals)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: only u8 can be casted into char + --> $DIR/cast_char.rs:16:22 + | +16 | const XY: char = 129160 as char; + | ^^^^^^^^^^^^^^ help: use a char literal instead: `'/u{1F888}'` + +error: aborting due to 2 previous errors + From 14f488ee7d05c39b8d6ea2855da274157555df0b Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sat, 10 Feb 2018 19:22:04 +0300 Subject: [PATCH 14/52] Whitelist pclmul x86 feature flag Relevant `stdsimd` [issue](https://github.com/rust-lang-nursery/stdsimd/issues/318). --- src/librustc_trans/llvm_util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 843231d376f6c..f719562b47647 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -88,7 +88,7 @@ const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bm "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0", "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0", "xsave\0", "xsaveopt\0", "xsavec\0", - "xsaves\0", "aes\0", + "xsaves\0", "aes\0", "pclmul\0" "avx512bw\0", "avx512cd\0", "avx512dq\0", "avx512er\0", "avx512f\0", "avx512ifma\0", From 877272ba066dd81d9d920b851d0300bb3e7ee2b3 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sat, 10 Feb 2018 20:07:37 +0300 Subject: [PATCH 15/52] typo fix --- src/librustc_trans/llvm_util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index f719562b47647..21def37e5e6e5 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -88,7 +88,7 @@ const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bm "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0", "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0", "xsave\0", "xsaveopt\0", "xsavec\0", - "xsaves\0", "aes\0", "pclmul\0" + "xsaves\0", "aes\0", "pclmul\0", "avx512bw\0", "avx512cd\0", "avx512dq\0", "avx512er\0", "avx512f\0", "avx512ifma\0", From 3c01dea03e1b4ffbcb665a68bcf228c02497ecdc Mon Sep 17 00:00:00 2001 From: roblabla Date: Sat, 10 Feb 2018 21:29:10 +0100 Subject: [PATCH 16/52] Add comment about the problem, and use provided path if available --- src/bootstrap/native.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index bb482813a23fe..108b0159dce74 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -155,11 +155,18 @@ impl Step for Llvm { .define("WITH_POLLY", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") - .define("LLVM_OCAML_INSTALL_PATH", "usr/lib/ocaml") .define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string()) .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) .define("LLVM_DEFAULT_TARGET_TRIPLE", target); + // By default, LLVM will automatically find OCaml and, if it finds it, + // install the LLVM bindings in LLVM_OCAML_INSTALL_PATH, which defaults + // to /usr/bin/ocaml. + // This causes problem for non-root builds of Rust. Side-step the issue + // by setting LLVM_OCAML_INSTALL_PATH to a relative path, so it installs + // in the prefix. + cfg.define("LLVM_OCAML_INSTALL_PATH", + env::var_os("LLVM_OCAML_INSTALL_PATH").unwrap_or_else(|| "usr/lib/ocaml".into())); // This setting makes the LLVM tools link to the dynamic LLVM library, // which saves both memory during parallel links and overall disk space From 45d5a420ada9c11f61347fd4c63c7f0234adaea7 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sat, 10 Feb 2018 21:20:42 +0000 Subject: [PATCH 17/52] Correct a few stability attributes --- src/libcore/num/mod.rs | 6 +++--- src/libcore/ptr.rs | 4 ++-- src/libcore/time.rs | 4 ++-- src/libstd/io/cursor.rs | 2 +- src/libstd/path.rs | 2 +- src/libsyntax/feature_gate.rs | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 1fae88b9c7775..21d4a486b9833 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2881,7 +2881,7 @@ pub enum FpCategory { issue = "32110")] pub trait Float: Sized { /// Type used by `to_bits` and `from_bits`. - #[stable(feature = "core_float_bits", since = "1.24.0")] + #[stable(feature = "core_float_bits", since = "1.25.0")] type Bits; /// Returns `true` if this value is NaN and false otherwise. @@ -2947,10 +2947,10 @@ pub trait Float: Sized { fn min(self, other: Self) -> Self; /// Raw transmutation to integer. - #[stable(feature = "core_float_bits", since="1.24.0")] + #[stable(feature = "core_float_bits", since="1.25.0")] fn to_bits(self) -> Self::Bits; /// Raw transmutation from integer. - #[stable(feature = "core_float_bits", since="1.24.0")] + #[stable(feature = "core_float_bits", since="1.25.0")] fn from_bits(v: Self::Bits) -> Self; } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 3d84e910fe662..b266771b818e5 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2573,7 +2573,7 @@ impl Clone for NonNull { #[stable(feature = "nonnull", since = "1.25.0")] impl Copy for NonNull { } -#[stable(feature = "nonnull", since = "1.25.0")] +#[unstable(feature = "coerce_unsized", issue = "27732")] impl CoerceUnsized> for NonNull where T: Unsize { } #[stable(feature = "nonnull", since = "1.25.0")] @@ -2621,7 +2621,7 @@ impl hash::Hash for NonNull { } } -#[stable(feature = "nonnull", since = "1.25.0")] +#[unstable(feature = "ptr_internals", issue = "0")] impl From> for NonNull { fn from(unique: Unique) -> Self { NonNull { pointer: unique.pointer } diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 1a0208d2f25b2..b8d0719b9b992 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![stable(feature = "duration_core", since = "1.24.0")] +#![stable(feature = "duration_core", since = "1.25.0")] //! Temporal quantification. //! @@ -58,7 +58,7 @@ const MICROS_PER_SEC: u64 = 1_000_000; /// /// let ten_millis = Duration::from_millis(10); /// ``` -#[stable(feature = "duration_core", since = "1.24.0")] +#[stable(feature = "duration", since = "1.3.0")] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] pub struct Duration { secs: u64, diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index c8447707d5baf..76bcb5fedc94a 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -296,7 +296,7 @@ impl<'a> Write for Cursor<&'a mut [u8]> { fn flush(&mut self) -> io::Result<()> { Ok(()) } } -#[unstable(feature = "cursor_mut_vec", issue = "30132")] +#[stable(feature = "cursor_mut_vec", since = "1.25.0")] impl<'a> Write for Cursor<&'a mut Vec> { fn write(&mut self, buf: &[u8]) -> io::Result { vec_write(&mut self.pos, self.inner, buf) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index ed102c2949ede..e03a182653e5a 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -576,7 +576,7 @@ impl<'a> AsRef for Component<'a> { } } -#[stable(feature = "path_component_asref", since = "1.24.0")] +#[stable(feature = "path_component_asref", since = "1.25.0")] impl<'a> AsRef for Component<'a> { fn as_ref(&self) -> &Path { self.as_os_str().as_ref() diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9c6520cd874a8..f8dbc4d0f4532 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -538,7 +538,7 @@ declare_features! ( // instead of just the platforms on which it is the C ABI (accepted, abi_sysv64, "1.24.0", Some(36167)), // Allows `repr(align(16))` struct attribute (RFC 1358) - (accepted, repr_align, "1.24.0", Some(33626)), + (accepted, repr_align, "1.25.0", Some(33626)), // allow '|' at beginning of match arms (RFC 1925) (accepted, match_beginning_vert, "1.25.0", Some(44101)), // Nested groups in `use` (RFC 2128) From 8be306840f89b92ee49d2c0fae2b189c45706b2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Sun, 11 Feb 2018 02:27:21 +0300 Subject: [PATCH 18/52] added conversion from Rust feature to LLVM feature --- src/librustc_trans/attributes.rs | 5 ++- src/librustc_trans/llvm_util.rs | 72 +++++++++++++++++--------------- 2 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index 6c8088375c4b0..8309c91ab2573 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -142,7 +142,7 @@ pub fn provide(providers: &mut Providers) { assert_eq!(cnum, LOCAL_CRATE); Rc::new(llvm_util::target_feature_whitelist(tcx.sess) .iter() - .map(|c| c.to_str().unwrap().to_string()) + .map(|c| c.to_string()) .collect()) }; @@ -212,7 +212,8 @@ fn from_target_feature( let value = value.as_str(); for feature in value.split(',') { if whitelist.contains(feature) { - target_features.push(format!("+{}", feature)); + let llvm_feature = llvm_util::to_llvm_feature(feature); + target_features.push(format!("+{}", llvm_feature)); continue } diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 21def37e5e6e5..61eefb32e099a 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -79,45 +79,54 @@ unsafe fn configure_llvm(sess: &Session) { // detection code will walk past the end of the feature array, // leading to crashes. -const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "v7\0", "vfp2\0", "vfp3\0", "vfp4\0"]; - -const AARCH64_WHITELIST: &'static [&'static str] = &["neon\0", "v7\0"]; - -const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0", - "sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0", - "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0", - "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0", - "xsave\0", "xsaveopt\0", "xsavec\0", - "xsaves\0", "aes\0", "pclmul\0", - "avx512bw\0", "avx512cd\0", - "avx512dq\0", "avx512er\0", - "avx512f\0", "avx512ifma\0", - "avx512pf\0", "avx512vbmi\0", - "avx512vl\0", "avx512vpopcntdq\0", - "mmx\0", "fxsr\0"]; - -const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx\0", "hvx-double\0"]; - -const POWERPC_WHITELIST: &'static [&'static str] = &["altivec\0", - "power8-altivec\0", "power9-altivec\0", - "power8-vector\0", "power9-vector\0", - "vsx\0"]; - -const MIPS_WHITELIST: &'static [&'static str] = &["msa\0"]; +const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"]; + +const AARCH64_WHITELIST: &'static [&'static str] = &["neon", "v7"]; + +const X86_WHITELIST: &'static [&'static str] = &["avx", "avx2", "bmi", "bmi2", "sse", + "sse2", "sse3", "sse4.1", "sse4.2", + "ssse3", "tbm", "lzcnt", "popcnt", + "sse4a", "rdrnd", "rdseed", "fma", + "xsave", "xsaveopt", "xsavec", + "xsaves", "aes", "pclmulqdq", + "avx512bw", "avx512cd", + "avx512dq", "avx512er", + "avx512f", "avx512ifma", + "avx512pf", "avx512vbmi", + "avx512vl", "avx512vpopcntdq", + "mmx", "fxsr"]; + +const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx", "hvx-double"]; + +const POWERPC_WHITELIST: &'static [&'static str] = &["altivec", + "power8-altivec", "power9-altivec", + "power8-vector", "power9-vector", + "vsx"]; + +const MIPS_WHITELIST: &'static [&'static str] = &["msa"]; + +pub fn to_llvm_feature(s: &str) -> &str { + match s { + "pclmulqdq" => "pclmul", + s => s, + } +} pub fn target_features(sess: &Session) -> Vec { let whitelist = target_feature_whitelist(sess); let target_machine = create_target_machine(sess); let mut features = Vec::new(); - for feat in whitelist { - if unsafe { llvm::LLVMRustHasFeature(target_machine, feat.as_ptr()) } { - features.push(Symbol::intern(feat.to_str().unwrap())); + for feature in whitelist { + let llvm_feature = to_llvm_feature(feature); + let ptr = CString::new(llvm_feature).as_ptr(); + if unsafe { llvm::LLVMRustHasFeature(target_machine, ptr) } { + features.push(Symbol::intern(feature)); } } features } -pub fn target_feature_whitelist(sess: &Session) -> Vec<&CStr> { +pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] { let whitelist = match &*sess.target.target.arch { "arm" => ARM_WHITELIST, "aarch64" => AARCH64_WHITELIST, @@ -126,10 +135,7 @@ pub fn target_feature_whitelist(sess: &Session) -> Vec<&CStr> { "mips" | "mips64" => MIPS_WHITELIST, "powerpc" | "powerpc64" => POWERPC_WHITELIST, _ => &[], - }; - whitelist.iter().map(|m| { - CStr::from_bytes_with_nul(m.as_bytes()).unwrap() - }).collect() + } } pub fn print_version() { From c97aa0911785fc1c1306b38e978093b3153666ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Sun, 11 Feb 2018 02:36:22 +0300 Subject: [PATCH 19/52] iterator instead loop --- src/librustc_trans/llvm_util.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 61eefb32e099a..8839129f3f88e 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -113,17 +113,15 @@ pub fn to_llvm_feature(s: &str) -> &str { } pub fn target_features(sess: &Session) -> Vec { - let whitelist = target_feature_whitelist(sess); let target_machine = create_target_machine(sess); - let mut features = Vec::new(); - for feature in whitelist { - let llvm_feature = to_llvm_feature(feature); - let ptr = CString::new(llvm_feature).as_ptr(); - if unsafe { llvm::LLVMRustHasFeature(target_machine, ptr) } { - features.push(Symbol::intern(feature)); - } - } - features + target_feature_whitelist(sess) + .iter() + .filter(|feature| { + let llvm_feature = to_llvm_feature(feature); + let ptr = CString::new(llvm_feature).as_ptr(); + unsafe { llvm::LLVMRustHasFeature(target_machine, ptr) } + }) + .map(Symbol::intern).collect() } pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] { From 161e8ffda79d25ef7a570bf0c0d884201267c6cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 11 Feb 2018 00:56:24 +0100 Subject: [PATCH 20/52] typo: correct endianess to endianness (this also changes function names!) --- src/librustc_mir/interpret/memory.rs | 32 ++++++++++++++-------------- src/libstd/f32.rs | 2 +- src/libstd/f64.rs | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 3a28eae2d1c49..7cc4ba8489525 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -238,7 +238,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { self.tcx.data_layout.pointer_size.bytes() } - pub fn endianess(&self) -> layout::Endian { + pub fn endianness(&self) -> layout::Endian { self.tcx.data_layout.endian } @@ -722,7 +722,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { pub fn read_primval(&self, ptr: MemoryPointer, ptr_align: Align, size: u64, signed: bool) -> EvalResult<'tcx, PrimVal> { self.check_relocation_edges(ptr, size)?; // Make sure we don't read part of a pointer as a pointer - let endianess = self.endianess(); + let endianness = self.endianness(); let bytes = self.get_bytes_unchecked(ptr, size, ptr_align.min(self.int_align(size)))?; // Undef check happens *after* we established that the alignment is correct. // We must not return Ok() for unaligned pointers! @@ -731,9 +731,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } // Now we do the actual reading let bytes = if signed { - read_target_int(endianess, bytes).unwrap() as u128 + read_target_int(endianness, bytes).unwrap() as u128 } else { - read_target_uint(endianess, bytes).unwrap() + read_target_uint(endianness, bytes).unwrap() }; // See if we got a pointer if size != self.pointer_size() { @@ -756,7 +756,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } pub fn write_primval(&mut self, ptr: MemoryPointer, ptr_align: Align, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> { - let endianess = self.endianess(); + let endianness = self.endianness(); let bytes = match val { PrimVal::Ptr(val) => { @@ -788,9 +788,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { let align = self.int_align(size); let dst = self.get_bytes_mut(ptr, size, ptr_align.min(align))?; if signed { - write_target_int(endianess, dst, bytes as i128).unwrap(); + write_target_int(endianness, dst, bytes as i128).unwrap(); } else { - write_target_uint(endianess, dst, bytes).unwrap(); + write_target_uint(endianness, dst, bytes).unwrap(); } } @@ -941,41 +941,41 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } //////////////////////////////////////////////////////////////////////////////// -// Methods to access integers in the target endianess +// Methods to access integers in the target endianness //////////////////////////////////////////////////////////////////////////////// fn write_target_uint( - endianess: layout::Endian, + endianness: layout::Endian, mut target: &mut [u8], data: u128, ) -> Result<(), io::Error> { let len = target.len(); - match endianess { + match endianness { layout::Endian::Little => target.write_uint128::(data, len), layout::Endian::Big => target.write_uint128::(data, len), } } fn write_target_int( - endianess: layout::Endian, + endianness: layout::Endian, mut target: &mut [u8], data: i128, ) -> Result<(), io::Error> { let len = target.len(); - match endianess { + match endianness { layout::Endian::Little => target.write_int128::(data, len), layout::Endian::Big => target.write_int128::(data, len), } } -fn read_target_uint(endianess: layout::Endian, mut source: &[u8]) -> Result { - match endianess { +fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result { + match endianness { layout::Endian::Little => source.read_uint128::(source.len()), layout::Endian::Big => source.read_uint128::(source.len()), } } -fn read_target_int(endianess: layout::Endian, mut source: &[u8]) -> Result { - match endianess { +fn read_target_int(endianness: layout::Endian, mut source: &[u8]) -> Result { + match endianness { layout::Endian::Little => source.read_int128::(source.len()), layout::Endian::Big => source.read_int128::(source.len()), } diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index ecf68f29d6f1f..a760922115aef 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1023,7 +1023,7 @@ impl f32 { /// This is currently identical to `transmute::(v)` on all platforms. /// It turns out this is incredibly portable, for two reasons: /// - /// * Floats and Ints have the same endianess on all supported platforms. + /// * Floats and Ints have the same endianness on all supported platforms. /// * IEEE-754 very precisely specifies the bit layout of floats. /// /// However there is one caveat: prior to the 2008 version of IEEE-754, how diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 29ba7d0dac635..6f34f176a9711 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -978,7 +978,7 @@ impl f64 { /// This is currently identical to `transmute::(v)` on all platforms. /// It turns out this is incredibly portable, for two reasons: /// - /// * Floats and Ints have the same endianess on all supported platforms. + /// * Floats and Ints have the same endianness on all supported platforms. /// * IEEE-754 very precisely specifies the bit layout of floats. /// /// However there is one caveat: prior to the 2008 version of IEEE-754, how From 7c6adb475abef794cc6b81f6a21094f3257ee37b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Sun, 11 Feb 2018 03:27:04 +0300 Subject: [PATCH 21/52] fixed errors --- src/librustc_trans/llvm_util.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 8839129f3f88e..1f921513fe628 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -14,7 +14,7 @@ use llvm; use rustc::session::Session; use rustc::session::config::PrintRequest; use libc::c_int; -use std::ffi::{CStr, CString}; +use std::ffi::CString; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Once; @@ -118,14 +118,14 @@ pub fn target_features(sess: &Session) -> Vec { .iter() .filter(|feature| { let llvm_feature = to_llvm_feature(feature); - let ptr = CString::new(llvm_feature).as_ptr(); + let ptr = CString::new(llvm_feature).unwrap().as_ptr(); unsafe { llvm::LLVMRustHasFeature(target_machine, ptr) } }) - .map(Symbol::intern).collect() + .map(|feature| Symbol::intern(feature)).collect() } pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] { - let whitelist = match &*sess.target.target.arch { + match &*sess.target.target.arch { "arm" => ARM_WHITELIST, "aarch64" => AARCH64_WHITELIST, "x86" | "x86_64" => X86_WHITELIST, From 22b0489f80dae5242f19c4ce892b50d3685dbf82 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 10 Feb 2018 16:32:05 -0800 Subject: [PATCH 22/52] Add the emptiness condition to the docs; add a PartialOrd example with NAN --- src/libcore/ops/range.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 4e4d334752370..8a45444f1ab0c 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -60,7 +60,7 @@ impl fmt::Debug for RangeFull { /// (`start..end`). /// /// The `Range` `start..end` contains all values with `x >= start` and -/// `x < end`. +/// `x < end`. It is empty unless `start < end`. /// /// # Examples /// @@ -124,6 +124,17 @@ impl> Range { /// assert!( (3..3).is_empty()); /// assert!( (3..2).is_empty()); /// ``` + /// + /// The range is empty if either side is incomparable: + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// use std::f32::NAN; + /// assert!(!(3.0..5.0).is_empty()); + /// assert!( (3.0..NAN).is_empty()); + /// assert!( (NAN..5.0).is_empty()); + /// ``` #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] pub fn is_empty(&self) -> bool { !(self.start < self.end) @@ -260,7 +271,7 @@ impl> RangeTo { /// An range bounded inclusively below and above (`start..=end`). /// /// The `RangeInclusive` `start..=end` contains all values with `x >= start` -/// and `x <= end`. +/// and `x <= end`. It is empty unless `start <= end`. /// /// This iterator is [fused], but the specific values of `start` and `end` after /// iteration has finished are **unspecified** other than that [`.is_empty()`] @@ -337,6 +348,17 @@ impl> RangeInclusive { /// assert!( (3..=2).is_empty()); /// ``` /// + /// The range is empty if either side is incomparable: + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// use std::f32::NAN; + /// assert!(!(3.0..=5.0).is_empty()); + /// assert!( (3.0..=NAN).is_empty()); + /// assert!( (NAN..=5.0).is_empty()); + /// ``` + /// /// This method returns `true` after iteration has finished: /// /// ``` From bf69b0feed33f40ddbef2940b9a3d99845982153 Mon Sep 17 00:00:00 2001 From: kennytm Date: Fri, 26 Jan 2018 03:14:20 +0800 Subject: [PATCH 23/52] Upgrade the Travis CI macOS images for testing from Xcode 8.3 to 9.2. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1007aad925d96..280da05699506 100644 --- a/.travis.yml +++ b/.travis.yml @@ -56,7 +56,7 @@ matrix: NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 os: osx - osx_image: xcode8.3 + osx_image: xcode9.2 if: branch = auto - env: > @@ -70,7 +70,7 @@ matrix: NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 os: osx - osx_image: xcode8.3 + osx_image: xcode9.2 if: branch = auto # OSX builders producing releases. These do not run the full test suite and From c2a31dee835c2312a9e527b1f9ea1b77c24beeab Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sun, 11 Feb 2018 15:57:07 +0300 Subject: [PATCH 24/52] Dangling pointer fix --- src/librustc_trans/llvm_util.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 1f921513fe628..b25562252e72e 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -118,8 +118,8 @@ pub fn target_features(sess: &Session) -> Vec { .iter() .filter(|feature| { let llvm_feature = to_llvm_feature(feature); - let ptr = CString::new(llvm_feature).unwrap().as_ptr(); - unsafe { llvm::LLVMRustHasFeature(target_machine, ptr) } + let cstr = CString::new(llvm_feature).unwrap(); + unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } }) .map(|feature| Symbol::intern(feature)).collect() } From bd426f1d69ec8371d86e06382e96e9ed842f3933 Mon Sep 17 00:00:00 2001 From: Jason Schein Date: Sun, 11 Feb 2018 17:54:44 -0800 Subject: [PATCH 25/52] Update ops range example to avoid confusion between indexes and values. --- src/libcore/ops/range.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 3f573f7c7eb69..a80699c0f5afd 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -68,11 +68,11 @@ impl fmt::Debug for RangeFull { /// assert_eq!((3..5), std::ops::Range { start: 3, end: 5 }); /// assert_eq!(3 + 4 + 5, (3..6).sum()); /// -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ .. ], [0,1,2,3]); -/// assert_eq!(arr[ ..3], [0,1,2 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3]); -/// assert_eq!(arr[1..3], [ 1,2 ]); // Range +/// let arr = ['a', 'b', 'c', 'd']; +/// assert_eq!(arr[ .. ], ['a', 'b', 'c', 'd']); +/// assert_eq!(arr[ ..3], ['a', 'b', 'c', ]); +/// assert_eq!(arr[1.. ], [ 'b', 'c', 'd']); +/// assert_eq!(arr[1..3], [ 'b', 'c' ]); // Range /// ``` #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] From f7cabc6550f23d8a761abf737763a0375a0ac41a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 11 Feb 2018 22:10:35 -0800 Subject: [PATCH 26/52] Continue parsing function after finding `...` arg When encountering a variadic argument in a function definition that doesn't accept it, if immediately after there's a closing paren, continue parsing as normal. Otherwise keep current behavior of emitting error and stopping. --- src/libsyntax/parse/parser.rs | 21 +++++++++++++++----- src/test/ui/invalid-variadic-function.rs | 13 ++++++++++++ src/test/ui/invalid-variadic-function.stderr | 14 +++++++++++++ 3 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/invalid-variadic-function.rs create mode 100644 src/test/ui/invalid-variadic-function.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index dc3745fc4a3ee..ac582627f88fd 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4859,19 +4859,30 @@ impl<'a> Parser<'a> { |p| { if p.token == token::DotDotDot { p.bump(); + variadic = true; if allow_variadic { if p.token != token::CloseDelim(token::Paren) { let span = p.span; p.span_err(span, "`...` must be last in argument list for variadic function"); } + Ok(None) } else { - let span = p.span; - p.span_err(span, - "only foreign functions are allowed to be variadic"); + let span = p.prev_span; + if p.token == token::CloseDelim(token::Paren) { + // continue parsing to present any further errors + p.struct_span_err( + span, + "only foreign functions are allowed to be variadic" + ).emit(); + Ok(Some(dummy_arg(span))) + } else { + // this function definition looks beyond recovery, stop parsing + p.span_err(span, + "only foreign functions are allowed to be variadic"); + Ok(None) + } } - variadic = true; - Ok(None) } else { match p.parse_arg_general(named_args) { Ok(arg) => Ok(Some(arg)), diff --git a/src/test/ui/invalid-variadic-function.rs b/src/test/ui/invalid-variadic-function.rs new file mode 100644 index 0000000000000..3d421e00b08e4 --- /dev/null +++ b/src/test/ui/invalid-variadic-function.rs @@ -0,0 +1,13 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern "C" fn foo(x: u8, ...); +//~^ ERROR only foreign functions are allowed to be variadic +//~| ERROR expected one of `->`, `where`, or `{`, found `;` diff --git a/src/test/ui/invalid-variadic-function.stderr b/src/test/ui/invalid-variadic-function.stderr new file mode 100644 index 0000000000000..15a908b3f00f2 --- /dev/null +++ b/src/test/ui/invalid-variadic-function.stderr @@ -0,0 +1,14 @@ +error: only foreign functions are allowed to be variadic + --> $DIR/invalid-variadic-function.rs:11:26 + | +11 | extern "C" fn foo(x: u8, ...); + | ^^^ + +error: expected one of `->`, `where`, or `{`, found `;` + --> $DIR/invalid-variadic-function.rs:11:30 + | +11 | extern "C" fn foo(x: u8, ...); + | ^ expected one of `->`, `where`, or `{` here + +error: aborting due to 2 previous errors + From 0f789aad2b3cfc0b0925b726295200267130e69d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 08:05:46 +0100 Subject: [PATCH 27/52] add core::iter::repeat_with --- src/libcore/iter/sources.rs | 104 ++++++++++++++++++++++++++++++++++++ src/libcore/tests/iter.rs | 44 +++++++++++++++ 2 files changed, 148 insertions(+) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index b05a893e66104..980f3fc7443ac 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -57,6 +57,12 @@ unsafe impl TrustedLen for Repeat {} /// /// [`take`]: trait.Iterator.html#method.take /// +/// If the element type of the iterator you need does not implement `Clone`, +/// or if you do not want to keep the repeated element in memory, you can +/// instead use the [`repeat_with`] function. +/// +/// [`repeat_with`]: fn.repeat_with.html +/// /// # Examples /// /// Basic usage: @@ -99,6 +105,104 @@ pub fn repeat(elt: T) -> Repeat { Repeat{element: elt} } +/// An iterator that repeats elements of type `A` endlessly by +/// applying the provided closure `F: FnMut() -> A`. +/// +/// This `struct` is created by the [`repeat_with`] function. +/// See its documentation for more. +/// +/// [`repeat_with`]: fn.repeat_with.html +#[unstable(feature = "iterator_repeat_with", issue = "0")] +pub struct RepeatWith { + repeater: F +} + +#[unstable(feature = "iterator_repeat_with", issue = "0")] +impl A> Iterator for RepeatWith { + type Item = A; + + #[inline] + fn next(&mut self) -> Option { Some((self.repeater)()) } + + #[inline] + fn size_hint(&self) -> (usize, Option) { (usize::MAX, None) } +} + +#[unstable(feature = "iterator_repeat_with", issue = "0")] +impl A> DoubleEndedIterator for RepeatWith { + #[inline] + fn next_back(&mut self) -> Option { self.next() } +} + +#[unstable(feature = "fused", issue = "35602")] +impl A> FusedIterator for RepeatWith {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl A> TrustedLen for RepeatWith {} + +/// Creates a new that repeats elements of type `A` endlessly by +/// applying the provided closure, the repeater, `F: FnMut() -> A`. +/// +/// The `repeat_with()` function calls the repeater over and over and over and +/// over and over and 🔁. +/// +/// Infinite iterators like `repeat_with()` are often used with adapters like +/// [`take`], in order to make them finite. +/// +/// [`take`]: trait.Iterator.html#method.take +/// +/// If the element type of the iterator you need implements `Clone`, and +/// it is OK to keep the source element in memory, you should instead use +/// the [`repeat`] function. +/// +/// [`repeat`]: fn.repeat.html +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::iter; +/// +/// // let's assume we have some value of a type that is not `Clone` +/// // or which don't want to have in memory just yet because it is expensive: +/// #[derive(PartialEq, Debug)] +/// struct Expensive; +/// +/// // a particular value forever: +/// let mut things = iter::repeat_with(|| Expensive); +/// +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// ``` +/// +/// Using mutation and going finite: +/// +/// ```rust +/// use std::iter; +/// +/// // From the zeroth to the third power of two: +/// let mut curr = 1; +/// let mut pow2 = iter::repeat_with(|| { let tmp = curr; curr *= 2; tmp }) +/// .take(4); +/// +/// assert_eq!(Some(1), pow2.next()); +/// assert_eq!(Some(2), pow2.next()); +/// assert_eq!(Some(4), pow2.next()); +/// assert_eq!(Some(8), pow2.next()); +/// +/// // ... and now we're done +/// assert_eq!(None, pow2.next()); +/// ``` +#[inline] +#[unstable(feature = "iterator_repeat_with", issue = "0")] +pub fn repeat_with A>(repeater: F) -> RepeatWith { + RepeatWith { repeater } +} + /// An iterator that yields nothing. /// /// This `struct` is created by the [`empty`] function. See its documentation for more. diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index b2a5243d5e67b..ca5318d198e7c 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1549,6 +1549,50 @@ fn test_repeat_take_collect() { assert_eq!(v, vec![42, 42, 42]); } +#[test] +fn test_repeat_with() { + struct NotClone(usize); + let mut it = repeat_with(|| NotClone(42)); + assert_eq!(it.next(), Some(NotClone(42))); + assert_eq!(it.next(), Some(NotClone(42))); + assert_eq!(it.next(), Some(NotClone(42))); + assert_eq!(repeat_with(|| NotClone(42)).size_hint(), (usize::MAX, None)); +} + +#[test] +fn test_repeat_with_rev() { + let mut curr = 1; + let mut pow2 = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) + .rev().take(4); + assert_eq!(it.next(), Some(1)); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.next(), Some(4)); + assert_eq!(it.next(), Some(8)); + assert_eq!(it.next(), None); +} + +#[test] +fn test_repeat_with_take() { + let mut it = repeat_with(|| 42).take(3); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), None); + is_trusted_len(repeat_with(|| 42).take(3)); + assert_eq!(repeat_with(|| 42).take(3).size_hint(), (3, Some(3))); + assert_eq!(repeat_with(|| 42).take(0).size_hint(), (0, Some(0))); + assert_eq!(repeat_with(|| 42).take(usize::MAX).size_hint(), + (usize::MAX, Some(usize::MAX))); +} + +#[test] +fn test_repeat_take_collect() { + let mut curr = 1; + let v: Vec<_> = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) + .take(5).collect(); + assert_eq!(v, vec![1, 2, 4, 8, 16]); +} + #[test] fn test_fuse() { let mut it = 0..3; From c4099ca4b11acb9949ef0da804a819b4ddfa24a2 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 08:25:39 +0100 Subject: [PATCH 28/52] core::iter::repeat_with: general fixes --- src/libcore/iter/mod.rs | 2 ++ src/libcore/iter/sources.rs | 4 ++++ src/libcore/lib.rs | 1 + 3 files changed, 7 insertions(+) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 29b62c901f310..ac3fb5a57dd38 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -333,6 +333,8 @@ pub use self::range::Step; #[stable(feature = "rust1", since = "1.0.0")] pub use self::sources::{Repeat, repeat}; +#[unstable(feature = "iterator_repeat_with", issue = "0")] +pub use self::sources::{RepeatWith, repeat_with}; #[stable(feature = "iter_empty", since = "1.2.0")] pub use self::sources::{Empty, empty}; #[stable(feature = "iter_once", since = "1.2.0")] diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 980f3fc7443ac..2cf90fd079e22 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -162,6 +162,8 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Basic usage: /// /// ``` +/// #![feature("iterator_repeat_with")] +/// /// use std::iter; /// /// // let's assume we have some value of a type that is not `Clone` @@ -182,6 +184,8 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Using mutation and going finite: /// /// ```rust +/// #![feature("iterator_repeat_with")] +/// /// use std::iter; /// /// // From the zeroth to the third power of two: diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 59a296c2a762c..447e144bf0fd6 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -92,6 +92,7 @@ #![feature(unwind_attributes)] #![feature(doc_spotlight)] #![feature(rustc_const_unstable)] +#![feature(iterator_repeat_with)] #[prelude_import] #[allow(unused)] From 1af9ee1350cc69e7c1873d26637064824d07c2b8 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 08:35:12 +0100 Subject: [PATCH 29/52] core::iter::repeat_with: derive Copy, Clone, Debug --- src/libcore/iter/sources.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 2cf90fd079e22..d77e8d4db04a9 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -112,6 +112,7 @@ pub fn repeat(elt: T) -> Repeat { /// See its documentation for more. /// /// [`repeat_with`]: fn.repeat_with.html +#[derive(Copy, Clone, Debug)] #[unstable(feature = "iterator_repeat_with", issue = "0")] pub struct RepeatWith { repeater: F From f025eff21d1832fcd3941ae847fec2aaf23d3b0b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 09:13:47 +0100 Subject: [PATCH 30/52] core::iter::repeat_with: fix tests --- src/libcore/tests/iter.rs | 3 ++- src/libcore/tests/lib.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index ca5318d198e7c..f42970685f57c 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1551,6 +1551,7 @@ fn test_repeat_take_collect() { #[test] fn test_repeat_with() { + #[derive(PartialEq, Debug)] struct NotClone(usize); let mut it = repeat_with(|| NotClone(42)); assert_eq!(it.next(), Some(NotClone(42))); @@ -1586,7 +1587,7 @@ fn test_repeat_with_take() { } #[test] -fn test_repeat_take_collect() { +fn test_repeat_with_take_collect() { let mut curr = 1; let v: Vec<_> = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) .take(5).collect(); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 9e90313bc0e9e..2b9fae88bf497 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -27,6 +27,7 @@ #![feature(iterator_try_fold)] #![feature(iter_rfind)] #![feature(iter_rfold)] +#![feature(iterator_repeat_with)] #![feature(nonzero)] #![feature(pattern)] #![feature(raw)] From 55c669c4d9f7b245e2c237dc2b5d0390afe2620d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 09:15:13 +0100 Subject: [PATCH 31/52] core::iter::repeat_with: fix tests some more --- src/libcore/tests/iter.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index f42970685f57c..4c33c8440a3d0 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1565,11 +1565,11 @@ fn test_repeat_with_rev() { let mut curr = 1; let mut pow2 = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) .rev().take(4); - assert_eq!(it.next(), Some(1)); - assert_eq!(it.next(), Some(2)); - assert_eq!(it.next(), Some(4)); - assert_eq!(it.next(), Some(8)); - assert_eq!(it.next(), None); + assert_eq!(pow2.next(), Some(1)); + assert_eq!(pow2.next(), Some(2)); + assert_eq!(pow2.next(), Some(4)); + assert_eq!(pow2.next(), Some(8)); + assert_eq!(pow2.next(), None); } #[test] From efa332038c74931738c44f48622c2a99b5a36cf0 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 09:18:22 +0100 Subject: [PATCH 32/52] core::iter::repeat_with: fix doc tests --- src/libcore/iter/sources.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index d77e8d4db04a9..b364292f57e94 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -163,7 +163,7 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Basic usage: /// /// ``` -/// #![feature("iterator_repeat_with")] +/// #![feature(iterator_repeat_with)] /// /// use std::iter; /// @@ -185,7 +185,7 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Using mutation and going finite: /// /// ```rust -/// #![feature("iterator_repeat_with")] +/// #![feature(iterator_repeat_with)] /// /// use std::iter; /// From 29f71488bc50843b65660867ab41e6ebf1101e6e Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Mon, 12 Feb 2018 14:00:08 +0000 Subject: [PATCH 33/52] 38880 remove redundant extra function --- src/libstd/collections/hash/map.rs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 04c9f617d019f..d798854927d32 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -397,17 +397,6 @@ pub struct HashMap { resize_policy: DefaultResizePolicy, } -/// Search for a pre-hashed key when the hash map is known to be non-empty. -#[inline] -fn search_hashed_nonempty(table: M, hash: SafeHash, is_match: F) - -> InternalEntry - where M: Deref>, - F: FnMut(&K) -> bool -{ - // Do not check the capacity as an extra branch could slow the lookup. - search_hashed_body(table, hash, is_match) -} - /// Search for a pre-hashed key. /// If you don't already know the hash, use search or search_mut instead #[inline] @@ -422,16 +411,19 @@ fn search_hashed(table: M, hash: SafeHash, is_match: F) -> InternalE return InternalEntry::TableIsEmpty; } - search_hashed_body(table, hash, is_match) + search_hashed_nonempty(table, hash, is_match) } -/// The body of the search_hashed[_nonempty] functions + +/// Search for a pre-hashed key when the hash map is known to be non-empty. #[inline] -fn search_hashed_body(table: M, hash: SafeHash, mut is_match: F) +fn search_hashed_nonempty(table: M, hash: SafeHash, is_match: F) -> InternalEntry where M: Deref>, F: FnMut(&K) -> bool { + // Do not check the capacity as an extra branch could slow the lookup. + let size = table.size(); let mut probe = Bucket::new(table, hash); let mut displacement = 0; From fd78621717e4f9f73b41256627bfe3a83aa5e660 Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Mon, 12 Feb 2018 14:53:09 +0000 Subject: [PATCH 34/52] 38880 fixup add missing mut --- src/libstd/collections/hash/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index d798854927d32..c4f3fdc283ef3 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -417,7 +417,7 @@ fn search_hashed(table: M, hash: SafeHash, is_match: F) -> InternalE /// Search for a pre-hashed key when the hash map is known to be non-empty. #[inline] -fn search_hashed_nonempty(table: M, hash: SafeHash, is_match: F) +fn search_hashed_nonempty(table: M, hash: SafeHash, mut is_match: F) -> InternalEntry where M: Deref>, F: FnMut(&K) -> bool From 0f16eee013aa64108a1b1ca8fa9f9cf263635071 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 25 Jan 2018 21:21:02 -0800 Subject: [PATCH 35/52] rustc: Add the ability to not run dsymutil This commit adds the ability for rustc to not run `dsymutil` by default on OSX. A new codegen option, `-Z run-dsymutil=no`, was added to specify that `dsymutil` should *not* run and instead the compiler should unconditionally keep the object files around in a compilation if necessary for debug information. cc #47240 --- src/librustc/session/config.rs | 2 ++ src/librustc_trans/back/link.rs | 58 +++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 5b8092e86da04..1f40c2db45397 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1320,6 +1320,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "The epoch to build Rust with. Newer epochs may include features that require breaking changes. The default epoch is 2015 (the first epoch). Crates compiled with different epochs can be linked together."), + run_dsymutil: Option = (None, parse_opt_bool, [TRACKED], + "run `dsymutil` and delete intermediate object files"), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index f050edcd513b9..4fe294a790fc4 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -166,7 +166,9 @@ pub(crate) fn link_binary(sess: &Session, // Remove the temporary object file and metadata if we aren't saving temps if !sess.opts.cg.save_temps { - if sess.opts.output_types.should_trans() { + if sess.opts.output_types.should_trans() && + !preserve_objects_for_their_debuginfo(sess) + { for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) { remove(sess, obj); } @@ -190,6 +192,52 @@ pub(crate) fn link_binary(sess: &Session, out_filenames } +/// Returns a boolean indicating whether we should preserve the object files on +/// the filesystem for their debug information. This is often useful with +/// split-dwarf like schemes. +fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool { + // If the objects don't have debuginfo there's nothing to preserve. + if sess.opts.debuginfo == NoDebugInfo { + return false + } + + // If we're only producing artifacts that are archives, no need to preserve + // the objects as they're losslessly contained inside the archives. + let output_linked = sess.crate_types.borrow() + .iter() + .any(|x| *x != config::CrateTypeRlib && *x != config::CrateTypeStaticlib); + if !output_linked { + return false + } + + // If we're on OSX then the equivalent of split dwarf is turned on by + // default. The final executable won't actually have any debug information + // except it'll have pointers to elsewhere. Historically we've always run + // `dsymutil` to "link all the dwarf together" but this is actually sort of + // a bummer for incremental compilation! (the whole point of split dwarf is + // that you don't do this sort of dwarf link). + // + // Basically as a result this just means that if we're on OSX and we're + // *not* running dsymutil then the object files are the only source of truth + // for debug information, so we must preserve them. + if sess.target.target.options.is_like_osx { + match sess.opts.debugging_opts.run_dsymutil { + // dsymutil is not being run, preserve objects + Some(false) => return true, + + // dsymutil is being run, no need to preserve the objects + Some(true) => return false, + + // The default historical behavior was to always run dsymutil, so + // we're preserving that temporarily, but we're likely to switch the + // default soon. + None => return false, + } + } + + false +} + fn filename_for_metadata(sess: &Session, crate_name: &str, outputs: &OutputFilenames) -> PathBuf { let out_filename = outputs.single_output_file.clone() .unwrap_or(outputs @@ -736,8 +784,12 @@ fn link_natively(sess: &Session, // On macOS, debuggers need this utility to get run to do some munging of - // the symbols - if sess.target.target.options.is_like_osx && sess.opts.debuginfo != NoDebugInfo { + // the symbols. Note, though, that if the object files are being preserved + // for their debug information there's no need for us to run dsymutil. + if sess.target.target.options.is_like_osx && + sess.opts.debuginfo != NoDebugInfo && + !preserve_objects_for_their_debuginfo(sess) + { match Command::new("dsymutil").arg(out_filename).output() { Ok(..) => {} Err(e) => sess.fatal(&format!("failed to run dsymutil: {}", e)), From 9cee79a7ff09851109f621bd4510909f5740ae28 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 18:03:56 +0100 Subject: [PATCH 36/52] core::iter::repeat_with: document DoubleEndedIterator behavior --- src/libcore/iter/sources.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index b364292f57e94..abf2befa9cd1d 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -158,6 +158,12 @@ unsafe impl A> TrustedLen for RepeatWith {} /// /// [`repeat`]: fn.repeat.html /// +/// An iterator produced by `repeat_with()` is a `DoubleEndedIterator`. +/// It is important to not that reversing `repeat_with(f)` will produce +/// the exact same sequence as the non-reversed iterator. In other words, +/// `repeat_with(f).rev().collect::>()` is equivalent to +/// `repeat_with(f).collect::>()`. +/// /// # Examples /// /// Basic usage: From 43e8ac27d9bf645b66a15f762be6969e9fe16285 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 12 Feb 2018 08:38:46 -0800 Subject: [PATCH 37/52] rustc: Persist LLVM's `Linker` in Fat LTO This commit updates our Fat LTO logic to tweak our custom wrapper around LLVM's "link modules" functionality. Previously whenever the `LLVMRustLinkInExternalBitcode` function was called it would call LLVM's `Linker::linkModules` wrapper. Internally this would crate an instance of a `Linker` which internally creates an instance of an `IRMover`. Unfortunately for us the creation of `IRMover` is somewhat O(n) with the input module. This means that every time we linked a module it was O(n) with respect to the entire module we had built up! Now the modules we build up during LTO are quite large, so this quickly started creating an O(n^2) problem for us! Discovered in #48025 it turns out this has always been a problem and we just haven't noticed it. It became particularly worse recently though due to most libraries having 16x more object files than they previously did (1 -> 16). This commit fixes this performance issue by preserving the `Linker` instance across all links into the main LLVM module. This means we only create one `IRMover` and allows LTO to progress much speedier. From the `cargo-cache` project in #48025 a **full build** locally when from 5m15s to 2m24s. Looking at the timing logs each object file was linked in in single-digit millisecond rather than hundreds, clearly being a nice improvement! Closes #48025 --- src/librustc_llvm/build.rs | 1 + src/librustc_llvm/ffi.rs | 10 ++++- src/librustc_trans/back/lto.rs | 40 +++++++++++++++---- src/rustllvm/Linker.cpp | 72 ++++++++++++++++++++++++++++++++++ src/rustllvm/RustWrapper.cpp | 40 ------------------- 5 files changed, 114 insertions(+), 49 deletions(-) create mode 100644 src/rustllvm/Linker.cpp diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 49b93f3c7d6a2..54e3f544acb68 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -155,6 +155,7 @@ fn main() { cfg.file("../rustllvm/PassWrapper.cpp") .file("../rustllvm/RustWrapper.cpp") .file("../rustllvm/ArchiveWrapper.cpp") + .file("../rustllvm/Linker.cpp") .cpp(true) .cpp_link_stdlib(None) // we handle this below .compile("rustllvm"); diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 99e43a2ddf98d..e71bef512cf06 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -444,6 +444,9 @@ pub type RustArchiveMemberRef = *mut RustArchiveMember_opaque; #[allow(missing_copy_implementations)] pub enum OperandBundleDef_opaque {} pub type OperandBundleDefRef = *mut OperandBundleDef_opaque; +#[allow(missing_copy_implementations)] +pub enum Linker_opaque {} +pub type LinkerRef = *mut Linker_opaque; pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void); pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint); @@ -1608,7 +1611,6 @@ extern "C" { pub fn LLVMRustPrintPasses(); pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *const c_char); pub fn LLVMRustAddAlwaysInlinePass(P: PassManagerBuilderRef, AddLifetimes: bool); - pub fn LLVMRustLinkInExternalBitcode(M: ModuleRef, bc: *const c_char, len: size_t) -> bool; pub fn LLVMRustRunRestrictionPass(M: ModuleRef, syms: *const *const c_char, len: size_t); pub fn LLVMRustMarkAllFunctionsNounwind(M: ModuleRef); @@ -1724,4 +1726,10 @@ extern "C" { CU2: *mut *mut c_void); pub fn LLVMRustThinLTOPatchDICompileUnit(M: ModuleRef, CU: *mut c_void); pub fn LLVMRustThinLTORemoveAvailableExternally(M: ModuleRef); + + pub fn LLVMRustLinkerNew(M: ModuleRef) -> LinkerRef; + pub fn LLVMRustLinkerAdd(linker: LinkerRef, + bytecode: *const c_char, + bytecode_len: usize) -> bool; + pub fn LLVMRustLinkerFree(linker: LinkerRef); } diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 9ff5bcf7a33ca..a33270380196f 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -247,22 +247,20 @@ fn fat_lto(cgcx: &CodegenContext, // know much about the memory management here so we err on the side of being // save and persist everything with the original module. let mut serialized_bitcode = Vec::new(); + let mut linker = Linker::new(llmod); for (bc_decoded, name) in serialized_modules { info!("linking {:?}", name); - time(cgcx.time_passes, &format!("ll link {:?}", name), || unsafe { + time(cgcx.time_passes, &format!("ll link {:?}", name), || { let data = bc_decoded.data(); - if llvm::LLVMRustLinkInExternalBitcode(llmod, - data.as_ptr() as *const libc::c_char, - data.len() as libc::size_t) { - Ok(()) - } else { + linker.add(&data).map_err(|()| { let msg = format!("failed to load bc of {:?}", name); - Err(write::llvm_err(&diag_handler, msg)) - } + write::llvm_err(&diag_handler, msg) + }) })?; timeline.record(&format!("link {:?}", name)); serialized_bitcode.push(bc_decoded); } + drop(linker); cgcx.save_temp_bitcode(&module, "lto.input"); // Internalize everything that *isn't* in our whitelist to help strip out @@ -289,6 +287,32 @@ fn fat_lto(cgcx: &CodegenContext, }]) } +struct Linker(llvm::LinkerRef); + +impl Linker { + fn new(llmod: ModuleRef) -> Linker { + unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) } + } + + fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> { + unsafe { + if llvm::LLVMRustLinkerAdd(self.0, + bytecode.as_ptr() as *const libc::c_char, + bytecode.len()) { + Ok(()) + } else { + Err(()) + } + } + } +} + +impl Drop for Linker { + fn drop(&mut self) { + unsafe { llvm::LLVMRustLinkerFree(self.0); } + } +} + /// Prepare "thin" LTO to get run on these modules. /// /// The general structure of ThinLTO is quite different from the structure of diff --git a/src/rustllvm/Linker.cpp b/src/rustllvm/Linker.cpp new file mode 100644 index 0000000000000..534e4b910902e --- /dev/null +++ b/src/rustllvm/Linker.cpp @@ -0,0 +1,72 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#include "llvm/Linker/Linker.h" + +#include "rustllvm.h" + +using namespace llvm; + +struct RustLinker { + Linker L; + LLVMContext &Ctx; + + RustLinker(Module &M) : + L(M), + Ctx(M.getContext()) + {} +}; + +extern "C" RustLinker* +LLVMRustLinkerNew(LLVMModuleRef DstRef) { + Module *Dst = unwrap(DstRef); + + auto Ret = llvm::make_unique(*Dst); + return Ret.release(); +} + +extern "C" void +LLVMRustLinkerFree(RustLinker *L) { + delete L; +} + +extern "C" bool +LLVMRustLinkerAdd(RustLinker *L, char *BC, size_t Len) { + std::unique_ptr Buf = + MemoryBuffer::getMemBufferCopy(StringRef(BC, Len)); + +#if LLVM_VERSION_GE(4, 0) + Expected> SrcOrError = + llvm::getLazyBitcodeModule(Buf->getMemBufferRef(), L->Ctx); + if (!SrcOrError) { + LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str()); + return false; + } + + auto Src = std::move(*SrcOrError); +#else + ErrorOr> Src = + llvm::getLazyBitcodeModule(std::move(Buf), L->Ctx); + if (!Src) { + LLVMRustSetLastError(Src.getError().message().c_str()); + return false; + } +#endif + +#if LLVM_VERSION_GE(4, 0) + if (L->L.linkInModule(std::move(Src))) { +#else + if (L->L.linkInModule(std::move(Src.get()))) { +#endif + LLVMRustSetLastError(""); + return false; + } + return true; +} diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 4dfc4029d75dc..27d5496f57628 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -916,46 +916,6 @@ extern "C" void LLVMRustWriteValueToString(LLVMValueRef V, } } -extern "C" bool LLVMRustLinkInExternalBitcode(LLVMModuleRef DstRef, char *BC, - size_t Len) { - Module *Dst = unwrap(DstRef); - - std::unique_ptr Buf = - MemoryBuffer::getMemBufferCopy(StringRef(BC, Len)); - -#if LLVM_VERSION_GE(4, 0) - Expected> SrcOrError = - llvm::getLazyBitcodeModule(Buf->getMemBufferRef(), Dst->getContext()); - if (!SrcOrError) { - LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str()); - return false; - } - - auto Src = std::move(*SrcOrError); -#else - ErrorOr> Src = - llvm::getLazyBitcodeModule(std::move(Buf), Dst->getContext()); - if (!Src) { - LLVMRustSetLastError(Src.getError().message().c_str()); - return false; - } -#endif - - std::string Err; - - raw_string_ostream Stream(Err); - DiagnosticPrinterRawOStream DP(Stream); -#if LLVM_VERSION_GE(4, 0) - if (Linker::linkModules(*Dst, std::move(Src))) { -#else - if (Linker::linkModules(*Dst, std::move(Src.get()))) { -#endif - LLVMRustSetLastError(Err.c_str()); - return false; - } - return true; -} - // Note that the two following functions look quite similar to the // LLVMGetSectionName function. Sadly, it appears that this function only // returns a char* pointer, which isn't guaranteed to be null-terminated. The From 4c658f76c1b51ced4f6c30ea37441c4141659b93 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 12 Feb 2018 10:46:31 -0800 Subject: [PATCH 38/52] Update compiletest's `read2` function This was originally copied over from Cargo and Cargo has since [been updated][update] so let's pull in the fixes here too! [update]: https://github.com/rust-lang/cargo/pull/5030 --- src/tools/compiletest/src/read2.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs index 1d8816c7db132..486c0d81e3f40 100644 --- a/src/tools/compiletest/src/read2.rs +++ b/src/tools/compiletest/src/read2.rs @@ -58,9 +58,12 @@ mod imp { fds[0].events = libc::POLLIN; fds[1].fd = err_pipe.as_raw_fd(); fds[1].events = libc::POLLIN; - loop { + let mut nfds = 2; + let mut errfd = 1; + + while nfds > 0 { // wait for either pipe to become readable using `select` - let r = unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) }; + let r = unsafe { libc::poll(fds.as_mut_ptr(), nfds, -1) }; if r == -1 { let err = io::Error::last_os_error(); if err.kind() == io::ErrorKind::Interrupted { @@ -86,19 +89,20 @@ mod imp { } } }; - if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? { - out_done = true; - } - data(true, &mut out, out_done); - if !err_done && fds[1].revents != 0 && handle(err_pipe.read_to_end(&mut err))? { + if !err_done && fds[errfd].revents != 0 && handle(err_pipe.read_to_end(&mut err))? { err_done = true; + nfds -= 1; } data(false, &mut err, err_done); - - if out_done && err_done { - return Ok(()) + if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? { + out_done = true; + fds[0].fd = err_pipe.as_raw_fd(); + errfd = 0; + nfds -= 1; } + data(true, &mut out, out_done); } + Ok(()) } } From f237e9e2e74dfd5b223589f6254c80e8a69b724e Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Mon, 12 Feb 2018 12:28:32 -0700 Subject: [PATCH 39/52] Remove allocation from width of character function. --- src/libsyntax/codemap.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 3601b9ba8a8c1..ff6f32fc3be0b 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -690,14 +690,16 @@ impl CodeMap { return 1; } + let src = local_begin.fm.external_src.borrow(); + // We need to extend the snippet to the end of the src rather than to end_index so when // searching forwards for boundaries we've got somewhere to search. let snippet = if let Some(ref src) = local_begin.fm.src { let len = src.len(); - (&src[start_index..len]).to_string() - } else if let Some(src) = local_begin.fm.external_src.borrow().get_source() { + (&src[start_index..len]) + } else if let Some(src) = src.get_source() { let len = src.len(); - (&src[start_index..len]).to_string() + (&src[start_index..len]) } else { return 1; }; From 91a4b9044d7f104516984d1076b04b99cef7a6b9 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 21:47:59 +0100 Subject: [PATCH 40/52] core::iter::repeat_with: tracking issue is #48169 --- src/libcore/iter/mod.rs | 2 +- src/libcore/iter/sources.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index ac3fb5a57dd38..d929d1d65a918 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -333,7 +333,7 @@ pub use self::range::Step; #[stable(feature = "rust1", since = "1.0.0")] pub use self::sources::{Repeat, repeat}; -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] pub use self::sources::{RepeatWith, repeat_with}; #[stable(feature = "iter_empty", since = "1.2.0")] pub use self::sources::{Empty, empty}; diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index abf2befa9cd1d..eb8a22709b06e 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -113,12 +113,12 @@ pub fn repeat(elt: T) -> Repeat { /// /// [`repeat_with`]: fn.repeat_with.html #[derive(Copy, Clone, Debug)] -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] pub struct RepeatWith { repeater: F } -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] impl A> Iterator for RepeatWith { type Item = A; @@ -129,7 +129,7 @@ impl A> Iterator for RepeatWith { fn size_hint(&self) -> (usize, Option) { (usize::MAX, None) } } -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] impl A> DoubleEndedIterator for RepeatWith { #[inline] fn next_back(&mut self) -> Option { self.next() } @@ -209,7 +209,7 @@ unsafe impl A> TrustedLen for RepeatWith {} /// assert_eq!(None, pow2.next()); /// ``` #[inline] -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] pub fn repeat_with A>(repeater: F) -> RepeatWith { RepeatWith { repeater } } From db13296b6fd6b68ab06055bdcb9a22078b11de6a Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 13 Feb 2018 06:20:17 +0100 Subject: [PATCH 41/52] core::iter::repeat_with: fix missing word, see @Pazzaz's review --- src/libcore/iter/sources.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index eb8a22709b06e..3e9d799c08948 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -141,7 +141,7 @@ impl A> FusedIterator for RepeatWith {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl A> TrustedLen for RepeatWith {} -/// Creates a new that repeats elements of type `A` endlessly by +/// Creates a new iterator that repeats elements of type `A` endlessly by /// applying the provided closure, the repeater, `F: FnMut() -> A`. /// /// The `repeat_with()` function calls the repeater over and over and over and From 0397fc1b3ad598819b3eedcd7773ef32b2a685b7 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 12 Feb 2018 17:21:01 +0100 Subject: [PATCH 42/52] Handle path prefix mapping in a more stable way when computing the crate hash. --- src/librustc/hir/map/collector.rs | 20 ++++++++++++++++++-- src/librustc/hir/map/mod.rs | 1 + src/librustc/session/config.rs | 6 +++--- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 0e1c66277163e..99b1e5783e01e 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -9,14 +9,15 @@ // except according to those terms. use super::*; - use dep_graph::{DepGraph, DepKind, DepNodeIndex}; +use hir::def_id::{LOCAL_CRATE, CrateNum}; use hir::intravisit::{Visitor, NestedVisitorMap}; use hir::svh::Svh; use middle::cstore::CrateStore; use session::CrateDisambiguator; use std::iter::repeat; use syntax::ast::{NodeId, CRATE_NODE_ID}; +use syntax::codemap::CodeMap; use syntax_pos::Span; use ich::StableHashingContext; @@ -123,6 +124,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { pub(super) fn finalize_and_compute_crate_hash(self, crate_disambiguator: CrateDisambiguator, cstore: &CrateStore, + codemap: &CodeMap, commandline_args_hash: u64) -> (Vec>, Svh) { let mut node_hashes: Vec<_> = self @@ -147,11 +149,25 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { (name1, dis1).cmp(&(name2, dis2)) }); + // We hash the final, remapped names of all local source files so we + // don't have to include the path prefix remapping commandline args. + // If we included the full mapping in the SVH, we could only have + // reproducible builds by compiling from the same directory. So we just + // hash the result of the mapping instead of the mapping itself. + let mut source_file_names: Vec<_> = codemap + .files() + .iter() + .filter(|filemap| CrateNum::from_u32(filemap.crate_of_origin) == LOCAL_CRATE) + .map(|filemap| filemap.name_hash) + .collect(); + + source_file_names.sort_unstable(); + let (_, crate_dep_node_index) = self .dep_graph .with_task(DepNode::new_no_params(DepKind::Krate), &self.hcx, - ((node_hashes, upstream_crates), + (((node_hashes, upstream_crates), source_file_names), (commandline_args_hash, crate_disambiguator.to_fingerprint())), identity_fn); diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 5feea602d2814..b6b3e8955351c 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -1065,6 +1065,7 @@ pub fn map_crate<'hir>(sess: &::session::Session, let cmdline_args = sess.opts.dep_tracking_hash(); collector.finalize_and_compute_crate_hash(crate_disambiguator, cstore, + sess.codemap(), cmdline_args) }; diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 5b8092e86da04..82ee7e31dae09 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1269,9 +1269,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "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"), - remap_path_prefix_from: Vec = (vec![], parse_pathbuf_push, [TRACKED], + remap_path_prefix_from: Vec = (vec![], parse_pathbuf_push, [UNTRACKED], "add a source pattern to the file path remapping config"), - remap_path_prefix_to: Vec = (vec![], parse_pathbuf_push, [TRACKED], + remap_path_prefix_to: Vec = (vec![], parse_pathbuf_push, [UNTRACKED], "add a mapping target to the file path remapping config"), force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED], "force all crates to be `rustc_private` unstable"), @@ -1717,7 +1717,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) } let remap_path_prefix_sources = debugging_opts.remap_path_prefix_from.len(); - let remap_path_prefix_targets = debugging_opts.remap_path_prefix_from.len(); + let remap_path_prefix_targets = debugging_opts.remap_path_prefix_to.len(); if remap_path_prefix_targets < remap_path_prefix_sources { for source in &debugging_opts.remap_path_prefix_from[remap_path_prefix_targets..] { From 580dd42cfaefcb3189eab786224403ffe45bd37f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Feb 2018 13:37:32 +0100 Subject: [PATCH 43/52] incr.comp.: Run cache directory garbage collection before loading dep-graph. --- src/librustc_driver/driver.rs | 9 +++++++++ src/librustc_incremental/lib.rs | 1 + src/librustc_incremental/persist/fs.rs | 16 +++++++++++++++- src/librustc_incremental/persist/mod.rs | 3 ++- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index f344624666a6c..b8a1fe9910540 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -660,6 +660,15 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, disambiguator, ); + if sess.opts.incremental.is_some() { + time(time_passes, "garbage collect incremental cache directory", || { + if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) { + warn!("Error while trying to garbage collect incremental \ + compilation cache directory: {}", e); + } + }); + } + // If necessary, compute the dependency graph (in the background). let future_dep_graph = if sess.opts.build_dep_graph() { Some(rustc_incremental::load_dep_graph(sess, time_passes)) diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index b53ee1daada42..65fbd9d0bf8f1 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -46,3 +46,4 @@ pub use persist::in_incr_comp_dir; pub use persist::prepare_session_directory; pub use persist::finalize_session_directory; pub use persist::delete_workproduct_files; +pub use persist::garbage_collect_session_directories; diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index f4171f951f407..795825f180c9d 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -603,7 +603,7 @@ fn timestamp_to_string(timestamp: SystemTime) -> String { } fn string_to_timestamp(s: &str) -> Result { - let micros_since_unix_epoch = u64::from_str_radix(s, 36); + let micros_since_unix_epoch = u64::from_str_radix(s, INT_ENCODE_BASE as u32); if micros_since_unix_epoch.is_err() { return Err(()) @@ -733,6 +733,20 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { }) .collect(); + // Delete all session directories that don't have a lock file. + for directory_name in session_directories { + if !lock_file_to_session_dir.values().any(|dir| *dir == directory_name) { + let path = crate_directory.join(directory_name); + if let Err(err) = safe_remove_dir_all(&path) { + sess.warn(&format!("Failed to garbage collect invalid incremental \ + compilation session directory `{}`: {}", + path.display(), + err)); + } + } + } + + // Now garbage collect the valid session directories. let mut deletion_candidates = vec![]; let mut definitely_delete = vec![]; diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs index 82a43d85bc608..2f864aaefba89 100644 --- a/src/librustc_incremental/persist/mod.rs +++ b/src/librustc_incremental/persist/mod.rs @@ -20,9 +20,10 @@ mod save; mod work_product; mod file_format; -pub use self::fs::prepare_session_directory; pub use self::fs::finalize_session_directory; +pub use self::fs::garbage_collect_session_directories; pub use self::fs::in_incr_comp_dir; +pub use self::fs::prepare_session_directory; pub use self::load::dep_graph_tcx_init; pub use self::load::load_dep_graph; pub use self::load::load_query_result_cache; From 7cf5ea02a94814d52825c742bd1d1415748c505b Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Tue, 13 Feb 2018 08:08:38 -0700 Subject: [PATCH 44/52] Add note about Cargo cwd change to release notes --- RELEASES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index d6f95f52075d2..7a9d256be282f 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -78,6 +78,7 @@ Compatibility Notes - [`column!()` macro is one-based instead of zero-based][46977] - [`fmt::Arguments` can no longer be shared across threads][45198] - [Access to `#[repr(packed)]` struct fields is now unsafe][44884] +- [Cargo sets a different working directory for the compiler][cargo/4788] [44884]: https://github.com/rust-lang/rust/pull/44884 [45198]: https://github.com/rust-lang/rust/pull/45198 @@ -106,6 +107,7 @@ Compatibility Notes [47080]: https://github.com/rust-lang/rust/pull/47080 [47084]: https://github.com/rust-lang/rust/pull/47084 [cargo/4743]: https://github.com/rust-lang/cargo/pull/4743 +[cargo/4788]: https://github.com/rust-lang/cargo/pull/4788 [cargo/4817]: https://github.com/rust-lang/cargo/pull/4817 [`RefCell::replace`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.replace [`RefCell::swap`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.swap From fbad3b2468f46c14d0fd1283aa4935b3d79f007b Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Tue, 13 Feb 2018 08:48:25 -0700 Subject: [PATCH 45/52] Switch to retain calling drain_filter. --- src/liballoc/vec.rs | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 41ba8e12105bb..5c7f8ef73217f 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -805,27 +805,7 @@ impl Vec { pub fn retain(&mut self, mut f: F) where F: FnMut(&T) -> bool { - let len = self.len(); - let mut del = 0; - { - let v = &mut **self; - - for i in 0..len { - if !f(&v[i]) { - del += 1; - unsafe { - ptr::drop_in_place(&mut v[i]); - } - } else if del > 0 { - let src: *const T = &v[i]; - let dst: *mut T = &mut v[i - del]; - unsafe { - ptr::copy_nonoverlapping(src, dst, 1); - } - } - } - } - self.len = len - del; + self.drain_filter(|x| !f(x)); } /// Removes all but the first of consecutive elements in the vector that resolve to the same From a295ec1ec9d7616474a620a8acd15944aaf0c638 Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Tue, 13 Feb 2018 16:32:35 +0000 Subject: [PATCH 46/52] 38880 restore original entry(key) method --- src/libstd/collections/hash/map.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index c4f3fdc283ef3..23a932c7aa360 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1031,7 +1031,9 @@ impl HashMap pub fn entry(&mut self, key: K) -> Entry { // Gotta resize now. self.reserve(1); - self.search_mut(&key).into_entry(key).expect("unreachable") + let hash = self.make_hash(&key); + search_hashed(&mut self.table, hash, |q| q.eq(&key)) + .into_entry(key).expect("unreachable") } /// Returns the number of elements in the map. From 94c3c84b6a9c382862b1f750f782c33256fa58bd Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Tue, 13 Feb 2018 16:33:00 +0000 Subject: [PATCH 47/52] 38880 hashmap check size=0, not just capacity=0 --- src/libstd/collections/hash/map.rs | 54 +++++++++++++----------------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 23a932c7aa360..fdc62be3dd960 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -414,7 +414,6 @@ fn search_hashed(table: M, hash: SafeHash, is_match: F) -> InternalE search_hashed_nonempty(table, hash, is_match) } - /// Search for a pre-hashed key when the hash map is known to be non-empty. #[inline] fn search_hashed_nonempty(table: M, hash: SafeHash, mut is_match: F) @@ -557,32 +556,36 @@ impl HashMap } /// Search for a key, yielding the index if it's found in the hashtable. - /// If you already have the hash for the key lying around, use - /// search_hashed. + /// If you already have the hash for the key lying around, or if you need an + /// InternalEntry, use search_hashed or search_hashed_nonempty. #[inline] - fn search<'a, Q: ?Sized>(&'a self, q: &Q) -> InternalEntry> + fn search<'a, Q: ?Sized>(&'a self, q: &Q) + -> Option>> where K: Borrow, Q: Eq + Hash { - if self.table.capacity() != 0 { - let hash = self.make_hash(q); - search_hashed_nonempty(&self.table, hash, |k| q.eq(k.borrow())) - } else { - InternalEntry::TableIsEmpty + if !self.is_empty() { + return None; } + + let hash = self.make_hash(q); + search_hashed_nonempty(&self.table, hash, |k| q.eq(k.borrow())) + .into_occupied_bucket() } #[inline] - fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) -> InternalEntry> + fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) + -> Option>> where K: Borrow, Q: Eq + Hash { - if self.table.capacity() != 0 { - let hash = self.make_hash(q); - search_hashed_nonempty(&mut self.table, hash, |k| q.eq(k.borrow())) - } else { - InternalEntry::TableIsEmpty + if self.is_empty() { + return None; } + + let hash = self.make_hash(q); + search_hashed_nonempty(&mut self.table, hash, |k| q.eq(k.borrow())) + .into_occupied_bucket() } // The caller should ensure that invariants by Robin Hood Hashing hold @@ -1140,7 +1143,7 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - self.search(k).into_occupied_bucket().map(|bucket| bucket.into_refs().1) + self.search(k).map(|bucket| bucket.into_refs().1) } /// Returns true if the map contains a value for the specified key. @@ -1167,7 +1170,7 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - self.search(k).into_occupied_bucket().is_some() + self.search(k).is_some() } /// Returns a mutable reference to the value corresponding to the key. @@ -1196,7 +1199,7 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - self.search_mut(k).into_occupied_bucket().map(|bucket| bucket.into_mut_refs().1) + self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) } /// Inserts a key-value pair into the map. @@ -1256,11 +1259,7 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - if self.table.size() == 0 { - return None; - } - - self.search_mut(k).into_occupied_bucket().map(|bucket| pop_internal(bucket).1) + self.search_mut(k).map(|bucket| pop_internal(bucket).1) } /// Removes a key from the map, returning the stored key and value if the @@ -1296,7 +1295,6 @@ impl HashMap } self.search_mut(k) - .into_occupied_bucket() .map(|bucket| { let (k, v, _) = pop_internal(bucket); (k, v) @@ -2654,15 +2652,11 @@ impl super::Recover for HashMap #[inline] fn get(&self, key: &Q) -> Option<&K> { - self.search(key).into_occupied_bucket().map(|bucket| bucket.into_refs().0) + self.search(key).map(|bucket| bucket.into_refs().0) } fn take(&mut self, key: &Q) -> Option { - if self.table.size() == 0 { - return None; - } - - self.search_mut(key).into_occupied_bucket().map(|bucket| pop_internal(bucket).0) + self.search_mut(key).map(|bucket| pop_internal(bucket).0) } #[inline] From f3330cea7f43288362fec9b010b04e22dfbf45a2 Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Tue, 13 Feb 2018 17:15:58 +0000 Subject: [PATCH 48/52] 38880 fix incorrect negation --- src/libstd/collections/hash/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index fdc62be3dd960..a8f419d6c6c80 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -564,7 +564,7 @@ impl HashMap where K: Borrow, Q: Eq + Hash { - if !self.is_empty() { + if self.is_empty() { return None; } From e034dddb32cd9814d9f71bb2b444f9863fba2dfc Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Tue, 13 Feb 2018 20:25:10 +0000 Subject: [PATCH 49/52] 38880 remove unnecessary self.table.size check --- src/libstd/collections/hash/map.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a8f419d6c6c80..a82ff915093c6 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1290,10 +1290,6 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - if self.table.size() == 0 { - return None; - } - self.search_mut(k) .map(|bucket| { let (k, v, _) = pop_internal(bucket); From 893fc3274477fe22fb3b481583df9d0b81df718d Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Tue, 13 Feb 2018 22:25:41 +0100 Subject: [PATCH 50/52] Update compiler-builtins to latest master. - Rebase compiler-rt to LLVM 6 - New VFP intrinsics on ARM - Add generic conversion from a narrower to a wider FP type (f32->f64) - Fixes minor issues on _subsf3, __subdf3 and __aeabi_fcmple - Split test suite to a separate crate --- src/libcompiler_builtins | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcompiler_builtins b/src/libcompiler_builtins index 345447948f7a5..266ea0740a5bd 160000 --- a/src/libcompiler_builtins +++ b/src/libcompiler_builtins @@ -1 +1 @@ -Subproject commit 345447948f7a51eca970fa036cefd613d54a4f79 +Subproject commit 266ea0740a5bdd262a38bbd88fb55fc3d2a7a96e From 288c0c3081419c0d522d76cfbb36fabd038ed4f2 Mon Sep 17 00:00:00 2001 From: Jacob Hughes Date: Wed, 14 Feb 2018 11:30:53 +0000 Subject: [PATCH 51/52] Clarified why `Sized` bound not implicit on trait's implicit `Self` type. --- src/libcore/marker.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 3032fb2de33ad..5b482d467bc8d 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -63,9 +63,13 @@ impl !Send for *mut T { } /// struct BarUse(Bar<[i32]>); // OK /// ``` /// -/// The one exception is the implicit `Self` type of a trait, which does not -/// get an implicit `Sized` bound. This is because a `Sized` bound prevents -/// the trait from being used to form a [trait object]: +/// The one exception is the implicit `Self` type of a trait. A trait does not +/// have an implicit `Sized` bound as this is incompatible with [trait object]s +/// where, by definition, one cannot know the size of all possible +/// implementations of the trait. +/// +/// Although Rust will let you bind `Sized` to a trait, you won't +/// be able to use it as a trait object later: /// /// ``` /// # #![allow(unused_variables)] From 38064a9a7ce6b5050ca1d629aef22f17f2548d07 Mon Sep 17 00:00:00 2001 From: Jacob Hughes Date: Wed, 14 Feb 2018 19:14:25 +0000 Subject: [PATCH 52/52] Review change - Expanded on explanation. --- src/libcore/marker.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 5b482d467bc8d..98e0f71eb9356 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -65,11 +65,11 @@ impl !Send for *mut T { } /// /// The one exception is the implicit `Self` type of a trait. A trait does not /// have an implicit `Sized` bound as this is incompatible with [trait object]s -/// where, by definition, one cannot know the size of all possible -/// implementations of the trait. +/// where, by definition, the trait needs to work with all possible implementors, +/// and thus could be any size. /// /// Although Rust will let you bind `Sized` to a trait, you won't -/// be able to use it as a trait object later: +/// be able to use it to form a trait object later: /// /// ``` /// # #![allow(unused_variables)]