From a02014280586b53997622c501db00398376967a8 Mon Sep 17 00:00:00 2001 From: Nathan West Date: Thu, 10 Sep 2020 23:39:55 -0400 Subject: [PATCH 01/50] Refactor io/buffered.rs into submodules --- library/std/src/io/buffered.rs | 1325 +---------------- library/std/src/io/buffered/bufreader.rs | 423 ++++++ library/std/src/io/buffered/bufwriter.rs | 387 +++++ library/std/src/io/buffered/linewriter.rs | 232 +++ library/std/src/io/buffered/linewritershim.rs | 270 ++++ 5 files changed, 1331 insertions(+), 1306 deletions(-) create mode 100644 library/std/src/io/buffered/bufreader.rs create mode 100644 library/std/src/io/buffered/bufwriter.rs create mode 100644 library/std/src/io/buffered/linewriter.rs create mode 100644 library/std/src/io/buffered/linewritershim.rs diff --git a/library/std/src/io/buffered.rs b/library/std/src/io/buffered.rs index 97c4b879793b7..7329ea53736ec 100644 --- a/library/std/src/io/buffered.rs +++ b/library/std/src/io/buffered.rs @@ -1,506 +1,21 @@ //! Buffering wrappers for I/O traits +mod bufreader; +mod bufwriter; +mod linewriter; +mod linewritershim; + #[cfg(test)] mod tests; -use crate::io::prelude::*; - -use crate::cmp; use crate::error; use crate::fmt; -use crate::io::{ - self, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, SeekFrom, DEFAULT_BUF_SIZE, -}; -use crate::memchr; - -/// The `BufReader` struct adds buffering to any reader. -/// -/// It can be excessively inefficient to work directly with a [`Read`] instance. -/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`] -/// results in a system call. A `BufReader` performs large, infrequent reads on -/// the underlying [`Read`] and maintains an in-memory buffer of the results. -/// -/// `BufReader` can improve the speed of programs that make *small* and -/// *repeated* read calls to the same file or network socket. It does not -/// help when reading very large amounts at once, or reading just one or a few -/// times. It also provides no advantage when reading from a source that is -/// already in memory, like a [`Vec`]``. -/// -/// When the `BufReader` is dropped, the contents of its buffer will be -/// discarded. Creating multiple instances of a `BufReader` on the same -/// stream can cause data loss. Reading from the underlying reader after -/// unwrapping the `BufReader` with [`BufReader::into_inner`] can also cause -/// data loss. -/// -/// [`TcpStream::read`]: Read::read -/// [`TcpStream`]: crate::net::TcpStream -/// -/// # Examples -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::io::BufReader; -/// use std::fs::File; -/// -/// fn main() -> std::io::Result<()> { -/// let f = File::open("log.txt")?; -/// let mut reader = BufReader::new(f); -/// -/// let mut line = String::new(); -/// let len = reader.read_line(&mut line)?; -/// println!("First line is {} bytes long", len); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct BufReader { - inner: R, - buf: Box<[u8]>, - pos: usize, - cap: usize, -} - -impl BufReader { - /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB, - /// but may change in the future. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let reader = BufReader::new(f); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(inner: R) -> BufReader { - BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) - } - - /// Creates a new `BufReader` with the specified buffer capacity. - /// - /// # Examples - /// - /// Creating a buffer with ten bytes of capacity: - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let reader = BufReader::with_capacity(10, f); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(capacity: usize, inner: R) -> BufReader { - unsafe { - let mut buffer = Vec::with_capacity(capacity); - buffer.set_len(capacity); - inner.initializer().initialize(&mut buffer); - BufReader { inner, buf: buffer.into_boxed_slice(), pos: 0, cap: 0 } - } - } -} - -impl BufReader { - /// Gets a reference to the underlying reader. - /// - /// It is inadvisable to directly read from the underlying reader. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let reader = BufReader::new(f1); - /// - /// let f2 = reader.get_ref(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_ref(&self) -> &R { - &self.inner - } - - /// Gets a mutable reference to the underlying reader. - /// - /// It is inadvisable to directly read from the underlying reader. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let mut reader = BufReader::new(f1); - /// - /// let f2 = reader.get_mut(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut R { - &mut self.inner - } - - /// Returns a reference to the internally buffered data. - /// - /// Unlike [`fill_buf`], this will not attempt to fill the buffer if it is empty. - /// - /// [`fill_buf`]: BufRead::fill_buf - /// - /// # Examples - /// - /// ```no_run - /// use std::io::{BufReader, BufRead}; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let mut reader = BufReader::new(f); - /// assert!(reader.buffer().is_empty()); - /// - /// if reader.fill_buf()?.len() > 0 { - /// assert!(!reader.buffer().is_empty()); - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "bufreader_buffer", since = "1.37.0")] - pub fn buffer(&self) -> &[u8] { - &self.buf[self.pos..self.cap] - } - - /// Returns the number of bytes the internal buffer can hold at once. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::{BufReader, BufRead}; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let mut reader = BufReader::new(f); - /// - /// let capacity = reader.capacity(); - /// let buffer = reader.fill_buf()?; - /// assert!(buffer.len() <= capacity); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "buffered_io_capacity", since = "1.46.0")] - pub fn capacity(&self) -> usize { - self.buf.len() - } - - /// Unwraps this `BufReader`, returning the underlying reader. - /// - /// Note that any leftover data in the internal buffer is lost. Therefore, - /// a following read from the underlying reader may lead to data loss. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let reader = BufReader::new(f1); - /// - /// let f2 = reader.into_inner(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(self) -> R { - self.inner - } - - /// Invalidates all data in the internal buffer. - #[inline] - fn discard_buffer(&mut self) { - self.pos = 0; - self.cap = 0; - } -} - -impl BufReader { - /// Seeks relative to the current position. If the new position lies within the buffer, - /// the buffer will not be flushed, allowing for more efficient seeks. - /// This method does not return the location of the underlying reader, so the caller - /// must track this information themselves if it is required. - #[unstable(feature = "bufreader_seek_relative", issue = "31100")] - pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> { - let pos = self.pos as u64; - if offset < 0 { - if let Some(new_pos) = pos.checked_sub((-offset) as u64) { - self.pos = new_pos as usize; - return Ok(()); - } - } else { - if let Some(new_pos) = pos.checked_add(offset as u64) { - if new_pos <= self.cap as u64 { - self.pos = new_pos as usize; - return Ok(()); - } - } - } - self.seek(SeekFrom::Current(offset)).map(drop) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for BufReader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - // If we don't have any buffered data and we're doing a massive read - // (larger than our internal buffer), bypass our internal buffer - // entirely. - if self.pos == self.cap && buf.len() >= self.buf.len() { - self.discard_buffer(); - return self.inner.read(buf); - } - let nread = { - let mut rem = self.fill_buf()?; - rem.read(buf)? - }; - self.consume(nread); - Ok(nread) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - let total_len = bufs.iter().map(|b| b.len()).sum::(); - if self.pos == self.cap && total_len >= self.buf.len() { - self.discard_buffer(); - return self.inner.read_vectored(bufs); - } - let nread = { - let mut rem = self.fill_buf()?; - rem.read_vectored(bufs)? - }; - self.consume(nread); - Ok(nread) - } - - fn is_read_vectored(&self) -> bool { - self.inner.is_read_vectored() - } - - // we can't skip unconditionally because of the large buffer case in read. - unsafe fn initializer(&self) -> Initializer { - self.inner.initializer() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl BufRead for BufReader { - fn fill_buf(&mut self) -> io::Result<&[u8]> { - // If we've reached the end of our internal buffer then we need to fetch - // some more data from the underlying reader. - // Branch using `>=` instead of the more correct `==` - // to tell the compiler that the pos..cap slice is always valid. - if self.pos >= self.cap { - debug_assert!(self.pos == self.cap); - self.cap = self.inner.read(&mut self.buf)?; - self.pos = 0; - } - Ok(&self.buf[self.pos..self.cap]) - } - - fn consume(&mut self, amt: usize) { - self.pos = cmp::min(self.pos + amt, self.cap); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for BufReader -where - R: fmt::Debug, -{ - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("BufReader") - .field("reader", &self.inner) - .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len())) - .finish() - } -} +use crate::io::Error; -#[stable(feature = "rust1", since = "1.0.0")] -impl Seek for BufReader { - /// Seek to an offset, in bytes, in the underlying reader. - /// - /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the - /// position the underlying reader would be at if the `BufReader` had no - /// internal buffer. - /// - /// Seeking always discards the internal buffer, even if the seek position - /// would otherwise fall within it. This guarantees that calling - /// [`BufReader::into_inner()`] immediately after a seek yields the underlying reader - /// at the same position. - /// - /// To seek without discarding the internal buffer, use [`BufReader::seek_relative`]. - /// - /// See [`std::io::Seek`] for more details. - /// - /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)` - /// where `n` minus the internal buffer length overflows an `i64`, two - /// seeks will be performed instead of one. If the second seek returns - /// [`Err`], the underlying reader will be left at the same position it would - /// have if you called `seek` with [`SeekFrom::Current`]`(0)`. - /// - /// [`std::io::Seek`]: Seek - fn seek(&mut self, pos: SeekFrom) -> io::Result { - let result: u64; - if let SeekFrom::Current(n) = pos { - let remainder = (self.cap - self.pos) as i64; - // it should be safe to assume that remainder fits within an i64 as the alternative - // means we managed to allocate 8 exbibytes and that's absurd. - // But it's not out of the realm of possibility for some weird underlying reader to - // support seeking by i64::MIN so we need to handle underflow when subtracting - // remainder. - if let Some(offset) = n.checked_sub(remainder) { - result = self.inner.seek(SeekFrom::Current(offset))?; - } else { - // seek backwards by our remainder, and then by the offset - self.inner.seek(SeekFrom::Current(-remainder))?; - self.discard_buffer(); - result = self.inner.seek(SeekFrom::Current(n))?; - } - } else { - // Seeking with Start/End doesn't care about our buffer length. - result = self.inner.seek(pos)?; - } - self.discard_buffer(); - Ok(result) - } - - /// Returns the current seek position from the start of the stream. - /// - /// The value returned is equivalent to `self.seek(SeekFrom::Current(0))` - /// but does not flush the internal buffer. Due to this optimization the - /// function does not guarantee that calling `.into_inner()` immediately - /// afterwards will yield the underlying reader at the same position. Use - /// [`BufReader::seek`] instead if you require that guarantee. - /// - /// # Panics - /// - /// This function will panic if the position of the inner reader is smaller - /// than the amount of buffered data. That can happen if the inner reader - /// has an incorrect implementation of [`Seek::stream_position`], or if the - /// position has gone out of sync due to calling [`Seek::seek`] directly on - /// the underlying reader. - /// - /// # Example - /// - /// ```no_run - /// #![feature(seek_convenience)] - /// use std::{ - /// io::{self, BufRead, BufReader, Seek}, - /// fs::File, - /// }; - /// - /// fn main() -> io::Result<()> { - /// let mut f = BufReader::new(File::open("foo.txt")?); - /// - /// let before = f.stream_position()?; - /// f.read_line(&mut String::new())?; - /// let after = f.stream_position()?; - /// - /// println!("The first line was {} bytes long", after - before); - /// Ok(()) - /// } - /// ``` - fn stream_position(&mut self) -> io::Result { - let remainder = (self.cap - self.pos) as u64; - self.inner.stream_position().map(|pos| { - pos.checked_sub(remainder).expect( - "overflow when subtracting remaining buffer size from inner stream position", - ) - }) - } -} - -/// Wraps a writer and buffers its output. -/// -/// It can be excessively inefficient to work directly with something that -/// implements [`Write`]. For example, every call to -/// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A -/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying -/// writer in large, infrequent batches. -/// -/// `BufWriter` can improve the speed of programs that make *small* and -/// *repeated* write calls to the same file or network socket. It does not -/// help when writing very large amounts at once, or writing just one or a few -/// times. It also provides no advantage when writing to a destination that is -/// in memory, like a [`Vec`]`. -/// -/// It is critical to call [`flush`] before `BufWriter` is dropped. Though -/// dropping will attempt to flush the contents of the buffer, any errors -/// that happen in the process of dropping will be ignored. Calling [`flush`] -/// ensures that the buffer is empty and thus dropping will not even attempt -/// file operations. -/// -/// # Examples -/// -/// Let's write the numbers one through ten to a [`TcpStream`]: -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::net::TcpStream; -/// -/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); -/// -/// for i in 0..10 { -/// stream.write(&[i+1]).unwrap(); -/// } -/// ``` -/// -/// Because we're not buffering, we write each one in turn, incurring the -/// overhead of a system call per byte written. We can fix this with a -/// `BufWriter`: -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::io::BufWriter; -/// use std::net::TcpStream; -/// -/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); -/// -/// for i in 0..10 { -/// stream.write(&[i+1]).unwrap(); -/// } -/// stream.flush().unwrap(); -/// ``` -/// -/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped -/// together by the buffer and will all be written out in one system call when -/// the `stream` is flushed. -/// -/// [`TcpStream::write`]: Write::write -/// [`TcpStream`]: crate::net::TcpStream -/// [`flush`]: Write::flush -#[stable(feature = "rust1", since = "1.0.0")] -pub struct BufWriter { - inner: Option, - buf: Vec, - // #30888: If the inner writer panics in a call to write, we don't want to - // write the buffered data a second time in BufWriter's destructor. This - // flag tells the Drop impl if it should skip the flush. - panicked: bool, -} +pub use bufreader::BufReader; +pub use bufwriter::BufWriter; +pub use linewriter::LineWriter; +pub(super) use linewritershim::LineWriterShim; /// An error returned by [`BufWriter::into_inner`] which combines an error that /// happened while writing out the buffer, and the buffered writer object @@ -530,321 +45,19 @@ pub struct BufWriter { #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoInnerError(W, Error); -impl BufWriter { - /// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB, - /// but may change in the future. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(inner: W) -> BufWriter { - BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) - } - - /// Creates a new `BufWriter` with the specified buffer capacity. - /// - /// # Examples - /// - /// Creating a buffer with a buffer of a hundred bytes. - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap(); - /// let mut buffer = BufWriter::with_capacity(100, stream); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(capacity: usize, inner: W) -> BufWriter { - BufWriter { inner: Some(inner), buf: Vec::with_capacity(capacity), panicked: false } - } - - /// Send data in our local buffer into the inner writer, looping as - /// necessary until either it's all been sent or an error occurs. - /// - /// Because all the data in the buffer has been reported to our owner as - /// "successfully written" (by returning nonzero success values from - /// `write`), any 0-length writes from `inner` must be reported as i/o - /// errors from this method. - fn flush_buf(&mut self) -> io::Result<()> { - /// Helper struct to ensure the buffer is updated after all the writes - /// are complete. It tracks the number of written bytes and drains them - /// all from the front of the buffer when dropped. - struct BufGuard<'a> { - buffer: &'a mut Vec, - written: usize, - } - - impl<'a> BufGuard<'a> { - fn new(buffer: &'a mut Vec) -> Self { - Self { buffer, written: 0 } - } - - /// The unwritten part of the buffer - fn remaining(&self) -> &[u8] { - &self.buffer[self.written..] - } - - /// Flag some bytes as removed from the front of the buffer - fn consume(&mut self, amt: usize) { - self.written += amt; - } - - /// true if all of the bytes have been written - fn done(&self) -> bool { - self.written >= self.buffer.len() - } - } - - impl Drop for BufGuard<'_> { - fn drop(&mut self) { - if self.written > 0 { - self.buffer.drain(..self.written); - } - } - } - - let mut guard = BufGuard::new(&mut self.buf); - let inner = self.inner.as_mut().unwrap(); - while !guard.done() { - self.panicked = true; - let r = inner.write(guard.remaining()); - self.panicked = false; - - match r { - Ok(0) => { - return Err(Error::new( - ErrorKind::WriteZero, - "failed to write the buffered data", - )); - } - Ok(n) => guard.consume(n), - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - Ok(()) - } - - /// Buffer some data without flushing it, regardless of the size of the - /// data. Writes as much as possible without exceeding capacity. Returns - /// the number of bytes written. - fn write_to_buf(&mut self, buf: &[u8]) -> usize { - let available = self.buf.capacity() - self.buf.len(); - let amt_to_buffer = available.min(buf.len()); - self.buf.extend_from_slice(&buf[..amt_to_buffer]); - amt_to_buffer - } - - /// Gets a reference to the underlying writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // we can use reference just like buffer - /// let reference = buffer.get_ref(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_ref(&self) -> &W { - self.inner.as_ref().unwrap() - } - - /// Gets a mutable reference to the underlying writer. - /// - /// It is inadvisable to directly write to the underlying writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // we can use reference just like buffer - /// let reference = buffer.get_mut(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut W { - self.inner.as_mut().unwrap() - } - - /// Returns a reference to the internally buffered data. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // See how many bytes are currently buffered - /// let bytes_buffered = buf_writer.buffer().len(); - /// ``` - #[stable(feature = "bufreader_buffer", since = "1.37.0")] - pub fn buffer(&self) -> &[u8] { - &self.buf - } - - /// Returns the number of bytes the internal buffer can hold without flushing. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // Check the capacity of the inner buffer - /// let capacity = buf_writer.capacity(); - /// // Calculate how many bytes can be written without flushing - /// let without_flush = capacity - buf_writer.buffer().len(); - /// ``` - #[stable(feature = "buffered_io_capacity", since = "1.46.0")] - pub fn capacity(&self) -> usize { - self.buf.capacity() - } - - /// Unwraps this `BufWriter`, returning the underlying writer. - /// - /// The buffer is written out before returning the writer. - /// - /// # Errors - /// - /// An [`Err`] will be returned if an error occurs while flushing the buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // unwrap the TcpStream and flush the buffer - /// let stream = buffer.into_inner().unwrap(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(mut self) -> Result>> { - match self.flush_buf() { - Err(e) => Err(IntoInnerError(self, e)), - Ok(()) => Ok(self.inner.take().unwrap()), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for BufWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { - if self.buf.len() + buf.len() > self.buf.capacity() { - self.flush_buf()?; - } - // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 - if buf.len() >= self.buf.capacity() { - self.panicked = true; - let r = self.get_mut().write(buf); - self.panicked = false; - r - } else { - self.buf.extend_from_slice(buf); - Ok(buf.len()) - } - } - - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - // Normally, `write_all` just calls `write` in a loop. We can do better - // by calling `self.get_mut().write_all()` directly, which avoids - // round trips through the buffer in the event of a series of partial - // writes in some circumstances. - if self.buf.len() + buf.len() > self.buf.capacity() { - self.flush_buf()?; - } - // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 - if buf.len() >= self.buf.capacity() { - self.panicked = true; - let r = self.get_mut().write_all(buf); - self.panicked = false; - r - } else { - self.buf.extend_from_slice(buf); - Ok(()) - } - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let total_len = bufs.iter().map(|b| b.len()).sum::(); - if self.buf.len() + total_len > self.buf.capacity() { - self.flush_buf()?; - } - // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 - if total_len >= self.buf.capacity() { - self.panicked = true; - let r = self.get_mut().write_vectored(bufs); - self.panicked = false; - r - } else { - bufs.iter().for_each(|b| self.buf.extend_from_slice(b)); - Ok(total_len) - } - } - - fn is_write_vectored(&self) -> bool { - self.get_ref().is_write_vectored() - } - - fn flush(&mut self) -> io::Result<()> { - self.flush_buf().and_then(|()| self.get_mut().flush()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for BufWriter -where - W: fmt::Debug, -{ - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("BufWriter") - .field("writer", &self.inner.as_ref().unwrap()) - .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity())) - .finish() +impl IntoInnerError { + /// Construct a new IntoInnerError + fn new(writer: W, error: Error) -> Self { + Self(writer, error) } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Seek for BufWriter { - /// Seek to the offset, in bytes, in the underlying writer. - /// - /// Seeking always writes out the internal buffer before seeking. - fn seek(&mut self, pos: SeekFrom) -> io::Result { - self.flush_buf()?; - self.get_mut().seek(pos) + /// Helper to construct a new IntoInnerError; intended to help with + /// adapters that wrap other adapters + fn new_wrapped(self, f: impl FnOnce(W) -> W2) -> IntoInnerError { + let Self(writer, error) = self; + IntoInnerError::new(f(writer), error) } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Drop for BufWriter { - fn drop(&mut self) { - if self.inner.is_some() && !self.panicked { - // dtors should not panic, so we ignore a failed flush - let _r = self.flush_buf(); - } - } -} - -impl IntoInnerError { /// Returns the error which caused the call to [`BufWriter::into_inner()`] /// to fail. /// @@ -936,503 +149,3 @@ impl fmt::Display for IntoInnerError { self.error().fmt(f) } } - -/// Private helper struct for implementing the line-buffered writing logic. -/// This shim temporarily wraps a BufWriter, and uses its internals to -/// implement a line-buffered writer (specifically by using the internal -/// methods like write_to_buf and flush_buf). In this way, a more -/// efficient abstraction can be created than one that only had access to -/// `write` and `flush`, without needlessly duplicating a lot of the -/// implementation details of BufWriter. This also allows existing -/// `BufWriters` to be temporarily given line-buffering logic; this is what -/// enables Stdout to be alternately in line-buffered or block-buffered mode. -#[derive(Debug)] -pub(super) struct LineWriterShim<'a, W: Write> { - buffer: &'a mut BufWriter, -} - -impl<'a, W: Write> LineWriterShim<'a, W> { - pub fn new(buffer: &'a mut BufWriter) -> Self { - Self { buffer } - } - - /// Get a mutable reference to the inner writer (that is, the writer - /// wrapped by the BufWriter). Be careful with this writer, as writes to - /// it will bypass the buffer. - fn inner_mut(&mut self) -> &mut W { - self.buffer.get_mut() - } - - /// Get the content currently buffered in self.buffer - fn buffered(&self) -> &[u8] { - self.buffer.buffer() - } - - /// Flush the buffer iff the last byte is a newline (indicating that an - /// earlier write only succeeded partially, and we want to retry flushing - /// the buffered line before continuing with a subsequent write) - fn flush_if_completed_line(&mut self) -> io::Result<()> { - match self.buffered().last().copied() { - Some(b'\n') => self.buffer.flush_buf(), - _ => Ok(()), - } - } -} - -impl<'a, W: Write> Write for LineWriterShim<'a, W> { - /// Write some data into this BufReader with line buffering. This means - /// that, if any newlines are present in the data, the data up to the last - /// newline is sent directly to the underlying writer, and data after it - /// is buffered. Returns the number of bytes written. - /// - /// This function operates on a "best effort basis"; in keeping with the - /// convention of `Write::write`, it makes at most one attempt to write - /// new data to the underlying writer. If that write only reports a partial - /// success, the remaining data will be buffered. - /// - /// Because this function attempts to send completed lines to the underlying - /// writer, it will also flush the existing buffer if it ends with a - /// newline, even if the incoming data does not contain any newlines. - fn write(&mut self, buf: &[u8]) -> io::Result { - let newline_idx = match memchr::memrchr(b'\n', buf) { - // If there are no new newlines (that is, if this write is less than - // one line), just do a regular buffered write (which may flush if - // we exceed the inner buffer's size) - None => { - self.flush_if_completed_line()?; - return self.buffer.write(buf); - } - // Otherwise, arrange for the lines to be written directly to the - // inner writer. - Some(newline_idx) => newline_idx + 1, - }; - - // Flush existing content to prepare for our write. We have to do this - // before attempting to write `buf` in order to maintain consistency; - // if we add `buf` to the buffer then try to flush it all at once, - // we're obligated to return Ok(), which would mean suppressing any - // errors that occur during flush. - self.buffer.flush_buf()?; - - // This is what we're going to try to write directly to the inner - // writer. The rest will be buffered, if nothing goes wrong. - let lines = &buf[..newline_idx]; - - // Write `lines` directly to the inner writer. In keeping with the - // `write` convention, make at most one attempt to add new (unbuffered) - // data. Because this write doesn't touch the BufWriter state directly, - // and the buffer is known to be empty, we don't need to worry about - // self.buffer.panicked here. - let flushed = self.inner_mut().write(lines)?; - - // If buffer returns Ok(0), propagate that to the caller without - // doing additional buffering; otherwise we're just guaranteeing - // an "ErrorKind::WriteZero" later. - if flushed == 0 { - return Ok(0); - } - - // Now that the write has succeeded, buffer the rest (or as much of - // the rest as possible). If there were any unwritten newlines, we - // only buffer out to the last unwritten newline that fits in the - // buffer; this helps prevent flushing partial lines on subsequent - // calls to LineWriterShim::write. - - // Handle the cases in order of most-common to least-common, under - // the presumption that most writes succeed in totality, and that most - // writes are smaller than the buffer. - // - Is this a partial line (ie, no newlines left in the unwritten tail) - // - If not, does the data out to the last unwritten newline fit in - // the buffer? - // - If not, scan for the last newline that *does* fit in the buffer - let tail = if flushed >= newline_idx { - &buf[flushed..] - } else if newline_idx - flushed <= self.buffer.capacity() { - &buf[flushed..newline_idx] - } else { - let scan_area = &buf[flushed..]; - let scan_area = &scan_area[..self.buffer.capacity()]; - match memchr::memrchr(b'\n', scan_area) { - Some(newline_idx) => &scan_area[..newline_idx + 1], - None => scan_area, - } - }; - - let buffered = self.buffer.write_to_buf(tail); - Ok(flushed + buffered) - } - - fn flush(&mut self) -> io::Result<()> { - self.buffer.flush() - } - - /// Write some vectored data into this BufReader with line buffering. This - /// means that, if any newlines are present in the data, the data up to - /// and including the buffer containing the last newline is sent directly - /// to the inner writer, and the data after it is buffered. Returns the - /// number of bytes written. - /// - /// This function operates on a "best effort basis"; in keeping with the - /// convention of `Write::write`, it makes at most one attempt to write - /// new data to the underlying writer. - /// - /// Because this function attempts to send completed lines to the underlying - /// writer, it will also flush the existing buffer if it contains any - /// newlines. - /// - /// Because sorting through an array of `IoSlice` can be a bit convoluted, - /// This method differs from write in the following ways: - /// - /// - It attempts to write the full content of all the buffers up to and - /// including the one containing the last newline. This means that it - /// may attempt to write a partial line, that buffer has data past the - /// newline. - /// - If the write only reports partial success, it does not attempt to - /// find the precise location of the written bytes and buffer the rest. - /// - /// If the underlying vector doesn't support vectored writing, we instead - /// simply write the first non-empty buffer with `write`. This way, we - /// get the benefits of more granular partial-line handling without losing - /// anything in efficiency - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - // If there's no specialized behavior for write_vectored, just use - // write. This has the benefit of more granular partial-line handling. - if !self.is_write_vectored() { - return match bufs.iter().find(|buf| !buf.is_empty()) { - Some(buf) => self.write(buf), - None => Ok(0), - }; - } - - // Find the buffer containing the last newline - let last_newline_buf_idx = bufs - .iter() - .enumerate() - .rev() - .find_map(|(i, buf)| memchr::memchr(b'\n', buf).map(|_| i)); - - // If there are no new newlines (that is, if this write is less than - // one line), just do a regular buffered write - let last_newline_buf_idx = match last_newline_buf_idx { - // No newlines; just do a normal buffered write - None => { - self.flush_if_completed_line()?; - return self.buffer.write_vectored(bufs); - } - Some(i) => i, - }; - - // Flush existing content to prepare for our write - self.buffer.flush_buf()?; - - // This is what we're going to try to write directly to the inner - // writer. The rest will be buffered, if nothing goes wrong. - let (lines, tail) = bufs.split_at(last_newline_buf_idx + 1); - - // Write `lines` directly to the inner writer. In keeping with the - // `write` convention, make at most one attempt to add new (unbuffered) - // data. Because this write doesn't touch the BufWriter state directly, - // and the buffer is known to be empty, we don't need to worry about - // self.panicked here. - let flushed = self.inner_mut().write_vectored(lines)?; - - // If inner returns Ok(0), propagate that to the caller without - // doing additional buffering; otherwise we're just guaranteeing - // an "ErrorKind::WriteZero" later. - if flushed == 0 { - return Ok(0); - } - - // Don't try to reconstruct the exact amount written; just bail - // in the event of a partial write - let lines_len = lines.iter().map(|buf| buf.len()).sum(); - if flushed < lines_len { - return Ok(flushed); - } - - // Now that the write has succeeded, buffer the rest (or as much of the - // rest as possible) - let buffered: usize = tail - .iter() - .filter(|buf| !buf.is_empty()) - .map(|buf| self.buffer.write_to_buf(buf)) - .take_while(|&n| n > 0) - .sum(); - - Ok(flushed + buffered) - } - - fn is_write_vectored(&self) -> bool { - self.buffer.is_write_vectored() - } - - /// Write some data into this BufReader with line buffering. This means - /// that, if any newlines are present in the data, the data up to the last - /// newline is sent directly to the underlying writer, and data after it - /// is buffered. - /// - /// Because this function attempts to send completed lines to the underlying - /// writer, it will also flush the existing buffer if it contains any - /// newlines, even if the incoming data does not contain any newlines. - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - match memchr::memrchr(b'\n', buf) { - // If there are no new newlines (that is, if this write is less than - // one line), just do a regular buffered write (which may flush if - // we exceed the inner buffer's size) - None => { - self.flush_if_completed_line()?; - self.buffer.write_all(buf) - } - Some(newline_idx) => { - let (lines, tail) = buf.split_at(newline_idx + 1); - - if self.buffered().is_empty() { - self.inner_mut().write_all(lines)?; - } else { - // If there is any buffered data, we add the incoming lines - // to that buffer before flushing, which saves us at least - // one write call. We can't really do this with `write`, - // since we can't do this *and* not suppress errors *and* - // report a consistent state to the caller in a return - // value, but here in write_all it's fine. - self.buffer.write_all(lines)?; - self.buffer.flush_buf()?; - } - - self.buffer.write_all(tail) - } - } - } -} - -/// Wraps a writer and buffers output to it, flushing whenever a newline -/// (`0x0a`, `'\n'`) is detected. -/// -/// The [`BufWriter`] struct wraps a writer and buffers its output. -/// But it only does this batched write when it goes out of scope, or when the -/// internal buffer is full. Sometimes, you'd prefer to write each line as it's -/// completed, rather than the entire buffer at once. Enter `LineWriter`. It -/// does exactly that. -/// -/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the -/// `LineWriter` goes out of scope or when its internal buffer is full. -/// -/// If there's still a partial line in the buffer when the `LineWriter` is -/// dropped, it will flush those contents. -/// -/// # Examples -/// -/// We can use `LineWriter` to write one line at a time, significantly -/// reducing the number of actual writes to the file. -/// -/// ```no_run -/// use std::fs::{self, File}; -/// use std::io::prelude::*; -/// use std::io::LineWriter; -/// -/// fn main() -> std::io::Result<()> { -/// let road_not_taken = b"I shall be telling this with a sigh -/// Somewhere ages and ages hence: -/// Two roads diverged in a wood, and I - -/// I took the one less traveled by, -/// And that has made all the difference."; -/// -/// let file = File::create("poem.txt")?; -/// let mut file = LineWriter::new(file); -/// -/// file.write_all(b"I shall be telling this with a sigh")?; -/// -/// // No bytes are written until a newline is encountered (or -/// // the internal buffer is filled). -/// assert_eq!(fs::read_to_string("poem.txt")?, ""); -/// file.write_all(b"\n")?; -/// assert_eq!( -/// fs::read_to_string("poem.txt")?, -/// "I shall be telling this with a sigh\n", -/// ); -/// -/// // Write the rest of the poem. -/// file.write_all(b"Somewhere ages and ages hence: -/// Two roads diverged in a wood, and I - -/// I took the one less traveled by, -/// And that has made all the difference.")?; -/// -/// // The last line of the poem doesn't end in a newline, so -/// // we have to flush or drop the `LineWriter` to finish -/// // writing. -/// file.flush()?; -/// -/// // Confirm the whole poem was written. -/// assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct LineWriter { - inner: BufWriter, -} - -impl LineWriter { - /// Creates a new `LineWriter`. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::new(file); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(inner: W) -> LineWriter { - // Lines typically aren't that long, don't use a giant buffer - LineWriter::with_capacity(1024, inner) - } - - /// Creates a new `LineWriter` with a specified capacity for the internal - /// buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::with_capacity(100, file); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(capacity: usize, inner: W) -> LineWriter { - LineWriter { inner: BufWriter::with_capacity(capacity, inner) } - } - - /// Gets a reference to the underlying writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::new(file); - /// - /// let reference = file.get_ref(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_ref(&self) -> &W { - self.inner.get_ref() - } - - /// Gets a mutable reference to the underlying writer. - /// - /// Caution must be taken when calling methods on the mutable reference - /// returned as extra writes could corrupt the output stream. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let mut file = LineWriter::new(file); - /// - /// // we can use reference just like file - /// let reference = file.get_mut(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut W { - self.inner.get_mut() - } - - /// Unwraps this `LineWriter`, returning the underlying writer. - /// - /// The internal buffer is written out before returning the writer. - /// - /// # Errors - /// - /// An [`Err`] will be returned if an error occurs while flushing the buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// - /// let writer: LineWriter = LineWriter::new(file); - /// - /// let file: File = writer.into_inner()?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(self) -> Result>> { - self.inner - .into_inner() - .map_err(|IntoInnerError(buf, e)| IntoInnerError(LineWriter { inner: buf }, e)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for LineWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { - LineWriterShim::new(&mut self.inner).write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.inner.flush() - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - LineWriterShim::new(&mut self.inner).write_vectored(bufs) - } - - fn is_write_vectored(&self) -> bool { - self.inner.is_write_vectored() - } - - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - LineWriterShim::new(&mut self.inner).write_all(buf) - } - - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - LineWriterShim::new(&mut self.inner).write_all_vectored(bufs) - } - - fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { - LineWriterShim::new(&mut self.inner).write_fmt(fmt) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for LineWriter -where - W: fmt::Debug, -{ - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("LineWriter") - .field("writer", &self.inner.inner) - .field( - "buffer", - &format_args!("{}/{}", self.inner.buf.len(), self.inner.buf.capacity()), - ) - .finish() - } -} diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs new file mode 100644 index 0000000000000..8fe29f08a7bd7 --- /dev/null +++ b/library/std/src/io/buffered/bufreader.rs @@ -0,0 +1,423 @@ +use crate::cmp; +use crate::fmt; +use crate::io::{self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, DEFAULT_BUF_SIZE}; + +/// The `BufReader` struct adds buffering to any reader. +/// +/// It can be excessively inefficient to work directly with a [`Read`] instance. +/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`] +/// results in a system call. A `BufReader` performs large, infrequent reads on +/// the underlying [`Read`] and maintains an in-memory buffer of the results. +/// +/// `BufReader` can improve the speed of programs that make *small* and +/// *repeated* read calls to the same file or network socket. It does not +/// help when reading very large amounts at once, or reading just one or a few +/// times. It also provides no advantage when reading from a source that is +/// already in memory, like a [`Vec`]``. +/// +/// When the `BufReader` is dropped, the contents of its buffer will be +/// discarded. Creating multiple instances of a `BufReader` on the same +/// stream can cause data loss. Reading from the underlying reader after +/// unwrapping the `BufReader` with [`BufReader::into_inner`] can also cause +/// data loss. +/// +/// [`TcpStream::read`]: Read::read +/// [`TcpStream`]: crate::net::TcpStream +/// +/// # Examples +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::io::BufReader; +/// use std::fs::File; +/// +/// fn main() -> std::io::Result<()> { +/// let f = File::open("log.txt")?; +/// let mut reader = BufReader::new(f); +/// +/// let mut line = String::new(); +/// let len = reader.read_line(&mut line)?; +/// println!("First line is {} bytes long", len); +/// Ok(()) +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub struct BufReader { + inner: R, + buf: Box<[u8]>, + pos: usize, + cap: usize, +} + +impl BufReader { + /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB, + /// but may change in the future. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let reader = BufReader::new(f); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(inner: R) -> BufReader { + BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) + } + + /// Creates a new `BufReader` with the specified buffer capacity. + /// + /// # Examples + /// + /// Creating a buffer with ten bytes of capacity: + /// + /// ```no_run + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let reader = BufReader::with_capacity(10, f); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(capacity: usize, inner: R) -> BufReader { + unsafe { + let mut buffer = Vec::with_capacity(capacity); + buffer.set_len(capacity); + inner.initializer().initialize(&mut buffer); + BufReader { inner, buf: buffer.into_boxed_slice(), pos: 0, cap: 0 } + } + } +} + +impl BufReader { + /// Gets a reference to the underlying reader. + /// + /// It is inadvisable to directly read from the underlying reader. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f1 = File::open("log.txt")?; + /// let reader = BufReader::new(f1); + /// + /// let f2 = reader.get_ref(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_ref(&self) -> &R { + &self.inner + } + + /// Gets a mutable reference to the underlying reader. + /// + /// It is inadvisable to directly read from the underlying reader. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f1 = File::open("log.txt")?; + /// let mut reader = BufReader::new(f1); + /// + /// let f2 = reader.get_mut(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut R { + &mut self.inner + } + + /// Returns a reference to the internally buffered data. + /// + /// Unlike [`fill_buf`], this will not attempt to fill the buffer if it is empty. + /// + /// [`fill_buf`]: BufRead::fill_buf + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{BufReader, BufRead}; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let mut reader = BufReader::new(f); + /// assert!(reader.buffer().is_empty()); + /// + /// if reader.fill_buf()?.len() > 0 { + /// assert!(!reader.buffer().is_empty()); + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "bufreader_buffer", since = "1.37.0")] + pub fn buffer(&self) -> &[u8] { + &self.buf[self.pos..self.cap] + } + + /// Returns the number of bytes the internal buffer can hold at once. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{BufReader, BufRead}; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let mut reader = BufReader::new(f); + /// + /// let capacity = reader.capacity(); + /// let buffer = reader.fill_buf()?; + /// assert!(buffer.len() <= capacity); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "buffered_io_capacity", since = "1.46.0")] + pub fn capacity(&self) -> usize { + self.buf.len() + } + + /// Unwraps this `BufReader`, returning the underlying reader. + /// + /// Note that any leftover data in the internal buffer is lost. Therefore, + /// a following read from the underlying reader may lead to data loss. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f1 = File::open("log.txt")?; + /// let reader = BufReader::new(f1); + /// + /// let f2 = reader.into_inner(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_inner(self) -> R { + self.inner + } + + /// Invalidates all data in the internal buffer. + #[inline] + fn discard_buffer(&mut self) { + self.pos = 0; + self.cap = 0; + } +} + +impl BufReader { + /// Seeks relative to the current position. If the new position lies within the buffer, + /// the buffer will not be flushed, allowing for more efficient seeks. + /// This method does not return the location of the underlying reader, so the caller + /// must track this information themselves if it is required. + #[unstable(feature = "bufreader_seek_relative", issue = "31100")] + pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> { + let pos = self.pos as u64; + if offset < 0 { + if let Some(new_pos) = pos.checked_sub((-offset) as u64) { + self.pos = new_pos as usize; + return Ok(()); + } + } else { + if let Some(new_pos) = pos.checked_add(offset as u64) { + if new_pos <= self.cap as u64 { + self.pos = new_pos as usize; + return Ok(()); + } + } + } + self.seek(SeekFrom::Current(offset)).map(drop) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Read for BufReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + // If we don't have any buffered data and we're doing a massive read + // (larger than our internal buffer), bypass our internal buffer + // entirely. + if self.pos == self.cap && buf.len() >= self.buf.len() { + self.discard_buffer(); + return self.inner.read(buf); + } + let nread = { + let mut rem = self.fill_buf()?; + rem.read(buf)? + }; + self.consume(nread); + Ok(nread) + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + let total_len = bufs.iter().map(|b| b.len()).sum::(); + if self.pos == self.cap && total_len >= self.buf.len() { + self.discard_buffer(); + return self.inner.read_vectored(bufs); + } + let nread = { + let mut rem = self.fill_buf()?; + rem.read_vectored(bufs)? + }; + self.consume(nread); + Ok(nread) + } + + fn is_read_vectored(&self) -> bool { + self.inner.is_read_vectored() + } + + // we can't skip unconditionally because of the large buffer case in read. + unsafe fn initializer(&self) -> Initializer { + self.inner.initializer() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl BufRead for BufReader { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + // If we've reached the end of our internal buffer then we need to fetch + // some more data from the underlying reader. + // Branch using `>=` instead of the more correct `==` + // to tell the compiler that the pos..cap slice is always valid. + if self.pos >= self.cap { + debug_assert!(self.pos == self.cap); + self.cap = self.inner.read(&mut self.buf)?; + self.pos = 0; + } + Ok(&self.buf[self.pos..self.cap]) + } + + fn consume(&mut self, amt: usize) { + self.pos = cmp::min(self.pos + amt, self.cap); + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for BufReader +where + R: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("BufReader") + .field("reader", &self.inner) + .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len())) + .finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Seek for BufReader { + /// Seek to an offset, in bytes, in the underlying reader. + /// + /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the + /// position the underlying reader would be at if the `BufReader` had no + /// internal buffer. + /// + /// Seeking always discards the internal buffer, even if the seek position + /// would otherwise fall within it. This guarantees that calling + /// [`BufReader::into_inner()`] immediately after a seek yields the underlying reader + /// at the same position. + /// + /// To seek without discarding the internal buffer, use [`BufReader::seek_relative`]. + /// + /// See [`std::io::Seek`] for more details. + /// + /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)` + /// where `n` minus the internal buffer length overflows an `i64`, two + /// seeks will be performed instead of one. If the second seek returns + /// [`Err`], the underlying reader will be left at the same position it would + /// have if you called `seek` with [`SeekFrom::Current`]`(0)`. + /// + /// [`std::io::Seek`]: Seek + fn seek(&mut self, pos: SeekFrom) -> io::Result { + let result: u64; + if let SeekFrom::Current(n) = pos { + let remainder = (self.cap - self.pos) as i64; + // it should be safe to assume that remainder fits within an i64 as the alternative + // means we managed to allocate 8 exbibytes and that's absurd. + // But it's not out of the realm of possibility for some weird underlying reader to + // support seeking by i64::MIN so we need to handle underflow when subtracting + // remainder. + if let Some(offset) = n.checked_sub(remainder) { + result = self.inner.seek(SeekFrom::Current(offset))?; + } else { + // seek backwards by our remainder, and then by the offset + self.inner.seek(SeekFrom::Current(-remainder))?; + self.discard_buffer(); + result = self.inner.seek(SeekFrom::Current(n))?; + } + } else { + // Seeking with Start/End doesn't care about our buffer length. + result = self.inner.seek(pos)?; + } + self.discard_buffer(); + Ok(result) + } + + /// Returns the current seek position from the start of the stream. + /// + /// The value returned is equivalent to `self.seek(SeekFrom::Current(0))` + /// but does not flush the internal buffer. Due to this optimization the + /// function does not guarantee that calling `.into_inner()` immediately + /// afterwards will yield the underlying reader at the same position. Use + /// [`BufReader::seek`] instead if you require that guarantee. + /// + /// # Panics + /// + /// This function will panic if the position of the inner reader is smaller + /// than the amount of buffered data. That can happen if the inner reader + /// has an incorrect implementation of [`Seek::stream_position`], or if the + /// position has gone out of sync due to calling [`Seek::seek`] directly on + /// the underlying reader. + /// + /// # Example + /// + /// ```no_run + /// #![feature(seek_convenience)] + /// use std::{ + /// io::{self, BufRead, BufReader, Seek}, + /// fs::File, + /// }; + /// + /// fn main() -> io::Result<()> { + /// let mut f = BufReader::new(File::open("foo.txt")?); + /// + /// let before = f.stream_position()?; + /// f.read_line(&mut String::new())?; + /// let after = f.stream_position()?; + /// + /// println!("The first line was {} bytes long", after - before); + /// Ok(()) + /// } + /// ``` + fn stream_position(&mut self) -> io::Result { + let remainder = (self.cap - self.pos) as u64; + self.inner.stream_position().map(|pos| { + pos.checked_sub(remainder).expect( + "overflow when subtracting remaining buffer size from inner stream position", + ) + }) + } +} diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs new file mode 100644 index 0000000000000..8ce795a05ed36 --- /dev/null +++ b/library/std/src/io/buffered/bufwriter.rs @@ -0,0 +1,387 @@ +use crate::fmt; +use crate::io::{ + self, Error, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE, +}; + +/// Wraps a writer and buffers its output. +/// +/// It can be excessively inefficient to work directly with something that +/// implements [`Write`]. For example, every call to +/// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A +/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying +/// writer in large, infrequent batches. +/// +/// `BufWriter` can improve the speed of programs that make *small* and +/// *repeated* write calls to the same file or network socket. It does not +/// help when writing very large amounts at once, or writing just one or a few +/// times. It also provides no advantage when writing to a destination that is +/// in memory, like a [`Vec`]`. +/// +/// It is critical to call [`flush`] before `BufWriter` is dropped. Though +/// dropping will attempt to flush the contents of the buffer, any errors +/// that happen in the process of dropping will be ignored. Calling [`flush`] +/// ensures that the buffer is empty and thus dropping will not even attempt +/// file operations. +/// +/// # Examples +/// +/// Let's write the numbers one through ten to a [`TcpStream`]: +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::net::TcpStream; +/// +/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); +/// +/// for i in 0..10 { +/// stream.write(&[i+1]).unwrap(); +/// } +/// ``` +/// +/// Because we're not buffering, we write each one in turn, incurring the +/// overhead of a system call per byte written. We can fix this with a +/// `BufWriter`: +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::io::BufWriter; +/// use std::net::TcpStream; +/// +/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); +/// +/// for i in 0..10 { +/// stream.write(&[i+1]).unwrap(); +/// } +/// stream.flush().unwrap(); +/// ``` +/// +/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped +/// together by the buffer and will all be written out in one system call when +/// the `stream` is flushed. +/// +/// [`TcpStream::write`]: Write::write +/// [`TcpStream`]: crate::net::TcpStream +/// [`flush`]: Write::flush +#[stable(feature = "rust1", since = "1.0.0")] +pub struct BufWriter { + inner: Option, + buf: Vec, + // #30888: If the inner writer panics in a call to write, we don't want to + // write the buffered data a second time in BufWriter's destructor. This + // flag tells the Drop impl if it should skip the flush. + panicked: bool, +} + +impl BufWriter { + /// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB, + /// but may change in the future. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(inner: W) -> BufWriter { + BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) + } + + /// Creates a new `BufWriter` with the specified buffer capacity. + /// + /// # Examples + /// + /// Creating a buffer with a buffer of a hundred bytes. + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap(); + /// let mut buffer = BufWriter::with_capacity(100, stream); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(capacity: usize, inner: W) -> BufWriter { + BufWriter { inner: Some(inner), buf: Vec::with_capacity(capacity), panicked: false } + } + + /// Send data in our local buffer into the inner writer, looping as + /// necessary until either it's all been sent or an error occurs. + /// + /// Because all the data in the buffer has been reported to our owner as + /// "successfully written" (by returning nonzero success values from + /// `write`), any 0-length writes from `inner` must be reported as i/o + /// errors from this method. + pub(super) fn flush_buf(&mut self) -> io::Result<()> { + /// Helper struct to ensure the buffer is updated after all the writes + /// are complete. It tracks the number of written bytes and drains them + /// all from the front of the buffer when dropped. + struct BufGuard<'a> { + buffer: &'a mut Vec, + written: usize, + } + + impl<'a> BufGuard<'a> { + fn new(buffer: &'a mut Vec) -> Self { + Self { buffer, written: 0 } + } + + /// The unwritten part of the buffer + fn remaining(&self) -> &[u8] { + &self.buffer[self.written..] + } + + /// Flag some bytes as removed from the front of the buffer + fn consume(&mut self, amt: usize) { + self.written += amt; + } + + /// true if all of the bytes have been written + fn done(&self) -> bool { + self.written >= self.buffer.len() + } + } + + impl Drop for BufGuard<'_> { + fn drop(&mut self) { + if self.written > 0 { + self.buffer.drain(..self.written); + } + } + } + + let mut guard = BufGuard::new(&mut self.buf); + let inner = self.inner.as_mut().unwrap(); + while !guard.done() { + self.panicked = true; + let r = inner.write(guard.remaining()); + self.panicked = false; + + match r { + Ok(0) => { + return Err(Error::new( + ErrorKind::WriteZero, + "failed to write the buffered data", + )); + } + Ok(n) => guard.consume(n), + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + Ok(()) + } + + /// Buffer some data without flushing it, regardless of the size of the + /// data. Writes as much as possible without exceeding capacity. Returns + /// the number of bytes written. + pub(super) fn write_to_buf(&mut self, buf: &[u8]) -> usize { + let available = self.buf.capacity() - self.buf.len(); + let amt_to_buffer = available.min(buf.len()); + self.buf.extend_from_slice(&buf[..amt_to_buffer]); + amt_to_buffer + } + + /// Gets a reference to the underlying writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // we can use reference just like buffer + /// let reference = buffer.get_ref(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_ref(&self) -> &W { + self.inner.as_ref().unwrap() + } + + /// Gets a mutable reference to the underlying writer. + /// + /// It is inadvisable to directly write to the underlying writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // we can use reference just like buffer + /// let reference = buffer.get_mut(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut W { + self.inner.as_mut().unwrap() + } + + /// Returns a reference to the internally buffered data. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // See how many bytes are currently buffered + /// let bytes_buffered = buf_writer.buffer().len(); + /// ``` + #[stable(feature = "bufreader_buffer", since = "1.37.0")] + pub fn buffer(&self) -> &[u8] { + &self.buf + } + + /// Returns the number of bytes the internal buffer can hold without flushing. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // Check the capacity of the inner buffer + /// let capacity = buf_writer.capacity(); + /// // Calculate how many bytes can be written without flushing + /// let without_flush = capacity - buf_writer.buffer().len(); + /// ``` + #[stable(feature = "buffered_io_capacity", since = "1.46.0")] + pub fn capacity(&self) -> usize { + self.buf.capacity() + } + + /// Unwraps this `BufWriter`, returning the underlying writer. + /// + /// The buffer is written out before returning the writer. + /// + /// # Errors + /// + /// An [`Err`] will be returned if an error occurs while flushing the buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // unwrap the TcpStream and flush the buffer + /// let stream = buffer.into_inner().unwrap(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_inner(mut self) -> Result>> { + match self.flush_buf() { + Err(e) => Err(IntoInnerError::new(self, e)), + Ok(()) => Ok(self.inner.take().unwrap()), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Write for BufWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + if self.buf.len() + buf.len() > self.buf.capacity() { + self.flush_buf()?; + } + // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 + if buf.len() >= self.buf.capacity() { + self.panicked = true; + let r = self.get_mut().write(buf); + self.panicked = false; + r + } else { + self.buf.extend_from_slice(buf); + Ok(buf.len()) + } + } + + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + // Normally, `write_all` just calls `write` in a loop. We can do better + // by calling `self.get_mut().write_all()` directly, which avoids + // round trips through the buffer in the event of a series of partial + // writes in some circumstances. + if self.buf.len() + buf.len() > self.buf.capacity() { + self.flush_buf()?; + } + // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 + if buf.len() >= self.buf.capacity() { + self.panicked = true; + let r = self.get_mut().write_all(buf); + self.panicked = false; + r + } else { + self.buf.extend_from_slice(buf); + Ok(()) + } + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let total_len = bufs.iter().map(|b| b.len()).sum::(); + if self.buf.len() + total_len > self.buf.capacity() { + self.flush_buf()?; + } + // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 + if total_len >= self.buf.capacity() { + self.panicked = true; + let r = self.get_mut().write_vectored(bufs); + self.panicked = false; + r + } else { + bufs.iter().for_each(|b| self.buf.extend_from_slice(b)); + Ok(total_len) + } + } + + fn is_write_vectored(&self) -> bool { + self.get_ref().is_write_vectored() + } + + fn flush(&mut self) -> io::Result<()> { + self.flush_buf().and_then(|()| self.get_mut().flush()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for BufWriter +where + W: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("BufWriter") + .field("writer", &self.inner.as_ref().unwrap()) + .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity())) + .finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Seek for BufWriter { + /// Seek to the offset, in bytes, in the underlying writer. + /// + /// Seeking always writes out the internal buffer before seeking. + fn seek(&mut self, pos: SeekFrom) -> io::Result { + self.flush_buf()?; + self.get_mut().seek(pos) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Drop for BufWriter { + fn drop(&mut self) { + if self.inner.is_some() && !self.panicked { + // dtors should not panic, so we ignore a failed flush + let _r = self.flush_buf(); + } + } +} diff --git a/library/std/src/io/buffered/linewriter.rs b/library/std/src/io/buffered/linewriter.rs new file mode 100644 index 0000000000000..502c6e3c6c0b9 --- /dev/null +++ b/library/std/src/io/buffered/linewriter.rs @@ -0,0 +1,232 @@ +use crate::fmt; +use crate::io::{self, buffered::LineWriterShim, BufWriter, IntoInnerError, IoSlice, Write}; + +/// Wraps a writer and buffers output to it, flushing whenever a newline +/// (`0x0a`, `'\n'`) is detected. +/// +/// The [`BufWriter`] struct wraps a writer and buffers its output. +/// But it only does this batched write when it goes out of scope, or when the +/// internal buffer is full. Sometimes, you'd prefer to write each line as it's +/// completed, rather than the entire buffer at once. Enter `LineWriter`. It +/// does exactly that. +/// +/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the +/// `LineWriter` goes out of scope or when its internal buffer is full. +/// +/// If there's still a partial line in the buffer when the `LineWriter` is +/// dropped, it will flush those contents. +/// +/// # Examples +/// +/// We can use `LineWriter` to write one line at a time, significantly +/// reducing the number of actual writes to the file. +/// +/// ```no_run +/// use std::fs::{self, File}; +/// use std::io::prelude::*; +/// use std::io::LineWriter; +/// +/// fn main() -> std::io::Result<()> { +/// let road_not_taken = b"I shall be telling this with a sigh +/// Somewhere ages and ages hence: +/// Two roads diverged in a wood, and I - +/// I took the one less traveled by, +/// And that has made all the difference."; +/// +/// let file = File::create("poem.txt")?; +/// let mut file = LineWriter::new(file); +/// +/// file.write_all(b"I shall be telling this with a sigh")?; +/// +/// // No bytes are written until a newline is encountered (or +/// // the internal buffer is filled). +/// assert_eq!(fs::read_to_string("poem.txt")?, ""); +/// file.write_all(b"\n")?; +/// assert_eq!( +/// fs::read_to_string("poem.txt")?, +/// "I shall be telling this with a sigh\n", +/// ); +/// +/// // Write the rest of the poem. +/// file.write_all(b"Somewhere ages and ages hence: +/// Two roads diverged in a wood, and I - +/// I took the one less traveled by, +/// And that has made all the difference.")?; +/// +/// // The last line of the poem doesn't end in a newline, so +/// // we have to flush or drop the `LineWriter` to finish +/// // writing. +/// file.flush()?; +/// +/// // Confirm the whole poem was written. +/// assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]); +/// Ok(()) +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub struct LineWriter { + inner: BufWriter, +} + +impl LineWriter { + /// Creates a new `LineWriter`. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let file = LineWriter::new(file); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(inner: W) -> LineWriter { + // Lines typically aren't that long, don't use a giant buffer + LineWriter::with_capacity(1024, inner) + } + + /// Creates a new `LineWriter` with a specified capacity for the internal + /// buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let file = LineWriter::with_capacity(100, file); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(capacity: usize, inner: W) -> LineWriter { + LineWriter { inner: BufWriter::with_capacity(capacity, inner) } + } + + /// Gets a reference to the underlying writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let file = LineWriter::new(file); + /// + /// let reference = file.get_ref(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_ref(&self) -> &W { + self.inner.get_ref() + } + + /// Gets a mutable reference to the underlying writer. + /// + /// Caution must be taken when calling methods on the mutable reference + /// returned as extra writes could corrupt the output stream. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let mut file = LineWriter::new(file); + /// + /// // we can use reference just like file + /// let reference = file.get_mut(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut W { + self.inner.get_mut() + } + + /// Unwraps this `LineWriter`, returning the underlying writer. + /// + /// The internal buffer is written out before returning the writer. + /// + /// # Errors + /// + /// An [`Err`] will be returned if an error occurs while flushing the buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// + /// let writer: LineWriter = LineWriter::new(file); + /// + /// let file: File = writer.into_inner()?; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_inner(self) -> Result>> { + self.inner.into_inner().map_err(|err| err.new_wrapped(|inner| LineWriter { inner })) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Write for LineWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + LineWriterShim::new(&mut self.inner).write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + LineWriterShim::new(&mut self.inner).write_vectored(bufs) + } + + fn is_write_vectored(&self) -> bool { + self.inner.is_write_vectored() + } + + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + LineWriterShim::new(&mut self.inner).write_all(buf) + } + + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + LineWriterShim::new(&mut self.inner).write_all_vectored(bufs) + } + + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { + LineWriterShim::new(&mut self.inner).write_fmt(fmt) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for LineWriter +where + W: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("LineWriter") + .field("writer", &self.get_ref()) + .field( + "buffer", + &format_args!("{}/{}", self.inner.buffer().len(), self.inner.capacity()), + ) + .finish() + } +} diff --git a/library/std/src/io/buffered/linewritershim.rs b/library/std/src/io/buffered/linewritershim.rs new file mode 100644 index 0000000000000..a80d08db8692e --- /dev/null +++ b/library/std/src/io/buffered/linewritershim.rs @@ -0,0 +1,270 @@ +use crate::io::{self, BufWriter, IoSlice, Write}; +use crate::memchr; + +/// Private helper struct for implementing the line-buffered writing logic. +/// This shim temporarily wraps a BufWriter, and uses its internals to +/// implement a line-buffered writer (specifically by using the internal +/// methods like write_to_buf and flush_buf). In this way, a more +/// efficient abstraction can be created than one that only had access to +/// `write` and `flush`, without needlessly duplicating a lot of the +/// implementation details of BufWriter. This also allows existing +/// `BufWriters` to be temporarily given line-buffering logic; this is what +/// enables Stdout to be alternately in line-buffered or block-buffered mode. +#[derive(Debug)] +pub struct LineWriterShim<'a, W: Write> { + buffer: &'a mut BufWriter, +} + +impl<'a, W: Write> LineWriterShim<'a, W> { + pub fn new(buffer: &'a mut BufWriter) -> Self { + Self { buffer } + } + + /// Get a mutable reference to the inner writer (that is, the writer + /// wrapped by the BufWriter). Be careful with this writer, as writes to + /// it will bypass the buffer. + fn inner_mut(&mut self) -> &mut W { + self.buffer.get_mut() + } + + /// Get the content currently buffered in self.buffer + fn buffered(&self) -> &[u8] { + self.buffer.buffer() + } + + /// Flush the buffer iff the last byte is a newline (indicating that an + /// earlier write only succeeded partially, and we want to retry flushing + /// the buffered line before continuing with a subsequent write) + fn flush_if_completed_line(&mut self) -> io::Result<()> { + match self.buffered().last().copied() { + Some(b'\n') => self.buffer.flush_buf(), + _ => Ok(()), + } + } +} + +impl<'a, W: Write> Write for LineWriterShim<'a, W> { + /// Write some data into this BufReader with line buffering. This means + /// that, if any newlines are present in the data, the data up to the last + /// newline is sent directly to the underlying writer, and data after it + /// is buffered. Returns the number of bytes written. + /// + /// This function operates on a "best effort basis"; in keeping with the + /// convention of `Write::write`, it makes at most one attempt to write + /// new data to the underlying writer. If that write only reports a partial + /// success, the remaining data will be buffered. + /// + /// Because this function attempts to send completed lines to the underlying + /// writer, it will also flush the existing buffer if it ends with a + /// newline, even if the incoming data does not contain any newlines. + fn write(&mut self, buf: &[u8]) -> io::Result { + let newline_idx = match memchr::memrchr(b'\n', buf) { + // If there are no new newlines (that is, if this write is less than + // one line), just do a regular buffered write (which may flush if + // we exceed the inner buffer's size) + None => { + self.flush_if_completed_line()?; + return self.buffer.write(buf); + } + // Otherwise, arrange for the lines to be written directly to the + // inner writer. + Some(newline_idx) => newline_idx + 1, + }; + + // Flush existing content to prepare for our write. We have to do this + // before attempting to write `buf` in order to maintain consistency; + // if we add `buf` to the buffer then try to flush it all at once, + // we're obligated to return Ok(), which would mean suppressing any + // errors that occur during flush. + self.buffer.flush_buf()?; + + // This is what we're going to try to write directly to the inner + // writer. The rest will be buffered, if nothing goes wrong. + let lines = &buf[..newline_idx]; + + // Write `lines` directly to the inner writer. In keeping with the + // `write` convention, make at most one attempt to add new (unbuffered) + // data. Because this write doesn't touch the BufWriter state directly, + // and the buffer is known to be empty, we don't need to worry about + // self.buffer.panicked here. + let flushed = self.inner_mut().write(lines)?; + + // If buffer returns Ok(0), propagate that to the caller without + // doing additional buffering; otherwise we're just guaranteeing + // an "ErrorKind::WriteZero" later. + if flushed == 0 { + return Ok(0); + } + + // Now that the write has succeeded, buffer the rest (or as much of + // the rest as possible). If there were any unwritten newlines, we + // only buffer out to the last unwritten newline that fits in the + // buffer; this helps prevent flushing partial lines on subsequent + // calls to LineWriterShim::write. + + // Handle the cases in order of most-common to least-common, under + // the presumption that most writes succeed in totality, and that most + // writes are smaller than the buffer. + // - Is this a partial line (ie, no newlines left in the unwritten tail) + // - If not, does the data out to the last unwritten newline fit in + // the buffer? + // - If not, scan for the last newline that *does* fit in the buffer + let tail = if flushed >= newline_idx { + &buf[flushed..] + } else if newline_idx - flushed <= self.buffer.capacity() { + &buf[flushed..newline_idx] + } else { + let scan_area = &buf[flushed..]; + let scan_area = &scan_area[..self.buffer.capacity()]; + match memchr::memrchr(b'\n', scan_area) { + Some(newline_idx) => &scan_area[..newline_idx + 1], + None => scan_area, + } + }; + + let buffered = self.buffer.write_to_buf(tail); + Ok(flushed + buffered) + } + + fn flush(&mut self) -> io::Result<()> { + self.buffer.flush() + } + + /// Write some vectored data into this BufReader with line buffering. This + /// means that, if any newlines are present in the data, the data up to + /// and including the buffer containing the last newline is sent directly + /// to the inner writer, and the data after it is buffered. Returns the + /// number of bytes written. + /// + /// This function operates on a "best effort basis"; in keeping with the + /// convention of `Write::write`, it makes at most one attempt to write + /// new data to the underlying writer. + /// + /// Because this function attempts to send completed lines to the underlying + /// writer, it will also flush the existing buffer if it contains any + /// newlines. + /// + /// Because sorting through an array of `IoSlice` can be a bit convoluted, + /// This method differs from write in the following ways: + /// + /// - It attempts to write the full content of all the buffers up to and + /// including the one containing the last newline. This means that it + /// may attempt to write a partial line, that buffer has data past the + /// newline. + /// - If the write only reports partial success, it does not attempt to + /// find the precise location of the written bytes and buffer the rest. + /// + /// If the underlying vector doesn't support vectored writing, we instead + /// simply write the first non-empty buffer with `write`. This way, we + /// get the benefits of more granular partial-line handling without losing + /// anything in efficiency + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + // If there's no specialized behavior for write_vectored, just use + // write. This has the benefit of more granular partial-line handling. + if !self.is_write_vectored() { + return match bufs.iter().find(|buf| !buf.is_empty()) { + Some(buf) => self.write(buf), + None => Ok(0), + }; + } + + // Find the buffer containing the last newline + let last_newline_buf_idx = bufs + .iter() + .enumerate() + .rev() + .find_map(|(i, buf)| memchr::memchr(b'\n', buf).map(|_| i)); + + // If there are no new newlines (that is, if this write is less than + // one line), just do a regular buffered write + let last_newline_buf_idx = match last_newline_buf_idx { + // No newlines; just do a normal buffered write + None => { + self.flush_if_completed_line()?; + return self.buffer.write_vectored(bufs); + } + Some(i) => i, + }; + + // Flush existing content to prepare for our write + self.buffer.flush_buf()?; + + // This is what we're going to try to write directly to the inner + // writer. The rest will be buffered, if nothing goes wrong. + let (lines, tail) = bufs.split_at(last_newline_buf_idx + 1); + + // Write `lines` directly to the inner writer. In keeping with the + // `write` convention, make at most one attempt to add new (unbuffered) + // data. Because this write doesn't touch the BufWriter state directly, + // and the buffer is known to be empty, we don't need to worry about + // self.panicked here. + let flushed = self.inner_mut().write_vectored(lines)?; + + // If inner returns Ok(0), propagate that to the caller without + // doing additional buffering; otherwise we're just guaranteeing + // an "ErrorKind::WriteZero" later. + if flushed == 0 { + return Ok(0); + } + + // Don't try to reconstruct the exact amount written; just bail + // in the event of a partial write + let lines_len = lines.iter().map(|buf| buf.len()).sum(); + if flushed < lines_len { + return Ok(flushed); + } + + // Now that the write has succeeded, buffer the rest (or as much of the + // rest as possible) + let buffered: usize = tail + .iter() + .filter(|buf| !buf.is_empty()) + .map(|buf| self.buffer.write_to_buf(buf)) + .take_while(|&n| n > 0) + .sum(); + + Ok(flushed + buffered) + } + + fn is_write_vectored(&self) -> bool { + self.buffer.is_write_vectored() + } + + /// Write some data into this BufReader with line buffering. This means + /// that, if any newlines are present in the data, the data up to the last + /// newline is sent directly to the underlying writer, and data after it + /// is buffered. + /// + /// Because this function attempts to send completed lines to the underlying + /// writer, it will also flush the existing buffer if it contains any + /// newlines, even if the incoming data does not contain any newlines. + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + match memchr::memrchr(b'\n', buf) { + // If there are no new newlines (that is, if this write is less than + // one line), just do a regular buffered write (which may flush if + // we exceed the inner buffer's size) + None => { + self.flush_if_completed_line()?; + self.buffer.write_all(buf) + } + Some(newline_idx) => { + let (lines, tail) = buf.split_at(newline_idx + 1); + + if self.buffered().is_empty() { + self.inner_mut().write_all(lines)?; + } else { + // If there is any buffered data, we add the incoming lines + // to that buffer before flushing, which saves us at least + // one write call. We can't really do this with `write`, + // since we can't do this *and* not suppress errors *and* + // report a consistent state to the caller in a return + // value, but here in write_all it's fine. + self.buffer.write_all(lines)?; + self.buffer.flush_buf()?; + } + + self.buffer.write_all(tail) + } + } + } +} From 96229f02402e82914ec6100b28ad2cbdd273a0d4 Mon Sep 17 00:00:00 2001 From: Nathan West Date: Thu, 10 Sep 2020 23:48:22 -0400 Subject: [PATCH 02/50] move buffered.rs to mod.rs --- library/std/src/io/{buffered.rs => buffered/mod.rs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename library/std/src/io/{buffered.rs => buffered/mod.rs} (98%) diff --git a/library/std/src/io/buffered.rs b/library/std/src/io/buffered/mod.rs similarity index 98% rename from library/std/src/io/buffered.rs rename to library/std/src/io/buffered/mod.rs index 7329ea53736ec..f9caeaf98e2fb 100644 --- a/library/std/src/io/buffered.rs +++ b/library/std/src/io/buffered/mod.rs @@ -15,7 +15,7 @@ use crate::io::Error; pub use bufreader::BufReader; pub use bufwriter::BufWriter; pub use linewriter::LineWriter; -pub(super) use linewritershim::LineWriterShim; +use linewritershim::LineWriterShim; /// An error returned by [`BufWriter::into_inner`] which combines an error that /// happened while writing out the buffer, and the buffered writer object From 6d75cdfc9ed9e6987bd23add6cf3954d2499dce2 Mon Sep 17 00:00:00 2001 From: Nathan West Date: Mon, 14 Sep 2020 22:16:50 -0400 Subject: [PATCH 03/50] Added updated compiler diagnostic --- .../mut-borrow-needed-by-trait.stderr | 25 ++++--------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr index c1eea56f70dc1..8ab1014485665 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -5,18 +5,13 @@ LL | let fp = BufWriter::new(fp); | ^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` | = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` - = note: required by `BufWriter::::new` + = note: required by `std::io::BufWriter::::new` error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied --> $DIR/mut-borrow-needed-by-trait.rs:17:14 | LL | let fp = BufWriter::new(fp); | ^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` - | - ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL - | -LL | pub struct BufWriter { - | ----- required by this bound in `BufWriter` | = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` @@ -25,28 +20,18 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satis | LL | let fp = BufWriter::new(fp); | ^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` - | - ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL - | -LL | pub struct BufWriter { - | ----- required by this bound in `BufWriter` | = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` -error[E0599]: no method named `write_fmt` found for struct `BufWriter<&dyn std::io::Write>` in the current scope +error[E0599]: no method named `write_fmt` found for struct `std::io::BufWriter<&dyn std::io::Write>` in the current scope --> $DIR/mut-borrow-needed-by-trait.rs:22:5 | -LL | writeln!(fp, "hello world").unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `BufWriter<&dyn std::io::Write>` - | - ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL - | -LL | pub struct BufWriter { - | ------------------------------ doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write` +LL | writeln!(fp, "hello world").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `std::io::BufWriter<&dyn std::io::Write>` | = note: the method `write_fmt` exists but the following trait bounds were not satisfied: `&dyn std::io::Write: std::io::Write` - which is required by `BufWriter<&dyn std::io::Write>: std::io::Write` + which is required by `std::io::BufWriter<&dyn std::io::Write>: std::io::Write` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors From da700cba08a2b194d19e63d3c51ebadce96fe46b Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi Date: Mon, 31 Aug 2020 02:59:56 +0800 Subject: [PATCH 04/50] Stabilize move_ref_pattern --- compiler/rustc_feature/src/accepted.rs | 3 + compiler/rustc_feature/src/active.rs | 4 - .../src/thir/pattern/check_match.rs | 70 +------------- ...or-patterns-slice-patterns-box-patterns.rs | 2 - ...atterns-slice-patterns-box-patterns.stderr | 34 +++---- src/test/ui/drop/dynamic-drop-async.rs | 2 - src/test/ui/drop/dynamic-drop.rs | 1 - src/test/ui/error-codes/E0007.rs | 11 --- src/test/ui/error-codes/E0007.stderr | 22 ----- ...her-can-live-while-the-other-survives-1.rs | 1 - ...can-live-while-the-other-survives-1.stderr | 12 +-- .../bind-by-move-no-subbindings-fun-param.rs | 1 - ...nd-by-move-no-subbindings-fun-param.stderr | 2 +- .../borrowck-move-and-move.rs | 1 - .../borrowck-move-and-move.stderr | 16 ++-- .../borrowck-pat-at-and-box-pass.rs | 1 - .../borrowck-pat-at-and-box.rs | 1 - .../borrowck-pat-at-and-box.stderr | 34 +++---- ...k-pat-by-move-and-ref-inverse-promotion.rs | 1 - ...t-by-move-and-ref-inverse-promotion.stderr | 2 +- .../borrowck-pat-by-move-and-ref-inverse.rs | 1 - ...orrowck-pat-by-move-and-ref-inverse.stderr | 96 +++++++++---------- .../borrowck-pat-by-move-and-ref.rs | 1 - .../borrowck-pat-by-move-and-ref.stderr | 50 +++++----- .../borrowck-pat-ref-mut-and-ref.rs | 1 - .../borrowck-pat-ref-mut-and-ref.stderr | 94 +++++++++--------- .../borrowck-pat-ref-mut-twice.rs | 1 - .../borrowck-pat-ref-mut-twice.stderr | 68 ++++++------- .../bindings-after-at/copy-and-move-mixed.rs | 1 - .../copy-and-move-mixed.stderr | 6 +- ...lt-binding-modes-both-sides-independent.rs | 1 - ...inding-modes-both-sides-independent.stderr | 12 +-- .../borrowck-move-ref-pattern-pass.rs | 2 - .../borrowck-move-ref-pattern.rs | 2 - .../borrowck-move-ref-pattern.stderr | 36 +++---- .../by-move-sub-pat-unreachable.rs | 1 - .../feature-gate-move_ref_pattern.rs | 23 ----- .../feature-gate-move_ref_pattern.stderr | 66 ------------- .../pattern/move-ref-patterns/issue-53840.rs | 2 - ...ve-ref-patterns-closure-captures-inside.rs | 2 - ...ef-patterns-closure-captures-inside.stderr | 54 +++++------ ...move-ref-patterns-closure-captures-pass.rs | 2 - .../move-ref-patterns-closure-captures.rs | 2 - .../move-ref-patterns-closure-captures.stderr | 6 +- ...move-ref-patterns-default-binding-modes.rs | 2 - ...-ref-patterns-default-binding-modes.stderr | 4 +- .../move-ref-patterns-dynamic-semantics.rs | 2 - .../ui/rfc-2005-default-binding-mode/for.rs | 2 - .../rfc-2005-default-binding-mode/for.stderr | 2 +- 49 files changed, 271 insertions(+), 492 deletions(-) delete mode 100644 src/test/ui/error-codes/E0007.rs delete mode 100644 src/test/ui/error-codes/E0007.stderr delete mode 100644 src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs delete mode 100644 src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 0477f6f149b87..ce002ac3cdf64 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -270,6 +270,9 @@ declare_features! ( (accepted, track_caller, "1.46.0", Some(47809), None), /// Allows `#[doc(alias = "...")]`. (accepted, doc_alias, "1.48.0", Some(50146), None), + /// Allows patterns with concurrent by-move and by-ref bindings. + /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref. + (accepted, move_ref_pattern, "1.48.0", Some(68354), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index d4664292a0cbd..ed5560bb6d706 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -527,10 +527,6 @@ declare_features! ( /// For example, you can write `x @ Some(y)`. (active, bindings_after_at, "1.41.0", Some(65490), None), - /// Allows patterns with concurrent by-move and by-ref bindings. - /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref. - (active, move_ref_pattern, "1.42.0", Some(68354), None), - /// Allows `impl const Trait for T` syntax. (active, const_trait_impl, "1.42.0", Some(67792), None), diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 047bf7db4c867..1a7b8474411b8 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -71,13 +71,13 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> { hir::LocalSource::AwaitDesugar => ("`await` future binding", None), }; self.check_irrefutable(&loc.pat, msg, sp); - self.check_patterns(false, &loc.pat); + self.check_patterns(&loc.pat); } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { intravisit::walk_param(self, param); self.check_irrefutable(¶m.pat, "function argument", None); - self.check_patterns(false, ¶m.pat); + self.check_patterns(¶m.pat); } } @@ -119,10 +119,7 @@ impl PatCtxt<'_, '_> { } impl<'tcx> MatchVisitor<'_, 'tcx> { - fn check_patterns(&mut self, has_guard: bool, pat: &Pat<'_>) { - if !self.tcx.features().move_ref_pattern { - check_legality_of_move_bindings(self, has_guard, pat); - } + fn check_patterns(&mut self, pat: &Pat<'_>) { pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat)); if !self.tcx.features().bindings_after_at { check_legality_of_bindings_in_at_patterns(self, pat); @@ -165,7 +162,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { ) { for arm in arms { // Check the arm for some things unrelated to exhaustiveness. - self.check_patterns(arm.guard.is_some(), &arm.pat); + self.check_patterns(&arm.pat); } let mut cx = self.new_cx(scrut.hir_id); @@ -601,65 +598,6 @@ fn is_binding_by_move(cx: &MatchVisitor<'_, '_>, hir_id: HirId, span: Span) -> b !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx.at(span), cx.param_env) } -/// Check the legality of legality of by-move bindings. -fn check_legality_of_move_bindings(cx: &mut MatchVisitor<'_, '_>, has_guard: bool, pat: &Pat<'_>) { - let sess = cx.tcx.sess; - let typeck_results = cx.typeck_results; - - // Find all by-ref spans. - let mut by_ref_spans = Vec::new(); - pat.each_binding(|_, hir_id, span, _| { - if let Some(ty::BindByReference(_)) = - typeck_results.extract_binding_mode(sess, hir_id, span) - { - by_ref_spans.push(span); - } - }); - - // Find bad by-move spans: - let by_move_spans = &mut Vec::new(); - let mut check_move = |p: &Pat<'_>, sub: Option<&Pat<'_>>| { - // Check legality of moving out of the enum. - // - // `x @ Foo(..)` is legal, but `x @ Foo(y)` isn't. - if sub.map_or(false, |p| p.contains_bindings()) { - struct_span_err!(sess, p.span, E0007, "cannot bind by-move with sub-bindings") - .span_label(p.span, "binds an already bound by-move value by moving it") - .emit(); - } else if !has_guard && !by_ref_spans.is_empty() { - by_move_spans.push(p.span); - } - }; - pat.walk_always(|p| { - if let hir::PatKind::Binding(.., sub) = &p.kind { - if let Some(ty::BindByValue(_)) = - typeck_results.extract_binding_mode(sess, p.hir_id, p.span) - { - if is_binding_by_move(cx, p.hir_id, p.span) { - check_move(p, sub.as_deref()); - } - } - } - }); - - // Found some bad by-move spans, error! - if !by_move_spans.is_empty() { - let mut err = feature_err( - &sess.parse_sess, - sym::move_ref_pattern, - by_move_spans.clone(), - "binding by-move and by-ref in the same pattern is unstable", - ); - for span in by_ref_spans.iter() { - err.span_label(*span, "by-ref pattern here"); - } - for span in by_move_spans.iter() { - err.span_label(*span, "by-move pattern here"); - } - err.emit(); - } -} - /// Check that there are no borrow or move conflicts in `binding @ subpat` patterns. /// /// For example, this would reject: diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs index b67d494866b85..97f96ab69295f 100644 --- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs +++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs @@ -3,8 +3,6 @@ #![feature(or_patterns)] #![feature(box_patterns)] -#![feature(move_ref_pattern)] - enum Test { Foo, Bar, diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr index 1bf8158927552..96e313b39ed1e 100644 --- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr +++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr @@ -1,5 +1,5 @@ error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:40:9 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:38:9 | LL | ref foo @ [.., ref mut bar] => (), | -------^^^^^^^^-----------^ @@ -8,7 +8,7 @@ LL | ref foo @ [.., ref mut bar] => (), | immutable borrow, by `foo`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:124:9 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:122:9 | LL | ref foo @ Some(box ref mut s) => (), | -------^^^^^^^^^^^^---------^ @@ -17,7 +17,7 @@ LL | ref foo @ Some(box ref mut s) => (), | immutable borrow, by `foo`, occurs here error[E0382]: borrow of moved value: `x` - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:22:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:20:5 | LL | fn bindings_after_at_slice_patterns_move_binding(x: [String; 4]) { | - move occurs because `x` has type `[String; 4]`, which does not implement the `Copy` trait @@ -29,7 +29,7 @@ LL | &x; | ^^ value borrowed here after move error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:32:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:30:5 | LL | ref mut foo @ [.., _] => Some(foo), | --------------------- mutable borrow occurs here @@ -41,7 +41,7 @@ LL | drop(r); | - mutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:54:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:52:5 | LL | [ref foo @ .., ref bar] => Some(foo), | ------------ immutable borrow occurs here @@ -53,7 +53,7 @@ LL | drop(r); | - immutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:66:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:64:5 | LL | ref foo @ [.., ref bar] => Some(foo), | ----------------------- immutable borrow occurs here @@ -65,7 +65,7 @@ LL | drop(r); | - immutable borrow later used here error[E0382]: borrow of moved value: `x` - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:80:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:78:5 | LL | fn bindings_after_at_or_patterns_move(x: Option) { | - move occurs because `x` has type `Option`, which does not implement the `Copy` trait @@ -80,7 +80,7 @@ LL | &x; | ^^ value borrowed here after move error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:90:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:88:5 | LL | ref foo @ Some(Test::Foo | Test::Bar) => Some(foo), | ------------------------------------- immutable borrow occurs here @@ -92,7 +92,7 @@ LL | drop(r); | - immutable borrow later used here error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:102:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:100:5 | LL | ref mut foo @ Some(Test::Foo | Test::Bar) => Some(foo), | ----------------------------------------- mutable borrow occurs here @@ -104,7 +104,7 @@ LL | drop(r); | - mutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:116:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:114:5 | LL | ref foo @ Some(box ref s) => Some(foo), | ------------------------- immutable borrow occurs here @@ -116,7 +116,7 @@ LL | drop(r); | - immutable borrow later used here error[E0382]: borrow of moved value: `x` - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:138:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:136:5 | LL | fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option; 4]) { | - move occurs because `x` has type `[Option; 4]`, which does not implement the `Copy` trait @@ -131,7 +131,7 @@ LL | &x; | ^^ value borrowed here after move error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:148:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:146:5 | LL | ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(a), | ------------------------------------------------- immutable borrow occurs here @@ -143,7 +143,7 @@ LL | drop(r); | - immutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:160:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:158:5 | LL | ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(b), | ---------- immutable borrow occurs here @@ -155,7 +155,7 @@ LL | drop(r); | - immutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:174:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:172:5 | LL | [_, ref a @ Some(box ref b), ..] => Some(a), | ----------------------- immutable borrow occurs here @@ -167,7 +167,7 @@ LL | drop(r); | - immutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:190:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:188:5 | LL | [_, ref a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), | ------------------------------------------- immutable borrow occurs here @@ -179,7 +179,7 @@ LL | drop(r); | - immutable borrow later used here error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:204:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:202:5 | LL | [_, ref mut a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), | ----------------------------------------------- mutable borrow occurs here @@ -191,7 +191,7 @@ LL | drop(r); | - mutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:218:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:216:5 | LL | ref a @ [_, ref b @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), | ------------------------------------------------------------ immutable borrow occurs here diff --git a/src/test/ui/drop/dynamic-drop-async.rs b/src/test/ui/drop/dynamic-drop-async.rs index 88d36ab6aa664..b027faa9d7c3a 100644 --- a/src/test/ui/drop/dynamic-drop-async.rs +++ b/src/test/ui/drop/dynamic-drop-async.rs @@ -7,8 +7,6 @@ // edition:2018 // ignore-wasm32-bare compiled with panic=abort by default -#![feature(move_ref_pattern)] - #![allow(unused)] use std::{ diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs index d31736f142c3f..ada61bf0df04c 100644 --- a/src/test/ui/drop/dynamic-drop.rs +++ b/src/test/ui/drop/dynamic-drop.rs @@ -2,7 +2,6 @@ // ignore-wasm32-bare compiled with panic=abort by default #![feature(generators, generator_trait, untagged_unions)] -#![feature(move_ref_pattern)] #![feature(bindings_after_at)] #![allow(unused_assignments)] diff --git a/src/test/ui/error-codes/E0007.rs b/src/test/ui/error-codes/E0007.rs deleted file mode 100644 index 022ac5fc113dd..0000000000000 --- a/src/test/ui/error-codes/E0007.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![feature(bindings_after_at)] - -fn main() { - let x = Some("s".to_string()); - match x { - op_string @ Some(s) => {}, - //~^ ERROR E0007 - //~| ERROR E0382 - None => {}, - } -} diff --git a/src/test/ui/error-codes/E0007.stderr b/src/test/ui/error-codes/E0007.stderr deleted file mode 100644 index 89c1051619438..0000000000000 --- a/src/test/ui/error-codes/E0007.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0007]: cannot bind by-move with sub-bindings - --> $DIR/E0007.rs:6:9 - | -LL | op_string @ Some(s) => {}, - | ^^^^^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it - -error[E0382]: use of moved value - --> $DIR/E0007.rs:6:26 - | -LL | let x = Some("s".to_string()); - | - move occurs because `x` has type `Option`, which does not implement the `Copy` trait -LL | match x { -LL | op_string @ Some(s) => {}, - | -----------------^- - | | | - | | value used here after move - | value moved here - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0007, E0382. -For more information about an error, try `rustc --explain E0007`. diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs index c00296c34c4e5..ba9543bf73869 100644 --- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs @@ -3,7 +3,6 @@ // where one side is by-ref and the other is by-move. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] struct X { x: (), diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr index 8a6ea8e91a25a..44dbcb9a75466 100644 --- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr @@ -1,5 +1,5 @@ error: cannot move out of value because it is borrowed - --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:15:14 + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:14:14 | LL | Some(ref _y @ _z) => {} | ------^^^-- @@ -8,7 +8,7 @@ LL | Some(ref _y @ _z) => {} | value borrowed, by `_y`, here error: borrow of moved value - --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:21:14 + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:20:14 | LL | Some(_z @ ref _y) => {} | --^^^------ @@ -18,7 +18,7 @@ LL | Some(_z @ ref _y) => {} | move occurs because `_z` has type `X` which does not implement the `Copy` trait error: cannot move out of value because it is borrowed - --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:29:14 + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:28:14 | LL | Some(ref mut _y @ _z) => {} | ----------^^^-- @@ -27,7 +27,7 @@ LL | Some(ref mut _y @ _z) => {} | value borrowed, by `_y`, here error: borrow of moved value - --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:35:14 + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:34:14 | LL | Some(_z @ ref mut _y) => {} | --^^^---------- @@ -37,7 +37,7 @@ LL | Some(_z @ ref mut _y) => {} | move occurs because `_z` has type `X` which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:21:19 + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:20:19 | LL | Some(_z @ ref _y) => {} | -----^^^^^^ @@ -52,7 +52,7 @@ LL | Some(ref _z @ ref _y) => {} | ^^^ error[E0382]: borrow of moved value - --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:35:19 + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:34:19 | LL | Some(_z @ ref mut _y) => {} | -----^^^^^^^^^^ diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs index 7a2e5128b8537..3ab6f40725cfb 100644 --- a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs @@ -1,7 +1,6 @@ // See issue #12534. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() {} diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr index cfd978e132709..f25d5a2d9b82d 100644 --- a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value - --> $DIR/bind-by-move-no-subbindings-fun-param.rs:10:12 + --> $DIR/bind-by-move-no-subbindings-fun-param.rs:9:12 | LL | fn f(a @ A(u): A) -> Box { | ------^- diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs index 10865b92393b6..d014c9828da2a 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs @@ -1,7 +1,6 @@ // Test that moving on both sides of an `@` pattern is not allowed. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() { struct U; // Not copy! diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr index d28edd11e1283..5039f580ff6ea 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:14:13 + --> $DIR/borrowck-move-and-move.rs:13:13 | LL | let a @ b = U; | ----^ - move occurs because value has type `U`, which does not implement the `Copy` trait @@ -8,7 +8,7 @@ LL | let a @ b = U; | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:16:17 + --> $DIR/borrowck-move-and-move.rs:15:17 | LL | let a @ (b, c) = (U, U); | --------^- ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait @@ -17,7 +17,7 @@ LL | let a @ (b, c) = (U, U); | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:18:17 + --> $DIR/borrowck-move-and-move.rs:17:17 | LL | let a @ (b, c) = (u(), u()); | --------^- ---------- move occurs because value has type `(U, U)`, which does not implement the `Copy` trait @@ -26,7 +26,7 @@ LL | let a @ (b, c) = (u(), u()); | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:21:16 + --> $DIR/borrowck-move-and-move.rs:20:16 | LL | match Ok(U) { | ----- move occurs because value has type `std::result::Result`, which does not implement the `Copy` trait @@ -37,7 +37,7 @@ LL | a @ Ok(b) | a @ Err(b) => {} | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:21:29 + --> $DIR/borrowck-move-and-move.rs:20:29 | LL | match Ok(U) { | ----- move occurs because value has type `std::result::Result`, which does not implement the `Copy` trait @@ -48,7 +48,7 @@ LL | a @ Ok(b) | a @ Err(b) => {} | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:28:22 + --> $DIR/borrowck-move-and-move.rs:27:22 | LL | match [u(), u(), u(), u()] { | -------------------- move occurs because value has type `[U; 4]`, which does not implement the `Copy` trait @@ -59,7 +59,7 @@ LL | xs @ [a, .., b] => {} | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:32:18 + --> $DIR/borrowck-move-and-move.rs:31:18 | LL | match [u(), u(), u(), u()] { | -------------------- move occurs because value has type `[U; 4]`, which does not implement the `Copy` trait @@ -70,7 +70,7 @@ LL | xs @ [_, ys @ .., _] => {} | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:25:16 + --> $DIR/borrowck-move-and-move.rs:24:16 | LL | fn fun(a @ b: U) {} | ----^ diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs index 271f4bca0fcb8..f1ee87bc9c69b 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs @@ -3,7 +3,6 @@ // Test `@` patterns combined with `box` patterns. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] #![feature(box_patterns)] #[derive(Copy, Clone)] diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs index f1680e9e8884e..236710ed85493 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs @@ -1,7 +1,6 @@ // Test `@` patterns combined with `box` patterns. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] #![feature(box_patterns)] #[derive(Copy, Clone)] diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr index 44888369ab2f7..d9a8bbfb6b103 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr @@ -1,5 +1,5 @@ error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-at-and-box.rs:37:9 + --> $DIR/borrowck-pat-at-and-box.rs:36:9 | LL | let ref a @ box b = Box::new(NC); | -----^^^^^^^- @@ -8,7 +8,7 @@ LL | let ref a @ box b = Box::new(NC); | value borrowed, by `a`, here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-at-and-box.rs:39:9 + --> $DIR/borrowck-pat-at-and-box.rs:38:9 | LL | let ref a @ box ref mut b = Box::new(nc()); | -----^^^^^^^--------- @@ -17,7 +17,7 @@ LL | let ref a @ box ref mut b = Box::new(nc()); | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-at-and-box.rs:41:9 + --> $DIR/borrowck-pat-at-and-box.rs:40:9 | LL | let ref a @ box ref mut b = Box::new(NC); | -----^^^^^^^--------- @@ -26,7 +26,7 @@ LL | let ref a @ box ref mut b = Box::new(NC); | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-at-and-box.rs:43:9 + --> $DIR/borrowck-pat-at-and-box.rs:42:9 | LL | let ref a @ box ref mut b = Box::new(NC); | -----^^^^^^^--------- @@ -35,7 +35,7 @@ LL | let ref a @ box ref mut b = Box::new(NC); | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-at-and-box.rs:46:9 + --> $DIR/borrowck-pat-at-and-box.rs:45:9 | LL | let ref a @ box ref mut b = Box::new(NC); | -----^^^^^^^--------- @@ -44,7 +44,7 @@ LL | let ref a @ box ref mut b = Box::new(NC); | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-at-and-box.rs:52:9 + --> $DIR/borrowck-pat-at-and-box.rs:51:9 | LL | let ref mut a @ box ref b = Box::new(NC); | ---------^^^^^^^----- @@ -53,7 +53,7 @@ LL | let ref mut a @ box ref b = Box::new(NC); | mutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-at-and-box.rs:66:9 + --> $DIR/borrowck-pat-at-and-box.rs:65:9 | LL | ref mut a @ box ref b => { | ---------^^^^^^^----- @@ -62,7 +62,7 @@ LL | ref mut a @ box ref b => { | mutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-at-and-box.rs:58:11 + --> $DIR/borrowck-pat-at-and-box.rs:57:11 | LL | fn f5(ref mut a @ box ref b: Box) { | ---------^^^^^^^----- @@ -71,7 +71,7 @@ LL | fn f5(ref mut a @ box ref b: Box) { | mutable borrow, by `a`, occurs here error[E0382]: use of moved value - --> $DIR/borrowck-pat-at-and-box.rs:21:18 + --> $DIR/borrowck-pat-at-and-box.rs:20:18 | LL | let a @ box &b = Box::new(&C); | ---------^ ------------ move occurs because value has type `Box<&C>`, which does not implement the `Copy` trait @@ -80,7 +80,7 @@ LL | let a @ box &b = Box::new(&C); | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-pat-at-and-box.rs:24:17 + --> $DIR/borrowck-pat-at-and-box.rs:23:17 | LL | let a @ box b = Box::new(C); | --------^ ----------- move occurs because value has type `Box`, which does not implement the `Copy` trait @@ -89,7 +89,7 @@ LL | let a @ box b = Box::new(C); | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-pat-at-and-box.rs:34:17 + --> $DIR/borrowck-pat-at-and-box.rs:33:17 | LL | match Box::new(C) { | ----------- move occurs because value has type `Box`, which does not implement the `Copy` trait @@ -100,7 +100,7 @@ LL | a @ box b => {} | value moved here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-at-and-box.rs:46:21 + --> $DIR/borrowck-pat-at-and-box.rs:45:21 | LL | let ref a @ box ref mut b = Box::new(NC); | ------------^^^^^^^^^ @@ -112,7 +112,7 @@ LL | drop(a); | - immutable borrow later used here error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-at-and-box.rs:52:25 + --> $DIR/borrowck-pat-at-and-box.rs:51:25 | LL | let ref mut a @ box ref b = Box::new(NC); | ----------------^^^^^ @@ -124,7 +124,7 @@ LL | *a = Box::new(NC); | -- mutable borrow later used here error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-at-and-box.rs:66:25 + --> $DIR/borrowck-pat-at-and-box.rs:65:25 | LL | ref mut a @ box ref b => { | ----------------^^^^^ @@ -136,7 +136,7 @@ LL | *a = Box::new(NC); | -- mutable borrow later used here error[E0382]: use of moved value - --> $DIR/borrowck-pat-at-and-box.rs:27:20 + --> $DIR/borrowck-pat-at-and-box.rs:26:20 | LL | fn f1(a @ box &b: Box<&C>) {} | ---------^ @@ -146,7 +146,7 @@ LL | fn f1(a @ box &b: Box<&C>) {} | move occurs because value has type `Box<&C>`, which does not implement the `Copy` trait error[E0382]: use of moved value - --> $DIR/borrowck-pat-at-and-box.rs:30:19 + --> $DIR/borrowck-pat-at-and-box.rs:29:19 | LL | fn f2(a @ box b: Box) {} | --------^ @@ -156,7 +156,7 @@ LL | fn f2(a @ box b: Box) {} | move occurs because value has type `Box`, which does not implement the `Copy` trait error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-at-and-box.rs:58:27 + --> $DIR/borrowck-pat-at-and-box.rs:57:27 | LL | fn f5(ref mut a @ box ref b: Box) { | ----------------^^^^^ diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs index 993954b450e37..a22d27763d261 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs @@ -2,7 +2,6 @@ // Currently this logic exists in THIR match checking as opposed to borrowck. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() { struct U; diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr index dacf23f9ded98..0e09d478e3a10 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr @@ -1,5 +1,5 @@ error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse-promotion.rs:9:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse-promotion.rs:8:9 | LL | let a @ ref b = U; | -^^^----- diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs index 7d9618c8df78d..3e5a543c4c36a 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs @@ -1,7 +1,6 @@ // Test that `by_move_binding @ pat_with_by_ref_bindings` is prevented. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() { struct U; diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr index 86e09e55585f7..282031aeb0754 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr @@ -1,5 +1,5 @@ error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:29:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:28:9 | LL | let a @ ref b = U; | -^^^----- @@ -9,7 +9,7 @@ LL | let a @ ref b = U; | move occurs because `a` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:9 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | -^^^^^^^^^^^^---------^^^^^^-----^ @@ -20,7 +20,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:14 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:14 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | -----^^^--------- @@ -30,7 +30,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:33 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:33 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | -^^^----- @@ -40,7 +40,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:37:9 | LL | let a @ [ref mut b, ref c] = [U, U]; | -^^^^---------^^-----^ @@ -51,7 +51,7 @@ LL | let a @ [ref mut b, ref c] = [U, U]; | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:41:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:40:9 | LL | let a @ ref b = u(); | -^^^----- @@ -61,7 +61,7 @@ LL | let a @ ref b = u(); | move occurs because `a` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:9 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | -^^^^^^^^^^^^---------^^^^^^-----^ @@ -72,7 +72,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:14 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:14 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | -----^^^--------- @@ -82,7 +82,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:33 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:33 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | -^^^----- @@ -92,7 +92,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:51:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:50:9 | LL | let a @ [ref mut b, ref c] = [u(), u()]; | -^^^^---------^^-----^ @@ -103,7 +103,7 @@ LL | let a @ [ref mut b, ref c] = [u(), u()]; | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:56:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:9 | LL | a @ Some(ref b) => {} | -^^^^^^^^-----^ @@ -113,7 +113,7 @@ LL | a @ Some(ref b) => {} | move occurs because `a` has type `Option` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:9 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^ @@ -124,7 +124,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:19 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:19 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -----^^^--------- @@ -134,7 +134,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:38 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -^^^----- @@ -144,7 +144,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:70:9 | LL | mut a @ Some([ref b, ref mut c]) => {} | -----^^^^^^^^^-----^^---------^^ @@ -155,7 +155,7 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:77:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:76:9 | LL | a @ Some(ref b) => {} | -^^^^^^^^-----^ @@ -165,7 +165,7 @@ LL | a @ Some(ref b) => {} | move occurs because `a` has type `Option` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:9 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^ @@ -176,7 +176,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:19 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:19 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -----^^^--------- @@ -186,7 +186,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:38 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -^^^----- @@ -196,7 +196,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:92:9 | LL | mut a @ Some([ref b, ref mut c]) => {} | -----^^^^^^^^^-----^^---------^^ @@ -207,7 +207,7 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:13:11 | LL | fn f1(a @ ref b: U) {} | -^^^----- @@ -217,7 +217,7 @@ LL | fn f1(a @ ref b: U) {} | move occurs because `a` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:11 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:11 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | -----^^^^^^^^-----^^^^^^^^^^-----^ @@ -228,7 +228,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:20 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:20 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | -^^^----- @@ -238,7 +238,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:31 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:31 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | -----^^^----- @@ -248,7 +248,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:25:11 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:11 | LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {} | -^^^^---------^^-----^ @@ -259,7 +259,7 @@ LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {} | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:22 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:22 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | --------^^^^^^^^^ @@ -270,7 +270,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: use of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:33 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:33 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | ------------------------^^^^^^^^^- ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait @@ -279,7 +279,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:37 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:37 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | ----^^^^^ @@ -290,7 +290,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:25 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:37:25 | LL | let a @ [ref mut b, ref c] = [U, U]; | ----------------^^^^^- ------ move occurs because value has type `[U; 2]`, which does not implement the `Copy` trait @@ -299,7 +299,7 @@ LL | let a @ [ref mut b, ref c] = [U, U]; | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:41:13 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:40:13 | LL | let a @ ref b = u(); | ----^^^^^ --- move occurs because value has type `U`, which does not implement the `Copy` trait @@ -308,7 +308,7 @@ LL | let a @ ref b = u(); | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:22 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:22 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | --------^^^^^^^^^ @@ -319,7 +319,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: use of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:33 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:33 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | ------------------------^^^^^^^^^- ---------- move occurs because value has type `(U, U)`, which does not implement the `Copy` trait @@ -328,7 +328,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:37 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:37 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | ----^^^^^ @@ -339,7 +339,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:51:25 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:50:25 | LL | let a @ [ref mut b, ref c] = [u(), u()]; | ----------------^^^^^- ---------- move occurs because value has type `[U; 2]`, which does not implement the `Copy` trait @@ -348,7 +348,7 @@ LL | let a @ [ref mut b, ref c] = [u(), u()]; | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:27 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:27 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | --------^^^^^^^^^ @@ -363,7 +363,7 @@ LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {} | ^^^ error[E0382]: use of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:38 | LL | match Some((U, U)) { | ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait @@ -374,7 +374,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:42 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:42 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | ----^^^^^ @@ -389,7 +389,7 @@ LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {} | ^^^ error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:30 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:70:30 | LL | match Some([U, U]) { | ------------ move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait @@ -400,7 +400,7 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:77:18 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:76:18 | LL | match Some(u()) { | --------- move occurs because value has type `Option`, which does not implement the `Copy` trait @@ -411,7 +411,7 @@ LL | a @ Some(ref b) => {} | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:27 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:27 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | --------^^^^^^^^^ @@ -426,7 +426,7 @@ LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {} | ^^^ error[E0382]: use of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:38 | LL | match Some((u(), u())) { | ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait @@ -437,7 +437,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:42 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:42 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | ----^^^^^ @@ -452,7 +452,7 @@ LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {} | ^^^ error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:30 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:92:30 | LL | match Some([u(), u()]) { | ---------------- move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait @@ -463,7 +463,7 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:15 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:13:15 | LL | fn f1(a @ ref b: U) {} | ----^^^^^ @@ -473,7 +473,7 @@ LL | fn f1(a @ ref b: U) {} | move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:24 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:24 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | ----^^^^^ @@ -484,7 +484,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: use of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:31 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:31 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | --------------------^^^^^^^^^^^^^- @@ -494,7 +494,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | move occurs because value has type `(U, U)`, which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:39 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:39 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | --------^^^^^ @@ -505,7 +505,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:25:27 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:27 | LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {} | ----------------^^^^^- diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs index b7c8c8766c00a..42c3290ddfbb2 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs @@ -1,7 +1,6 @@ // Test that `ref mut? @ pat_with_by_move_bindings` is prevented. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() { struct U; diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr index e5419efa00b36..a275705b19332 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr @@ -1,5 +1,5 @@ error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:23:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:22:9 | LL | let ref a @ b = U; | -----^^^- @@ -8,7 +8,7 @@ LL | let ref a @ b = U; | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:25:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:24:9 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | -----^^^^^^^^^^^^-----^^^^^^^^^^-^ @@ -18,7 +18,7 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:25:18 + --> $DIR/borrowck-pat-by-move-and-ref.rs:24:18 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | -----^^^----- @@ -27,7 +27,7 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | value borrowed, by `b`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:25:33 + --> $DIR/borrowck-pat-by-move-and-ref.rs:24:33 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | -----^^^- @@ -36,7 +36,7 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | value borrowed, by `d`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:29:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:28:9 | LL | let ref mut a @ [b, mut c] = [U, U]; | ---------^^^^-^^-----^ @@ -46,7 +46,7 @@ LL | let ref mut a @ [b, mut c] = [U, U]; | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:31:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9 | LL | let ref a @ b = u(); | -----^^^- @@ -55,7 +55,7 @@ LL | let ref a @ b = u(); | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:32:9 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | -----^^^^^^^^^^^^-----^^^^^^^^^^-^ @@ -65,7 +65,7 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:33:18 + --> $DIR/borrowck-pat-by-move-and-ref.rs:32:18 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | -----^^^----- @@ -74,7 +74,7 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | value borrowed, by `b`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:33:33 + --> $DIR/borrowck-pat-by-move-and-ref.rs:32:33 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | -----^^^- @@ -83,7 +83,7 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | value borrowed, by `d`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:37:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:36:9 | LL | let ref mut a @ [b, mut c] = [u(), u()]; | ---------^^^^-^^-----^ @@ -93,7 +93,7 @@ LL | let ref mut a @ [b, mut c] = [u(), u()]; | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:41:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:40:9 | LL | ref a @ Some(b) => {} | -----^^^^^^^^-^ @@ -102,7 +102,7 @@ LL | ref a @ Some(b) => {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:46:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:45:9 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^ @@ -112,7 +112,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:46:23 + --> $DIR/borrowck-pat-by-move-and-ref.rs:45:23 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^----- @@ -121,7 +121,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed, by `b`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:46:38 + --> $DIR/borrowck-pat-by-move-and-ref.rs:45:38 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^- @@ -130,7 +130,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed, by `d`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:53:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:52:9 | LL | ref mut a @ Some([b, mut c]) => {} | ---------^^^^^^^^^-^^-----^^ @@ -140,7 +140,7 @@ LL | ref mut a @ Some([b, mut c]) => {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:58:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:57:9 | LL | ref a @ Some(b) => {} | -----^^^^^^^^-^ @@ -149,7 +149,7 @@ LL | ref a @ Some(b) => {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:63:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:62:9 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^ @@ -159,7 +159,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:63:23 + --> $DIR/borrowck-pat-by-move-and-ref.rs:62:23 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^----- @@ -168,7 +168,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed, by `b`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:63:38 + --> $DIR/borrowck-pat-by-move-and-ref.rs:62:38 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^- @@ -177,7 +177,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed, by `d`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:70:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:69:9 | LL | ref mut a @ Some([b, mut c]) => {} | ---------^^^^^^^^^-^^-----^^ @@ -187,7 +187,7 @@ LL | ref mut a @ Some([b, mut c]) => {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:14:11 + --> $DIR/borrowck-pat-by-move-and-ref.rs:13:11 | LL | fn f1(ref a @ b: U) {} | -----^^^- @@ -196,7 +196,7 @@ LL | fn f1(ref a @ b: U) {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:16:11 + --> $DIR/borrowck-pat-by-move-and-ref.rs:15:11 | LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | -----^^^^^^^^^^^^-----^^^^^^^^^^-^ @@ -206,7 +206,7 @@ LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:16:20 + --> $DIR/borrowck-pat-by-move-and-ref.rs:15:20 | LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | -----^^^----- @@ -215,7 +215,7 @@ LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | value borrowed, by `b`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:16:35 + --> $DIR/borrowck-pat-by-move-and-ref.rs:15:35 | LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | -----^^^- @@ -224,7 +224,7 @@ LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | value borrowed, by `d`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11 + --> $DIR/borrowck-pat-by-move-and-ref.rs:19:11 | LL | fn f3(ref mut a @ [b, mut c]: [U; 2]) {} | ---------^^^^-^^-----^ diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs index 2b5e339c6396e..f67cd45ca95ab 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs @@ -1,5 +1,4 @@ #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] enum Option { None, diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr index 695da9639af9a..e6231dd49bade 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr @@ -1,5 +1,5 @@ error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:11:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:10:9 | LL | ref mut z @ &mut Some(ref a) => { | ---------^^^^^^^^^^^^^-----^ @@ -8,7 +8,7 @@ LL | ref mut z @ &mut Some(ref a) => { | mutable borrow, by `z`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:35:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:34:9 | LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub | ---------^^^^-----------------^ @@ -18,7 +18,7 @@ LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:35:22 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:34:22 | LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub | -----^^^--------- @@ -27,7 +27,7 @@ LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub | immutable borrow, by `b`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:39:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:38:9 | LL | let ref a @ ref mut b = U; | -----^^^--------- @@ -36,7 +36,7 @@ LL | let ref a @ ref mut b = U; | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:41:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:40:9 | LL | let ref mut a @ ref b = U; | ---------^^^----- @@ -45,7 +45,7 @@ LL | let ref mut a @ ref b = U; | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:43:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:42:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | -----^^^^---------^^---------^ @@ -55,7 +55,7 @@ LL | let ref a @ (ref mut b, ref mut c) = (U, U); | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:45:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:44:9 | LL | let ref mut a @ (ref b, ref c) = (U, U); | ---------^^^^-----^^-----^ @@ -65,7 +65,7 @@ LL | let ref mut a @ (ref b, ref c) = (U, U); | mutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:48:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:47:9 | LL | let ref mut a @ ref b = u(); | ---------^^^----- @@ -74,7 +74,7 @@ LL | let ref mut a @ ref b = u(); | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:53:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:52:9 | LL | let ref a @ ref mut b = u(); | -----^^^--------- @@ -83,7 +83,7 @@ LL | let ref a @ ref mut b = u(); | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:59:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:58:9 | LL | let ref mut a @ ref b = U; | ---------^^^----- @@ -92,7 +92,7 @@ LL | let ref mut a @ ref b = U; | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:63:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:62:9 | LL | let ref a @ ref mut b = U; | -----^^^--------- @@ -101,7 +101,7 @@ LL | let ref a @ ref mut b = U; | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:69:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:68:9 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { | ---------^^^^^^-----^ @@ -110,7 +110,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { | mutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:69:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:68:33 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { | ---------^^^^^^^-----^ @@ -119,7 +119,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:9 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | -----^^^^^^---------^ @@ -128,7 +128,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:33 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | -----^^^^^^^---------^ @@ -137,7 +137,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:89:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:88:9 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} | -----^^^^^^---------^ @@ -146,7 +146,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:89:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:88:33 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} | -----^^^^^^^---------^ @@ -155,7 +155,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:95:9 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} | ---------^^^^^^-----^ @@ -164,7 +164,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); fa | mutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:95:33 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} | ---------^^^^^^^-----^ @@ -173,7 +173,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); fa | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:9 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} | -----^^^^^^---------^ @@ -182,7 +182,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:33 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} | -----^^^^^^^---------^ @@ -191,7 +191,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:9 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} | ---------^^^^^^-----^ @@ -200,7 +200,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false | mutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:33 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} | ---------^^^^^^^-----^ @@ -209,7 +209,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:119:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:118:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | -----^^^^---------^^---------^ @@ -219,7 +219,7 @@ LL | let ref a @ (ref mut b, ref mut c) = (U, U); | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:124:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | -----^^^^---------^^---------^ @@ -229,7 +229,7 @@ LL | let ref a @ (ref mut b, ref mut c) = (U, U); | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:130:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | -----^^^^---------^^---------^ @@ -239,7 +239,7 @@ LL | let ref a @ (ref mut b, ref mut c) = (U, U); | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:136:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:135:9 | LL | let ref mut a @ (ref b, ref c) = (U, U); | ---------^^^^-----^^-----^ @@ -249,7 +249,7 @@ LL | let ref mut a @ (ref b, ref c) = (U, U); | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:25:11 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:24:11 | LL | fn f1(ref a @ ref mut b: U) {} | -----^^^--------- @@ -258,7 +258,7 @@ LL | fn f1(ref a @ ref mut b: U) {} | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:27:11 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:26:11 | LL | fn f2(ref mut a @ ref b: U) {} | ---------^^^----- @@ -267,7 +267,7 @@ LL | fn f2(ref mut a @ ref b: U) {} | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:29:11 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:11 | LL | fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {} | -----^^^^^^^^^^^----------------^^^^^^^^ @@ -276,7 +276,7 @@ LL | fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {} | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:31:22 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:30:22 | LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} | -----^^^------------- @@ -286,7 +286,7 @@ LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} | immutable borrow, by `a`, occurs here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:31:30 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:30:30 | LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} | ---------^^^- @@ -295,7 +295,7 @@ LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} | value borrowed, by `b`, here error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:11:31 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:10:31 | LL | ref mut z @ &mut Some(ref a) => { | ----------------------^^^^^- @@ -307,7 +307,7 @@ LL | **z = None; | ---------- mutable borrow later used here error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:48:21 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:47:21 | LL | let ref mut a @ ref b = u(); | ------------^^^^^ @@ -319,7 +319,7 @@ LL | *a = u(); | -------- mutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:53:17 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:52:17 | LL | let ref a @ ref mut b = u(); | --------^^^^^^^^^ @@ -331,7 +331,7 @@ LL | drop(a); | - immutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:20 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:20 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | -----------^^^^^^^^^- @@ -343,7 +343,7 @@ LL | drop(a); | - immutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:45 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:45 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | ------------^^^^^^^^^- @@ -355,7 +355,7 @@ LL | drop(a); | - immutable borrow later used here error[E0594]: cannot assign to `*b`, as it is immutable for the pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:89:61 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:88:61 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} | ^^^^^^ cannot assign @@ -363,7 +363,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } = note: variables bound in patterns are immutable until the end of the pattern guard error[E0594]: cannot assign to `*a`, as it is immutable for the pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:61 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:95:61 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} | ^^^^^^^^^^^ cannot assign @@ -371,7 +371,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); fa = note: variables bound in patterns are immutable until the end of the pattern guard error[E0507]: cannot move out of `b` in pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:66 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait @@ -379,7 +379,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error[E0507]: cannot move out of `b` in pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:66 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait @@ -387,7 +387,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error[E0507]: cannot move out of `a` in pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:66 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:66 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} | ^ move occurs because `a` has type `&mut std::result::Result`, which does not implement the `Copy` trait @@ -395,7 +395,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error[E0507]: cannot move out of `a` in pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:66 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:66 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} | ^ move occurs because `a` has type `&mut std::result::Result`, which does not implement the `Copy` trait @@ -403,7 +403,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:124:18 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:18 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | ---------^^^^^^^^^------------ @@ -415,7 +415,7 @@ LL | drop(a); | - immutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:124:29 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:29 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | --------------------^^^^^^^^^- @@ -427,7 +427,7 @@ LL | drop(a); | - immutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:18 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:130:18 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | ---------^^^^^^^^^------------ @@ -439,7 +439,7 @@ LL | drop(a); | - immutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:29 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:130:29 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | --------------------^^^^^^^^^- diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs index a208d0087ff53..8faaa1c881fbf 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs @@ -1,7 +1,6 @@ // Test that `ref mut x @ ref mut y` and varieties of that are not allowed. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() { struct U; diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr index 1cd3e267b9950..2e0f5fcabddf3 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr @@ -1,5 +1,5 @@ error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:28:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:27:9 | LL | let ref mut a @ ref mut b = U; | ---------^^^--------- @@ -8,7 +8,7 @@ LL | let ref mut a @ ref mut b = U; | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:32:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:31:9 | LL | let ref mut a @ ref mut b = U; | ---------^^^--------- @@ -17,7 +17,7 @@ LL | let ref mut a @ ref mut b = U; | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:35:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:34:9 | LL | let ref mut a @ ref mut b = U; | ---------^^^--------- @@ -26,7 +26,7 @@ LL | let ref mut a @ ref mut b = U; | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:38:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:37:9 | LL | let ref mut a @ ref mut b = U; | ---------^^^--------- @@ -35,7 +35,7 @@ LL | let ref mut a @ ref mut b = U; | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:42:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:41:9 | LL | let ref mut a @ ref mut b = U; | ---------^^^--------- @@ -44,7 +44,7 @@ LL | let ref mut a @ ref mut b = U; | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:46:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:45:9 | LL | let ref mut a @ ( | ^-------- @@ -66,7 +66,7 @@ LL | | ) = (U, [U, U, U]); | |_____^ error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:56:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:55:9 | LL | let ref mut a @ ( | ^-------- @@ -88,7 +88,7 @@ LL | | ) = (u(), [u(), u(), u()]); | |_________^ error: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:66:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:65:9 | LL | let a @ (ref mut b, ref mut c) = (U, U); | -^^^^---------^^---------^ @@ -99,7 +99,7 @@ LL | let a @ (ref mut b, ref mut c) = (U, U); | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:70:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:69:9 | LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- | -^^^^-^^^-^^-^^ @@ -111,7 +111,7 @@ LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- | move occurs because `a` has type `&mut (U, [U; 2])` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:74:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:73:9 | LL | let a @ &mut ref mut b = &mut U; | -^^^^^^^^--------- @@ -121,7 +121,7 @@ LL | let a @ &mut ref mut b = &mut U; | move occurs because `a` has type `&mut U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:77:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:76:9 | LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); | -^^^^^^^^^---------^^---------^ @@ -132,7 +132,7 @@ LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); | move occurs because `a` has type `&mut (U, U)` which does not implement the `Copy` trait error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:82:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:81:9 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^---------^ @@ -141,7 +141,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:82:37 + --> $DIR/borrowck-pat-ref-mut-twice.rs:81:37 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^^---------^ @@ -150,7 +150,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:88:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:87:9 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^---------^ @@ -159,7 +159,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:88:37 + --> $DIR/borrowck-pat-ref-mut-twice.rs:87:37 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^^---------^ @@ -168,7 +168,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:95:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:94:9 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^---------^ @@ -177,7 +177,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:95:37 + --> $DIR/borrowck-pat-ref-mut-twice.rs:94:37 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^^---------^ @@ -186,7 +186,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:107:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:106:9 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^---------^ @@ -195,7 +195,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:107:37 + --> $DIR/borrowck-pat-ref-mut-twice.rs:106:37 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^^---------^ @@ -204,7 +204,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:11:11 + --> $DIR/borrowck-pat-ref-mut-twice.rs:10:11 | LL | fn f1(ref mut a @ ref mut b: U) {} | ---------^^^--------- @@ -213,7 +213,7 @@ LL | fn f1(ref mut a @ ref mut b: U) {} | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:13:11 + --> $DIR/borrowck-pat-ref-mut-twice.rs:12:11 | LL | fn f2(ref mut a @ ref mut b: U) {} | ---------^^^--------- @@ -222,7 +222,7 @@ LL | fn f2(ref mut a @ ref mut b: U) {} | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:16:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:15:9 | LL | ref mut a @ [ | ^-------- @@ -240,7 +240,7 @@ LL | | ] : [[U; 4]; 5] | |_________^ error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:24:22 + --> $DIR/borrowck-pat-ref-mut-twice.rs:23:22 | LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} | ---------^^^------------- @@ -250,7 +250,7 @@ LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} | first mutable borrow, by `a`, occurs here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-ref-mut-twice.rs:24:34 + --> $DIR/borrowck-pat-ref-mut-twice.rs:23:34 | LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} | ---------^^^- @@ -259,7 +259,7 @@ LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} | value borrowed, by `b`, here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:28:21 + --> $DIR/borrowck-pat-ref-mut-twice.rs:27:21 | LL | let ref mut a @ ref mut b = U; | ------------^^^^^^^^^ @@ -271,7 +271,7 @@ LL | drop(a); | - first borrow later used here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:38:21 + --> $DIR/borrowck-pat-ref-mut-twice.rs:37:21 | LL | let ref mut a @ ref mut b = U; | ------------^^^^^^^^^ @@ -283,7 +283,7 @@ LL | *a = U; | ------ first borrow later used here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:66:25 + --> $DIR/borrowck-pat-ref-mut-twice.rs:65:25 | LL | let a @ (ref mut b, ref mut c) = (U, U); | ----------------^^^^^^^^^- ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait @@ -292,7 +292,7 @@ LL | let a @ (ref mut b, ref mut c) = (U, U); | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:70:21 + --> $DIR/borrowck-pat-ref-mut-twice.rs:69:21 | LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- | ------------^-- -------- move occurs because value has type `&mut (U, [U; 2])`, which does not implement the `Copy` trait @@ -301,7 +301,7 @@ LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:74:18 + --> $DIR/borrowck-pat-ref-mut-twice.rs:73:18 | LL | let a @ &mut ref mut b = &mut U; | ---------^^^^^^^^^ ------ move occurs because value has type `&mut U`, which does not implement the `Copy` trait @@ -310,7 +310,7 @@ LL | let a @ &mut ref mut b = &mut U; | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:77:30 + --> $DIR/borrowck-pat-ref-mut-twice.rs:76:30 | LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); | ---------------------^^^^^^^^^- ----------- move occurs because value has type `&mut (U, U)`, which does not implement the `Copy` trait @@ -319,7 +319,7 @@ LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); | value moved here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:95:24 + --> $DIR/borrowck-pat-ref-mut-twice.rs:94:24 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------------^^^^^^^^^- @@ -331,7 +331,7 @@ LL | *a = Err(U); | ----------- first borrow later used here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:95:53 + --> $DIR/borrowck-pat-ref-mut-twice.rs:94:53 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ----------------^^^^^^^^^- @@ -343,7 +343,7 @@ LL | *a = Err(U); | ----------- first borrow later used here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:107:24 + --> $DIR/borrowck-pat-ref-mut-twice.rs:106:24 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------------^^^^^^^^^- @@ -355,7 +355,7 @@ LL | drop(a); | - first borrow later used here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:107:53 + --> $DIR/borrowck-pat-ref-mut-twice.rs:106:53 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ----------------^^^^^^^^^- diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs index 821d4b42962bf..3954d17e1c2bc 100644 --- a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs +++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs @@ -1,7 +1,6 @@ // Test that mixing `Copy` and non-`Copy` types in `@` patterns is forbidden. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] #[derive(Copy, Clone)] struct C; diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr index 7e89008a60496..cc2786a13f4e8 100644 --- a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr +++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value - --> $DIR/copy-and-move-mixed.rs:12:19 + --> $DIR/copy-and-move-mixed.rs:11:19 | LL | let a @ NC(b, c) = NC(C, C); | ----------^- -------- move occurs because value has type `NC`, which does not implement the `Copy` trait @@ -8,7 +8,7 @@ LL | let a @ NC(b, c) = NC(C, C); | value moved here error[E0382]: use of moved value - --> $DIR/copy-and-move-mixed.rs:15:19 + --> $DIR/copy-and-move-mixed.rs:14:19 | LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); | ----------^^^^^^^^^^^^- --------------- move occurs because value has type `NC>`, which does not implement the `Copy` trait @@ -17,7 +17,7 @@ LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); | value moved here error[E0382]: use of moved value - --> $DIR/copy-and-move-mixed.rs:15:29 + --> $DIR/copy-and-move-mixed.rs:14:29 | LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); | ----------^- diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs index a45497229ac9e..276088b9a9ee9 100644 --- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs +++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs @@ -8,7 +8,6 @@ // this would create problems for the generalization aforementioned. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() { struct NotCopy; diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr index a63a5a1e6c7d4..11d5e24f34e13 100644 --- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr +++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr @@ -1,5 +1,5 @@ error: cannot move out of value because it is borrowed - --> $DIR/default-binding-modes-both-sides-independent.rs:28:9 + --> $DIR/default-binding-modes-both-sides-independent.rs:27:9 | LL | let ref a @ b = NotCopy; | -----^^^- @@ -8,7 +8,7 @@ LL | let ref a @ b = NotCopy; | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/default-binding-modes-both-sides-independent.rs:31:9 + --> $DIR/default-binding-modes-both-sides-independent.rs:30:9 | LL | let ref mut a @ b = NotCopy; | ---------^^^- @@ -17,7 +17,7 @@ LL | let ref mut a @ b = NotCopy; | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/default-binding-modes-both-sides-independent.rs:36:12 + --> $DIR/default-binding-modes-both-sides-independent.rs:35:12 | LL | Ok(ref a @ b) | Err(b @ ref a) => { | -----^^^- @@ -26,7 +26,7 @@ LL | Ok(ref a @ b) | Err(b @ ref a) => { | value borrowed, by `a`, here error: borrow of moved value - --> $DIR/default-binding-modes-both-sides-independent.rs:36:29 + --> $DIR/default-binding-modes-both-sides-independent.rs:35:29 | LL | Ok(ref a @ b) | Err(b @ ref a) => { | -^^^----- @@ -36,7 +36,7 @@ LL | Ok(ref a @ b) | Err(b @ ref a) => { | move occurs because `b` has type `NotCopy` which does not implement the `Copy` trait error: cannot move out of value because it is borrowed - --> $DIR/default-binding-modes-both-sides-independent.rs:44:9 + --> $DIR/default-binding-modes-both-sides-independent.rs:43:9 | LL | ref a @ b => { | -----^^^- @@ -45,7 +45,7 @@ LL | ref a @ b => { | value borrowed, by `a`, here error[E0505]: cannot move out of value because it is borrowed - --> $DIR/default-binding-modes-both-sides-independent.rs:31:21 + --> $DIR/default-binding-modes-both-sides-independent.rs:30:21 | LL | let ref mut a @ b = NotCopy; | ------------^ diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs index d2d4e61e049b2..5445696fdff7d 100644 --- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs +++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(move_ref_pattern)] - fn main() {} struct U; diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs index 3ee008fd84f09..9c320edc4dc0e 100644 --- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs +++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs @@ -1,5 +1,3 @@ -#![feature(move_ref_pattern)] - fn main() {} struct U; diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr index d718ee29cf9b5..285c203f382df 100644 --- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr +++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr @@ -1,5 +1,5 @@ error[E0505]: cannot move out of `arr[..]` because it is borrowed - --> $DIR/borrowck-move-ref-pattern.rs:10:24 + --> $DIR/borrowck-move-ref-pattern.rs:8:24 | LL | let hold_all = &arr; | ---- borrow of `arr` occurs here @@ -10,7 +10,7 @@ LL | drop(hold_all); | -------- borrow later used here error[E0384]: cannot assign twice to immutable variable `_x1` - --> $DIR/borrowck-move-ref-pattern.rs:11:5 + --> $DIR/borrowck-move-ref-pattern.rs:9:5 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; | --- @@ -21,7 +21,7 @@ LL | _x1 = U; | ^^^^^^^ cannot assign twice to immutable variable error[E0505]: cannot move out of `arr[..]` because it is borrowed - --> $DIR/borrowck-move-ref-pattern.rs:13:10 + --> $DIR/borrowck-move-ref-pattern.rs:11:10 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; | ------------ borrow of `arr[..]` occurs here @@ -32,7 +32,7 @@ LL | drop(_x0_hold); | -------- borrow later used here error[E0502]: cannot borrow `arr[..]` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-move-ref-pattern.rs:15:16 + --> $DIR/borrowck-move-ref-pattern.rs:13:16 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; | ---------------- immutable borrow occurs here @@ -44,7 +44,7 @@ LL | drop(xs_hold); | ------- immutable borrow later used here error[E0505]: cannot move out of `arr[..]` because it is borrowed - --> $DIR/borrowck-move-ref-pattern.rs:15:29 + --> $DIR/borrowck-move-ref-pattern.rs:13:29 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; | ---------------- borrow of `arr[..]` occurs here @@ -56,7 +56,7 @@ LL | drop(xs_hold); | ------- borrow later used here error[E0505]: cannot move out of `arr[..]` because it is borrowed - --> $DIR/borrowck-move-ref-pattern.rs:15:34 + --> $DIR/borrowck-move-ref-pattern.rs:13:34 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; | ---------------- borrow of `arr[..]` occurs here @@ -68,7 +68,7 @@ LL | drop(xs_hold); | ------- borrow later used here error[E0384]: cannot assign twice to immutable variable `_x1` - --> $DIR/borrowck-move-ref-pattern.rs:25:5 + --> $DIR/borrowck-move-ref-pattern.rs:23:5 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; | --- @@ -79,7 +79,7 @@ LL | _x1 = U; | ^^^^^^^ cannot assign twice to immutable variable error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-move-ref-pattern.rs:26:20 + --> $DIR/borrowck-move-ref-pattern.rs:24:20 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; | ------- immutable borrow occurs here @@ -91,7 +91,7 @@ LL | *_x0 = U; | -------- immutable borrow later used here error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-move-ref-pattern.rs:27:10 + --> $DIR/borrowck-move-ref-pattern.rs:25:10 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; | ------- immutable borrow occurs here @@ -102,7 +102,7 @@ LL | *_x0 = U; | -------- immutable borrow later used here error[E0594]: cannot assign to `*_x0` which is behind a `&` reference - --> $DIR/borrowck-move-ref-pattern.rs:28:5 + --> $DIR/borrowck-move-ref-pattern.rs:26:5 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; | ------- help: consider changing this to be a mutable reference: `ref mut _x0` @@ -111,7 +111,7 @@ LL | *_x0 = U; | ^^^^^^^^ `_x0` is a `&` reference, so the data it refers to cannot be written error[E0594]: cannot assign to `*_x2` which is behind a `&` reference - --> $DIR/borrowck-move-ref-pattern.rs:29:5 + --> $DIR/borrowck-move-ref-pattern.rs:27:5 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; | ------- help: consider changing this to be a mutable reference: `ref mut _x2` @@ -120,7 +120,7 @@ LL | *_x2 = U; | ^^^^^^^^ `_x2` is a `&` reference, so the data it refers to cannot be written error[E0382]: use of moved value: `tup.1` - --> $DIR/borrowck-move-ref-pattern.rs:30:10 + --> $DIR/borrowck-move-ref-pattern.rs:28:10 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; | --- value moved here @@ -131,7 +131,7 @@ LL | drop(tup.1); = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `tup.1` - --> $DIR/borrowck-move-ref-pattern.rs:31:20 + --> $DIR/borrowck-move-ref-pattern.rs:29:20 | LL | drop(tup.1); | ----- value moved here @@ -141,7 +141,7 @@ LL | let _x1_hold = &tup.1; = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait error[E0502]: cannot borrow `tup.3` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-move-ref-pattern.rs:33:20 + --> $DIR/borrowck-move-ref-pattern.rs:31:20 | LL | let (.., ref mut _x3) = tup; | ----------- mutable borrow occurs here @@ -152,7 +152,7 @@ LL | drop(_x3); | --- mutable borrow later used here error[E0499]: cannot borrow `tup.3` as mutable more than once at a time - --> $DIR/borrowck-move-ref-pattern.rs:34:20 + --> $DIR/borrowck-move-ref-pattern.rs:32:20 | LL | let (.., ref mut _x3) = tup; | ----------- first mutable borrow occurs here @@ -164,7 +164,7 @@ LL | drop(_x3); | --- first borrow later used here error[E0499]: cannot borrow `tup.3` as mutable more than once at a time - --> $DIR/borrowck-move-ref-pattern.rs:35:14 + --> $DIR/borrowck-move-ref-pattern.rs:33:14 | LL | let (.., ref mut _x3) = tup; | ----------- first mutable borrow occurs here @@ -176,7 +176,7 @@ LL | drop(_x3); | --- first borrow later used here error[E0502]: cannot borrow `tup.3` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-move-ref-pattern.rs:36:14 + --> $DIR/borrowck-move-ref-pattern.rs:34:14 | LL | let (.., ref mut _x3) = tup; | ----------- mutable borrow occurs here @@ -187,7 +187,7 @@ LL | drop(_x3); | --- mutable borrow later used here error[E0382]: use of moved value: `tup` - --> $DIR/borrowck-move-ref-pattern.rs:45:14 + --> $DIR/borrowck-move-ref-pattern.rs:43:14 | LL | let mut tup = (U, U, U); | ------- move occurs because `tup` has type `(U, U, U)`, which does not implement the `Copy` trait diff --git a/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs b/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs index 08fb5cd2e1688..18663c3fe3f96 100644 --- a/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs +++ b/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs @@ -4,7 +4,6 @@ // check-pass -#![feature(move_ref_pattern)] #![feature(bindings_after_at)] fn main() { diff --git a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs b/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs deleted file mode 100644 index fb92eb1ba32e0..0000000000000 --- a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs +++ /dev/null @@ -1,23 +0,0 @@ -fn main() { - #[derive(Clone)] - struct X { - x: (), - } - let mut tup = (X { x: () }, X { x: () }); - match Some(tup.clone()) { - Some((y, ref z)) => {} - //~^ ERROR binding by-move and by-ref in the same pattern is unstable - None => panic!(), - } - - let (ref a, b) = tup.clone(); - //~^ ERROR binding by-move and by-ref in the same pattern is unstable - - let (a, mut b) = &tup; - //~^ ERROR binding by-move and by-ref in the same pattern is unstable - //~| ERROR cannot move out of a shared reference - - let (mut a, b) = &mut tup; - //~^ ERROR binding by-move and by-ref in the same pattern is unstable - //~| ERROR cannot move out of a mutable reference -} diff --git a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr b/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr deleted file mode 100644 index 5335569a972b2..0000000000000 --- a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr +++ /dev/null @@ -1,66 +0,0 @@ -error[E0658]: binding by-move and by-ref in the same pattern is unstable - --> $DIR/feature-gate-move_ref_pattern.rs:8:15 - | -LL | Some((y, ref z)) => {} - | ^ ----- by-ref pattern here - | | - | by-move pattern here - | - = note: see issue #68354 for more information - = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable - -error[E0658]: binding by-move and by-ref in the same pattern is unstable - --> $DIR/feature-gate-move_ref_pattern.rs:13:17 - | -LL | let (ref a, b) = tup.clone(); - | ----- ^ by-move pattern here - | | - | by-ref pattern here - | - = note: see issue #68354 for more information - = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable - -error[E0658]: binding by-move and by-ref in the same pattern is unstable - --> $DIR/feature-gate-move_ref_pattern.rs:16:13 - | -LL | let (a, mut b) = &tup; - | - ^^^^^ by-move pattern here - | | - | by-ref pattern here - | - = note: see issue #68354 for more information - = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable - -error[E0658]: binding by-move and by-ref in the same pattern is unstable - --> $DIR/feature-gate-move_ref_pattern.rs:20:10 - | -LL | let (mut a, b) = &mut tup; - | ^^^^^ - by-ref pattern here - | | - | by-move pattern here - | - = note: see issue #68354 for more information - = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable - -error[E0507]: cannot move out of a shared reference - --> $DIR/feature-gate-move_ref_pattern.rs:16:22 - | -LL | let (a, mut b) = &tup; - | ----- ^^^^ - | | - | data moved here - | move occurs because `b` has type `X`, which does not implement the `Copy` trait - -error[E0507]: cannot move out of a mutable reference - --> $DIR/feature-gate-move_ref_pattern.rs:20:22 - | -LL | let (mut a, b) = &mut tup; - | ----- ^^^^^^^^ - | | - | data moved here - | move occurs because `a` has type `X`, which does not implement the `Copy` trait - -error: aborting due to 6 previous errors - -Some errors have detailed explanations: E0507, E0658. -For more information about an error, try `rustc --explain E0507`. diff --git a/src/test/ui/pattern/move-ref-patterns/issue-53840.rs b/src/test/ui/pattern/move-ref-patterns/issue-53840.rs index ab7d10d9f837d..80effc497ed93 100644 --- a/src/test/ui/pattern/move-ref-patterns/issue-53840.rs +++ b/src/test/ui/pattern/move-ref-patterns/issue-53840.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(move_ref_pattern)] - enum E { Foo(String, String, String), } diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs index 4c3ca62e16586..ebb1683af7de6 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs @@ -1,5 +1,3 @@ -#![feature(move_ref_pattern)] - fn main() { struct S; // Not `Copy`. diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr index 9ad84879595e7..f19fed0891740 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr @@ -1,5 +1,5 @@ error[E0382]: borrow of moved value: `tup0` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:33:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:31:10 | LL | let mut tup0 = (S, S); | -------- move occurs because `tup0` has type `(S, S)`, which does not implement the `Copy` trait @@ -14,7 +14,7 @@ LL | drop(&tup0); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup1` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:34:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:32:10 | LL | let mut tup1 = (S, S, S); | -------- move occurs because `tup1` has type `(S, S, S)`, which does not implement the `Copy` trait @@ -29,7 +29,7 @@ LL | drop(&tup1); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup2` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:35:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:33:10 | LL | let tup2 = (S, S); | ---- move occurs because `tup2` has type `(S, S)`, which does not implement the `Copy` trait @@ -44,7 +44,7 @@ LL | drop(&tup2); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup3` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:36:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:34:10 | LL | let tup3 = (S, S, S); | ---- move occurs because `tup3` has type `(S, S, S)`, which does not implement the `Copy` trait @@ -59,7 +59,7 @@ LL | drop(&tup3); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup4` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:41:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:39:10 | LL | let tup4 = (S, S); | ---- move occurs because `tup4` has type `(S, S)`, which does not implement the `Copy` trait @@ -74,7 +74,7 @@ LL | drop(&tup4.0); | ^^^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr0` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:43:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:41:10 | LL | let mut arr0 = [S, S, S]; | -------- move occurs because `arr0` has type `[S; 3]`, which does not implement the `Copy` trait @@ -89,7 +89,7 @@ LL | drop(&arr0); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr1` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:44:36 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:42:36 | LL | let mut arr1 = [S, S, S, S, S]; | -------- move occurs because `arr1` has type `[S; 5]`, which does not implement the `Copy` trait @@ -104,7 +104,7 @@ LL | let [_, mov1, mov2, mov3, _] = &arr1; | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr2` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:45:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:43:10 | LL | let arr2 = [S, S, S]; | ---- move occurs because `arr2` has type `[S; 3]`, which does not implement the `Copy` trait @@ -119,7 +119,7 @@ LL | drop(&arr2); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr3` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:46:36 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:44:36 | LL | let arr3 = [S, S, S, S, S]; | ---- move occurs because `arr3` has type `[S; 5]`, which does not implement the `Copy` trait @@ -134,7 +134,7 @@ LL | let [_, mov1, mov2, mov3, _] = &arr3; | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup0` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:77:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:75:10 | LL | let mut tup0: Option<(S, S)> = None; | -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait @@ -148,7 +148,7 @@ LL | drop(&tup0); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup1` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:78:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:76:10 | LL | let mut tup1: Option<(S, S, S)> = None; | -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait @@ -163,7 +163,7 @@ LL | drop(&tup1); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup2` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:79:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:77:10 | LL | let tup2: Option<(S, S)> = None; | ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait @@ -178,7 +178,7 @@ LL | drop(&tup2); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup3` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:80:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:78:10 | LL | let tup3: Option<(S, S, S)> = None; | ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait @@ -193,7 +193,7 @@ LL | drop(&tup3); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup4` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:81:21 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:79:21 | LL | let tup4: Option<(S, S)> = None; | ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait @@ -208,7 +208,7 @@ LL | m!((ref x, _) = &tup4); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr0` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:82:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:80:10 | LL | let mut arr0: Option<[S; 3]> = None; | -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait @@ -223,7 +223,7 @@ LL | drop(&arr0); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr1` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:83:35 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:81:35 | LL | let mut arr1: Option<[S; 5]> = None; | -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait @@ -238,7 +238,7 @@ LL | m!([_, mov1, mov2, mov3, _] = &arr1); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr2` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:84:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:82:10 | LL | let arr2: Option<[S; 3]> = None; | ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait @@ -253,7 +253,7 @@ LL | drop(&arr2); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr3` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:85:35 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:83:35 | LL | let arr3: Option<[S; 5]> = None; | ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait @@ -267,7 +267,7 @@ LL | m!([_, mov1, mov2, mov3, _] = &arr3); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup0` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:113:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:111:10 | LL | let mut tup0: Option<(S, S)> = None; | -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait @@ -281,7 +281,7 @@ LL | drop(&tup0); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup1` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:114:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:112:10 | LL | let mut tup1: Option<(S, S, S)> = None; | -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait @@ -296,7 +296,7 @@ LL | drop(&tup1); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup2` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:115:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:113:10 | LL | let tup2: Option<(S, S)> = None; | ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait @@ -311,7 +311,7 @@ LL | drop(&tup2); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup3` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:116:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:114:10 | LL | let tup3: Option<(S, S, S)> = None; | ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait @@ -326,7 +326,7 @@ LL | drop(&tup3); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup4` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:117:21 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:115:21 | LL | let tup4: Option<(S, S)> = None; | ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait @@ -341,7 +341,7 @@ LL | m!((ref x, _) = &tup4); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr0` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:118:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:116:10 | LL | let mut arr0: Option<[S; 3]> = None; | -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait @@ -356,7 +356,7 @@ LL | drop(&arr0); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr1` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:119:35 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:117:35 | LL | let mut arr1: Option<[S; 5]> = None; | -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait @@ -371,7 +371,7 @@ LL | m!([_, mov1, mov2, mov3, _] = &arr1); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr2` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:120:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:118:10 | LL | let arr2: Option<[S; 3]> = None; | ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait @@ -386,7 +386,7 @@ LL | drop(&arr2); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr3` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:121:35 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:119:35 | LL | let arr3: Option<[S; 5]> = None; | ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs index e1844d36e4aa4..583f70f41aa70 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(move_ref_pattern)] - fn main() { struct U; fn accept_fn_once(_: impl FnOnce()) {} diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs index 7f1c02c05cb0d..cd619cc41eb27 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs @@ -1,5 +1,3 @@ -#![feature(move_ref_pattern)] - fn main() { struct U; fn accept_fn_once(_: &impl FnOnce()) {} diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr index ca82353c1c9ab..d96e863939c02 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr @@ -1,5 +1,5 @@ error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce` - --> $DIR/move-ref-patterns-closure-captures.rs:11:14 + --> $DIR/move-ref-patterns-closure-captures.rs:9:14 | LL | let c1 = || { | ^^ this closure implements `FnOnce`, not `FnMut` @@ -11,7 +11,7 @@ LL | accept_fn_mut(&c1); | ------------- the requirement to implement `FnMut` derives from here error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce` - --> $DIR/move-ref-patterns-closure-captures.rs:11:14 + --> $DIR/move-ref-patterns-closure-captures.rs:9:14 | LL | let c1 = || { | ^^ this closure implements `FnOnce`, not `Fn` @@ -23,7 +23,7 @@ LL | accept_fn(&c1); | --------- the requirement to implement `Fn` derives from here error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut` - --> $DIR/move-ref-patterns-closure-captures.rs:22:14 + --> $DIR/move-ref-patterns-closure-captures.rs:20:14 | LL | let c2 = || { | ^^ this closure implements `FnMut`, not `Fn` diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs index 5c51c47d9798a..1dd66aad57a33 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs @@ -1,5 +1,3 @@ -#![feature(move_ref_pattern)] - fn main() { struct U; diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr index f92699f5c3cc7..6952c743a3069 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of a shared reference - --> $DIR/move-ref-patterns-default-binding-modes.rs:10:22 + --> $DIR/move-ref-patterns-default-binding-modes.rs:8:22 | LL | let (a, mut b) = &p; | ----- ^^ @@ -8,7 +8,7 @@ LL | let (a, mut b) = &p; | move occurs because `b` has type `U`, which does not implement the `Copy` trait error[E0507]: cannot move out of a mutable reference - --> $DIR/move-ref-patterns-default-binding-modes.rs:14:22 + --> $DIR/move-ref-patterns-default-binding-modes.rs:12:22 | LL | let (a, mut b) = &mut p; | ----- ^^^^^^ diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs index c78695390b598..1d6d9acead1d4 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs @@ -3,8 +3,6 @@ // This test checks the dynamic semantics and drop order of pattern matching // where a product pattern has both a by-move and by-ref binding. -#![feature(move_ref_pattern)] - use std::cell::RefCell; use std::rc::Rc; diff --git a/src/test/ui/rfc-2005-default-binding-mode/for.rs b/src/test/ui/rfc-2005-default-binding-mode/for.rs index aa42c7bb9c2f1..d6c5a13b1bdb0 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/for.rs +++ b/src/test/ui/rfc-2005-default-binding-mode/for.rs @@ -1,5 +1,3 @@ -#![feature(move_ref_pattern)] - struct Foo {} pub fn main() { diff --git a/src/test/ui/rfc-2005-default-binding-mode/for.stderr b/src/test/ui/rfc-2005-default-binding-mode/for.stderr index ef62431388081..9cc20a7bf3144 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/for.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/for.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of a shared reference - --> $DIR/for.rs:8:23 + --> $DIR/for.rs:6:23 | LL | for (n, mut m) in &tups { | ----- ^^^^^ From afb9eeb1b9ea16ca65e38673a0ef3e7be81d7252 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi Date: Mon, 31 Aug 2020 07:01:32 +0800 Subject: [PATCH 05/50] Disabled error `E0007` from rustc_error_codes --- compiler/rustc_error_codes/src/error_codes/E0007.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0007.md b/compiler/rustc_error_codes/src/error_codes/E0007.md index 2be7870d5aeee..2c22b86af9246 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0007.md +++ b/compiler/rustc_error_codes/src/error_codes/E0007.md @@ -1,3 +1,5 @@ +#### Note: this error code is no longer emitted by the compiler. + This error indicates that the bindings in a match arm would require a value to be moved into more than one location, thus violating unique ownership. Code like the following is invalid as it requires the entire `Option` to be @@ -6,11 +8,13 @@ inner `String` to be moved into a variable called `s`. Erroneous code example: -```compile_fail,E0007 +```compile_fail,E0382 +#![feature(bindings_after_at)] + let x = Some("s".to_string()); match x { - op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings + op_string @ Some(s) => {}, // error: use of moved value None => {}, } ``` From c4280af8285c61b367a87c8f6eef9876011a8150 Mon Sep 17 00:00:00 2001 From: Nathan West Date: Wed, 16 Sep 2020 23:52:41 -0400 Subject: [PATCH 06/50] Retry fix error reporting suggestions --- .../mut-borrow-needed-by-trait.stderr | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr index 8ab1014485665..8a9a1e5793588 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -5,13 +5,18 @@ LL | let fp = BufWriter::new(fp); | ^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` | = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` - = note: required by `std::io::BufWriter::::new` + = note: required by `BufWriter::::new` error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied --> $DIR/mut-borrow-needed-by-trait.rs:17:14 | LL | let fp = BufWriter::new(fp); | ^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` + | + ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL + | +LL | pub struct BufWriter { + | ----- required by this bound in `BufWriter` | = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` @@ -20,18 +25,28 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satis | LL | let fp = BufWriter::new(fp); | ^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` + | + ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL + | +LL | pub struct BufWriter { + | ----- required by this bound in `BufWriter` | = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` -error[E0599]: no method named `write_fmt` found for struct `std::io::BufWriter<&dyn std::io::Write>` in the current scope +error[E0599]: no method named `write_fmt` found for struct `BufWriter<&dyn std::io::Write>` in the current scope --> $DIR/mut-borrow-needed-by-trait.rs:22:5 | -LL | writeln!(fp, "hello world").unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `std::io::BufWriter<&dyn std::io::Write>` +LL | writeln!(fp, "hello world").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `BufWriter<&dyn std::io::Write>` + | + ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL + | +LL | pub struct BufWriter { + | ------------------------------ doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write` | = note: the method `write_fmt` exists but the following trait bounds were not satisfied: `&dyn std::io::Write: std::io::Write` - which is required by `std::io::BufWriter<&dyn std::io::Write>: std::io::Write` + which is required by `BufWriter<&dyn std::io::Write>: std::io::Write` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors From 0b923d3ca0b7f5a1a611564ee48c1e92f896d79e Mon Sep 17 00:00:00 2001 From: Waffle Date: Thu, 1 Oct 2020 20:06:44 +0300 Subject: [PATCH 07/50] add `str::{Split,RSplit}::as_str` methods This commit introduses 2 methods under "str_split_as_str" gate with common signature of `&Split<'a, _> -> &'a str'`. Both of them work like `Chars::as_str` - return unyield part of the inner string. --- library/core/src/lib.rs | 1 + library/core/src/str/iter.rs | 55 ++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 22bf2b15d6695..c7588f618e133 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -125,6 +125,7 @@ #![feature(staged_api)] #![feature(std_internals)] #![feature(stmt_expr_attributes)] +#![feature(str_split_as_str)] #![feature(transparent_unions)] #![feature(unboxed_closures)] #![feature(unsized_locals)] diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 27a67e2b22f23..1b71f54bd843e 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -690,6 +690,19 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { }, } } + + #[inline] + fn as_str(&self) -> &'a str { + // `Self::get_end` doesn't change `self.start` + if self.finished { + return ""; + } + + // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. + unsafe { + self.matcher.haystack().get_unchecked(self.start..self.end) + } + } } generate_pattern_iterators! { @@ -710,6 +723,48 @@ generate_pattern_iterators! { delegate double ended; } +impl<'a, P: Pattern<'a>> Split<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "Mary had a little lamb".split(' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "had a little lamb"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_as_str", issue = "none")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + +impl<'a, P: Pattern<'a>> RSplit<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "Mary had a little lamb".rsplit(' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "Mary had a little"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_as_str", issue = "none")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + generate_pattern_iterators! { forward: /// Created with the method [`split_terminator`]. From 4747215d778abd9f280202d07f279fdeaea519f8 Mon Sep 17 00:00:00 2001 From: Waffle Date: Thu, 1 Oct 2020 23:08:15 +0300 Subject: [PATCH 08/50] add `str::{SplitN, RSplitN, SplitTerminator, RSplitTerminator}::as_str` methods This commit entroduce 4 methods smililar to `Split::as_str` all under the same gate "str_split_as_str". --- library/core/src/str/iter.rs | 89 ++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 1b71f54bd843e..dc2c2e0168f56 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -783,6 +783,48 @@ generate_pattern_iterators! { delegate double ended; } +impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "A..B..".split_terminator('.'); + /// assert_eq!(split.as_str(), "A..B.."); + /// split.next(); + /// assert_eq!(split.as_str(), ".B.."); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_as_str", issue = "none")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + +impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "A..B..".rsplit_terminator('.'); + /// assert_eq!(split.as_str(), "A..B.."); + /// split.next(); + /// assert_eq!(split.as_str(), "A..B"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_as_str", issue = "none")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + derive_pattern_clone! { clone SplitNInternal with |s| SplitNInternal { iter: s.iter.clone(), ..*s } @@ -839,6 +881,11 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { } } } + + #[inline] + fn as_str(&self) -> &'a str { + self.iter.as_str() + } } generate_pattern_iterators! { @@ -859,6 +906,48 @@ generate_pattern_iterators! { delegate single ended; } +impl<'a, P: Pattern<'a>> SplitN<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "Mary had a little lamb".splitn(3, ' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "had a little lamb"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_as_str", issue = "none")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + +impl<'a, P: Pattern<'a>> RSplitN<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "Mary had a little lamb".rsplitn(3, ' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "Mary had a little"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_as_str", issue = "none")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + derive_pattern_clone! { clone MatchIndicesInternal with |s| MatchIndicesInternal(s.0.clone()) From 076514c8a82591547116a7a2212c4de4bdc56f76 Mon Sep 17 00:00:00 2001 From: Waffle Date: Thu, 1 Oct 2020 23:39:20 +0300 Subject: [PATCH 09/50] add `str::SplitInclusive::as_str` method This commit entroduces `core::str::SplitInclusive::as_str` method similar to `core::str::Split::as_str`, but under different gate - "str_split_inclusive_as_str" (this is done so because `SplitInclusive` is itself unstable). --- library/core/src/lib.rs | 1 + library/core/src/str/iter.rs | 26 +++++++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index c7588f618e133..8f1826a47e1c5 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -126,6 +126,7 @@ #![feature(std_internals)] #![feature(stmt_expr_attributes)] #![feature(str_split_as_str)] +#![feature(str_split_inclusive_as_str)] #![feature(transparent_unions)] #![feature(unboxed_closures)] #![feature(unsized_locals)] diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index dc2c2e0168f56..2da390b2b2b24 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -699,9 +699,7 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { } // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. - unsafe { - self.matcher.haystack().get_unchecked(self.start..self.end) - } + unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) } } } @@ -1278,6 +1276,28 @@ impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator #[unstable(feature = "split_inclusive", issue = "72360")] impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {} +impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_inclusive_as_str)] + /// #![feature(split_inclusive)] + /// let mut split = "Mary had a little lamb".split_inclusive(' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "had a little lamb"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_inclusive_as_str", issue = "none")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + /// An iterator of [`u16`] over the string encoded as UTF-16. /// /// This struct is created by the [`encode_utf16`] method on [`str`]. From f84f01c0148cfb2451775fcbf299a2e7b10b1e81 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 6 Oct 2020 20:01:42 +0200 Subject: [PATCH 10/50] Use futex-based thread-parker for Wasm32. --- library/std/src/sys/wasm/futex_atomics.rs | 17 +++++++++++++++++ library/std/src/sys/wasm/mod.rs | 2 ++ library/std/src/sys_common/thread_parker/mod.rs | 6 +++++- 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 library/std/src/sys/wasm/futex_atomics.rs diff --git a/library/std/src/sys/wasm/futex_atomics.rs b/library/std/src/sys/wasm/futex_atomics.rs new file mode 100644 index 0000000000000..3d8bf42f7255e --- /dev/null +++ b/library/std/src/sys/wasm/futex_atomics.rs @@ -0,0 +1,17 @@ +use crate::arch::wasm32; +use crate::convert::TryInto; +use crate::sync::atomic::AtomicI32; +use crate::time::Duration; + +pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option) { + let timeout = timeout.and_then(|t| t.as_nanos().try_into().ok()).unwrap_or(-1); + unsafe { + wasm32::memory_atomic_wait32(futex as *const AtomicI32 as *mut i32, expected, timeout); + } +} + +pub fn futex_wake(futex: &AtomicI32) { + unsafe { + wasm32::memory_atomic_notify(futex as *const AtomicI32 as *mut i32, 1); + } +} diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs index 2934ea59ab5ff..ca50c393c0bfc 100644 --- a/library/std/src/sys/wasm/mod.rs +++ b/library/std/src/sys/wasm/mod.rs @@ -55,6 +55,8 @@ cfg_if::cfg_if! { pub mod mutex; #[path = "rwlock_atomics.rs"] pub mod rwlock; + #[path = "futex_atomics.rs"] + pub mod futex; } else { #[path = "../unsupported/condvar.rs"] pub mod condvar; diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs index 23c17c8e2cf26..5e75ac65de419 100644 --- a/library/std/src/sys_common/thread_parker/mod.rs +++ b/library/std/src/sys_common/thread_parker/mod.rs @@ -1,5 +1,9 @@ cfg_if::cfg_if! { - if #[cfg(any(target_os = "linux", target_os = "android"))] { + if #[cfg(any( + target_os = "linux", + target_os = "android", + all(target_arch = "wasm32", target_feature = "atomics"), + ))] { mod futex; pub use futex::Parker; } else { From 54a71e89546886951e32035960aa82a15a343668 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 13:54:16 +0200 Subject: [PATCH 11/50] For backtrace, use StaticMutex instead of a raw sys Mutex. --- library/std/src/backtrace.rs | 6 ++++-- library/std/src/sys_common/backtrace.rs | 22 +++++----------------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index cc29e1c0b0522..a9d8a4e2a81c1 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -303,7 +303,8 @@ impl Backtrace { // Capture a backtrace which start just before the function addressed by // `ip` fn create(ip: usize) -> Backtrace { - let _lock = lock(); + // SAFETY: We don't attempt to lock this reentrantly. + let _lock = unsafe { lock() }; let mut frames = Vec::new(); let mut actual_start = None; unsafe { @@ -408,7 +409,8 @@ impl Capture { // Use the global backtrace lock to synchronize this as it's a // requirement of the `backtrace` crate, and then actually resolve // everything. - let _lock = lock(); + // SAFETY: We don't attempt to lock this reentrantly. + let _lock = unsafe { lock() }; for frame in self.frames.iter_mut() { let symbols = &mut frame.symbols; let frame = match &frame.frame { diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs index 1c5fbf7d70102..a549770d8b378 100644 --- a/library/std/src/sys_common/backtrace.rs +++ b/library/std/src/sys_common/backtrace.rs @@ -8,27 +8,15 @@ use crate::io; use crate::io::prelude::*; use crate::path::{self, Path, PathBuf}; use crate::sync::atomic::{self, Ordering}; -use crate::sys::mutex::Mutex; +use crate::sys_common::mutex::StaticMutex; /// Max number of frames to print. const MAX_NB_FRAMES: usize = 100; -pub fn lock() -> impl Drop { - struct Guard; - static LOCK: Mutex = Mutex::new(); - - impl Drop for Guard { - fn drop(&mut self) { - unsafe { - LOCK.unlock(); - } - } - } - - unsafe { - LOCK.lock(); - Guard - } +// SAFETY: Don't attempt to lock this reentrantly. +pub unsafe fn lock() -> impl Drop { + static LOCK: StaticMutex = StaticMutex::new(); + LOCK.lock() } /// Prints the current backtrace. From e6d61ade9c1523dc2dd7cbd97206d6ebc5b5d481 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 18:14:47 +0200 Subject: [PATCH 12/50] Use slice_as_mut_ptr instead of first_ptr_mut. This function was renamed. --- library/std/src/sys/cloudabi/condvar.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/cloudabi/condvar.rs b/library/std/src/sys/cloudabi/condvar.rs index 82d89b260fafd..c549208b2d793 100644 --- a/library/std/src/sys/cloudabi/condvar.rs +++ b/library/std/src/sys/cloudabi/condvar.rs @@ -124,7 +124,7 @@ impl Condvar { let mut nevents: mem::MaybeUninit = mem::MaybeUninit::uninit(); let ret = abi::poll( subscriptions.as_ptr(), - mem::MaybeUninit::first_ptr_mut(&mut events), + mem::MaybeUninit::slice_as_mut_ptr(&mut events), 2, nevents.as_mut_ptr(), ); From 0f26578f2e2e41c51279f3b2bd967785241d316d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 18:16:02 +0200 Subject: [PATCH 13/50] Get rid of UnsafeCells in cloudabi mutex. --- library/std/src/sys/cloudabi/mutex.rs | 52 +++++++++++++-------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/library/std/src/sys/cloudabi/mutex.rs b/library/std/src/sys/cloudabi/mutex.rs index 66839e05bf076..8f57bdd390cda 100644 --- a/library/std/src/sys/cloudabi/mutex.rs +++ b/library/std/src/sys/cloudabi/mutex.rs @@ -1,4 +1,4 @@ -use crate::cell::UnsafeCell; +use crate::cell::Cell; use crate::mem; use crate::mem::MaybeUninit; use crate::sync::atomic::{AtomicU32, Ordering}; @@ -50,28 +50,23 @@ impl Mutex { } pub struct ReentrantMutex { - lock: UnsafeCell>, - recursion: UnsafeCell>, + lock: AtomicU32, + recursion: Cell, } +unsafe impl Send for ReentrantMutex {} +unsafe impl Sync for ReentrantMutex {} + impl ReentrantMutex { pub const unsafe fn uninitialized() -> ReentrantMutex { - ReentrantMutex { - lock: UnsafeCell::new(MaybeUninit::uninit()), - recursion: UnsafeCell::new(MaybeUninit::uninit()), - } + ReentrantMutex { lock: AtomicU32::new(abi::LOCK_UNLOCKED.0), recursion: Cell::new(0) } } - pub unsafe fn init(&self) { - *self.lock.get() = MaybeUninit::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)); - *self.recursion.get() = MaybeUninit::new(0); - } + pub unsafe fn init(&self) {} pub unsafe fn try_lock(&self) -> bool { // Attempt to acquire the lock. - let lock = (*self.lock.get()).as_mut_ptr(); - let recursion = (*self.recursion.get()).as_mut_ptr(); - if let Err(old) = (*lock).compare_exchange( + if let Err(old) = self.lock.compare_exchange( abi::LOCK_UNLOCKED.0, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, Ordering::Acquire, @@ -80,14 +75,14 @@ impl ReentrantMutex { // If we fail to acquire the lock, it may be the case // that we've already acquired it and may need to recurse. if old & !abi::LOCK_KERNEL_MANAGED.0 == __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 { - *recursion += 1; + self.recursion.set(self.recursion.get() + 1); true } else { false } } else { // Success. - assert_eq!(*recursion, 0, "Mutex has invalid recursion count"); + assert_eq!(self.recursion.get(), 0, "Mutex has invalid recursion count"); true } } @@ -95,7 +90,7 @@ impl ReentrantMutex { pub unsafe fn lock(&self) { if !self.try_lock() { // Call into the kernel to acquire a write lock. - let lock = self.lock.get(); + let lock = &self.lock as *const AtomicU32; let subscription = abi::subscription { type_: abi::eventtype::LOCK_WRLOCK, union: abi::subscription_union { @@ -116,17 +111,17 @@ impl ReentrantMutex { } pub unsafe fn unlock(&self) { - let lock = (*self.lock.get()).as_mut_ptr(); - let recursion = (*self.recursion.get()).as_mut_ptr(); assert_eq!( - (*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, + self.lock.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, "This mutex is locked by a different thread" ); - if *recursion > 0 { - *recursion -= 1; - } else if !(*lock) + let r = self.recursion.get(); + if r > 0 { + self.recursion.set(r - 1); + } else if !self + .lock .compare_exchange( __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, abi::LOCK_UNLOCKED.0, @@ -137,19 +132,20 @@ impl ReentrantMutex { { // Lock is managed by kernelspace. Call into the kernel // to unblock waiting threads. - let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE); + let ret = abi::lock_unlock( + &self.lock as *const AtomicU32 as *mut abi::lock, + abi::scope::PRIVATE, + ); assert_eq!(ret, abi::errno::SUCCESS, "Failed to unlock a mutex"); } } pub unsafe fn destroy(&self) { - let lock = (*self.lock.get()).as_mut_ptr(); - let recursion = (*self.recursion.get()).as_mut_ptr(); assert_eq!( - (*lock).load(Ordering::Relaxed), + self.lock.load(Ordering::Relaxed), abi::LOCK_UNLOCKED.0, "Attempted to destroy locked mutex" ); - assert_eq!(*recursion, 0, "Recursion counter invalid"); + assert_eq!(self.recursion.get(), 0, "Recursion counter invalid"); } } From 41066beb4dd3a7618e1f7617d60704f5c4425bf7 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 18:17:16 +0200 Subject: [PATCH 14/50] Get rid of UnsafeCell in cloudabi rwlock. --- library/std/src/sys/cloudabi/rwlock.rs | 45 ++++++++++++-------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/library/std/src/sys/cloudabi/rwlock.rs b/library/std/src/sys/cloudabi/rwlock.rs index b8af5af1d701c..8306819423db6 100644 --- a/library/std/src/sys/cloudabi/rwlock.rs +++ b/library/std/src/sys/cloudabi/rwlock.rs @@ -1,4 +1,3 @@ -use crate::cell::UnsafeCell; use crate::mem; use crate::mem::MaybeUninit; use crate::sync::atomic::{AtomicU32, Ordering}; @@ -13,28 +12,25 @@ extern "C" { static mut RDLOCKS_ACQUIRED: u32 = 0; pub struct RWLock { - lock: UnsafeCell, + lock: AtomicU32, } pub unsafe fn raw(r: &RWLock) -> *mut AtomicU32 { - r.lock.get() + &r.lock as *const AtomicU32 as *mut AtomicU32 } unsafe impl Send for RWLock {} unsafe impl Sync for RWLock {} -const NEW: RWLock = RWLock { lock: UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)) }; - impl RWLock { pub const fn new() -> RWLock { - NEW + RWLock { lock: AtomicU32::new(abi::LOCK_UNLOCKED.0) } } pub unsafe fn try_read(&self) -> bool { - let lock = self.lock.get(); let mut old = abi::LOCK_UNLOCKED.0; while let Err(cur) = - (*lock).compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed) + self.lock.compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed) { if (cur & abi::LOCK_WRLOCKED.0) != 0 { // Another thread already has a write lock. @@ -61,12 +57,11 @@ impl RWLock { pub unsafe fn read(&self) { if !self.try_read() { // Call into the kernel to acquire a read lock. - let lock = self.lock.get(); let subscription = abi::subscription { type_: abi::eventtype::LOCK_RDLOCK, union: abi::subscription_union { lock: abi::subscription_lock { - lock: lock as *mut abi::lock, + lock: &self.lock as *const AtomicU32 as *mut abi::lock, lock_scope: abi::scope::PRIVATE, }, }, @@ -96,11 +91,10 @@ impl RWLock { assert!(RDLOCKS_ACQUIRED > 0, "Bad lock count"); let mut old = 1; loop { - let lock = self.lock.get(); if old == 1 | abi::LOCK_KERNEL_MANAGED.0 { // Last read lock while threads are waiting. Attempt to upgrade // to a write lock before calling into the kernel to unlock. - if let Err(cur) = (*lock).compare_exchange_weak( + if let Err(cur) = self.lock.compare_exchange_weak( old, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 | abi::LOCK_KERNEL_MANAGED.0, Ordering::Acquire, @@ -109,7 +103,10 @@ impl RWLock { old = cur; } else { // Call into the kernel to unlock. - let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE); + let ret = abi::lock_unlock( + &self.lock as *const AtomicU32 as *mut abi::lock, + abi::scope::PRIVATE, + ); assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock"); break; } @@ -122,7 +119,7 @@ impl RWLock { 0, "Attempted to read-unlock a write-locked rwlock" ); - if let Err(cur) = (*lock).compare_exchange_weak( + if let Err(cur) = self.lock.compare_exchange_weak( old, old - 1, Ordering::Acquire, @@ -140,8 +137,7 @@ impl RWLock { pub unsafe fn try_write(&self) -> bool { // Attempt to acquire the lock. - let lock = self.lock.get(); - if let Err(old) = (*lock).compare_exchange( + if let Err(old) = self.lock.compare_exchange( abi::LOCK_UNLOCKED.0, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, Ordering::Acquire, @@ -163,12 +159,11 @@ impl RWLock { pub unsafe fn write(&self) { if !self.try_write() { // Call into the kernel to acquire a write lock. - let lock = self.lock.get(); let subscription = abi::subscription { type_: abi::eventtype::LOCK_WRLOCK, union: abi::subscription_union { lock: abi::subscription_lock { - lock: lock as *mut abi::lock, + lock: &self.lock as *const AtomicU32 as *mut abi::lock, lock_scope: abi::scope::PRIVATE, }, }, @@ -184,14 +179,14 @@ impl RWLock { } pub unsafe fn write_unlock(&self) { - let lock = self.lock.get(); assert_eq!( - (*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, + self.lock.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, "This rwlock is not write-locked by this thread" ); - if !(*lock) + if !self + .lock .compare_exchange( __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, abi::LOCK_UNLOCKED.0, @@ -202,15 +197,17 @@ impl RWLock { { // Lock is managed by kernelspace. Call into the kernel // to unblock waiting threads. - let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE); + let ret = abi::lock_unlock( + &self.lock as *const AtomicU32 as *mut abi::lock, + abi::scope::PRIVATE, + ); assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock"); } } pub unsafe fn destroy(&self) { - let lock = self.lock.get(); assert_eq!( - (*lock).load(Ordering::Relaxed), + self.lock.load(Ordering::Relaxed), abi::LOCK_UNLOCKED.0, "Attempted to destroy locked rwlock" ); From 060e8cbaf1e3a57b97f96b13f702e04de4a5f1d3 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 18:17:46 +0200 Subject: [PATCH 15/50] Get rid of raw pointers and UnsafeCell in cloudabi condvar. --- library/std/src/sys/cloudabi/condvar.rs | 35 +++++++++---------------- library/std/src/sys/cloudabi/mutex.rs | 2 +- library/std/src/sys/cloudabi/rwlock.rs | 4 +-- 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/library/std/src/sys/cloudabi/condvar.rs b/library/std/src/sys/cloudabi/condvar.rs index c549208b2d793..4584b43809c46 100644 --- a/library/std/src/sys/cloudabi/condvar.rs +++ b/library/std/src/sys/cloudabi/condvar.rs @@ -1,4 +1,3 @@ -use crate::cell::UnsafeCell; use crate::mem; use crate::sync::atomic::{AtomicU32, Ordering}; use crate::sys::cloudabi::abi; @@ -12,7 +11,7 @@ extern "C" { } pub struct Condvar { - condvar: UnsafeCell, + condvar: AtomicU32, } pub type MovableCondvar = Condvar; @@ -20,29 +19,24 @@ pub type MovableCondvar = Condvar; unsafe impl Send for Condvar {} unsafe impl Sync for Condvar {} -const NEW: Condvar = - Condvar { condvar: UnsafeCell::new(AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0)) }; - impl Condvar { pub const fn new() -> Condvar { - NEW + Condvar { condvar: AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0) } } pub unsafe fn init(&mut self) {} pub unsafe fn notify_one(&self) { - let condvar = self.condvar.get(); - if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { - let ret = abi::condvar_signal(condvar as *mut abi::condvar, abi::scope::PRIVATE, 1); + if self.condvar.load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { + let ret = abi::condvar_signal(&self.condvar as *const AtomicU32 as *mut abi::condvar, abi::scope::PRIVATE, 1); assert_eq!(ret, abi::errno::SUCCESS, "Failed to signal on condition variable"); } } pub unsafe fn notify_all(&self) { - let condvar = self.condvar.get(); - if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { + if self.condvar.load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { let ret = abi::condvar_signal( - condvar as *mut abi::condvar, + &self.condvar as *const AtomicU32 as *mut abi::condvar, abi::scope::PRIVATE, abi::nthreads::MAX, ); @@ -53,20 +47,19 @@ impl Condvar { pub unsafe fn wait(&self, mutex: &Mutex) { let mutex = mutex::raw(mutex); assert_eq!( - (*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, + mutex.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, "This lock is not write-locked by this thread" ); // Call into the kernel to wait on the condition variable. - let condvar = self.condvar.get(); let subscription = abi::subscription { type_: abi::eventtype::CONDVAR, union: abi::subscription_union { condvar: abi::subscription_condvar { - condvar: condvar as *mut abi::condvar, + condvar: &self.condvar as *const AtomicU32 as *mut abi::condvar, condvar_scope: abi::scope::PRIVATE, - lock: mutex as *mut abi::lock, + lock: mutex as *const AtomicU32 as *mut abi::lock, lock_scope: abi::scope::PRIVATE, }, }, @@ -86,13 +79,12 @@ impl Condvar { pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { let mutex = mutex::raw(mutex); assert_eq!( - (*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, + mutex.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, "This lock is not write-locked by this thread" ); // Call into the kernel to wait on the condition variable. - let condvar = self.condvar.get(); let timeout = checked_dur2intervals(&dur).expect("overflow converting duration to nanoseconds"); let subscriptions = [ @@ -100,9 +92,9 @@ impl Condvar { type_: abi::eventtype::CONDVAR, union: abi::subscription_union { condvar: abi::subscription_condvar { - condvar: condvar as *mut abi::condvar, + condvar: &self.condvar as *const AtomicU32 as *mut abi::condvar, condvar_scope: abi::scope::PRIVATE, - lock: mutex as *mut abi::lock, + lock: mutex as *const AtomicU32 as *mut abi::lock, lock_scope: abi::scope::PRIVATE, }, }, @@ -144,9 +136,8 @@ impl Condvar { } pub unsafe fn destroy(&self) { - let condvar = self.condvar.get(); assert_eq!( - (*condvar).load(Ordering::Relaxed), + self.condvar.load(Ordering::Relaxed), abi::CONDVAR_HAS_NO_WAITERS.0, "Attempted to destroy a condition variable with blocked threads" ); diff --git a/library/std/src/sys/cloudabi/mutex.rs b/library/std/src/sys/cloudabi/mutex.rs index 8f57bdd390cda..1203d8de0c572 100644 --- a/library/std/src/sys/cloudabi/mutex.rs +++ b/library/std/src/sys/cloudabi/mutex.rs @@ -17,7 +17,7 @@ pub struct Mutex(RWLock); pub type MovableMutex = Mutex; -pub unsafe fn raw(m: &Mutex) -> *mut AtomicU32 { +pub unsafe fn raw(m: &Mutex) -> &AtomicU32 { rwlock::raw(&m.0) } diff --git a/library/std/src/sys/cloudabi/rwlock.rs b/library/std/src/sys/cloudabi/rwlock.rs index 8306819423db6..508de8ba47c6e 100644 --- a/library/std/src/sys/cloudabi/rwlock.rs +++ b/library/std/src/sys/cloudabi/rwlock.rs @@ -15,8 +15,8 @@ pub struct RWLock { lock: AtomicU32, } -pub unsafe fn raw(r: &RWLock) -> *mut AtomicU32 { - &r.lock as *const AtomicU32 as *mut AtomicU32 +pub unsafe fn raw(r: &RWLock) -> &AtomicU32 { + &r.lock } unsafe impl Send for RWLock {} From b3be11efbdd274b0dfd94c720cf6e396cab98c33 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 18:20:56 +0200 Subject: [PATCH 16/50] Formatting. --- library/std/src/sys/cloudabi/condvar.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/cloudabi/condvar.rs b/library/std/src/sys/cloudabi/condvar.rs index 4584b43809c46..f09bc01701b74 100644 --- a/library/std/src/sys/cloudabi/condvar.rs +++ b/library/std/src/sys/cloudabi/condvar.rs @@ -28,7 +28,11 @@ impl Condvar { pub unsafe fn notify_one(&self) { if self.condvar.load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { - let ret = abi::condvar_signal(&self.condvar as *const AtomicU32 as *mut abi::condvar, abi::scope::PRIVATE, 1); + let ret = abi::condvar_signal( + &self.condvar as *const AtomicU32 as *mut abi::condvar, + abi::scope::PRIVATE, + 1, + ); assert_eq!(ret, abi::errno::SUCCESS, "Failed to signal on condition variable"); } } From 6f0544abe4b62021ad2849a24db9f89ca3d38ddb Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Tue, 6 Oct 2020 20:48:01 +0200 Subject: [PATCH 17/50] Simplify doc-cfg rendering based on the current context For sub-items on a page don't show cfg that has already been rendered on a parent item. At its simplest this means not showing anything that is shown in the portability message at the top of the page, but also for things like fields of an enum variant if that variant itself is cfg-gated then don't repeat those cfg on each field of the variant. This does not touch trait implementation rendering, as that is more complex and there are existing issues around how it deals with doc-cfg that need to be fixed first. --- src/librustdoc/clean/cfg.rs | 29 ++++ src/librustdoc/html/render/mod.rs | 104 ++++++++---- src/test/rustdoc/doc-cfg-simplification.rs | 182 +++++++++++++++++++++ src/test/rustdoc/doc-cfg.rs | 7 +- src/test/rustdoc/duplicate-cfg.rs | 26 ++- 5 files changed, 296 insertions(+), 52 deletions(-) create mode 100644 src/test/rustdoc/doc-cfg-simplification.rs diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index c039b181178a4..4d8168dd8ef74 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -201,6 +201,35 @@ impl Cfg { _ => false, } } + + /// Attempt to simplify this cfg by assuming that `assume` is already known to be true, will + /// return `None` if simplification managed to completely eliminate any requirements from this + /// `Cfg`. + pub(crate) fn simplify_with(&self, assume: &Cfg) -> Option { + if self == assume { + return None; + } + + if let Cfg::All(a) = self { + let mut sub_cfgs: Vec = if let Cfg::All(b) = assume { + a.iter().filter(|a| !b.contains(a)).cloned().collect() + } else { + a.iter().filter(|&a| a != assume).cloned().collect() + }; + let len = sub_cfgs.len(); + return match len { + 0 => None, + 1 => sub_cfgs.pop(), + _ => Some(Cfg::All(sub_cfgs)), + }; + } else if let Cfg::All(b) = assume { + if b.contains(self) { + return None; + } + } + + Some(self.clone()) + } } impl ops::Not for Cfg { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 8b5ba7a239c5f..e71df4b45c339 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1762,11 +1762,11 @@ crate fn shorten(s: String) -> String { } } -fn document(w: &mut Buffer, cx: &Context, item: &clean::Item) { +fn document(w: &mut Buffer, cx: &Context, item: &clean::Item, parent: Option<&clean::Item>) { if let Some(ref name) = item.name { info!("Documenting {}", name); } - document_stability(w, cx, item, false); + document_stability(w, cx, item, false, parent); document_full(w, item, cx, "", false); } @@ -1850,8 +1850,14 @@ fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context, prefix: &str, } } -fn document_stability(w: &mut Buffer, cx: &Context, item: &clean::Item, is_hidden: bool) { - let stabilities = short_stability(item, cx); +fn document_stability( + w: &mut Buffer, + cx: &Context, + item: &clean::Item, + is_hidden: bool, + parent: Option<&clean::Item>, +) { + let stabilities = short_stability(item, cx, parent); if !stabilities.is_empty() { write!(w, "
", if is_hidden { " hidden" } else { "" }); for stability in stabilities { @@ -1951,7 +1957,7 @@ pub fn compare_names(mut lhs: &str, mut rhs: &str) -> Ordering { } fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean::Item]) { - document(w, cx, item); + document(w, cx, item, None); let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::>(); @@ -2108,7 +2114,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: {stab_tags}{docs}\ ", name = *myitem.name.as_ref().unwrap(), - stab_tags = stability_tags(myitem), + stab_tags = stability_tags(myitem, item), docs = MarkdownSummaryLine(doc_value, &myitem.links()).into_string(), class = myitem.type_(), add = add, @@ -2132,7 +2138,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: /// Render the stability and deprecation tags that are displayed in the item's summary at the /// module level. -fn stability_tags(item: &clean::Item) -> String { +fn stability_tags(item: &clean::Item, parent: &clean::Item) -> String { let mut tags = String::new(); fn tag_html(class: &str, title: &str, contents: &str) -> String { @@ -2159,7 +2165,13 @@ fn stability_tags(item: &clean::Item) -> String { tags += &tag_html("unstable", "", "Experimental"); } - if let Some(ref cfg) = item.attrs.cfg { + let cfg = match (&item.attrs.cfg, parent.attrs.cfg.as_ref()) { + (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg), + (cfg, _) => cfg.as_deref().cloned(), + }; + + info!("Portability {:?} - {:?} = {:?}", item.attrs.cfg, parent.attrs.cfg, cfg); + if let Some(ref cfg) = cfg { tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html()); } @@ -2168,7 +2180,7 @@ fn stability_tags(item: &clean::Item) -> String { /// Render the stability and/or deprecation warning that is displayed at the top of the item's /// documentation. -fn short_stability(item: &clean::Item, cx: &Context) -> Vec { +fn short_stability(item: &clean::Item, cx: &Context, parent: Option<&clean::Item>) -> Vec { let mut stability = vec![]; let error_codes = cx.shared.codes; @@ -2242,7 +2254,18 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { stability.push(format!("
{}
", message)); } - if let Some(ref cfg) = item.attrs.cfg { + let cfg = match (&item.attrs.cfg, parent.and_then(|p| p.attrs.cfg.as_ref())) { + (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg), + (cfg, _) => cfg.as_deref().cloned(), + }; + + info!( + "Portability {:?} - {:?} = {:?}", + item.attrs.cfg, + parent.and_then(|p| p.attrs.cfg.as_ref()), + cfg + ); + if let Some(cfg) = cfg { stability.push(format!("
{}
", cfg.render_long_html())); } @@ -2281,7 +2304,7 @@ fn item_constant(w: &mut Buffer, cx: &Context, it: &clean::Item, c: &clean::Cons } write!(w, ""); - document(w, cx, it) + document(w, cx, it, None) } fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static) { @@ -2295,7 +2318,7 @@ fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static name = it.name.as_ref().unwrap(), typ = s.type_.print() ); - document(w, cx, it) + document(w, cx, it, None) } fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Function) { @@ -2328,7 +2351,7 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func .print(), spotlight = spotlight_decl(&f.decl), ); - document(w, cx, it) + document(w, cx, it, None) } fn render_implementor( @@ -2353,6 +2376,7 @@ fn render_implementor( w, cx, implementor, + None, AssocItemLink::Anchor(None), RenderMode::Normal, implementor.impl_item.stable_since(), @@ -2382,6 +2406,7 @@ fn render_impls( &mut buffer, cx, i, + Some(containing_item), assoc_link, RenderMode::Normal, containing_item.stable_since(), @@ -2501,7 +2526,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, }); // Trait documentation - document(w, cx, it); + document(w, cx, it, None); fn write_small_section_header(w: &mut Buffer, id: &str, title: &str, extra_content: &str) { write!( @@ -2519,6 +2544,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, fn trait_item(w: &mut Buffer, cx: &Context, m: &clean::Item, t: &clean::Item) { let name = m.name.as_ref().unwrap(); + info!("Documenting {} on {}", name, t.name.as_deref().unwrap_or_default()); let item_type = m.type_(); let id = cx.derive_id(format!("{}.{}", item_type, name)); write!(w, "

", id = id,); @@ -2526,7 +2552,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, write!(w, ""); render_stability_since(w, m, t); write!(w, "

"); - document(w, cx, m); + document(w, cx, m, Some(t)); } if !types.is_empty() { @@ -2627,6 +2653,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, w, cx, &implementor, + None, assoc_link, RenderMode::Normal, implementor.impl_item.stable_since(), @@ -2885,7 +2912,7 @@ fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct write!(w, "") }); - document(w, cx, it); + document(w, cx, it, None); let mut fields = s .fields .iter() @@ -2920,7 +2947,7 @@ fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct name = field.name.as_ref().unwrap(), ty = ty.print() ); - document(w, cx, field); + document(w, cx, field, Some(it)); } } } @@ -2935,7 +2962,7 @@ fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union, write!(w, "") }); - document(w, cx, it); + document(w, cx, it, None); let mut fields = s .fields .iter() @@ -2967,7 +2994,7 @@ fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union, if let Some(stability_class) = field.stability_class() { write!(w, "", stab = stability_class); } - document(w, cx, field); + document(w, cx, field, Some(it)); } } render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache) @@ -3022,7 +3049,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca write!(w, "") }); - document(w, cx, it); + document(w, cx, it, None); if !e.variants.is_empty() { write!( w, @@ -3055,7 +3082,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca } } write!(w, "
"); - document(w, cx, variant); + document(w, cx, variant, Some(it)); document_non_exhaustive(w, variant); use crate::clean::{Variant, VariantKind}; @@ -3090,7 +3117,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca f = field.name.as_ref().unwrap(), t = ty.print() ); - document(w, cx, field); + document(w, cx, field, Some(variant)); } } write!(w, ""); @@ -3288,6 +3315,10 @@ fn render_assoc_items( what: AssocItemRender<'_>, cache: &Cache, ) { + info!( + "Documenting associated items of {}", + containing_item.name.as_deref().unwrap_or_default() + ); let v = match cache.impls.get(&it) { Some(v) => v, None => return, @@ -3322,6 +3353,7 @@ fn render_assoc_items( w, cx, i, + Some(containing_item), AssocItemLink::Anchor(None), render_mode, containing_item.stable_since(), @@ -3513,6 +3545,7 @@ fn render_impl( w: &mut Buffer, cx: &Context, i: &Impl, + parent: Option<&clean::Item>, link: AssocItemLink<'_>, render_mode: RenderMode, outer_version: Option<&str>, @@ -3592,6 +3625,7 @@ fn render_impl( w: &mut Buffer, cx: &Context, item: &clean::Item, + parent: Option<&clean::Item>, link: AssocItemLink<'_>, render_mode: RenderMode, is_default_item: bool, @@ -3676,7 +3710,7 @@ fn render_impl( if let Some(it) = t.items.iter().find(|i| i.name == item.name) { // We need the stability of the item from the trait // because impls can't have a stability. - document_stability(w, cx, it, is_hidden); + document_stability(w, cx, it, is_hidden, parent); if item.doc_value().is_some() { document_full(w, item, cx, "", is_hidden); } else if show_def_docs { @@ -3686,13 +3720,13 @@ fn render_impl( } } } else { - document_stability(w, cx, item, is_hidden); + document_stability(w, cx, item, is_hidden, parent); if show_def_docs { document_full(w, item, cx, "", is_hidden); } } } else { - document_stability(w, cx, item, is_hidden); + document_stability(w, cx, item, is_hidden, parent); if show_def_docs { document_short(w, item, link, "", is_hidden); } @@ -3709,6 +3743,7 @@ fn render_impl( w, cx, trait_item, + parent, link, render_mode, false, @@ -3724,6 +3759,7 @@ fn render_impl( cx: &Context, t: &clean::Trait, i: &clean::Impl, + parent: Option<&clean::Item>, render_mode: RenderMode, outer_version: Option<&str>, show_def_docs: bool, @@ -3741,6 +3777,7 @@ fn render_impl( w, cx, trait_item, + parent, assoc_link, render_mode, true, @@ -3763,6 +3800,7 @@ fn render_impl( cx, t, &i.inner_impl(), + parent, render_mode, outer_version, show_def_docs, @@ -3791,7 +3829,7 @@ fn item_opaque_ty( bounds = bounds(&t.bounds, false) ); - document(w, cx, it); + document(w, cx, it, None); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -3818,7 +3856,7 @@ fn item_trait_alias( bounds(&t.bounds, true) ); - document(w, cx, it); + document(w, cx, it, None); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -3839,7 +3877,7 @@ fn item_typedef(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Typed type_ = t.type_.print() ); - document(w, cx, it); + document(w, cx, it, None); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -3858,7 +3896,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context, it: &clean::Item, cache: &Cac it.name.as_ref().unwrap(), ); - document(w, cx, it); + document(w, cx, it, None); render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache) } @@ -4502,7 +4540,7 @@ fn item_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Macro) None, )) }); - document(w, cx, it) + document(w, cx, it, None) } fn item_proc_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, m: &clean::ProcMacro) { @@ -4532,16 +4570,16 @@ fn item_proc_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, m: &clean::Pr write!(w, ""); } } - document(w, cx, it) + document(w, cx, it, None) } fn item_primitive(w: &mut Buffer, cx: &Context, it: &clean::Item, cache: &Cache) { - document(w, cx, it); + document(w, cx, it, None); render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache) } fn item_keyword(w: &mut Buffer, cx: &Context, it: &clean::Item) { - document(w, cx, it) + document(w, cx, it, None) } crate const BASIC_KEYWORDS: &str = "rust, rustlang, rust-lang"; diff --git a/src/test/rustdoc/doc-cfg-simplification.rs b/src/test/rustdoc/doc-cfg-simplification.rs new file mode 100644 index 0000000000000..633df661be026 --- /dev/null +++ b/src/test/rustdoc/doc-cfg-simplification.rs @@ -0,0 +1,182 @@ +#![crate_name = "globuliferous"] +#![feature(doc_cfg)] + +// @has 'globuliferous/index.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' '^ratel$' + +// @has 'globuliferous/ratel/index.html' +// @count - '//*[@class="stab portability"]' 8 +// @matches - '//*[@class="stab portability"]' 'crate feature ratel' +// @matches - '//*[@class="stab portability"]' '^zoonosology$' +// @matches - '//*[@class="stab portability"]' '^yusho$' +// @matches - '//*[@class="stab portability"]' '^nunciative$' +// @matches - '//*[@class="stab portability"]' '^thionic$' +// @matches - '//*[@class="stab portability"]' '^zincic$' +// @matches - '//*[@class="stab portability"]' '^cosmotellurian$' +// @matches - '//*[@class="stab portability"]' '^aposiopesis$' +#[doc(cfg(feature = "ratel"))] +pub mod ratel { + // @has 'globuliferous/ratel/fn.ovicide.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub fn ovicide() {} + + // @has 'globuliferous/ratel/fn.zoonosology.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and zoonosology' + #[doc(cfg(feature = "zoonosology"))] + pub fn zoonosology() {} + + // @has 'globuliferous/ratel/constant.DIAGRAPHICS.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub const DIAGRAPHICS: () = (); + + // @has 'globuliferous/ratel/constant.YUSHO.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and yusho' + #[doc(cfg(feature = "yusho"))] + pub const YUSHO: () = (); + + // @has 'globuliferous/ratel/static.KEYBUGLE.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub static KEYBUGLE: () = (); + + // @has 'globuliferous/ratel/static.NUNCIATIVE.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and nunciative' + #[doc(cfg(feature = "nunciative"))] + pub static NUNCIATIVE: () = (); + + // @has 'globuliferous/ratel/type.Wrick.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub type Wrick = (); + + // @has 'globuliferous/ratel/type.Thionic.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and thionic' + #[doc(cfg(feature = "thionic"))] + pub type Thionic = (); + + // @has 'globuliferous/ratel/struct.Eventration.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub struct Eventration; + + // @has 'globuliferous/ratel/struct.Zincic.html' + // @count - '//*[@class="stab portability"]' 2 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and zincic' + // @matches - '//*[@class="stab portability"]' 'crate feature rutherford' + #[doc(cfg(feature = "zincic"))] + pub struct Zincic { + pub rectigrade: (), + + #[doc(cfg(feature = "rutherford"))] + pub rutherford: (), + } + + // @has 'globuliferous/ratel/enum.Cosmotellurian.html' + // @count - '//*[@class="stab portability"]' 10 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and cosmotellurian' + // @matches - '//*[@class="stab portability"]' 'crate feature biotaxy' + // @matches - '//*[@class="stab portability"]' 'crate feature xiphopagus' + // @matches - '//*[@class="stab portability"]' 'crate feature juxtapositive' + // @matches - '//*[@class="stab portability"]' 'crate feature fuero' + // @matches - '//*[@class="stab portability"]' 'crate feature palaeophile' + // @matches - '//*[@class="stab portability"]' 'crate feature broadcloth' + // @matches - '//*[@class="stab portability"]' 'crate features broadcloth and xanthocomic' + // @matches - '//*[@class="stab portability"]' 'crate feature broadcloth' + // @matches - '//*[@class="stab portability"]' 'crate features broadcloth and whosoever' + #[doc(cfg(feature = "cosmotellurian"))] + pub enum Cosmotellurian { + Groundsel { + jagger: (), + + #[doc(cfg(feature = "xiphopagus"))] + xiphopagus: (), + }, + + #[doc(cfg(feature = "biotaxy"))] + Biotaxy { + glossography: (), + + #[doc(cfg(feature = "juxtapositive"))] + juxtapositive: (), + }, + } + + impl Cosmotellurian { + pub fn uxoricide() {} + + #[doc(cfg(feature = "fuero"))] + pub fn fuero() {} + + pub const MAMELLE: () = (); + + #[doc(cfg(feature = "palaeophile"))] + pub const PALAEOPHILE: () = (); + } + + #[doc(cfg(feature = "broadcloth"))] + impl Cosmotellurian { + pub fn trabeculated() {} + + #[doc(cfg(feature = "xanthocomic"))] + pub fn xanthocomic() {} + + pub const BRACHIFEROUS: () = (); + + #[doc(cfg(feature = "whosoever"))] + pub const WHOSOEVER: () = (); + } + + // @has 'globuliferous/ratel/trait.Gnotobiology.html' + // @count - '//*[@class="stab portability"]' 4 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + // @matches - '//*[@class="stab portability"]' 'crate feature unzymotic' + // @matches - '//*[@class="stab portability"]' 'crate feature summate' + // @matches - '//*[@class="stab portability"]' 'crate feature unctuous' + pub trait Gnotobiology { + const XYLOTHERAPY: (); + + #[doc(cfg(feature = "unzymotic"))] + const UNZYMOTIC: (); + + type Lepadoid; + + #[doc(cfg(feature = "summate"))] + type Summate; + + fn decalcomania(); + + #[doc(cfg(feature = "unctuous"))] + fn unctuous(); + } + + // @has 'globuliferous/ratel/trait.Aposiopesis.html' + // @count - '//*[@class="stab portability"]' 4 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and aposiopesis' + // @matches - '//*[@class="stab portability"]' 'crate feature umbracious' + // @matches - '//*[@class="stab portability"]' 'crate feature uakari' + // @matches - '//*[@class="stab portability"]' 'crate feature rotograph' + #[doc(cfg(feature = "aposiopesis"))] + pub trait Aposiopesis { + const REDHIBITION: (); + + #[doc(cfg(feature = "umbracious"))] + const UMBRACIOUS: (); + + type Ophthalmoscope; + + #[doc(cfg(feature = "uakari"))] + type Uakari; + + fn meseems(); + + #[doc(cfg(feature = "rotograph"))] + fn rotograph(); + } +} diff --git a/src/test/rustdoc/doc-cfg.rs b/src/test/rustdoc/doc-cfg.rs index aa407b7e92618..d7041ee2f1af8 100644 --- a/src/test/rustdoc/doc-cfg.rs +++ b/src/test/rustdoc/doc-cfg.rs @@ -10,9 +10,8 @@ pub struct Portable; // @has doc_cfg/unix_only/index.html \ // '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' \ // 'This is supported on Unix only.' -// @matches - '//*[@class="module-item"]//*[@class="stab portability"]' '\AUnix\Z' -// @matches - '//*[@class="module-item"]//*[@class="stab portability"]' '\AUnix and ARM\Z' -// @count - '//*[@class="stab portability"]' 3 +// @matches - '//*[@class="module-item"]//*[@class="stab portability"]' '\AARM\Z' +// @count - '//*[@class="stab portability"]' 2 #[doc(cfg(unix))] pub mod unix_only { // @has doc_cfg/unix_only/fn.unix_only_function.html \ @@ -26,7 +25,7 @@ pub mod unix_only { // @has doc_cfg/unix_only/trait.ArmOnly.html \ // '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' \ // 'This is supported on Unix and ARM only.' - // @count - '//*[@class="stab portability"]' 3 + // @count - '//*[@class="stab portability"]' 2 #[doc(cfg(target_arch = "arm"))] pub trait ArmOnly { fn unix_and_arm_only_function(); diff --git a/src/test/rustdoc/duplicate-cfg.rs b/src/test/rustdoc/duplicate-cfg.rs index 47ba362c97789..7b938af3c7d50 100644 --- a/src/test/rustdoc/duplicate-cfg.rs +++ b/src/test/rustdoc/duplicate-cfg.rs @@ -14,45 +14,41 @@ pub struct Foo; // @has 'foo/bar/index.html' -// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync$' -// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` only' - -// @has 'foo/bar/struct.Bar.html' // @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.' #[doc(cfg(feature = "sync"))] pub mod bar { + // @has 'foo/bar/struct.Bar.html' + // @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.' #[doc(cfg(feature = "sync"))] pub struct Bar; } // @has 'foo/baz/index.html' -// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync and send$' -// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate features `sync` and `send` only' - -// @has 'foo/baz/struct.Baz.html' // @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.' #[doc(cfg(all(feature = "sync", feature = "send")))] pub mod baz { + // @has 'foo/baz/struct.Baz.html' + // @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.' #[doc(cfg(feature = "sync"))] pub struct Baz; } -// @has 'foo/qux/struct.Qux.html' -// @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.' +// @has 'foo/qux/index.html' +// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.' #[doc(cfg(feature = "sync"))] pub mod qux { + // @has 'foo/qux/struct.Qux.html' + // @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.' #[doc(cfg(all(feature = "sync", feature = "send")))] pub struct Qux; } // @has 'foo/quux/index.html' -// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync and send and foo and bar$' -// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` and crate feature `send` and `foo` and `bar` only' - -// @has 'foo/quux/struct.Quux.html' -// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync and crate feature send and foo and bar only.' +// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync and crate feature send and foo only.' #[doc(cfg(all(feature = "sync", feature = "send", foo)))] pub mod quux { + // @has 'foo/quux/struct.Quux.html' + // @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync and crate feature send and foo and bar only.' #[doc(cfg(all(feature = "send", feature = "sync", bar)))] pub struct Quux; } From 17eb8d8b34a733640a0565e5ae589711f28c6e7a Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Sat, 19 Sep 2020 17:51:24 +0430 Subject: [PATCH 18/50] ICEs should print the top of the query stack --- compiler/rustc_driver/src/lib.rs | 7 +------ compiler/rustc_middle/src/ty/query/plumbing.rs | 5 ++++- src/tools/clippy/src/driver.rs | 7 +------ 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 066a61a7a7b53..a664863950958 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -1211,12 +1211,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { handler.note_without_error(¬e); } - // If backtraces are enabled, also print the query stack - let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false); - - if backtrace { - TyCtxt::try_print_query_stack(&handler); - } + TyCtxt::try_print_query_stack(&handler, Some(2)); #[cfg(windows)] unsafe { diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs index f3fa3634026fd..6debd0cc7f3b8 100644 --- a/compiler/rustc_middle/src/ty/query/plumbing.rs +++ b/compiler/rustc_middle/src/ty/query/plumbing.rs @@ -124,7 +124,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn try_print_query_stack(handler: &Handler) { + pub fn try_print_query_stack(handler: &Handler, num_frames: Option) { eprintln!("query stack during panic:"); // Be careful reyling on global state here: this code is called from @@ -138,6 +138,9 @@ impl<'tcx> TyCtxt<'tcx> { let mut i = 0; while let Some(query) = current_query { + if i == num_frames.unwrap() { + break; + } let query_info = if let Some(info) = query_map.as_ref().and_then(|map| map.get(&query)) { info diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index f4f2259cefd51..c88dffc88f422 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -274,12 +274,7 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { handler.note_without_error(¬e); } - // If backtraces are enabled, also print the query stack - let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0"); - - if backtrace { - TyCtxt::try_print_query_stack(&handler); - } + TyCtxt::try_print_query_stack(&handler, Some(2)); } fn toolchain_path(home: Option, toolchain: Option) -> Option { From 20ea9290ed152b0c25cf4f54dbe2c4a269ecace7 Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Sat, 19 Sep 2020 18:37:58 +0430 Subject: [PATCH 19/50] run full query stack print just when RUST_BACKTRACE is set --- compiler/rustc_driver/src/lib.rs | 5 ++++- compiler/rustc_middle/src/ty/query/plumbing.rs | 10 +++++++--- src/tools/clippy/src/driver.rs | 5 ++++- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index a664863950958..177256008f8ef 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -1211,7 +1211,10 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { handler.note_without_error(¬e); } - TyCtxt::try_print_query_stack(&handler, Some(2)); + // If backtraces are enabled, also print the query stack + let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false); + + TyCtxt::try_print_query_stack(&handler, Some(2), Some(backtrace)); #[cfg(windows)] unsafe { diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs index 6debd0cc7f3b8..239d5bce607c4 100644 --- a/compiler/rustc_middle/src/ty/query/plumbing.rs +++ b/compiler/rustc_middle/src/ty/query/plumbing.rs @@ -124,7 +124,11 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn try_print_query_stack(handler: &Handler, num_frames: Option) { + pub fn try_print_query_stack( + handler: &Handler, + num_frames: Option, + backtrace: Option, + ) { eprintln!("query stack during panic:"); // Be careful reyling on global state here: this code is called from @@ -138,9 +142,9 @@ impl<'tcx> TyCtxt<'tcx> { let mut i = 0; while let Some(query) = current_query { - if i == num_frames.unwrap() { + if backtrace.unwrap() == false && i == num_frames.unwrap() { break; - } + } let query_info = if let Some(info) = query_map.as_ref().and_then(|map| map.get(&query)) { info diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index c88dffc88f422..0b324775b0d1a 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -274,7 +274,10 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { handler.note_without_error(¬e); } - TyCtxt::try_print_query_stack(&handler, Some(2)); + // If backtraces are enabled, also print the query stack + let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0"); + + TyCtxt::try_print_query_stack(&handler, Some(2), Some(backtrace)); } fn toolchain_path(home: Option, toolchain: Option) -> Option { From 7ccca35c66591607dff49fd1e6c93b380b072e42 Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Sat, 19 Sep 2020 22:05:04 +0430 Subject: [PATCH 20/50] fix invalid-punct-ident-1 test --- src/test/ui/proc-macro/invalid-punct-ident-1.rs | 3 +++ src/test/ui/proc-macro/invalid-punct-ident-1.stderr | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.rs b/src/test/ui/proc-macro/invalid-punct-ident-1.rs index 3f78dea917b19..a3133a1a79070 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-1.rs +++ b/src/test/ui/proc-macro/invalid-punct-ident-1.rs @@ -9,6 +9,9 @@ // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" // normalize-stderr-test "note: compiler flags.*\n\n" -> "" // normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" +// normalize-stderr-test "query stack during panic:\n" -> "" +// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> "" +// normalize-stderr-test "end of query stack\n" -> "" #[macro_use] extern crate invalid_punct_ident; diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr index fc821d29d5a0c..5ef22709cb371 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr @@ -1,5 +1,5 @@ error: proc macro panicked - --> $DIR/invalid-punct-ident-1.rs:16:1 + --> $DIR/invalid-punct-ident-1.rs:19:1 | LL | invalid_punct!(); | ^^^^^^^^^^^^^^^^^ From d6d4388ae78737891d10e15244dce2df7627fb46 Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Sun, 20 Sep 2020 17:07:55 +0430 Subject: [PATCH 21/50] add filter regexes to load-panic-backtraces test --- src/test/ui/proc-macro/invalid-punct-ident-2.rs | 3 +++ src/test/ui/proc-macro/invalid-punct-ident-2.stderr | 2 +- src/test/ui/proc-macro/invalid-punct-ident-3.rs | 3 +++ src/test/ui/proc-macro/invalid-punct-ident-3.stderr | 2 +- src/test/ui/proc-macro/load-panic-backtrace.rs | 3 +++ src/test/ui/proc-macro/load-panic-backtrace.stderr | 2 +- 6 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.rs b/src/test/ui/proc-macro/invalid-punct-ident-2.rs index 4e89e80ae7c41..04a0a8733115a 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-2.rs +++ b/src/test/ui/proc-macro/invalid-punct-ident-2.rs @@ -9,6 +9,9 @@ // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" // normalize-stderr-test "note: compiler flags.*\n\n" -> "" // normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" +// normalize-stderr-test "query stack during panic:\n" -> "" +// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> "" +// normalize-stderr-test "end of query stack\n" -> "" #[macro_use] extern crate invalid_punct_ident; diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr index 8b30edaf85c09..4bd7a5351d3a0 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr @@ -1,5 +1,5 @@ error: proc macro panicked - --> $DIR/invalid-punct-ident-2.rs:16:1 + --> $DIR/invalid-punct-ident-2.rs:19:1 | LL | invalid_ident!(); | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.rs b/src/test/ui/proc-macro/invalid-punct-ident-3.rs index 8d8ce8f932e71..aebba341625ae 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-3.rs +++ b/src/test/ui/proc-macro/invalid-punct-ident-3.rs @@ -9,6 +9,9 @@ // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" // normalize-stderr-test "note: compiler flags.*\n\n" -> "" // normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" +// normalize-stderr-test "query stack during panic:\n" -> "" +// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> "" +// normalize-stderr-test "end of query stack\n" -> "" #[macro_use] extern crate invalid_punct_ident; diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr index d46fab08e14f0..072d13956ac6c 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr @@ -1,5 +1,5 @@ error: proc macro panicked - --> $DIR/invalid-punct-ident-3.rs:16:1 + --> $DIR/invalid-punct-ident-3.rs:19:1 | LL | invalid_raw_ident!(); | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/proc-macro/load-panic-backtrace.rs b/src/test/ui/proc-macro/load-panic-backtrace.rs index 90fe109abb8f0..4a3ba9aee7453 100644 --- a/src/test/ui/proc-macro/load-panic-backtrace.rs +++ b/src/test/ui/proc-macro/load-panic-backtrace.rs @@ -10,6 +10,9 @@ // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" // normalize-stderr-test "note: compiler flags.*\n\n" -> "" // normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" +// normalize-stderr-test "query stack during panic:\n" -> "" +// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> "" +// normalize-stderr-test "end of query stack\n" -> "" #[macro_use] extern crate test_macros; diff --git a/src/test/ui/proc-macro/load-panic-backtrace.stderr b/src/test/ui/proc-macro/load-panic-backtrace.stderr index 63378b5735a3c..f825047e33168 100644 --- a/src/test/ui/proc-macro/load-panic-backtrace.stderr +++ b/src/test/ui/proc-macro/load-panic-backtrace.stderr @@ -1,6 +1,6 @@ at 'panic-derive', $DIR/auxiliary/test-macros.rs:43:5 error: proc-macro derive panicked - --> $DIR/load-panic-backtrace.rs:17:10 + --> $DIR/load-panic-backtrace.rs:20:10 | LL | #[derive(Panic)] | ^^^^^ From d60b7e29f7f80674984c8d2f3567b15253b14f2f Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Wed, 23 Sep 2020 19:08:21 +0330 Subject: [PATCH 22/50] fix show we're just showing... message instead of the end of query stack message when RUST_BACKTRACE=0 --- compiler/rustc_middle/src/ty/query/plumbing.rs | 6 +++++- src/test/ui/pattern/const-pat-ice.stderr | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/pattern/const-pat-ice.stderr diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs index 239d5bce607c4..d5fbcf6c9b14b 100644 --- a/compiler/rustc_middle/src/ty/query/plumbing.rs +++ b/compiler/rustc_middle/src/ty/query/plumbing.rs @@ -170,7 +170,11 @@ impl<'tcx> TyCtxt<'tcx> { } }); - eprintln!("end of query stack"); + if num_frames != None { + eprintln!("we're just showing a limited slice of the query stack"); + } else { + eprintln!("end of query stack"); + } } } diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr new file mode 100644 index 0000000000000..90497db519c34 --- /dev/null +++ b/src/test/ui/pattern/const-pat-ice.stderr @@ -0,0 +1,17 @@ +thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', compiler/rustc_mir_build/src/thir/pattern/_match.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + +error: internal compiler error: unexpected panic + +note: the compiler unexpectedly panicked. this is a bug. + +note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md + +note: rustc VERSION running on TARGET + +note: compiler flags: FLAGS + +query stack during panic: +#0 [check_match] match-checking `main` +#1 [analysis] running analysis passes on this crate +we're just showing a limited slice of the query stack From 6e7e4ac419554883c430be7f4b234b0b4d88648c Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Fri, 25 Sep 2020 19:55:32 +0330 Subject: [PATCH 23/50] fix clippy custom_ice_message test --- src/tools/clippy/tests/ui/custom_ice_message.stderr | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/clippy/tests/ui/custom_ice_message.stderr b/src/tools/clippy/tests/ui/custom_ice_message.stderr index a9a65a38c109d..784ab9e5c7078 100644 --- a/src/tools/clippy/tests/ui/custom_ice_message.stderr +++ b/src/tools/clippy/tests/ui/custom_ice_message.stderr @@ -9,3 +9,5 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy note: Clippy version: foo +query stack during panic: +we're just showing a limited slice of the query stack \ No newline at end of file From 15663a432d281749655916ac22eaca8248260551 Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Mon, 28 Sep 2020 22:07:31 +0330 Subject: [PATCH 24/50] add new line --- src/tools/clippy/tests/ui/custom_ice_message.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clippy/tests/ui/custom_ice_message.stderr b/src/tools/clippy/tests/ui/custom_ice_message.stderr index 784ab9e5c7078..87cdb7a8b99dd 100644 --- a/src/tools/clippy/tests/ui/custom_ice_message.stderr +++ b/src/tools/clippy/tests/ui/custom_ice_message.stderr @@ -10,4 +10,4 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy note: Clippy version: foo query stack during panic: -we're just showing a limited slice of the query stack \ No newline at end of file +we're just showing a limited slice of the query stack From 2124e9b50e2ba208700f1ab928e0863e407eb158 Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Tue, 29 Sep 2020 18:14:07 +0330 Subject: [PATCH 25/50] rebase with master --- compiler/rustc_driver/src/lib.rs | 4 +++- compiler/rustc_middle/src/ty/query/plumbing.rs | 8 ++++++++ src/tools/clippy/src/driver.rs | 4 +++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 177256008f8ef..a2c244d6f1744 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -1214,7 +1214,9 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { // If backtraces are enabled, also print the query stack let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false); - TyCtxt::try_print_query_stack(&handler, Some(2), Some(backtrace)); + let num_frames = if backtrace { None } else { Some(2) }; + + TyCtxt::try_print_query_stack(&handler, num_frames); #[cfg(windows)] unsafe { diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs index d5fbcf6c9b14b..d64e32c4d36b7 100644 --- a/compiler/rustc_middle/src/ty/query/plumbing.rs +++ b/compiler/rustc_middle/src/ty/query/plumbing.rs @@ -124,11 +124,15 @@ impl<'tcx> TyCtxt<'tcx> { }) } +<<<<<<< HEAD pub fn try_print_query_stack( handler: &Handler, num_frames: Option, backtrace: Option, ) { +======= + pub fn try_print_query_stack(handler: &Handler, num_frames: Option) { +>>>>>>> 15827338aa231fd408561bf5db8d8eea85d1a51a eprintln!("query stack during panic:"); // Be careful reyling on global state here: this code is called from @@ -142,7 +146,11 @@ impl<'tcx> TyCtxt<'tcx> { let mut i = 0; while let Some(query) = current_query { +<<<<<<< HEAD if backtrace.unwrap() == false && i == num_frames.unwrap() { +======= + if num_frames == Some(i) { +>>>>>>> 15827338aa231fd408561bf5db8d8eea85d1a51a break; } let query_info = diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 0b324775b0d1a..bf9110b43492f 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -277,7 +277,9 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { // If backtraces are enabled, also print the query stack let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0"); - TyCtxt::try_print_query_stack(&handler, Some(2), Some(backtrace)); + let num_frames = if backtrace { None } else { Some(2) }; + + TyCtxt::try_print_query_stack(&handler, num_frames); } fn toolchain_path(home: Option, toolchain: Option) -> Option { From 2b91b7fba99c47ffc214b2fd36b586b844a509bd Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Sat, 19 Sep 2020 17:51:24 +0430 Subject: [PATCH 26/50] ICEs should print the top of the query stack --- compiler/rustc_middle/src/ty/query/plumbing.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs index d64e32c4d36b7..451ed6506f483 100644 --- a/compiler/rustc_middle/src/ty/query/plumbing.rs +++ b/compiler/rustc_middle/src/ty/query/plumbing.rs @@ -124,15 +124,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } -<<<<<<< HEAD - pub fn try_print_query_stack( - handler: &Handler, - num_frames: Option, - backtrace: Option, - ) { -======= pub fn try_print_query_stack(handler: &Handler, num_frames: Option) { ->>>>>>> 15827338aa231fd408561bf5db8d8eea85d1a51a eprintln!("query stack during panic:"); // Be careful reyling on global state here: this code is called from @@ -146,11 +138,7 @@ impl<'tcx> TyCtxt<'tcx> { let mut i = 0; while let Some(query) = current_query { -<<<<<<< HEAD - if backtrace.unwrap() == false && i == num_frames.unwrap() { -======= - if num_frames == Some(i) { ->>>>>>> 15827338aa231fd408561bf5db8d8eea85d1a51a + if Some(i) == num_frames { break; } let query_info = From 01f838a6269460ea97fdf305b1afb236f6528b74 Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Sat, 19 Sep 2020 18:37:58 +0430 Subject: [PATCH 27/50] run full query stack print just when RUST_BACKTRACE is set --- compiler/rustc_middle/src/ty/query/plumbing.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs index 451ed6506f483..61f8cd8caad13 100644 --- a/compiler/rustc_middle/src/ty/query/plumbing.rs +++ b/compiler/rustc_middle/src/ty/query/plumbing.rs @@ -124,7 +124,11 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn try_print_query_stack(handler: &Handler, num_frames: Option) { + pub fn try_print_query_stack( + handler: &Handler, + num_frames: Option, + backtrace: Option, + ) { eprintln!("query stack during panic:"); // Be careful reyling on global state here: this code is called from From 2bfdd644dc65b7ef746b7128dbaef2333e5cec7f Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Sat, 19 Sep 2020 19:54:04 +0430 Subject: [PATCH 28/50] change approach and run ui tests --- compiler/rustc_middle/src/ty/query/plumbing.rs | 6 +----- src/test/ui/proc-macro/invalid-punct-ident-1.stderr | 2 ++ src/test/ui/proc-macro/invalid-punct-ident-2.stderr | 2 ++ src/test/ui/proc-macro/invalid-punct-ident-3.stderr | 2 ++ 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs index 61f8cd8caad13..451ed6506f483 100644 --- a/compiler/rustc_middle/src/ty/query/plumbing.rs +++ b/compiler/rustc_middle/src/ty/query/plumbing.rs @@ -124,11 +124,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn try_print_query_stack( - handler: &Handler, - num_frames: Option, - backtrace: Option, - ) { + pub fn try_print_query_stack(handler: &Handler, num_frames: Option) { eprintln!("query stack during panic:"); // Be careful reyling on global state here: this code is called from diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr index 5ef22709cb371..9948670b691fe 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr @@ -1,3 +1,5 @@ +query stack during panic: +end of query stack error: proc macro panicked --> $DIR/invalid-punct-ident-1.rs:19:1 | diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr index 4bd7a5351d3a0..55f7344e2e6f0 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr @@ -1,3 +1,5 @@ +query stack during panic: +end of query stack error: proc macro panicked --> $DIR/invalid-punct-ident-2.rs:19:1 | diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr index 072d13956ac6c..915720482de66 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr @@ -1,3 +1,5 @@ +query stack during panic: +end of query stack error: proc macro panicked --> $DIR/invalid-punct-ident-3.rs:19:1 | From b6e9f08fbfce298082817bf7f2eaf00dd9097d14 Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Sat, 19 Sep 2020 21:29:57 +0430 Subject: [PATCH 29/50] show a message when we are showing limited slice of query stack --- compiler/rustc_middle/src/ty/query/plumbing.rs | 3 +++ src/test/ui/pattern/const-pat-ice.stderr | 1 + src/test/ui/proc-macro/invalid-punct-ident-1.stderr | 1 + src/test/ui/proc-macro/invalid-punct-ident-2.stderr | 1 + src/test/ui/proc-macro/invalid-punct-ident-3.stderr | 1 + 5 files changed, 7 insertions(+) diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs index 451ed6506f483..17eb8dbdca9c6 100644 --- a/compiler/rustc_middle/src/ty/query/plumbing.rs +++ b/compiler/rustc_middle/src/ty/query/plumbing.rs @@ -127,6 +127,9 @@ impl<'tcx> TyCtxt<'tcx> { pub fn try_print_query_stack(handler: &Handler, num_frames: Option) { eprintln!("query stack during panic:"); + if num_frames != None { + eprintln!("we're just showing a limited slice of the query stack"); + } // Be careful reyling on global state here: this code is called from // a panic hook, which means that the global `Handler` may be in a weird // state if it was responsible for triggering the panic. diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr index 90497db519c34..436958d210a90 100644 --- a/src/test/ui/pattern/const-pat-ice.stderr +++ b/src/test/ui/pattern/const-pat-ice.stderr @@ -12,6 +12,7 @@ note: rustc VERSION running on TARGET note: compiler flags: FLAGS query stack during panic: +we're just showing a limited slice of the query stack #0 [check_match] match-checking `main` #1 [analysis] running analysis passes on this crate we're just showing a limited slice of the query stack diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr index 9948670b691fe..edfb977f7ae64 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr @@ -1,4 +1,5 @@ query stack during panic: +we're just showing a limited slice of the query stack end of query stack error: proc macro panicked --> $DIR/invalid-punct-ident-1.rs:19:1 diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr index 55f7344e2e6f0..ea17175253f56 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr @@ -1,4 +1,5 @@ query stack during panic: +we're just showing a limited slice of the query stack end of query stack error: proc macro panicked --> $DIR/invalid-punct-ident-2.rs:19:1 diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr index 915720482de66..d60afd12095ea 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr @@ -1,4 +1,5 @@ query stack during panic: +we're just showing a limited slice of the query stack end of query stack error: proc macro panicked --> $DIR/invalid-punct-ident-3.rs:19:1 From 3c56ba5a6d69d9376a4998dc559796b8b47ace0b Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Sat, 19 Sep 2020 22:05:04 +0430 Subject: [PATCH 30/50] fix invalid-punct-ident-1 test --- src/test/ui/proc-macro/invalid-punct-ident-1.stderr | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr index edfb977f7ae64..5ef22709cb371 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr @@ -1,6 +1,3 @@ -query stack during panic: -we're just showing a limited slice of the query stack -end of query stack error: proc macro panicked --> $DIR/invalid-punct-ident-1.rs:19:1 | From d1e30592b330bda437cc8584d30f751dc97c08fc Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Sun, 20 Sep 2020 17:07:55 +0430 Subject: [PATCH 31/50] add filter regexes to load-panic-backtraces test --- src/test/ui/proc-macro/invalid-punct-ident-2.stderr | 3 --- src/test/ui/proc-macro/invalid-punct-ident-3.stderr | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr index ea17175253f56..4bd7a5351d3a0 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr @@ -1,6 +1,3 @@ -query stack during panic: -we're just showing a limited slice of the query stack -end of query stack error: proc macro panicked --> $DIR/invalid-punct-ident-2.rs:19:1 | diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr index d60afd12095ea..072d13956ac6c 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr @@ -1,6 +1,3 @@ -query stack during panic: -we're just showing a limited slice of the query stack -end of query stack error: proc macro panicked --> $DIR/invalid-punct-ident-3.rs:19:1 | From 6c0f06a107992eefa93a57f6f29f2a008e5051a1 Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Wed, 23 Sep 2020 19:08:21 +0330 Subject: [PATCH 32/50] fix show we're just showing... message instead of the end of query stack message when RUST_BACKTRACE=0 --- compiler/rustc_middle/src/ty/query/plumbing.rs | 3 --- src/test/ui/pattern/const-pat-ice.stderr | 1 - 2 files changed, 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs index 17eb8dbdca9c6..451ed6506f483 100644 --- a/compiler/rustc_middle/src/ty/query/plumbing.rs +++ b/compiler/rustc_middle/src/ty/query/plumbing.rs @@ -127,9 +127,6 @@ impl<'tcx> TyCtxt<'tcx> { pub fn try_print_query_stack(handler: &Handler, num_frames: Option) { eprintln!("query stack during panic:"); - if num_frames != None { - eprintln!("we're just showing a limited slice of the query stack"); - } // Be careful reyling on global state here: this code is called from // a panic hook, which means that the global `Handler` may be in a weird // state if it was responsible for triggering the panic. diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr index 436958d210a90..90497db519c34 100644 --- a/src/test/ui/pattern/const-pat-ice.stderr +++ b/src/test/ui/pattern/const-pat-ice.stderr @@ -12,7 +12,6 @@ note: rustc VERSION running on TARGET note: compiler flags: FLAGS query stack during panic: -we're just showing a limited slice of the query stack #0 [check_match] match-checking `main` #1 [analysis] running analysis passes on this crate we're just showing a limited slice of the query stack From c61d95b2cd62020e916d316014dd95b5601cd71d Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Tue, 29 Sep 2020 21:17:44 +0330 Subject: [PATCH 33/50] remove new line --- src/test/ui/pattern/const-pat-ice.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr index 90497db519c34..5116531d9cfca 100644 --- a/src/test/ui/pattern/const-pat-ice.stderr +++ b/src/test/ui/pattern/const-pat-ice.stderr @@ -14,4 +14,4 @@ note: compiler flags: FLAGS query stack during panic: #0 [check_match] match-checking `main` #1 [analysis] running analysis passes on this crate -we're just showing a limited slice of the query stack +we're just showing a limited slice of the query stack \ No newline at end of file From 998186eb156345767007cca323e2f756ba1abfff Mon Sep 17 00:00:00 2001 From: hosseind75 Date: Sat, 3 Oct 2020 17:04:27 +0330 Subject: [PATCH 34/50] revert deleted new line --- src/test/ui/pattern/const-pat-ice.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr index 5116531d9cfca..90497db519c34 100644 --- a/src/test/ui/pattern/const-pat-ice.stderr +++ b/src/test/ui/pattern/const-pat-ice.stderr @@ -14,4 +14,4 @@ note: compiler flags: FLAGS query stack during panic: #0 [check_match] match-checking `main` #1 [analysis] running analysis passes on this crate -we're just showing a limited slice of the query stack \ No newline at end of file +we're just showing a limited slice of the query stack From 42ebae3175a542c07b75c174bdddb22c6b18b10d Mon Sep 17 00:00:00 2001 From: hosseind88 Date: Tue, 6 Oct 2020 22:15:31 +0330 Subject: [PATCH 35/50] delete const-pat-ice test stderr --- src/test/ui/pattern/const-pat-ice.stderr | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 src/test/ui/pattern/const-pat-ice.stderr diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr deleted file mode 100644 index 90497db519c34..0000000000000 --- a/src/test/ui/pattern/const-pat-ice.stderr +++ /dev/null @@ -1,17 +0,0 @@ -thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', compiler/rustc_mir_build/src/thir/pattern/_match.rs:LL:CC -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace - -error: internal compiler error: unexpected panic - -note: the compiler unexpectedly panicked. this is a bug. - -note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md - -note: rustc VERSION running on TARGET - -note: compiler flags: FLAGS - -query stack during panic: -#0 [check_match] match-checking `main` -#1 [analysis] running analysis passes on this crate -we're just showing a limited slice of the query stack From 73d8f0045fff127c3bdbf907da7a8c3e07b7145a Mon Sep 17 00:00:00 2001 From: hosseind88 Date: Thu, 8 Oct 2020 21:07:12 +0330 Subject: [PATCH 36/50] change condition for end of query stack message --- compiler/rustc_middle/src/ty/query/plumbing.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs index 451ed6506f483..27bf22dac75cb 100644 --- a/compiler/rustc_middle/src/ty/query/plumbing.rs +++ b/compiler/rustc_middle/src/ty/query/plumbing.rs @@ -130,12 +130,12 @@ impl<'tcx> TyCtxt<'tcx> { // Be careful reyling on global state here: this code is called from // a panic hook, which means that the global `Handler` may be in a weird // state if it was responsible for triggering the panic. + let mut i = 0; ty::tls::with_context_opt(|icx| { if let Some(icx) = icx { let query_map = icx.tcx.queries.try_collect_active_jobs(); let mut current_query = icx.query; - let mut i = 0; while let Some(query) = current_query { if Some(i) == num_frames { @@ -166,10 +166,10 @@ impl<'tcx> TyCtxt<'tcx> { } }); - if num_frames != None { - eprintln!("we're just showing a limited slice of the query stack"); - } else { + if num_frames == None || num_frames >= Some(i) { eprintln!("end of query stack"); + } else { + eprintln!("we're just showing a limited slice of the query stack"); } } } From 7280f6aa41edf77d2488511bd880ad1c509ec865 Mon Sep 17 00:00:00 2001 From: Caleb Cartwright Date: Fri, 9 Oct 2020 23:40:27 -0500 Subject: [PATCH 37/50] rustc_parse: correct span on cast expr with attrs --- compiler/rustc_parse/src/parser/expr.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 0eac04df3c9f5..649a86f219db4 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -245,11 +245,7 @@ impl<'a> Parser<'a> { this.parse_assoc_expr_with(prec + prec_adjustment, LhsExpr::NotYetParsed) })?; - // Make sure that the span of the parent node is larger than the span of lhs and rhs, - // including the attributes. - let lhs_span = - lhs.attrs.iter().find(|a| a.style == AttrStyle::Outer).map_or(lhs_span, |a| a.span); - let span = lhs_span.to(rhs.span); + let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span); lhs = match op { AssocOp::Add | AssocOp::Subtract @@ -570,7 +566,11 @@ impl<'a> Parser<'a> { expr_kind: fn(P, P) -> ExprKind, ) -> PResult<'a, P> { let mk_expr = |this: &mut Self, rhs: P| { - this.mk_expr(lhs_span.to(rhs.span), expr_kind(lhs, rhs), AttrVec::new()) + this.mk_expr( + this.mk_expr_sp(&lhs, lhs_span, rhs.span), + expr_kind(lhs, rhs), + AttrVec::new(), + ) }; // Save the state of the parser before parsing type normally, in case there is a @@ -2298,4 +2298,14 @@ impl<'a> Parser<'a> { pub(super) fn mk_expr_err(&self, span: Span) -> P { self.mk_expr(span, ExprKind::Err, AttrVec::new()) } + + /// Create expression span ensuring the span of the parent node + /// is larger than the span of lhs and rhs, including the attributes. + fn mk_expr_sp(&self, lhs: &P, lhs_span: Span, rhs_span: Span) -> Span { + lhs.attrs + .iter() + .find(|a| a.style == AttrStyle::Outer) + .map_or(lhs_span, |a| a.span) + .to(rhs_span) + } } From 4e82da4a48d4cf86521608c6f1cf137a5765910b Mon Sep 17 00:00:00 2001 From: Caleb Cartwright Date: Mon, 12 Oct 2020 12:24:24 -0500 Subject: [PATCH 38/50] rustc_parse: correct span on range expr with attrs --- compiler/rustc_parse/src/parser/expr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 649a86f219db4..d0dfca7348541 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -406,7 +406,7 @@ impl<'a> Parser<'a> { None }; let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span); - let span = lhs.span.to(rhs_span); + let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span); let limits = if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed }; Ok(self.mk_expr(span, self.mk_range(Some(lhs), rhs, limits)?, AttrVec::new())) From 4e263fe999a94f958023b93e8b6f44685a7b15c6 Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Tue, 13 Oct 2020 20:18:46 +0200 Subject: [PATCH 39/50] Add test-examples for Cfg::simplify_with --- src/librustdoc/clean/cfg.rs | 2 ++ src/librustdoc/clean/cfg/tests.rs | 36 +++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 4d8168dd8ef74..b659f3eab4318 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -205,6 +205,8 @@ impl Cfg { /// Attempt to simplify this cfg by assuming that `assume` is already known to be true, will /// return `None` if simplification managed to completely eliminate any requirements from this /// `Cfg`. + /// + /// See `tests::test_simplify_with` for examples. pub(crate) fn simplify_with(&self, assume: &Cfg) -> Option { if self == assume { return None; diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index 794a7bcaf1cb7..3a78269f19af0 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -433,3 +433,39 @@ fn test_render_long_html() { ); }) } + +#[test] +fn test_simplify_with() { + // This is a tiny subset of things that could be simplified, but it likely covers 90% of + // real world usecases well. + with_default_session_globals(|| { + let foo = word_cfg("foo"); + let bar = word_cfg("bar"); + let baz = word_cfg("baz"); + let quux = word_cfg("quux"); + + let foobar = Cfg::All(vec![foo.clone(), bar.clone()]); + let barbaz = Cfg::All(vec![bar.clone(), baz.clone()]); + let foobarbaz = Cfg::All(vec![foo.clone(), bar.clone(), baz.clone()]); + let bazquux = Cfg::All(vec![baz.clone(), quux.clone()]); + + // Unrelated cfgs don't affect each other + assert_eq!(foo.simplify_with(&bar).as_ref(), Some(&foo)); + assert_eq!(foobar.simplify_with(&bazquux).as_ref(), Some(&foobar)); + + // Identical cfgs are eliminated + assert_eq!(foo.simplify_with(&foo), None); + assert_eq!(foobar.simplify_with(&foobar), None); + + // Multiple cfgs eliminate a single assumed cfg + assert_eq!(foobar.simplify_with(&foo).as_ref(), Some(&bar)); + assert_eq!(foobar.simplify_with(&bar).as_ref(), Some(&foo)); + + // A single cfg is eliminated by multiple assumed cfg containing it + assert_eq!(foo.simplify_with(&foobar), None); + + // Multiple cfgs eliminate the matching subset of multiple assumed cfg + assert_eq!(foobar.simplify_with(&barbaz).as_ref(), Some(&foo)); + assert_eq!(foobar.simplify_with(&foobarbaz), None); + }); +} From 4409cb2e3807c50d2e636ab293f10e6b8a87a7d4 Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Tue, 13 Oct 2020 20:21:49 +0200 Subject: [PATCH 40/50] Make portability log at debug level --- src/librustdoc/html/render/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index e71df4b45c339..bd50902102207 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2170,7 +2170,7 @@ fn stability_tags(item: &clean::Item, parent: &clean::Item) -> String { (cfg, _) => cfg.as_deref().cloned(), }; - info!("Portability {:?} - {:?} = {:?}", item.attrs.cfg, parent.attrs.cfg, cfg); + debug!("Portability {:?} - {:?} = {:?}", item.attrs.cfg, parent.attrs.cfg, cfg); if let Some(ref cfg) = cfg { tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html()); } @@ -2259,7 +2259,7 @@ fn short_stability(item: &clean::Item, cx: &Context, parent: Option<&clean::Item (cfg, _) => cfg.as_deref().cloned(), }; - info!( + debug!( "Portability {:?} - {:?} = {:?}", item.attrs.cfg, parent.and_then(|p| p.attrs.cfg.as_ref()), From 58756573fc5a2198f98e9b4889c494bb60f38e3d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 14:06:17 +0200 Subject: [PATCH 41/50] Fix comment about non-reentrant StaticMutex::lock(). The comment said it's UB to call lock() while it is locked. That'd be quite a useless Mutex. :) It was supposed to say 'locked by the same thread', not just 'locked'. --- library/std/src/sys_common/mutex.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs index 91d919a3f9b75..47fa75393308d 100644 --- a/library/std/src/sys_common/mutex.rs +++ b/library/std/src/sys_common/mutex.rs @@ -28,8 +28,9 @@ impl StaticMutex { /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex /// will be unlocked. /// - /// It is undefined behaviour to call this function while locked, or if the - /// mutex has been moved since the last time this was called. + /// It is undefined behaviour to call this function while locked by the + /// same thread, or if the mutex has been moved since the last time this + /// was called. #[inline] pub unsafe fn lock(&self) -> StaticMutexGuard<'_> { self.0.lock(); From 44a2af32ccc4c71c5e8bc9cb79c9042c6e608ce8 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 Oct 2020 14:08:33 +0200 Subject: [PATCH 42/50] Remove lifetime from StaticMutex and assume 'static. StaticMutex is only ever used with as a static (as the name already suggests). So it doesn't have to be generic over a lifetime, but can simply assume 'static. This 'static lifetime guarantees the object is never moved, so this is no longer a manually checked requirement for unsafe calls to lock(). --- library/std/src/sys/unix/os.rs | 2 +- library/std/src/sys/vxworks/os.rs | 2 +- library/std/src/sys_common/mutex.rs | 17 +++++------------ 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index c9f9ed01e120e..2392238d0a194 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -470,7 +470,7 @@ pub unsafe fn environ() -> *mut *const *const c_char { &mut environ } -pub unsafe fn env_lock() -> StaticMutexGuard<'static> { +pub unsafe fn env_lock() -> StaticMutexGuard { // It is UB to attempt to acquire this mutex reentrantly! static ENV_LOCK: StaticMutex = StaticMutex::new(); ENV_LOCK.lock() diff --git a/library/std/src/sys/vxworks/os.rs b/library/std/src/sys/vxworks/os.rs index 08394a8d29de1..6eaec6f1e50df 100644 --- a/library/std/src/sys/vxworks/os.rs +++ b/library/std/src/sys/vxworks/os.rs @@ -212,7 +212,7 @@ pub unsafe fn environ() -> *mut *const *const c_char { &mut environ } -pub unsafe fn env_lock() -> StaticMutexGuard<'static> { +pub unsafe fn env_lock() -> StaticMutexGuard { // It is UB to attempt to acquire this mutex reentrantly! static ENV_LOCK: StaticMutex = StaticMutex::new(); ENV_LOCK.lock() diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs index 47fa75393308d..f3e7efb955a2f 100644 --- a/library/std/src/sys_common/mutex.rs +++ b/library/std/src/sys_common/mutex.rs @@ -3,8 +3,7 @@ use crate::sys::mutex as imp; /// An OS-based mutual exclusion lock, meant for use in static variables. /// /// This mutex has a const constructor ([`StaticMutex::new`]), does not -/// implement `Drop` to cleanup resources, and causes UB when moved or used -/// reentrantly. +/// implement `Drop` to cleanup resources, and causes UB when used reentrantly. /// /// This mutex does not implement poisoning. /// @@ -16,11 +15,6 @@ unsafe impl Sync for StaticMutex {} impl StaticMutex { /// Creates a new mutex for use. - /// - /// Behavior is undefined if the mutex is moved after it is - /// first used with any of the functions below. - /// Also, the behavior is undefined if this mutex is ever used reentrantly, - /// i.e., `lock` is called by the thread currently holding the lock. pub const fn new() -> Self { Self(imp::Mutex::new()) } @@ -29,19 +23,18 @@ impl StaticMutex { /// will be unlocked. /// /// It is undefined behaviour to call this function while locked by the - /// same thread, or if the mutex has been moved since the last time this - /// was called. + /// same thread. #[inline] - pub unsafe fn lock(&self) -> StaticMutexGuard<'_> { + pub unsafe fn lock(&'static self) -> StaticMutexGuard { self.0.lock(); StaticMutexGuard(&self.0) } } #[must_use] -pub struct StaticMutexGuard<'a>(&'a imp::Mutex); +pub struct StaticMutexGuard(&'static imp::Mutex); -impl Drop for StaticMutexGuard<'_> { +impl Drop for StaticMutexGuard { #[inline] fn drop(&mut self) { unsafe { From a22cd05965fd79c756ba6890ba720dd280d314ae Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Wed, 14 Oct 2020 13:55:09 +0200 Subject: [PATCH 43/50] BTreeMap: making PartialCmp/PartialEq explicit and tested --- library/alloc/src/collections/btree/node.rs | 36 +++++++++++++++---- .../alloc/src/collections/btree/node/tests.rs | 33 +++++++++++++++++ 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 4fa97ff053e60..903faf3fa969a 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -257,8 +257,13 @@ impl Root { /// `NodeRef` points to an internal node, and when this is `LeafOrInternal` the /// `NodeRef` could be pointing to either type of node. pub struct NodeRef { - /// The number of levels below the node. + /// The number of levels below the node, a property of the node that cannot be + /// entirely described by `Type` and that the node does not store itself either. + /// Unconstrained if `Type` is `LeafOrInternal`, must be zero if `Type` is `Leaf`, + /// and must be non-zero if `Type` is `Internal`. height: usize, + /// The pointer to the leaf or internal node. The definition of `InternalNode` + /// ensures that the pointer is valid either way. node: NonNull>, _marker: PhantomData<(BorrowType, Type)>, } @@ -315,8 +320,8 @@ impl NodeRef { unsafe { usize::from((*self.as_leaf_ptr()).len) } } - /// Returns the height of this node in the whole tree. Zero height denotes the - /// leaf level. + /// Returns the height of this node with respect to the leaf level. Zero height means the + /// node is a leaf itself. pub fn height(&self) -> usize { self.height } @@ -584,9 +589,11 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { // to avoid aliasing with outstanding references to other elements, // in particular, those returned to the caller in earlier iterations. let leaf = self.node.as_ptr(); + let keys = unsafe { &raw const (*leaf).keys }; + let vals = unsafe { &raw mut (*leaf).vals }; // We must coerce to unsized array pointers because of Rust issue #74679. - let keys: *const [_] = unsafe { &raw const (*leaf).keys }; - let vals: *mut [_] = unsafe { &raw mut (*leaf).vals }; + let keys: *const [_] = keys; + let vals: *mut [_] = vals; // SAFETY: The keys and values of a node must always be initialized up to length. let key = unsafe { (&*keys.get_unchecked(idx)).assume_init_ref() }; let val = unsafe { (&mut *vals.get_unchecked_mut(idx)).assume_init_mut() }; @@ -817,11 +824,25 @@ impl Handle, mar } } +impl NodeRef { + /// Could be a public implementation of PartialEq, but only used in this module. + fn eq(&self, other: &Self) -> bool { + let Self { node, height, _marker: _ } = self; + if *node == other.node { + debug_assert_eq!(*height, other.height); + true + } else { + false + } + } +} + impl PartialEq for Handle, HandleType> { fn eq(&self, other: &Self) -> bool { - self.node.node == other.node.node && self.idx == other.idx + let Self { node, idx, _marker: _ } = self; + node.eq(&other.node) && *idx == other.idx } } @@ -829,7 +850,8 @@ impl PartialOrd for Handle, HandleType> { fn partial_cmp(&self, other: &Self) -> Option { - if self.node.node == other.node.node { Some(self.idx.cmp(&other.idx)) } else { None } + let Self { node, idx, _marker: _ } = self; + if node.eq(&other.node) { Some(idx.cmp(&other.idx)) } else { None } } } diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs index 54c3709821acd..2ef9aad0ccdcf 100644 --- a/library/alloc/src/collections/btree/node/tests.rs +++ b/library/alloc/src/collections/btree/node/tests.rs @@ -1,4 +1,5 @@ use super::*; +use core::cmp::Ordering::*; #[test] fn test_splitpoint() { @@ -24,6 +25,38 @@ fn test_splitpoint() { } } +#[test] +fn test_partial_cmp_eq() { + let mut root1: Root = Root::new_leaf(); + let mut leaf1 = unsafe { root1.leaf_node_as_mut() }; + leaf1.push(1, ()); + root1.push_internal_level(); + let root2: Root = Root::new_leaf(); + + let leaf_edge_1a = root1.node_as_ref().first_leaf_edge().forget_node_type(); + let leaf_edge_1b = root1.node_as_ref().last_leaf_edge().forget_node_type(); + let top_edge_1 = root1.node_as_ref().first_edge(); + let top_edge_2 = root2.node_as_ref().first_edge(); + + assert!(leaf_edge_1a == leaf_edge_1a); + assert!(leaf_edge_1a != leaf_edge_1b); + assert!(leaf_edge_1a != top_edge_1); + assert!(leaf_edge_1a != top_edge_2); + assert!(top_edge_1 == top_edge_1); + assert!(top_edge_1 != top_edge_2); + + assert_eq!(leaf_edge_1a.partial_cmp(&leaf_edge_1a), Some(Equal)); + assert_eq!(leaf_edge_1a.partial_cmp(&leaf_edge_1b), Some(Less)); + assert_eq!(leaf_edge_1a.partial_cmp(&top_edge_1), None); + assert_eq!(leaf_edge_1a.partial_cmp(&top_edge_2), None); + assert_eq!(top_edge_1.partial_cmp(&top_edge_1), Some(Equal)); + assert_eq!(top_edge_1.partial_cmp(&top_edge_2), None); + + root1.pop_internal_level(); + unsafe { root1.into_ref().deallocate_and_ascend() }; + unsafe { root2.into_ref().deallocate_and_ascend() }; +} + #[test] #[cfg(target_arch = "x86_64")] fn test_sizes() { From 46cc889abf6564408ffa1d9e896a3fc22a859d10 Mon Sep 17 00:00:00 2001 From: hosseind88 Date: Wed, 14 Oct 2020 18:19:26 +0330 Subject: [PATCH 44/50] fix stderr file of clippy/custom_ice_message test --- src/tools/clippy/tests/ui/custom_ice_message.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clippy/tests/ui/custom_ice_message.stderr b/src/tools/clippy/tests/ui/custom_ice_message.stderr index 87cdb7a8b99dd..a1b8e2ee162cf 100644 --- a/src/tools/clippy/tests/ui/custom_ice_message.stderr +++ b/src/tools/clippy/tests/ui/custom_ice_message.stderr @@ -10,4 +10,4 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy note: Clippy version: foo query stack during panic: -we're just showing a limited slice of the query stack +end of query stack From 9752787dca8f891634c8802ba196d5eca4c80c27 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 18 Aug 2020 18:40:03 +0100 Subject: [PATCH 45/50] mangling: non-monomorphic `#[rustc_symbol_name]` This commit adjust `#[rustc_symbol_name]` so that it can be applied to non-monomorphic functions without producing an ICE. Signed-off-by: David Wood --- compiler/rustc_middle/src/ty/instance.rs | 12 +++++++++++- compiler/rustc_middle/src/ty/util.rs | 18 ++---------------- compiler/rustc_symbol_mangling/src/legacy.rs | 1 - compiler/rustc_symbol_mangling/src/test.rs | 9 ++++++--- 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index f8e8c209d373d..4a2c97b4a400f 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -291,7 +291,17 @@ impl<'tcx> Instance<'tcx> { } pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> { - Instance::new(def_id, tcx.empty_substs_for_def_id(def_id)) + let substs = InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind { + ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), + ty::GenericParamDefKind::Type { .. } => { + bug!("Instance::mono: {:?} has type parameters", def_id) + } + ty::GenericParamDefKind::Const { .. } => { + bug!("Instance::mono: {:?} has const parameters", def_id) + } + }); + + Instance::new(def_id, substs) } #[inline] diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 8734acad9b228..b0f0f0ba57fad 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -6,9 +6,9 @@ use crate::mir::interpret::{sign_extend, truncate}; use crate::ty::fold::TypeFolder; use crate::ty::layout::IntegerExt; use crate::ty::query::TyCtxtAt; -use crate::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef}; +use crate::ty::subst::{GenericArgKind, Subst, SubstsRef}; use crate::ty::TyKind::*; -use crate::ty::{self, DefIdTree, GenericParamDefKind, List, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, DefIdTree, List, Ty, TyCtxt, TypeFoldable}; use rustc_apfloat::Float as _; use rustc_ast as ast; use rustc_attr::{self as attr, SignedInt, UnsignedInt}; @@ -509,20 +509,6 @@ impl<'tcx> TyCtxt<'tcx> { Some(ty::Binder::bind(env_ty)) } - /// Given the `DefId` of some item that has no type or const parameters, make - /// a suitable "empty substs" for it. - pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> SubstsRef<'tcx> { - InternalSubsts::for_item(self, item_def_id, |param, _| match param.kind { - GenericParamDefKind::Lifetime => self.lifetimes.re_erased.into(), - GenericParamDefKind::Type { .. } => { - bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) - } - GenericParamDefKind::Const { .. } => { - bug!("empty_substs_for_def_id: {:?} has const parameters", item_def_id) - } - }) - } - /// Returns `true` if the node pointed to by `def_id` is a `static` item. pub fn is_static(self, def_id: DefId) -> bool { self.static_mutability(def_id).is_some() diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index b96e318bd3ea1..2c9caf73b8e42 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -115,7 +115,6 @@ fn get_symbol_hash<'tcx>( } // also include any type parameters (for generic items) - assert!(!substs.has_erasable_regions()); substs.hash_stable(&mut hcx, &mut hasher); if let Some(instantiating_crate) = instantiating_crate { diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index d2c9b05c5607f..822a835293474 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -6,7 +6,7 @@ use rustc_hir as hir; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{Instance, TyCtxt}; +use rustc_middle::ty::{subst::InternalSubsts, Instance, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; const SYMBOL_NAME: Symbol = sym::rustc_symbol_name; @@ -36,8 +36,11 @@ impl SymbolNamesTest<'tcx> { let def_id = tcx.hir().local_def_id(hir_id); for attr in tcx.get_attrs(def_id.to_def_id()).iter() { if tcx.sess.check_name(attr, SYMBOL_NAME) { - // for now, can only use on monomorphic names - let instance = Instance::mono(tcx, def_id.to_def_id()); + let def_id = def_id.to_def_id(); + let instance = Instance::new( + def_id, + tcx.erase_regions(&InternalSubsts::identity_for_item(tcx, def_id)), + ); let mangled = tcx.symbol_name(instance); tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled)); if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) { From fbdfe2c63bb11c91edc8488e7391e9fd2fd415ac Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 24 Aug 2020 15:39:31 +0100 Subject: [PATCH 46/50] mangling: encode all impl parameters This commit modifies v0 symbol mangling to include all generic parameters from impl blocks (not just those used in the self type). Signed-off-by: David Wood --- compiler/rustc_symbol_mangling/src/v0.rs | 65 ++++++++++++------- .../ui/symbol-names/issue-75326.legacy.stderr | 20 ++++++ src/test/ui/symbol-names/issue-75326.rs | 58 +++++++++++++++++ .../ui/symbol-names/issue-75326.v0.stderr | 20 ++++++ 4 files changed, 140 insertions(+), 23 deletions(-) create mode 100644 src/test/ui/symbol-names/issue-75326.legacy.stderr create mode 100644 src/test/ui/symbol-names/issue-75326.rs create mode 100644 src/test/ui/symbol-names/issue-75326.v0.stderr diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 183a11a527723..16d0b86903ea8 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -259,7 +259,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { } fn print_impl_path( - self, + mut self, impl_def_id: DefId, substs: &'tcx [GenericArg<'tcx>], mut self_ty: Ty<'tcx>, @@ -284,12 +284,37 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { } } - self.path_append_impl( - |cx| cx.print_def_path(parent_def_id, &[]), - &key.disambiguated_data, - self_ty, - impl_trait_ref, - ) + self.push(match impl_trait_ref { + Some(_) => "X", + None => "M", + }); + + // Encode impl generic params if the substitutions contain parameters (implying + // polymorphization is enabled) and this isn't an inherent impl. + if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_param_types_or_consts()) { + self = self.path_generic_args( + |this| { + this.path_append_ns( + |cx| cx.print_def_path(parent_def_id, &[]), + 'I', + key.disambiguated_data.disambiguator as u64, + "", + ) + }, + substs, + )?; + } else { + self.push_disambiguator(key.disambiguated_data.disambiguator as u64); + self = self.print_def_path(parent_def_id, &[])?; + } + + self = self_ty.print(self)?; + + if let Some(trait_ref) = impl_trait_ref { + self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?; + } + + Ok(self) } fn print_region(mut self, region: ty::Region<'_>) -> Result { @@ -538,6 +563,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { self.push_ident(&name); Ok(self) } + fn path_qualified( mut self, self_ty: Ty<'tcx>, @@ -552,24 +578,16 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { } fn path_append_impl( - mut self, - print_prefix: impl FnOnce(Self) -> Result, - disambiguated_data: &DisambiguatedDefPathData, - self_ty: Ty<'tcx>, - trait_ref: Option>, + self, + _: impl FnOnce(Self) -> Result, + _: &DisambiguatedDefPathData, + _: Ty<'tcx>, + _: Option>, ) -> Result { - self.push(match trait_ref { - Some(_) => "X", - None => "M", - }); - self.push_disambiguator(disambiguated_data.disambiguator as u64); - self = print_prefix(self)?; - self = self_ty.print(self)?; - if let Some(trait_ref) = trait_ref { - self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?; - } - Ok(self) + // Inlined into `print_impl_path` + unreachable!() } + fn path_append( self, print_prefix: impl FnOnce(Self) -> Result, @@ -603,6 +621,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { name.as_ref().map_or("", |s| &s[..]), ) } + fn path_generic_args( mut self, print_prefix: impl FnOnce(Self) -> Result, diff --git a/src/test/ui/symbol-names/issue-75326.legacy.stderr b/src/test/ui/symbol-names/issue-75326.legacy.stderr new file mode 100644 index 0000000000000..5f822f6660c09 --- /dev/null +++ b/src/test/ui/symbol-names/issue-75326.legacy.stderr @@ -0,0 +1,20 @@ +error: symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next17SYMBOL_HASH) + --> $DIR/issue-75326.rs:43:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling( as issue_75326::Iterator2>::next::SYMBOL_HASH) + --> $DIR/issue-75326.rs:43:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt( as issue_75326::Iterator2>::next) + --> $DIR/issue-75326.rs:43:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/symbol-names/issue-75326.rs b/src/test/ui/symbol-names/issue-75326.rs new file mode 100644 index 0000000000000..ce315164cefd3 --- /dev/null +++ b/src/test/ui/symbol-names/issue-75326.rs @@ -0,0 +1,58 @@ +// build-fail +// ignore-tidy-linelength +// revisions: legacy v0 +//[legacy]compile-flags: -Z symbol-mangling-version=legacy +//[v0]compile-flags: -Z symbol-mangling-version=v0 +//[legacy]normalize-stderr-32bit: "h[\d\w]+" -> "SYMBOL_HASH" +//[legacy]normalize-stderr-64bit: "h[\d\w]+" -> "SYMBOL_HASH" + +#![feature(rustc_attrs)] + +pub(crate) struct Foo(I, E); + +pub trait Iterator2 { + type Item; + + fn next(&mut self) -> Option; + + fn find

(&mut self, predicate: P) -> Option + where + Self: Sized, + P: FnMut(&Self::Item) -> bool, + { + unimplemented!() + } +} + +struct Bar; + +impl Iterator2 for Bar { + type Item = (u32, u16); + + fn next(&mut self) -> Option { + unimplemented!() + } +} + +impl Iterator2 for Foo +where + I: Iterator2, +{ + type Item = T; + + #[rustc_symbol_name] + //[legacy]~^ ERROR symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next + //[legacy]~| ERROR demangling( as issue_75326::Iterator2>::next + //[legacy]~| ERROR demangling-alt( as issue_75326::Iterator2>::next) + //[v0]~^^^^ ERROR symbol-name(_RNvXINICs4fqI2P2rA04_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_) + //[v0]~| ERROR demangling( as issue_75326[317d481089b8c8fe]::Iterator2>::next) + //[v0]~| ERROR demangling-alt( as issue_75326::Iterator2>::next) + fn next(&mut self) -> Option { + self.find(|_| true) + } +} + +fn main() { + let mut a = Foo(Bar, 1u16); + let _ = a.next(); +} diff --git a/src/test/ui/symbol-names/issue-75326.v0.stderr b/src/test/ui/symbol-names/issue-75326.v0.stderr new file mode 100644 index 0000000000000..59bdfa8ca3681 --- /dev/null +++ b/src/test/ui/symbol-names/issue-75326.v0.stderr @@ -0,0 +1,20 @@ +error: symbol-name(_RNvXINICs4fqI2P2rA04_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_) + --> $DIR/issue-75326.rs:43:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling( as issue_75326[317d481089b8c8fe]::Iterator2>::next) + --> $DIR/issue-75326.rs:43:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt( as issue_75326::Iterator2>::next) + --> $DIR/issue-75326.rs:43:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + From 95daa068f10ac01482cc654bb211e93ab7b56445 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Sat, 26 Sep 2020 13:46:00 -0400 Subject: [PATCH 47/50] fix off-by-one in parameter spans --- compiler/rustc_parse/src/parser/item.rs | 2 +- .../variadic-ffi-no-fixed-args.stderr | 2 +- .../ui/mismatched_types/issue-38371.stderr | 2 +- .../variadic-ffi-semantic-restrictions.stderr | 68 +++++++++---------- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 26ca99801277b..48341f71d33ea 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1744,7 +1744,7 @@ impl<'a> Parser<'a> { } }; - let span = lo.to(self.token.span); + let span = lo.until(self.token.span); Ok(Param { attrs: attrs.into(), diff --git a/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr b/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr index 7af38c88f4334..e11ba43ca2a9a 100644 --- a/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr @@ -2,7 +2,7 @@ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-no-fixed-args.rs:2:12 | LL | fn foo(...); - | ^^^^ + | ^^^ error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr index c2bce305877b4..5d2ce9302ece6 100644 --- a/src/test/ui/mismatched_types/issue-38371.stderr +++ b/src/test/ui/mismatched_types/issue-38371.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-38371.rs:4:8 | LL | fn foo(&foo: Foo) { - | ^^^^------ + | ^^^^----- | | | | | expected due to this | expected struct `Foo`, found reference diff --git a/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr b/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr index 21992a29670c9..3f3ddfed14a66 100644 --- a/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr +++ b/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr @@ -2,205 +2,205 @@ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:5:19 | LL | fn f1_1(x: isize, ...) {} - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:8:9 | LL | fn f1_2(...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:8:9 | LL | fn f1_2(...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:12:30 | LL | extern "C" fn f2_1(x: isize, ...) {} - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20 | LL | extern "C" fn f2_2(...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20 | LL | extern "C" fn f2_2(...) {} - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:19:20 | LL | extern "C" fn f2_3(..., x: isize) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:19:20 | LL | extern "C" fn f2_3(..., x: isize) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:23:26 | LL | extern fn f3_1(x: isize, ...) {} - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:26:16 | LL | extern fn f3_2(...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:26:16 | LL | extern fn f3_2(...) {} - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:30:16 | LL | extern fn f3_3(..., x: isize) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:30:16 | LL | extern fn f3_3(..., x: isize) {} - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:35:13 | LL | fn e_f1(...); - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:37:13 | LL | fn e_f2(..., x: isize); - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:44:23 | LL | fn i_f1(x: isize, ...) {} - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:46:13 | LL | fn i_f2(...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:46:13 | LL | fn i_f2(...) {} - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:49:13 | LL | fn i_f3(..., x: isize, ...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:49:13 | LL | fn i_f3(..., x: isize, ...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:49:28 | LL | fn i_f3(..., x: isize, ...) {} - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:53:13 | LL | fn i_f4(..., x: isize, ...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:53:13 | LL | fn i_f4(..., x: isize, ...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:53:28 | LL | fn i_f4(..., x: isize, ...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:60:23 | LL | fn t_f1(x: isize, ...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:62:23 | LL | fn t_f2(x: isize, ...); - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:64:13 | LL | fn t_f3(...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:64:13 | LL | fn t_f3(...) {} - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:67:13 | LL | fn t_f4(...); - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:67:13 | LL | fn t_f4(...); - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:70:13 | LL | fn t_f5(..., x: isize) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:70:13 | LL | fn t_f5(..., x: isize) {} - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:73:13 | LL | fn t_f6(..., x: isize); - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:73:13 | LL | fn t_f6(..., x: isize); - | ^^^^ + | ^^^ error: aborting due to 34 previous errors From 14b2d16c5c014de994c46eb17e52773ee01864c5 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Wed, 23 Sep 2020 22:43:32 -0400 Subject: [PATCH 48/50] ensure arguments are included in count mismatch span --- compiler/rustc_hir/src/hir.rs | 28 +++++++++++++ compiler/rustc_typeck/src/check/callee.rs | 8 ++-- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 27 +++++++++--- src/test/ui/arg-count-mismatch.stderr | 9 ++-- src/test/ui/c-variadic/variadic-ffi-1.stderr | 18 +++++--- src/test/ui/error-codes/E0060.stderr | 9 ++-- src/test/ui/error-codes/E0061.stderr | 18 +++++--- src/test/ui/hrtb/issue-58451.stderr | 20 ++++----- src/test/ui/issues/issue-18819.stderr | 9 ++-- src/test/ui/issues/issue-26094.stderr | 9 ++-- src/test/ui/issues/issue-4935.stderr | 9 ++-- .../ui/methods/method-call-err-msg.stderr | 36 ++++++++++------ src/test/ui/not-enough-arguments.rs | 19 +++++++++ src/test/ui/not-enough-arguments.stderr | 39 ++++++++++++++--- src/test/ui/span/issue-34264.stderr | 18 +++++--- src/test/ui/span/missing-unit-argument.stderr | 42 ++++++++++++------- ...priority-higher-than-other-inherent.stderr | 9 ++-- 17 files changed, 239 insertions(+), 88 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2141d5b1ee7b6..52727e3a61949 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2742,4 +2742,32 @@ impl<'hir> Node<'hir> { _ => None, } } + + pub fn hir_id(&self) -> Option { + match self { + Node::Item(Item { hir_id, .. }) + | Node::ForeignItem(ForeignItem { hir_id, .. }) + | Node::TraitItem(TraitItem { hir_id, .. }) + | Node::ImplItem(ImplItem { hir_id, .. }) + | Node::Field(StructField { hir_id, .. }) + | Node::AnonConst(AnonConst { hir_id, .. }) + | Node::Expr(Expr { hir_id, .. }) + | Node::Stmt(Stmt { hir_id, .. }) + | Node::Ty(Ty { hir_id, .. }) + | Node::Binding(Pat { hir_id, .. }) + | Node::Pat(Pat { hir_id, .. }) + | Node::Arm(Arm { hir_id, .. }) + | Node::Block(Block { hir_id, .. }) + | Node::Local(Local { hir_id, .. }) + | Node::MacroDef(MacroDef { hir_id, .. }) + | Node::Lifetime(Lifetime { hir_id, .. }) + | Node::Param(Param { hir_id, .. }) + | Node::GenericParam(GenericParam { hir_id, .. }) => Some(*hir_id), + Node::TraitRef(TraitRef { hir_ref_id, .. }) => Some(*hir_ref_id), + Node::PathSegment(PathSegment { hir_id, .. }) => *hir_id, + Node::Variant(Variant { id, .. }) => Some(*id), + Node::Ctor(variant) => variant.ctor_hir_id(), + Node::Crate(_) | Node::Visibility(_) => None, + } + } } diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 740783aeb9d1e..a38fb9642b92e 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -285,10 +285,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_exprs: &'tcx [hir::Expr<'tcx>], expected: Expectation<'tcx>, ) -> Ty<'tcx> { - let (fn_sig, def_span) = match *callee_ty.kind() { - ty::FnDef(def_id, _) => { - (callee_ty.fn_sig(self.tcx), self.tcx.hir().span_if_local(def_id)) - } + let (fn_sig, def_id) = match *callee_ty.kind() { + ty::FnDef(def_id, _) => (callee_ty.fn_sig(self.tcx), Some(def_id)), ty::FnPtr(sig) => (sig, None), ref t => { let mut unit_variant = None; @@ -427,7 +425,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_exprs, fn_sig.c_variadic, TupleArgumentsFlag::DontTupleArguments, - def_span, + def_id, ); fn_sig.output() diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 3224e04ee49fa..fd2f5eb5018d4 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -19,7 +19,7 @@ use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty}; use rustc_session::Session; use rustc_span::symbol::{sym, Ident}; -use rustc_span::{self, Span}; +use rustc_span::{self, MultiSpan, Span}; use rustc_trait_selection::traits::{self, ObligationCauseCode}; use std::mem::replace; @@ -83,7 +83,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args_no_rcvr, method.sig.c_variadic, tuple_arguments, - self.tcx.hir().span_if_local(method.def_id), + Some(method.def_id), ); method.sig.output() } @@ -99,7 +99,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args: &'tcx [hir::Expr<'tcx>], c_variadic: bool, tuple_arguments: TupleArgumentsFlag, - def_span: Option, + def_id: Option, ) { let tcx = self.tcx; // Grab the argument types, supplying fresh type variables @@ -172,9 +172,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - if let Some(def_s) = def_span.map(|sp| tcx.sess.source_map().guess_head_span(sp)) { - err.span_label(def_s, "defined here"); + if let Some(def_id) = def_id { + if let Some(node) = tcx.hir().get_if_local(def_id) { + let mut spans: MultiSpan = node + .ident() + .map(|ident| ident.span) + .unwrap_or_else(|| tcx.hir().span(node.hir_id().unwrap())) + .into(); + + if let Some(id) = node.body_id() { + let body = tcx.hir().body(id); + for param in body.params { + spans.push_span_label(param.span, String::new()); + } + } + + let def_kind = tcx.def_kind(def_id); + err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); + } } + if sugg_unit { let sugg_span = tcx.sess.source_map().end_point(expr.span); // remove closing `)` from the span diff --git a/src/test/ui/arg-count-mismatch.stderr b/src/test/ui/arg-count-mismatch.stderr index 7bc06134a690d..d0577e4864a78 100644 --- a/src/test/ui/arg-count-mismatch.stderr +++ b/src/test/ui/arg-count-mismatch.stderr @@ -1,13 +1,16 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/arg-count-mismatch.rs:5:28 | -LL | fn f(x: isize) { } - | -------------- defined here -LL | LL | fn main() { let i: (); i = f(); } | ^-- supplied 0 arguments | | | expected 1 argument + | +note: function defined here + --> $DIR/arg-count-mismatch.rs:3:4 + | +LL | fn f(x: isize) { } + | ^ -------- error: aborting due to previous error diff --git a/src/test/ui/c-variadic/variadic-ffi-1.stderr b/src/test/ui/c-variadic/variadic-ffi-1.stderr index 89ea65fd43fe4..6f2a6c359b537 100644 --- a/src/test/ui/c-variadic/variadic-ffi-1.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-1.stderr @@ -7,24 +7,30 @@ LL | fn printf(_: *const u8, ...); error[E0060]: this function takes at least 2 arguments but 0 arguments were supplied --> $DIR/variadic-ffi-1.rs:17:9 | -LL | fn foo(f: isize, x: u8, ...); - | ----------------------------- defined here -... LL | foo(); | ^^^-- supplied 0 arguments | | | expected at least 2 arguments + | +note: function defined here + --> $DIR/variadic-ffi-1.rs:10:8 + | +LL | fn foo(f: isize, x: u8, ...); + | ^^^ error[E0060]: this function takes at least 2 arguments but 1 argument was supplied --> $DIR/variadic-ffi-1.rs:18:9 | -LL | fn foo(f: isize, x: u8, ...); - | ----------------------------- defined here -... LL | foo(1); | ^^^ - supplied 1 argument | | | expected at least 2 arguments + | +note: function defined here + --> $DIR/variadic-ffi-1.rs:10:8 + | +LL | fn foo(f: isize, x: u8, ...); + | ^^^ error[E0308]: mismatched types --> $DIR/variadic-ffi-1.rs:20:56 diff --git a/src/test/ui/error-codes/E0060.stderr b/src/test/ui/error-codes/E0060.stderr index a600592c6c2e7..c80014d14763b 100644 --- a/src/test/ui/error-codes/E0060.stderr +++ b/src/test/ui/error-codes/E0060.stderr @@ -1,13 +1,16 @@ error[E0060]: this function takes at least 1 argument but 0 arguments were supplied --> $DIR/E0060.rs:6:14 | -LL | fn printf(_: *const u8, ...) -> u32; - | ------------------------------------ defined here -... LL | unsafe { printf(); } | ^^^^^^-- supplied 0 arguments | | | expected at least 1 argument + | +note: function defined here + --> $DIR/E0060.rs:2:8 + | +LL | fn printf(_: *const u8, ...) -> u32; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0061.stderr b/src/test/ui/error-codes/E0061.stderr index dfefa0df31332..98488a2d298b9 100644 --- a/src/test/ui/error-codes/E0061.stderr +++ b/src/test/ui/error-codes/E0061.stderr @@ -1,24 +1,30 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/E0061.rs:6:5 | -LL | fn f(a: u16, b: &str) {} - | --------------------- defined here -... LL | f(0); | ^ - supplied 1 argument | | | expected 2 arguments + | +note: function defined here + --> $DIR/E0061.rs:1:4 + | +LL | fn f(a: u16, b: &str) {} + | ^ ------ ------- error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/E0061.rs:10:5 | -LL | fn f2(a: u16) {} - | ------------- defined here -... LL | f2(); | ^^-- supplied 0 arguments | | | expected 1 argument + | +note: function defined here + --> $DIR/E0061.rs:3:4 + | +LL | fn f2(a: u16) {} + | ^^ ------ error: aborting due to 2 previous errors diff --git a/src/test/ui/hrtb/issue-58451.stderr b/src/test/ui/hrtb/issue-58451.stderr index bd08fc1bfaeea..2cc1c7a2e7269 100644 --- a/src/test/ui/hrtb/issue-58451.stderr +++ b/src/test/ui/hrtb/issue-58451.stderr @@ -1,16 +1,16 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/issue-58451.rs:12:9 | -LL | / fn f(i: I) -LL | | where -LL | | I: IntoIterator, -LL | | I::Item: for<'a> Into<&'a ()>, - | |__________________________________- defined here -... -LL | f(&[f()]); - | ^-- supplied 0 arguments - | | - | expected 1 argument +LL | f(&[f()]); + | ^-- supplied 0 arguments + | | + | expected 1 argument + | +note: function defined here + --> $DIR/issue-58451.rs:5:4 + | +LL | fn f(i: I) + | ^ ---- error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18819.stderr b/src/test/ui/issues/issue-18819.stderr index a952c9b46c9d8..b10d26abe3485 100644 --- a/src/test/ui/issues/issue-18819.stderr +++ b/src/test/ui/issues/issue-18819.stderr @@ -1,13 +1,16 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/issue-18819.rs:16:5 | -LL | fn print_x(_: &dyn Foo, extra: &str) { - | ----------------------------------------------- defined here -... LL | print_x(X); | ^^^^^^^ - supplied 1 argument | | | expected 2 arguments + | +note: function defined here + --> $DIR/issue-18819.rs:11:4 + | +LL | fn print_x(_: &dyn Foo, extra: &str) { + | ^^^^^^^ ---------------------- ----------- error: aborting due to previous error diff --git a/src/test/ui/issues/issue-26094.stderr b/src/test/ui/issues/issue-26094.stderr index 2038d88bf4651..a6f1ac9286cda 100644 --- a/src/test/ui/issues/issue-26094.stderr +++ b/src/test/ui/issues/issue-26094.stderr @@ -4,11 +4,14 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied LL | $other(None) | ---- supplied 1 argument ... -LL | fn some_function() {} - | ------------------ defined here -... LL | some_macro!(some_function); | ^^^^^^^^^^^^^ expected 0 arguments + | +note: function defined here + --> $DIR/issue-26094.rs:7:4 + | +LL | fn some_function() {} + | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-4935.stderr b/src/test/ui/issues/issue-4935.stderr index 0cc686e1cf87f..03b9b91edefb2 100644 --- a/src/test/ui/issues/issue-4935.stderr +++ b/src/test/ui/issues/issue-4935.stderr @@ -1,13 +1,16 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/issue-4935.rs:5:13 | -LL | fn foo(a: usize) {} - | ---------------- defined here -LL | LL | fn main() { foo(5, 6) } | ^^^ - - supplied 2 arguments | | | expected 1 argument + | +note: function defined here + --> $DIR/issue-4935.rs:3:4 + | +LL | fn foo(a: usize) {} + | ^^^ -------- error: aborting due to previous error diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr index b0d1bb9823b8d..60f9eeeca27fe 100644 --- a/src/test/ui/methods/method-call-err-msg.stderr +++ b/src/test/ui/methods/method-call-err-msg.stderr @@ -1,35 +1,44 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied --> $DIR/method-call-err-msg.rs:13:7 | -LL | fn zero(self) -> Foo { self } - | -------------------- defined here -... LL | x.zero(0) | ^^^^ - supplied 1 argument | | | expected 0 arguments + | +note: associated function defined here + --> $DIR/method-call-err-msg.rs:5:8 + | +LL | fn zero(self) -> Foo { self } + | ^^^^ ---- error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/method-call-err-msg.rs:14:7 | -LL | fn one(self, _: isize) -> Foo { self } - | ----------------------------- defined here -... LL | .one() | ^^^- supplied 0 arguments | | | expected 1 argument + | +note: associated function defined here + --> $DIR/method-call-err-msg.rs:6:8 + | +LL | fn one(self, _: isize) -> Foo { self } + | ^^^ ---- -------- error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/method-call-err-msg.rs:15:7 | -LL | fn two(self, _: isize, _: isize) -> Foo { self } - | --------------------------------------- defined here -... LL | .two(0); | ^^^ - supplied 1 argument | | | expected 2 arguments + | +note: associated function defined here + --> $DIR/method-call-err-msg.rs:7:8 + | +LL | fn two(self, _: isize, _: isize) -> Foo { self } + | ^^^ ---- -------- -------- error[E0599]: no method named `take` found for struct `Foo` in the current scope --> $DIR/method-call-err-msg.rs:19:7 @@ -53,13 +62,16 @@ LL | .take() error[E0061]: this function takes 3 arguments but 0 arguments were supplied --> $DIR/method-call-err-msg.rs:21:7 | -LL | fn three(self, _: T, _: T, _: T) -> Foo { self } - | ------------------------------------------ defined here -... LL | y.three::(); | ^^^^^--------- supplied 0 arguments | | | expected 3 arguments + | +note: associated function defined here + --> $DIR/method-call-err-msg.rs:8:8 + | +LL | fn three(self, _: T, _: T, _: T) -> Foo { self } + | ^^^^^ ---- ---- ---- ---- error: aborting due to 5 previous errors diff --git a/src/test/ui/not-enough-arguments.rs b/src/test/ui/not-enough-arguments.rs index 631bb1dd27415..4247625518871 100644 --- a/src/test/ui/not-enough-arguments.rs +++ b/src/test/ui/not-enough-arguments.rs @@ -6,7 +6,26 @@ fn foo(a: isize, b: isize, c: isize, d:isize) { panic!(); } +// Check that all arguments are shown in the error message, even if they're across multiple lines. +fn bar( + a: i32, + b: i32, + c: i32, + d: i32, + e: i32, + f: i32, +) { + println!("{}", a); + println!("{}", b); + println!("{}", c); + println!("{}", d); + println!("{}", e); + println!("{}", f); +} + fn main() { foo(1, 2, 3); //~^ ERROR this function takes 4 arguments but 3 + bar(1, 2, 3); + //~^ ERROR this function takes 6 arguments but 3 } diff --git a/src/test/ui/not-enough-arguments.stderr b/src/test/ui/not-enough-arguments.stderr index f2b57f71400f1..df95783724148 100644 --- a/src/test/ui/not-enough-arguments.stderr +++ b/src/test/ui/not-enough-arguments.stderr @@ -1,14 +1,43 @@ error[E0061]: this function takes 4 arguments but 3 arguments were supplied - --> $DIR/not-enough-arguments.rs:10:3 + --> $DIR/not-enough-arguments.rs:27:3 | -LL | fn foo(a: isize, b: isize, c: isize, d:isize) { - | --------------------------------------------- defined here -... LL | foo(1, 2, 3); | ^^^ - - - supplied 3 arguments | | | expected 4 arguments + | +note: function defined here + --> $DIR/not-enough-arguments.rs:5:4 + | +LL | fn foo(a: isize, b: isize, c: isize, d:isize) { + | ^^^ -------- -------- -------- ------- + +error[E0061]: this function takes 6 arguments but 3 arguments were supplied + --> $DIR/not-enough-arguments.rs:29:3 + | +LL | bar(1, 2, 3); + | ^^^ - - - supplied 3 arguments + | | + | expected 6 arguments + | +note: function defined here + --> $DIR/not-enough-arguments.rs:10:4 + | +LL | fn bar( + | ^^^ +LL | a: i32, + | ------ +LL | b: i32, + | ------ +LL | c: i32, + | ------ +LL | d: i32, + | ------ +LL | e: i32, + | ------ +LL | f: i32, + | ------ -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0061`. diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr index 40c3219bf27b0..5cda17fd6a1fc 100644 --- a/src/test/ui/span/issue-34264.stderr +++ b/src/test/ui/span/issue-34264.stderr @@ -53,13 +53,16 @@ LL | fn bar(_: x, y: usize) {} error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:7:5 | -LL | fn foo(Option, String) {} - | --------------------------- defined here -... LL | foo(Some(42), 2, ""); | ^^^ -------- - -- supplied 3 arguments | | | expected 2 arguments + | +note: function defined here + --> $DIR/issue-34264.rs:1:4 + | +LL | fn foo(Option, String) {} + | ^^^ ----------- ------ error[E0308]: mismatched types --> $DIR/issue-34264.rs:8:13 @@ -70,13 +73,16 @@ LL | bar("", ""); error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:10:5 | -LL | fn bar(x, y: usize) {} - | ------------------- defined here -... LL | bar(1, 2, 3); | ^^^ - - - supplied 3 arguments | | | expected 2 arguments + | +note: function defined here + --> $DIR/issue-34264.rs:3:4 + | +LL | fn bar(x, y: usize) {} + | ^^^ - -------- error: aborting due to 6 previous errors diff --git a/src/test/ui/span/missing-unit-argument.stderr b/src/test/ui/span/missing-unit-argument.stderr index f6344fba3d368..b15da2cb47955 100644 --- a/src/test/ui/span/missing-unit-argument.stderr +++ b/src/test/ui/span/missing-unit-argument.stderr @@ -12,34 +12,42 @@ LL | let _: Result<(), String> = Ok(()); error[E0061]: this function takes 2 arguments but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:12:5 | -LL | fn foo(():(), ():()) {} - | -------------------- defined here -... LL | foo(); | ^^^-- supplied 0 arguments | | | expected 2 arguments + | +note: function defined here + --> $DIR/missing-unit-argument.rs:1:4 + | +LL | fn foo(():(), ():()) {} + | ^^^ ----- ----- error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/missing-unit-argument.rs:13:5 | -LL | fn foo(():(), ():()) {} - | -------------------- defined here -... LL | foo(()); | ^^^ -- supplied 1 argument | | | expected 2 arguments + | +note: function defined here + --> $DIR/missing-unit-argument.rs:1:4 + | +LL | fn foo(():(), ():()) {} + | ^^^ ----- ----- error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:14:5 | -LL | fn bar(():()) {} - | ------------- defined here -... LL | bar(); | ^^^-- supplied 0 arguments | +note: function defined here + --> $DIR/missing-unit-argument.rs:2:4 + | +LL | fn bar(():()) {} + | ^^^ ----- help: expected the unit value `()`; create it with empty parentheses | LL | bar(()); @@ -48,12 +56,14 @@ LL | bar(()); error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:15:7 | -LL | fn baz(self, (): ()) { } - | -------------------- defined here -... LL | S.baz(); | ^^^- supplied 0 arguments | +note: associated function defined here + --> $DIR/missing-unit-argument.rs:6:8 + | +LL | fn baz(self, (): ()) { } + | ^^^ ---- ------ help: expected the unit value `()`; create it with empty parentheses | LL | S.baz(()); @@ -62,12 +72,14 @@ LL | S.baz(()); error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:16:7 | -LL | fn generic(self, _: T) { } - | ------------------------- defined here -... LL | S.generic::<()>(); | ^^^^^^^------ supplied 0 arguments | +note: associated function defined here + --> $DIR/missing-unit-argument.rs:7:8 + | +LL | fn generic(self, _: T) { } + | ^^^^^^^ ---- ---- help: expected the unit value `()`; create it with empty parentheses | LL | S.generic::<()>(()); diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr index 46e7dd0c517e8..20e260584513a 100644 --- a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr +++ b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr @@ -1,13 +1,16 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:21:5 | -LL | V(u8) - | ----- defined here -... LL | ::V(); | ^^^^^^-- supplied 0 arguments | | | expected 1 argument + | +note: tuple variant defined here + --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:5:5 + | +LL | V(u8) + | ^^^^^ error[E0308]: mismatched types --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:22:17 From 1c03f6dee571f63613432b00bbfe3d613929e672 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 15 Oct 2020 08:53:09 -0700 Subject: [PATCH 49/50] Fix intra doc link for needs_drop --- library/core/src/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index b2798ea66250f..2a7c105e807f4 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1082,7 +1082,7 @@ extern "rust-intrinsic" { /// If the actual type neither requires drop glue nor implements /// `Copy`, then the return value of this function is unspecified. /// - /// The stabilized version of this intrinsic is [`needs_drop`]. + /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop). #[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")] pub fn needs_drop() -> bool; From 7bd6403b38965a17bd0f0693fa1563d09681d422 Mon Sep 17 00:00:00 2001 From: Waffle Date: Fri, 16 Oct 2020 01:11:39 +0300 Subject: [PATCH 50/50] fill in the tracking issue --- library/core/src/str/iter.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 2da390b2b2b24..bee86df520c80 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -736,7 +736,7 @@ impl<'a, P: Pattern<'a>> Split<'a, P> { /// assert_eq!(split.as_str(), ""); /// ``` #[inline] - #[unstable(feature = "str_split_as_str", issue = "none")] + #[unstable(feature = "str_split_as_str", issue = "77998")] pub fn as_str(&self) -> &'a str { self.0.as_str() } @@ -757,7 +757,7 @@ impl<'a, P: Pattern<'a>> RSplit<'a, P> { /// assert_eq!(split.as_str(), ""); /// ``` #[inline] - #[unstable(feature = "str_split_as_str", issue = "none")] + #[unstable(feature = "str_split_as_str", issue = "77998")] pub fn as_str(&self) -> &'a str { self.0.as_str() } @@ -796,7 +796,7 @@ impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> { /// assert_eq!(split.as_str(), ""); /// ``` #[inline] - #[unstable(feature = "str_split_as_str", issue = "none")] + #[unstable(feature = "str_split_as_str", issue = "77998")] pub fn as_str(&self) -> &'a str { self.0.as_str() } @@ -817,7 +817,7 @@ impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> { /// assert_eq!(split.as_str(), ""); /// ``` #[inline] - #[unstable(feature = "str_split_as_str", issue = "none")] + #[unstable(feature = "str_split_as_str", issue = "77998")] pub fn as_str(&self) -> &'a str { self.0.as_str() } @@ -919,7 +919,7 @@ impl<'a, P: Pattern<'a>> SplitN<'a, P> { /// assert_eq!(split.as_str(), ""); /// ``` #[inline] - #[unstable(feature = "str_split_as_str", issue = "none")] + #[unstable(feature = "str_split_as_str", issue = "77998")] pub fn as_str(&self) -> &'a str { self.0.as_str() } @@ -940,7 +940,7 @@ impl<'a, P: Pattern<'a>> RSplitN<'a, P> { /// assert_eq!(split.as_str(), ""); /// ``` #[inline] - #[unstable(feature = "str_split_as_str", issue = "none")] + #[unstable(feature = "str_split_as_str", issue = "77998")] pub fn as_str(&self) -> &'a str { self.0.as_str() } @@ -1292,7 +1292,7 @@ impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> { /// assert_eq!(split.as_str(), ""); /// ``` #[inline] - #[unstable(feature = "str_split_inclusive_as_str", issue = "none")] + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] pub fn as_str(&self) -> &'a str { self.0.as_str() }