{"id":"12b8e7bc2367099f","repo":"rust-lang/rust","slug":"pointee-type","errorCode":null,"errorMessage":"pointee type","messagePattern":"pointee type","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler/rustc_codegen_gcc/src/builder.rs","lineNumber":1218,"sourceCode":"\n    fn gep(\n        &mut self,\n        typ: Type<'gcc>,\n        ptr: RValue<'gcc>,\n        indices: &[RValue<'gcc>],\n    ) -> RValue<'gcc> {\n        // NOTE: due to opaque pointers now being used, we need to cast here.\n        let ptr = self.context.new_cast(self.location, ptr, typ.make_pointer());\n        let ptr_type = ptr.get_type();\n        let mut pointee_type = ptr.get_type();\n        // NOTE: we cannot use array indexing here like in inbounds_gep because array indexing is\n        // always considered in bounds in GCC (FIXME(antoyo): to be verified).\n        // So, we have to cast to a number.\n        let mut result = self.context.new_bitcast(self.location, ptr, self.sizet_type);\n        // FIXME(antoyo): if there were more than 1 index, this code is probably wrong and would\n        // require dereferencing the pointer.\n        for index in indices {\n            pointee_type = pointee_type.get_pointee().expect(\"pointee type\");\n            #[cfg(feature = \"master\")]\n            let pointee_size = {\n                let size = self.cx.context.new_sizeof(pointee_type);\n                self.context.new_cast(self.location, size, index.get_type())\n            };\n            #[cfg(not(feature = \"master\"))]\n            let pointee_size =\n                self.context.new_rvalue_from_int(index.get_type(), pointee_type.get_size() as i32);\n            result = result + self.gcc_int_cast(*index * pointee_size, self.sizet_type);\n        }\n        self.context.new_bitcast(self.location, result, ptr_type)\n    }\n\n    fn inbounds_gep(\n        &mut self,\n        typ: Type<'gcc>,\n        ptr: RValue<'gcc>,\n        indices: &[RValue<'gcc>],","sourceCodeStart":1200,"sourceCodeEnd":1236,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_codegen_gcc/src/builder.rs#L1200-L1236","documentation":"Thrown by rustc_codegen_gcc inside gep() (the lowering of LLVM-style getelementptr / pointer arithmetic). While walking each index, the backend computes the stride by calling pointee_type.get_pointee().expect(\"pointee type\") to advance by sizeof the pointed-to type. If the current GCC type is not a pointer (or libgccjit reports no pointee for it), the expect panics. It indicates pointer type information was lost - typically because the value was cast to a plain integer/byte pointer before GEP.","triggerScenarios":"Indexing into a pointer/array via GEP where the GCC type of the pointer has no recoverable pointee: e.g. GEP on a value bitcast through sizet_type (as gep itself does internally) without re-attaching element-type info, indexing a *const T whose T was erased by a prior opaque cast, or multi-index GEP where the FIXME note in the source says dereferencing is unimplemented. Most common with slices, arrays, and &[T] indexing under the gcc backend.","commonSituations":"libgccjit version where get_pointee() returns None for opaque/integer-cast pointers; code that does heavy raw-pointer arithmetic (parsers, allocators, FFI buffers) compiled with the gcc backend; gcc 13->14 opaque-pointer transition that stopped tagging pointee types on casts.","solutions":["Update/pin libgccjit to the version compatible with this rustc_codegen_gcc release (opaque-pointer get_pointee support is version-sensitive).","Avoid raw-pointer arithmetic through integer/usize casts; index typed &[T] or *const T directly so the element type is preserved through to GEP.","Switch the affected crate to the LLVM backend to confirm and bypass the gccjit-specific panic while it is reproduced.","File an issue / patch gep() in builder.rs to reconstruct the pointee type from the typ parameter (which carries the intended element type) instead of relying on get_pointee() (upstream)."],"exampleFix":"// before - pointer cast to usize loses pointee type before GEP\nlet p = x as usize;\nlet item = unsafe { &*(p as *const u8).add(offset * size) };\n\n// after - keep a typed pointer/slice so GEP has a pointee type\nlet slice: &[u8] = &data;\nlet item = &slice[offset * size];","handlingStrategy":"type-guard","validationCode":"// Avoid `ptr::from_exposed_addr` / int->reference casts that force cg_gcc\n// to derive a pointee type from an opaque integer (builder.rs:1218).\nlet re = regex::Regex::new(r\"(from_exposed_addr|transmute::<(?:usize|u\\d+),\\s*&)\").unwrap();\nif re.is_match(&src) { eprintln!(\"cg_gcc cannot infer pointee type; refactor to typed ptrs.\"); }","typeGuard":"// Always carry the pointee type in the pointer — never bare usize.\nfn typed_ptr<T>(p: *mut T) -> *mut T { p } // identity, but forces T to be known\n// Reject opaque-address APIs at the type level:\npub struct OpaqueAddr(pub usize); // do NOT transmute this to *mut T\npub struct TypedPtr<T>(*mut T);   // do use this instead","tryCatchPattern":"// Compile-time panic in cg_gcc; cannot be caught. Resolve by giving the\n// pointer a concrete pointee type or by compiling the crate with LLVM.","preventionTips":["Never reconstruct pointers from `usize` via `transmute` or `from_exposed_addr` under cg_gcc; use `ptr::with_addr` on a typed `*mut T`.","Keep the pointee type tied to the pointer across FFI boundaries — pass `*mut T`, not raw addresses.","Avoid `*mut ()` then `as *mut Concrete` chains; cast from the originally-typed pointer instead."],"tags":["rustc","gcc","gccjit","codegen","expect","pointer-arithmetic","gep","opaque-pointer"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}