Skip to content

Commit dbec5c4

Browse files
committed
Auto merge of rust-lang#131665 - matthiaskrgr:rollup-i5hluna, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - rust-lang#128967 (std::fs::get_path freebsd update.) - rust-lang#129794 (uefi: Implement getcwd and chdir) - rust-lang#130629 (core/net: add Ipv[46]Addr::from_octets, Ipv6Addr::from_segments.) - rust-lang#131274 (library: Const-stabilize `MaybeUninit::assume_init_mut`) - rust-lang#131473 (compiler: `{TyAnd,}Layout` comes home) - rust-lang#131533 (emscripten: Use the latest emsdk 3.1.68) - rust-lang#131593 (miri: avoid cloning AllocExtra) - rust-lang#131616 (merge const_ipv4 / const_ipv6 feature gate into 'ip' feature gate) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 5ceb623 + 06462e1 commit dbec5c4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+515
-349
lines changed

compiler/rustc_abi/src/callconv.rs

+254
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
mod abi {
2+
pub(crate) use crate::Primitive::*;
3+
pub(crate) use crate::Variants;
4+
}
5+
6+
use rustc_macros::HashStable_Generic;
7+
8+
use crate::{Abi, Align, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
9+
10+
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
11+
pub enum RegKind {
12+
Integer,
13+
Float,
14+
Vector,
15+
}
16+
17+
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
18+
pub struct Reg {
19+
pub kind: RegKind,
20+
pub size: Size,
21+
}
22+
23+
macro_rules! reg_ctor {
24+
($name:ident, $kind:ident, $bits:expr) => {
25+
pub fn $name() -> Reg {
26+
Reg { kind: RegKind::$kind, size: Size::from_bits($bits) }
27+
}
28+
};
29+
}
30+
31+
impl Reg {
32+
reg_ctor!(i8, Integer, 8);
33+
reg_ctor!(i16, Integer, 16);
34+
reg_ctor!(i32, Integer, 32);
35+
reg_ctor!(i64, Integer, 64);
36+
reg_ctor!(i128, Integer, 128);
37+
38+
reg_ctor!(f32, Float, 32);
39+
reg_ctor!(f64, Float, 64);
40+
}
41+
42+
impl Reg {
43+
pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
44+
let dl = cx.data_layout();
45+
match self.kind {
46+
RegKind::Integer => match self.size.bits() {
47+
1 => dl.i1_align.abi,
48+
2..=8 => dl.i8_align.abi,
49+
9..=16 => dl.i16_align.abi,
50+
17..=32 => dl.i32_align.abi,
51+
33..=64 => dl.i64_align.abi,
52+
65..=128 => dl.i128_align.abi,
53+
_ => panic!("unsupported integer: {self:?}"),
54+
},
55+
RegKind::Float => match self.size.bits() {
56+
16 => dl.f16_align.abi,
57+
32 => dl.f32_align.abi,
58+
64 => dl.f64_align.abi,
59+
128 => dl.f128_align.abi,
60+
_ => panic!("unsupported float: {self:?}"),
61+
},
62+
RegKind::Vector => dl.vector_align(self.size).abi,
63+
}
64+
}
65+
}
66+
67+
/// Return value from the `homogeneous_aggregate` test function.
68+
#[derive(Copy, Clone, Debug)]
69+
pub enum HomogeneousAggregate {
70+
/// Yes, all the "leaf fields" of this struct are passed in the
71+
/// same way (specified in the `Reg` value).
72+
Homogeneous(Reg),
73+
74+
/// There are no leaf fields at all.
75+
NoData,
76+
}
77+
78+
/// Error from the `homogeneous_aggregate` test function, indicating
79+
/// there are distinct leaf fields passed in different ways,
80+
/// or this is uninhabited.
81+
#[derive(Copy, Clone, Debug)]
82+
pub struct Heterogeneous;
83+
84+
impl HomogeneousAggregate {
85+
/// If this is a homogeneous aggregate, returns the homogeneous
86+
/// unit, else `None`.
87+
pub fn unit(self) -> Option<Reg> {
88+
match self {
89+
HomogeneousAggregate::Homogeneous(reg) => Some(reg),
90+
HomogeneousAggregate::NoData => None,
91+
}
92+
}
93+
94+
/// Try to combine two `HomogeneousAggregate`s, e.g. from two fields in
95+
/// the same `struct`. Only succeeds if only one of them has any data,
96+
/// or both units are identical.
97+
fn merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous> {
98+
match (self, other) {
99+
(x, HomogeneousAggregate::NoData) | (HomogeneousAggregate::NoData, x) => Ok(x),
100+
101+
(HomogeneousAggregate::Homogeneous(a), HomogeneousAggregate::Homogeneous(b)) => {
102+
if a != b {
103+
return Err(Heterogeneous);
104+
}
105+
Ok(self)
106+
}
107+
}
108+
}
109+
}
110+
111+
impl<'a, Ty> TyAndLayout<'a, Ty> {
112+
/// Returns `true` if this is an aggregate type (including a ScalarPair!)
113+
pub fn is_aggregate(&self) -> bool {
114+
match self.abi {
115+
Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false,
116+
Abi::ScalarPair(..) | Abi::Aggregate { .. } => true,
117+
}
118+
}
119+
120+
/// Returns `Homogeneous` if this layout is an aggregate containing fields of
121+
/// only a single type (e.g., `(u32, u32)`). Such aggregates are often
122+
/// special-cased in ABIs.
123+
///
124+
/// Note: We generally ignore 1-ZST fields when computing this value (see #56877).
125+
///
126+
/// This is public so that it can be used in unit tests, but
127+
/// should generally only be relevant to the ABI details of
128+
/// specific targets.
129+
pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>
130+
where
131+
Ty: TyAbiInterface<'a, C> + Copy,
132+
{
133+
match self.abi {
134+
Abi::Uninhabited => Err(Heterogeneous),
135+
136+
// The primitive for this algorithm.
137+
Abi::Scalar(scalar) => {
138+
let kind = match scalar.primitive() {
139+
abi::Int(..) | abi::Pointer(_) => RegKind::Integer,
140+
abi::Float(_) => RegKind::Float,
141+
};
142+
Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
143+
}
144+
145+
Abi::Vector { .. } => {
146+
assert!(!self.is_zst());
147+
Ok(HomogeneousAggregate::Homogeneous(Reg {
148+
kind: RegKind::Vector,
149+
size: self.size,
150+
}))
151+
}
152+
153+
Abi::ScalarPair(..) | Abi::Aggregate { sized: true } => {
154+
// Helper for computing `homogeneous_aggregate`, allowing a custom
155+
// starting offset (used below for handling variants).
156+
let from_fields_at =
157+
|layout: Self,
158+
start: Size|
159+
-> Result<(HomogeneousAggregate, Size), Heterogeneous> {
160+
let is_union = match layout.fields {
161+
FieldsShape::Primitive => {
162+
unreachable!("aggregates can't have `FieldsShape::Primitive`")
163+
}
164+
FieldsShape::Array { count, .. } => {
165+
assert_eq!(start, Size::ZERO);
166+
167+
let result = if count > 0 {
168+
layout.field(cx, 0).homogeneous_aggregate(cx)?
169+
} else {
170+
HomogeneousAggregate::NoData
171+
};
172+
return Ok((result, layout.size));
173+
}
174+
FieldsShape::Union(_) => true,
175+
FieldsShape::Arbitrary { .. } => false,
176+
};
177+
178+
let mut result = HomogeneousAggregate::NoData;
179+
let mut total = start;
180+
181+
for i in 0..layout.fields.count() {
182+
let field = layout.field(cx, i);
183+
if field.is_1zst() {
184+
// No data here and no impact on layout, can be ignored.
185+
// (We might be able to also ignore all aligned ZST but that's less clear.)
186+
continue;
187+
}
188+
189+
if !is_union && total != layout.fields.offset(i) {
190+
// This field isn't just after the previous one we considered, abort.
191+
return Err(Heterogeneous);
192+
}
193+
194+
result = result.merge(field.homogeneous_aggregate(cx)?)?;
195+
196+
// Keep track of the offset (without padding).
197+
let size = field.size;
198+
if is_union {
199+
total = total.max(size);
200+
} else {
201+
total += size;
202+
}
203+
}
204+
205+
Ok((result, total))
206+
};
207+
208+
let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?;
209+
210+
match &self.variants {
211+
abi::Variants::Single { .. } => {}
212+
abi::Variants::Multiple { variants, .. } => {
213+
// Treat enum variants like union members.
214+
// HACK(eddyb) pretend the `enum` field (discriminant)
215+
// is at the start of every variant (otherwise the gap
216+
// at the start of all variants would disqualify them).
217+
//
218+
// NB: for all tagged `enum`s (which include all non-C-like
219+
// `enum`s with defined FFI representation), this will
220+
// match the homogeneous computation on the equivalent
221+
// `struct { tag; union { variant1; ... } }` and/or
222+
// `union { struct { tag; variant1; } ... }`
223+
// (the offsets of variant fields should be identical
224+
// between the two for either to be a homogeneous aggregate).
225+
let variant_start = total;
226+
for variant_idx in variants.indices() {
227+
let (variant_result, variant_total) =
228+
from_fields_at(self.for_variant(cx, variant_idx), variant_start)?;
229+
230+
result = result.merge(variant_result)?;
231+
total = total.max(variant_total);
232+
}
233+
}
234+
}
235+
236+
// There needs to be no padding.
237+
if total != self.size {
238+
Err(Heterogeneous)
239+
} else {
240+
match result {
241+
HomogeneousAggregate::Homogeneous(_) => {
242+
assert_ne!(total, Size::ZERO);
243+
}
244+
HomogeneousAggregate::NoData => {
245+
assert_eq!(total, Size::ZERO);
246+
}
247+
}
248+
Ok(result)
249+
}
250+
}
251+
Abi::Aggregate { sized: false } => Err(Heterogeneous),
252+
}
253+
}
254+
}

compiler/rustc_abi/src/layout.rs

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ use crate::{
1111
Variants, WrappingRange,
1212
};
1313

14+
mod ty;
15+
16+
pub use ty::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
17+
1418
// A variant is absent if it's uninhabited and only has ZST fields.
1519
// Present uninhabited variants only require space for their fields,
1620
// but *not* an encoding of the discriminant (e.g., a tag value).

compiler/rustc_target/src/abi/mod.rs compiler/rustc_abi/src/layout/ty.rs

+1-11
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,8 @@ use Primitive::*;
66
use rustc_data_structures::intern::Interned;
77
use rustc_macros::HashStable_Generic;
88

9-
use crate::json::{Json, ToJson};
10-
11-
pub mod call;
12-
139
// Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
14-
pub use rustc_abi::{Float, *};
15-
16-
impl ToJson for Endian {
17-
fn to_json(&self) -> Json {
18-
self.as_str().to_json()
19-
}
20-
}
10+
use crate::{Float, *};
2111

2212
rustc_index::newtype_index! {
2313
/// The *source-order* index of a field in a variant.

compiler/rustc_abi/src/lib.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// tidy-alphabetical-start
22
#![cfg_attr(feature = "nightly", allow(internal_features))]
33
#![cfg_attr(feature = "nightly", doc(rust_logo))]
4+
#![cfg_attr(feature = "nightly", feature(rustc_attrs))]
45
#![cfg_attr(feature = "nightly", feature(rustdoc_internals))]
56
#![cfg_attr(feature = "nightly", feature(step_trait))]
67
#![warn(unreachable_pub)]
@@ -22,11 +23,16 @@ use rustc_macros::HashStable_Generic;
2223
#[cfg(feature = "nightly")]
2324
use rustc_macros::{Decodable_Generic, Encodable_Generic};
2425

26+
mod callconv;
2527
mod layout;
2628
#[cfg(test)]
2729
mod tests;
2830

29-
pub use layout::{LayoutCalculator, LayoutCalculatorError};
31+
pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind};
32+
pub use layout::{
33+
FIRST_VARIANT, FieldIdx, Layout, LayoutCalculator, LayoutCalculatorError, TyAbiInterface,
34+
TyAndLayout, VariantIdx,
35+
};
3036

3137
/// Requirements for a `StableHashingContext` to be used in this crate.
3238
/// This is a hack to allow using the `HashStable_Generic` derive macro

compiler/rustc_const_eval/src/const_eval/machine.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxIndexMap<K, V> {
140140

141141
#[inline(always)]
142142
fn filter_map_collect<T>(&self, mut f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T> {
143-
self.iter().filter_map(move |(k, v)| f(k, &*v)).collect()
143+
self.iter().filter_map(move |(k, v)| f(k, v)).collect()
144144
}
145145

146146
#[inline(always)]

compiler/rustc_const_eval/src/interpret/memory.rs

+18-13
Original file line numberDiff line numberDiff line change
@@ -993,11 +993,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
993993
bytes
994994
}
995995

996-
/// Find leaked allocations. Allocations reachable from `static_roots` or a `Global` allocation
997-
/// are not considered leaked, as well as leaks whose kind's `may_leak()` returns true.
998-
pub fn find_leaked_allocations(
999-
&self,
1000-
static_roots: &[AllocId],
996+
/// Find leaked allocations, remove them from memory and return them. Allocations reachable from
997+
/// `static_roots` or a `Global` allocation are not considered leaked, as well as leaks whose
998+
/// kind's `may_leak()` returns true.
999+
///
1000+
/// This is highly destructive, no more execution can happen after this!
1001+
pub fn take_leaked_allocations(
1002+
&mut self,
1003+
static_roots: impl FnOnce(&Self) -> &[AllocId],
10011004
) -> Vec<(AllocId, MemoryKind<M::MemoryKind>, Allocation<M::Provenance, M::AllocExtra, M::Bytes>)>
10021005
{
10031006
// Collect the set of allocations that are *reachable* from `Global` allocations.
@@ -1008,7 +1011,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
10081011
self.memory.alloc_map.filter_map_collect(move |&id, &(kind, _)| {
10091012
if Some(kind) == global_kind { Some(id) } else { None }
10101013
});
1011-
todo.extend(static_roots);
1014+
todo.extend(static_roots(self));
10121015
while let Some(id) = todo.pop() {
10131016
if reachable.insert(id) {
10141017
// This is a new allocation, add the allocation it points to `todo`.
@@ -1023,13 +1026,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
10231026
};
10241027

10251028
// All allocations that are *not* `reachable` and *not* `may_leak` are considered leaking.
1026-
self.memory.alloc_map.filter_map_collect(|id, (kind, alloc)| {
1027-
if kind.may_leak() || reachable.contains(id) {
1028-
None
1029-
} else {
1030-
Some((*id, *kind, alloc.clone()))
1031-
}
1032-
})
1029+
let leaked: Vec<_> = self.memory.alloc_map.filter_map_collect(|&id, &(kind, _)| {
1030+
if kind.may_leak() || reachable.contains(&id) { None } else { Some(id) }
1031+
});
1032+
let mut result = Vec::new();
1033+
for &id in leaked.iter() {
1034+
let (kind, alloc) = self.memory.alloc_map.remove(&id).unwrap();
1035+
result.push((id, kind, alloc));
1036+
}
1037+
result
10331038
}
10341039

10351040
/// Runs the closure in "validation" mode, which means the machine's memory read hooks will be

compiler/rustc_middle/src/ty/context.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::marker::PhantomData;
1212
use std::ops::{Bound, Deref};
1313
use std::{fmt, iter, mem};
1414

15+
use rustc_abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx};
1516
use rustc_ast::{self as ast, attr};
1617
use rustc_data_structures::defer;
1718
use rustc_data_structures::fingerprint::Fingerprint;
@@ -48,7 +49,6 @@ use rustc_session::{Limit, MetadataKind, Session};
4849
use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId};
4950
use rustc_span::symbol::{Ident, Symbol, kw, sym};
5051
use rustc_span::{DUMMY_SP, Span};
51-
use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx};
5252
use rustc_target::spec::abi;
5353
use rustc_type_ir::TyKind::*;
5454
use rustc_type_ir::fold::TypeFoldable;

0 commit comments

Comments
 (0)