use crate::ast::{GenericParam, GenericParamKind};
use crate::ast::GenericArg;
use crate::ast::{Ident, ImplItem, IsAsync, IsAuto, Item, ItemKind};
-use crate::ast::{Label, Lifetime, Lit, LitKind};
+use crate::ast::{Label, Lifetime};
use crate::ast::{Local, LocalSource};
use crate::ast::MacStmtStyle;
use crate::ast::{Mac, Mac_, MacDelimiter};
use crate::{ast, attr};
use crate::ext::base::DummyResult;
use crate::source_map::{self, SourceMap, Spanned, respan};
-use crate::parse::{self, SeqSep, classify, token};
+use crate::parse::{SeqSep, classify, literal, token};
use crate::parse::lexer::{TokenAndSpan, UnmatchedBrace};
use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
use crate::parse::token::DelimToken;
use crate::parse::PResult;
use crate::ThinVec;
use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint};
-use crate::symbol::{Symbol, keywords};
+use crate::symbol::{keywords, sym, Symbol};
use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError};
use rustc_target::spec::abi::{self, Abi};
-use syntax_pos::{Span, MultiSpan, BytePos, FileName};
+use syntax_pos::{
+ Span, MultiSpan, BytePos, FileName,
+ hygiene::CompilerDesugaringKind,
+};
use log::{debug, trace};
use std::borrow::Cow;
Interpolated,
Eof,
Ident,
+ BitOr,
Other,
}
})
}
- fn this_token_descr(&self) -> String {
+ crate fn this_token_descr(&self) -> String {
if let Some(prefix) = self.token_descr() {
format!("{} `{}`", prefix, self.this_token_to_string())
} else {
}
}
- fn unexpected_last<T>(&self, t: &token::Token) -> PResult<'a, T> {
- let token_str = pprust::token_to_string(t);
- Err(self.span_fatal(self.prev_span, &format!("unexpected token: `{}`", token_str)))
- }
-
crate fn unexpected<T>(&mut self) -> PResult<'a, T> {
match self.expect_one_of(&[], &[]) {
Err(e) => Err(e),
}
fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<ast::Name>) {
- match suffix {
- None => {/* everything ok */}
- Some(suf) => {
- let text = suf.as_str();
- if text.is_empty() {
- self.span_bug(sp, "found empty literal suffix in Some")
- }
- let mut err = if kind == "a tuple index" &&
- ["i32", "u32", "isize", "usize"].contains(&text.to_string().as_str())
- {
- // #59553: warn instead of reject out of hand to allow the fix to percolate
- // through the ecosystem when people fix their macros
- let mut err = self.struct_span_warn(
- sp,
- &format!("suffixes on {} are invalid", kind),
- );
- err.note(&format!(
- "`{}` is *temporarily* accepted on tuple index fields as it was \
- incorrectly accepted on stable for a few releases",
- text,
- ));
- err.help(
- "on proc macros, you'll want to use `syn::Index::from` or \
- `proc_macro::Literal::*_unsuffixed` for code that will desugar \
- to tuple field access",
- );
- err.note(
- "for more context, see https://github.com/rust-lang/rust/issues/60210",
- );
- err
- } else {
- self.struct_span_err(sp, &format!("suffixes on {} are invalid", kind))
- };
- err.span_label(sp, format!("invalid suffix `{}`", text));
- err.emit();
- }
- }
+ literal::expect_no_suffix(sp, &self.sess.span_diagnostic, kind, suffix)
}
/// Attempts to consume a `<`. If `<<` is seen, replaces it with a single
token::DocComment(..) => PrevTokenKind::DocComment,
token::Comma => PrevTokenKind::Comma,
token::BinOp(token::Plus) => PrevTokenKind::Plus,
+ token::BinOp(token::Or) => PrevTokenKind::BitOr,
token::Interpolated(..) => PrevTokenKind::Interpolated,
token::Eof => PrevTokenKind::Eof,
token::Ident(..) => PrevTokenKind::Ident,
})
}
- fn look_ahead_span(&self, dist: usize) -> Span {
+ crate fn look_ahead_span(&self, dist: usize) -> Span {
if dist == 0 {
return self.span
}
crate fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
self.sess.span_diagnostic.struct_span_err(sp, m)
}
- fn struct_span_warn<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
- self.sess.span_diagnostic.struct_span_warn(sp, m)
- }
crate fn span_bug<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> ! {
self.sess.span_diagnostic.span_bug(sp, m)
}
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
- let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| {
+ let mut decl = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| {
// This is somewhat dubious; We don't want to allow
// argument names to be left off if there is a
// definition...
p.parse_arg_general(p.span.rust_2018(), true, false)
})?;
generics.where_clause = self.parse_where_clause()?;
- self.construct_async_arguments(&mut asyncness, &d);
+ self.construct_async_arguments(&mut asyncness, &mut decl);
let sig = ast::MethodSig {
header: FnHeader {
abi,
asyncness,
},
- decl: d,
+ decl,
};
let body = match self.token {
Ok(MutTy { ty: t, mutbl: mutbl })
}
- fn is_named_argument(&mut self) -> bool {
+ fn is_named_argument(&self) -> bool {
let offset = match self.token {
token::Interpolated(ref nt) => match **nt {
token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
/// This version of parse arg doesn't necessarily require identifier names.
fn parse_arg_general(&mut self, require_name: bool, is_trait_item: bool,
allow_c_variadic: bool) -> PResult<'a, Arg> {
- maybe_whole!(self, NtArg, |x| x);
-
if let Ok(Some(_)) = self.parse_self_arg() {
let mut err = self.struct_span_err(self.prev_span,
"unexpected `self` argument in function");
}
}
- /// Matches `token_lit = LIT_INTEGER | ...`.
- fn parse_lit_token(&mut self) -> PResult<'a, LitKind> {
- let out = match self.token {
- token::Interpolated(ref nt) => match **nt {
- token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node {
- ExprKind::Lit(ref lit) => { lit.node.clone() }
- _ => { return self.unexpected_last(&self.token); }
- },
- _ => { return self.unexpected_last(&self.token); }
- },
- token::Literal(lit, suf) => {
- let diag = Some((self.span, &self.sess.span_diagnostic));
- let (suffix_illegal, result) = parse::lit_token(lit, suf, diag);
-
- if suffix_illegal {
- let sp = self.span;
- self.expect_no_suffix(sp, &format!("a {}", lit.literal_name()), suf)
- }
-
- result.unwrap()
- }
- token::Dot if self.look_ahead(1, |t| match t {
- token::Literal(parse::token::Lit::Integer(_) , _) => true,
- _ => false,
- }) => { // recover from `let x = .4;`
- let lo = self.span;
- self.bump();
- if let token::Literal(
- parse::token::Lit::Integer(val),
- suffix,
- ) = self.token {
- let suffix = suffix.and_then(|s| {
- let s = s.as_str();
- if s == "f32" {
- Some("f32")
- } else if s == "f64" {
- Some("f64")
- } else {
- None
- }
- }).unwrap_or("");
- self.bump();
- let sp = lo.to(self.prev_span);
- let mut err = self.diagnostic()
- .struct_span_err(sp, "float literals must have an integer part");
- err.span_suggestion(
- sp,
- "must have an integer part",
- format!("0.{}{}", val, suffix),
- Applicability::MachineApplicable,
- );
- err.emit();
- return Ok(match suffix {
- "f32" => ast::LitKind::Float(val, ast::FloatTy::F32),
- "f64" => ast::LitKind::Float(val, ast::FloatTy::F64),
- _ => ast::LitKind::FloatUnsuffixed(val),
- });
- } else {
- unreachable!();
- };
- }
- _ => { return self.unexpected_last(&self.token); }
- };
-
- self.bump();
- Ok(out)
- }
-
- /// Matches `lit = true | false | token_lit`.
- crate fn parse_lit(&mut self) -> PResult<'a, Lit> {
- let lo = self.span;
- let lit = if self.eat_keyword(keywords::True) {
- LitKind::Bool(true)
- } else if self.eat_keyword(keywords::False) {
- LitKind::Bool(false)
- } else {
- let lit = self.parse_lit_token()?;
- lit
- };
- Ok(source_map::Spanned { node: lit, span: lo.to(self.prev_span) })
- }
-
/// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`).
crate fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
maybe_whole_expr!(self);
let ident = self.parse_path_segment_ident()?;
let is_args_start = |token: &token::Token| match *token {
- token::Lt | token::BinOp(token::Shl) | token::OpenDelim(token::Paren) => true,
+ token::Lt | token::BinOp(token::Shl) | token::OpenDelim(token::Paren)
+ | token::LArrow => true,
_ => false,
};
let check_args_start = |this: &mut Self| {
})
}
- fn mk_expr(&mut self, span: Span, node: ExprKind, attrs: ThinVec<Attribute>) -> P<Expr> {
+ fn mk_expr(&self, span: Span, node: ExprKind, attrs: ThinVec<Attribute>) -> P<Expr> {
P(Expr { node, span, attrs, id: ast::DUMMY_NODE_ID })
}
- fn mk_unary(&mut self, unop: ast::UnOp, expr: P<Expr>) -> ast::ExprKind {
+ fn mk_unary(&self, unop: ast::UnOp, expr: P<Expr>) -> ast::ExprKind {
ExprKind::Unary(unop, expr)
}
- fn mk_binary(&mut self, binop: ast::BinOp, lhs: P<Expr>, rhs: P<Expr>) -> ast::ExprKind {
+ fn mk_binary(&self, binop: ast::BinOp, lhs: P<Expr>, rhs: P<Expr>) -> ast::ExprKind {
ExprKind::Binary(binop, lhs, rhs)
}
- fn mk_call(&mut self, f: P<Expr>, args: Vec<P<Expr>>) -> ast::ExprKind {
+ fn mk_call(&self, f: P<Expr>, args: Vec<P<Expr>>) -> ast::ExprKind {
ExprKind::Call(f, args)
}
- fn mk_index(&mut self, expr: P<Expr>, idx: P<Expr>) -> ast::ExprKind {
+ fn mk_index(&self, expr: P<Expr>, idx: P<Expr>) -> ast::ExprKind {
ExprKind::Index(expr, idx)
}
- fn mk_range(&mut self,
+ fn mk_range(&self,
start: Option<P<Expr>>,
end: Option<P<Expr>>,
limits: RangeLimits)
}
}
- fn mk_assign_op(&mut self, binop: ast::BinOp,
+ fn mk_assign_op(&self, binop: ast::BinOp,
lhs: P<Expr>, rhs: P<Expr>) -> ast::ExprKind {
ExprKind::AssignOp(binop, lhs, rhs)
}
hi = path.span;
return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs));
}
- if self.span.rust_2018() && self.check_keyword(keywords::Async)
- {
- if self.is_async_block() { // check for `async {` and `async move {`
- return self.parse_async_block(attrs);
+ if self.span.rust_2018() && self.check_keyword(keywords::Async) {
+ return if self.is_async_block() { // check for `async {` and `async move {`
+ self.parse_async_block(attrs)
} else {
- return self.parse_lambda_expr(attrs);
- }
+ self.parse_lambda_expr(attrs)
+ };
}
if self.check_keyword(keywords::Move) || self.check_keyword(keywords::Static) {
return self.parse_lambda_expr(attrs);
db.span_label(self.span, "expected expression");
db.note("variable declaration using `let` is a statement");
return Err(db);
+ } else if self.span.rust_2018() && self.eat_keyword(keywords::Await) {
+ // FIXME: remove this branch when `await!` is no longer supported
+ // https://github.com/rust-lang/rust/issues/60610
+ self.expect(&token::Not)?;
+ self.expect(&token::OpenDelim(token::Paren))?;
+ let expr = self.parse_expr()?;
+ self.expect(&token::CloseDelim(token::Paren))?;
+ ex = ExprKind::Await(ast::AwaitOrigin::MacroLike, expr);
} else if self.token.is_path_start() {
let path = self.parse_path(PathStyle::Expr)?;
let msg = format!("expected expression, found {}",
self.this_token_descr());
let mut err = self.fatal(&msg);
+ let sp = self.sess.source_map().start_point(self.span);
+ if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow()
+ .get(&sp)
+ {
+ self.sess.expr_parentheses_needed(&mut err, *sp, None);
+ }
err.span_label(self.span, "expected expression");
return Err(err);
}
"struct literals are not allowed here",
);
err.multipart_suggestion(
- "surround the struct literal with parenthesis",
+ "surround the struct literal with parentheses",
vec![
(lo.shrink_to_lo(), "(".to_string()),
(expr.span.shrink_to_hi(), ")".to_string()),
// Assuming we have just parsed `.`, continue parsing into an expression.
fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
+ if self.span.rust_2018() && self.eat_keyword(keywords::Await) {
+ let span = lo.to(self.prev_span);
+ let await_expr = self.mk_expr(
+ span,
+ ExprKind::Await(ast::AwaitOrigin::FieldLike, self_arg),
+ ThinVec::new(),
+ );
+ return Ok(await_expr);
+ }
let segment = self.parse_path_segment(PathStyle::Expr)?;
self.check_trailing_angle_brackets(&segment, token::OpenDelim(token::Paren));
}
};
- if self.expr_is_complete(&lhs) {
- // Semi-statement forms are odd. See https://github.com/rust-lang/rust/issues/29071
- return Ok(lhs);
+ match (self.expr_is_complete(&lhs), AssocOp::from_token(&self.token)) {
+ (true, None) => {
+ // Semi-statement forms are odd. See https://github.com/rust-lang/rust/issues/29071
+ return Ok(lhs);
+ }
+ (false, _) => {} // continue parsing the expression
+ // An exhaustive check is done in the following block, but these are checked first
+ // because they *are* ambiguous but also reasonable looking incorrect syntax, so we
+ // want to keep their span info to improve diagnostics in these cases in a later stage.
+ (true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
+ (true, Some(AssocOp::Subtract)) | // `{ 42 } -5`
+ (true, Some(AssocOp::Add)) => { // `{ 42 } + 42
+ // These cases are ambiguous and can't be identified in the parser alone
+ let sp = self.sess.source_map().start_point(self.span);
+ self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
+ return Ok(lhs);
+ }
+ (true, Some(ref op)) if !op.can_continue_expr_unambiguously() => {
+ return Ok(lhs);
+ }
+ (true, Some(_)) => {
+ // We've found an expression that would be parsed as a statement, but the next
+ // token implies this should be parsed as an expression.
+ // For example: `if let Some(x) = x { x } else { 0 } / 2`
+ let mut err = self.sess.span_diagnostic.struct_span_err(self.span, &format!(
+ "expected expression, found `{}`",
+ pprust::token_to_string(&self.token),
+ ));
+ err.span_label(self.span, "expected expression");
+ self.sess.expr_parentheses_needed(
+ &mut err,
+ lhs.span,
+ Some(pprust::expr_to_string(&lhs),
+ ));
+ err.emit();
+ }
}
self.expected_tokens.push(TokenType::Operator);
while let Some(op) = AssocOp::from_token(&self.token) {
} else {
self.restrictions
};
- if op.precedence() < min_prec {
+ let prec = op.precedence();
+ if prec < min_prec {
break;
}
// Check for deprecated `...` syntax
// We have 2 alternatives here: `x..y`/`x..=y` and `x..`/`x..=` The other
// two variants are handled with `parse_prefix_range_expr` call above.
let rhs = if self.is_at_start_of_range_notation_rhs() {
- Some(self.parse_assoc_expr_with(op.precedence() + 1,
- LhsExpr::NotYetParsed)?)
+ Some(self.parse_assoc_expr_with(prec + 1, LhsExpr::NotYetParsed)?)
} else {
None
};
break
}
- let rhs = match op.fixity() {
- Fixity::Right => self.with_res(
- restrictions - Restrictions::STMT_EXPR,
- |this| {
- this.parse_assoc_expr_with(op.precedence(),
- LhsExpr::NotYetParsed)
- }),
- Fixity::Left => self.with_res(
- restrictions - Restrictions::STMT_EXPR,
- |this| {
- this.parse_assoc_expr_with(op.precedence() + 1,
- LhsExpr::NotYetParsed)
- }),
+ let fixity = op.fixity();
+ let prec_adjustment = match fixity {
+ Fixity::Right => 0,
+ Fixity::Left => 1,
// We currently have no non-associative operators that are not handled above by
// the special cases. The code is here only for future convenience.
- Fixity::None => self.with_res(
- restrictions - Restrictions::STMT_EXPR,
- |this| {
- this.parse_assoc_expr_with(op.precedence() + 1,
- LhsExpr::NotYetParsed)
- }),
- }?;
+ Fixity::None => 1,
+ };
+ let rhs = self.with_res(
+ restrictions - Restrictions::STMT_EXPR,
+ |this| this.parse_assoc_expr_with(prec + prec_adjustment, LhsExpr::NotYetParsed)
+ )?;
// Make sure that the span of the parent node is larger than the span of lhs and rhs,
// including the attributes.
}
};
- if op.fixity() == Fixity::None { break }
+ if let Fixity::None = fixity { break }
}
Ok(lhs)
}
/// Produce an error if comparison operators are chained (RFC #558).
/// We only need to check lhs, not rhs, because all comparison ops
/// have same precedence and are left-associative
- fn check_no_chained_comparison(&mut self, lhs: &Expr, outer_op: &AssocOp) {
+ fn check_no_chained_comparison(&self, lhs: &Expr, outer_op: &AssocOp) {
debug_assert!(outer_op.is_comparison(),
"check_no_chained_comparison: {:?} is not comparison",
outer_op);
}
crate fn parse_arm(&mut self) -> PResult<'a, Arm> {
- maybe_whole!(self, NtArm, |x| x);
-
let attrs = self.parse_outer_attributes()?;
let pats = self.parse_pats()?;
let guard = if self.eat_keyword(keywords::If) {
);
let mut err = self.fatal(&msg);
err.span_label(self.span, format!("expected {}", expected));
+ let sp = self.sess.source_map().start_point(self.span);
+ if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
+ self.sess.expr_parentheses_needed(&mut err, *sp, None);
+ }
return Err(err);
}
}
})
}
- fn is_async_block(&mut self) -> bool {
+ fn is_async_block(&self) -> bool {
self.token.is_keyword(keywords::Async) &&
(
( // `async move {`
)
}
- fn is_async_fn(&mut self) -> bool {
+ fn is_async_fn(&self) -> bool {
self.token.is_keyword(keywords::Async) &&
self.look_ahead(1, |t| t.is_keyword(keywords::Fn))
}
- fn is_do_catch_block(&mut self) -> bool {
+ fn is_do_catch_block(&self) -> bool {
self.token.is_keyword(keywords::Do) &&
self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) &&
self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace)) &&
!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
}
- fn is_try_block(&mut self) -> bool {
+ fn is_try_block(&self) -> bool {
self.token.is_keyword(keywords::Try) &&
self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) &&
self.span.rust_2018() &&
self.look_ahead(1, |t| t.is_keyword(keywords::Type))
}
- fn is_auto_trait_item(&mut self) -> bool {
+ fn is_auto_trait_item(&self) -> bool {
// auto trait
(self.token.is_keyword(keywords::Auto)
&& self.look_ahead(1, |t| t.is_keyword(keywords::Trait)))
(ident, ast::MacroDef { tokens: tokens.into(), legacy: false })
}
- token::Ident(ident, _) if ident.name == "macro_rules" &&
+ token::Ident(ident, _) if ident.name == sym::macro_rules &&
self.look_ahead(1, |t| *t == token::Not) => {
let prev_span = self.prev_span;
self.complain_if_pub_macro(&vis.node, prev_span);
}
/// Checks if this expression is a successfully parsed statement.
- fn expr_is_complete(&mut self, e: &Expr) -> bool {
+ fn expr_is_complete(&self, e: &Expr) -> bool {
self.restrictions.contains(Restrictions::STMT_EXPR) &&
!classify::expr_requires_semi_to_be_stmt(e)
}
/// | ( < lifetimes , typaramseq ( , )? > )
/// where typaramseq = ( typaram ) | ( typaram , typaramseq )
fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
- maybe_whole!(self, NtGenerics, |x| x);
-
let span_lo = self.span;
if self.eat_lt() {
let params = self.parse_generic_params()?;
});
assoc_ty_bindings.push(span);
} else if self.check_const_arg() {
- // FIXME(const_generics): to distinguish between idents for types and consts,
- // we should introduce a GenericArg::Ident in the AST and distinguish when
- // lowering to the HIR. For now, idents for const args are not permitted.
-
// Parse const argument.
let expr = if let token::OpenDelim(token::Brace) = self.token {
self.parse_block_expr(None, self.span, BlockCheckMode::Default, ThinVec::new())?
self.fatal("identifiers may currently not be used for const generics")
);
} else {
- // FIXME(const_generics): this currently conflicts with emplacement syntax
- // with negative integer literals.
self.parse_literal_maybe_minus()?
};
let value = AnonConst {
/// where T : Trait<U, V> + 'b, 'a : 'b
/// ```
fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> {
- maybe_whole!(self, NtWhereClause, |x| x);
-
let mut where_clause = WhereClause {
id: ast::DUMMY_NODE_ID,
predicates: Vec::new(),
Ok((id, generics))
}
- fn mk_item(&mut self, span: Span, ident: Ident, node: ItemKind, vis: Visibility,
+ fn mk_item(&self, span: Span, ident: Ident, node: ItemKind, vis: Visibility,
attrs: Vec<Attribute>) -> P<Item> {
P(Item {
ident,
-> PResult<'a, ItemInfo> {
let (ident, mut generics) = self.parse_fn_header()?;
let allow_c_variadic = abi == Abi::C && unsafety == Unsafety::Unsafe;
- let decl = self.parse_fn_decl(allow_c_variadic)?;
+ let mut decl = self.parse_fn_decl(allow_c_variadic)?;
generics.where_clause = self.parse_where_clause()?;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
- self.construct_async_arguments(&mut asyncness, &decl);
+ self.construct_async_arguments(&mut asyncness, &mut decl);
let header = FnHeader { unsafety, asyncness, constness, abi };
Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs)))
}
/// Returns `true` if we are looking at `const ID`
/// (returns `false` for things like `const fn`, etc.).
- fn is_const_item(&mut self) -> bool {
+ fn is_const_item(&self) -> bool {
self.token.is_keyword(keywords::Const) &&
!self.look_ahead(1, |t| t.is_keyword(keywords::Fn)) &&
!self.look_ahead(1, |t| t.is_keyword(keywords::Unsafe))
})
}
- fn complain_if_pub_macro(&mut self, vis: &VisibilityKind, sp: Span) {
+ fn complain_if_pub_macro(&self, vis: &VisibilityKind, sp: Span) {
match *vis {
VisibilityKind::Inherited => {}
_ => {
}
}
- fn missing_assoc_item_kind_err(&mut self, item_type: &str, prev_span: Span)
+ fn missing_assoc_item_kind_err(&self, item_type: &str, prev_span: Span)
-> DiagnosticBuilder<'a>
{
let expected_kinds = if item_type == "extern" {
let (constness, unsafety, mut asyncness, abi) = self.parse_fn_front_matter()?;
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
- let decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?;
+ let mut decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?;
generics.where_clause = self.parse_where_clause()?;
- self.construct_async_arguments(&mut asyncness, &decl);
+ self.construct_async_arguments(&mut asyncness, &mut decl);
*at_end = true;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
let header = ast::FnHeader { abi, unsafety, constness, asyncness };
}
fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
- if let Some(path) = attr::first_attr_value_str_by_name(attrs, "path") {
+ if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) {
self.directory.path.to_mut().push(&path.as_str());
self.directory.ownership = DirectoryOwnership::Owned { relative: None };
} else {
}
pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
- if let Some(s) = attr::first_attr_value_str_by_name(attrs, "path") {
+ if let Some(s) = attr::first_attr_value_str_by_name(attrs, sym::path) {
let s = s.as_str();
// On windows, the base path might have the form
///
/// The arguments of the function are replaced in HIR lowering with the arguments created by
/// this function and the statements created here are inserted at the top of the closure body.
- fn construct_async_arguments(&mut self, asyncness: &mut Spanned<IsAsync>, decl: &FnDecl) {
+ fn construct_async_arguments(&mut self, asyncness: &mut Spanned<IsAsync>, decl: &mut FnDecl) {
+ // FIXME(davidtwco): This function should really live in the HIR lowering but because
+ // the types constructed here need to be used in parts of resolve so that the correct
+ // locals are considered upvars, it is currently easier for it to live here in the parser,
+ // where it can be constructed once.
if let IsAsync::Async { ref mut arguments, .. } = asyncness.node {
- for (index, input) in decl.inputs.iter().enumerate() {
+ for (index, input) in decl.inputs.iter_mut().enumerate() {
let id = ast::DUMMY_NODE_ID;
let span = input.pat.span;
// `let <pat> = __argN;` statement, instead just adding a `let <pat> = <pat>;`
// statement.
let (binding_mode, ident, is_simple_pattern) = match input.pat.node {
- PatKind::Ident(binding_mode, ident, _) => (binding_mode, ident, true),
- _ => (BindingMode::ByValue(Mutability::Immutable), ident, false),
+ PatKind::Ident(binding_mode @ BindingMode::ByValue(_), ident, _) => {
+ // Simple patterns like this don't have a generated argument, but they are
+ // moved into the closure with a statement, so any `mut` bindings on the
+ // argument will be unused. This binding mode can't be removed, because
+ // this would affect the input to procedural macros, but they can have
+ // their span marked as being the result of a compiler desugaring so
+ // that they aren't linted against.
+ input.pat.span = self.sess.source_map().mark_span_with_reason(
+ CompilerDesugaringKind::Async, span, None);
+
+ (binding_mode, ident, true)
+ }
+ _ => (BindingMode::ByValue(Mutability::Mutable), ident, false),
};
// Construct an argument representing `__argN: <ty>` to replace the argument of the