diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index a924a81f89b0d..7b39b953e3be0 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -727,7 +727,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let typeck_results = self.cx.typeck_results(); let adjustments = typeck_results.expr_adjustments(expr); let mut place_with_id = self.cat_expr_unadjusted(expr)?; - for adjustment in adjustments { + for (adjustment_index, adjustment) in adjustments.iter().enumerate() { + let is_last_adjustment = adjustment_index + 1 == adjustments.len(); debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); match adjustment.kind { adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => { @@ -752,13 +753,13 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx self.walk_autoref(expr, &place_with_id, autoref); } - adjustment::Adjust::GenericReborrow(_reborrow) => { - // To build an expression as a place expression, it needs to be a field - // projection or deref at the outmost layer. So it is field projection or deref - // on an adjusted value. But this means that adjustment is applied on a - // subexpression that is not the final operand/rvalue for function call or - // assignment. This is a contradiction. - unreachable!("Reborrow trait usage during adjustment walk"); + adjustment::Adjust::GenericReborrow(mutability) if is_last_adjustment => { + let bk = ty::BorrowKind::from_mutbl(mutability); + self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk); + } + + adjustment::Adjust::GenericReborrow(_) => { + span_bug!(expr.span, "generic reborrow adjustment must be terminal"); } } place_with_id = self.cat_expr_adjusted(expr, place_with_id, adjustment)?; diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index a96f4e9457cb0..24aa4ac513d45 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -187,7 +187,9 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( } ThreadLocalRef(_) => {} Yield { value } => visitor.visit_expr(&visitor.thir()[value]), - Reborrow { .. } => {} + Reborrow { source, mutability: _, target: _ } => { + visitor.visit_expr(&visitor.thir()[source]) + } } } diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 2e8779e05ca76..b673abdff7ba1 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -876,6 +876,29 @@ impl TcpListener { /// is established. When established, the corresponding [`TcpStream`] and the /// remote peer's address will be returned. /// + /// # Errors + /// + /// Some errors this function returns do not indicate a problem with the + /// listener itself, and a program serving a long-lived listener will + /// usually want to handle them and keep accepting connections rather than + /// treat them as fatal. These include, but are not limited to: + /// + /// - An error specific to a single incoming connection that failed before + /// it could be accepted, such as one aborted by the peer + /// ([`ConnectionAborted`]). A later call may succeed immediately. + /// - An error from reaching the per-process or system-wide open file + /// descriptor limit. The call can be retried once other file descriptors + /// have been closed, typically after a short delay. + /// - An error from failing to allocate memory while accepting a connection + /// ([`OutOfMemory`]). + /// + /// Which errors can occur is platform-specific. On Unix, [`Interrupted`] + /// errors are retried internally rather than being returned. + /// + /// [`ConnectionAborted`]: io::ErrorKind::ConnectionAborted + /// [`OutOfMemory`]: io::ErrorKind::OutOfMemory + /// [`Interrupted`]: io::ErrorKind::Interrupted + /// /// # Examples /// /// ```no_run @@ -902,6 +925,11 @@ impl TcpListener { /// the peer's [`SocketAddr`] structure. Iterating over it is equivalent to /// calling [`TcpListener::accept`] in a loop. /// + /// # Errors + /// + /// Each connection yielded by the iterator can fail for the same reasons as + /// [`TcpListener::accept`]; see its documentation for details. + /// /// # Examples /// /// ```no_run @@ -937,6 +965,11 @@ impl TcpListener { /// the peer's [`SocketAddr`] structure. Iterating over it is equivalent to /// calling [`TcpListener::accept`] in a loop. /// + /// # Errors + /// + /// Each connection yielded by the iterator can fail for the same reasons as + /// [`TcpListener::accept`]; see its documentation for details. + /// /// # Examples /// /// ```no_run diff --git a/tests/ui/reborrow/generic-reborrow-expr-use-visitor-closure.rs b/tests/ui/reborrow/generic-reborrow-expr-use-visitor-closure.rs new file mode 100644 index 0000000000000..c28cb1ef4fda4 --- /dev/null +++ b/tests/ui/reborrow/generic-reborrow-expr-use-visitor-closure.rs @@ -0,0 +1,34 @@ +//@ check-pass + +#![feature(reborrow)] + +use std::marker::{CoerceShared, Reborrow}; + +#[allow(unused)] +struct CustomMut<'a, T>(&'a mut T); +impl<'a, T> Reborrow for CustomMut<'a, T> {} +impl<'a, T> CoerceShared> for CustomMut<'a, T> {} + +#[allow(unused)] +struct CustomRef<'a, T>(&'a T); +impl<'a, T> Clone for CustomRef<'a, T> { + fn clone(&self) -> Self { + Self(self.0) + } +} +impl<'a, T> Copy for CustomRef<'a, T> {} + +fn takes_mut(_: CustomMut<'_, ()>) {} +fn takes_shared(_: CustomRef<'_, ()>) {} + +fn main() { + let a = CustomMut(&mut ()); + + let mut f = || { + takes_mut(a); + takes_shared(a); + }; + + f(); + f(); +} diff --git a/tests/ui/reborrow/generic-reborrow-expr-use-visitor.rs b/tests/ui/reborrow/generic-reborrow-expr-use-visitor.rs new file mode 100644 index 0000000000000..d513577e901a0 --- /dev/null +++ b/tests/ui/reborrow/generic-reborrow-expr-use-visitor.rs @@ -0,0 +1,32 @@ +//@ check-pass + +#![feature(reborrow)] + +use std::marker::{CoerceShared, Reborrow}; + +#[allow(unused)] +struct CustomMut<'a, T>(&'a mut T); +impl<'a, T> Reborrow for CustomMut<'a, T> {} +impl<'a, T> CoerceShared> for CustomMut<'a, T> {} + +#[allow(unused)] +struct CustomRef<'a, T>(&'a T); +impl<'a, T> Clone for CustomRef<'a, T> { + fn clone(&self) -> Self { + Self(self.0) + } +} +impl<'a, T> Copy for CustomRef<'a, T> {} + +fn takes_mut(_: CustomMut<'_, ()>) {} +fn takes_shared(_: CustomRef<'_, ()>) {} + +fn main() { + let a = CustomMut(&mut ()); + + takes_mut(a); + takes_mut(a); + + takes_shared(a); + takes_shared(a); +} diff --git a/tests/ui/reborrow/reborrow-source-unsafety.rs b/tests/ui/reborrow/reborrow-source-unsafety.rs new file mode 100644 index 0000000000000..e6f3540768a44 --- /dev/null +++ b/tests/ui/reborrow/reborrow-source-unsafety.rs @@ -0,0 +1,28 @@ +// Regression test for rust-lang/rust#158033. + +#![feature(reborrow)] +#![allow(dead_code)] +#![deny(unsafe_code)] + +use std::marker::Reborrow; + +struct Thing<'a> { + field: &'a mut usize, +} + +impl<'a> Reborrow for Thing<'a> {} + +fn takes(_: Thing<'_>) {} + +fn main() { + let mut x = 0; + let thing = Thing { field: &mut x }; + let y = 123usize; + + takes({ + let p: *const usize = &y; + std::hint::black_box(std::ptr::read(p)); + //~^ ERROR call to unsafe function `std::ptr::read` is unsafe + thing + }); +} diff --git a/tests/ui/reborrow/reborrow-source-unsafety.stderr b/tests/ui/reborrow/reborrow-source-unsafety.stderr new file mode 100644 index 0000000000000..431893a4d0ced --- /dev/null +++ b/tests/ui/reborrow/reborrow-source-unsafety.stderr @@ -0,0 +1,11 @@ +error[E0133]: call to unsafe function `std::ptr::read` is unsafe and requires unsafe function or block + --> $DIR/reborrow-source-unsafety.rs:24:30 + | +LL | std::hint::black_box(std::ptr::read(p)); + | ^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0133`.