denoland/deno · error · syn::Error

cppgc_inherits_from specified more than once

Error message

cppgc_inherits_from specified more than once

What it means

Thrown by the `CppgcInherits` derive macro (deno_core's cppgc garbage-collector bridge). `parse_base_attr` in libs/ops/cppgc.rs scans the type's attributes for `#[cppgc_inherits_from(Base)]`, stores the first match, and raises this compile error on the span of any second occurrence because a cppgc-managed type can declare exactly one C++ base class.

Source

Thrown at libs/ops/cppgc.rs:174

      {
        return Ok(());
      }
    }
  }
  Err(Error::new(
    span,
    "cppgc inheritance requires #[repr(C)] on the type",
  ))
}

fn parse_base_attr(attrs: &[Attribute]) -> Result<Type> {
  let mut found = None;
  for attr in attrs {
    if !attr.path().is_ident("cppgc_inherits_from") {
      continue;
    }
    if found.is_some() {
      return Err(Error::new(
        attr.span(),
        "cppgc_inherits_from specified more than once",
      ));
    }
    let base = attr.parse_args::<Type>()?;
    found = Some(base);
  }
  found.ok_or_else(|| {
    Error::new(
      proc_macro2::Span::call_site(),
      "derive(CppgcInherits) requires #[cppgc_inherits_from(BaseType)]",
    )
  })
}

#[derive(Clone)]
enum FieldRef {
  Named(Ident, proc_macro2::Span),

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Delete all but one `#[cppgc_inherits_from(...)]` attribute on the type, keeping the direct base you actually wrap.
  2. If the type genuinely needs two bases, introduce an intermediate Rust/C++ base type that itself derives `CppgcInherits` from the grandparent, and inherit from that single intermediate.
  3. After a merge conflict, grep the file for `cppgc_inherits_from` and make sure only one attribute survives.

Example fix

// before
#[derive(CppgcInherits, CppgcBase)]
#[cppgc_inherits_from(DOMPointReadOnly)]
#[cppgc_inherits_from(CSSStyleValue)]
struct DOMPoint { /* ... */ }

// after
#[derive(CppgcInherits, CppgcBase)]
#[cppgc_inherits_from(DOMPointReadOnly)]
struct DOMPoint { /* ... */ }
Defensive patterns

Strategy: validation

Validate before calling

# In CI or a pre-commit check, flag types with more than one cppgc_inherits_from:
# (grep-based guard; the real enforcement is the compile error itself)
! grep -rn --include='*.rs' -E '^[[:space:]]*#\[cppgc_inherits_from' path/to/file | awk -F: '{print $1}' | uniq -c | awk '$1 > 1 { exit 1 }'

Prevention

When it happens

Trigger: Annotating one type with two `#[cppgc_inherits_from(...)]` helper attributes: `#[derive(CppgcInherits)] #[cppgc_inherits_from(A)] #[cppgc_inherits_from(B)] struct X;` — the error span points at the duplicate attribute.

Common situations: Copy-pasting an existing cppgc type (e.g. the DOMPoint example in ext/web/geometry.rs) and adding a new base without removing the old attribute; merge conflicts that leave both versions of the attribute; attempting multiple inheritance, which cppgc does not support.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/adb1b4df340330ad. Report an issue: GitHub.