-
Notifications
You must be signed in to change notification settings - Fork 13.5k
Reduce precedence of expressions that have an outer attr #134661
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
Conversation
r? @fee1-dead rustbot has assigned @fee1-dead. Use |
This comment has been minimized.
This comment has been minimized.
Some changes occurred in src/tools/clippy cc @rust-lang/clippy |
r? compiler |
☔ The latest upstream changes (presumably #134788) made this pull request unmergeable. Please resolve the merge conflicts. |
Rebased to resolve conflict. |
I'm going to look at this in a few hours. |
fn prefix_attrs_precedence(attrs: &AttrVec) -> ExprPrecedence { | ||
for attr in attrs { | ||
if let AttrStyle::Outer = attr.style { | ||
return ExprPrecedence::Prefix; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think ExprPrecedence::Prefix
isn't low enough. Consider the following cases involving binops:
#![feature(stmt_expr_attributes)]
macro_rules! group { ($e:expr) => { $e } }
macro_rules! extra { ($e:expr) => { #[allow()] $e } }
fn main() { // `-Zunpretty=expanded` on master & prefixattr:
let _ = #[allow()] 1 + 1; // let _ = #[allow()] 1 + 1;
let _ = group!(#[allow()] 1) + 1; // let _ = #[allow()] 1 + 1;
let _ = 1 + group!(#[allow()] 1); // let _ = 1 + #[allow()] 1;
let _ = extra!({ 0 }) + 1; // let _ = #[allow()] { 0 } + 1;
let _ = extra!({ 0 } + 1); // let _ = #[allow()] { 0 } + 1;
}
I haven't given it that much thought yet, so I don't know which specific precedence level(s) would make sense instead.
And indeed, this example is heavily inspired by the ones found in #15701 / #127436. So maybe answering this pretty-printing question is partially blocked by the open design question (meaning we can ignore it for now).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that bug is orthogonal to this one.
The bug fixed by this PR is about when an outer expression A contains a subexpression B where B contains an attribute, and in the prettyprinter-produced code the attribute ended up applying to parts of A instead of only to B. This is fixed by having A observe a different effective precedence for its subexpression B, making A generate parentheses around the subexpression containing the attribute, i.e. the attribute will end up inside the parentheses.
In contrast, the bug you have identified is about an outer expression A that has an attribute, and a subexpression B that has no attribute. In this case when parentheses are inserted, the attribute will end up outside the parentheses.
I will fix that as well but I expect it will involve unrelated code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix: #142476
☔ The latest upstream changes (presumably #137235) made this pull request unmergeable. Please resolve the merge conflicts. |
Hi @fmease, it looks like you marked this as waiting on review recently. Is this actually waiting on review or for the author to respond to your previous review comment? |
@bors r=fmease |
Reduce precedence of expressions that have an outer attr Previously, `-Zunpretty=expanded` would expand this program as follows: ```rust #![feature(stmt_expr_attributes)] macro_rules! repro { ($e:expr) => { #[allow(deprecated)] $e }; } #[derive(Default)] struct Thing { #[deprecated] field: i32, } fn main() { let thing = Thing::default(); let _ = repro!(thing).field; } ``` ```rs #![feature(prelude_import)] #![feature(stmt_expr_attributes)] #[prelude_import] use std::prelude::rust_2021::*; #[macro_use] extern crate std; struct Thing { #[deprecated] field: i32, } #[automatically_derived] impl ::core::default::Default for Thing { #[inline] fn default() -> Thing { Thing { field: ::core::default::Default::default() } } } fn main() { let thing = Thing::default(); let _ = #[allow(deprecated)] thing.field; } ``` This is not the correct expansion. The correct output would have `(#[allow(deprecated)] thing).field` with the attribute applying only to `thing`, not to `thing.field`.
Rollup of 10 pull requests Successful merges: - #133952 (Remove wasm legacy abi) - #134661 (Reduce precedence of expressions that have an outer attr) - #141769 (Move metadata object generation for dylibs to the linker code ) - #141864 (Handle win32 separator for cygwin paths) - #142347 (Async drop - fix for StorageLive/StorageDead codegen for pinned future) - #142377 (Try unremapping compiler sources) - #142389 (Apply ABI attributes on return types in `rustc_codegen_cranelift`) - #142470 (Add some missing mailmap entries) - #142481 (Add `f16` inline asm support for LoongArch) - #142509 (bump std libc dependency) r? `@ghost` `@rustbot` modify labels: rollup
Reduce precedence of expressions that have an outer attr Previously, `-Zunpretty=expanded` would expand this program as follows: ```rust #![feature(stmt_expr_attributes)] macro_rules! repro { ($e:expr) => { #[allow(deprecated)] $e }; } #[derive(Default)] struct Thing { #[deprecated] field: i32, } fn main() { let thing = Thing::default(); let _ = repro!(thing).field; } ``` ```rs #![feature(prelude_import)] #![feature(stmt_expr_attributes)] #[prelude_import] use std::prelude::rust_2021::*; #[macro_use] extern crate std; struct Thing { #[deprecated] field: i32, } #[automatically_derived] impl ::core::default::Default for Thing { #[inline] fn default() -> Thing { Thing { field: ::core::default::Default::default() } } } fn main() { let thing = Thing::default(); let _ = #[allow(deprecated)] thing.field; } ``` This is not the correct expansion. The correct output would have `(#[allow(deprecated)] thing).field` with the attribute applying only to `thing`, not to `thing.field`.
Rollup of 9 pull requests Successful merges: - #133952 (Remove wasm legacy abi) - #134661 (Reduce precedence of expressions that have an outer attr) - #141769 (Move metadata object generation for dylibs to the linker code ) - #141864 (Handle win32 separator for cygwin paths) - #141937 (Report never type lints in dependencies) - #142347 (Async drop - fix for StorageLive/StorageDead codegen for pinned future) - #142389 (Apply ABI attributes on return types in `rustc_codegen_cranelift`) - #142470 (Add some missing mailmap entries) - #142481 (Add `f16` inline asm support for LoongArch) r? `@ghost` `@rustbot` modify labels: rollup
Rollup of 10 pull requests Successful merges: - #133952 (Remove wasm legacy abi) - #134661 (Reduce precedence of expressions that have an outer attr) - #141769 (Move metadata object generation for dylibs to the linker code ) - #141937 (Report never type lints in dependencies) - #142347 (Async drop - fix for StorageLive/StorageDead codegen for pinned future) - #142389 (Apply ABI attributes on return types in `rustc_codegen_cranelift`) - #142470 (Add some missing mailmap entries) - #142481 (Add `f16` inline asm support for LoongArch) - #142499 (Remove check run bootstrap) - #142543 (Suggest adding semicolon in user code rather than macro impl details) r? `@ghost` `@rustbot` modify labels: rollup
Rollup merge of #134661 - dtolnay:prefixattr, r=fmease Reduce precedence of expressions that have an outer attr Previously, `-Zunpretty=expanded` would expand this program as follows: ```rust #![feature(stmt_expr_attributes)] macro_rules! repro { ($e:expr) => { #[allow(deprecated)] $e }; } #[derive(Default)] struct Thing { #[deprecated] field: i32, } fn main() { let thing = Thing::default(); let _ = repro!(thing).field; } ``` ```rs #![feature(prelude_import)] #![feature(stmt_expr_attributes)] #[prelude_import] use std::prelude::rust_2021::*; #[macro_use] extern crate std; struct Thing { #[deprecated] field: i32, } #[automatically_derived] impl ::core::default::Default for Thing { #[inline] fn default() -> Thing { Thing { field: ::core::default::Default::default() } } } fn main() { let thing = Thing::default(); let _ = #[allow(deprecated)] thing.field; } ``` This is not the correct expansion. The correct output would have `(#[allow(deprecated)] thing).field` with the attribute applying only to `thing`, not to `thing.field`.
Insert parentheses around binary operation with attribute Fixes the bug found by `@fmease` in rust-lang#134661 (review). Previously, `-Zunpretty=expanded` would expand this program as follows: ```rust #![feature(stmt_expr_attributes)] #![allow(unused_attributes)] macro_rules! group { ($e:expr) => { $e }; } macro_rules! extra { ($e:expr) => { #[allow()] $e }; } fn main() { let _ = #[allow()] 1 + 1; let _ = group!(#[allow()] 1) + 1; let _ = 1 + group!(#[allow()] 1); let _ = extra!({ 0 }) + 1; let _ = extra!({ 0 } + 1); } ``` ```console let _ = #[allow()] 1 + 1; let _ = #[allow()] 1 + 1; let _ = 1 + #[allow()] 1; let _ = #[allow()] { 0 } + 1; let _ = #[allow()] { 0 } + 1; ``` The first 4 statements are the correct expansion, but the last one is not. The attribute is supposed to apply to the entire binary operation, not only to the left operand. After this PR, the 5th statement will expand to: ```console let _ = #[allow()] ({ 0 } + 1); ``` In the future, as some subset of `stmt_expr_attributes` approaches stabilization, it is possible that we will need to do parenthesization for a number of additional cases depending on the outcome of rust-lang#127436. But for now, at least this PR makes the pretty-printer align with the current behavior of the parser. r? fmease
Rollup merge of #142476 - dtolnay:attrbinop, r=fmease Insert parentheses around binary operation with attribute Fixes the bug found by `@fmease` in #134661 (review). Previously, `-Zunpretty=expanded` would expand this program as follows: ```rust #![feature(stmt_expr_attributes)] #![allow(unused_attributes)] macro_rules! group { ($e:expr) => { $e }; } macro_rules! extra { ($e:expr) => { #[allow()] $e }; } fn main() { let _ = #[allow()] 1 + 1; let _ = group!(#[allow()] 1) + 1; let _ = 1 + group!(#[allow()] 1); let _ = extra!({ 0 }) + 1; let _ = extra!({ 0 } + 1); } ``` ```console let _ = #[allow()] 1 + 1; let _ = #[allow()] 1 + 1; let _ = 1 + #[allow()] 1; let _ = #[allow()] { 0 } + 1; let _ = #[allow()] { 0 } + 1; ``` The first 4 statements are the correct expansion, but the last one is not. The attribute is supposed to apply to the entire binary operation, not only to the left operand. After this PR, the 5th statement will expand to: ```console let _ = #[allow()] ({ 0 } + 1); ``` In the future, as some subset of `stmt_expr_attributes` approaches stabilization, it is possible that we will need to do parenthesization for a number of additional cases depending on the outcome of #127436. But for now, at least this PR makes the pretty-printer align with the current behavior of the parser. r? fmease
Previously,
-Zunpretty=expanded
would expand this program as follows:This is not the correct expansion. The correct output would have
(#[allow(deprecated)] thing).field
with the attribute applying only tothing
, not tothing.field
.