Skip to content

remote-derive: prefix every generated binding with __buffa_ - #693

Open
0xSh1mm3r wants to merge 2 commits into
anthropics:mainfrom
0xSh1mm3r:fix/remote-derive-shadowed-names
Open

0xSh1mm3r wants to merge 2 commits into
anthropics:mainfrom
0xSh1mm3r:fix/remote-derive-shadowed-names

Conversation

@0xSh1mm3r

Copy link
Copy Markdown

Fixes #652.

What

The five buffa-remote-derive derives, and their arbitrary impls, bound method parameters with plain names: iter, v, s, payload, value, key and u. All of these now start with __buffa_ (__buffa_iter, __buffa_vec, __buffa_str, __buffa_string, __buffa_payload, __buffa_value, __buffa_key, __buffa_unstructured). That is the prefix the crate already reserves for its generated lifetimes, type parameters and serde/arbitrary bindings.

Why

An identifier pattern that names a constant in scope is a constant pattern, not a new binding. So any of these items beside a derive made a parameter a pattern of the wrong type:

  • a constant, e.g. const v: u8 = 0;
  • a const generic, e.g. struct L<T, const iter: usize>(Vec<T>)
  • a unit struct with one of those names

Each case failed with E0308 inside the derive, and the error did not name the cause. A static or tuple struct with one of those names fails the same way, with E0530. payload, in from_wire of ProtoString and ProtoBytes, was affected as well, although the issue does not list it.

A related problem: a one-segment override path with one of those names, such as new = value or insert = key, resolved to the parameter. The crate docs asked for a path of two or more segments to work around it. This PR drops that restriction.

Span::mixed_site() would not have fixed the constant case. Mixed-site hygiene resolves only locals, labels and $crate at the definition site. Constants are items, so they still resolve at the call site. A macro_rules! macro, which has the same hygiene, hits the same E0308.

Implementation

  • list.rs, string.rs, bytes.rs, map.rs, box_ptr.rs, forwarders.rs: rename the bindings. string.rs loses ctor_from_wire, which was the same tokens as ctor_from_str and can now share it.
  • lib.rs: "Reserved identifiers" now covers every name the impls introduce, and every item in scope at the derive. The paragraph that asked for multi-segment override paths is removed.
  • New unit test every_binding_starts_with_the_reserved_prefix. It walks each expansion with syn::visit, covering tuple and named-field structs and every override key, and checks that each PatIdent starts with __buffa_. This means a future plain-named parameter, closure parameter or let fails a test. syn's visit feature is enabled for dev-dependencies only, so the shipped proc macro does not build it.
  • New integration test tests/shadowed_names.rs. It declares lower-case constants, const generics, a static, a unit struct and a tuple struct with every old parameter name. It also uses one-segment new = value, new = u and insert = key overrides, and exercises each derive at runtime. Before the fix it fails to compile with 64 errors.

Testing

  • cargo fmt --all --check
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test --workspace (protoc 33.5)
  • RUSTDOCFLAGS="-D warnings" cargo doc -p buffa-remote-derive --no-deps
  • cargo clippy -p buffa-test --all-targets --features arbitrary -- -D warnings and cargo test -p buffa-test --features arbitrary --lib --tests

Follow-ups (not in this PR)

Review turned up two older holes of a different kind, which I would file separately:

  • The expansions spell str, u8 and usize without a path, so a user type with one of those names in scope breaks them. Codegen fixed the same class of problem in codegen: support types named after Rust keywords and primitives #556. Here the fix would be ::core::primitive::*.
  • __buffa_payload.to_str() and .as_slice() use method-call syntax. A trait in scope with a by-value method of the same name, implemented for WirePayload, would win method resolution. The fix is the fully qualified form the crate already uses for as_ref.

🤖 Generated with Claude Code

0xSh1mm3r and others added 2 commits October 10, 2026 19:56
The derives bound method parameters named `iter`, `v`, `s`, `payload`,
`value`, `key` and `u`. An identifier pattern that names a constant in
scope is a constant pattern, so a constant, const generic, static, unit
struct or tuple struct with one of those names made the parameter a
pattern of the wrong type (E0308 or E0530 inside the derive). A
one-segment override path with one of those names resolved to the
parameter.

Every binding now starts with `__buffa_`, the prefix the crate already
reserves. `Span::mixed_site()` does not help here: a constant is an item,
and items resolve at the call site under mixed-site hygiene.

Fixes anthropics#652.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@0xSh1mm3r

Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

github-actions Bot added a commit that referenced this pull request Oct 10, 2026

This branch has not been deployed

No deployments
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.

remote-derive: a constant named iter, v, s, value, key or u in scope breaks the generated impls

1 participant