Skip to content

Item-level lint control attributes: #[allow]/#[warn]/#[deny] + lint-level source map #13395

Description

@AztecBot

Part of epic #7460. Closes the core of #12323. Depends on #7461 (lint slugs).

Goal

Generalise the existing ad-hoc #[allow(<slug>)] into a proper item-scoped lint-level mechanism supporting #[allow], #[warn], and #[deny], resolved through a single code path so it can later cover backend warnings too (#[expect] is intentionally out of scope for now).

Background — what exists today

SecondaryAttributeKind::Allow(String) already parses (parser/parser/attributes.rs) and is consumed ad-hoc at ~5 sites, each hand-rolling has_allow/is_allow:

  • dead_code on functions/structs/enums/traits — hir/def_collector/dc_mod.rs, elaborator/impls.rs
  • unused_variables, unused_mut on let statements — elaborator/statements.rs:223-225

Limitations: no central registry, typo'd slugs silently no-op, single name only (parse_single_name_attribute), allow only (no warn/deny), and no nesting/override semantics.

Scope

  1. Attribute surface. Add warn/deny alongside allow (parser + SecondaryAttributeKind); support name lists #[allow(a, b)]. Attachment sites: items + let statements only for this issue — broader attachment (blocks/expressions/match arms) is deliberate follow-up.
  2. Tag diagnostics. Add lint: Option<Lint> to CustomDiagnostic (noirc_errors/src/reporter.rs) and set it on the frontend "opinionated" warnings (unused var/item, unused mut, unnecessary pub/unsafe, unreachable code/match, unnecessary trait constraint, unbounded recursion, …). Uses the slugs from Attach a human-readable code for each error variant. #7461.
  3. Lint-level source map. During elaboration/def-collection, record every lint attribute into a persisted structure { node span, lint, level, attr location } (analogous to the existing FunctionLocations that already rides into noirc_errors).
  4. Single resolution point. Replace the scattered has_allow checks with one pass (in/around report_all): for each diagnostic with a lint, find the innermost enclosing lint-level entry containing the diagnostic's location and apply it — allow drops, warn keeps, deny upgrades kind to Error. Innermost wins → nesting + override for free.
  5. Global-flag precedence. An item-level allow/deny wins over the global --deny-warnings / --silence-warnings flags (rustc cap-lint intuition). Document the precedence.

Acceptance

  • #[allow(dead_code)] / #[allow(unused_variables)] / #[allow(unused_mut)] behave exactly as today (migrated, not regressed).
  • #[deny(unused_variables)] turns that warning into a compile error on the annotated item; #[warn(...)] overrides an outer #[allow(...)].
  • An unrecognised slug reports via the unknown_lint lint (from Attach a human-readable code for each error variant. #7461) instead of silently no-op'ing.
  • Item-level #[allow(...)] suppresses even under --deny-warnings.

Full design + file-by-file notes: https://gist.github.com/AztecBot/85187c49f6c5286d72df0980d8aed46a

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions