Auto merge of #134605 - jhpratt:rollup-quiss71, r=jhpratt
Rollup of 7 pull requests Successful merges: - #133087 (Detect missing `.` in method chain in `let` bindings and statements) - #134575 (Handle `DropKind::ForLint` in coroutines correctly) - #134576 (Improve prose around basic examples of Iter and IterMut) - #134577 (Improve prose around `as_slice` example of Iter) - #134579 (Improve prose around into_slice example of IterMut) - #134593 (Less unwrap() in documentation) - #134600 (Fix parenthesization of chained comparisons by pretty-printer) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
6076beecb8
24 changed files with 379 additions and 110 deletions
|
@ -153,9 +153,10 @@ impl AssocOp {
|
|||
match *self {
|
||||
Assign | AssignOp(_) => Fixity::Right,
|
||||
As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd
|
||||
| BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual
|
||||
| LAnd | LOr => Fixity::Left,
|
||||
DotDot | DotDotEq => Fixity::None,
|
||||
| BitXor | BitOr | LAnd | LOr => Fixity::Left,
|
||||
Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | DotDot | DotDotEq => {
|
||||
Fixity::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1481,14 +1481,6 @@ fn build_scope_drops<'tcx>(
|
|||
block = next;
|
||||
}
|
||||
DropKind::ForLint => {
|
||||
// If the operand has been moved, and we are not on an unwind
|
||||
// path, then don't generate the drop. (We only take this into
|
||||
// account for non-unwind paths so as not to disturb the
|
||||
// caching mechanism.)
|
||||
if scope.moved_locals.iter().any(|&o| o == local) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// As in the `DropKind::Storage` case below:
|
||||
// normally lint-related drops are not emitted for unwind,
|
||||
// so we can just leave `unwind_to` unmodified, but in some
|
||||
|
@ -1500,6 +1492,14 @@ fn build_scope_drops<'tcx>(
|
|||
unwind_to = unwind_drops.drops[unwind_to].next;
|
||||
}
|
||||
|
||||
// If the operand has been moved, and we are not on an unwind
|
||||
// path, then don't generate the drop. (We only take this into
|
||||
// account for non-unwind paths so as not to disturb the
|
||||
// caching mechanism.)
|
||||
if scope.moved_locals.iter().any(|&o| o == local) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cfg.push(block, Statement {
|
||||
source_info,
|
||||
kind: StatementKind::BackwardIncompatibleDropHint {
|
||||
|
@ -1552,7 +1552,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
|
|||
let mut unwind_indices = IndexVec::from_elem_n(unwind_target, 1);
|
||||
for (drop_idx, drop_node) in drops.drops.iter_enumerated().skip(1) {
|
||||
match drop_node.data.kind {
|
||||
DropKind::Storage => {
|
||||
DropKind::Storage | DropKind::ForLint => {
|
||||
if is_coroutine {
|
||||
let unwind_drop = self
|
||||
.scopes
|
||||
|
@ -1563,7 +1563,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
|
|||
unwind_indices.push(unwind_indices[drop_node.next]);
|
||||
}
|
||||
}
|
||||
DropKind::Value | DropKind::ForLint => {
|
||||
DropKind::Value => {
|
||||
let unwind_drop = self
|
||||
.scopes
|
||||
.unwind_drops
|
||||
|
|
|
@ -279,13 +279,9 @@ impl<'a> Parser<'a> {
|
|||
break;
|
||||
}
|
||||
|
||||
let fixity = op.fixity();
|
||||
let min_prec = match fixity {
|
||||
let min_prec = match op.fixity() {
|
||||
Fixity::Right => Bound::Included(prec),
|
||||
Fixity::Left => Bound::Excluded(prec),
|
||||
// We currently have no non-associative operators that are not handled above by
|
||||
// the special cases. The code is here only for future convenience.
|
||||
Fixity::None => Bound::Excluded(prec),
|
||||
Fixity::Left | Fixity::None => Bound::Excluded(prec),
|
||||
};
|
||||
let (rhs, _) = self.with_res(restrictions - Restrictions::STMT_EXPR, |this| {
|
||||
let attrs = this.parse_outer_attributes()?;
|
||||
|
@ -337,10 +333,6 @@ impl<'a> Parser<'a> {
|
|||
self.dcx().span_bug(span, "AssocOp should have been handled by special case")
|
||||
}
|
||||
};
|
||||
|
||||
if let Fixity::None = fixity {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok((lhs, parsed_something))
|
||||
|
|
|
@ -745,6 +745,51 @@ impl<'a> Parser<'a> {
|
|||
Ok(self.mk_block(stmts, s, lo.to(self.prev_token.span)))
|
||||
}
|
||||
|
||||
fn recover_missing_dot(&mut self, err: &mut Diag<'_>) {
|
||||
let Some((ident, _)) = self.token.ident() else {
|
||||
return;
|
||||
};
|
||||
if let Some(c) = ident.name.as_str().chars().next()
|
||||
&& c.is_uppercase()
|
||||
{
|
||||
return;
|
||||
}
|
||||
if self.token.is_reserved_ident() && !self.token.is_ident_named(kw::Await) {
|
||||
return;
|
||||
}
|
||||
if self.prev_token.is_reserved_ident() && self.prev_token.is_ident_named(kw::Await) {
|
||||
// Likely `foo.await bar`
|
||||
} else if !self.prev_token.is_reserved_ident() && self.prev_token.is_ident() {
|
||||
// Likely `foo bar`
|
||||
} else if self.prev_token.kind == token::Question {
|
||||
// `foo? bar`
|
||||
} else if self.prev_token.kind == token::CloseDelim(Delimiter::Parenthesis) {
|
||||
// `foo() bar`
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if self.token.span == self.prev_token.span {
|
||||
// Account for syntax errors in proc-macros.
|
||||
return;
|
||||
}
|
||||
if self.look_ahead(1, |t| [token::Semi, token::Question, token::Dot].contains(&t.kind)) {
|
||||
err.span_suggestion_verbose(
|
||||
self.prev_token.span.between(self.token.span),
|
||||
"you might have meant to write a field access",
|
||||
".".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
if self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Parenthesis)) {
|
||||
err.span_suggestion_verbose(
|
||||
self.prev_token.span.between(self.token.span),
|
||||
"you might have meant to write a method call",
|
||||
".".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses a statement, including the trailing semicolon.
|
||||
pub fn parse_full_stmt(
|
||||
&mut self,
|
||||
|
@ -851,7 +896,8 @@ impl<'a> Parser<'a> {
|
|||
Some(if recover.no() {
|
||||
res?
|
||||
} else {
|
||||
res.unwrap_or_else(|e| {
|
||||
res.unwrap_or_else(|mut e| {
|
||||
self.recover_missing_dot(&mut e);
|
||||
let guar = e.emit();
|
||||
self.recover_stmt();
|
||||
guar
|
||||
|
@ -872,7 +918,12 @@ impl<'a> Parser<'a> {
|
|||
// We might be at the `,` in `let x = foo<bar, baz>;`. Try to recover.
|
||||
match &mut local.kind {
|
||||
LocalKind::Init(expr) | LocalKind::InitElse(expr, _) => {
|
||||
self.check_mistyped_turbofish_with_multiple_type_params(e, expr)?;
|
||||
self.check_mistyped_turbofish_with_multiple_type_params(e, expr).map_err(
|
||||
|mut e| {
|
||||
self.recover_missing_dot(&mut e);
|
||||
e
|
||||
},
|
||||
)?;
|
||||
// We found `foo<bar, baz>`, have we fully recovered?
|
||||
self.expect_semi()?;
|
||||
}
|
||||
|
|
|
@ -531,8 +531,7 @@ impl<T: Ord, A: Allocator> BinaryHeap<T, A> {
|
|||
/// heap.push(1);
|
||||
/// heap.push(5);
|
||||
/// heap.push(2);
|
||||
/// {
|
||||
/// let mut val = heap.peek_mut().unwrap();
|
||||
/// if let Some(mut val) = heap.peek_mut() {
|
||||
/// *val = 0;
|
||||
/// }
|
||||
/// assert_eq!(heap.peek(), Some(&2));
|
||||
|
|
|
@ -262,7 +262,9 @@ impl<T> OnceCell<T> {
|
|||
///
|
||||
/// let value = cell.get_mut_or_try_init(|| "1234".parse());
|
||||
/// assert_eq!(value, Ok(&mut 1234));
|
||||
/// *value.unwrap() += 2;
|
||||
///
|
||||
/// let Ok(value) = value else { return; };
|
||||
/// *value += 2;
|
||||
/// assert_eq!(cell.get(), Some(&1236))
|
||||
/// ```
|
||||
#[unstable(feature = "once_cell_get_mut", issue = "121641")]
|
||||
|
@ -304,8 +306,8 @@ impl<T> OnceCell<T> {
|
|||
/// assert_eq!(cell.into_inner(), None);
|
||||
///
|
||||
/// let cell = OnceCell::new();
|
||||
/// cell.set("hello".to_string()).unwrap();
|
||||
/// assert_eq!(cell.into_inner(), Some("hello".to_string()));
|
||||
/// let _ = cell.set("hello".to_owned());
|
||||
/// assert_eq!(cell.into_inner(), Some("hello".to_owned()));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "once_cell", since = "1.70.0")]
|
||||
|
@ -332,8 +334,8 @@ impl<T> OnceCell<T> {
|
|||
/// assert_eq!(cell.take(), None);
|
||||
///
|
||||
/// let mut cell = OnceCell::new();
|
||||
/// cell.set("hello".to_string()).unwrap();
|
||||
/// assert_eq!(cell.take(), Some("hello".to_string()));
|
||||
/// let _ = cell.set("hello".to_owned());
|
||||
/// assert_eq!(cell.take(), Some("hello".to_owned()));
|
||||
/// assert_eq!(cell.get(), None);
|
||||
/// ```
|
||||
#[inline]
|
||||
|
|
|
@ -152,8 +152,9 @@ pub trait Write {
|
|||
/// }
|
||||
///
|
||||
/// let mut buf = String::new();
|
||||
/// writer(&mut buf, "hola").unwrap();
|
||||
/// writer(&mut buf, "hola")?;
|
||||
/// assert_eq!(&buf, "hola");
|
||||
/// # std::fmt::Result::Ok(())
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn write_str(&mut self, s: &str) -> Result;
|
||||
|
@ -179,9 +180,10 @@ pub trait Write {
|
|||
/// }
|
||||
///
|
||||
/// let mut buf = String::new();
|
||||
/// writer(&mut buf, 'a').unwrap();
|
||||
/// writer(&mut buf, 'b').unwrap();
|
||||
/// writer(&mut buf, 'a')?;
|
||||
/// writer(&mut buf, 'b')?;
|
||||
/// assert_eq!(&buf, "ab");
|
||||
/// # std::fmt::Result::Ok(())
|
||||
/// ```
|
||||
#[stable(feature = "fmt_write_char", since = "1.1.0")]
|
||||
fn write_char(&mut self, c: char) -> Result {
|
||||
|
@ -208,8 +210,9 @@ pub trait Write {
|
|||
/// }
|
||||
///
|
||||
/// let mut buf = String::new();
|
||||
/// writer(&mut buf, "world").unwrap();
|
||||
/// writer(&mut buf, "world")?;
|
||||
/// assert_eq!(&buf, "world");
|
||||
/// # std::fmt::Result::Ok(())
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn write_fmt(&mut self, args: Arguments<'_>) -> Result {
|
||||
|
|
|
@ -34,7 +34,7 @@ use crate::iter::{FusedIterator, TrustedLen};
|
|||
/// use std::fs;
|
||||
/// use std::path::PathBuf;
|
||||
///
|
||||
/// let dirs = fs::read_dir(".foo").unwrap();
|
||||
/// let dirs = fs::read_dir(".foo")?;
|
||||
///
|
||||
/// // we need to convert from an iterator of DirEntry-s to an iterator of
|
||||
/// // PathBufs, so we use map
|
||||
|
@ -50,6 +50,7 @@ use crate::iter::{FusedIterator, TrustedLen};
|
|||
/// for f in files {
|
||||
/// println!("{f:?}");
|
||||
/// }
|
||||
/// # std::io::Result::Ok(())
|
||||
/// ```
|
||||
#[stable(feature = "iter_once", since = "1.2.0")]
|
||||
pub fn once<T>(value: T) -> Once<T> {
|
||||
|
|
|
@ -2564,7 +2564,7 @@ pub trait Iterator {
|
|||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// let reduced: i32 = (1..10).reduce(|acc, e| acc + e).unwrap();
|
||||
/// let reduced: i32 = (1..10).reduce(|acc, e| acc + e).unwrap_or(0);
|
||||
/// assert_eq!(reduced, 45);
|
||||
///
|
||||
/// // Which is equivalent to doing it with `fold`:
|
||||
|
@ -3087,7 +3087,7 @@ pub trait Iterator {
|
|||
/// [2.4, f32::NAN, 1.3]
|
||||
/// .into_iter()
|
||||
/// .reduce(f32::max)
|
||||
/// .unwrap(),
|
||||
/// .unwrap_or(0.),
|
||||
/// 2.4
|
||||
/// );
|
||||
/// ```
|
||||
|
@ -3123,7 +3123,7 @@ pub trait Iterator {
|
|||
/// [2.4, f32::NAN, 1.3]
|
||||
/// .into_iter()
|
||||
/// .reduce(f32::min)
|
||||
/// .unwrap(),
|
||||
/// .unwrap_or(0.),
|
||||
/// 1.3
|
||||
/// );
|
||||
/// ```
|
||||
|
|
|
@ -937,10 +937,16 @@ impl<T> Option<T> {
|
|||
/// Returns the contained [`Some`] value, consuming the `self` value.
|
||||
///
|
||||
/// Because this function may panic, its use is generally discouraged.
|
||||
/// Panics are meant for unrecoverable errors, and
|
||||
/// [may abort the entire program][panic-abort].
|
||||
///
|
||||
/// Instead, prefer to use pattern matching and handle the [`None`]
|
||||
/// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or
|
||||
/// [`unwrap_or_default`].
|
||||
/// [`unwrap_or_default`]. In functions returning `Option`, you can use
|
||||
/// [the `?` (try) operator][try-option].
|
||||
///
|
||||
/// [panic-abort]: https://doc.rust-lang.org/book/ch09-01-unrecoverable-errors-with-panic.html
|
||||
/// [try-option]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#where-the--operator-can-be-used
|
||||
/// [`unwrap_or`]: Option::unwrap_or
|
||||
/// [`unwrap_or_else`]: Option::unwrap_or_else
|
||||
/// [`unwrap_or_default`]: Option::unwrap_or_default
|
||||
|
|
|
@ -502,11 +502,12 @@ impl<T: ?Sized> *const T {
|
|||
/// let mut out = String::new();
|
||||
/// while ptr != end_rounded_up {
|
||||
/// unsafe {
|
||||
/// write!(&mut out, "{}, ", *ptr).unwrap();
|
||||
/// write!(&mut out, "{}, ", *ptr)?;
|
||||
/// }
|
||||
/// ptr = ptr.wrapping_offset(step);
|
||||
/// }
|
||||
/// assert_eq!(out.as_str(), "1, 3, 5, ");
|
||||
/// # std::fmt::Result::Ok(())
|
||||
/// ```
|
||||
#[stable(feature = "ptr_wrapping_offset", since = "1.16.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
|
@ -1125,11 +1126,12 @@ impl<T: ?Sized> *const T {
|
|||
/// let mut out = String::new();
|
||||
/// while ptr != end_rounded_up {
|
||||
/// unsafe {
|
||||
/// write!(&mut out, "{}, ", *ptr).unwrap();
|
||||
/// write!(&mut out, "{}, ", *ptr)?;
|
||||
/// }
|
||||
/// ptr = ptr.wrapping_add(step);
|
||||
/// }
|
||||
/// assert_eq!(out, "1, 3, 5, ");
|
||||
/// # std::fmt::Result::Ok(())
|
||||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
|
@ -1203,11 +1205,12 @@ impl<T: ?Sized> *const T {
|
|||
/// let mut out = String::new();
|
||||
/// while ptr != start_rounded_down {
|
||||
/// unsafe {
|
||||
/// write!(&mut out, "{}, ", *ptr).unwrap();
|
||||
/// write!(&mut out, "{}, ", *ptr)?;
|
||||
/// }
|
||||
/// ptr = ptr.wrapping_sub(step);
|
||||
/// }
|
||||
/// assert_eq!(out, "5, 3, 1, ");
|
||||
/// # std::fmt::Result::Ok(())
|
||||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
|
|
|
@ -1065,10 +1065,15 @@ impl<T, E> Result<T, E> {
|
|||
/// Returns the contained [`Ok`] value, consuming the `self` value.
|
||||
///
|
||||
/// Because this function may panic, its use is generally discouraged.
|
||||
/// Instead, prefer to use pattern matching and handle the [`Err`]
|
||||
/// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or
|
||||
/// [`unwrap_or_default`].
|
||||
/// Panics are meant for unrecoverable errors, and
|
||||
/// [may abort the entire program][panic-abort].
|
||||
///
|
||||
/// Instead, prefer to use [the `?` (try) operator][try-operator], or pattern matching
|
||||
/// to handle the [`Err`] case explicitly, or call [`unwrap_or`],
|
||||
/// [`unwrap_or_else`], or [`unwrap_or_default`].
|
||||
///
|
||||
/// [panic-abort]: https://doc.rust-lang.org/book/ch09-01-unrecoverable-errors-with-panic.html
|
||||
/// [try-operator]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
|
||||
/// [`unwrap_or`]: Result::unwrap_or
|
||||
/// [`unwrap_or_else`]: Result::unwrap_or_else
|
||||
/// [`unwrap_or_default`]: Result::unwrap_or_default
|
||||
|
|
|
@ -46,13 +46,19 @@ impl<'a, T> IntoIterator for &'a mut [T] {
|
|||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // First, we declare a type which has `iter` method to get the `Iter` struct (`&[usize]` here):
|
||||
/// // First, we need a slice to call the `iter` method on:
|
||||
/// let slice = &[1, 2, 3];
|
||||
///
|
||||
/// // Then, we iterate over it:
|
||||
/// // Then we call `iter` on the slice to get the `Iter` struct,
|
||||
/// // and iterate over it:
|
||||
/// for element in slice.iter() {
|
||||
/// println!("{element}");
|
||||
/// }
|
||||
///
|
||||
/// // This for loop actually already works without calling `iter`:
|
||||
/// for element in slice {
|
||||
/// println!("{element}");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`iter`]: slice::iter
|
||||
|
@ -109,19 +115,25 @@ impl<'a, T> Iter<'a, T> {
|
|||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // First, we declare a type which has the `iter` method to get the `Iter`
|
||||
/// // First, we need a slice to call the `iter` method on:
|
||||
/// // struct (`&[usize]` here):
|
||||
/// let slice = &[1, 2, 3];
|
||||
///
|
||||
/// // Then, we get the iterator:
|
||||
/// // Then we call `iter` on the slice to get the `Iter` struct:
|
||||
/// let mut iter = slice.iter();
|
||||
/// // So if we print what `as_slice` method returns here, we have "[1, 2, 3]":
|
||||
/// // Here `as_slice` still returns the whole slice, so this prints "[1, 2, 3]":
|
||||
/// println!("{:?}", iter.as_slice());
|
||||
///
|
||||
/// // Next, we move to the second element of the slice:
|
||||
/// // Now, we call the `next` method to remove the first element of the iterator:
|
||||
/// iter.next();
|
||||
/// // Now `as_slice` returns "[2, 3]":
|
||||
/// // Here the iterator does not contain the first element of the slice any more,
|
||||
/// // so `as_slice` only returns the last two elements of the slice,
|
||||
/// // and so this prints "[2, 3]":
|
||||
/// println!("{:?}", iter.as_slice());
|
||||
///
|
||||
/// // The underlying slice has not been modified and still contains three elements,
|
||||
/// // so this prints "[1, 2, 3]":
|
||||
/// println!("{:?}", slice);
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "iter_to_slice", since = "1.4.0")]
|
||||
|
@ -166,11 +178,11 @@ impl<T> AsRef<[T]> for Iter<'_, T> {
|
|||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // First, we declare a type which has `iter_mut` method to get the `IterMut`
|
||||
/// // struct (`&[usize]` here):
|
||||
/// let mut slice = &mut [1, 2, 3];
|
||||
/// // First, we need a slice to call the `iter_mut` method on:
|
||||
/// let slice = &mut [1, 2, 3];
|
||||
///
|
||||
/// // Then, we iterate over it and increment each element value:
|
||||
/// // Then we call `iter_mut` on the slice to get the `IterMut` struct,
|
||||
/// // iterate over it and increment each element value:
|
||||
/// for element in slice.iter_mut() {
|
||||
/// *element += 1;
|
||||
/// }
|
||||
|
@ -247,28 +259,21 @@ impl<'a, T> IterMut<'a, T> {
|
|||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // First, we declare a type which has `iter_mut` method to get the `IterMut`
|
||||
/// // struct (`&[usize]` here):
|
||||
/// // First, we need a slice to call the `iter_mut` method on:
|
||||
/// let mut slice = &mut [1, 2, 3];
|
||||
///
|
||||
/// {
|
||||
/// // Then, we get the iterator:
|
||||
/// let mut iter = slice.iter_mut();
|
||||
/// // We move to next element:
|
||||
/// iter.next();
|
||||
/// // So if we print what `into_slice` method returns here, we have "[2, 3]":
|
||||
/// println!("{:?}", iter.into_slice());
|
||||
/// }
|
||||
///
|
||||
/// // Now let's modify a value of the slice:
|
||||
/// {
|
||||
/// // First we get back the iterator:
|
||||
/// let mut iter = slice.iter_mut();
|
||||
/// // We change the value of the first element of the slice returned by the `next` method:
|
||||
/// *iter.next().unwrap() += 1;
|
||||
/// }
|
||||
/// // Now slice is "[2, 2, 3]":
|
||||
/// println!("{slice:?}");
|
||||
/// // Then we call `iter_mut` on the slice to get the `IterMut` struct:
|
||||
/// let mut iter = slice.iter_mut();
|
||||
/// // Now, we call the `next` method to remove the first element of the iterator,
|
||||
/// // unwrap and dereference what we get from `next` and increase its value by 1:
|
||||
/// *iter.next().unwrap() += 1;
|
||||
/// // Here the iterator does not contain the first element of the slice any more,
|
||||
/// // so `into_slice` only returns the last two elements of the slice,
|
||||
/// // and so this prints "[2, 3]":
|
||||
/// println!("{:?}", iter.into_slice());
|
||||
/// // The underlying slice still contains three elements, but its first element
|
||||
/// // was increased by 1, so this prints "[2, 2, 3]":
|
||||
/// println!("{:?}", slice);
|
||||
/// ```
|
||||
#[must_use = "`self` will be dropped if the result is not used"]
|
||||
#[stable(feature = "iter_to_slice", since = "1.4.0")]
|
||||
|
|
|
@ -47,10 +47,11 @@ use crate::{mem, ptr};
|
|||
/// // some bytes, in a vector
|
||||
/// let sparkle_heart = vec![240, 159, 146, 150];
|
||||
///
|
||||
/// // We know these bytes are valid, so just use `unwrap()`.
|
||||
/// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap();
|
||||
/// // We can use the ? (try) operator to check if the bytes are valid
|
||||
/// let sparkle_heart = str::from_utf8(&sparkle_heart)?;
|
||||
///
|
||||
/// assert_eq!("💖", sparkle_heart);
|
||||
/// # Ok::<_, str::Utf8Error>(())
|
||||
/// ```
|
||||
///
|
||||
/// Incorrect bytes:
|
||||
|
|
|
@ -86,7 +86,7 @@
|
|||
//! // This is fine: `join` synchronizes the code in a way such that the atomic
|
||||
//! // store happens-before the non-atomic write.
|
||||
//! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed)); // atomic store
|
||||
//! handle.join().unwrap(); // synchronize
|
||||
//! handle.join().expect("thread won't panic"); // synchronize
|
||||
//! s.spawn(|| unsafe { atomic.as_ptr().write(2) }); // non-atomic write
|
||||
//! });
|
||||
//!
|
||||
|
@ -103,7 +103,7 @@
|
|||
//! // This is fine: `join` synchronizes the code in a way such that
|
||||
//! // the 1-byte store happens-before the 2-byte store.
|
||||
//! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed));
|
||||
//! handle.join().unwrap();
|
||||
//! handle.join().expect("thread won't panic");
|
||||
//! s.spawn(|| unsafe {
|
||||
//! let differently_sized = transmute::<&AtomicU16, &AtomicU8>(&atomic);
|
||||
//! differently_sized.store(2, Ordering::Relaxed);
|
||||
|
|
|
@ -1083,7 +1083,7 @@ pub trait Read {
|
|||
/// let f = BufReader::new(File::open("foo.txt")?);
|
||||
///
|
||||
/// for byte in f.bytes() {
|
||||
/// println!("{}", byte.unwrap());
|
||||
/// println!("{}", byte?);
|
||||
/// }
|
||||
/// Ok(())
|
||||
/// }
|
||||
|
@ -1995,15 +1995,16 @@ pub trait Seek {
|
|||
/// .write(true)
|
||||
/// .read(true)
|
||||
/// .create(true)
|
||||
/// .open("foo.txt").unwrap();
|
||||
/// .open("foo.txt")?;
|
||||
///
|
||||
/// let hello = "Hello!\n";
|
||||
/// write!(f, "{hello}").unwrap();
|
||||
/// f.rewind().unwrap();
|
||||
/// write!(f, "{hello}")?;
|
||||
/// f.rewind()?;
|
||||
///
|
||||
/// let mut buf = String::new();
|
||||
/// f.read_to_string(&mut buf).unwrap();
|
||||
/// f.read_to_string(&mut buf)?;
|
||||
/// assert_eq!(&buf, hello);
|
||||
/// # std::io::Result::Ok(())
|
||||
/// ```
|
||||
#[stable(feature = "seek_rewind", since = "1.55.0")]
|
||||
fn rewind(&mut self) -> Result<()> {
|
||||
|
@ -2212,8 +2213,9 @@ fn skip_until<R: BufRead + ?Sized>(r: &mut R, delim: u8) -> Result<usize> {
|
|||
///
|
||||
/// let stdin = io::stdin();
|
||||
/// for line in stdin.lock().lines() {
|
||||
/// println!("{}", line.unwrap());
|
||||
/// println!("{}", line?);
|
||||
/// }
|
||||
/// # std::io::Result::Ok(())
|
||||
/// ```
|
||||
///
|
||||
/// If you have something that implements [`Read`], you can use the [`BufReader`
|
||||
|
@ -2236,7 +2238,8 @@ fn skip_until<R: BufRead + ?Sized>(r: &mut R, delim: u8) -> Result<usize> {
|
|||
/// let f = BufReader::new(f);
|
||||
///
|
||||
/// for line in f.lines() {
|
||||
/// println!("{}", line.unwrap());
|
||||
/// let line = line?;
|
||||
/// println!("{line}");
|
||||
/// }
|
||||
///
|
||||
/// Ok(())
|
||||
|
@ -2274,7 +2277,7 @@ pub trait BufRead: Read {
|
|||
/// let stdin = io::stdin();
|
||||
/// let mut stdin = stdin.lock();
|
||||
///
|
||||
/// let buffer = stdin.fill_buf().unwrap();
|
||||
/// let buffer = stdin.fill_buf()?;
|
||||
///
|
||||
/// // work with buffer
|
||||
/// println!("{buffer:?}");
|
||||
|
@ -2282,6 +2285,7 @@ pub trait BufRead: Read {
|
|||
/// // ensure the bytes we worked with aren't returned again later
|
||||
/// let length = buffer.len();
|
||||
/// stdin.consume(length);
|
||||
/// # std::io::Result::Ok(())
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn fill_buf(&mut self) -> Result<&[u8]>;
|
||||
|
@ -2327,12 +2331,13 @@ pub trait BufRead: Read {
|
|||
/// let stdin = io::stdin();
|
||||
/// let mut stdin = stdin.lock();
|
||||
///
|
||||
/// while stdin.has_data_left().unwrap() {
|
||||
/// while stdin.has_data_left()? {
|
||||
/// let mut line = String::new();
|
||||
/// stdin.read_line(&mut line).unwrap();
|
||||
/// stdin.read_line(&mut line)?;
|
||||
/// // work with line
|
||||
/// println!("{line:?}");
|
||||
/// }
|
||||
/// # std::io::Result::Ok(())
|
||||
/// ```
|
||||
#[unstable(feature = "buf_read_has_data_left", reason = "recently added", issue = "86423")]
|
||||
fn has_data_left(&mut self) -> Result<bool> {
|
||||
|
|
|
@ -224,7 +224,7 @@ pub struct Child {
|
|||
/// has been captured. You might find it helpful to do
|
||||
///
|
||||
/// ```ignore (incomplete)
|
||||
/// let stdin = child.stdin.take().unwrap();
|
||||
/// let stdin = child.stdin.take().expect("handle present");
|
||||
/// ```
|
||||
///
|
||||
/// to avoid partially moving the `child` and thus blocking yourself from calling
|
||||
|
@ -236,7 +236,7 @@ pub struct Child {
|
|||
/// has been captured. You might find it helpful to do
|
||||
///
|
||||
/// ```ignore (incomplete)
|
||||
/// let stdout = child.stdout.take().unwrap();
|
||||
/// let stdout = child.stdout.take().expect("handle present");
|
||||
/// ```
|
||||
///
|
||||
/// to avoid partially moving the `child` and thus blocking yourself from calling
|
||||
|
@ -248,7 +248,7 @@ pub struct Child {
|
|||
/// has been captured. You might find it helpful to do
|
||||
///
|
||||
/// ```ignore (incomplete)
|
||||
/// let stderr = child.stderr.take().unwrap();
|
||||
/// let stderr = child.stderr.take().expect("handle present");
|
||||
/// ```
|
||||
///
|
||||
/// to avoid partially moving the `child` and thus blocking yourself from calling
|
||||
|
@ -1052,14 +1052,14 @@ impl Command {
|
|||
/// use std::io::{self, Write};
|
||||
/// let output = Command::new("/bin/cat")
|
||||
/// .arg("file.txt")
|
||||
/// .output()
|
||||
/// .expect("failed to execute process");
|
||||
/// .output()?;
|
||||
///
|
||||
/// println!("status: {}", output.status);
|
||||
/// io::stdout().write_all(&output.stdout).unwrap();
|
||||
/// io::stderr().write_all(&output.stderr).unwrap();
|
||||
/// io::stdout().write_all(&output.stdout)?;
|
||||
/// io::stderr().write_all(&output.stderr)?;
|
||||
///
|
||||
/// assert!(output.status.success());
|
||||
/// # io::Result::Ok(())
|
||||
/// ```
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
pub fn output(&mut self) -> io::Result<Output> {
|
||||
|
@ -1391,11 +1391,11 @@ impl Stdio {
|
|||
/// let output = Command::new("rev")
|
||||
/// .stdin(Stdio::inherit())
|
||||
/// .stdout(Stdio::piped())
|
||||
/// .output()
|
||||
/// .expect("Failed to execute command");
|
||||
/// .output()?;
|
||||
///
|
||||
/// print!("You piped in the reverse of: ");
|
||||
/// io::stdout().write_all(&output.stdout).unwrap();
|
||||
/// io::stdout().write_all(&output.stdout)?;
|
||||
/// # io::Result::Ok(())
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
|
@ -1575,14 +1575,14 @@ impl From<fs::File> for Stdio {
|
|||
/// use std::process::Command;
|
||||
///
|
||||
/// // With the `foo.txt` file containing "Hello, world!"
|
||||
/// let file = File::open("foo.txt").unwrap();
|
||||
/// let file = File::open("foo.txt")?;
|
||||
///
|
||||
/// let reverse = Command::new("rev")
|
||||
/// .stdin(file) // Implicit File conversion into a Stdio
|
||||
/// .output()
|
||||
/// .expect("failed reverse command");
|
||||
/// .output()?;
|
||||
///
|
||||
/// assert_eq!(reverse.stdout, b"!dlrow ,olleH");
|
||||
/// # std::io::Result::Ok(())
|
||||
/// ```
|
||||
fn from(file: fs::File) -> Stdio {
|
||||
Stdio::from_inner(file.into_inner().into())
|
||||
|
@ -2179,7 +2179,7 @@ impl Child {
|
|||
/// ```no_run
|
||||
/// use std::process::Command;
|
||||
///
|
||||
/// let mut child = Command::new("ls").spawn().unwrap();
|
||||
/// let mut child = Command::new("ls").spawn()?;
|
||||
///
|
||||
/// match child.try_wait() {
|
||||
/// Ok(Some(status)) => println!("exited with: {status}"),
|
||||
|
@ -2190,6 +2190,7 @@ impl Child {
|
|||
/// }
|
||||
/// Err(e) => println!("error attempting to wait: {e}"),
|
||||
/// }
|
||||
/// # std::io::Result::Ok(())
|
||||
/// ```
|
||||
#[stable(feature = "process_try_wait", since = "1.18.0")]
|
||||
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
|
||||
|
|
|
@ -61,6 +61,9 @@ static EXPRS: &[&str] = &[
|
|||
"(2 + 2) * 2",
|
||||
"2 * (2 + 2)",
|
||||
"2 + 2 + 2",
|
||||
// Right-associative operator.
|
||||
"2 += 2 += 2",
|
||||
"(2 += 2) += 2",
|
||||
// Return has lower precedence than a binary operator.
|
||||
"(return 2) + 2",
|
||||
"2 + (return 2)", // FIXME: no parenthesis needed.
|
||||
|
@ -89,6 +92,13 @@ static EXPRS: &[&str] = &[
|
|||
// allowed, except if the break is also labeled.
|
||||
"break 'outer 'inner: loop {} + 2",
|
||||
"break ('inner: loop {} + 2)",
|
||||
// Grammar restriction: ranges cannot be the endpoint of another range.
|
||||
"(2..2)..2",
|
||||
"2..(2..2)",
|
||||
"(2..2)..",
|
||||
"..(2..2)",
|
||||
// Grammar restriction: comparison operators cannot be chained (1 < 2 == false).
|
||||
"((1 < 2) == false) as usize",
|
||||
// Grammar restriction: the value in let-else is not allowed to end in a
|
||||
// curly brace.
|
||||
"{ let _ = 1 + 1 else {}; }",
|
||||
|
@ -113,10 +123,6 @@ static EXPRS: &[&str] = &[
|
|||
"if let _ = () && (Struct {}).x {}",
|
||||
*/
|
||||
/*
|
||||
// FIXME: pretty-printer produces invalid syntax. `(1 < 2 == false) as usize`
|
||||
"((1 < 2) == false) as usize",
|
||||
*/
|
||||
/*
|
||||
// FIXME: pretty-printer produces invalid syntax. `for _ in 1..{ 2 } {}`
|
||||
"for _ in (1..{ 2 }) {}",
|
||||
*/
|
||||
|
|
29
tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.rs
Normal file
29
tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
//@ edition: 2021
|
||||
//@ build-fail
|
||||
|
||||
// Make sure we don't ICE when emitting the "lint" drop statement
|
||||
// used for tail_expr_drop_order.
|
||||
|
||||
#![deny(tail_expr_drop_order)]
|
||||
|
||||
struct Drop;
|
||||
impl std::ops::Drop for Drop {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
async fn func() -> Result<(), Drop> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn retry_db() -> Result<(), Drop> {
|
||||
loop {
|
||||
match func().await {
|
||||
//~^ ERROR relative drop order changing in Rust 2024
|
||||
//~| WARNING this changes meaning in Rust 2024
|
||||
Ok(()) => return Ok(()),
|
||||
Err(e) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,52 @@
|
|||
error: relative drop order changing in Rust 2024
|
||||
--> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:20:15
|
||||
|
|
||||
LL | match func().await {
|
||||
| ^^^^^^^-----
|
||||
| | |
|
||||
| | this value will be stored in a temporary; let us call it `#1`
|
||||
| | `#1` will be dropped later as of Edition 2024
|
||||
| this value will be stored in a temporary; let us call it `#2`
|
||||
| up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024
|
||||
...
|
||||
LL | Err(e) => {}
|
||||
| -
|
||||
| |
|
||||
| `e` calls a custom destructor
|
||||
| `e` will be dropped later as of Edition 2024
|
||||
LL | }
|
||||
LL | }
|
||||
| - now the temporary value is dropped here, before the local variables in the block or statement
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
|
||||
note: `#2` invokes this custom destructor
|
||||
--> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:10:1
|
||||
|
|
||||
LL | / impl std::ops::Drop for Drop {
|
||||
LL | | fn drop(&mut self) {}
|
||||
LL | | }
|
||||
| |_^
|
||||
note: `#1` invokes this custom destructor
|
||||
--> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:10:1
|
||||
|
|
||||
LL | / impl std::ops::Drop for Drop {
|
||||
LL | | fn drop(&mut self) {}
|
||||
LL | | }
|
||||
| |_^
|
||||
note: `e` invokes this custom destructor
|
||||
--> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:10:1
|
||||
|
|
||||
LL | / impl std::ops::Drop for Drop {
|
||||
LL | | fn drop(&mut self) {}
|
||||
LL | | }
|
||||
| |_^
|
||||
= note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
|
||||
note: the lint level is defined here
|
||||
--> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:7:9
|
||||
|
|
||||
LL | #![deny(tail_expr_drop_order)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
//@ run-rustfix
|
||||
#![allow(unused_must_use, dead_code)]
|
||||
struct S {
|
||||
field: (),
|
||||
}
|
||||
fn main() {
|
||||
let _ = [1, 2, 3].iter().map(|x| x); //~ ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `map`
|
||||
//~^ HELP you might have meant to write a method call
|
||||
}
|
||||
fn foo() {
|
||||
let baz = S {
|
||||
field: ()
|
||||
};
|
||||
let _ = baz.field; //~ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `field`
|
||||
//~^ HELP you might have meant to write a field
|
||||
}
|
||||
|
||||
fn bar() {
|
||||
[1, 2, 3].iter().map(|x| x); //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `map`
|
||||
//~^ HELP you might have meant to write a method call
|
||||
}
|
||||
fn baz() {
|
||||
let baz = S {
|
||||
field: ()
|
||||
};
|
||||
baz.field; //~ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `field`
|
||||
//~^ HELP you might have meant to write a field
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
//@ run-rustfix
|
||||
#![allow(unused_must_use, dead_code)]
|
||||
struct S {
|
||||
field: (),
|
||||
}
|
||||
fn main() {
|
||||
let _ = [1, 2, 3].iter()map(|x| x); //~ ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `map`
|
||||
//~^ HELP you might have meant to write a method call
|
||||
}
|
||||
fn foo() {
|
||||
let baz = S {
|
||||
field: ()
|
||||
};
|
||||
let _ = baz field; //~ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `field`
|
||||
//~^ HELP you might have meant to write a field
|
||||
}
|
||||
|
||||
fn bar() {
|
||||
[1, 2, 3].iter()map(|x| x); //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `map`
|
||||
//~^ HELP you might have meant to write a method call
|
||||
}
|
||||
fn baz() {
|
||||
let baz = S {
|
||||
field: ()
|
||||
};
|
||||
baz field; //~ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `field`
|
||||
//~^ HELP you might have meant to write a field
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
error: expected one of `.`, `;`, `?`, `else`, or an operator, found `map`
|
||||
--> $DIR/missing-dot-on-statement-expression.rs:7:29
|
||||
|
|
||||
LL | let _ = [1, 2, 3].iter()map(|x| x);
|
||||
| ^^^ expected one of `.`, `;`, `?`, `else`, or an operator
|
||||
|
|
||||
help: you might have meant to write a method call
|
||||
|
|
||||
LL | let _ = [1, 2, 3].iter().map(|x| x);
|
||||
| +
|
||||
|
||||
error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `field`
|
||||
--> $DIR/missing-dot-on-statement-expression.rs:14:17
|
||||
|
|
||||
LL | let _ = baz field;
|
||||
| ^^^^^ expected one of 8 possible tokens
|
||||
|
|
||||
help: you might have meant to write a field access
|
||||
|
|
||||
LL | let _ = baz.field;
|
||||
| +
|
||||
|
||||
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `map`
|
||||
--> $DIR/missing-dot-on-statement-expression.rs:19:21
|
||||
|
|
||||
LL | [1, 2, 3].iter()map(|x| x);
|
||||
| ^^^ expected one of `.`, `;`, `?`, `}`, or an operator
|
||||
|
|
||||
help: you might have meant to write a method call
|
||||
|
|
||||
LL | [1, 2, 3].iter().map(|x| x);
|
||||
| +
|
||||
|
||||
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `field`
|
||||
--> $DIR/missing-dot-on-statement-expression.rs:26:9
|
||||
|
|
||||
LL | baz field;
|
||||
| ^^^^^ expected one of 8 possible tokens
|
||||
|
|
||||
help: you might have meant to write a field access
|
||||
|
|
||||
LL | baz.field;
|
||||
| +
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
|
@ -3,6 +3,11 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found
|
|||
|
|
||||
LL | not rust;
|
||||
| ^^^^ expected one of 8 possible tokens
|
||||
|
|
||||
help: you might have meant to write a field access
|
||||
|
|
||||
LL | not.rust;
|
||||
| +
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue