google / google/zerocopy

[derive] Make generated-scope syntax validation an explicit capability

Open
#3,639 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
2.6k
Forks
179
Avg merge
1d 19h
Merged PRs (30d)
29

Description

## Motivation

The fixes for #3619 and #3633 validate caller syntax before replaying it in
generated scopes. In the #3633 fix, correctness currently depends on each
derive path remembering independently:

- which field types, generic parameters, predicates, or expressions are
copied;
- which exact helper names or prefixes exist in the destination scope;
- whether contextual names such as `Self` change meaning there;
- whether unresolved syntax (especially macros or `Verbatim`) can expand
differently; and
- whether syntax is evaluated more than once and therefore needs a stronger
specialized grammar.

This is easy to omit at a new replay site, and generated identifiers and
literal reserved-name lists can drift apart. The immediate fixes should land
independently; this issue tracks reducing that residual proof surface.

## Proposal

Represent “this syntax has been checked for this generated destination”
explicitly, rather than passing raw `syn::Type`/`syn::Expr` values from
validation into generation by convention. One possible shape is:

```rust
struct GeneratedScope {
exact_names: &'static [&'static str],
reserved_prefixes: &'static [&'static str],
rebinds_self: bool,
evaluation: Evaluation,
}

struct ValidatedCopiedType<'a> { /* private */ }
struct StableCopiedDiscriminant<'a> { /* private */ }
```

Constructors would perform the checks appropriate to that destination:
unresolved macro/`Verbatim` rejection, unqualified-name capture checks,
contextual-`Self` checks, and repeated-evaluation restrictions. Generators
which replay caller syntax should accept an opaque validated wrapper instead
of a raw AST node where practical.

Define generated names and their corresponding reservations from one registry
or scope descriptor, including prefix-generated names, so adding or renaming a
helper cannot silently leave validation stale.

Keep validation path-sensitive rather than introducing one global syntax
allowlist:

- syntax emitted unchanged in its original scope may need no restriction;
- copied field types need lexical-capture and contextual-name checks;
- expressions evaluated repeatedly need stability constraints; and
- enum discriminants need the stronger grammar introduced for #3619, not
merely #3633’s lexical checks.

## Suggested rollout

1. Inventory every place `zerocopy-derive` copies caller types, generics,
predicates, expressions, attributes, or patterns into a new generated
scope.
2. Define destination-scope descriptors for the sites fixed by #3633 first.
3. Make those emitters consume validated wrappers.
4. Migrate other replay sites incrementally, preserving diagnostics where
reasonable.
5. Add tests which fail if a helper is added or renamed without updating the
scope validation, plus regressions for generated-name capture, contextual
`Self`, unresolved macros, raw identifiers, qualified paths, and nested
scopes binding their own `Self`.

## Non-goals

- Hashed/randomized helper names are not a soundness boundary; callers can
still choose names and deterministic validation is reviewable.
- Do not collapse distinct grammars into one global rejection rule.
- Do not require original-scope syntax to pass copied-syntax checks.
- This refactor does not by itself prove all proc-macro output sound; it makes
a validation obligation explicit and harder to omit.

## Acceptance criteria

- Generated helper names/prefixes and capture validation have one authoritative
definition per destination scope.
- A migrated generator cannot replay raw caller syntax without first obtaining
the matching validation capability.
- The #3619 and #3633 regression families remain covered, including
`on_error = "skip"` and supertrait-chain behavior where applicable.
- Specialized restrictions remain separately documented and tested.

Related: #11, #1684, #1725, #388, #3619, #3633.

*Authored by an AI agent acting on Josh Liebow-Feeser's behalf.*

Contributor guide

Open the contributing guide

Research direction

Start by inventorying every caller-syntax replay site in zerocopy-derive, then read the regression work from #3619 and #3633. Define destination-scope descriptors and validated wrappers for the migrated emitters, and preserve their regression coverage, including on_error = "skip" and relevant supertrait-chain cases.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.