Skip to content

Commit 0493557

Browse files
committed
Auto merge of rust-lang#135682 - matthiaskrgr:rollup-cl7zlt1, r=matthiaskrgr
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
2 parents efc2576 + 23fb4f2 commit 0493557

File tree

25 files changed

+444
-377
lines changed

25 files changed

+444
-377
lines changed

.github/workflows/ghcr.yml

+17-6
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,21 @@ jobs:
4848

4949
- name: Mirror DockerHub
5050
run: |
51-
# DockerHub image we want to mirror
52-
image="ubuntu:22.04"
51+
# List of DockerHub images to mirror to ghcr.io
52+
images=(
53+
# Mirrored because used by the mingw-check-tidy, which doesn't cache Docker images
54+
"ubuntu:22.04"
55+
# Mirrored because used by all linux CI jobs, including mingw-check-tidy
56+
"moby/buildkit:buildx-stable-1"
57+
)
5358
54-
# Mirror image from DockerHub to ghcr.io
55-
./crane copy \
56-
docker.io/${image} \
57-
ghcr.io/${{ github.repository_owner }}/${image}
59+
# Mirror each image from DockerHub to ghcr.io
60+
for img in "${images[@]}"; do
61+
echo "Mirroring ${img}..."
62+
# Remove namespace from the image if any.
63+
# E.g. "moby/buildkit:buildx-stable-1" becomes "buildkit:buildx-stable-1"
64+
dest_image=$(echo "${img}" | cut -d'/' -f2-)
65+
./crane copy \
66+
"docker.io/${img}" \
67+
"ghcr.io/${{ github.repository_owner }}/${dest_image}"
68+
done

compiler/rustc_borrowck/src/polonius/loan_liveness.rs

+60-23
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,21 @@ use rustc_middle::ty::{RegionVid, TyCtxt};
99
use rustc_mir_dataflow::points::PointIndex;
1010

1111
use super::{LiveLoans, LocalizedOutlivesConstraintSet};
12+
use crate::constraints::OutlivesConstraint;
1213
use crate::dataflow::BorrowIndex;
1314
use crate::region_infer::values::LivenessValues;
15+
use crate::type_check::Locations;
1416
use crate::{BorrowSet, PlaceConflictBias, places_conflict};
1517

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

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

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

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

128-
/// The localized constraint graph is currently the per-node map of its physical edges. In the
129-
/// future, we'll add logical edges to model constraints that hold at all points in the CFG.
130-
type LocalizedConstraintGraph = FxHashMap<LocalizedNode, FxIndexSet<LocalizedNode>>;
137+
/// The localized constraint graph indexes the physical and logical edges to compute a given node's
138+
/// successors during traversal.
139+
struct LocalizedConstraintGraph {
140+
/// The actual, physical, edges we have recorded for a given node.
141+
edges: FxHashMap<LocalizedNode, FxIndexSet<LocalizedNode>>,
142+
143+
/// The logical edges representing the outlives constraints that hold at all points in the CFG,
144+
/// which we don't localize to avoid creating a lot of unnecessary edges in the graph. Some CFGs
145+
/// can be big, and we don't need to create such a physical edge for every point in the CFG.
146+
logical_edges: FxHashMap<RegionVid, FxIndexSet<RegionVid>>,
147+
}
131148

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

139-
/// Traverses the constraints and returns the indexable graph of edges per node.
140-
fn index_constraints(constraints: &LocalizedOutlivesConstraintSet) -> LocalizedConstraintGraph {
141-
let mut edges = LocalizedConstraintGraph::default();
142-
for constraint in &constraints.outlives {
143-
let source = LocalizedNode { region: constraint.source, point: constraint.from };
144-
let target = LocalizedNode { region: constraint.target, point: constraint.to };
145-
edges.entry(source).or_default().insert(target);
146-
}
156+
impl LocalizedConstraintGraph {
157+
/// Traverses the constraints and returns the indexed graph of edges per node.
158+
fn new<'tcx>(
159+
constraints: &LocalizedOutlivesConstraintSet,
160+
logical_constraints: impl Iterator<Item = OutlivesConstraint<'tcx>>,
161+
) -> Self {
162+
let mut edges: FxHashMap<_, FxIndexSet<_>> = FxHashMap::default();
163+
for constraint in &constraints.outlives {
164+
let source = LocalizedNode { region: constraint.source, point: constraint.from };
165+
let target = LocalizedNode { region: constraint.target, point: constraint.to };
166+
edges.entry(source).or_default().insert(target);
167+
}
147168

148-
edges
149-
}
169+
let mut logical_edges: FxHashMap<_, FxIndexSet<_>> = FxHashMap::default();
170+
for constraint in logical_constraints {
171+
logical_edges.entry(constraint.sup).or_default().insert(constraint.sub);
172+
}
173+
174+
LocalizedConstraintGraph { edges, logical_edges }
175+
}
150176

151-
/// Returns the outgoing edges of a given node, not its transitive closure.
152-
fn outgoing_edges(
153-
graph: &LocalizedConstraintGraph,
154-
node: LocalizedNode,
155-
) -> impl Iterator<Item = LocalizedNode> + use<'_> {
156-
graph.get(&node).into_iter().flat_map(|edges| edges.iter().copied())
177+
/// Returns the outgoing edges of a given node, not its transitive closure.
178+
fn outgoing_edges(&self, node: LocalizedNode) -> impl Iterator<Item = LocalizedNode> + use<'_> {
179+
// The outgoing edges are:
180+
// - the physical edges present at this node,
181+
// - the materialized logical edges that exist virtually at all points for this node's
182+
// region, localized at this point.
183+
let physical_edges =
184+
self.edges.get(&node).into_iter().flat_map(|targets| targets.iter().copied());
185+
let materialized_edges =
186+
self.logical_edges.get(&node.region).into_iter().flat_map(move |targets| {
187+
targets
188+
.iter()
189+
.copied()
190+
.map(move |target| LocalizedNode { point: node.point, region: target })
191+
});
192+
physical_edges.chain(materialized_edges)
193+
}
157194
}
158195

159196
/// Traverses the MIR and collects kills.

compiler/rustc_borrowck/src/polonius/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ impl PoloniusContext {
130130
tcx,
131131
body,
132132
regioncx.liveness_constraints(),
133+
regioncx.outlives_constraints(),
133134
borrow_set,
134135
&localized_outlives_constraints,
135136
);

compiler/rustc_borrowck/src/polonius/typeck_constraints.rs

+5-17
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,11 @@ pub(super) fn convert_typeck_constraints<'tcx>(
2222
for outlives_constraint in outlives_constraints {
2323
match outlives_constraint.locations {
2424
Locations::All(_) => {
25-
// For now, turn logical constraints holding at all points into physical edges at
26-
// every point in the graph.
27-
// FIXME: encode this into *traversal* instead.
28-
for (block, bb) in body.basic_blocks.iter_enumerated() {
29-
let statement_count = bb.statements.len();
30-
for statement_index in 0..=statement_count {
31-
let current_location = Location { block, statement_index };
32-
let current_point = liveness.point_from_location(current_location);
33-
34-
localized_outlives_constraints.push(LocalizedOutlivesConstraint {
35-
source: outlives_constraint.sup,
36-
from: current_point,
37-
target: outlives_constraint.sub,
38-
to: current_point,
39-
});
40-
}
41-
}
25+
// We don't turn constraints holding at all points into physical edges at every
26+
// point in the graph. They are encoded into *traversal* instead: a given node's
27+
// successors will combine these logical edges with the regular, physical, localized
28+
// edges.
29+
continue;
4230
}
4331

4432
Locations::Single(location) => {

compiler/rustc_const_eval/src/interpret/memory.rs

+17-8
Original file line numberDiff line numberDiff line change
@@ -1481,22 +1481,31 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
14811481
/// Test if this value might be null.
14821482
/// If the machine does not support ptr-to-int casts, this is conservative.
14831483
pub fn scalar_may_be_null(&self, scalar: Scalar<M::Provenance>) -> InterpResult<'tcx, bool> {
1484-
interp_ok(match scalar.try_to_scalar_int() {
1485-
Ok(int) => int.is_null(),
1484+
match scalar.try_to_scalar_int() {
1485+
Ok(int) => interp_ok(int.is_null()),
14861486
Err(_) => {
1487-
// Can only happen during CTFE.
1487+
// We can't cast this pointer to an integer. Can only happen during CTFE.
14881488
let ptr = scalar.to_pointer(self)?;
14891489
match self.ptr_try_get_alloc_id(ptr, 0) {
14901490
Ok((alloc_id, offset, _)) => {
1491-
let size = self.get_alloc_info(alloc_id).size;
1492-
// If the pointer is out-of-bounds, it may be null.
1493-
// Note that one-past-the-end (offset == size) is still inbounds, and never null.
1494-
offset > size
1491+
let info = self.get_alloc_info(alloc_id);
1492+
// If the pointer is in-bounds (including "at the end"), it is definitely not null.
1493+
if offset <= info.size {
1494+
return interp_ok(false);
1495+
}
1496+
// If the allocation is N-aligned, and the offset is not divisible by N,
1497+
// then `base + offset` has a non-zero remainder after division by `N`,
1498+
// which means `base + offset` cannot be null.
1499+
if offset.bytes() % info.align.bytes() != 0 {
1500+
return interp_ok(false);
1501+
}
1502+
// We don't know enough, this might be null.
1503+
interp_ok(true)
14951504
}
14961505
Err(_offset) => bug!("a non-int scalar is always a pointer"),
14971506
}
14981507
}
1499-
})
1508+
}
15001509
}
15011510

15021511
/// Turning a "maybe pointer" into a proper pointer (and some information

library/core/src/num/f128.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,6 @@ impl f128 {
504504
///
505505
/// ```rust
506506
/// #![feature(f128)]
507-
/// #![feature(float_next_up_down)]
508507
/// # // FIXME(f16_f128): remove when `eqtf2` is available
509508
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
510509
///
@@ -516,13 +515,15 @@ impl f128 {
516515
/// # }
517516
/// ```
518517
///
518+
/// This operation corresponds to IEEE-754 `nextUp`.
519+
///
519520
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
520521
/// [`INFINITY`]: Self::INFINITY
521522
/// [`MIN`]: Self::MIN
522523
/// [`MAX`]: Self::MAX
523524
#[inline]
525+
#[doc(alias = "nextUp")]
524526
#[unstable(feature = "f128", issue = "116909")]
525-
// #[unstable(feature = "float_next_up_down", issue = "91399")]
526527
pub const fn next_up(self) -> Self {
527528
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
528529
// denormals to zero. This is in general unsound and unsupported, but here
@@ -558,7 +559,6 @@ impl f128 {
558559
///
559560
/// ```rust
560561
/// #![feature(f128)]
561-
/// #![feature(float_next_up_down)]
562562
/// # // FIXME(f16_f128): remove when `eqtf2` is available
563563
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
564564
///
@@ -570,13 +570,15 @@ impl f128 {
570570
/// # }
571571
/// ```
572572
///
573+
/// This operation corresponds to IEEE-754 `nextDown`.
574+
///
573575
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
574576
/// [`INFINITY`]: Self::INFINITY
575577
/// [`MIN`]: Self::MIN
576578
/// [`MAX`]: Self::MAX
577579
#[inline]
580+
#[doc(alias = "nextDown")]
578581
#[unstable(feature = "f128", issue = "116909")]
579-
// #[unstable(feature = "float_next_up_down", issue = "91399")]
580582
pub const fn next_down(self) -> Self {
581583
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
582584
// denormals to zero. This is in general unsound and unsupported, but here

library/core/src/num/f16.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,6 @@ impl f16 {
497497
///
498498
/// ```rust
499499
/// #![feature(f16)]
500-
/// #![feature(float_next_up_down)]
501500
/// # // FIXME(f16_f128): ABI issues on MSVC
502501
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
503502
///
@@ -509,13 +508,15 @@ impl f16 {
509508
/// # }
510509
/// ```
511510
///
511+
/// This operation corresponds to IEEE-754 `nextUp`.
512+
///
512513
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
513514
/// [`INFINITY`]: Self::INFINITY
514515
/// [`MIN`]: Self::MIN
515516
/// [`MAX`]: Self::MAX
516517
#[inline]
518+
#[doc(alias = "nextUp")]
517519
#[unstable(feature = "f16", issue = "116909")]
518-
// #[unstable(feature = "float_next_up_down", issue = "91399")]
519520
pub const fn next_up(self) -> Self {
520521
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
521522
// denormals to zero. This is in general unsound and unsupported, but here
@@ -551,7 +552,6 @@ impl f16 {
551552
///
552553
/// ```rust
553554
/// #![feature(f16)]
554-
/// #![feature(float_next_up_down)]
555555
/// # // FIXME(f16_f128): ABI issues on MSVC
556556
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
557557
///
@@ -563,13 +563,15 @@ impl f16 {
563563
/// # }
564564
/// ```
565565
///
566+
/// This operation corresponds to IEEE-754 `nextDown`.
567+
///
566568
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
567569
/// [`INFINITY`]: Self::INFINITY
568570
/// [`MIN`]: Self::MIN
569571
/// [`MAX`]: Self::MAX
570572
#[inline]
573+
#[doc(alias = "nextDown")]
571574
#[unstable(feature = "f16", issue = "116909")]
572-
// #[unstable(feature = "float_next_up_down", issue = "91399")]
573575
pub const fn next_down(self) -> Self {
574576
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
575577
// denormals to zero. This is in general unsound and unsupported, but here

library/core/src/num/f32.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -726,20 +726,23 @@ impl f32 {
726726
/// is finite `x == x.next_up().next_down()` also holds.
727727
///
728728
/// ```rust
729-
/// #![feature(float_next_up_down)]
730729
/// // f32::EPSILON is the difference between 1.0 and the next number up.
731730
/// assert_eq!(1.0f32.next_up(), 1.0 + f32::EPSILON);
732731
/// // But not for most numbers.
733732
/// assert!(0.1f32.next_up() < 0.1 + f32::EPSILON);
734733
/// assert_eq!(16777216f32.next_up(), 16777218.0);
735734
/// ```
736735
///
736+
/// This operation corresponds to IEEE-754 `nextUp`.
737+
///
737738
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
738739
/// [`INFINITY`]: Self::INFINITY
739740
/// [`MIN`]: Self::MIN
740741
/// [`MAX`]: Self::MAX
741742
#[inline]
742-
#[unstable(feature = "float_next_up_down", issue = "91399")]
743+
#[doc(alias = "nextUp")]
744+
#[stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")]
745+
#[rustc_const_stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")]
743746
pub const fn next_up(self) -> Self {
744747
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
745748
// denormals to zero. This is in general unsound and unsupported, but here
@@ -774,20 +777,23 @@ impl f32 {
774777
/// is finite `x == x.next_down().next_up()` also holds.
775778
///
776779
/// ```rust
777-
/// #![feature(float_next_up_down)]
778780
/// let x = 1.0f32;
779781
/// // Clamp value into range [0, 1).
780782
/// let clamped = x.clamp(0.0, 1.0f32.next_down());
781783
/// assert!(clamped < 1.0);
782784
/// assert_eq!(clamped.next_up(), 1.0);
783785
/// ```
784786
///
787+
/// This operation corresponds to IEEE-754 `nextDown`.
788+
///
785789
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
786790
/// [`INFINITY`]: Self::INFINITY
787791
/// [`MIN`]: Self::MIN
788792
/// [`MAX`]: Self::MAX
789793
#[inline]
790-
#[unstable(feature = "float_next_up_down", issue = "91399")]
794+
#[doc(alias = "nextDown")]
795+
#[stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")]
796+
#[rustc_const_stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")]
791797
pub const fn next_down(self) -> Self {
792798
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
793799
// denormals to zero. This is in general unsound and unsupported, but here

0 commit comments

Comments
 (0)