Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix duplicated attributes on nonterminal expressions #126678

Merged
merged 11 commits into from
Jun 19, 2024

Conversation

nnethercote
Copy link
Contributor

@nnethercote nnethercote commented Jun 19, 2024

This PR fixes a long-standing bug (#86055) whereby expression attributes can be duplicated when expanded through declarative macros.

First, consider how items are parsed in declarative macros:

Items:
- parse_nonterminal
  - parse_item(ForceCollect::Yes)
    - parse_item_
      - attrs = parse_outer_attributes
      - parse_item_common(attrs)
        - maybe_whole!
        - collect_tokens_trailing_token

The important thing is that the parsing of outer attributes is outside token collection, so the item's tokens don't include the attributes. This is how it's supposed to be.

Now consider how expression are parsed in declarative macros:

Exprs:
- parse_nonterminal
  - parse_expr_force_collect
    - collect_tokens_no_attrs
      - collect_tokens_trailing_token
        - parse_expr
          - parse_expr_res(None)
            - parse_expr_assoc_with
              - parse_expr_prefix
                - parse_or_use_outer_attributes
                - parse_expr_dot_or_call

The important thing is that the parsing of outer attributes is inside token collection, so the the expr's tokens do include the attributes, i.e. in AttributesData::tokens.

This PR fixes the bug by rearranging expression parsing to that outer attribute parsing happens outside of token collection. This requires a number of small refactorings because expression parsing is somewhat complicated. While doing so the PR makes the code a bit cleaner and simpler, by eliminating parse_or_use_outer_attributes and Option<AttrWrapper> arguments (in favour of the simpler parse_outer_attributes and AttrWrapper arguments), and simplifying LhsExpr.

r? @petrochenkov

Something that was non-obvious to me.
The call in `parse_expr_prefix` for the `++` case passes an empty
`attrs`, but it doesn' need to. This commit changes it to pass the
parsed `attrs`, which doesn't change any behaviour. As a result,
`parse_expr_dot_or_call` no longer needs an `Option` argument, and no
longer needs to call `parse_or_use_outer_attributes`.
The `Option<AttrWrapper>` one maps to the first two variants, and the
`P<Expr>` one maps to the third. Weird. The code is shorter and clearer
without them.
Combine `NotYetParsed` and `AttributesParsed` into a single variant,
because (a) that reflects the structure of the code that consumes
`LhsExpr`, and (b) because that variant will have the `Option` removed
in a later commit.
It has a single call site.
This eliminates one `Option<AttrWrapper>` argument.
This eliminates another `Option<AttrWrapper>` argument and changes one
obscure error message.
By making the `AttrWrapper` non-optional.
This removes the final `Option<AttrWrapper>` argument.
It now parses outer attributes before collecting tokens. This avoids the
problem where the outer attribute tokens were being stored twice -- for
the attribute tokesn, and also for the expression tokens.

Fixes rust-lang#86055.
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 19, 2024
@petrochenkov
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented Jun 19, 2024

📌 Commit 64c2e9e has been approved by petrochenkov

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 19, 2024
@fmease

This comment was marked as off-topic.

@bors

This comment was marked as off-topic.

@bors
Copy link
Contributor

bors commented Jun 19, 2024

⌛ Testing commit 64c2e9e with merge 79d1c3f...

bors added a commit to rust-lang-ci/rust that referenced this pull request Jun 19, 2024
…nt-expr, r=petrochenkov

Fix duplicated attributes on nonterminal expressions

This PR fixes a long-standing bug (rust-lang#86055) whereby expression attributes can be duplicated when expanded through declarative macros.

First, consider how items are parsed in declarative macros:
```
Items:
- parse_nonterminal
  - parse_item(ForceCollect::Yes)
    - parse_item_
      - attrs = parse_outer_attributes
      - parse_item_common(attrs)
        - maybe_whole!
        - collect_tokens_trailing_token
```
The important thing is that the parsing of outer attributes is outside token collection, so the item's tokens don't include the attributes. This is how it's supposed to be.

Now consider how expression are parsed in declarative macros:
```
Exprs:
- parse_nonterminal
  - parse_expr_force_collect
    - collect_tokens_no_attrs
      - collect_tokens_trailing_token
        - parse_expr
          - parse_expr_res(None)
            - parse_expr_assoc_with
              - parse_expr_prefix
                - parse_or_use_outer_attributes
                - parse_expr_dot_or_call
```
The important thing is that the parsing of outer attributes is inside token collection, so the the expr's tokens do include the attributes, i.e. in `AttributesData::tokens`.

This PR fixes the bug by rearranging expression parsing to that outer attribute parsing happens outside of token collection. This requires a number of small refactorings because expression parsing is somewhat complicated. While doing so the PR makes the code a bit cleaner and simpler, by eliminating `parse_or_use_outer_attributes` and `Option<AttrWrapper>` arguments (in favour of the simpler `parse_outer_attributes` and `AttrWrapper` arguments), and simplifying `LhsExpr`.

r? `@petrochenkov`
@bors
Copy link
Contributor

bors commented Jun 19, 2024

⌛ Testing commit 64c2e9e with merge 894f7a4...

@bors
Copy link
Contributor

bors commented Jun 19, 2024

☀️ Test successful - checks-actions
Approved by: petrochenkov
Pushing 894f7a4 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Jun 19, 2024
@bors bors merged commit 894f7a4 into rust-lang:master Jun 19, 2024
7 checks passed
@rustbot rustbot added this to the 1.81.0 milestone Jun 19, 2024
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (894f7a4): comparison URL.

Overall result: ✅ improvements - no action needed

@rustbot label: -perf-regression

Instruction count

This is a highly reliable metric that was used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
-0.4% [-0.5%, -0.2%] 7
Improvements ✅
(secondary)
-0.7% [-0.7%, -0.6%] 3
All ❌✅ (primary) -0.4% [-0.5%, -0.2%] 7

Max RSS (memory usage)

This benchmark run did not return any relevant results for this metric.

Cycles

Results (secondary 2.1%)

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
2.1% [2.1%, 2.1%] 1
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 690.996s -> 690.539s (-0.07%)
Artifact size: 323.62 MiB -> 323.81 MiB (0.06%)

@nnethercote nnethercote deleted the fix-duplicated-attrs-on-nt-expr branch June 19, 2024 18:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants