denoland/deno · error · syn::Error
cppgc inheritance requires at least one field
Error message
cppgc inheritance requires at least one field
What it means
#[derive(CppgcInherits)] with #[cppgc_inherits_from(Base)] models C++-style inheritance by embedding the base as the first field; the derive grabs that first field to build the transitive-base plumbing (field_path/field_ty_span used for the offset assertions). If the struct has no fields at all, first_field() returns None and this compile error fires on the type's span — an empty struct cannot inherit anything.
Source
Thrown at libs/ops/cppgc.rs:58
attrs,
..
} = input;
let base = parse_base_attr(&attrs)?;
let mut impl_generics = generics.clone();
impl_generics.params.push(parse_quote!(__TransitiveBase));
let where_clause = impl_generics.make_where_clause();
where_clause
.predicates
.push(parse_quote!(#base: deno_core::cppgc::Inherits<__TransitiveBase>));
where_clause
.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) =View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Add the base field first, exactly as the derive requires: struct Square { base: Shape } — the base type named in #[cppgc_inherits_from(...)].
- If the type is not meant to inherit, remove #[derive(CppgcInherits)] and the #[cppgc_inherits_from] attribute.
Example fix
// before
#[derive(CppgcInherits)]
#[cppgc_inherits_from(Shape)]
#[repr(C)]
pub struct Square; // error: cppgc inheritance requires at least one field
// after
#[derive(CppgcInherits)]
#[cppgc_inherits_from(Shape)]
#[repr(C)]
pub struct Square {
base: Shape,
} Defensive patterns
Strategy: validation
Prevention
- Start every CppgcInherits struct from the template: #[repr(C)] + a first field holding the #[cppgc_inherits_from(...)] base type.
- Don't stub derived classes empty — the base field is mandatory, not optional.
When it happens
Trigger: Declaring #[derive(CppgcInherits)] #[cppgc_inherits_from(Shape)] struct Square; (or struct Square {}) — a derived cppgc class with zero fields.
Common situations: Starting to port a JS-exposed native class and stubbing the struct empty before adding the base field; deleting all fields during a refactor and forgetting the derive now needs a base.
Related errors
- first field must be the base type for cppgc inheritance
- 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/21cb1e480534defb.
Report an issue: GitHub.