Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f0a751d
std_detect: support detecting more features on aarch64 Windows
lilith Apr 27, 2026
89cfc22
Suggest const destruct bounds on `Drop` impls when they are missing
oli-obk Apr 25, 2026
61e876f
Suggest various missing trait bounds on `HostEffect` clauses not bein…
oli-obk Apr 27, 2026
8b3f6db
Update with new LLVM 22 target for `wasm32-wali-linux-target`
arjunr2 Apr 28, 2026
e743a4d
bootstrap: remap OUT_DIR paths to fix build script path leakage in ar…
paradoxicalguy Apr 28, 2026
26ce8a9
Apply suggestion from @bjorn3
paradoxicalguy Apr 28, 2026
1c613d1
Introduce `VariantLayout` struct
moulins Dec 17, 2025
4118daa
Remove redundant `VariantLayout.variants` field
moulins Dec 17, 2025
f4e8f99
Store `FieldsShape::Arbitrary` fields directly in `VariantLayout`
moulins Dec 17, 2025
89e3bd3
Remove unused `VariantLayout.randomization_seed` field
moulins Dec 18, 2025
93db272
Remove per-variant alignment in `VariantLayout`
moulins Jan 13, 2026
fffc4b5
Update `opt_ast_lowering_delayed_lints` query to allow "stealing" lin…
GuillaumeGomez Apr 28, 2026
44b9251
use the new `//@ needs-asm-mnemonic: ret` more
folkertdev Apr 27, 2026
23c7bf0
Fix passing paths with space into dlltool
ChrisDenton Apr 28, 2026
6d20c98
Test that raw-dylib works with whitespace paths
ChrisDenton Apr 28, 2026
a940270
Make `FlatMapInPlaceVec` an unsafe trait.
nnethercote Apr 29, 2026
e119e75
Rollup merge of #151742 - moulins:variant-layout, r=saethlin
jhpratt Apr 29, 2026
e64e2e0
Rollup merge of #155856 - imazen:winarm-stable-features, r=Amanieu
jhpratt Apr 29, 2026
6d93314
Rollup merge of #155861 - oli-obk:effect-bound-suggestions, r=jdonsze…
jhpratt Apr 29, 2026
da6255c
Rollup merge of #155899 - ChrisDenton:dlltool, r=mati865
jhpratt Apr 29, 2026
fbd3323
Rollup merge of #155916 - arjunr2:llvm-22-update, r=JohnTitor
jhpratt Apr 29, 2026
5fecb7b
Rollup merge of #155935 - paradoxicalguy:fix-out-dir-remap, r=Urgau,
jhpratt Apr 29, 2026
552dad3
Rollup merge of #155950 - folkertdev:needs-ret-mnemonic, r=chenyukang
jhpratt Apr 29, 2026
99f9bea
Rollup merge of #155949 - GuillaumeGomez:steal-lints, r=JonathanBrouw…
jhpratt Apr 29, 2026
143227f
Rollup merge of #155951 - nnethercote:unsafe-FlatMapInPlaceVec, r=kiv…
jhpratt Apr 29, 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
92 changes: 36 additions & 56 deletions compiler/rustc_abi/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use tracing::{debug, trace};
use crate::{
AbiAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer,
LayoutData, Niche, NonZeroUsize, NumScalableVectors, Primitive, ReprOptions, Scalar, Size,
StructKind, TagEncoding, TargetDataLayout, Variants, WrappingRange,
StructKind, TagEncoding, TargetDataLayout, VariantLayout, Variants, WrappingRange,
};

mod coroutine;
Expand Down Expand Up @@ -638,6 +638,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
}

let calculate_niche_filling_layout = || -> Option<LayoutData<FieldIdx, VariantIdx>> {
struct VariantLayoutInfo {
align_abi: Align,
}

if repr.inhibit_enum_layout_opt() {
return None;
}
Expand All @@ -649,18 +653,22 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
let mut align = dl.aggregate_align;
let mut max_repr_align = repr.align;
let mut unadjusted_abi_align = align;
let mut combined_seed = repr.field_shuffle_seed;

let mut variants_info = IndexVec::<VariantIdx, _>::with_capacity(variants.len());
let mut variant_layouts = variants
.iter_enumerated()
.map(|(j, v)| {
let mut st = self.univariant(v, repr, StructKind::AlwaysSized).ok()?;
st.variants = Variants::Single { index: j };
.iter()
.map(|v| {
let st = self.univariant(v, repr, StructKind::AlwaysSized).ok()?;

variants_info.push(VariantLayoutInfo { align_abi: st.align.abi });

align = align.max(st.align.abi);
max_repr_align = max_repr_align.max(st.max_repr_align);
unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align);
combined_seed = combined_seed.wrapping_add(st.randomization_seed);

Some(st)
Some(VariantLayout::from_layout(st))
})
.collect::<Option<IndexVec<VariantIdx, _>>>()?;

Expand Down Expand Up @@ -698,23 +706,16 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
}

// Determine if it'll fit after the niche.
let this_align = layout.align.abi;
let this_align = variants_info[i].align_abi;
let this_offset = (niche_offset + niche_size).align_to(this_align);

if this_offset + layout.size > size {
return false;
}

// It'll fit, but we need to make some adjustments.
match layout.fields {
FieldsShape::Arbitrary { ref mut offsets, .. } => {
for offset in offsets.iter_mut() {
*offset += this_offset;
}
}
FieldsShape::Primitive | FieldsShape::Array { .. } | FieldsShape::Union(..) => {
panic!("Layout of fields should be Arbitrary for variants")
}
for offset in layout.field_offsets.iter_mut() {
*offset += this_offset;
}

// It can't be a Scalar or ScalarPair because the offset isn't 0.
Expand All @@ -736,7 +737,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
.iter_enumerated()
.all(|(i, layout)| i == largest_variant_index || layout.size == Size::ZERO);
let same_size = size == variant_layouts[largest_variant_index].size;
let same_align = align == variant_layouts[largest_variant_index].align.abi;
let same_align = align == variants_info[largest_variant_index].align_abi;

let uninhabited = variant_layouts.iter().all(|v| v.is_uninhabited());
let abi = if same_size && same_align && others_zst {
Expand All @@ -759,11 +760,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
BackendRepr::Memory { sized: true }
};

let combined_seed = variant_layouts
.iter()
.map(|v| v.randomization_seed)
.fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed));

let layout = LayoutData {
variants: Variants::Multiple {
tag: niche_scalar,
Expand Down Expand Up @@ -856,6 +852,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
let mut align = dl.aggregate_align;
let mut max_repr_align = repr.align;
let mut unadjusted_abi_align = align;
let mut combined_seed = repr.field_shuffle_seed;

let mut size = Size::ZERO;

Expand All @@ -879,14 +876,13 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {

// Create the set of structs that represent each variant.
let mut layout_variants = variants
.iter_enumerated()
.map(|(i, field_layouts)| {
let mut st = self.univariant(
.iter()
.map(|field_layouts| {
let st = self.univariant(
field_layouts,
repr,
StructKind::Prefixed(min_ity.size(), prefix_align),
)?;
st.variants = Variants::Single { index: i };
// Find the first field we can't move later
// to make room for a larger discriminant.
for field_idx in st.fields.index_by_increasing_offset() {
Expand All @@ -900,7 +896,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
align = align.max(st.align.abi);
max_repr_align = max_repr_align.max(st.max_repr_align);
unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align);
Ok(st)
combined_seed = combined_seed.wrapping_add(st.randomization_seed);
Ok(VariantLayout::from_layout(st))
})
.collect::<Result<IndexVec<VariantIdx, _>, _>>()?;

Expand Down Expand Up @@ -955,23 +952,16 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
let old_ity_size = min_ity.size();
let new_ity_size = ity.size();
for variant in &mut layout_variants {
match variant.fields {
FieldsShape::Arbitrary { ref mut offsets, .. } => {
for i in offsets {
if *i <= old_ity_size {
assert_eq!(*i, old_ity_size);
*i = new_ity_size;
}
}
// We might be making the struct larger.
if variant.size <= old_ity_size {
variant.size = new_ity_size;
}
}
FieldsShape::Primitive | FieldsShape::Array { .. } | FieldsShape::Union(..) => {
panic!("encountered a non-arbitrary layout during enum layout")
for i in &mut variant.field_offsets {
if *i <= old_ity_size {
assert_eq!(*i, old_ity_size);
*i = new_ity_size;
}
}
// We might be making the struct larger.
if variant.size <= old_ity_size {
variant.size = new_ity_size;
}
}
}

Expand All @@ -996,12 +986,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
let mut common_prim = None;
let mut common_prim_initialized_in_all_variants = true;
for (field_layouts, layout_variant) in iter::zip(variants, &layout_variants) {
let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else {
panic!("encountered a non-arbitrary layout during enum layout");
};
// We skip *all* ZST here and later check if we are good in terms of alignment.
// This lets us handle some cases involving aligned ZST.
let mut fields = iter::zip(field_layouts, offsets).filter(|p| !p.0.is_zst());
let mut fields = iter::zip(field_layouts, &layout_variant.field_offsets)
.filter(|p| !p.0.is_zst());
let (field, offset) = match (fields.next(), fields.next()) {
(None, None) => {
common_prim_initialized_in_all_variants = false;
Expand Down Expand Up @@ -1096,25 +1084,17 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
for variant in &mut layout_variants {
// We only do this for variants with fields; the others are not accessed anyway.
// Also do not overwrite any already existing "clever" ABIs.
if variant.fields.count() > 0
&& matches!(variant.backend_repr, BackendRepr::Memory { .. })
if matches!(variant.backend_repr, BackendRepr::Memory { .. } if variant.has_fields())
{
variant.backend_repr = abi;
// Also need to bump up the size and alignment, so that the entire value fits
// in here.
// Also need to bump up the size, so that the entire value fits in here.
variant.size = cmp::max(variant.size, size);
variant.align.abi = cmp::max(variant.align.abi, align);
}
}
}

let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);

let combined_seed = layout_variants
.iter()
.map(|v| v.randomization_seed)
.fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed));

let tagged_layout = LayoutData {
variants: Variants::Multiple {
tag,
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_abi/src/layout/coroutine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use tracing::{debug, trace};

use crate::{
BackendRepr, FieldsShape, HasDataLayout, Integer, LayoutData, Primitive, ReprOptions, Scalar,
StructKind, TagEncoding, Variants, WrappingRange,
StructKind, TagEncoding, VariantLayout, Variants, WrappingRange,
};

/// Overlap eligibility and variant assignment for each CoroutineSavedLocal.
Expand Down Expand Up @@ -230,7 +230,6 @@ pub(super) fn layout<
&ReprOptions::default(),
StructKind::Prefixed(prefix_size, prefix_align.abi),
)?;
variant.variants = Variants::Single { index };

let FieldsShape::Arbitrary { offsets, in_memory_order } = variant.fields else {
unreachable!();
Expand Down Expand Up @@ -281,7 +280,7 @@ pub(super) fn layout<

size = size.max(variant.size);
align = align.max(variant.align);
Ok(variant)
Ok(VariantLayout::from_layout(variant))
})
.collect::<Result<IndexVec<VariantIdx, _>, _>>()?;

Expand Down
24 changes: 24 additions & 0 deletions compiler/rustc_abi/src/layout/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,28 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
randomization_seed: Hash64::ZERO,
}
}

/// Returns a layout for an inhabited variant.
pub fn for_variant(parent: &Self, index: VariantIdx) -> Self {
let layout = match &parent.variants {
Variants::Multiple { variants, .. } => &variants[index],
_ => panic!("Expected multi-variant layout in `Layout::for_variant`"),
};

Self {
fields: FieldsShape::Arbitrary {
offsets: layout.field_offsets.clone(),
in_memory_order: layout.fields_in_memory_order.clone(),
},
variants: Variants::Single { index },
backend_repr: layout.backend_repr,
largest_niche: layout.largest_niche,
uninhabited: layout.uninhabited,
size: layout.size,
align: parent.align,
max_repr_align: parent.max_repr_align,
unadjusted_abi_align: parent.unadjusted_abi_align,
randomization_seed: Hash64::ZERO,
}
}
}
39 changes: 38 additions & 1 deletion compiler/rustc_abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1974,7 +1974,7 @@ pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
tag: Scalar,
tag_encoding: TagEncoding<VariantIdx>,
tag_field: FieldIdx,
variants: IndexVec<VariantIdx, LayoutData<FieldIdx, VariantIdx>>,
variants: IndexVec<VariantIdx, VariantLayout<FieldIdx>>,
},
}

Expand Down Expand Up @@ -2340,3 +2340,40 @@ pub enum AbiFromStrErr {
/// no "-unwind" variant can be used here
NoExplicitUnwind,
}

// NOTE: This struct is generic over the FieldIdx and VariantIdx for rust-analyzer usage.
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
pub struct VariantLayout<FieldIdx: Idx> {
pub size: Size,
pub backend_repr: BackendRepr,
pub field_offsets: IndexVec<FieldIdx, Size>,
fields_in_memory_order: IndexVec<u32, FieldIdx>,
largest_niche: Option<Niche>,
uninhabited: bool,
}

impl<FieldIdx: Idx> VariantLayout<FieldIdx> {
pub fn from_layout(layout: LayoutData<FieldIdx, impl Idx>) -> Self {
let FieldsShape::Arbitrary { offsets, in_memory_order } = layout.fields else {
panic!("Layout of fields should be Arbitrary for variants");
};

Self {
size: layout.size,
backend_repr: layout.backend_repr,
field_offsets: offsets,
fields_in_memory_order: in_memory_order,
largest_niche: layout.largest_niche,
uninhabited: layout.uninhabited,
}
}

pub fn is_uninhabited(&self) -> bool {
self.uninhabited
}

pub fn has_fields(&self) -> bool {
self.field_offsets.len() > 0
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let mut bodies = std::mem::take(&mut self.bodies);
let define_opaque = std::mem::take(&mut self.define_opaque);
let trait_map = std::mem::take(&mut self.trait_map);
let delayed_lints = std::mem::take(&mut self.delayed_lints).into_boxed_slice();
let delayed_lints = Steal::new(std::mem::take(&mut self.delayed_lints).into_boxed_slice());

#[cfg(debug_assertions)]
for (id, attrs) in attrs.iter() {
Expand Down
13 changes: 6 additions & 7 deletions compiler/rustc_codegen_ssa/src/back/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,12 +217,10 @@ fn create_mingw_dll_import_lib(
// able to control the *exact* spelling of each of the symbols that are being imported:
// hence we don't want `dlltool` adding leading underscores automatically.
let dlltool = find_binutils_dlltool(sess);
let temp_prefix = {
let mut path = PathBuf::from(&output_path);
path.pop();
path.push(lib_name);
path
};
// temp_prefix doesn't handle paths with spaces so
// use a relative path and set the current working directory
let cwd = output_path.parent().unwrap_or(output_path);
let temp_prefix = lib_name;
// dlltool target architecture args from:
// https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69
let (dlltool_target_arch, dlltool_target_bitness) = match &sess.target.arch {
Expand All @@ -246,7 +244,8 @@ fn create_mingw_dll_import_lib(
.arg(dlltool_target_bitness)
.arg("--no-leading-underscore")
.arg("--temp-prefix")
.arg(temp_prefix);
.arg(temp_prefix)
.current_dir(cwd);

match dlltool_cmd.output() {
Err(e) => {
Expand Down
15 changes: 10 additions & 5 deletions compiler/rustc_data_structures/src/flat_map_in_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,13 @@ impl<V: FlatMapInPlaceVec> FlatMapInPlace<V::Elem> for V {
}
}

// A vec-like type must implement these operations to support `flat_map_in_place`.
pub trait FlatMapInPlaceVec {
/// A vec-like type must implement these operations to support `flat_map_in_place`.
///
/// # Safety
///
/// The memory safety of the unsafe block in `flat_map_in_place` relies on impls of this trait
/// implementing all the operations correctly.
pub unsafe trait FlatMapInPlaceVec {
type Elem;

fn len(&self) -> usize;
Expand All @@ -78,7 +83,7 @@ pub trait FlatMapInPlaceVec {
fn insert(&mut self, idx: usize, elem: Self::Elem);
}

impl<T> FlatMapInPlaceVec for Vec<T> {
unsafe impl<T> FlatMapInPlaceVec for Vec<T> {
type Elem = T;

fn len(&self) -> usize {
Expand All @@ -104,7 +109,7 @@ impl<T> FlatMapInPlaceVec for Vec<T> {
}
}

impl<T> FlatMapInPlaceVec for ThinVec<T> {
unsafe impl<T> FlatMapInPlaceVec for ThinVec<T> {
type Elem = T;

fn len(&self) -> usize {
Expand All @@ -130,7 +135,7 @@ impl<T> FlatMapInPlaceVec for ThinVec<T> {
}
}

impl<T, const N: usize> FlatMapInPlaceVec for SmallVec<[T; N]> {
unsafe impl<T, const N: usize> FlatMapInPlaceVec for SmallVec<[T; N]> {
type Elem = T;

fn len(&self) -> usize {
Expand Down
Loading
Loading