denoland/deno · error · syn::Error
first field must be the base type for cppgc inheritance
Error message
first field must be the base type for cppgc inheritance
What it means
After finding the first field, the CppgcInherits derive verifies its type is exactly the base named in #[cppgc_inherits_from(Base)] (types_equal check) because the generated offset/layout code assumes field 0 IS the base subobject. A first field of any other type — or the right base placed second — fails with this compile error pointing at the field's type span.
Source
Thrown at libs/ops/cppgc.rs:70
.predicates
.push(parse_quote!(__TransitiveBase: deno_core::cppgc::Base));
ensure_repr_c(&attrs, ident.span())?;
let first_field = first_field(&data).ok_or_else(|| {
Error::new(
ident.span(),
"cppgc inheritance requires at least one field",
)
})?;
let (field_path, field_ty_span) = match &first_field.field {
FieldRef::Named(ident, ty_span) => (quote!(#ident), *ty_span),
FieldRef::Unnamed(idx, ty_span) => (quote!(#idx), *ty_span),
};
if !types_equal(&first_field.ty, &base) {
return Err(Error::new(
field_ty_span,
"first field must be the base type for cppgc inheritance",
));
}
let (transitive_impl_generics, _, transitive_where_clause) =
impl_generics.split_for_impl();
let (base_impl_generics, base_ty_generics, base_where_clause) =
generics.split_for_impl();
let offset_assert = quote! {
const _: () = {
const OFFSET: usize = ::core::mem::offset_of!(#ident #base_ty_generics, #field_path);
assert!(OFFSET == 0, "base field must be at offset 0");
};
};
let size_align_assert = quote! {
const _: () = {View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Move the base to be the literal first field: struct Rectangle { base: Shape, width: GcCell<f64> }.
- Make the first field's type token-for-token the same type you passed to #[cppgc_inherits_from(...)] — no aliases, references, or Boxes.
- If you changed the base type, update #[cppgc_inherits_from(...)] and #[op2(inherit = ...)] to match.
Example fix
// before
#[derive(CppgcInherits)]
#[cppgc_inherits_from(Shape)]
#[repr(C)]
pub struct Rectangle {
width: GcCell<f64>, // error: first field must be the base type for cppgc inheritance
base: Shape,
}
// after
#[derive(CppgcInherits)]
#[cppgc_inherits_from(Shape)]
#[repr(C)]
pub struct Rectangle {
base: Shape, // first field, exact base type
width: GcCell<f64>,
} Defensive patterns
Strategy: validation
Prevention
- Always put the base field first and type it exactly as the #[cppgc_inherits_from(...)] argument — no aliases, boxes, or references.
- When renaming a base type, update the derive attribute, the first field's type, and #[op2(inherit = ...)] in one commit.
When it happens
Trigger: struct Rectangle { width: GcCell<f64>, base: Shape } (base not first), or struct Rectangle { shape: Shape, ... } where the field is named differently than the attribute's type — the check is on the field's TYPE, so any first field whose type is not the exact #[cppgc_inherits_from(...)] argument triggers it.
Common situations: Reordering fields (Rust allows any order; the derive does not); renaming the base type or the attribute argument so they no longer match textually; using a type alias or wrapper (Box<Shape>) instead of the bare base type.
Related errors
- cppgc inheritance requires at least one field
- cppgc inheritance requires #[repr(C)] on the type
- FromV8 enum derive currently supports only unit and single-e
- Unions are not supported
- Unit fields are currently not supported
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/b67f5e98ca874e38.
Report an issue: GitHub.