Skip to content

Commit

Permalink
Auto merge of rust-lang#135682 - matthiaskrgr:rollup-cl7zlt1, r=matth…
Browse files Browse the repository at this point in the history
…iaskrgr

Rollup of 7 pull requests

Successful merges:

 - rust-lang#133700 (const-eval: detect more pointers as definitely not-null)
 - rust-lang#135290 (Encode constraints that hold at all points as logical edges in location-sensitive polonius)
 - rust-lang#135478 (Run clippy for rustc_codegen_gcc on CI)
 - rust-lang#135583 (Move `std::pipe::*` into `std::io`)
 - rust-lang#135612 (Include x scripts in tarballs)
 - rust-lang#135624 (ci: mirror buildkit image to ghcr)
 - rust-lang#135661 (Stabilize `float_next_up_down`)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Jan 18, 2025
2 parents efc2576 + 23fb4f2 commit 0493557
Show file tree
Hide file tree
Showing 25 changed files with 444 additions and 377 deletions.
23 changes: 17 additions & 6 deletions .github/workflows/ghcr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,21 @@ jobs:

- name: Mirror DockerHub
run: |
# DockerHub image we want to mirror
image="ubuntu:22.04"
# List of DockerHub images to mirror to ghcr.io
images=(
# Mirrored because used by the mingw-check-tidy, which doesn't cache Docker images
"ubuntu:22.04"
# Mirrored because used by all linux CI jobs, including mingw-check-tidy
"moby/buildkit:buildx-stable-1"
)
# Mirror image from DockerHub to ghcr.io
./crane copy \
docker.io/${image} \
ghcr.io/${{ github.repository_owner }}/${image}
# Mirror each image from DockerHub to ghcr.io
for img in "${images[@]}"; do
echo "Mirroring ${img}..."
# Remove namespace from the image if any.
# E.g. "moby/buildkit:buildx-stable-1" becomes "buildkit:buildx-stable-1"
dest_image=$(echo "${img}" | cut -d'/' -f2-)
./crane copy \
"docker.io/${img}" \
"ghcr.io/${{ github.repository_owner }}/${dest_image}"
done
83 changes: 60 additions & 23 deletions compiler/rustc_borrowck/src/polonius/loan_liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,21 @@ use rustc_middle::ty::{RegionVid, TyCtxt};
use rustc_mir_dataflow::points::PointIndex;

use super::{LiveLoans, LocalizedOutlivesConstraintSet};
use crate::constraints::OutlivesConstraint;
use crate::dataflow::BorrowIndex;
use crate::region_infer::values::LivenessValues;
use crate::type_check::Locations;
use crate::{BorrowSet, PlaceConflictBias, places_conflict};

/// With the full graph of constraints, we can compute loan reachability, stop at kills, and trace
/// loan liveness throughout the CFG.
/// Compute loan reachability, stop at kills, and trace loan liveness throughout the CFG, by
/// traversing the full graph of constraints that combines:
/// - the localized constraints (the physical edges),
/// - with the constraints that hold at all points (the logical edges).
pub(super) fn compute_loan_liveness<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
liveness: &LivenessValues,
outlives_constraints: impl Iterator<Item = OutlivesConstraint<'tcx>>,
borrow_set: &BorrowSet<'tcx>,
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
) -> LiveLoans {
Expand All @@ -29,7 +34,11 @@ pub(super) fn compute_loan_liveness<'tcx>(
// edges when visualizing the constraint graph anyways.
let kills = collect_kills(body, tcx, borrow_set);

let graph = index_constraints(&localized_outlives_constraints);
// Create the full graph with the physical edges we've localized earlier, and the logical edges
// of constraints that hold at all points.
let logical_constraints =
outlives_constraints.filter(|c| matches!(c.locations, Locations::All(_)));
let graph = LocalizedConstraintGraph::new(&localized_outlives_constraints, logical_constraints);
let mut visited = FxHashSet::default();
let mut stack = Vec::new();

Expand Down Expand Up @@ -108,7 +117,7 @@ pub(super) fn compute_loan_liveness<'tcx>(
let is_loan_killed =
kills.get(&current_location).is_some_and(|kills| kills.contains(&loan_idx));

for succ in outgoing_edges(&graph, node) {
for succ in graph.outgoing_edges(node) {
// If the loan is killed at this point, it is killed _on exit_. But only during
// forward traversal.
if is_loan_killed {
Expand All @@ -125,9 +134,17 @@ pub(super) fn compute_loan_liveness<'tcx>(
live_loans
}

/// The localized constraint graph is currently the per-node map of its physical edges. In the
/// future, we'll add logical edges to model constraints that hold at all points in the CFG.
type LocalizedConstraintGraph = FxHashMap<LocalizedNode, FxIndexSet<LocalizedNode>>;
/// The localized constraint graph indexes the physical and logical edges to compute a given node's
/// successors during traversal.
struct LocalizedConstraintGraph {
/// The actual, physical, edges we have recorded for a given node.
edges: FxHashMap<LocalizedNode, FxIndexSet<LocalizedNode>>,

/// The logical edges representing the outlives constraints that hold at all points in the CFG,
/// which we don't localize to avoid creating a lot of unnecessary edges in the graph. Some CFGs
/// can be big, and we don't need to create such a physical edge for every point in the CFG.
logical_edges: FxHashMap<RegionVid, FxIndexSet<RegionVid>>,
}

/// A node in the graph to be traversed, one of the two vertices of a localized outlives constraint.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
Expand All @@ -136,24 +153,44 @@ struct LocalizedNode {
point: PointIndex,
}

/// Traverses the constraints and returns the indexable graph of edges per node.
fn index_constraints(constraints: &LocalizedOutlivesConstraintSet) -> LocalizedConstraintGraph {
let mut edges = LocalizedConstraintGraph::default();
for constraint in &constraints.outlives {
let source = LocalizedNode { region: constraint.source, point: constraint.from };
let target = LocalizedNode { region: constraint.target, point: constraint.to };
edges.entry(source).or_default().insert(target);
}
impl LocalizedConstraintGraph {
/// Traverses the constraints and returns the indexed graph of edges per node.
fn new<'tcx>(
constraints: &LocalizedOutlivesConstraintSet,
logical_constraints: impl Iterator<Item = OutlivesConstraint<'tcx>>,
) -> Self {
let mut edges: FxHashMap<_, FxIndexSet<_>> = FxHashMap::default();
for constraint in &constraints.outlives {
let source = LocalizedNode { region: constraint.source, point: constraint.from };
let target = LocalizedNode { region: constraint.target, point: constraint.to };
edges.entry(source).or_default().insert(target);
}

edges
}
let mut logical_edges: FxHashMap<_, FxIndexSet<_>> = FxHashMap::default();
for constraint in logical_constraints {
logical_edges.entry(constraint.sup).or_default().insert(constraint.sub);
}

LocalizedConstraintGraph { edges, logical_edges }
}

/// Returns the outgoing edges of a given node, not its transitive closure.
fn outgoing_edges(
graph: &LocalizedConstraintGraph,
node: LocalizedNode,
) -> impl Iterator<Item = LocalizedNode> + use<'_> {
graph.get(&node).into_iter().flat_map(|edges| edges.iter().copied())
/// Returns the outgoing edges of a given node, not its transitive closure.
fn outgoing_edges(&self, node: LocalizedNode) -> impl Iterator<Item = LocalizedNode> + use<'_> {
// The outgoing edges are:
// - the physical edges present at this node,
// - the materialized logical edges that exist virtually at all points for this node's
// region, localized at this point.
let physical_edges =
self.edges.get(&node).into_iter().flat_map(|targets| targets.iter().copied());
let materialized_edges =
self.logical_edges.get(&node.region).into_iter().flat_map(move |targets| {
targets
.iter()
.copied()
.map(move |target| LocalizedNode { point: node.point, region: target })
});
physical_edges.chain(materialized_edges)
}
}

/// Traverses the MIR and collects kills.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_borrowck/src/polonius/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ impl PoloniusContext {
tcx,
body,
regioncx.liveness_constraints(),
regioncx.outlives_constraints(),
borrow_set,
&localized_outlives_constraints,
);
Expand Down
22 changes: 5 additions & 17 deletions compiler/rustc_borrowck/src/polonius/typeck_constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,11 @@ pub(super) fn convert_typeck_constraints<'tcx>(
for outlives_constraint in outlives_constraints {
match outlives_constraint.locations {
Locations::All(_) => {
// For now, turn logical constraints holding at all points into physical edges at
// every point in the graph.
// FIXME: encode this into *traversal* instead.
for (block, bb) in body.basic_blocks.iter_enumerated() {
let statement_count = bb.statements.len();
for statement_index in 0..=statement_count {
let current_location = Location { block, statement_index };
let current_point = liveness.point_from_location(current_location);

localized_outlives_constraints.push(LocalizedOutlivesConstraint {
source: outlives_constraint.sup,
from: current_point,
target: outlives_constraint.sub,
to: current_point,
});
}
}
// We don't turn constraints holding at all points into physical edges at every
// point in the graph. They are encoded into *traversal* instead: a given node's
// successors will combine these logical edges with the regular, physical, localized
// edges.
continue;
}

Locations::Single(location) => {
Expand Down
25 changes: 17 additions & 8 deletions compiler/rustc_const_eval/src/interpret/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1481,22 +1481,31 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// Test if this value might be null.
/// If the machine does not support ptr-to-int casts, this is conservative.
pub fn scalar_may_be_null(&self, scalar: Scalar<M::Provenance>) -> InterpResult<'tcx, bool> {
interp_ok(match scalar.try_to_scalar_int() {
Ok(int) => int.is_null(),
match scalar.try_to_scalar_int() {
Ok(int) => interp_ok(int.is_null()),
Err(_) => {
// Can only happen during CTFE.
// We can't cast this pointer to an integer. Can only happen during CTFE.
let ptr = scalar.to_pointer(self)?;
match self.ptr_try_get_alloc_id(ptr, 0) {
Ok((alloc_id, offset, _)) => {
let size = self.get_alloc_info(alloc_id).size;
// If the pointer is out-of-bounds, it may be null.
// Note that one-past-the-end (offset == size) is still inbounds, and never null.
offset > size
let info = self.get_alloc_info(alloc_id);
// If the pointer is in-bounds (including "at the end"), it is definitely not null.
if offset <= info.size {
return interp_ok(false);
}
// If the allocation is N-aligned, and the offset is not divisible by N,
// then `base + offset` has a non-zero remainder after division by `N`,
// which means `base + offset` cannot be null.
if offset.bytes() % info.align.bytes() != 0 {
return interp_ok(false);
}
// We don't know enough, this might be null.
interp_ok(true)
}
Err(_offset) => bug!("a non-int scalar is always a pointer"),
}
}
})
}
}

/// Turning a "maybe pointer" into a proper pointer (and some information
Expand Down
10 changes: 6 additions & 4 deletions library/core/src/num/f128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,6 @@ impl f128 {
///
/// ```rust
/// #![feature(f128)]
/// #![feature(float_next_up_down)]
/// # // FIXME(f16_f128): remove when `eqtf2` is available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
///
Expand All @@ -516,13 +515,15 @@ impl f128 {
/// # }
/// ```
///
/// This operation corresponds to IEEE-754 `nextUp`.
///
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
/// [`INFINITY`]: Self::INFINITY
/// [`MIN`]: Self::MIN
/// [`MAX`]: Self::MAX
#[inline]
#[doc(alias = "nextUp")]
#[unstable(feature = "f128", issue = "116909")]
// #[unstable(feature = "float_next_up_down", issue = "91399")]
pub const fn next_up(self) -> Self {
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
// denormals to zero. This is in general unsound and unsupported, but here
Expand Down Expand Up @@ -558,7 +559,6 @@ impl f128 {
///
/// ```rust
/// #![feature(f128)]
/// #![feature(float_next_up_down)]
/// # // FIXME(f16_f128): remove when `eqtf2` is available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
///
Expand All @@ -570,13 +570,15 @@ impl f128 {
/// # }
/// ```
///
/// This operation corresponds to IEEE-754 `nextDown`.
///
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
/// [`INFINITY`]: Self::INFINITY
/// [`MIN`]: Self::MIN
/// [`MAX`]: Self::MAX
#[inline]
#[doc(alias = "nextDown")]
#[unstable(feature = "f128", issue = "116909")]
// #[unstable(feature = "float_next_up_down", issue = "91399")]
pub const fn next_down(self) -> Self {
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
// denormals to zero. This is in general unsound and unsupported, but here
Expand Down
10 changes: 6 additions & 4 deletions library/core/src/num/f16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,6 @@ impl f16 {
///
/// ```rust
/// #![feature(f16)]
/// #![feature(float_next_up_down)]
/// # // FIXME(f16_f128): ABI issues on MSVC
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
///
Expand All @@ -509,13 +508,15 @@ impl f16 {
/// # }
/// ```
///
/// This operation corresponds to IEEE-754 `nextUp`.
///
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
/// [`INFINITY`]: Self::INFINITY
/// [`MIN`]: Self::MIN
/// [`MAX`]: Self::MAX
#[inline]
#[doc(alias = "nextUp")]
#[unstable(feature = "f16", issue = "116909")]
// #[unstable(feature = "float_next_up_down", issue = "91399")]
pub const fn next_up(self) -> Self {
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
// denormals to zero. This is in general unsound and unsupported, but here
Expand Down Expand Up @@ -551,7 +552,6 @@ impl f16 {
///
/// ```rust
/// #![feature(f16)]
/// #![feature(float_next_up_down)]
/// # // FIXME(f16_f128): ABI issues on MSVC
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
///
Expand All @@ -563,13 +563,15 @@ impl f16 {
/// # }
/// ```
///
/// This operation corresponds to IEEE-754 `nextDown`.
///
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
/// [`INFINITY`]: Self::INFINITY
/// [`MIN`]: Self::MIN
/// [`MAX`]: Self::MAX
#[inline]
#[doc(alias = "nextDown")]
#[unstable(feature = "f16", issue = "116909")]
// #[unstable(feature = "float_next_up_down", issue = "91399")]
pub const fn next_down(self) -> Self {
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
// denormals to zero. This is in general unsound and unsupported, but here
Expand Down
14 changes: 10 additions & 4 deletions library/core/src/num/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -726,20 +726,23 @@ impl f32 {
/// is finite `x == x.next_up().next_down()` also holds.
///
/// ```rust
/// #![feature(float_next_up_down)]
/// // f32::EPSILON is the difference between 1.0 and the next number up.
/// assert_eq!(1.0f32.next_up(), 1.0 + f32::EPSILON);
/// // But not for most numbers.
/// assert!(0.1f32.next_up() < 0.1 + f32::EPSILON);
/// assert_eq!(16777216f32.next_up(), 16777218.0);
/// ```
///
/// This operation corresponds to IEEE-754 `nextUp`.
///
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
/// [`INFINITY`]: Self::INFINITY
/// [`MIN`]: Self::MIN
/// [`MAX`]: Self::MAX
#[inline]
#[unstable(feature = "float_next_up_down", issue = "91399")]
#[doc(alias = "nextUp")]
#[stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")]
pub const fn next_up(self) -> Self {
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
// denormals to zero. This is in general unsound and unsupported, but here
Expand Down Expand Up @@ -774,20 +777,23 @@ impl f32 {
/// is finite `x == x.next_down().next_up()` also holds.
///
/// ```rust
/// #![feature(float_next_up_down)]
/// let x = 1.0f32;
/// // Clamp value into range [0, 1).
/// let clamped = x.clamp(0.0, 1.0f32.next_down());
/// assert!(clamped < 1.0);
/// assert_eq!(clamped.next_up(), 1.0);
/// ```
///
/// This operation corresponds to IEEE-754 `nextDown`.
///
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
/// [`INFINITY`]: Self::INFINITY
/// [`MIN`]: Self::MIN
/// [`MAX`]: Self::MAX
#[inline]
#[unstable(feature = "float_next_up_down", issue = "91399")]
#[doc(alias = "nextDown")]
#[stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")]
pub const fn next_down(self) -> Self {
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
// denormals to zero. This is in general unsound and unsupported, but here
Expand Down
Loading

0 comments on commit 0493557

Please sign in to comment.