Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions compiler/rustc_hir_typeck/src/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(_) => {
Expand All @@ -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)?;
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_middle/src/thir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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])
}
}
}

Expand Down
33 changes: 33 additions & 0 deletions library/std/src/net/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
34 changes: 34 additions & 0 deletions tests/ui/reborrow/generic-reborrow-expr-use-visitor-closure.rs
Original file line number Diff line number Diff line change
@@ -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<CustomRef<'a, T>> 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();
}
32 changes: 32 additions & 0 deletions tests/ui/reborrow/generic-reborrow-expr-use-visitor.rs
Original file line number Diff line number Diff line change
@@ -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<CustomRef<'a, T>> 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);
}
28 changes: 28 additions & 0 deletions tests/ui/reborrow/reborrow-source-unsafety.rs
Original file line number Diff line number Diff line change
@@ -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
});
}
11 changes: 11 additions & 0 deletions tests/ui/reborrow/reborrow-source-unsafety.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Loading