Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
842c087
Fix requires_lto targets needing lto set in cargo
Flakebi Dec 29, 2025
d1d2efd
Introduce `VariantLayout` struct
moulins Dec 17, 2025
dcc9f81
Remove redundant `VariantLayout.variants` field
moulins Dec 17, 2025
82a3a13
Store `FieldsShape::Arbitrary` fields directly in `VariantLayout`
moulins Dec 17, 2025
8f0df41
Remove unused `VariantLayout.randomization_seed` field
moulins Dec 18, 2025
db81f4e
Remove per-variant alignment in `VariantLayout`
moulins Jan 13, 2026
7c77389
Remove `VariantLayout::largest_niche` field
moulins Jan 14, 2026
2c79213
field representing types: remove explicit `Send` and `Sync` impls
BennoLossin Apr 21, 2026
59f18c2
field representing types: implement Debug through reflection
BennoLossin Apr 21, 2026
f3719b1
field representing types: implement Default
BennoLossin Apr 21, 2026
104914e
field representing types: implement Hash, Eq & Ord
BennoLossin Apr 21, 2026
ca700ed
field representing types: test all implemented traits
BennoLossin Apr 21, 2026
a041a76
field representing types: add test for unsized types
BennoLossin Apr 21, 2026
4abc28f
`<Take as Read>::read_buf`: Clarify local variable name.
briansmith Apr 22, 2026
71076f2
`<Take as Read>::read_buf`: Eliminate unneeded local variables.
briansmith Apr 22, 2026
c716ce5
`<Take as Read>::read_buf`: Clarify safety comments and naming.
briansmith Apr 22, 2026
3a0a14f
`<Take as Read>::read_buf`: Don't initialize `buf` if it was already …
briansmith Apr 22, 2026
1a8d8ae
NVPTX: Drop support for old hw and old ISAs
kjetilkjeka Feb 1, 2026
5e00484
Avoid misleading closure return type note
chenyukang Apr 25, 2026
4fc64f4
Add boxing suggestions for `impl Trait` return type mismatches
Unique-Usman Apr 23, 2026
163aedc
Convert attribute `FinalizeFn` to fn pointer
JonathanBrouwer Apr 26, 2026
a677828
Add boxing suggestions for return expressions in `impl Trait` functions
Unique-Usman Apr 26, 2026
a7330f4
rustc_attr_parsing: use a `try {}` in `or_malformed`
scrabsha Apr 26, 2026
d9e227e
Fix broken logic in `incremental_verify_ich_failed`
jyn514 Apr 26, 2026
7151184
Add some debugging to `rustc_session` filename handling
jyn514 Apr 26, 2026
041c1c9
Rollup merge of #151742 - moulins:variant-layout, r=saethlin
JonathanBrouwer Apr 26, 2026
5bd8450
Rollup merge of #149624 - Flakebi:fix-lto, r=bjorn3
JonathanBrouwer Apr 26, 2026
42186a0
Rollup merge of #152443 - kjetilkjeka:nvptx_drop_support_old_hw_and_i…
JonathanBrouwer Apr 26, 2026
28fca87
Rollup merge of #155317 - briansmith:b/take-opt, r=Mark-Simulacrum
JonathanBrouwer Apr 26, 2026
73487d5
Rollup merge of #155588 - BennoLossin:frt-traits, r=Mark-Simulacrum
JonathanBrouwer Apr 26, 2026
a0bf90d
Rollup merge of #155682 - Unique-Usman:ua/box-impl, r=mejrs
JonathanBrouwer Apr 26, 2026
fbec5ca
Rollup merge of #155770 - chenyukang:yukang-fix-155670-closure-return…
JonathanBrouwer Apr 26, 2026
bd251ba
Rollup merge of #155818 - JonathanBrouwer:finalize-fn-ptr, r=mejrs
JonathanBrouwer Apr 26, 2026
f9205f4
Rollup merge of #155829 - scrabsha:push-kwlqypwmnpul, r=mejrs
JonathanBrouwer Apr 26, 2026
d33e6e2
Rollup merge of #155835 - jyn514:jyn/verify-ich-diagnostics, r=wesley…
JonathanBrouwer Apr 26, 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
111 changes: 47 additions & 64 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,26 +653,35 @@ 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 largest_variant_size = Size::ZERO;
let mut largest_variant_index = VariantIdx::new(0);
let mut largest_variant_niche = None;

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 };
.map(|(i, v)| {
let st = self.univariant(v, repr, StructKind::AlwaysSized).ok()?;

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

if st.size > largest_variant_size {
largest_variant_index = i;
largest_variant_size = st.size;
largest_variant_niche = st.largest_niche;
}

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, _>>>()?;

let largest_variant_index = variant_layouts
.iter_enumerated()
.max_by_key(|(_i, layout)| layout.size.bytes())
.map(|(i, _layout)| i)?;

let all_indices = variants.indices();
let needs_disc =
|index: VariantIdx| index != largest_variant_index && !absent(&variants[index]);
Expand All @@ -679,42 +692,33 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
(niche_variants.end().index() as u128 - niche_variants.start().index() as u128) + 1;

// Use the largest niche in the largest variant.
let niche = variant_layouts[largest_variant_index].largest_niche?;
let niche = largest_variant_niche?;
let (niche_start, niche_scalar) = niche.reserve(dl, count)?;
let niche_offset = niche.offset;
let niche_size = niche.value.size(dl);
let size = variant_layouts[largest_variant_index].size.align_to(align);
let size = largest_variant_size.align_to(align);

let all_variants_fit = variant_layouts.iter_enumerated_mut().all(|(i, layout)| {
if i == largest_variant_index {
return true;
}

layout.largest_niche = None;

if layout.size <= niche_offset {
// This variant will fit before the niche.
return true;
}

// 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 +740,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 +763,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 +855,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 +879,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 +899,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 +955,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 +989,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 +1087,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: None,
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,
}
}
}
37 changes: 36 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 @@ -2339,3 +2339,38 @@ 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>,
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,
uninhabited: layout.uninhabited,
}
}

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

pub fn has_fields(&self) -> bool {
self.field_offsets.len() > 0
}
}
8 changes: 5 additions & 3 deletions compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,11 @@ fn parse_directive_items<'p, S: Stage>(
}}

macro or_malformed($($code:tt)*) {{
let Some(ret) = (||{
Some($($code)*)
})() else {
let Some(ret) = (
try {
$($code)*
}
) else {
malformed!()
};
ret
Expand Down
7 changes: 3 additions & 4 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,7 @@ pub(super) struct GroupTypeInnerAccept<S: Stage> {

pub(crate) type AcceptFn<S> =
Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser) + Send + Sync>;
pub(crate) type FinalizeFn<S> =
Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>>;
pub(crate) type FinalizeFn<S> = fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>;

macro_rules! attribute_parsers {
(
Expand Down Expand Up @@ -131,10 +130,10 @@ macro_rules! attribute_parsers {
}),
safety: <$names as crate::attributes::AttributeParser<$stage>>::SAFETY,
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
finalizer: Box::new(|cx| {
finalizer: |cx| {
let state = STATE_OBJECT.take();
state.finalize(cx)
})
}
});
}
Entry::Occupied(_) => panic!("Attribute {path:?} has multiple accepters"),
Expand Down
Loading
Loading