From a6a1c1fcffccc953e7e54da18a02d006b60027fc Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 30 Jul 2026 21:08:08 +0300 Subject: [PATCH] WIP --- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_parse/src/parser/expr.rs | 65 +++++- compiler/rustc_parse/src/parser/pat.rs | 7 + compiler/rustc_parse/src/parser/path.rs | 1 + expr-attr-2.md | 56 +++++ expr-attr.md | 195 ++++++++++++++++++ tests/ui/attributes/instrument_fn.rs | 1 + tests/ui/attributes/instrument_fn.stderr | 26 ++- .../unused/unused-doc-comments-edge-cases.rs | 2 +- .../unused-doc-comments-edge-cases.stderr | 16 +- tests/ui/macros/stringify.rs | 1 + .../attribute/attr-stmt-expr-attr-bad.rs | 2 +- .../attribute/attr-stmt-expr-attr-bad.stderr | 15 +- .../ICE-119271-never-arm-attr-in-guard.rs | 1 + .../ICE-119271-never-arm-attr-in-guard.stderr | 16 +- 15 files changed, 382 insertions(+), 23 deletions(-) create mode 100644 expr-attr-2.md create mode 100644 expr-attr.md diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index c1134e1dd7300..7fb72a4775c83 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -460,6 +460,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { "`fn(#[rustc_splat] (a, ...))` is incomplete", "call as func((a, ...)) instead" ); + gate_all!(stmt_expr_attributes, "attributes on some expressions are unstable"); gate_all!(super_let, "`super let` is experimental"); gate_all!(try_blocks_heterogeneous, "`try bikeshed` expression is experimental"); gate_all!(unnamed_enum_variants, "unnamed enum variants are experimental"); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 12de4957e99c2..c87f6d8dd0a11 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -134,6 +134,15 @@ impl<'a> Parser<'a> { self.parse_expr_assoc_rest(min_prec, false, lhs) } + pub(super) fn suspicious_attribute(&self, expr: &Expr, _descr: &str) { + for attr in &expr.attrs { + if attr.style == AttrStyle::Outer { + // self.dcx().span_err(attr.span, format!("suspicious attribute: {descr}")); + self.psess.gated_spans.gate(sym::stmt_expr_attributes, attr.span); + } + } + } + /// Parses the rest of an associative expression (i.e. the part after the lhs) with operators /// of at least `min_prec` precedence. The `bool` in the return value indicates if something /// was actually parsed. @@ -284,7 +293,11 @@ impl<'a> Parser<'a> { let binary = self.mk_binary(respan(cur_op_span, ast_op), lhs, rhs); self.mk_expr(span, binary) } - AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs, cur_op_span)), + AssocOp::Assign => { + self.suspicious_attribute(&lhs, "ExprKind::Assign lhs"); + self.suspicious_attribute(&rhs, "ExprKind::Assign rhs"); + self.mk_expr(span, ExprKind::Assign(lhs, rhs, cur_op_span)) + } AssocOp::AssignOp(aop) => { let aopexpr = self.mk_assign_op(respan(cur_op_span, aop), lhs, rhs); self.mk_expr(span, aopexpr) @@ -648,6 +661,7 @@ impl<'a> Parser<'a> { expr_kind: fn(Box, Box) -> ExprKind, ) -> PResult<'a, Box> { let mk_expr = |this: &mut Self, lhs: Box, rhs: Box| { + this.suspicious_attribute(&lhs, "ExprKind::Cast"); this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span), expr_kind(lhs, rhs)) }; @@ -831,6 +845,7 @@ impl<'a> Parser<'a> { self.expected_token_types.insert(TokenType::KwConst); } + self.suspicious_attribute(&expr, "ExprKind::AddrOf"); Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr))) } @@ -884,6 +899,7 @@ impl<'a> Parser<'a> { }; if has_question { // `expr?` + // self.suspicious_attribute(&e, "ExprKind::Try"); e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e)); continue; } @@ -1228,6 +1244,7 @@ impl<'a> Parser<'a> { suffix, }); } + // self.suspicious_attribute(&base, "ExprKind::Field tuple"); self.mk_expr(lo.to(ident_span), ExprKind::Field(base, Ident::new(field, ident_span))) } @@ -1389,6 +1406,7 @@ impl<'a> Parser<'a> { if self.eat_keyword(exp!(Yield)) { let yield_span = self.prev_token.span; self.psess.gated_spans.gate(sym::yield_expr, yield_span); + // self.suspicious_attribute(&self_arg, "ExprKind::Yield postfix"); return Ok( self.mk_expr(lo.to(yield_span), ExprKind::Yield(YieldKind::Postfix(self_arg))) ); @@ -1404,6 +1422,7 @@ impl<'a> Parser<'a> { let args = self.parse_expr_paren_seq()?; let fn_span = fn_span_lo.to(self.prev_token.span); let span = lo.to(self.prev_token.span); + // self.suspicious_attribute(&self_arg, "ExprKind::MethodCall"); Ok(self.mk_expr( span, ExprKind::MethodCall(Box::new(ast::MethodCall { @@ -1423,6 +1442,7 @@ impl<'a> Parser<'a> { .stash(seg.ident.span, StashKey::GenericInFieldExpr); } + // self.suspicious_attribute(&self_arg, "ExprKind::Field struct"); Ok(self.mk_expr(span, ExprKind::Field(self_arg, seg.ident))) } } @@ -1869,7 +1889,11 @@ impl<'a> Parser<'a> { /// Parse `"return" expr?`. fn parse_expr_return(&mut self) -> PResult<'a, Box> { let lo = self.prev_token.span; - let kind = ExprKind::Ret(self.parse_expr_opt()?); + let expr = self.parse_expr_opt()?; + // if let Some(expr) = &expr { + // self.suspicious_attribute(expr, "ExprKind::Ret"); + // } + let kind = ExprKind::Ret(expr); let expr = self.mk_expr(lo.to(self.prev_token.span), kind); self.maybe_recover_from_bad_qpath(expr) } @@ -1881,7 +1905,11 @@ impl<'a> Parser<'a> { self.bump(); // `do` self.bump(); // `yeet` - let kind = ExprKind::Yeet(self.parse_expr_opt()?); + let expr = self.parse_expr_opt()?; + // if let Some(expr) = &expr { + // self.suspicious_attribute(expr, "ExprKind::Yeet"); + // } + let kind = ExprKind::Yeet(expr); let span = lo.to(self.prev_token.span); self.psess.gated_spans.gate(sym::yeet_expr, span); @@ -1892,7 +1920,9 @@ impl<'a> Parser<'a> { /// Parse `"become" expr`, with `"become"` token already eaten. fn parse_expr_become(&mut self) -> PResult<'a, Box> { let lo = self.prev_token.span; - let kind = ExprKind::Become(self.parse_expr()?); + let inner = self.parse_expr()?; + // self.suspicious_attribute(&inner, "ExprKind::Become"); + let kind = ExprKind::Become(inner); let span = lo.to(self.prev_token.span); self.psess.gated_spans.gate(sym::explicit_tail_calls, span); let expr = self.mk_expr(span, kind); @@ -1970,6 +2000,9 @@ impl<'a> Parser<'a> { } else { None }; + // if let Some(expr) = &kind { + // self.suspicious_attribute(expr, "ExprKind::Break"); + // } let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind)); self.maybe_recover_from_bad_qpath(expr) } @@ -1994,7 +2027,11 @@ impl<'a> Parser<'a> { /// Parse `"yield" expr?`. fn parse_expr_yield(&mut self) -> PResult<'a, Box> { let lo = self.prev_token.span; - let kind = ExprKind::Yield(YieldKind::Prefix(self.parse_expr_opt()?)); + let expr = self.parse_expr_opt()?; + // if let Some(expr) = &expr { + // self.suspicious_attribute(expr, "ExprKind::Yield prefix"); + // } + let kind = ExprKind::Yield(YieldKind::Prefix(expr)); let span = lo.to(self.prev_token.span); self.psess.gated_spans.gate(sym::yield_expr, span); let expr = self.mk_expr(span, kind); @@ -2498,6 +2535,7 @@ impl<'a> Parser<'a> { let body_span = body.span; + // self.suspicious_attribute(&body, "Closure::body"); let closure = self.mk_expr( lo.to(body.span), ExprKind::Closure(Box::new(ast::Closure { @@ -2832,6 +2870,7 @@ impl<'a> Parser<'a> { } let expr = self.parse_expr_assoc(Bound::Excluded(prec_let_scrutinee_needs_par()))?; let span = lo.to(expr.span); + self.suspicious_attribute(&expr, "ExprKind::Let rhs"); Ok(self.mk_expr(span, ExprKind::Let(Box::new(pat), expr, span, recovered))) } @@ -3559,6 +3598,7 @@ impl<'a> Parser<'a> { CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond); + self.suspicious_attribute(&cond, "Guard::cond arm"); let guard = Guard { cond: *cond, span_with_leading_if: leading_if_span.to(cond_span) }; Ok(Box::new(guard)) } @@ -4142,6 +4182,8 @@ impl<'a> Parser<'a> { } fn mk_assign_op(&self, assign_op: AssignOp, lhs: Box, rhs: Box) -> ExprKind { + self.suspicious_attribute(&lhs, "ExprKind::AssignOp lhs"); + self.suspicious_attribute(&rhs, "ExprKind::AssignOp rhs"); ExprKind::AssignOp(assign_op, lhs, rhs) } @@ -4155,28 +4197,40 @@ impl<'a> Parser<'a> { let guar = self.inclusive_range_with_incorrect_end(); ExprKind::Err(guar) } else { + if let Some(expr) = &start { + self.suspicious_attribute(&expr, "ExprKind::Range lhs"); + } + if let Some(expr) = &end { + self.suspicious_attribute(&expr, "ExprKind::Range rhs"); + } ExprKind::Range(start, end, limits) } } fn mk_unary(&self, unop: UnOp, expr: Box) -> ExprKind { + self.suspicious_attribute(&expr, "ExprKind::Unary"); ExprKind::Unary(unop, expr) } fn mk_binary(&self, binop: BinOp, lhs: Box, rhs: Box) -> ExprKind { + self.suspicious_attribute(&lhs, "ExprKind::Binary lhs"); + self.suspicious_attribute(&rhs, "ExprKind::Binary rhs"); ExprKind::Binary(binop, lhs, rhs) } fn mk_index(&self, expr: Box, idx: Box, brackets_span: Span) -> ExprKind { + // self.suspicious_attribute(&expr, "ExprKind::Index"); ExprKind::Index(expr, idx, brackets_span) } fn mk_call(&self, f: Box, args: ThinVec>) -> ExprKind { + // self.suspicious_attribute(&f, "ExprKind::Call"); ExprKind::Call(f, args) } fn mk_await_expr(&mut self, self_arg: Box, lo: Span) -> Box { let span = lo.to(self.prev_token.span); + // self.suspicious_attribute(&self_arg, "ExprKind::Await"); let await_expr = self.mk_expr(span, ExprKind::Await(self_arg, self.prev_token.span)); self.recover_from_await_method_call(); await_expr @@ -4184,6 +4238,7 @@ impl<'a> Parser<'a> { fn mk_use_expr(&mut self, self_arg: Box, lo: Span) -> Box { let span = lo.to(self.prev_token.span); + // self.suspicious_attribute(&self_arg, "ExprKind::Use"); let use_expr = self.mk_expr(span, ExprKind::Use(self_arg, self.prev_token.span)); self.recover_from_use(); use_expr diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 64cc8ad9812f2..eeaccaa360023 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -116,6 +116,7 @@ impl<'a> Parser<'a> { let leading_if_span = self.prev_token.span; let cond = self.parse_expr()?; let cond_span = cond.span; + self.suspicious_attribute(&cond, "Guard::cond pat"); Box::new(Guard { cond: *cond, span_with_leading_if: leading_if_span.to(cond_span) }) }; @@ -799,6 +800,7 @@ impl<'a> Parser<'a> { if let Some(re) = self.parse_range_end() { self.parse_pat_range_begin_with(const_expr, re)? } else { + self.suspicious_attribute(&const_expr, "PatKind::Expr const_block"); PatKind::Expr(const_expr) } } else if self.is_builtin() { @@ -1373,6 +1375,10 @@ impl<'a> Parser<'a> { } None }; + self.suspicious_attribute(&begin, "PatKind::Range lhs"); + if let Some(expr) = &end { + self.suspicious_attribute(&expr, "PatKind::Range rhs"); + } Ok(PatKind::Range(Some(begin), end, re)) } @@ -1414,6 +1420,7 @@ impl<'a> Parser<'a> { *syn = RangeSyntax::DotDotEq; self.dcx().emit_err(DotDotDotRangeToPatternNotAllowed { span: re.span }); } + self.suspicious_attribute(&end, "PatKind::Range end"); Ok(PatKind::Range(None, Some(end), re)) } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index cbd0891c7fe9a..97b2ff4330a8b 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -873,6 +873,7 @@ impl<'a> Parser<'a> { } else { self.parse_unambiguous_unbraced_const_arg()? }; + self.suspicious_attribute(&value, "AnonConst::value const_arg"); Ok(AnonConst { id: ast::DUMMY_NODE_ID, value }) } diff --git a/expr-attr-2.md b/expr-attr-2.md new file mode 100644 index 0000000000000..01e51a9a72d8a --- /dev/null +++ b/expr-attr-2.md @@ -0,0 +1,56 @@ +Regarding https://github.com/rust-lang/rust/pull/159581#issuecomment-5095419394. + +### Suspicious contexts (single -> list) + +In all these cases if `$expr` has a top level attribute inside it, it will migrate from a single to list context if the parentheses from the macro variable are not correctly preserved in AST. + +```rust +// 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` has a top level attribute inside it, it will migrate from a single expression to statement context if the parentheses from the macro variable are not correctly preserved in AST. + +```rust +// $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] path +``` + +If 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 https://github.com/rust-lang/rust/pull/160235#issuecomment-5159173426. + +### Conclusion + +These examples are only ambiguous if any of the involved attributes are active (including `cfg`), except that `cfg_attr` is ok (because we know what it does, and it does not depend on context). +So we don't need to gate any of this during parsing, and can continue using expansion-time gating. diff --git a/expr-attr.md b/expr-attr.md new file mode 100644 index 0000000000000..92a19af493116 --- /dev/null +++ b/expr-attr.md @@ -0,0 +1,195 @@ +Attributes in expressions, purely from syntactic point of view, at parsing time. +I.e. no distinction between active or inert, or built-in or custom attributes. +And without considering https://github.com/rust-lang/rust/pull/159581#issuecomment-5095419394. + +### Not syntactically suspicious (top level expressions): + +Definitely can stabilize after accounting for macro attributes and https://github.com/rust-lang/rust/pull/159581#issuecomment-5095419394. + +```rust +// 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 parameter constraint +foo::() + +// 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 closely +``` + +### Semi-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 https://github.com/rust-lang/rust/pull/159581#issuecomment-5095419394) or not stabilize. + +```rust +// 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 https://github.com/rust-lang/rust/pull/159581#issuecomment-5095419394) or not stabilize. + +```rust +// 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] 10 +``` + +### Suspicious (top level expressions): + +Cannot stabilize, this is a long stanging issue with too permissive pattern parsing. + +```rust +// `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. + +```rust +// 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 +``` diff --git a/tests/ui/attributes/instrument_fn.rs b/tests/ui/attributes/instrument_fn.rs index 7bb6b418b3d1f..d6dc44e24a560 100644 --- a/tests/ui/attributes/instrument_fn.rs +++ b/tests/ui/attributes/instrument_fn.rs @@ -13,6 +13,7 @@ impl F { fn no_instrument_fn(self, x: u32) -> u32 { #[instrument_fn = "off"] //~ ERROR attribute cannot be used on //~^ ERROR attributes on expressions are experimental + //~| ERROR attributes on some expressions are unstable x * 2 } } diff --git a/tests/ui/attributes/instrument_fn.stderr b/tests/ui/attributes/instrument_fn.stderr index c6d0887fcd9fa..27b411d9c9821 100644 --- a/tests/ui/attributes/instrument_fn.stderr +++ b/tests/ui/attributes/instrument_fn.stderr @@ -9,7 +9,7 @@ LL | #[instrument_fn = "off"] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: attributes on expressions are experimental - --> $DIR/instrument_fn.rs:47:14 + --> $DIR/instrument_fn.rs:48:14 | LL | let _x = #[instrument_fn = "on"] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -18,6 +18,16 @@ LL | let _x = #[instrument_fn = "on"] = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: attributes on some expressions are unstable + --> $DIR/instrument_fn.rs:14:9 + | +LL | #[instrument_fn = "off"] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error: the `instrument_fn` attribute cannot be used on crates --> $DIR/instrument_fn.rs:2:4 | @@ -59,7 +69,7 @@ LL | #[instrument_fn = "off"] = help: the `instrument_fn` attribute can only be applied to functions error: the `instrument_fn` attribute cannot be used on traits - --> $DIR/instrument_fn.rs:20:3 + --> $DIR/instrument_fn.rs:21:3 | LL | #[instrument_fn = "off"] | ^^^^^^^^^^^^^ @@ -67,7 +77,7 @@ LL | #[instrument_fn = "off"] = help: the `instrument_fn` attribute can only be applied to functions error: the `instrument_fn` attribute cannot be used on required trait methods - --> $DIR/instrument_fn.rs:22:7 + --> $DIR/instrument_fn.rs:23:7 | LL | #[instrument_fn = "off"] | ^^^^^^^^^^^^^ @@ -75,7 +85,7 @@ LL | #[instrument_fn = "off"] = help: the `instrument_fn` attribute can only be applied to functions with a body error[E0805]: malformed `instrument_fn` attribute input - --> $DIR/instrument_fn.rs:37:3 + --> $DIR/instrument_fn.rs:38:3 | LL | #[instrument_fn(entry = "on")] | ^^^^^^^^^^^^^-------------- @@ -89,7 +99,7 @@ LL + #[instrument_fn = "on|off"] | error[E0539]: malformed `instrument_fn` attribute input - --> $DIR/instrument_fn.rs:40:3 + --> $DIR/instrument_fn.rs:41:3 | LL | #[instrument_fn] | ^^^^^^^^^^^^^ valid arguments are "on" or "off" @@ -100,7 +110,7 @@ LL | #[instrument_fn = "on|off"] | ++++++++++ error[E0539]: malformed `instrument_fn` attribute input - --> $DIR/instrument_fn.rs:43:3 + --> $DIR/instrument_fn.rs:44:3 | LL | #[instrument_fn = 1] | ^^^^^^^^^^^^^^^^- @@ -114,14 +124,14 @@ LL + #[instrument_fn = "on|off"] | error: the `instrument_fn` attribute cannot be used on closures - --> $DIR/instrument_fn.rs:47:16 + --> $DIR/instrument_fn.rs:48:16 | LL | let _x = #[instrument_fn = "on"] | ^^^^^^^^^^^^^ | = help: the `instrument_fn` attribute can be applied to functions and methods -error: aborting due to 13 previous errors +error: aborting due to 14 previous errors Some errors have detailed explanations: E0539, E0658, E0805. For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/lint/unused/unused-doc-comments-edge-cases.rs b/tests/ui/lint/unused/unused-doc-comments-edge-cases.rs index ba32fb566e83b..09e386879ba1c 100644 --- a/tests/ui/lint/unused/unused-doc-comments-edge-cases.rs +++ b/tests/ui/lint/unused/unused-doc-comments-edge-cases.rs @@ -20,7 +20,7 @@ fn doc_comment_between_if_else(num: u8) -> bool { } fn doc_comment_on_expr(num: u8) -> bool { - /// useless doc comment + /// useless doc comment //~ ERROR attributes on some expressions are unstable //~^ ERROR: attributes on expressions are experimental //~| ERROR: unused doc comment num == 3 diff --git a/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr b/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr index 0f0288c6def60..6c8c948f2d9d4 100644 --- a/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr +++ b/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr @@ -8,13 +8,23 @@ error[E0658]: attributes on expressions are experimental --> $DIR/unused-doc-comments-edge-cases.rs:23:5 | LL | /// useless doc comment - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #15701 for more information = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = help: `///` is used for outer documentation comments; for a plain comment, use `//` +error[E0658]: attributes on some expressions are unstable + --> $DIR/unused-doc-comments-edge-cases.rs:23:5 + | +LL | /// useless doc comment + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error: unused doc comment --> $DIR/unused-doc-comments-edge-cases.rs:6:9 | @@ -35,7 +45,7 @@ error: unused doc comment --> $DIR/unused-doc-comments-edge-cases.rs:23:5 | LL | /// useless doc comment - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | num == 3 | --- rustdoc does not generate documentation for expressions @@ -112,7 +122,7 @@ help: you might have meant to return this value LL | return true; | ++++++ + -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors Some errors have detailed explanations: E0308, E0658. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index 242a91cab7e77..27af6ea93d2ad 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -16,6 +16,7 @@ #![feature(mut_restriction)] #![feature(never_patterns)] #![feature(specialization)] +#![feature(stmt_expr_attributes)] #![feature(trait_alias)] #![feature(try_blocks)] #![feature(yeet_expr)] diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs index 18f7b80fc9cea..b96043bc50fb4 100644 --- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs +++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs @@ -28,7 +28,7 @@ fn main() {} //~^ ERROR an inner attribute is not permitted in this context #[cfg(false)] fn e() { let _ = move || #![attr] {foo}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(false)] fn e() { let _ = #[attr] ..#[attr] 0; } +#[cfg(false)] fn e() { let _ = #[attr] ..#[attr] 0; } //~ ERROR attributes on some expressions are unstable //~^ ERROR attributes are not allowed on range expressions starting with `..` #[cfg(false)] fn e() { let _ = #[attr] ..; } //~^ ERROR attributes are not allowed on range expressions starting with `..` diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr index 86ef1ca681cf7..8c80659e358c9 100644 --- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr +++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr @@ -481,6 +481,17 @@ error: expected statement after outer attribute LL | #[cfg(false)] fn e() { { fn foo() { #[attr] } } } | ^^^^^^^ -error: aborting due to 53 previous errors +error[E0658]: attributes on some expressions are unstable + --> $DIR/attr-stmt-expr-attr-bad.rs:31:42 + | +LL | #[cfg(false)] fn e() { let _ = #[attr] ..#[attr] 0; } + | ^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 54 previous errors -For more information about this error, try `rustc --explain E0586`. +Some errors have detailed explanations: E0586, E0658. +For more information about an error, try `rustc --explain E0586`. diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-119271-never-arm-attr-in-guard.rs b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-119271-never-arm-attr-in-guard.rs index 715f5874b2cc2..9855c78729907 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-119271-never-arm-attr-in-guard.rs +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-119271-never-arm-attr-in-guard.rs @@ -5,6 +5,7 @@ fn attr_in_guard() { Some(!) //~ ERROR `!` patterns are experimental //~^ ERROR: mismatched types if #[deny(unused_mut)] //~ ERROR attributes on expressions are experimental + //~^ ERROR attributes on some expressions are unstable false //~ ERROR a guard on a never pattern will never be run } match false {} //~ ERROR: `bool` is non-empty diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-119271-never-arm-attr-in-guard.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-119271-never-arm-attr-in-guard.stderr index f16f5e5be8734..b28f34d6eca79 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-119271-never-arm-attr-in-guard.stderr +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-119271-never-arm-attr-in-guard.stderr @@ -8,6 +8,16 @@ LL | if #[deny(unused_mut)] = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: attributes on some expressions are unstable + --> $DIR/ICE-119271-never-arm-attr-in-guard.rs:7:16 + | +LL | if #[deny(unused_mut)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: `!` patterns are experimental --> $DIR/ICE-119271-never-arm-attr-in-guard.rs:5:14 | @@ -19,7 +29,7 @@ LL | Some(!) = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: a guard on a never pattern will never be run - --> $DIR/ICE-119271-never-arm-attr-in-guard.rs:8:13 + --> $DIR/ICE-119271-never-arm-attr-in-guard.rs:9:13 | LL | false | ^^^^^ help: remove this guard @@ -33,7 +43,7 @@ LL | Some(!) = note: the matched value is of type `u32` error[E0004]: non-exhaustive patterns: type `bool` is non-empty - --> $DIR/ICE-119271-never-arm-attr-in-guard.rs:10:11 + --> $DIR/ICE-119271-never-arm-attr-in-guard.rs:11:11 | LL | match false {} | ^^^^^ @@ -46,7 +56,7 @@ LL + _ => todo!(), LL ~ } | -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0004, E0658. For more information about an error, try `rustc --explain E0004`.