/// Parses an expression, forcing tokens to be collected
pub fn parse_expr_force_collect(&mut self) -> PResult<'a, P<Expr>> {
- // If we have outer attributes, then the call to `collect_tokens_trailing_token`
- // will be made for us.
- if matches!(self.token.kind, TokenKind::Pound | TokenKind::DocComment(..)) {
- self.parse_expr()
- } else {
- // If we don't have outer attributes, then we need to ensure
- // that collection happens by using `collect_tokens_no_attrs`.
- // Expression don't support custom inner attributes, so `parse_expr`
- // will never try to collect tokens if we don't have outer attributes.
- self.collect_tokens_no_attrs(|this| this.parse_expr())
- }
+ self.collect_tokens_no_attrs(|this| this.parse_expr())
}
pub fn parse_anon_const_expr(&mut self) -> PResult<'a, AnonConst> {
}
}
- fn parse_tuple_parens_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_tuple_parens_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
self.expect(&token::OpenDelim(token::Paren))?;
- attrs.extend(self.parse_inner_attributes()?); // `(#![foo] a, b, ...)` is OK.
let (es, trailing_comma) = match self.parse_seq_to_end(
&token::CloseDelim(token::Paren),
SeqSep::trailing_allowed(token::Comma),
self.maybe_recover_from_bad_qpath(expr, true)
}
- fn parse_array_or_repeat_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_array_or_repeat_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
self.bump(); // `[`
- attrs.extend(self.parse_inner_attributes()?);
-
let close = &token::CloseDelim(token::Bracket);
let kind = if self.eat(close) {
// Empty vector
}
/// Parses a `match ... { ... }` expression (`match` token already eaten).
- fn parse_match_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_match_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
let match_span = self.prev_token.span;
let lo = self.prev_token.span;
let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
}
return Err(e);
}
- attrs.extend(self.parse_inner_attributes()?);
let mut arms: Vec<Arm> = Vec::new();
while self.token != token::CloseDelim(token::Brace) {
pub(super) fn parse_struct_expr(
&mut self,
pth: ast::Path,
- mut attrs: AttrVec,
+ attrs: AttrVec,
recover: bool,
) -> PResult<'a, P<Expr>> {
let mut fields = Vec::new();
let mut base = ast::StructRest::None;
let mut recover_async = false;
- attrs.extend(self.parse_inner_attributes()?);
-
let mut async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| {
recover_async = true;
e.span_label(span, "`async` blocks are only allowed in Rust 2018 or later");
attrs: AttrWrapper,
f: impl FnOnce(&mut Self, Vec<ast::Attribute>) -> PResult<'a, P<Expr>>,
) -> PResult<'a, P<Expr>> {
- // FIXME - come up with a nice way to properly forward `ForceCollect`from
- // the nonterminal parsing code. TThis approach iscorrect, but will cause
- // us to unnecessarily capture tokens for exprs that have only builtin
- // attributes. Revisit this before #![feature(stmt_expr_attributes)] is stabilized
- let force_collect = if attrs.is_empty() { ForceCollect::No } else { ForceCollect::Yes };
- self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
+ self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
let res = f(this, attrs)?;
let trailing = if this.restrictions.contains(Restrictions::STMT_EXPR)
&& this.token.kind == token::Semi
{
TrailingToken::Semi
} else {
- TrailingToken::None
+ // FIXME - pass this through from the place where we know
+ // we need a comma, rather than assuming that `#[attr] expr,`
+ // always captures a trailing comma
+ TrailingToken::MaybeComma
};
Ok((res, trailing))
})