{"id":"26ab00a9bdfec2c6","repo":"rust-lang/rust","slug":"mask-should-be-of-struct-type","errorCode":null,"errorMessage":"mask should be of struct type","messagePattern":"mask should be of struct type","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler/rustc_codegen_gcc/src/builder.rs","lineNumber":2065,"sourceCode":"            self.int_type\n        };\n\n        // NOTE: this condition is needed because we call shuffle_vector in the implementation of\n        // simd_gather.\n        let mut mask_elements = if let Some(vector_type) = mask.get_type().dyncast_vector() {\n            let mask_num_units = vector_type.get_num_units();\n            let mut mask_elements = vec![];\n            for i in 0..mask_num_units {\n                let index = self.context.new_rvalue_from_long(self.cx.type_u32(), i as _);\n                mask_elements.push(self.context.new_cast(\n                    self.location,\n                    self.extract_element(mask, index).to_rvalue(),\n                    mask_element_type,\n                ));\n            }\n            mask_elements\n        } else {\n            let struct_type = mask.get_type().is_struct().expect(\"mask should be of struct type\");\n            let mask_num_units = struct_type.get_field_count();\n            let mut mask_elements = vec![];\n            for i in 0..mask_num_units {\n                let field = struct_type.get_field(i as i32);\n                mask_elements.push(self.context.new_cast(\n                    self.location,\n                    mask.access_field(self.location, field).to_rvalue(),\n                    mask_element_type,\n                ));\n            }\n            mask_elements\n        };\n        let mask_num_units = mask_elements.len();\n\n        // NOTE: the mask needs to be the same length as the input vectors, so add the missing\n        // elements in the mask if needed.\n        for _ in mask_num_units..vec_num_units {\n            mask_elements.push(self.context.new_rvalue_zero(mask_element_type));","sourceCodeStart":2047,"sourceCodeEnd":2083,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_codegen_gcc/src/builder.rs#L2047-L2083","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","Upgrade libgccjit to a recent master build so shuffle masks are represented as proper vector/struct types.","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.","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."],"exampleFix":"// before\nlet r: Simd<f32, 3> = simd_shuffle!(a, b, [0, 2, 5]); // non-power-of-two mask\n// after\nlet r: Simd<f32, 4> = simd_shuffle!(a, b, [0, 2, 1, 3]); // power-of-two vector mask","handlingStrategy":"type-guard","validationCode":"// In shuffle_vector, when the mask is NOT itself a vector, the code asserts\n// mask.get_type().is_struct().expect(\"mask should be of struct type\").\n// Validate the mask shape BEFORE calling shuffle_vector.\nfn valid_shuffle_mask<'gcc>(mask: RValue<'gcc>) -> Result<(), String> {\n    let ty = mask.get_type();\n    if ty.dyncast_vector().is_some() {\n        return Ok(()); // vector mask is fine\n    }\n    if ty.is_struct().is_some() {\n        return Ok(()); // struct mask is fine\n    }\n    Err(format!(\"shuffle_vector mask must be a vector or struct type, got {:?}\", ty))\n}\n\nvalid_shuffle_mask(mask)?;\nlet r = bx.shuffle_vector(v1, v2, mask);","typeGuard":"// Accept only vector- or struct-shaped masks.\nfn is_acceptable_mask<'gcc>(mask: RValue<'gcc>) -> bool {\n    let ty = mask.get_type();\n    ty.dyncast_vector().is_some() || ty.is_struct().is_some()\n}\n\nif !is_acceptable_mask(mask) {\n    return Err(\"mask must be a vector or struct type\");\n}\nlet r = bx.shuffle_vector(v1, v2, mask);","tryCatchPattern":null,"preventionTips":["Construct SIMD shuffle masks only via new_rvalue_from_vector (vector mask) or as a struct aggregate (struct mask); never a bare scalar/integer.","Remember the mask is taken in two shapes: a vector of indices OR a struct of fields; anything else hits the expect panic.","Keep mask element count aligned with the input vector lane count; the guard checks shape, not length."],"tags":["rust","codegen-gcc","simd","shuffle","mask","panic"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}