Skip to content

handle paren in macro expand for let-init-else expr #134034

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

Merged
merged 1 commit into from
May 2, 2025

Conversation

bvanjoi
Copy link
Contributor

@bvanjoi bvanjoi commented Dec 8, 2024

Fixes #131655

This PR modifies the codegen logic of the macro expansion within let-init-else expression:

  • Before: The expression let xxx = (mac! {}) else {} expands to let xxx = (expanded_ast) else {}.
  • After: The same expression expands to let xxx = expanded_ast else {}.

An alternative solution to this issue could involve handling the source code directly when encountering unused parentheses in let-init-else expressions. However, this approach might be more cumbersome due to the absence of the necessary data structure.

r? @petrochenkov

@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 Dec 8, 2024
@cjgillot
Copy link
Contributor

cjgillot commented Dec 8, 2024

This seems like a far reaching change because of a buggy lint.
Would a targeted exception on the lint itself be simpler?

@bvanjoi
Copy link
Contributor Author

bvanjoi commented Dec 9, 2024

Would a targeted exception on the lint itself be simpler?

If we follow this thought, we need to check the original AST for init_expr in let-init-else when encountering unused_paren. There are two possible approaches:

  • Parse the expression again to check if it is a macro call with braces.
  • Record the node_id if the paren expression contains a macro call with braces during expansion.

@petrochenkov
Copy link
Contributor

This is an issue with any context that restricts braces, right?
Like plain if:

fn main() {
    macro_rules! x {
        () => { true }
    }

    if (x! {}) {} // warning: unnecessary parentheses around `if` condition
}

See NO_STRUCT_LITERAL in the parser for all such contexts.
IIRC, braced macro calls like mac! {} are currently prohibited in all such contexts for consistency with other braced syntaxes (even if it's not technically necessary) due to a relatively recent lang team decision.

@dtolnay
Copy link
Member

dtolnay commented Dec 10, 2024

if (x! {}) {} is actually unnecessary parentheses. if x! {} {} is valid syntax.

@petrochenkov
Copy link
Contributor

Perhaps the lint should look at span of the expression inside the parentheses, check what macro expansion it comes from, and suppress the warning in suspicious cases.
The current implementation in this PR is certainly not the way to go.

IIRC @dtolnay was also recently working on pretty-printing / linting (un)necessary parentheses, maybe he has more suggestions.

@petrochenkov petrochenkov added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 10, 2024
@bvanjoi
Copy link
Contributor Author

bvanjoi commented Dec 11, 2024

Update: It now stores the span of necessary parenthesis nodes and uses it when checking for unused_parens lint.

@bvanjoi
Copy link
Contributor Author

bvanjoi commented Dec 12, 2024

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Dec 12, 2024
@bors

This comment was marked as resolved.

@petrochenkov
Copy link
Contributor

Sorry for the long delay.

I think the current version is still too much.
This can probably be fixed by a simpler heuristic local to compiler/rustc_lint/src/unused.rs - in if expr { ... } we look 1) at the span of expr and 2) at the span of the whole if expr { ... }, and if syntactic contexts of the spans do not match then we suppress the lint.
Something like Span::contains or similar could also be used instead of context comparison.
Other lints and diagnostics are full of checks like this.
@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 10, 2025
@alex-semenyuk
Copy link
Member

@bvanjoi
Thanks for your contribution
From wg-triage. Any updates on this PR? Also could you please rebase

@bvanjoi
Copy link
Contributor Author

bvanjoi commented Apr 29, 2025

This can probably be fixed by a simpler heuristic local

The root cause of this issue is that information gets lost during macro expansion. For example, the expression let Some(_) = (x! {}) else { return }; expands into let Some(_) = (None::<i32>) else { return }, making it impossible to determine whether None::<i32> originated from macro expansion or was written directly by the user. Is there any way to distinguish between the two? I’ll look into it.

@bvanjoi
Copy link
Contributor Author

bvanjoi commented Apr 29, 2025

The logic is now straightforward: if both the parenthesized expression and its inner expression originate from the same context, we continue checking. Otherwise, we stop.

@bvanjoi
Copy link
Contributor Author

bvanjoi commented Apr 29, 2025

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Apr 29, 2025
@petrochenkov
Copy link
Contributor

Thanks!
@bors r+

@bors
Copy link
Collaborator

bors commented Apr 30, 2025

📌 Commit e9d2fef has been approved by petrochenkov

It is now in the queue for this repository.

@bors bors removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Apr 30, 2025
@bors bors added the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Apr 30, 2025
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request May 1, 2025
handle paren in macro expand for let-init-else expr

Fixes rust-lang#131655

This PR modifies the codegen logic of the macro expansion within `let-init-else` expression:
- Before: The expression `let xxx = (mac! {}) else {}` expands to `let xxx = (expanded_ast) else {}`.
- After: The same expression expands to `let xxx = expanded_ast else {}`.

An alternative solution to this issue could involve handling the source code directly when encountering unused parentheses in `let-init-else` expressions. However, this approach might be more cumbersome due to the absence of the necessary data structure.

r? `@petrochenkov`
bors added a commit to rust-lang-ci/rust that referenced this pull request May 1, 2025
…iaskrgr

Rollup of 7 pull requests

Successful merges:

 - rust-lang#134034 (handle paren in macro expand for let-init-else expr)
 - rust-lang#139186 (Refactor `diy_float`)
 - rust-lang#140062 (std: mention `remove_dir_all` can emit `DirectoryNotEmpty` when concurrently written into)
 - rust-lang#140430 (Improve test coverage of HIR pretty printing.)
 - rust-lang#140485 (Optimize the codegen for `Span::from_expansion`)
 - rust-lang#140505 (linker: Quote symbol names in .def files)
 - rust-lang#140521 (interpret: better error message for out-of-bounds pointer arithmetic and accesses)

r? `@ghost`
`@rustbot` modify labels: rollup
Zalathar added a commit to Zalathar/rust that referenced this pull request May 1, 2025
handle paren in macro expand for let-init-else expr

Fixes rust-lang#131655

This PR modifies the codegen logic of the macro expansion within `let-init-else` expression:
- Before: The expression `let xxx = (mac! {}) else {}` expands to `let xxx = (expanded_ast) else {}`.
- After: The same expression expands to `let xxx = expanded_ast else {}`.

An alternative solution to this issue could involve handling the source code directly when encountering unused parentheses in `let-init-else` expressions. However, this approach might be more cumbersome due to the absence of the necessary data structure.

r? ``@petrochenkov``
bors added a commit to rust-lang-ci/rust that referenced this pull request May 1, 2025
Rollup of 11 pull requests

Successful merges:

 - rust-lang#134034 (handle paren in macro expand for let-init-else expr)
 - rust-lang#138703 (chore: remove redundant words in comment)
 - rust-lang#139186 (Refactor `diy_float`)
 - rust-lang#139343 (Change signature of File::try_lock and File::try_lock_shared)
 - rust-lang#139780 (docs: Add example to `Iterator::take` with `by_ref`)
 - rust-lang#139802 (Fix some grammar errors and hyperlinks in doc for `trait Allocator`)
 - rust-lang#140034 (simd_select_bitmask: the 'padding' bits in the mask are just ignored)
 - rust-lang#140062 (std: mention `remove_dir_all` can emit `DirectoryNotEmpty` when concurrently written into)
 - rust-lang#140485 (Optimize the codegen for `Span::from_expansion`)
 - rust-lang#140505 (linker: Quote symbol names in .def files)
 - rust-lang#140521 (interpret: better error message for out-of-bounds pointer arithmetic and accesses)

r? `@ghost`
`@rustbot` modify labels: rollup
Zalathar added a commit to Zalathar/rust that referenced this pull request May 1, 2025
handle paren in macro expand for let-init-else expr

Fixes rust-lang#131655

This PR modifies the codegen logic of the macro expansion within `let-init-else` expression:
- Before: The expression `let xxx = (mac! {}) else {}` expands to `let xxx = (expanded_ast) else {}`.
- After: The same expression expands to `let xxx = expanded_ast else {}`.

An alternative solution to this issue could involve handling the source code directly when encountering unused parentheses in `let-init-else` expressions. However, this approach might be more cumbersome due to the absence of the necessary data structure.

r? ```@petrochenkov```
bors added a commit to rust-lang-ci/rust that referenced this pull request May 1, 2025
Rollup of 10 pull requests

Successful merges:

 - rust-lang#134034 (handle paren in macro expand for let-init-else expr)
 - rust-lang#138703 (chore: remove redundant words in comment)
 - rust-lang#139186 (Refactor `diy_float`)
 - rust-lang#139343 (Change signature of File::try_lock and File::try_lock_shared)
 - rust-lang#139780 (docs: Add example to `Iterator::take` with `by_ref`)
 - rust-lang#139802 (Fix some grammar errors and hyperlinks in doc for `trait Allocator`)
 - rust-lang#140034 (simd_select_bitmask: the 'padding' bits in the mask are just ignored)
 - rust-lang#140062 (std: mention `remove_dir_all` can emit `DirectoryNotEmpty` when concurrently written into)
 - rust-lang#140485 (Optimize the codegen for `Span::from_expansion`)
 - rust-lang#140521 (interpret: better error message for out-of-bounds pointer arithmetic and accesses)

r? `@ghost`
`@rustbot` modify labels: rollup
bors added a commit to rust-lang-ci/rust that referenced this pull request May 2, 2025
Rollup of 12 pull requests

Successful merges:

 - rust-lang#134034 (handle paren in macro expand for let-init-else expr)
 - rust-lang#137474 (pretty-print: Print shebang at the top of the output)
 - rust-lang#138872 (rustc_target: RISC-V `Zfinx` is incompatible with `{ILP32,LP64}[FD]` ABIs)
 - rust-lang#139046 (Improve `Lifetime::suggestion`)
 - rust-lang#139206 (std: use the address of `errno` to identify threads in `unique_thread_exit`)
 - rust-lang#139608 (Clarify `async` block behaviour)
 - rust-lang#139847 (Delegate to inner `vec::IntoIter` from `env::ArgsOs`)
 - rust-lang#140159 (Avoid redundant WTF-8 checks in `PathBuf`)
 - rust-lang#140197 (Document breaking out of a named code block)
 - rust-lang#140389 (Remove `avx512dq` and `avx512vl` implication for `avx512fp16`)
 - rust-lang#140430 (Improve test coverage of HIR pretty printing.)
 - rust-lang#140507 (rustc_target: RISC-V: feature addition batch 3)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 96852e2 into rust-lang:master May 2, 2025
6 checks passed
@rustbot rustbot added this to the 1.88.0 milestone May 2, 2025
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request May 2, 2025
Rollup merge of rust-lang#134034 - bvanjoi:issue-131655, r=petrochenkov

handle paren in macro expand for let-init-else expr

Fixes rust-lang#131655

This PR modifies the codegen logic of the macro expansion within `let-init-else` expression:
- Before: The expression `let xxx = (mac! {}) else {}` expands to `let xxx = (expanded_ast) else {}`.
- After: The same expression expands to `let xxx = expanded_ast else {}`.

An alternative solution to this issue could involve handling the source code directly when encountering unused parentheses in `let-init-else` expressions. However, this approach might be more cumbersome due to the absence of the necessary data structure.

r? `@petrochenkov`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
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.

false positive for unused_parens in a let-else
7 participants