compiler/rustc_abi/src/callconv.rs RUST 194 lines View on github.com → Search inside
1#[cfg(feature = "nightly")]2use crate::{BackendRepr, FieldsShape, Primitive, Size, TyAbiInterface, TyAndLayout, Variants};34mod reg;56pub use reg::{Reg, RegKind};78/// Return value from the `homogeneous_aggregate` test function.9#[derive(Copy, Clone, Debug)]10pub enum HomogeneousAggregate {11    /// Yes, all the "leaf fields" of this struct are passed in the12    /// same way (specified in the `Reg` value).13    Homogeneous(Reg),1415    /// There are no leaf fields at all.16    NoData,17}1819/// Error from the `homogeneous_aggregate` test function, indicating20/// there are distinct leaf fields passed in different ways,21/// or this is uninhabited.22#[derive(Copy, Clone, Debug)]23pub struct Heterogeneous;2425impl HomogeneousAggregate {26    /// If this is a homogeneous aggregate, returns the homogeneous27    /// unit, else `None`.28    pub fn unit(self) -> Option<Reg> {29        match self {30            HomogeneousAggregate::Homogeneous(reg) => Some(reg),31            HomogeneousAggregate::NoData => None,32        }33    }3435    /// Try to combine two `HomogeneousAggregate`s, e.g. from two fields in36    /// the same `struct`. Only succeeds if only one of them has any data,37    /// or both units are identical.38    #[cfg(feature = "nightly")]39    fn merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous> {40        match (self, other) {41            (x, HomogeneousAggregate::NoData) | (HomogeneousAggregate::NoData, x) => Ok(x),4243            (HomogeneousAggregate::Homogeneous(a), HomogeneousAggregate::Homogeneous(b)) => {44                if a != b {45                    return Err(Heterogeneous);46                }47                Ok(self)48            }49        }50    }51}5253#[cfg(feature = "nightly")]54impl<'a, Ty> TyAndLayout<'a, Ty> {55    /// Returns `Homogeneous` if this layout is an aggregate containing fields of56    /// only a single type (e.g., `(u32, u32)`). Such aggregates are often57    /// special-cased in ABIs.58    ///59    /// Note: We generally ignore 1-ZST fields when computing this value (see #56877).60    ///61    /// This is public so that it can be used in unit tests, but62    /// should generally only be relevant to the ABI details of63    /// specific targets.64    #[tracing::instrument(skip(cx), level = "debug")]65    pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>66    where67        Ty: TyAbiInterface<'a, C> + Copy,68    {69        match self.backend_repr {70            // The primitive for this algorithm.71            BackendRepr::Scalar(scalar) => {72                let kind = match scalar.primitive() {73                    Primitive::Int(..) | Primitive::Pointer(_) => RegKind::Integer,74                    Primitive::Float(_) => RegKind::Float,75                };76                Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))77            }7879            BackendRepr::SimdVector { element, count: _ } => {80                assert!(!self.is_zst());8182                Ok(HomogeneousAggregate::Homogeneous(Reg {83                    kind: RegKind::Vector { hint_vector_elem: element.primitive() },84                    size: self.size,85                }))86            }8788            BackendRepr::SimdScalableVector { .. } => {89                unreachable!("`homogeneous_aggregate` should not be called for scalable vectors")90            }9192            BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => {93                // Helper for computing `homogeneous_aggregate`, allowing a custom94                // starting offset (used below for handling variants).95                let from_fields_at =96                    |layout: Self,97                     start: Size|98                     -> Result<(HomogeneousAggregate, Size), Heterogeneous> {99                        let is_union = match layout.fields {100                            FieldsShape::Primitive => {101                                unreachable!("aggregates can't have `FieldsShape::Primitive`")102                            }103                            FieldsShape::Array { count, .. } => {104                                assert_eq!(start, Size::ZERO);105106                                let result = if count > 0 {107                                    layout.field(cx, 0).homogeneous_aggregate(cx)?108                                } else {109                                    HomogeneousAggregate::NoData110                                };111                                return Ok((result, layout.size));112                            }113                            FieldsShape::Union(_) => true,114                            FieldsShape::Arbitrary { .. } => false,115                        };116117                        let mut result = HomogeneousAggregate::NoData;118                        let mut total = start;119120                        for i in 0..layout.fields.count() {121                            let field = layout.field(cx, i);122                            if field.is_1zst() {123                                // No data here and no impact on layout, can be ignored.124                                // (We might be able to also ignore all aligned ZST but that's less clear.)125                                continue;126                            }127128                            if !is_union && total != layout.fields.offset(i) {129                                // This field isn't just after the previous one we considered, abort.130                                return Err(Heterogeneous);131                            }132133                            result = result.merge(field.homogeneous_aggregate(cx)?)?;134135                            // Keep track of the offset (without padding).136                            let size = field.size;137                            if is_union {138                                total = total.max(size);139                            } else {140                                total += size;141                            }142                        }143144                        Ok((result, total))145                    };146147                let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?;148149                match &self.variants {150                    Variants::Single { .. } | Variants::Empty => {}151                    Variants::Multiple { variants, .. } => {152                        // Treat enum variants like union members.153                        // HACK(eddyb) pretend the `enum` field (discriminant)154                        // is at the start of every variant (otherwise the gap155                        // at the start of all variants would disqualify them).156                        //157                        // NB: for all tagged `enum`s (which include all non-C-like158                        // `enum`s with defined FFI representation), this will159                        // match the homogeneous computation on the equivalent160                        // `struct { tag; union { variant1; ... } }` and/or161                        // `union { struct { tag; variant1; } ... }`162                        // (the offsets of variant fields should be identical163                        // between the two for either to be a homogeneous aggregate).164                        let variant_start = total;165                        for variant_idx in variants.indices() {166                            let (variant_result, variant_total) =167                                from_fields_at(self.for_variant(cx, variant_idx), variant_start)?;168169                            result = result.merge(variant_result)?;170                            total = total.max(variant_total);171                        }172                    }173                }174175                // There needs to be no padding.176                if total != self.size {177                    Err(Heterogeneous)178                } else {179                    match result {180                        HomogeneousAggregate::Homogeneous(_) => {181                            assert_ne!(total, Size::ZERO);182                        }183                        HomogeneousAggregate::NoData => {184                            assert_eq!(total, Size::ZERO);185                        }186                    }187                    Ok(result)188                }189            }190            BackendRepr::Memory { sized: false } => Err(Heterogeneous),191        }192    }193}

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.