Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
34 changes: 33 additions & 1 deletion compiler/rustc_abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1871,12 +1871,25 @@ impl BackendRepr {
}
}

/// Returns `true` if this is a scalar type
/// Returns `true` if this is specifically a [`Self::Scalar`] type.
///
/// This excludes SIMD types.
#[inline]
pub fn is_scalar(&self) -> bool {
matches!(*self, BackendRepr::Scalar(_))
}

/// Returns `true` if this is a scalar type or SIMD type.
#[inline]
pub fn is_scalar_or_simd(&self) -> bool {
matches!(
*self,
BackendRepr::Scalar(_)
| BackendRepr::SimdVector { .. }
| BackendRepr::SimdScalableVector { .. }
)
}

/// Returns `true` if this is a bool
#[inline]
pub fn is_bool(&self) -> bool {
Expand Down Expand Up @@ -2322,6 +2335,25 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
}
}

/// In the backend, a value with this type and layout is fully represented by
/// its SSA value(s), independent of the contents of memory.
///
/// For example, you can swap by reading both then writing both without using
/// an alloca because the store of one cannot affect the value of the other.
///
/// Any projection into a standalone type must also yield a standalone type,
/// since it might not be in memory at all.
#[inline]
pub fn is_ssa_standalone(&self) -> bool {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weird name, but I kept trying to think of a better one and couldn't. It could be is_backend_standalone or has_standalone_repr but that's about it.

match self.backend_repr {
BackendRepr::Memory { .. } => self.is_zst(),
BackendRepr::Scalar(..)
| BackendRepr::ScalarPair { .. }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, is a ScalarPair really an "SSA standalone"...? Hmm...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For everywhere that uses this method, 100% yes it is. Maybe a different name would make that clearer, but it definitely needs to be in the same category as Scalar for this function. (I have "value(s)" in the description there to emphasize that it might be multiple SSA values but it's still standalone.)

For example you can swap two pairs by loading both and writing both, unlike Memory where a load_operand doesn't actually load anything so if you load-both-then-write-both it just makes one equal to the other. And projections into scalar pair can't give memory, only other scalar pairs (it was a wrapper around another scalar pair), single scalars (reading one or the other of the scalars), or zsts (like extra 1-zsts in a transparent wrapper).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah true true. 'kay!

| BackendRepr::SimdVector { .. }
| BackendRepr::SimdScalableVector { .. } => true,
}
}

/// Checks if these two `Layout` are equal enough to be considered "the same for all function
/// call ABIs". Note however that real ABIs depend on more details that are not reflected in the
/// `Layout`; the `PassMode` need to be compared as well. Also note that we assume
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_gcc/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1054,7 +1054,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
let val = if place.val.llextra.is_some() {
// FIXME: Merge with the `else` below?
OperandValue::Ref(place.val)
} else if place.layout.is_gcc_immediate() {
} else if place.layout.backend_repr.is_scalar_or_simd() {
let load = self.load(place.layout.gcc_type(self), place.val.llval, place.val.align);
OperandValue::Immediate(
if let abi::BackendRepr::Scalar(ref scalar) = place.layout.backend_repr {
Expand Down
29 changes: 0 additions & 29 deletions compiler/rustc_codegen_gcc/src/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,6 @@ fn uncached_gcc_type<'gcc, 'tcx>(
}

pub trait LayoutGccExt<'tcx> {
fn is_gcc_immediate(&self) -> bool;
fn is_gcc_scalar_pair(&self) -> bool;
fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
fn scalar_gcc_type_at<'gcc>(
Expand All @@ -177,25 +175,6 @@ pub trait LayoutGccExt<'tcx> {
}

impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
fn is_gcc_immediate(&self) -> bool {
match self.backend_repr {
BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => true,
// FIXME(rustc_scalable_vector): Not yet implemented in rustc_codegen_gcc.
BackendRepr::SimdScalableVector { .. } => todo!(),
BackendRepr::ScalarPair { .. } | BackendRepr::Memory { .. } => false,
}
}

fn is_gcc_scalar_pair(&self) -> bool {
match self.backend_repr {
BackendRepr::ScalarPair { .. } => true,
BackendRepr::Scalar(_)
| BackendRepr::SimdVector { .. }
| BackendRepr::SimdScalableVector { .. }
| BackendRepr::Memory { .. } => false,
}
}

/// Gets the GCC type corresponding to a Rust type, i.e., `rustc_middle::ty::Ty`.
/// The pointee type of the pointer in `PlaceRef` is always this type.
/// For sized types, it is also the right LLVM type for an `alloca`
Expand Down Expand Up @@ -350,14 +329,6 @@ impl<'gcc, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
layout.immediate_gcc_type(self)
}

fn is_backend_immediate(&self, layout: TyAndLayout<'tcx>) -> bool {
layout.is_gcc_immediate()
}

fn is_backend_scalar_pair(&self, layout: TyAndLayout<'tcx>) -> bool {
layout.is_gcc_scalar_pair()
}

fn scalar_pair_element_backend_type(
&self,
layout: TyAndLayout<'tcx>,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
let val = if let Some(_) = place.val.llextra {
// FIXME: Merge with the `else` below?
OperandValue::Ref(place.val)
} else if place.layout.is_llvm_immediate() {
} else if place.layout.backend_repr.is_scalar_or_simd() {
let mut const_llval = None;
let llty = place.layout.llvm_type(self);
if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) {
Expand Down
6 changes: 0 additions & 6 deletions compiler/rustc_codegen_llvm/src/type_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,12 +296,6 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> &'ll Type {
layout.immediate_llvm_type(self)
}
fn is_backend_immediate(&self, layout: TyAndLayout<'tcx>) -> bool {
layout.is_llvm_immediate()
}
fn is_backend_scalar_pair(&self, layout: TyAndLayout<'tcx>) -> bool {
layout.is_llvm_scalar_pair()
}
fn scalar_pair_element_backend_type(
&self,
layout: TyAndLayout<'tcx>,
Expand Down
21 changes: 0 additions & 21 deletions compiler/rustc_codegen_llvm/src/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,6 @@ impl<'a, 'tcx> CodegenCx<'a, 'tcx> {
}

pub(crate) trait LayoutLlvmExt<'tcx> {
fn is_llvm_immediate(&self) -> bool;
fn is_llvm_scalar_pair(&self) -> bool;
fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type;
fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type;
fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, scalar: Scalar) -> &'a Type;
Expand All @@ -223,25 +221,6 @@ pub(crate) trait LayoutLlvmExt<'tcx> {
}

impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
fn is_llvm_immediate(&self) -> bool {

@scottmcm scottmcm Jul 12, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are ancient, still there in recognizable form 8+ years ago in

fn is_llvm_immediate(&self) -> bool {
match self.abi {
layout::Abi::Uninhabited |
layout::Abi::Scalar(_) |
layout::Abi::Vector => true,
layout::Abi::ScalarPair(..) => false,
layout::Abi::Aggregate { .. } => self.is_zst()
}
}
fn is_llvm_scalar_pair<'a>(&self) -> bool {
match self.abi {
layout::Abi::ScalarPair(..) => true,
layout::Abi::Uninhabited |
layout::Abi::Scalar(_) |
layout::Abi::Vector |
layout::Abi::Aggregate { .. } => false
}
}

But also the types involved are pretty different now. Being explicitly BackendRepr instead of Abi to me makes using it directly for these "well what does it look like in the backend?" uses make way more sense than it probably did way back when.

View changes since the review

match self.backend_repr {
BackendRepr::Scalar(_)
| BackendRepr::SimdVector { .. }
| BackendRepr::SimdScalableVector { .. } => true,
BackendRepr::ScalarPair { .. } | BackendRepr::Memory { .. } => false,
}
}

fn is_llvm_scalar_pair(&self) -> bool {
match self.backend_repr {
BackendRepr::ScalarPair { .. } => true,
BackendRepr::Scalar(_)
| BackendRepr::SimdVector { .. }
| BackendRepr::SimdScalableVector { .. }
| BackendRepr::Memory { .. } => false,
}
}

/// Gets the LLVM type corresponding to a Rust type, i.e., `rustc_middle::ty::Ty`.
/// The pointee type of the pointer in `PlaceRef` is always this type.
/// For sized types, it is also the right LLVM type for an `alloca`
Expand Down
13 changes: 6 additions & 7 deletions compiler/rustc_codegen_ssa/src/mir/analyze.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,11 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx>
LocalKind::Unused => {
let ty = fx.monomorphize(decl.ty);
let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span);
*kind =
if fx.cx.is_backend_immediate(layout) || fx.cx.is_backend_scalar_pair(layout) {
LocalKind::SSA(location)
} else {
LocalKind::Memory
};
*kind = if let abi::BackendRepr::Memory { .. } = layout.backend_repr {
LocalKind::Memory
} else {
LocalKind::SSA(location)
};
Comment on lines +86 to +90

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm realizing I'm not entirely sure why this isn't conditioned on just is_ssa_standalone? The ZSTness question? But LocalKind::ZST is up there...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you say, with ZSTs already excluded it'll work both ways.

I don't know if it's easier to think of things here as "well you can only use a SSA definition if it's standalone" or "well if it's memory then it needs to me in memory".

(I guess the is_ssa_standalone phrasing makes the diff smaller...)

}
LocalKind::SSA(_) => *kind = LocalKind::Memory,
}
Expand Down Expand Up @@ -157,7 +156,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx>
}
}
debug_assert!(
!self.fx.cx.is_backend_ref(layout),
layout.is_ssa_standalone(),
"Post-projection {place_ref:?} layout should be non-Ref, but it's {layout:?}",
);
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if let sym::typed_swap_nonoverlapping = name {
let pointee_ty = fn_args.type_at(0);
let pointee_layout = bx.layout_of(pointee_ty);
if !bx.is_backend_ref(pointee_layout)
if pointee_layout.is_ssa_standalone()
// But if we're not going to optimize, trying to use the fallback
// body just makes things worse, so don't bother.
|| bx.sess().opts.optimize == OptLevel::No
Expand Down Expand Up @@ -609,7 +609,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
};

debug_assert!(
op_val.is_expected_variant_for_type(bx.cx(), result_layout),
op_val.is_expected_variant_for_type(result_layout),
"[{name:?}] Value {op_val:?} is wrong for type {result_layout:?}",
);

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
PassMode::Direct(_) => {
let llarg = bx.get_param(llarg_idx);
llarg_idx += 1;
debug_assert!(bx.is_backend_immediate(arg.layout));
debug_assert!(arg.layout.backend_repr.is_scalar_or_simd());
return local(OperandRef {
val: OperandValue::Immediate(llarg),
layout: arg.layout,
Expand Down
88 changes: 56 additions & 32 deletions compiler/rustc_codegen_ssa/src/mir/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,37 +28,54 @@ use crate::traits::*;
pub enum OperandValue<V> {
/// A reference to the actual operand. The data is guaranteed
/// to be valid for the operand's lifetime.
/// The second value, if any, is the extra data (vtable or length)
/// The [`PlaceValue::llextra`], if any, is the extra data (vtable or length)
/// which indicates that it refers to an unsized rvalue.
///
/// An `OperandValue` *must* be this variant for any type for which
/// [`LayoutTypeCodegenMethods::is_backend_ref`] returns `true`.
/// [`rustc_abi::LayoutData::is_ssa_standalone`] returns `false`.
/// (That basically amounts to "isn't one of the other variants".)
///
/// This holds a [`PlaceValue`] (like a [`PlaceRef`] does) with a pointer
/// to the location holding the value. The type behind that pointer is the
/// one returned by [`LayoutTypeCodegenMethods::backend_type`].
///
/// Note that a [`load_operand`] which produces this variant didn't actually
/// *load* anything; it just put the pointer-to-place into this variant.
///
/// [`load_operand`]: BuilderMethods::load_operand
Ref(PlaceValue<V>),
/// A single LLVM immediate value.
///
/// An `OperandValue` *must* be this variant for any type for which
/// [`LayoutTypeCodegenMethods::is_backend_immediate`] returns `true`.
/// An `OperandValue` *must* be this variant for any type that's
/// [`BackendRepr::Scalar`], [`BackendRepr::SimdVector`], or
/// [`BackendRepr::SimdScalableVector`].
///
/// The backend value in this variant must be the *immediate* backend type,
/// as returned by [`LayoutTypeCodegenMethods::immediate_backend_type`].
///
/// Notably, that means that in LLVM a `bool` is `i1` here, even though we
/// load and store `bool`s as LLVM's `i8` type. Methods such as
/// [`BuilderMethods::load_operand`] and [`OperandRef::store_with_annotation`]
/// will handle that correctly, but if you're using the value directly or
/// implementing such methods, be sure to convert using
/// [`BuilderMethods::from_immediate`] and [`BuilderMethods::to_immediate_scalar`]
/// in the appropriate places.
Immediate(V),
/// A pair of immediate LLVM values. Used by wide pointers too.
/// A pair of immediate LLVM values.
///
/// Notably this includes wide pointers, where the two values are the pointer
/// and the metadata (slice length, vtable pointer, etc).
///
/// # Invariants
/// - For `Pair(a, b)`, `a` is always at offset 0, but may have `FieldIdx(1..)`
/// - `b` is not at offset 0, because `V` is not a 1ZST type.
/// - `a` and `b` will have a different FieldIdx, but otherwise `b`'s may be lower
/// or they may not be adjacent, due to arbitrary numbers of 1ZST fields that
/// will not affect the shape of the data which determines if `Pair` will be used.
/// - An `OperandValue` *must* be this variant for any type for which
/// [`LayoutTypeCodegenMethods::is_backend_scalar_pair`] returns `true`.
/// - An `OperandValue` *must* be this variant for any type that's [`BackendRepr::ScalarPair`].
/// - The backend values in this variant must be the *immediate* backend types,
/// as returned by [`LayoutTypeCodegenMethods::scalar_pair_element_backend_type`]
/// with `immediate: true`.
/// with `immediate: true`. See the note in [`Self::Immediate`].
Pair(V, V),
/// A value taking no bytes, and which therefore needs no LLVM value at all.
///
Expand Down Expand Up @@ -104,16 +121,18 @@ impl<V: CodegenObject> OperandValue<V> {
}

#[must_use]
pub(crate) fn is_expected_variant_for_type<'tcx, Cx: LayoutTypeCodegenMethods<'tcx>>(
&self,
cx: &Cx,
ty: TyAndLayout<'tcx>,
) -> bool {
match self {
OperandValue::ZeroSized => ty.is_zst(),
OperandValue::Immediate(_) => cx.is_backend_immediate(ty),
OperandValue::Pair(_, _) => cx.is_backend_scalar_pair(ty),
OperandValue::Ref(_) => cx.is_backend_ref(ty),
pub(crate) fn is_expected_variant_for_type<'tcx>(&self, ty: TyAndLayout<'tcx>) -> bool {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...what a strange function. Feels worrying that it exists.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK it's only for ICEing.

For example I added

debug_assert!(
op_val.is_expected_variant_for_type(bx.cx(), result_layout),
"[{name:?}] Value {op_val:?} is wrong for type {result_layout:?}",
);

when doing the "intrinsic without an alloca" work as a double-check that it's returning the correct thing for the type.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm okay but it feels very "we're not correct-by-construction", is what I'm thinking.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well yeah, the problem is that everything's just a &'ll Value under the hood. So it's really easy to accidentally put an LLVM { i32, i1 } into an OperandValue::Immediate instead of the i32 and the i1 into an OperandValue::Pair, because there's no type-level check.

See our previous conversation about maybe having OperandRef check this always on construction (which would use this method, plus maybe more). Part of what motivates this PR is that that change will be much more feasible without needing a Cx in is_expected_variant_for_type since then the constructor won't require extra dependencies.

match (self, ty.backend_repr) {
(OperandValue::ZeroSized, BackendRepr::Memory { .. }) => ty.is_zst(),
(OperandValue::Ref(_), BackendRepr::Memory { .. }) => !ty.is_zst(),
(
OperandValue::Immediate(_),
BackendRepr::Scalar(..)
| BackendRepr::SimdVector { .. }
| BackendRepr::SimdScalableVector { .. },
) => true,
(OperandValue::Pair(_, _), BackendRepr::ScalarPair { .. }) => true,
_ => false,
}
}
}
Expand Down Expand Up @@ -369,11 +388,11 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
let field = self.layout.field(bx.cx(), i);
let offset = self.layout.fields.offset(i);

if !bx.is_backend_ref(self.layout) && bx.is_backend_ref(field) {
if self.layout.is_ssa_standalone() && !field.is_ssa_standalone() {
// Part of https://github.com/rust-lang/compiler-team/issues/838
span_bug!(
fx.mir.span,
"Non-ref type {self:?} cannot project to ref field type {field:?}",
"Standalone type {self:?} cannot project to memory-dependent field type {field:?}",
);
}

Expand Down Expand Up @@ -943,18 +962,23 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
layout: TyAndLayout<'tcx>,
) -> OperandValue<V> {
assert!(layout.is_sized());
if layout.is_zst() {
OperandValue::ZeroSized
} else if bx.cx().is_backend_immediate(layout) {
let ibty = bx.cx().immediate_backend_type(layout);
OperandValue::Immediate(bx.const_poison(ibty))
} else if bx.cx().is_backend_scalar_pair(layout) {
let ibty0 = bx.cx().scalar_pair_element_backend_type(layout, 0, true);
let ibty1 = bx.cx().scalar_pair_element_backend_type(layout, 1, true);
OperandValue::Pair(bx.const_poison(ibty0), bx.const_poison(ibty1))
} else {
let ptr = bx.cx().type_ptr();
OperandValue::Ref(PlaceValue::new_sized(bx.const_poison(ptr), layout.align.abi))
match layout.backend_repr {
_ if layout.is_zst() => OperandValue::ZeroSized,
BackendRepr::Scalar(_)
| BackendRepr::SimdVector { .. }
| BackendRepr::SimdScalableVector { .. } => {
let ibty = bx.cx().immediate_backend_type(layout);
OperandValue::Immediate(bx.const_poison(ibty))
}
BackendRepr::ScalarPair { .. } => {
let ibty0 = bx.cx().scalar_pair_element_backend_type(layout, 0, true);
let ibty1 = bx.cx().scalar_pair_element_backend_type(layout, 1, true);
OperandValue::Pair(bx.const_poison(ibty0), bx.const_poison(ibty1))
}
BackendRepr::Memory { .. } => {
let ptr = bx.cx().type_ptr();
OperandValue::Ref(PlaceValue::new_sized(bx.const_poison(ptr), layout.align.abi))
}
}
}

Expand Down
10 changes: 6 additions & 4 deletions compiler/rustc_codegen_ssa/src/mir/retag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ use rustc_middle::ty::layout::TyAndLayout;
use crate::mir::FunctionCx;
use crate::mir::operand::{OperandRef, OperandRefBuilder, OperandValue};
use crate::mir::place::PlaceRef;
use crate::traits::{
BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, LayoutTypeCodegenMethods,
};
use crate::traits::{BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods};
use crate::{RetagFlags, RetagInfo};

pub(crate) fn rvalue_needs_retag(rvalue: &Rvalue<'_>) -> bool {
Expand Down Expand Up @@ -255,8 +253,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {

let field_layout = curr_operand.layout.field(bx, ix.index());
// Part of https://github.com/rust-lang/compiler-team/issues/838
if !bx.is_backend_ref(curr_operand.layout) && bx.is_backend_ref(field_layout) {
if curr_operand.layout.is_ssa_standalone() && !field_layout.is_ssa_standalone()
{
// FIXME: support vector types, requires insert_element as part of cg-ssa
// FIXME: Nothing should be looking at the *array* inside a `repr(simd)` type,
// as that array doesn't really exist. Perhaps this should be a `bug!`,
// with simd types handled before getting here?
} else {
let field_operand = curr_operand.extract_field(self, bx, ix.as_usize());
self.retag_operand(bx, &plan, field_operand, builder, field_offset);
Expand Down
Loading
Loading