rust-lang/rust · error

mask should be of struct type

Error message

mask should be of struct type

What it means

Panicked by `.expect("mask should be of struct type")` inside `Builder::shuffle_vector` (master feature) at rustc_codegen_gcc/src/builder.rs:2065. After confirming the mask is not a GCC vector type (the `dyncast_vector()` branch above failed), the code falls back to treating it as a struct so it can iterate fields. If `is_struct()` also returns `None`, the mask is some other kind of type (scalar, union, opaque) and the shuffle cannot be reconstructed.

Source

Thrown at compiler/rustc_codegen_gcc/src/builder.rs:2065

            self.int_type
        };

        // NOTE: this condition is needed because we call shuffle_vector in the implementation of
        // simd_gather.
        let mut mask_elements = if let Some(vector_type) = mask.get_type().dyncast_vector() {
            let mask_num_units = vector_type.get_num_units();
            let mut mask_elements = vec![];
            for i in 0..mask_num_units {
                let index = self.context.new_rvalue_from_long(self.cx.type_u32(), i as _);
                mask_elements.push(self.context.new_cast(
                    self.location,
                    self.extract_element(mask, index).to_rvalue(),
                    mask_element_type,
                ));
            }
            mask_elements
        } else {
            let struct_type = mask.get_type().is_struct().expect("mask should be of struct type");
            let mask_num_units = struct_type.get_field_count();
            let mut mask_elements = vec![];
            for i in 0..mask_num_units {
                let field = struct_type.get_field(i as i32);
                mask_elements.push(self.context.new_cast(
                    self.location,
                    mask.access_field(self.location, field).to_rvalue(),
                    mask_element_type,
                ));
            }
            mask_elements
        };
        let mask_num_units = mask_elements.len();

        // NOTE: the mask needs to be the same length as the input vectors, so add the missing
        // elements in the mask if needed.
        for _ in mask_num_units..vec_num_units {
            mask_elements.push(self.context.new_rvalue_zero(mask_element_type));

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Rebuild with the LLVM backend (`-C codegen-backend=llvm`) to confirm the code is valid; if LLVM accepts it, this is a codegen_gcc bug to report.
  2. Upgrade libgccjit to a recent master build so shuffle masks are represented as proper vector/struct types.
  3. Rewrite the SIMD op to use `std::simd::Simd::swizzle` or explicit element-by-element selection, avoiding shuffle-mask constants with shapes libgccjit cannot represent.
  4. Reduce lane count to a power of two and standard width (e.g. `<4, f32>`, `<8, i8>`) which libgccjit models as a true vector, skipping the struct fallback.

Example fix

// before
let r: Simd<f32, 3> = simd_shuffle!(a, b, [0, 2, 5]); // non-power-of-two mask
// after
let r: Simd<f32, 4> = simd_shuffle!(a, b, [0, 2, 1, 3]); // power-of-two vector mask
Defensive patterns

Strategy: type-guard

Validate before calling

// In shuffle_vector, when the mask is NOT itself a vector, the code asserts
// mask.get_type().is_struct().expect("mask should be of struct type").
// Validate the mask shape BEFORE calling shuffle_vector.
fn valid_shuffle_mask<'gcc>(mask: RValue<'gcc>) -> Result<(), String> {
    let ty = mask.get_type();
    if ty.dyncast_vector().is_some() {
        return Ok(()); // vector mask is fine
    }
    if ty.is_struct().is_some() {
        return Ok(()); // struct mask is fine
    }
    Err(format!("shuffle_vector mask must be a vector or struct type, got {:?}", ty))
}

valid_shuffle_mask(mask)?;
let r = bx.shuffle_vector(v1, v2, mask);

Type guard

// Accept only vector- or struct-shaped masks.
fn is_acceptable_mask<'gcc>(mask: RValue<'gcc>) -> bool {
    let ty = mask.get_type();
    ty.dyncast_vector().is_some() || ty.is_struct().is_some()
}

if !is_acceptable_mask(mask) {
    return Err("mask must be a vector or struct type");
}
let r = bx.shuffle_vector(v1, v2, mask);

Prevention

When it happens

Trigger: A `simd_shuffle`/`shuffle_vector` call whose mask constant was lowered to a non-vector, non-struct GCC rvalue (e.g. an integer constant, array, or pointer) by an earlier codegen step. Most often seen with unusual lane counts or when the LLVM shuffle mask shape does not map cleanly onto libgccjit's type system.

Common situations: Hand-written SIMD intrinsics (`core::intrinsics::simd_shuffle*`) on the gcc backend. Mixing inline asm or arbitrary integer masks with SIMD ops. Older libgccjit versions that represent masks differently.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/26ab00a9bdfec2c6.json. Report an issue: GitHub.