Skip to content

codegen: stop blanket allow(warnings) from hiding embedded Rust diagnostics #359

Description

@tinovyatkin

Summary

Every generated lexer/parser currently wraps the entire generated module and
its public re-export in blanket warning suppression:

#[allow(warnings, missing_docs, clippy::all, clippy::pedantic, clippy::nursery)]
#[rustfmt::skip]
mod __antlr4_rust_generated {
    // generated scaffolding and embedded user-authored Rust
}

The header is emitted by
generated_module_header.

allow(warnings) solved the consumer problem reported in #29: generated code
must be drop-in under strict lint configurations. It also suppresses useful
compiler diagnostics from:

  • embedded actions, predicates, @members, and future supported named
    sections;
  • generator mistakes such as ignored Result values;
  • deprecated API use and future-compatibility warnings.

Narrow the suppression contract while preserving #29's drop-in behavior.

Why this matters

warnings is the lint group containing all warning-by-default rustc lints.
An inner allow(warnings) can override a consumer's outer deny(...) for code
inside the generated module, unless the consumer uses forbid.

For embedded Rust, the generated file is also the user's source file from
rustc's perspective. A body such as:

some_fallible_operation(); // Result is ignored

should remain visible under unused_must_use rather than being silently
accepted because the generator needed dead_code or naming allowances for its
own scaffolding.

The sdf-labs/antlr4 template uses a finite set of targeted lint allowances.
Its exact list should not be copied, but it demonstrates the preferable
ownership boundary.

Goal

Remove blanket allow(warnings) from generated output and replace it with the
smallest stable set of targeted allowances needed by generated scaffolding.

Possible approaches:

  • inventory and allow only expected rustc lints such as generated naming,
    dead-code, and unused generated imports/variables;
  • attach allowances to generated items/macros rather than the whole module;
  • isolate user-authored embedded bodies into scopes which do not inherit broad
    generated-code allowances;
  • use targeted #[expect(...)] only where the emitted shape guarantees the
    lint, provided this does not create version-sensitive unfulfilled
    expectations.

Keep #[rustfmt::skip]; formatting stability is a separate requirement from
warning visibility.

Required investigation

  • Compile the full generated fixture corpus under the exact CI command and
    record every rustc/clippy lint which currently depends on the blanket allow.
  • Separate unavoidable grammar-derived naming lints from renderer defects which
    should be fixed instead of allowed.
  • Check generated lexer/parser modules with and without listener/visitor,
    embedded/template actions, attrs, hooks, unreachable rules, and empty
    semantics.
  • Verify downstream crates with #![deny(warnings)],
    #![deny(unused_must_use)], and #![deny(deprecated)].

Acceptance criteria

  • Newly generated files contain no blanket allow(warnings).
  • The allow list is targeted and documented by ownership/purpose.
  • Generated code remains drop-in under the repository's exact
    cargo clippy --locked --workspace --all-targets --all-features -- -D warnings
    gate.
  • A fixture with ignored #[must_use]/Result output in embedded
    user-authored Rust fails under deny(unused_must_use).
  • A fixture using a deprecated item in embedded user-authored Rust remains
    observable under deny(deprecated).
  • Ordinary grammar-derived naming and unused generated helpers do not force
    downstream wrapper modules or lint configuration.
  • Checked-in generated recognizers are regenerated, and compatibility
    snapshots remain intentional.
  • Any generated-code API revision change follows AGENTS.md; a lint-only
    source change must not bump it automatically.

Related

Non-goals

  • Making generated source satisfy every optional Clippy lint without any
    allowances.
  • Removing rustfmt::skip.
  • Emitting warnings for target-language bodies which are not Rust; those should
    be rejected or handled by the semantic accountability issue instead.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions