Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a5e4dc9
Handle generic reborrow in expression-use adjustment walking
P8L1 May 28, 2026
640d7ae
Update task.rs
xmh0511 Jun 10, 2026
4671f48
Update wake.rs
xmh0511 Jun 10, 2026
4528827
Update wake.rs
xmh0511 Jun 10, 2026
61aa163
Update library/core/src/task/wake.rs
xmh0511 Jun 10, 2026
c5c5e81
Update wake.rs
xmh0511 Jun 10, 2026
e65db42
Update library/core/src/task/wake.rs
xmh0511 Jun 10, 2026
16ccf8e
Update library/alloc/src/task.rs
xmh0511 Jun 11, 2026
a0ecf25
Update library/core/src/task/wake.rs
xmh0511 Jun 11, 2026
0954d4c
Update wake.rs
xmh0511 Jun 12, 2026
42538ca
Update library/core/src/task/wake.rs
xmh0511 Jun 15, 2026
b8d7dcb
fix(thir): visit reborrow source expressions
kevin-valerio Jun 17, 2026
a487aec
Match all fields and removing `..`
kevin-valerio Jun 17, 2026
ef672ad
format reborrow visitor arm
kevin-valerio Jun 17, 2026
36f5b3f
Document transient connection errors from TcpListener::accept
valentynkit Jun 17, 2026
34d3eed
Document the file-descriptor-limit error from TcpListener::accept
valentynkit Jun 18, 2026
1447519
Document the out-of-memory error from TcpListener::accept
valentynkit Jun 18, 2026
dbf6d75
`RegionValues`: disable unnecessary range check
amandasystems Jun 17, 2026
ebea09f
renovate: Skip dashboard approval for GitHub Actions updates
Turbo87 Jun 18, 2026
cfadf6e
renovate: Enable monthly lock file maintenance
Turbo87 Jun 18, 2026
4e0bcfc
renovate: Extend `config:recommended` preset
Turbo87 Jun 18, 2026
5db91c4
renovate: Enable config migration PRs
Turbo87 Jun 18, 2026
fb55aa4
Rollup merge of #158026 - amandasystems:region-values-point-no-range-…
JonathanBrouwer Jun 18, 2026
5791600
Rollup merge of #156795 - P8L1:fix-generic-reborrow-expr-use-visitor,…
JonathanBrouwer Jun 18, 2026
2195c28
Rollup merge of #157694 - xmh0511:main, r=Darksonn
JonathanBrouwer Jun 18, 2026
ed586be
Rollup merge of #158034 - kevin-valerio:fix/issue-158033-reborrow-sou…
JonathanBrouwer Jun 18, 2026
b2090a9
Rollup merge of #158074 - valentynkt:docs/accept-transient-errors, r=…
JonathanBrouwer Jun 18, 2026
701e622
Rollup merge of #158086 - Turbo87:renovate-config, r=marcoieni
JonathanBrouwer Jun 18, 2026
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
15 changes: 13 additions & 2 deletions .github/renovate.json5
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended",
// Open a PR to migrate the config when Renovate deprecates syntax
":configMigration",
// Refresh lock files on the first day of each month
// (still gated by dashboard approval for now)
":maintainLockFilesMonthly",
// Pin GitHub Actions to their commit SHA digests, resolving floating tags
// (e.g. `v4`) to the full SemVer version (e.g. `v4.1.2`)
"helpers:pinGitHubActionDigestsToSemver"
],
// Let Renovatebot keep an opened issue that tracks our dependencies
"dependencyDashboard": true,
// Require manual approval from the Dependency Dashboard before opening PRs
"dependencyDashboardApproval": true,
"packageRules": [
{
// No dashboard approval necessary for GitHub Actions updates
"matchManagers": ["github-actions"],
"dependencyDashboardApproval": false
}
],
// Don't manage dependencies inside subtrees. They are updated upstream and
// synced in. See `src/doc/rustc-dev-guide/src/external-repos.md` for the list.
"ignorePaths": [
Expand Down
42 changes: 20 additions & 22 deletions compiler/rustc_borrowck/src/region_infer/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rustc_middle::bug;
use rustc_middle::mir::{BasicBlock, Location};
use rustc_middle::ty::{self, RegionVid};
use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
use tracing::debug;
use tracing::{debug, instrument};

use crate::BorrowIndex;
use crate::polonius::LiveLoans;
Expand Down Expand Up @@ -116,37 +116,43 @@ impl LivenessValues {
/// Records `region` as being live at the given `location`.
pub(crate) fn add_location(&mut self, region: RegionVid, location: Location) {
let point = self.location_map.point_from_location(location);
// This is a debug assert despite being cheap because it drops
// the current `point_in_range()` uses to 0 when debugging is off.
debug_assert!(
self.location_map.point_in_range(point),
"Tried inserting region {region:?} whose location {location:?} does not belong to this body!"
);
debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location);
match &mut self.live_regions {
LiveRegions::AtPoints(points) => {
points.insert(region, point);
}

LiveRegions::InBody(live_regions) if self.location_map.point_in_range(point) => {
LiveRegions::InBody(live_regions) => {
live_regions.insert(region);
}

LiveRegions::InBody(_) => (),
};
}

/// Records `region` as being live at all the given `points`.
pub(crate) fn add_points(&mut self, region: RegionVid, points: &IntervalSet<PointIndex>) {
debug_assert!(
points.iter().all(|point| self.location_map.point_in_range(point)),
"Tried inserting region {region:?} with some points not belonging to this body!"
);
debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points);
match &mut self.live_regions {
LiveRegions::AtPoints(these_points) => {
these_points.union_row(region, points);
}
LiveRegions::InBody(live_regions)
if points.iter().any(|point| self.location_map.point_in_range(point)) =>
{
LiveRegions::InBody(live_regions) => {
live_regions.insert(region);
}
LiveRegions::InBody(_) => (),
};
}

/// Records `region` as being live at all the control-flow points.
#[instrument(skip(self))]
pub(crate) fn add_all_points(&mut self, region: RegionVid) {
match &mut self.live_regions {
LiveRegions::AtPoints(points) => points.insert_all_into_row(region),
Expand All @@ -172,10 +178,7 @@ impl LivenessValues {

/// Returns an iterator of all the points where `region` is live.
fn live_points(&self, region: RegionVid) -> impl Iterator<Item = PointIndex> {
self.point_liveness(region)
.into_iter()
.flat_map(|set| set.iter())
.take_while(|&p| self.location_map.point_in_range(p))
self.point_liveness(region).into_iter().flat_map(|set| set.iter())
}

/// For debugging purposes, returns a pretty-printed string of the points where the `region` is
Expand Down Expand Up @@ -343,11 +346,10 @@ impl<'tcx, N: Idx> RegionValues<'tcx, N> {

/// Returns the locations contained within a given region `r`.
pub(crate) fn locations_outlived_by(&self, r: N) -> impl Iterator<Item = Location> {
self.points.row(r).into_iter().flat_map(move |set| {
set.iter()
.take_while(move |&p| self.location_map.point_in_range(p))
.map(move |p| self.location_map.to_location(p))
})
self.points
.row(r)
.into_iter()
.flat_map(move |set| set.iter().map(move |p| self.location_map.to_location(p)))
}

/// Returns just the universal regions that are contained in a given region's value.
Expand Down Expand Up @@ -413,11 +415,7 @@ pub(crate) fn pretty_print_points(
points: impl IntoIterator<Item = PointIndex>,
) -> String {
pretty_print_region_elements(
points
.into_iter()
.take_while(|&p| location_map.point_in_range(p))
.map(|p| location_map.to_location(p))
.map(RegionElement::Location),
points.into_iter().map(|p| location_map.to_location(p)).map(RegionElement::Location),
)
}

Expand Down
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
7 changes: 6 additions & 1 deletion compiler/rustc_mir_dataflow/src/points.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ impl DenseLocationMap {
for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb));
}

// Invariant: no block is preceded by more than all statements.
debug_assert!(*statements_before_block.iter().max().unwrap() < num_points);
Self { statements_before_block, basic_blocks, num_points }
}

Expand All @@ -42,10 +43,14 @@ impl DenseLocationMap {
}

/// Converts a `Location` into a `PointIndex`. O(1).
/// [[`Self::point_in_range()`]] guaranteed for the returned index.
#[inline]
pub fn point_from_location(&self, location: Location) -> PointIndex {
let Location { block, statement_index } = location;
let start_index = self.statements_before_block[block];
// Note the invariant in [`Self::new()`]; if the indexing
// operation above did not panic then this holds by construction.
debug_assert!(start_index < self.num_points);
PointIndex::new(start_index + statement_index)
}

Expand Down
4 changes: 4 additions & 0 deletions library/alloc/src/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ use crate::sync::Arc;
/// link ../../std/task/struct.Waker.html#impl-From%3CArc%3CW,+Global%3E%3E-for-Waker
/// without getting a link-checking error in CI. -->
///
/// # Memory Ordering
///
/// To avoid missed wakeups, all executors must adhere to the requirement described for [`Waker::wake`].
///
/// # Examples
///
/// A basic `block_on` function that takes a future and runs it to completion on
Expand Down
13 changes: 7 additions & 6 deletions library/core/src/task/wake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,15 +418,16 @@ unsafe impl Sync for Waker {}
impl Waker {
/// Wakes up the task associated with this `Waker`.
///
/// As long as the executor keeps running and the task is not finished, it is
/// guaranteed that each invocation of [`wake()`](Self::wake) (or
/// As long as the executor keeps running and the task is not finished,
/// it is guaranteed that each invocation of [`wake()`](Self::wake) (or
/// [`wake_by_ref()`](Self::wake_by_ref)) will be followed by at least one
/// [`poll()`] of the task to which this `Waker` belongs. This makes
/// it possible to temporarily yield to other tasks while running potentially
/// unbounded processing loops.
/// [`poll()`] of the task to which this `Waker` belongs, such that the call to
/// [`wake()`](Self::wake) (or [`wake_by_ref()`](Self::wake_by_ref)) _happens-before_
/// the beginning of the invocation of [`poll()`]. This makes it possible to temporarily
/// yield to other tasks while running potentially unbounded processing loops.
///
/// Note that the above implies that multiple wake-ups may be coalesced into a
/// single [`poll()`] invocation by the runtime.
/// single [`poll()`] invocation by the executor.
///
/// Also note that yielding to competing tasks is not guaranteed: it is the
/// executor’s choice which task to run and the executor may choose to run the
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