Skip to content

Commit

Permalink
Auto merge of #70865 - Dylan-DPC:rollup-jje2cuv, r=Dylan-DPC
Browse files Browse the repository at this point in the history
Rollup of 5 pull requests

Successful merges:

 - #70612 (Add io::Write::write_all_vectored)
 - #70690 (Clean up E0501 explanation)
 - #70821 (expose suggestions::InferCtxtExt for clippy)
 - #70839 (clean up E0506 explanation)
 - #70859 (Move sanitize-inline-always test to sanitize directory)

Failed merges:

r? @ghost
  • Loading branch information
bors committed Apr 7, 2020
2 parents 6dee5f1 + b9fe46d commit bf1f2ee
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 47 deletions.
20 changes: 11 additions & 9 deletions src/librustc_error_codes/error_codes/E0501.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
This error indicates that a mutable variable is being used while it is still
captured by a closure. Because the closure has borrowed the variable, it is not
available for use until the closure goes out of scope.

Note that a capture will either move or borrow a variable, but in this
situation, the closure is borrowing the variable. Take a look at the chapter
on [Capturing][capturing] in Rust By Example for more information.

[capturing]: https://doc.rust-lang.org/stable/rust-by-example/fn/closures/capture.html
A mutable variable is used but it is already captured by a closure.

Erroneous code example:

Expand All @@ -29,6 +21,16 @@ fn foo(a: &mut i32) {
}
```

This error indicates that a mutable variable is used while it is still captured
by a closure. Because the closure has borrowed the variable, it is not available
until the closure goes out of scope.

Note that a capture will either move or borrow a variable, but in this
situation, the closure is borrowing the variable. Take a look at the chapter
on [Capturing][capturing] in Rust By Example for more information.

[capturing]: https://doc.rust-lang.org/stable/rust-by-example/fn/closures/capture.html

To fix this error, you can finish using the closure before using the captured
variable:

Expand Down
60 changes: 26 additions & 34 deletions src/librustc_error_codes/error_codes/E0506.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
This error occurs when an attempt is made to assign to a borrowed value.
An attempt was made to assign to a borrowed value.

Erroneous code example:

Expand All @@ -7,14 +7,12 @@ struct FancyNum {
num: u8,
}
fn main() {
let mut fancy_num = FancyNum { num: 5 };
let fancy_ref = &fancy_num;
fancy_num = FancyNum { num: 6 };
// error: cannot assign to `fancy_num` because it is borrowed
let mut fancy_num = FancyNum { num: 5 };
let fancy_ref = &fancy_num;
fancy_num = FancyNum { num: 6 };
// error: cannot assign to `fancy_num` because it is borrowed
println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num);
}
println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num);
```

Because `fancy_ref` still holds a reference to `fancy_num`, `fancy_num` can't
Expand All @@ -27,13 +25,11 @@ struct FancyNum {
num: u8,
}
fn main() {
let mut fancy_num = FancyNum { num: 5 };
let moved_num = fancy_num;
fancy_num = FancyNum { num: 6 };
let mut fancy_num = FancyNum { num: 5 };
let moved_num = fancy_num;
fancy_num = FancyNum { num: 6 };
println!("Num: {}, Moved num: {}", fancy_num.num, moved_num.num);
}
println!("Num: {}, Moved num: {}", fancy_num.num, moved_num.num);
```

If the value has to be borrowed, try limiting the lifetime of the borrow using
Expand All @@ -44,18 +40,16 @@ struct FancyNum {
num: u8,
}
fn main() {
let mut fancy_num = FancyNum { num: 5 };
{
let fancy_ref = &fancy_num;
println!("Ref: {}", fancy_ref.num);
}
let mut fancy_num = FancyNum { num: 5 };
// Works because `fancy_ref` is no longer in scope
fancy_num = FancyNum { num: 6 };
println!("Num: {}", fancy_num.num);
{
let fancy_ref = &fancy_num;
println!("Ref: {}", fancy_ref.num);
}
// Works because `fancy_ref` is no longer in scope
fancy_num = FancyNum { num: 6 };
println!("Num: {}", fancy_num.num);
```

Or by moving the reference into a function:
Expand All @@ -65,17 +59,15 @@ struct FancyNum {
num: u8,
}
fn main() {
let mut fancy_num = FancyNum { num: 5 };
print_fancy_ref(&fancy_num);
// Works because function borrow has ended
fancy_num = FancyNum { num: 6 };
println!("Num: {}", fancy_num.num);
}
fn print_fancy_ref(fancy_ref: &FancyNum){
println!("Ref: {}", fancy_ref.num);
}
let mut fancy_num = FancyNum { num: 5 };
print_fancy_ref(&fancy_num);
// Works because function borrow has ended
fancy_num = FancyNum { num: 6 };
println!("Num: {}", fancy_num.num);
```
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ use std::fmt;
use super::InferCtxtPrivExt;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;

crate trait InferCtxtExt<'tcx> {
// This trait is public to expose the diagnostics methods to clippy.
pub trait InferCtxtExt<'tcx> {
fn suggest_restricting_param_bound(
&self,
err: &mut DiagnosticBuilder<'_>,
Expand Down
170 changes: 169 additions & 1 deletion src/libstd/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@

use crate::cmp;
use crate::fmt;
use crate::mem;
use crate::memchr;
use crate::ops::{Deref, DerefMut};
use crate::ptr;
Expand Down Expand Up @@ -1376,6 +1377,70 @@ pub trait Write {
Ok(())
}

/// Attempts to write multiple buffers into this writer.
///
/// This method will continuously call [`write_vectored`] until there is no
/// more data to be written or an error of non-[`ErrorKind::Interrupted`]
/// kind is returned. This method will not return until all buffers have
/// been successfully written or such an error occurs. The first error that
/// is not of [`ErrorKind::Interrupted`] kind generated from this method
/// will be returned.
///
/// If the buffer contains no data, this will never call [`write_vectored`].
///
/// [`write_vectored`]: #method.write_vectored
/// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
///
/// # Notes
///
///
/// Unlike `io::Write::write_vectored`, this takes a *mutable* reference to
/// a slice of `IoSlice`s, not an immutable one. That's because we need to
/// modify the slice to keep track of the bytes already written.
///
/// Once this function returns, the contents of `bufs` are unspecified, as
/// this depends on how many calls to `write_vectored` were necessary. It is
/// best to understand this function as taking ownership of `bufs` and to
/// not use `bufs` afterwards. The underlying buffers, to which the
/// `IoSlice`s point (but not the `IoSlice`s themselves), are unchanged and
/// can be reused.
///
/// # Examples
///
/// ```
/// #![feature(write_all_vectored)]
/// # fn main() -> std::io::Result<()> {
///
/// use std::io::{Write, IoSlice};
///
/// let mut writer = Vec::new();
/// let bufs = &mut [
/// IoSlice::new(&[1]),
/// IoSlice::new(&[2, 3]),
/// IoSlice::new(&[4, 5, 6]),
/// ];
///
/// writer.write_all_vectored(bufs)?;
/// // Note: the contents of `bufs` is now undefined, see the Notes section.
///
/// assert_eq!(writer, &[1, 2, 3, 4, 5, 6]);
/// # Ok(()) }
/// ```
#[unstable(feature = "write_all_vectored", issue = "70436")]
fn write_all_vectored(&mut self, mut bufs: &mut [IoSlice<'_>]) -> Result<()> {
while !bufs.is_empty() {
match self.write_vectored(bufs) {
Ok(0) => {
return Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer"));
}
Ok(n) => bufs = IoSlice::advance(mem::take(&mut bufs), n),
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
Ok(())
}

/// Writes a formatted string into this writer, returning any error
/// encountered.
///
Expand Down Expand Up @@ -2423,7 +2488,7 @@ impl<B: BufRead> Iterator for Lines<B> {
#[cfg(test)]
mod tests {
use super::{repeat, Cursor, SeekFrom};
use crate::cmp;
use crate::cmp::{self, min};
use crate::io::prelude::*;
use crate::io::{self, IoSlice, IoSliceMut};
use crate::ops::Deref;
Expand Down Expand Up @@ -2812,4 +2877,107 @@ mod tests {
bufs = IoSlice::advance(bufs, 9);
assert!(bufs.is_empty());
}

/// Create a new writer that reads from at most `n_bufs` and reads
/// `per_call` bytes (in total) per call to write.
fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter {
TestWriter { n_bufs, per_call, written: Vec::new() }
}

struct TestWriter {
n_bufs: usize,
per_call: usize,
written: Vec<u8>,
}

impl Write for TestWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.write_vectored(&[IoSlice::new(buf)])
}

fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
let mut left = self.per_call;
let mut written = 0;
for buf in bufs.iter().take(self.n_bufs) {
let n = min(left, buf.len());
self.written.extend_from_slice(&buf[0..n]);
left -= n;
written += n;
}
Ok(written)
}

fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}

#[test]
fn test_writer_read_from_one_buf() {
let mut writer = test_writer(1, 2);

assert_eq!(writer.write(&[]).unwrap(), 0);
assert_eq!(writer.write_vectored(&[]).unwrap(), 0);

// Read at most 2 bytes.
assert_eq!(writer.write(&[1, 1, 1]).unwrap(), 2);
let bufs = &[IoSlice::new(&[2, 2, 2])];
assert_eq!(writer.write_vectored(bufs).unwrap(), 2);

// Only read from first buf.
let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4, 4])];
assert_eq!(writer.write_vectored(bufs).unwrap(), 1);

assert_eq!(writer.written, &[1, 1, 2, 2, 3]);
}

#[test]
fn test_writer_read_from_multiple_bufs() {
let mut writer = test_writer(3, 3);

// Read at most 3 bytes from two buffers.
let bufs = &[IoSlice::new(&[1]), IoSlice::new(&[2, 2, 2])];
assert_eq!(writer.write_vectored(bufs).unwrap(), 3);

// Read at most 3 bytes from three buffers.
let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4]), IoSlice::new(&[5, 5])];
assert_eq!(writer.write_vectored(bufs).unwrap(), 3);

assert_eq!(writer.written, &[1, 2, 2, 3, 4, 5]);
}

#[test]
fn test_write_all_vectored() {
#[rustfmt::skip] // Becomes unreadable otherwise.
let tests: Vec<(_, &'static [u8])> = vec![
(vec![], &[]),
(vec![IoSlice::new(&[1])], &[1]),
(vec![IoSlice::new(&[1, 2])], &[1, 2]),
(vec![IoSlice::new(&[1, 2, 3])], &[1, 2, 3]),
(vec![IoSlice::new(&[1, 2, 3, 4])], &[1, 2, 3, 4]),
(vec![IoSlice::new(&[1, 2, 3, 4, 5])], &[1, 2, 3, 4, 5]),
(vec![IoSlice::new(&[1]), IoSlice::new(&[2])], &[1, 2]),
(vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2])], &[1, 2, 2]),
(vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2])], &[1, 1, 2, 2]),
(vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]),
(vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]),
(vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 1, 2, 2, 2]),
(vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 2, 2, 2, 2]),
(vec![IoSlice::new(&[1, 1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 1, 2, 2, 2, 2]),
(vec![IoSlice::new(&[1]), IoSlice::new(&[2]), IoSlice::new(&[3])], &[1, 2, 3]),
(vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3])], &[1, 1, 2, 2, 3, 3]),
(vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 2, 2, 3, 3, 3]),
(vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 1, 1, 2, 2, 2, 3, 3, 3]),
];

let writer_configs = &[(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)];

for (n_bufs, per_call) in writer_configs.iter().copied() {
for (mut input, wanted) in tests.clone().into_iter() {
let mut writer = test_writer(n_bufs, per_call);
assert!(writer.write_all_vectored(&mut *input).is_ok());
assert_eq!(&*writer.written, &*wanted);
}
}
}
}
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
warning: `no_sanitize` will have no effect after inlining
--> $DIR/sanitize-inline-always.rs:7:1
--> $DIR/inline-always.rs:7:1
|
LL | #[no_sanitize(address)]
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(inline_no_sanitize)]` on by default
note: inlining requested here
--> $DIR/sanitize-inline-always.rs:5:1
--> $DIR/inline-always.rs:5:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
Expand Down

0 comments on commit bf1f2ee

Please sign in to comment.