{"id":"29c53c7fd66c5a20","repo":"rust-lang/rust","slug":"get-element-type","errorCode":null,"errorMessage":"get element type","messagePattern":"get element type","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler/rustc_codegen_gcc/src/int.rs","lineNumber":104,"sourceCode":"                    std::cmp::Ordering::Equal => a >> b,\n                    _ => {\n                        // NOTE: it is OK to cast even if b has a type bigger than a because b has\n                        // been masked by codegen_ssa before calling Builder::lshr or\n                        // Builder::ashr.\n                        let b = self.context.new_cast(self.location, b, a_type);\n                        a >> b\n                    }\n                }\n            }\n        } else if a_type.is_vector() && b_type.is_vector() {\n            a >> b\n        } else if a_native && !b_native {\n            self.gcc_lshr(a, self.gcc_int_cast(b, a_type))\n        } else {\n            // NOTE: we cannot use the lshr builtin because it's calling hi() (to get the most\n            // significant half of the number) which uses lshr.\n\n            let native_int_type = a_type.dyncast_array().expect(\"get element type\");\n\n            let func = self.current_func();\n            let then_block = func.new_block(\"then\");\n            let else_block = func.new_block(\"else\");\n            let after_block = func.new_block(\"after\");\n            let b0_block = func.new_block(\"b0\");\n            let actual_else_block = func.new_block(\"actual_else\");\n\n            let result = func.new_local(self.location, a_type, \"shiftResult\");\n\n            let sixty_four = self.gcc_int(native_int_type, 64);\n            let sixty_three = self.gcc_int(native_int_type, 63);\n            let zero = self.gcc_zero(native_int_type);\n            let b = self.gcc_int_cast(b, native_int_type);\n            let condition = self.gcc_icmp(IntPredicate::IntNE, self.gcc_and(b, sixty_four), zero);\n            self.llbb().end_with_conditional(self.location, condition, then_block, else_block);\n\n            let shift_value = self.gcc_sub(b, sixty_four);","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_codegen_gcc/src/int.rs#L86-L122","documentation":"Raised inside the fallback branch of `Builder::gcc_lshr` (logical right-shift) for non-native integer operands. When neither `a` nor `b` is a native int and the vector-of-two-vectors path does not apply, the code assumes the operand type is an i128/u128 represented as a two-element array and calls `dyncast_array()` to recover the element (i64/u64) type. A `None` result means a non-array type reached this branch.","triggerScenarios":"`Builder::gcc_lshr(a, b)` is invoked with `a_type` failing `is_native_int_type`, `a_type.is_vector()` false, `b` non-native, and `a_type.dyncast_array()` returning `None`. Typically hit when shifting a 128-bit value on a target where the type is not actually materialized as a 2-element array.","commonSituations":"ICE during codegen of `>>` on i128/u128 on a 32-bit target, after upgrading libgccjit (array representation may have changed), or after a bug in `TypeReflection::is_non_native_int_type` mislabels a non-int (e.g. a pointer or aggregate) as a non-native int.","solutions":["Add an `eprintln!` of `a_type` (and `{:?}`) at the entry to the non-native branch to identify the unexpected type.","Audit callers of `gcc_lshr` in the codegen SSA layer to ensure `b` is always cast to `a_type` (or a native int) before this point.","Re-check `is_native_int_type` / `is_non_native_int_type` helpers for the target's pointer width — an i128 on a 64-bit target should be native.","Confirm libgccjit version: the array-of-two representation is a workaround and is sensitive to libgccjit's handling of 128-bit integers."],"exampleFix":"// before\nlet native_int_type = a_type.dyncast_array().expect(\"get element type\");\n\n// after\nlet native_int_type = a_type.dyncast_array().unwrap_or_else(|| {\n    panic!(\"gcc_lshr: non-native operand is not an i128 array: {:?}\", a_type);\n});","handlingStrategy":"type-guard","validationCode":"// gcc_lshr's emulation branch needs a_type.dyncast_array(). Reject mixed\n// native/non-native operand pairs before shifting.\nlet a_type = a.get_type();\nlet b_type = b.get_type();\nlet a_native = builder.is_native_int_type(a_type);\nlet b_native = builder.is_native_int_type(b_type);\nif !a_native && a_type.dyncast_array().is_none() {\n    return Err(\"lshr: left operand is neither native int nor an array type\");\n}\nif a_native != b_native && !(a_type.is_vector() && b_type.is_vector()) {\n    // cast b to a's native type first to stay on the native shift path\n    let b = builder.gcc_int_cast(b, a_type);\n}","typeGuard":"/// True when a >> b can take the gcc_lshr native/vector path without\n/// falling into the dyncast_array emulation branch.\nfn is_safe_lshr_pair<'gcc>(\n    &self,\n    a_type: gccjit::Type<'gcc>,\n    b_type: gccjit::Type<'gcc>,\n) -> bool {\n    let a_native = self.is_native_int_type(a_type);\n    let b_native = self.is_native_int_type(b_type);\n    (a_native && b_native)\n        || (a_type.is_vector() && b_type.is_vector())\n        || (a_native && !b_native)\n        || a_type.dyncast_array().is_some() // emulation branch is valid for arrays\n}","tryCatchPattern":null,"preventionTips":["Keep both shift operands the same signedness and width so gcc_lshr stays on the native path and never reaches the dyncast_array fallback.","Mask the shift amount (b & (width-1)) at the SSA layer before codegen, as codegen_ssa already does; a stray unmasked b on a non-native type forces the array path.","Avoid logical-right-shifting a value whose type the backend reports as non-native but cannot dyncast to an array (mis-built 128-bit value)."],"tags":["rustc-codegen-gcc","ice","i128","lshr","libgccjit"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}