diff --git a/Cargo.lock b/Cargo.lock
index 9e7dd54e13532..3af482adc3417 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3189,6 +3189,7 @@ dependencies = [
"rustc_interface",
"rustc_metadata",
"rustc_mir",
+ "rustc_plugin",
"rustc_plugin_impl",
"rustc_save_analysis",
"rustc_target",
@@ -3372,6 +3373,13 @@ dependencies = [
"syntax_pos",
]
+[[package]]
+name = "rustc_plugin"
+version = "0.0.0"
+dependencies = [
+ "rustc_plugin_impl",
+]
+
[[package]]
name = "rustc_plugin_impl"
version = "0.0.0"
diff --git a/src/libcore/iter/adapters/chain.rs b/src/libcore/iter/adapters/chain.rs
index 0b9f7f6b609e7..c9612596b1ba0 100644
--- a/src/libcore/iter/adapters/chain.rs
+++ b/src/libcore/iter/adapters/chain.rs
@@ -173,17 +173,23 @@ impl Iterator for Chain where
#[inline]
fn size_hint(&self) -> (usize, Option) {
- let (a_lower, a_upper) = self.a.size_hint();
- let (b_lower, b_upper) = self.b.size_hint();
+ match self.state {
+ ChainState::Both => {
+ let (a_lower, a_upper) = self.a.size_hint();
+ let (b_lower, b_upper) = self.b.size_hint();
- let lower = a_lower.saturating_add(b_lower);
+ let lower = a_lower.saturating_add(b_lower);
- let upper = match (a_upper, b_upper) {
- (Some(x), Some(y)) => x.checked_add(y),
- _ => None
- };
+ let upper = match (a_upper, b_upper) {
+ (Some(x), Some(y)) => x.checked_add(y),
+ _ => None
+ };
- (lower, upper)
+ (lower, upper)
+ }
+ ChainState::Front => self.a.size_hint(),
+ ChainState::Back => self.b.size_hint(),
+ }
}
}
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index ce5af13d4ca90..bfbbb15c8d488 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -4637,6 +4637,22 @@ impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> {
Some(tail)
}
}
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option {
+ let len = self.len();
+ if n >= len {
+ self.v = &mut [];
+ None
+ } else {
+ let start = (len - 1 - n) * self.chunk_size;
+ let end = start + self.chunk_size;
+ let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
+ let (head, nth_back) = temp.split_at_mut(start);
+ self.v = head;
+ Some(nth_back)
+ }
+ }
}
#[stable(feature = "chunks_exact", since = "1.31.0")]
diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs
index a1a27e1d5380f..3a4f76852a0d7 100644
--- a/src/libcore/tests/iter.rs
+++ b/src/libcore/tests/iter.rs
@@ -152,6 +152,54 @@ fn test_iterator_chain_find() {
assert_eq!(iter.next(), None);
}
+#[test]
+fn test_iterator_chain_size_hint() {
+ struct Iter {
+ is_empty: bool,
+ }
+
+ impl Iterator for Iter {
+ type Item = ();
+
+ // alternates between `None` and `Some(())`
+ fn next(&mut self) -> Option {
+ if self.is_empty {
+ self.is_empty = false;
+ None
+ } else {
+ self.is_empty = true;
+ Some(())
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option) {
+ if self.is_empty {
+ (0, Some(0))
+ } else {
+ (1, Some(1))
+ }
+ }
+ }
+
+ impl DoubleEndedIterator for Iter {
+ fn next_back(&mut self) -> Option {
+ self.next()
+ }
+ }
+
+ // this chains an iterator of length 0 with an iterator of length 1,
+ // so after calling `.next()` once, the iterator is empty and the
+ // state is `ChainState::Back`. `.size_hint()` should now disregard
+ // the size hint of the left iterator
+ let mut iter = Iter { is_empty: true }.chain(once(()));
+ assert_eq!(iter.next(), Some(()));
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+
+ let mut iter = once(()).chain(Iter { is_empty: true });
+ assert_eq!(iter.next_back(), Some(()));
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+}
+
#[test]
fn test_zip_nth() {
let xs = [0, 1, 2, 4, 5];
diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs
index 4790152512a39..6609bc3135ae0 100644
--- a/src/libcore/tests/slice.rs
+++ b/src/libcore/tests/slice.rs
@@ -374,6 +374,25 @@ fn test_chunks_exact_mut_nth() {
assert_eq!(c2.next(), None);
}
+#[test]
+fn test_chunks_exact_mut_nth_back() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let mut c = v.chunks_exact_mut(2);
+ assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[0, 1]);
+ assert_eq!(c.next(), None);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let mut c2 = v2.chunks_exact_mut(3);
+ assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]);
+ assert_eq!(c2.next(), None);
+ assert_eq!(c2.next_back(), None);
+
+ let v3: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let mut c3 = v3.chunks_exact_mut(10);
+ assert_eq!(c3.nth_back(0), None);
+}
+
#[test]
fn test_chunks_exact_mut_last() {
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index f7a423092acbd..b030517e28ec2 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -20,6 +20,7 @@ rustc_data_structures = { path = "../librustc_data_structures" }
errors = { path = "../librustc_errors", package = "rustc_errors" }
rustc_metadata = { path = "../librustc_metadata" }
rustc_mir = { path = "../librustc_mir" }
+rustc_plugin = { path = "../librustc_plugin/deprecated" } # To get this in the sysroot
rustc_plugin_impl = { path = "../librustc_plugin" }
rustc_save_analysis = { path = "../librustc_save_analysis" }
rustc_codegen_utils = { path = "../librustc_codegen_utils" }
diff --git a/src/librustc_plugin/deprecated/lib.rs b/src/librustc_plugin/deprecated/lib.rs
index 5fb18066759c6..1d0afe84c25a8 100644
--- a/src/librustc_plugin/deprecated/lib.rs
+++ b/src/librustc_plugin/deprecated/lib.rs
@@ -1,6 +1,6 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(staged_api)]
-#![unstable(feature = "rustc_plugin", issue = "29597")]
+#![unstable(feature = "rustc_private", issue = "27812")]
#![rustc_deprecated(since = "1.38.0", reason = "\
import this through `rustc_driver::plugin` instead to make TLS work correctly. \
See https://github.com/rust-lang/rust/issues/62717")]
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index f2b6ce6feb295..5060f368229bb 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -353,12 +353,17 @@ fn append_to_string(buf: &mut String, f: F) -> Result
// Because we're extending the buffer with uninitialized data for trusted
// readers, we need to make sure to truncate that if any of this panics.
fn read_to_end(r: &mut R, buf: &mut Vec) -> Result {
- read_to_end_with_reservation(r, buf, 32)
+ read_to_end_with_reservation(r, buf, |_| 32)
}
-fn read_to_end_with_reservation(r: &mut R,
- buf: &mut Vec,
- reservation_size: usize) -> Result
+fn read_to_end_with_reservation(
+ r: &mut R,
+ buf: &mut Vec,
+ mut reservation_size: F,
+) -> Result
+where
+ R: Read + ?Sized,
+ F: FnMut(&R) -> usize,
{
let start_len = buf.len();
let mut g = Guard { len: buf.len(), buf: buf };
@@ -366,7 +371,7 @@ fn read_to_end_with_reservation(r: &mut R,
loop {
if g.len == g.buf.len() {
unsafe {
- g.buf.reserve(reservation_size);
+ g.buf.reserve(reservation_size(r));
let capacity = g.buf.capacity();
g.buf.set_len(capacity);
r.initializer().initialize(&mut g.buf[g.len..]);
@@ -2253,9 +2258,10 @@ impl Read for Take {
}
fn read_to_end(&mut self, buf: &mut Vec) -> Result {
- let reservation_size = cmp::min(self.limit, 32) as usize;
-
- read_to_end_with_reservation(self, buf, reservation_size)
+ // Pass in a reservation_size closure that respects the current value
+ // of limit for each read. If we hit the read limit, this prevents the
+ // final zero-byte read from allocating again.
+ read_to_end_with_reservation(self, buf, |self_| cmp::min(self_.limit, 32) as usize)
}
}
@@ -2378,6 +2384,7 @@ impl Iterator for Lines {
#[cfg(test)]
mod tests {
+ use crate::cmp;
use crate::io::prelude::*;
use super::{Cursor, SeekFrom, repeat};
use crate::io::{self, IoSlice, IoSliceMut};
@@ -2651,6 +2658,49 @@ mod tests {
Ok(())
}
+ // A simple example reader which uses the default implementation of
+ // read_to_end.
+ struct ExampleSliceReader<'a> {
+ slice: &'a [u8],
+ }
+
+ impl<'a> Read for ExampleSliceReader<'a> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result {
+ let len = cmp::min(self.slice.len(), buf.len());
+ buf[..len].copy_from_slice(&self.slice[..len]);
+ self.slice = &self.slice[len..];
+ Ok(len)
+ }
+ }
+
+ #[test]
+ fn test_read_to_end_capacity() -> io::Result<()> {
+ let input = &b"foo"[..];
+
+ // read_to_end() generally needs to over-allocate, both for efficiency
+ // and so that it can distinguish EOF. Assert that this is the case
+ // with this simple ExampleSliceReader struct, which uses the default
+ // implementation of read_to_end. Even though vec1 is allocated with
+ // exactly enough capacity for the read, read_to_end will allocate more
+ // space here.
+ let mut vec1 = Vec::with_capacity(input.len());
+ ExampleSliceReader { slice: input }.read_to_end(&mut vec1)?;
+ assert_eq!(vec1.len(), input.len());
+ assert!(vec1.capacity() > input.len(), "allocated more");
+
+ // However, std::io::Take includes an implementation of read_to_end
+ // that will not allocate when the limit has already been reached. In
+ // this case, vec2 never grows.
+ let mut vec2 = Vec::with_capacity(input.len());
+ ExampleSliceReader { slice: input }
+ .take(input.len() as u64)
+ .read_to_end(&mut vec2)?;
+ assert_eq!(vec2.len(), input.len());
+ assert_eq!(vec2.capacity(), input.len(), "did not allocate more");
+
+ Ok(())
+ }
+
#[test]
fn io_slice_mut_advance() {
let mut buf1 = [1; 8];
diff --git a/src/test/ui/non-interger-atomic.rs b/src/test/ui/non-integer-atomic.rs
similarity index 100%
rename from src/test/ui/non-interger-atomic.rs
rename to src/test/ui/non-integer-atomic.rs
diff --git a/src/test/ui/non-interger-atomic.stderr b/src/test/ui/non-integer-atomic.stderr
similarity index 100%
rename from src/test/ui/non-interger-atomic.stderr
rename to src/test/ui/non-integer-atomic.stderr