diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7f766e63e0600..71932f02017ca 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -975,7 +975,9 @@ impl UnOp { } } -/// A statement +/// A statement. No `attrs` or `tokens` fields because each `StmtKind` variant +/// contains an AST node with those fields. (Except for `StmtKind::Empty`, +/// which never has attrs or tokens) #[derive(Clone, Encodable, Decodable, Debug)] pub struct Stmt { pub id: NodeId, diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index f678d11213c71..efb9526eabcfd 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -133,6 +133,8 @@ parse_dot_dot_dot_for_remaining_fields = expected field pattern, found `{$token_ parse_dot_dot_dot_range_to_pattern_not_allowed = range-to patterns with `...` are not allowed .suggestion = use `..=` instead +parse_dot_dot_range_attribute = attributes are not allowed on range expressions starting with `..` + parse_dotdotdot = unexpected token: `...` .suggest_exclusive_range = use `..` for an exclusive range .suggest_inclusive_range = or `..=` for an inclusive range diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 936fc9d6b7790..46e1573485304 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2990,3 +2990,10 @@ pub(crate) struct ExprRArrowCall { #[suggestion(style = "short", applicability = "machine-applicable", code = ".")] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(parse_dot_dot_range_attribute)] +pub(crate) struct DotDotRangeAttribute { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index f5c931034fd28..b5480b6b7d210 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -15,7 +15,7 @@ use std::ops::Range; /// for the attribute target. This allows us to perform cfg-expansion on /// a token stream before we invoke a derive proc-macro. /// -/// This wrapper prevents direct access to the underlying `ast::AttrVec>`. +/// This wrapper prevents direct access to the underlying `ast::AttrVec`. /// Parsing code can only get access to the underlying attributes /// by passing an `AttrWrapper` to `collect_tokens_trailing_tokens`. /// This makes it difficult to accidentally construct an AST node @@ -177,6 +177,10 @@ impl<'a> Parser<'a> { /// into a `LazyAttrTokenStream`, and returned along with the result /// of the callback. /// + /// The `attrs` passed in are in `AttrWrapper` form, which is opaque. The + /// `AttrVec` within is passed to `f`. See the comment on `AttrWrapper` for + /// details. + /// /// Note: If your callback consumes an opening delimiter /// (including the case where you call `collect_tokens` /// when the current token is an opening delimiter), diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index c1aac84bcaec7..c2b91488a117a 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2499,7 +2499,8 @@ impl<'a> Parser<'a> { /// wrapped in braces. pub(super) fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, P> { let start = self.token.span; - let expr = self.parse_expr_res(Restrictions::CONST_EXPR, None).map_err(|mut err| { + let attrs = self.parse_outer_attributes()?; + let expr = self.parse_expr_res(Restrictions::CONST_EXPR, attrs).map_err(|mut err| { err.span_label( start.shrink_to_lo(), "while parsing a const generic argument starting here", @@ -2621,7 +2622,10 @@ impl<'a> Parser<'a> { if is_op_or_dot { self.bump(); } - match self.parse_expr_res(Restrictions::CONST_EXPR, None) { + match (|| { + let attrs = self.parse_outer_attributes()?; + self.parse_expr_res(Restrictions::CONST_EXPR, attrs) + })() { Ok(expr) => { // Find a mistake like `MyTrait`. if token::EqEq == snapshot.token.kind { @@ -2675,7 +2679,10 @@ impl<'a> Parser<'a> { &mut self, mut snapshot: SnapshotParser<'a>, ) -> Option> { - match snapshot.parse_expr_res(Restrictions::CONST_EXPR, None) { + match (|| { + let attrs = self.parse_outer_attributes()?; + snapshot.parse_expr_res(Restrictions::CONST_EXPR, attrs) + })() { // Since we don't know the exact reason why we failed to parse the type or the // expression, employ a simple heuristic to weed out some pathological cases. Ok(expr) if let token::Comma | token::Gt = snapshot.token.kind => { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 5decfc142dacf..09f706143fa77 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -70,28 +70,10 @@ macro_rules! maybe_whole_expr { #[derive(Debug)] pub(super) enum LhsExpr { - NotYetParsed, - AttributesParsed(AttrWrapper), - AlreadyParsed { expr: P, starts_statement: bool }, -} - -impl From> for LhsExpr { - /// Converts `Some(attrs)` into `LhsExpr::AttributesParsed(attrs)` - /// and `None` into `LhsExpr::NotYetParsed`. - /// - /// This conversion does not allocate. - fn from(o: Option) -> Self { - if let Some(attrs) = o { LhsExpr::AttributesParsed(attrs) } else { LhsExpr::NotYetParsed } - } -} - -impl From> for LhsExpr { - /// Converts the `expr: P` into `LhsExpr::AlreadyParsed { expr, starts_statement: false }`. - /// - /// This conversion does not allocate. - fn from(expr: P) -> Self { - LhsExpr::AlreadyParsed { expr, starts_statement: false } - } + // Already parsed just the outer attributes. + Unparsed { attrs: AttrWrapper }, + // Already parsed the expression. + Parsed { expr: P, starts_statement: bool }, } #[derive(Debug)] @@ -112,12 +94,16 @@ impl<'a> Parser<'a> { pub fn parse_expr(&mut self) -> PResult<'a, P> { self.current_closure.take(); - self.parse_expr_res(Restrictions::empty(), None) + let attrs = self.parse_outer_attributes()?; + self.parse_expr_res(Restrictions::empty(), attrs) } - /// Parses an expression, forcing tokens to be collected + /// Parses an expression, forcing tokens to be collected. pub fn parse_expr_force_collect(&mut self) -> PResult<'a, P> { - self.collect_tokens_no_attrs(|this| this.parse_expr()) + self.current_closure.take(); + + let attrs = self.parse_outer_attributes()?; + self.collect_tokens_no_attrs(|this| this.parse_expr_res(Restrictions::empty(), attrs)) } pub fn parse_expr_anon_const(&mut self) -> PResult<'a, AnonConst> { @@ -125,7 +111,8 @@ impl<'a> Parser<'a> { } fn parse_expr_catch_underscore(&mut self, restrictions: Restrictions) -> PResult<'a, P> { - match self.parse_expr_res(restrictions, None) { + let attrs = self.parse_outer_attributes()?; + match self.parse_expr_res(restrictions, attrs) { Ok(expr) => Ok(expr), Err(err) => match self.token.ident() { Some((Ident { name: kw::Underscore, .. }, IdentIsRaw::No)) @@ -152,21 +139,9 @@ impl<'a> Parser<'a> { pub(super) fn parse_expr_res( &mut self, r: Restrictions, - already_parsed_attrs: Option, - ) -> PResult<'a, P> { - self.with_res(r, |this| this.parse_expr_assoc(already_parsed_attrs)) - } - - /// Parses an associative expression. - /// - /// This parses an expression accounting for associativity and precedence of the operators in - /// the expression. - #[inline] - fn parse_expr_assoc( - &mut self, - already_parsed_attrs: Option, + attrs: AttrWrapper, ) -> PResult<'a, P> { - self.parse_expr_assoc_with(0, already_parsed_attrs.into()) + self.with_res(r, |this| this.parse_expr_assoc_with(0, LhsExpr::Unparsed { attrs })) } /// Parses an associative expression with operators of at least `min_prec` precedence. @@ -176,18 +151,17 @@ impl<'a> Parser<'a> { lhs: LhsExpr, ) -> PResult<'a, P> { let mut starts_stmt = false; - let mut lhs = if let LhsExpr::AlreadyParsed { expr, starts_statement } = lhs { - starts_stmt = starts_statement; - expr - } else { - let attrs = match lhs { - LhsExpr::AttributesParsed(attrs) => Some(attrs), - _ => None, - }; - if self.token.is_range_separator() { - return self.parse_expr_prefix_range(attrs); - } else { - self.parse_expr_prefix(attrs)? + let mut lhs = match lhs { + LhsExpr::Parsed { expr, starts_statement } => { + starts_stmt = starts_statement; + expr + } + LhsExpr::Unparsed { attrs } => { + if self.token.is_range_separator() { + return self.parse_expr_prefix_range(attrs); + } else { + self.parse_expr_prefix(attrs)? + } } }; @@ -325,7 +299,8 @@ impl<'a> Parser<'a> { Fixity::None => 1, }; let rhs = self.with_res(restrictions - Restrictions::STMT_EXPR, |this| { - this.parse_expr_assoc_with(prec + prec_adjustment, LhsExpr::NotYetParsed) + let attrs = this.parse_outer_attributes()?; + this.parse_expr_assoc_with(prec + prec_adjustment, LhsExpr::Unparsed { attrs }) })?; let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span); @@ -498,8 +473,9 @@ impl<'a> Parser<'a> { ) -> PResult<'a, P> { let rhs = if self.is_at_start_of_range_notation_rhs() { let maybe_lt = self.token.clone(); + let attrs = self.parse_outer_attributes()?; Some( - self.parse_expr_assoc_with(prec + 1, LhsExpr::NotYetParsed) + self.parse_expr_assoc_with(prec + 1, LhsExpr::Unparsed { attrs }) .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?, ) } else { @@ -526,7 +502,12 @@ impl<'a> Parser<'a> { } /// Parses prefix-forms of range notation: `..expr`, `..`, `..=expr`. - fn parse_expr_prefix_range(&mut self, attrs: Option) -> PResult<'a, P> { + fn parse_expr_prefix_range(&mut self, attrs: AttrWrapper) -> PResult<'a, P> { + if !attrs.is_empty() { + let err = errors::DotDotRangeAttribute { span: self.token.span }; + self.dcx().emit_err(err); + } + // Check for deprecated `...` syntax. if self.token == token::DotDotDot { self.err_dotdotdot_syntax(self.token.span); @@ -543,20 +524,20 @@ impl<'a> Parser<'a> { _ => RangeLimits::Closed, }; let op = AssocOp::from_token(&self.token); - // FIXME: `parse_prefix_range_expr` is called when the current - // token is `DotDot`, `DotDotDot`, or `DotDotEq`. If we haven't already - // parsed attributes, then trying to parse them here will always fail. - // We should figure out how we want attributes on range expressions to work. - let attrs = self.parse_or_use_outer_attributes(attrs)?; + let attrs = self.parse_outer_attributes()?; self.collect_tokens_for_expr(attrs, |this, attrs| { let lo = this.token.span; let maybe_lt = this.look_ahead(1, |t| t.clone()); this.bump(); let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() { // RHS must be parsed with more associativity than the dots. - this.parse_expr_assoc_with(op.unwrap().precedence() + 1, LhsExpr::NotYetParsed) - .map(|x| (lo.to(x.span), Some(x))) - .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))? + let attrs = this.parse_outer_attributes()?; + this.parse_expr_assoc_with( + op.unwrap().precedence() + 1, + LhsExpr::Unparsed { attrs }, + ) + .map(|x| (lo.to(x.span), Some(x))) + .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))? } else { (lo, None) }; @@ -566,8 +547,7 @@ impl<'a> Parser<'a> { } /// Parses a prefix-unary-operator expr. - fn parse_expr_prefix(&mut self, attrs: Option) -> PResult<'a, P> { - let attrs = self.parse_or_use_outer_attributes(attrs)?; + fn parse_expr_prefix(&mut self, attrs: AttrWrapper) -> PResult<'a, P> { let lo = self.token.span; macro_rules! make_it { @@ -616,7 +596,8 @@ impl<'a> Parser<'a> { this.dcx().emit_err(err); this.bump(); - this.parse_expr_prefix(None) + let attrs = this.parse_outer_attributes()?; + this.parse_expr_prefix(attrs) } // Recover from `++x`: token::BinOp(token::Plus) @@ -629,7 +610,7 @@ impl<'a> Parser<'a> { this.bump(); this.bump(); - let operand_expr = this.parse_expr_dot_or_call(Default::default())?; + let operand_expr = this.parse_expr_dot_or_call(attrs)?; this.recover_from_prefix_increment(operand_expr, pre_span, starts_stmt) } token::Ident(..) if this.token.is_keyword(kw::Box) => { @@ -638,13 +619,14 @@ impl<'a> Parser<'a> { token::Ident(..) if this.may_recover() && this.is_mistaken_not_ident_negation() => { make_it!(this, attrs, |this, _| this.recover_not_expr(lo)) } - _ => return this.parse_expr_dot_or_call(Some(attrs)), + _ => return this.parse_expr_dot_or_call(attrs), } } fn parse_expr_prefix_common(&mut self, lo: Span) -> PResult<'a, (Span, P)> { self.bump(); - let expr = self.parse_expr_prefix(None)?; + let attrs = self.parse_outer_attributes()?; + let expr = self.parse_expr_prefix(attrs)?; let span = self.interpolated_or_expr_span(&expr); Ok((lo.to(span), expr)) } @@ -894,10 +876,11 @@ impl<'a> Parser<'a> { let has_lifetime = self.token.is_lifetime() && self.look_ahead(1, |t| t != &token::Colon); let lifetime = has_lifetime.then(|| self.expect_lifetime()); // For recovery, see below. let (borrow_kind, mutbl) = self.parse_borrow_modifiers(lo); + let attrs = self.parse_outer_attributes()?; let expr = if self.token.is_range_separator() { - self.parse_expr_prefix_range(None) + self.parse_expr_prefix_range(attrs) } else { - self.parse_expr_prefix(None) + self.parse_expr_prefix(attrs) }?; let hi = self.interpolated_or_expr_span(&expr); let span = lo.to(hi); @@ -927,8 +910,7 @@ impl<'a> Parser<'a> { } /// Parses `a.b` or `a(13)` or `a[4]` or just `a`. - fn parse_expr_dot_or_call(&mut self, attrs: Option) -> PResult<'a, P> { - let attrs = self.parse_or_use_outer_attributes(attrs)?; + fn parse_expr_dot_or_call(&mut self, attrs: AttrWrapper) -> PResult<'a, P> { self.collect_tokens_for_expr(attrs, |this, attrs| { let base = this.parse_expr_bottom()?; let span = this.interpolated_or_expr_span(&base); @@ -2365,7 +2347,8 @@ impl<'a> Parser<'a> { self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET; let prev = self.prev_token.clone(); let token = self.token.clone(); - match self.parse_expr_res(restrictions, None) { + let attrs = self.parse_outer_attributes()?; + match self.parse_expr_res(restrictions, attrs) { Ok(expr) => expr, Err(err) => self.recover_closure_body(err, before, prev, token, lo, decl_hi)?, } @@ -2613,8 +2596,9 @@ impl<'a> Parser<'a> { /// Parses the condition of a `if` or `while` expression. fn parse_expr_cond(&mut self) -> PResult<'a, P> { + let attrs = self.parse_outer_attributes()?; let mut cond = - self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, None)?; + self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, attrs)?; CondChecker::new(self).visit_expr(&mut cond); @@ -2661,7 +2645,11 @@ impl<'a> Parser<'a> { } else { self.expect(&token::Eq)?; } - let expr = self.parse_expr_assoc_with(1 + prec_let_scrutinee_needs_par(), None.into())?; + let attrs = self.parse_outer_attributes()?; + let expr = self.parse_expr_assoc_with( + 1 + prec_let_scrutinee_needs_par(), + LhsExpr::Unparsed { attrs }, + )?; let span = lo.to(expr.span); Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span, recovered))) } @@ -2794,7 +2782,8 @@ impl<'a> Parser<'a> { (Err(err), Some((start_span, left))) if self.eat_keyword(kw::In) => { // We know for sure we have seen `for ($SOMETHING in`. In the happy path this would // happen right before the return of this method. - let expr = match self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None) { + let attrs = self.parse_outer_attributes()?; + let expr = match self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, attrs) { Ok(expr) => expr, Err(expr_err) => { // We don't know what followed the `in`, so cancel and bubble up the @@ -2828,7 +2817,8 @@ impl<'a> Parser<'a> { self.error_missing_in_for_loop(); } self.check_for_for_in_in_typo(self.prev_token.span); - let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; + let attrs = self.parse_outer_attributes()?; + let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, attrs)?; Ok((pat, expr)) } @@ -2940,7 +2930,8 @@ impl<'a> Parser<'a> { /// Parses a `match ... { ... }` expression (`match` token already eaten). fn parse_expr_match(&mut self) -> PResult<'a, P> { let match_span = self.prev_token.span; - let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; + let attrs = self.parse_outer_attributes()?; + let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, attrs)?; self.parse_match_block(match_span, match_span, scrutinee, MatchKind::Prefix) } @@ -3144,8 +3135,9 @@ impl<'a> Parser<'a> { let arrow_span = this.prev_token.span; let arm_start_span = this.token.span; + let attrs = this.parse_outer_attributes()?; let expr = - this.parse_expr_res(Restrictions::STMT_EXPR, None).map_err(|mut err| { + this.parse_expr_res(Restrictions::STMT_EXPR, attrs).map_err(|mut err| { err.span_label(arrow_span, "while parsing the `match` arm starting here"); err })?; @@ -3350,7 +3342,8 @@ impl<'a> Parser<'a> { } fn parse_match_guard_condition(&mut self) -> PResult<'a, P> { - self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, None).map_err( + let attrs = self.parse_outer_attributes()?; + self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, attrs).map_err( |mut err| { if self.prev_token == token::OpenDelim(Delimiter::Brace) { let sugg_sp = self.prev_token.span.shrink_to_lo(); diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 6dee913c14166..2f12459da573e 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1330,17 +1330,6 @@ impl<'a> Parser<'a> { }) } - fn parse_or_use_outer_attributes( - &mut self, - already_parsed_attrs: Option, - ) -> PResult<'a, AttrWrapper> { - if let Some(attrs) = already_parsed_attrs { - Ok(attrs) - } else { - self.parse_outer_attributes() - } - } - /// Parses a single token tree from the input. pub fn parse_token_tree(&mut self) -> TokenTree { match self.token.kind { diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index f7f06ab7cbdd8..03aea0888d955 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -10,7 +10,7 @@ use crate::errors::{ UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, }; -use crate::parser::expr::could_be_unclosed_char_literal; +use crate::parser::expr::{could_be_unclosed_char_literal, LhsExpr}; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor}; use rustc_ast::ptr::P; @@ -398,9 +398,8 @@ impl<'a> Parser<'a> { // Parse an associative expression such as `+ expr`, `% expr`, ... // Assignements, ranges and `|` are disabled by [`Restrictions::IS_PAT`]. - if let Ok(expr) = - snapshot.parse_expr_assoc_with(0, expr.into()).map_err(|err| err.cancel()) - { + let lhs = LhsExpr::Parsed { expr, starts_statement: false }; + if let Ok(expr) = snapshot.parse_expr_assoc_with(0, lhs).map_err(|err| err.cancel()) { // We got a valid expression. self.restore_snapshot(snapshot); self.restrictions.remove(Restrictions::IS_PAT); diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 9beecd9849fbd..da8d1194325b4 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -920,7 +920,8 @@ impl<'a> Parser<'a> { // Fall back by trying to parse a const-expr expression. If we successfully do so, // then we should report an error that it needs to be wrapped in braces. let snapshot = self.create_snapshot_for_diagnostic(); - match self.parse_expr_res(Restrictions::CONST_EXPR, None) { + let attrs = self.parse_outer_attributes()?; + match self.parse_expr_res(Restrictions::CONST_EXPR, attrs) { Ok(expr) => { return Ok(Some(self.dummy_const_arg_needs_braces( self.dcx().struct_span_err(expr.span, "invalid const generic expression"), diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 104aae9b257e2..d65f6ff68eeeb 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -126,9 +126,9 @@ impl<'a> Parser<'a> { // Remainder are line-expr stmts. let e = match force_collect { ForceCollect::Yes => self.collect_tokens_no_attrs(|this| { - this.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs)) + this.parse_expr_res(Restrictions::STMT_EXPR, attrs) })?, - ForceCollect::No => self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))?, + ForceCollect::No => self.parse_expr_res(Restrictions::STMT_EXPR, attrs)?, }; if matches!(e.kind, ExprKind::Assign(..)) && self.eat_keyword(kw::Else) { let bl = self.parse_block()?; @@ -174,10 +174,7 @@ impl<'a> Parser<'a> { // Perform this outside of the `collect_tokens_trailing_token` closure, // since our outer attributes do not apply to this part of the expression let expr = self.with_res(Restrictions::STMT_EXPR, |this| { - this.parse_expr_assoc_with( - 0, - LhsExpr::AlreadyParsed { expr, starts_statement: true }, - ) + this.parse_expr_assoc_with(0, LhsExpr::Parsed { expr, starts_statement: true }) })?; Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr))) } else { @@ -210,10 +207,8 @@ impl<'a> Parser<'a> { let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac)); let e = self.maybe_recover_from_bad_qpath(e)?; let e = self.parse_expr_dot_or_call_with(e, lo, attrs)?; - let e = self.parse_expr_assoc_with( - 0, - LhsExpr::AlreadyParsed { expr: e, starts_statement: false }, - )?; + let e = self + .parse_expr_assoc_with(0, LhsExpr::Parsed { expr: e, starts_statement: false })?; StmtKind::Expr(e) }; Ok(self.mk_stmt(lo.to(hi), kind)) 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 d1950087c4c2d..26761a1d2544c 100644 --- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs +++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs @@ -28,9 +28,9 @@ fn main() {} #[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; } -//~^ ERROR expected expression, found `..` +//~^ ERROR attributes are not allowed on range expressions starting with `..` #[cfg(FALSE)] fn e() { let _ = #[attr] ..; } -//~^ ERROR expected expression, found `..` +//~^ ERROR attributes are not allowed on range expressions starting with `..` #[cfg(FALSE)] fn e() { let _ = #[attr] &#![attr] 0; } //~^ ERROR an inner attribute is not permitted in this context #[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; } 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 e46c591080d43..3593c5182ce9f 100644 --- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr +++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr @@ -119,17 +119,17 @@ LL | #[cfg(FALSE)] fn e() { let _ = move || #![attr] {foo}; } = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files = note: outer attributes, like `#[test]`, annotate the item following them -error: expected expression, found `..` +error: attributes are not allowed on range expressions starting with `..` --> $DIR/attr-stmt-expr-attr-bad.rs:30:40 | LL | #[cfg(FALSE)] fn e() { let _ = #[attr] ..#[attr] 0; } - | ^^ expected expression + | ^^ -error: expected expression, found `..` +error: attributes are not allowed on range expressions starting with `..` --> $DIR/attr-stmt-expr-attr-bad.rs:32:40 | LL | #[cfg(FALSE)] fn e() { let _ = #[attr] ..; } - | ^^ expected expression + | ^^ error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:34:41 diff --git a/tests/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout b/tests/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout index 6523f2485cd1f..0168689b605ff 100644 --- a/tests/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout +++ b/tests/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout @@ -1,4 +1,4 @@ -PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = #[allow(warnings)] #[allow(warnings)] 0; 0 }, } +PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = #[allow(warnings)] 0; 0 }, } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "enum", @@ -39,31 +39,6 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Group { delimiter: None, stream: TokenStream [ - Punct { - ch: '#', - spacing: Alone, - span: #0 bytes(543..544), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "allow", - span: #0 bytes(545..550), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "warnings", - span: #0 bytes(551..559), - }, - ], - span: #0 bytes(550..560), - }, - ], - span: #0 bytes(544..561), - }, Punct { ch: '#', spacing: Alone,