Skip to content

fix: use the latest value when a macro is redefined - #3409

Open
dhmztr wants to merge 1 commit into
rust-lang:mainfrom
dhmztr:fix/macro-redefinition-latest-value
Open

fix: use the latest value when a macro is redefined#3409
dhmztr wants to merge 1 commit into
rust-lang:mainfrom
dhmztr:fix/macro-redefinition-latest-value

Conversation

@dhmztr

@dhmztr dhmztr commented Jul 28, 2026

Copy link
Copy Markdown

Summary

Fixes #2722.

When a C header redefines a macro (#define A 1 ... later ... #define A 2), bindgen emitted pub const A: ... = 1; — the value from the first definition — instead of the last one.

ctx.parsed_macros already tracked the latest value internally (used when evaluating other macro expressions that reference the redefined macro), but Var::parse bailed out on redefinition before ever updating the already-emitted Var item, so the first-defined value stuck around in the generated bindings.

Change

On redefinition, Var::parse now finds the already-emitted Var item by name and updates its type/value in place (via new BindgenContext::resolve_item_mut and ItemKind::as_var_mut accessors), returning ParseResult::AlreadyResolved instead of silently discarding the redefinition.

The existing macro-redef.h / macro-redef.rs test pair already encoded this exact bug (FOO was expected to be 4, the first definition, while BAR/BAZ, which are expressions referencing FOO, were already correctly computed using the latest value). Updated the expectation so FOO is now 5, matching the last definition.

Scope note

#undef handling (raised in the issue thread) is intentionally left out of scope: libclang's CXCursor enum has no MacroUndef/undefinition kind, so #undef directives aren't observable via the cursor-based traversal bindgen currently uses. There's already a maintainer FIXME in var.rs acknowledging this same limitation. This PR implements "latest definition wins," which is what was explicitly endorsed in the issue thread.

Test plan

  • macro-redef.rs expectation updated and passing
  • Full bindgen-tests corpus (624 headers) passes, aside from 2 pre-existing unrelated failures confirmed present on unmodified main (a const-generics codegen difference tied to this environment's Rust/clang toolchain versions, and a dump_preprocessed_input test that needs the clang CLI binary rather than just libclang)
  • cargo clippy -- -D warnings clean
  • Manually confirmed the only other macro name collisions in the test corpus (RTE_STD_C11, several JSVAL_TAG_*) are mutually-exclusive #if/#elif branches, not real redefinitions, so this change doesn't affect them

Previously, when a C macro was redefined (e.g. `#define A 1` followed
later by `#define A 2`), bindgen kept the value from the *first*
definition when emitting the corresponding `pub const`, even though
`ctx.parsed_macros` already tracked the latest value internally for
evaluating other macro expressions.

`Var::parse` now looks up the already-emitted `Var` item for a
redefined macro and updates its value/type in place instead of
discarding the redefinition, so the generated constant reflects the
same value that later code in the header (and any macro expressions
referencing it) would actually see.

`#undef` is intentionally out of scope: libclang's cursor API has no
`CXCursor_MacroUndef` kind, so `#undef` directives cannot currently be
observed via cursor traversal.

Fixes rust-lang#2722
Copilot AI review requested due to automatic review settings July 28, 2026 19:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@ojeda

ojeda commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Fixes #2722.

#undef handling (raised in the issue thread) is intentionally left out of scope

In that case, I can open a new issue for that if this closes the one we have.

@dhmztr

dhmztr commented Jul 28, 2026

Copy link
Copy Markdown
Author

Yeah please do, but keep in mind libclang doesn't expose undef cursor kind at all, so it needs a different approach than cursor traversal, (token-level preprocessing scan or something similiar)

@ojeda ojeda mentioned this pull request Jul 28, 2026
@ojeda

ojeda commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Done! #3413

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Undefined/redefined C macro keeps old value

3 participants