Disallow ambiguous attributes on expressions (take 2) - #160235
Disallow ambiguous attributes on expressions (take 2)#160235petrochenkov wants to merge 1 commit into
Conversation
|
The parser was modified, potentially altering the grammar of (stable) Rust cc @fmease |
|
r? @chenyukang rustbot has assigned @chenyukang. Use Why was this reviewer chosen?The reviewer was selected based on:
|
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Attributes in expressions, purely from syntactic point of view, at parsing time. Not syntactically suspicious (top level expressions):Definitely can stabilize after accounting for macro attributes and #159581 (comment). // let initializer
let x = #[attr] 10;
let x = #[attr] 10 else { ... };
// const or static item initializer
const C: u8 = #[attr] 10;
static C: u8 = #[attr] 10;
// enum discriminant value
enum E { V = #[attr] 10 }
// field default
struct S { field: u8 = #[attr] 10 }
// key value attribute
#[key = #[attr] value]
// `match` arm
match 10 {
11 => #[attr] 12,
}
// struct literals fields
let x = Struct { field: #[attr] 10, ... }
// struct literals rest
let x = Struct { field: 10, ..#[attr] base }
// for loop iterator
for x in #[attr] 10 { ... }
// if condition
if #[attr] 10 { ... }
// while condition
while #[attr] 10 { ... }
// match scrutinee
match #[attr] 10 { ... }
// method call arguments
r.method(#[attr] 10, ...)
// array element or size
[#[attr] 10, 11, 12]
[#[attr] 10; 11]
[10; #[attr] 11]
[u8; #[attr] 11]
// function call argument
func(#[attr] 10, 11, 12)
// tuple element
(#[attr] 10, 11, 12)
// move expression
move(#[attr] 10)
// indexing argument
array[#[attr] 10]
// parentheses
(#[attr] 10)
// const generic defaults
fn foo<const C: u8 = #[attr] 10>() {}
// const parameter constraint
foo::<C = #[attr] 10>()
// const generic arguments (if supported at all)
foo::<#[attr] 10>()
// type ascription
builtin # type_ascribe(#[attr] 10, u8)
// unsafe binder casts
builtin # wrap_binder(#[attr] 10, u8)
// various inline asm operands
asm!("code", in("r") #[attr] x)
// some syntax for contracts, I didn't look closelySemi-suspicious (top level expressions):I don't see any actual issues, just would be interesting how often these will occur in the crater run. Can stabilize (after accounting for macro attributes and #159581 (comment)) or not stabilize. // closure body
let x = || #[attr] 10;
// break, return, yield, become, and yeet expressions
break #[attr] 10
return #[attr] 10
yield #[attr] 10
become #[attr] 10
do yeet #[attr] 10
// match or pattern guard conditions
pat if #[attr] true
// `expr` matcher as an await or yield receiver
$expr.await // `$expr` is `#[attr] 10`
$expr.yield // `$expr` is `#[attr] 10`
// `expr` matcher as a use receiver
$expr.use // `$expr` is `#[attr] 10`
// `expr` matcher as a field receiver
$expr.field // `$expr` is `#[attr] 10`
// `expr` matcher as a method receiver
$expr.method() // `$expr` is `#[attr] 10`
// `expr` matcher as a callable in a function call
$expr() // `$expr` is `#[attr] 10`
// `expr` matcher as an indexable expression
$expr[] // `$expr` is `#[attr] 10`
// `expr` matcher as a try expression
$expr? // `$expr` is `#[attr] 10`Semi-suspicious (non-top level expressions):I don't see any actual issues, just would be interesting how often these will occur in the crater run. Can stabilize (after accounting for macro attributes and #159581 (comment)) or not stabilize. // binary operator rhs
10 + #[attr] 11
// assignment rhs
lhs = #[attr] rhs
lhs += #[attr] rhs
// range rhs
10 .. #[attr] 11
// let expressions in if/while
if let x = #[attr] 10 && x == 11 { ... }
// prefix unary operator
- #[attr] 10
// reference operator
& #[attr] 10
& raw mut #[attr] 10Suspicious (top level expressions):Cannot stabilize, this is a long stanging issue with too permissive pattern parsing. // `expr` matcher as a pattern
match 10 { $expr => {} } // `$expr` is `#[attr] 10`
// `expr` matcher in a range pattern
match 10 { $expr .. $expr => {} } // `$expr` is `#[attr] 10`Suspicious (non-top level expressions):Cannot stabilize. // binary operator lhs
#[attr] 10 + 11
// assignment lhs
#[attr] lhs = rhs
#[attr] lhs += rhs
// range lhs
#[attr] 10 .. 11
// cast expressions
#[attr] 10 as u8 |
|
Regarding #159581 (comment). Suspicious contexts (single -> list)In all these cases if // method call arguments
r.method($expr, ...)
// array element or size
[$expr, 11, 12]
// function call argument
func($expr, 11, 12)
// tuple element
($expr, 11, 12)
// const generic arguments (if supported at all)
foo::<$expr>()Suspicious contexts (expr -> stmt)In all these cases if // $expr is:
// postfix await, yield or use
#[attr] val.await
#[attr] val.yield
#[attr] val.use
// field or method access
#[attr] val.field
#[attr] val.method()
// function call or indexing
#[attr] val()
#[attr] val[]
// expression
#[attr] val?
// path
#[attr] pathIf an attribute starts a statement as a part of some larger expression (e.g. a binary operator), it will already be reported as an error by #160235 (comment). ConclusionThese examples are only ambiguous if any of the involved attributes are active (including |
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
|
@bors try |
This comment has been minimized.
This comment has been minimized.
Disallow ambiguous attributes on expressions (take 2)
|
The job Click to see the possible cause of the failure (guessed by this bot) |
|
@craterbot check |
|
👌 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
There's at least one good reason to keep these unstable or unsupported (the "rhs" half including This gives us maximum freedom to change the attribute application priorities even inside expressions, not just at the statement start. Why we may want this at all? // `attr` is an attribute on the whole function parameter, not on the pattern `pat`
fn foo(#[attr] pat: Type) {}
// `attr` is an attribute on the whole generic parameter, not on the type `Type`
fn foo<#[attr] Type = Default>() {}
// `attr` is an attribute on the whole where clause predicate, not on the type `Type`
fn foo() where #[attr] Type: Trait {}
// `attr` is an attribute on the whole match arm, not on the range pattern or the range start expression
match 10 {
#[attr] 10 .. 11 => {}
}It is reasonable to expect that the same rule works for statements (or even expressions) // `attr` is an attribute on the whole statement, not on the lhs expression ???
#[attr]
lhs = rhs;, but it's not actually the case, the attribute applies only to the In purely expression contexts, like |
|
Ah, the conclusion regarding stabilization: if the syntactic restrictions from the above are enforced, then we'll be able to stabilize inert attributes on all expressions. |
Previous reverted attempt - #124099.
cc #159581
TODO: