Auto merge of #66994 - Centril:stmt-polish, r=estebank
refactor expr & stmt parsing + improve recovery
Summary of important changes (best read commit-by-commit, ignoring whitespace changes):
- `AttrVec` is introduces as an alias for `ThinVec<Attribute>`
- `parse_expr_bottom` and `parse_stmt` are thoroughly refactored.
- Extract diagnostics logic for `vec![...]` in a pattern context.
- Recovery is added for `do catch { ... }`
- Recovery is added for `'label: non_block_expr`
- Recovery is added for `var $local`, `auto $local`, and `mut $local`. Fixes #65257.
- Recovery is added for `e1 and e2` and `e1 or e2`.
- ~~`macro_legacy_warnings` is turned into an error (has been a warning for 3 years!)~~
- Fixes #63396 by forward-porting #64105 which now works thanks to added recovery.
- `ui-fulldeps/ast_stmt_expr_attr.rs` is turned into UI and pretty tests.
- Recovery is fixed for `#[attr] if expr {}`
r? @estebank
This commit is contained in:
commit
c64eecf4d0
47 changed files with 1771 additions and 1194 deletions
|
|
@ -53,7 +53,6 @@ use crate::util::nodemap::{DefIdMap, NodeMap};
|
|||
use errors::Applicability;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_data_structures::thin_vec::ThinVec;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
|
@ -1205,7 +1204,7 @@ impl<'a> LoweringContext<'a> {
|
|||
id: ty.id,
|
||||
kind: ExprKind::Path(qself.clone(), path.clone()),
|
||||
span: ty.span,
|
||||
attrs: ThinVec::new(),
|
||||
attrs: AttrVec::new(),
|
||||
};
|
||||
|
||||
let ct = self.with_new_scopes(|this| {
|
||||
|
|
@ -2751,7 +2750,7 @@ impl<'a> LoweringContext<'a> {
|
|||
/// has no attributes and is not targeted by a `break`.
|
||||
fn lower_block_expr(&mut self, b: &Block) -> hir::Expr {
|
||||
let block = self.lower_block(b, false);
|
||||
self.expr_block(block, ThinVec::new())
|
||||
self.expr_block(block, AttrVec::new())
|
||||
}
|
||||
|
||||
fn lower_pat(&mut self, p: &Pat) -> P<hir::Pat> {
|
||||
|
|
@ -3102,7 +3101,7 @@ impl<'a> LoweringContext<'a> {
|
|||
|
||||
fn stmt_let_pat(
|
||||
&mut self,
|
||||
attrs: ThinVec<Attribute>,
|
||||
attrs: AttrVec,
|
||||
span: Span,
|
||||
init: Option<P<hir::Expr>>,
|
||||
pat: P<hir::Pat>,
|
||||
|
|
|
|||
|
|
@ -1318,8 +1318,7 @@ impl LoweringContext<'_> {
|
|||
&mut self,
|
||||
span: Span,
|
||||
expr: P<hir::Expr>,
|
||||
attrs: ThinVec<Attribute>
|
||||
) -> hir::Expr {
|
||||
attrs: AttrVec) -> hir::Expr {
|
||||
self.expr(span, hir::ExprKind::DropTemps(expr), attrs)
|
||||
}
|
||||
|
||||
|
|
@ -1333,7 +1332,7 @@ impl LoweringContext<'_> {
|
|||
self.expr(span, hir::ExprKind::Match(arg, arms, source), ThinVec::new())
|
||||
}
|
||||
|
||||
fn expr_break(&mut self, span: Span, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
|
||||
fn expr_break(&mut self, span: Span, attrs: AttrVec) -> P<hir::Expr> {
|
||||
let expr_break = hir::ExprKind::Break(self.lower_loop_destination(None), None);
|
||||
P(self.expr(span, expr_break, attrs))
|
||||
}
|
||||
|
|
@ -1404,7 +1403,7 @@ impl LoweringContext<'_> {
|
|||
span: Span,
|
||||
components: &[Symbol],
|
||||
params: Option<P<hir::GenericArgs>>,
|
||||
attrs: ThinVec<Attribute>,
|
||||
attrs: AttrVec,
|
||||
) -> hir::Expr {
|
||||
let path = self.std_path(span, components, params, true);
|
||||
self.expr(
|
||||
|
|
@ -1423,7 +1422,7 @@ impl LoweringContext<'_> {
|
|||
span: Span,
|
||||
ident: Ident,
|
||||
binding: hir::HirId,
|
||||
attrs: ThinVec<Attribute>,
|
||||
attrs: AttrVec,
|
||||
) -> hir::Expr {
|
||||
let expr_path = hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
None,
|
||||
|
|
@ -1459,16 +1458,11 @@ impl LoweringContext<'_> {
|
|||
self.expr_block(P(blk), ThinVec::new())
|
||||
}
|
||||
|
||||
pub(super) fn expr_block(&mut self, b: P<hir::Block>, attrs: ThinVec<Attribute>) -> hir::Expr {
|
||||
pub(super) fn expr_block(&mut self, b: P<hir::Block>, attrs: AttrVec) -> hir::Expr {
|
||||
self.expr(b.span, hir::ExprKind::Block(b, None), attrs)
|
||||
}
|
||||
|
||||
pub(super) fn expr(
|
||||
&mut self,
|
||||
span: Span,
|
||||
kind: hir::ExprKind,
|
||||
attrs: ThinVec<Attribute>
|
||||
) -> hir::Expr {
|
||||
pub(super) fn expr(&mut self, span: Span, kind: hir::ExprKind, attrs: AttrVec) -> hir::Expr {
|
||||
hir::Expr { hir_id: self.next_id(), kind, span, attrs }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ use crate::hir::def_id::DefId;
|
|||
use crate::hir::def::{Res, DefKind};
|
||||
use crate::util::nodemap::NodeMap;
|
||||
|
||||
use rustc_data_structures::thin_vec::ThinVec;
|
||||
use rustc_target::spec::abi;
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
|
|
@ -899,7 +898,7 @@ impl LoweringContext<'_> {
|
|||
|
||||
/// Construct `ExprKind::Err` for the given `span`.
|
||||
fn expr_err(&mut self, span: Span) -> hir::Expr {
|
||||
self.expr(span, hir::ExprKind::Err, ThinVec::new())
|
||||
self.expr(span, hir::ExprKind::Err, AttrVec::new())
|
||||
}
|
||||
|
||||
fn lower_impl_item(&mut self, i: &AssocItem) -> hir::ImplItem {
|
||||
|
|
@ -1182,7 +1181,7 @@ impl LoweringContext<'_> {
|
|||
//
|
||||
// If this is the simple case, this parameter will end up being the same as the
|
||||
// original parameter, but with a different pattern id.
|
||||
let mut stmt_attrs = ThinVec::new();
|
||||
let mut stmt_attrs = AttrVec::new();
|
||||
stmt_attrs.extend(parameter.attrs.iter().cloned());
|
||||
let (new_parameter_pat, new_parameter_id) = this.pat_ident(desugared_span, ident);
|
||||
let new_parameter = hir::Param {
|
||||
|
|
@ -1226,7 +1225,7 @@ impl LoweringContext<'_> {
|
|||
desugared_span, ident, hir::BindingAnnotation::Mutable);
|
||||
let move_expr = this.expr_ident(desugared_span, ident, new_parameter_id);
|
||||
let move_stmt = this.stmt_let_pat(
|
||||
ThinVec::new(),
|
||||
AttrVec::new(),
|
||||
desugared_span,
|
||||
Some(P(move_expr)),
|
||||
move_pat,
|
||||
|
|
@ -1271,7 +1270,7 @@ impl LoweringContext<'_> {
|
|||
let user_body = this.expr_drop_temps(
|
||||
desugared_span,
|
||||
P(user_body),
|
||||
ThinVec::new(),
|
||||
AttrVec::new(),
|
||||
);
|
||||
|
||||
// As noted above, create the final block like
|
||||
|
|
@ -1288,9 +1287,9 @@ impl LoweringContext<'_> {
|
|||
statements.into(),
|
||||
Some(P(user_body)),
|
||||
);
|
||||
this.expr_block(P(body), ThinVec::new())
|
||||
this.expr_block(P(body), AttrVec::new())
|
||||
});
|
||||
(HirVec::from(parameters), this.expr(body_span, async_expr, ThinVec::new()))
|
||||
(HirVec::from(parameters), this.expr(body_span, async_expr, AttrVec::new()))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use errors::FatalError;
|
|||
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
|
||||
use syntax::source_map::Spanned;
|
||||
use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, AsmDialect};
|
||||
use syntax::ast::{Attribute, Label, LitKind, StrStyle, FloatTy, IntTy, UintTy};
|
||||
use syntax::ast::{AttrVec, Attribute, Label, LitKind, StrStyle, FloatTy, IntTy, UintTy};
|
||||
pub use syntax::ast::{Mutability, Constness, Unsafety, Movability, CaptureBy};
|
||||
pub use syntax::ast::{IsAuto, ImplPolarity, BorrowKind};
|
||||
use syntax::attr::{InlineAttr, OptimizeAttr};
|
||||
|
|
@ -29,7 +29,6 @@ use syntax::tokenstream::TokenStream;
|
|||
use syntax::util::parser::ExprPrecedence;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
|
||||
use rustc_data_structures::thin_vec::ThinVec;
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_serialize::{self, Encoder, Encodable, Decoder, Decodable};
|
||||
use std::collections::{BTreeSet, BTreeMap};
|
||||
|
|
@ -1274,7 +1273,7 @@ pub struct Local {
|
|||
pub init: Option<P<Expr>>,
|
||||
pub hir_id: HirId,
|
||||
pub span: Span,
|
||||
pub attrs: ThinVec<Attribute>,
|
||||
pub attrs: AttrVec,
|
||||
/// Can be `ForLoopDesugar` if the `let` statement is part of a `for` loop
|
||||
/// desugaring. Otherwise will be `Normal`.
|
||||
pub source: LocalSource,
|
||||
|
|
@ -1459,7 +1458,7 @@ pub struct AnonConst {
|
|||
pub struct Expr {
|
||||
pub hir_id: HirId,
|
||||
pub kind: ExprKind,
|
||||
pub attrs: ThinVec<Attribute>,
|
||||
pub attrs: AttrVec,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ use rustc_data_structures::jobserver;
|
|||
use rustc_data_structures::sync::{Lock, Lrc};
|
||||
use rustc_data_structures::stable_hasher::StableHasher;
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::thin_vec::ThinVec;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
|
||||
use rustc_errors::registry::Registry;
|
||||
use rustc_metadata::dynamic_lib::DynamicLibrary;
|
||||
|
|
@ -24,7 +23,7 @@ use std::ops::DerefMut;
|
|||
use smallvec::SmallVec;
|
||||
use syntax::ptr::P;
|
||||
use syntax::mut_visit::{*, MutVisitor, visit_clobber};
|
||||
use syntax::ast::BlockCheckMode;
|
||||
use syntax::ast::{AttrVec, BlockCheckMode};
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
use syntax::source_map::{FileLoader, RealFileLoader, SourceMap};
|
||||
use syntax::symbol::{Symbol, sym};
|
||||
|
|
@ -741,7 +740,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
|
|||
id: resolver.next_node_id(),
|
||||
kind: ast::ExprKind::Block(P(b), None),
|
||||
span: syntax_pos::DUMMY_SP,
|
||||
attrs: ThinVec::new(),
|
||||
attrs: AttrVec::new(),
|
||||
});
|
||||
|
||||
ast::Stmt {
|
||||
|
|
@ -756,7 +755,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
|
|||
kind: ast::ExprKind::Loop(P(empty_block), None),
|
||||
id: self.resolver.next_node_id(),
|
||||
span: syntax_pos::DUMMY_SP,
|
||||
attrs: ThinVec::new(),
|
||||
attrs: AttrVec::new(),
|
||||
});
|
||||
|
||||
let loop_stmt = ast::Stmt {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#![feature(bool_to_option)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::print::pprust;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use super::{SeqSep, Parser, TokenType, PathStyle};
|
||||
use super::{Parser, TokenType, PathStyle};
|
||||
use rustc_errors::PResult;
|
||||
use syntax::attr;
|
||||
use syntax::ast;
|
||||
|
|
@ -301,8 +301,10 @@ impl<'a> Parser<'a> {
|
|||
crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
|
||||
Ok(if self.eat(&token::Eq) {
|
||||
ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?)
|
||||
} else if self.eat(&token::OpenDelim(token::Paren)) {
|
||||
ast::MetaItemKind::List(self.parse_meta_seq()?)
|
||||
} else if self.check(&token::OpenDelim(token::Paren)) {
|
||||
// Matches `meta_seq = ( COMMASEP(meta_item_inner) )`.
|
||||
let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?;
|
||||
ast::MetaItemKind::List(list)
|
||||
} else {
|
||||
ast::MetaItemKind::Word
|
||||
})
|
||||
|
|
@ -311,16 +313,12 @@ impl<'a> Parser<'a> {
|
|||
/// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`.
|
||||
fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
|
||||
match self.parse_unsuffixed_lit() {
|
||||
Ok(lit) => {
|
||||
return Ok(ast::NestedMetaItem::Literal(lit))
|
||||
}
|
||||
Ok(lit) => return Ok(ast::NestedMetaItem::Literal(lit)),
|
||||
Err(ref mut err) => err.cancel(),
|
||||
}
|
||||
|
||||
match self.parse_meta_item() {
|
||||
Ok(mi) => {
|
||||
return Ok(ast::NestedMetaItem::MetaItem(mi))
|
||||
}
|
||||
Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)),
|
||||
Err(ref mut err) => err.cancel(),
|
||||
}
|
||||
|
||||
|
|
@ -328,11 +326,4 @@ impl<'a> Parser<'a> {
|
|||
let msg = format!("expected unsuffixed literal or identifier, found `{}`", found);
|
||||
Err(self.diagnostic().struct_span_err(self.token.span, &msg))
|
||||
}
|
||||
|
||||
/// Matches `meta_seq = ( COMMASEP(meta_item_inner) )`.
|
||||
fn parse_meta_seq(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
|
||||
self.parse_seq_to_end(&token::CloseDelim(token::Paren),
|
||||
SeqSep::trailing_allowed(token::Comma),
|
||||
|p: &mut Parser<'a>| p.parse_meta_item_inner())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,13 @@ use rustc_data_structures::fx::FxHashSet;
|
|||
use rustc_errors::{self, PResult, Applicability, DiagnosticBuilder, Handler, pluralize};
|
||||
use rustc_error_codes::*;
|
||||
use syntax::ast::{self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item};
|
||||
use syntax::ast::{ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind};
|
||||
use syntax::ast::{ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, AttrVec};
|
||||
use syntax::token::{self, TokenKind, token_can_begin_expr};
|
||||
use syntax::print::pprust;
|
||||
use syntax::ptr::P;
|
||||
use syntax::ThinVec;
|
||||
use syntax::util::parser::AssocOp;
|
||||
use syntax::struct_span_err;
|
||||
use syntax_pos::symbol::{kw, sym};
|
||||
use syntax_pos::symbol::kw;
|
||||
use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError};
|
||||
|
||||
use log::{debug, trace};
|
||||
|
|
@ -32,7 +31,7 @@ pub(super) fn dummy_arg(ident: Ident) -> Param {
|
|||
id: ast::DUMMY_NODE_ID
|
||||
};
|
||||
Param {
|
||||
attrs: ThinVec::default(),
|
||||
attrs: AttrVec::default(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
pat,
|
||||
span: ident.span,
|
||||
|
|
@ -164,7 +163,7 @@ impl RecoverQPath for Expr {
|
|||
Self {
|
||||
span: path.span,
|
||||
kind: ExprKind::Path(qself, path),
|
||||
attrs: ThinVec::new(),
|
||||
attrs: AttrVec::new(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
}
|
||||
}
|
||||
|
|
@ -312,22 +311,6 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
self.last_unexpected_token_span = Some(self.token.span);
|
||||
let mut err = self.fatal(&msg_exp);
|
||||
if self.token.is_ident_named(sym::and) {
|
||||
err.span_suggestion_short(
|
||||
self.token.span,
|
||||
"use `&&` instead of `and` for the boolean operator",
|
||||
"&&".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
if self.token.is_ident_named(sym::or) {
|
||||
err.span_suggestion_short(
|
||||
self.token.span,
|
||||
"use `||` instead of `or` for the boolean operator",
|
||||
"||".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
let sp = if self.token == token::Eof {
|
||||
// This is EOF; don't want to point at the following char, but rather the last token.
|
||||
self.prev_span
|
||||
|
|
@ -567,7 +550,7 @@ impl<'a> Parser<'a> {
|
|||
);
|
||||
|
||||
let mk_err_expr = |this: &Self, span| {
|
||||
Ok(Some(this.mk_expr(span, ExprKind::Err, ThinVec::new())))
|
||||
Ok(Some(this.mk_expr(span, ExprKind::Err, AttrVec::new())))
|
||||
};
|
||||
|
||||
match lhs.kind {
|
||||
|
|
@ -986,21 +969,32 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Consumes alternative await syntaxes like `await!(<expr>)`, `await <expr>`,
|
||||
/// `await? <expr>`, `await(<expr>)`, and `await { <expr> }`.
|
||||
pub(super) fn parse_incorrect_await_syntax(
|
||||
pub(super) fn recover_incorrect_await_syntax(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
await_sp: Span,
|
||||
) -> PResult<'a, (Span, ExprKind)> {
|
||||
if self.token == token::Not {
|
||||
attrs: AttrVec,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
let (hi, expr, is_question) = if self.token == token::Not {
|
||||
// Handle `await!(<expr>)`.
|
||||
self.expect(&token::Not)?;
|
||||
self.expect(&token::OpenDelim(token::Paren))?;
|
||||
let expr = self.parse_expr()?;
|
||||
self.expect(&token::CloseDelim(token::Paren))?;
|
||||
let sp = self.error_on_incorrect_await(lo, self.prev_span, &expr, false);
|
||||
return Ok((sp, ExprKind::Await(expr)))
|
||||
}
|
||||
self.recover_await_macro()?
|
||||
} else {
|
||||
self.recover_await_prefix(await_sp)?
|
||||
};
|
||||
let sp = self.error_on_incorrect_await(lo, hi, &expr, is_question);
|
||||
let expr = self.mk_expr(lo.to(sp), ExprKind::Await(expr), attrs);
|
||||
self.maybe_recover_from_bad_qpath(expr, true)
|
||||
}
|
||||
|
||||
fn recover_await_macro(&mut self) -> PResult<'a, (Span, P<Expr>, bool)> {
|
||||
self.expect(&token::Not)?;
|
||||
self.expect(&token::OpenDelim(token::Paren))?;
|
||||
let expr = self.parse_expr()?;
|
||||
self.expect(&token::CloseDelim(token::Paren))?;
|
||||
Ok((self.prev_span, expr, false))
|
||||
}
|
||||
|
||||
fn recover_await_prefix(&mut self, await_sp: Span) -> PResult<'a, (Span, P<Expr>, bool)> {
|
||||
let is_question = self.eat(&token::Question); // Handle `await? <expr>`.
|
||||
let expr = if self.token == token::OpenDelim(token::Brace) {
|
||||
// Handle `await { <expr> }`.
|
||||
|
|
@ -1010,7 +1004,7 @@ impl<'a> Parser<'a> {
|
|||
None,
|
||||
self.token.span,
|
||||
BlockCheckMode::Default,
|
||||
ThinVec::new(),
|
||||
AttrVec::new(),
|
||||
)
|
||||
} else {
|
||||
self.parse_expr()
|
||||
|
|
@ -1018,8 +1012,7 @@ impl<'a> Parser<'a> {
|
|||
err.span_label(await_sp, "while parsing this incorrect await expression");
|
||||
err
|
||||
})?;
|
||||
let sp = self.error_on_incorrect_await(lo, expr.span, &expr, is_question);
|
||||
Ok((sp, ExprKind::Await(expr)))
|
||||
Ok((expr.span, expr, is_question))
|
||||
}
|
||||
|
||||
fn error_on_incorrect_await(&self, lo: Span, hi: Span, expr: &Expr, is_question: bool) -> Span {
|
||||
|
|
@ -1132,7 +1125,7 @@ impl<'a> Parser<'a> {
|
|||
err.emit();
|
||||
// Recover from parse error, callers expect the closing delim to be consumed.
|
||||
self.consume_block(delim, ConsumeClosingDelim::Yes);
|
||||
self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new())
|
||||
self.mk_expr(lo.to(self.prev_span), ExprKind::Err, AttrVec::new())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -5,15 +5,14 @@ use crate::maybe_whole;
|
|||
|
||||
use rustc_errors::{PResult, Applicability, DiagnosticBuilder, StashKey};
|
||||
use rustc_error_codes::*;
|
||||
use syntax::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrKind, AttrStyle, AnonConst, Item};
|
||||
use syntax::ast::{AssocItem, AssocItemKind, ItemKind, UseTree, UseTreeKind};
|
||||
use syntax::ast::{self, DUMMY_NODE_ID, Ident, AttrVec, Attribute, AttrKind, AttrStyle, AnonConst};
|
||||
use syntax::ast::{AssocItem, AssocItemKind, Item, ItemKind, UseTree, UseTreeKind};
|
||||
use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness, Extern, StrLit};
|
||||
use syntax::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind};
|
||||
use syntax::ast::{Ty, TyKind, Generics, TraitRef, EnumDef, Variant, VariantData, StructField};
|
||||
use syntax::ast::{Mac, MacArgs, MacDelimiter, Block, BindingMode, FnDecl, FnSig, SelfKind, Param};
|
||||
use syntax::print::pprust;
|
||||
use syntax::ptr::P;
|
||||
use syntax::ThinVec;
|
||||
use syntax::token;
|
||||
use syntax::tokenstream::{DelimSpan, TokenTree, TokenStream};
|
||||
use syntax::struct_span_err;
|
||||
|
|
@ -2095,7 +2094,7 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
|
||||
let eself = source_map::respan(eself_lo.to(eself_hi), eself);
|
||||
Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident)))
|
||||
Ok(Some(Param::from_self(AttrVec::default(), eself, eself_ident)))
|
||||
}
|
||||
|
||||
fn is_named_param(&self) -> bool {
|
||||
|
|
|
|||
|
|
@ -15,9 +15,8 @@ use crate::{Directory, DirectoryOwnership};
|
|||
use crate::lexer::UnmatchedBrace;
|
||||
|
||||
use rustc_errors::{PResult, Applicability, DiagnosticBuilder, FatalError};
|
||||
use rustc_data_structures::thin_vec::ThinVec;
|
||||
use syntax::ast::{self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Extern, Ident, StrLit};
|
||||
use syntax::ast::{IsAsync, MacArgs, MacDelimiter, Mutability, Visibility, VisibilityKind, Unsafety};
|
||||
use syntax::ast::{self, DUMMY_NODE_ID, AttrVec, AttrStyle, CrateSugar, Extern, Ident, Unsafety};
|
||||
use syntax::ast::{StrLit, IsAsync, MacArgs, MacDelimiter, Mutability, Visibility, VisibilityKind};
|
||||
use syntax::print::pprust;
|
||||
use syntax::ptr::P;
|
||||
use syntax::token::{self, Token, TokenKind, DelimToken};
|
||||
|
|
@ -740,34 +739,6 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Parses a sequence, including the closing delimiter. The function
|
||||
/// `f` must consume tokens until reaching the next separator or
|
||||
/// closing bracket.
|
||||
fn parse_seq_to_end<T>(
|
||||
&mut self,
|
||||
ket: &TokenKind,
|
||||
sep: SeqSep,
|
||||
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
||||
) -> PResult<'a, Vec<T>> {
|
||||
let (val, _, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
|
||||
if !recovered {
|
||||
self.bump();
|
||||
}
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
/// Parses a sequence, not including the closing delimiter. The function
|
||||
/// `f` must consume tokens until reaching the next separator or
|
||||
/// closing bracket.
|
||||
fn parse_seq_to_before_end<T>(
|
||||
&mut self,
|
||||
ket: &TokenKind,
|
||||
sep: SeqSep,
|
||||
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
||||
) -> PResult<'a, (Vec<T>, bool, bool)> {
|
||||
self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f)
|
||||
}
|
||||
|
||||
fn expect_any_with_type(&mut self, kets: &[&TokenKind], expect: TokenExpectType) -> bool {
|
||||
kets.iter().any(|k| {
|
||||
match expect {
|
||||
|
|
@ -855,6 +826,34 @@ impl<'a> Parser<'a> {
|
|||
Ok((v, trailing, recovered))
|
||||
}
|
||||
|
||||
/// Parses a sequence, not including the closing delimiter. The function
|
||||
/// `f` must consume tokens until reaching the next separator or
|
||||
/// closing bracket.
|
||||
fn parse_seq_to_before_end<T>(
|
||||
&mut self,
|
||||
ket: &TokenKind,
|
||||
sep: SeqSep,
|
||||
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
||||
) -> PResult<'a, (Vec<T>, bool, bool)> {
|
||||
self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f)
|
||||
}
|
||||
|
||||
/// Parses a sequence, including the closing delimiter. The function
|
||||
/// `f` must consume tokens until reaching the next separator or
|
||||
/// closing bracket.
|
||||
fn parse_seq_to_end<T>(
|
||||
&mut self,
|
||||
ket: &TokenKind,
|
||||
sep: SeqSep,
|
||||
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
||||
) -> PResult<'a, (Vec<T>, bool /* trailing */)> {
|
||||
let (val, trailing, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
|
||||
if !recovered {
|
||||
self.eat(ket);
|
||||
}
|
||||
Ok((val, trailing))
|
||||
}
|
||||
|
||||
/// Parses a sequence, including the closing delimiter. The function
|
||||
/// `f` must consume tokens until reaching the next separator or
|
||||
/// closing bracket.
|
||||
|
|
@ -866,11 +865,7 @@ impl<'a> Parser<'a> {
|
|||
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
||||
) -> PResult<'a, (Vec<T>, bool)> {
|
||||
self.expect(bra)?;
|
||||
let (result, trailing, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
|
||||
if !recovered {
|
||||
self.eat(ket);
|
||||
}
|
||||
Ok((result, trailing))
|
||||
self.parse_seq_to_end(ket, sep, f)
|
||||
}
|
||||
|
||||
fn parse_delim_comma_seq<T>(
|
||||
|
|
@ -1054,8 +1049,8 @@ impl<'a> Parser<'a> {
|
|||
|
||||
fn parse_or_use_outer_attributes(
|
||||
&mut self,
|
||||
already_parsed_attrs: Option<ThinVec<Attribute>>,
|
||||
) -> PResult<'a, ThinVec<Attribute>> {
|
||||
already_parsed_attrs: Option<AttrVec>,
|
||||
) -> PResult<'a, AttrVec> {
|
||||
if let Some(attrs) = already_parsed_attrs {
|
||||
Ok(attrs)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
use super::{Parser, PathStyle};
|
||||
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
||||
use rustc_errors::{PResult, Applicability, DiagnosticBuilder};
|
||||
use syntax::ast::{self, Attribute, Pat, PatKind, FieldPat, RangeEnd, RangeSyntax, Mac};
|
||||
use syntax::ast::{self, AttrVec, Attribute, Pat, PatKind, FieldPat, RangeEnd, RangeSyntax, Mac};
|
||||
use syntax::ast::{BindingMode, Ident, Mutability, Path, QSelf, Expr, ExprKind};
|
||||
use syntax::mut_visit::{noop_visit_pat, noop_visit_mac, MutVisitor};
|
||||
use syntax::ptr::P;
|
||||
use syntax::print::pprust;
|
||||
use syntax::ThinVec;
|
||||
use syntax::token;
|
||||
use syntax_pos::source_map::{respan, Span, Spanned};
|
||||
use syntax_pos::symbol::{kw, sym};
|
||||
|
|
@ -636,7 +635,7 @@ impl<'a> Parser<'a> {
|
|||
let op_span = self.token.span;
|
||||
// Parse range
|
||||
let span = lo.to(self.prev_span);
|
||||
let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new());
|
||||
let begin = self.mk_expr(span, ExprKind::Path(qself, path), AttrVec::new());
|
||||
self.bump();
|
||||
let end = self.parse_pat_range_end_opt(&begin, form)?;
|
||||
Ok(PatKind::Range(begin, end, respan(op_span, end_kind)))
|
||||
|
|
@ -693,7 +692,7 @@ impl<'a> Parser<'a> {
|
|||
let lo = self.prev_span;
|
||||
let end = self.parse_pat_range_end()?;
|
||||
let range_span = lo.to(end.span);
|
||||
let begin = self.mk_expr(range_span, ExprKind::Err, ThinVec::new());
|
||||
let begin = self.mk_expr(range_span, ExprKind::Err, AttrVec::new());
|
||||
|
||||
self.diagnostic()
|
||||
.struct_span_err(range_span, &format!("`{}X` range patterns are not supported", form))
|
||||
|
|
@ -731,7 +730,7 @@ impl<'a> Parser<'a> {
|
|||
)
|
||||
.emit();
|
||||
|
||||
Ok(self.mk_expr(range_span, ExprKind::Err, ThinVec::new()))
|
||||
Ok(self.mk_expr(range_span, ExprKind::Err, AttrVec::new()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -747,7 +746,7 @@ impl<'a> Parser<'a> {
|
|||
(None, self.parse_path(PathStyle::Expr)?)
|
||||
};
|
||||
let hi = self.prev_span;
|
||||
Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path), ThinVec::new()))
|
||||
Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path), AttrVec::new()))
|
||||
} else {
|
||||
self.parse_literal_maybe_minus()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ use crate::maybe_whole;
|
|||
use rustc_errors::{PResult, Applicability, pluralize};
|
||||
use syntax::ast::{self, QSelf, Path, PathSegment, Ident, ParenthesizedArgs, AngleBracketedArgs};
|
||||
use syntax::ast::{AnonConst, GenericArg, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
|
||||
use syntax::ThinVec;
|
||||
use syntax::token::{self, Token};
|
||||
use syntax_pos::source_map::{Span, BytePos};
|
||||
use syntax_pos::symbol::{kw, sym};
|
||||
|
|
@ -400,7 +399,7 @@ impl<'a> Parser<'a> {
|
|||
// Parse const argument.
|
||||
let expr = if let token::OpenDelim(token::Brace) = self.token.kind {
|
||||
self.parse_block_expr(
|
||||
None, self.token.span, BlockCheckMode::Default, ThinVec::new()
|
||||
None, self.token.span, BlockCheckMode::Default, ast::AttrVec::new()
|
||||
)?
|
||||
} else if self.token.is_ident() {
|
||||
// FIXME(const_generics): to distinguish between idents for types and consts,
|
||||
|
|
|
|||
|
|
@ -7,15 +7,14 @@ use crate::maybe_whole;
|
|||
use crate::DirectoryOwnership;
|
||||
|
||||
use rustc_errors::{PResult, Applicability};
|
||||
use syntax::ThinVec;
|
||||
use syntax::ptr::P;
|
||||
use syntax::ast;
|
||||
use syntax::ast::{DUMMY_NODE_ID, Stmt, StmtKind, Local, Block, BlockCheckMode, Expr, ExprKind};
|
||||
use syntax::ast::{Attribute, AttrStyle, VisibilityKind, MacStmtStyle, Mac};
|
||||
use syntax::ast::{AttrVec, Attribute, AttrStyle, VisibilityKind, MacStmtStyle, Mac};
|
||||
use syntax::util::classify;
|
||||
use syntax::token;
|
||||
use syntax_pos::source_map::{respan, Span};
|
||||
use syntax_pos::symbol::{kw, sym};
|
||||
use syntax_pos::symbol::{kw, sym, Symbol};
|
||||
|
||||
use std::mem;
|
||||
|
||||
|
|
@ -23,15 +22,11 @@ impl<'a> Parser<'a> {
|
|||
/// Parses a statement. This stops just before trailing semicolons on everything but items.
|
||||
/// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed.
|
||||
pub fn parse_stmt(&mut self) -> PResult<'a, Option<Stmt>> {
|
||||
Ok(self.parse_stmt_(true))
|
||||
}
|
||||
|
||||
fn parse_stmt_(&mut self, macro_legacy_warnings: bool) -> Option<Stmt> {
|
||||
self.parse_stmt_without_recovery(macro_legacy_warnings).unwrap_or_else(|mut e| {
|
||||
Ok(self.parse_stmt_without_recovery(true).unwrap_or_else(|mut e| {
|
||||
e.emit();
|
||||
self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
|
||||
None
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn parse_stmt_without_recovery(
|
||||
|
|
@ -43,171 +38,195 @@ impl<'a> Parser<'a> {
|
|||
let attrs = self.parse_outer_attributes()?;
|
||||
let lo = self.token.span;
|
||||
|
||||
Ok(Some(if self.eat_keyword(kw::Let) {
|
||||
Stmt {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: StmtKind::Local(self.parse_local(attrs.into())?),
|
||||
span: lo.to(self.prev_span),
|
||||
}
|
||||
} else if let Some(macro_def) = self.eat_macro_def(
|
||||
&attrs,
|
||||
&respan(lo, VisibilityKind::Inherited),
|
||||
lo,
|
||||
)? {
|
||||
Stmt {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: StmtKind::Item(macro_def),
|
||||
span: lo.to(self.prev_span),
|
||||
}
|
||||
if self.eat_keyword(kw::Let) {
|
||||
return self.parse_local_mk(lo, attrs.into()).map(Some)
|
||||
}
|
||||
if self.is_kw_followed_by_ident(kw::Mut) {
|
||||
return self.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut");
|
||||
}
|
||||
if self.is_kw_followed_by_ident(kw::Auto) {
|
||||
self.bump(); // `auto`
|
||||
let msg = "write `let` instead of `auto` to introduce a new variable";
|
||||
return self.recover_stmt_local(lo, attrs.into(), msg, "let");
|
||||
}
|
||||
if self.is_kw_followed_by_ident(sym::var) {
|
||||
self.bump(); // `var`
|
||||
let msg = "write `let` instead of `var` to introduce a new variable";
|
||||
return self.recover_stmt_local(lo, attrs.into(), msg, "let");
|
||||
}
|
||||
|
||||
let mac_vis = respan(lo, VisibilityKind::Inherited);
|
||||
if let Some(macro_def) = self.eat_macro_def(&attrs, &mac_vis, lo)? {
|
||||
return Ok(Some(self.mk_stmt(lo.to(self.prev_span), StmtKind::Item(macro_def))));
|
||||
}
|
||||
|
||||
// Starts like a simple path, being careful to avoid contextual keywords
|
||||
// such as a union items, item with `crate` visibility or auto trait items.
|
||||
// Our goal here is to parse an arbitrary path `a::b::c` but not something that starts
|
||||
// like a path (1 token), but it fact not a path.
|
||||
// `union::b::c` - path, `union U { ... }` - not a path.
|
||||
// `crate::b::c` - path, `crate struct S;` - not a path.
|
||||
} else if self.token.is_path_start() &&
|
||||
!self.token.is_qpath_start() &&
|
||||
!self.is_union_item() &&
|
||||
!self.is_crate_vis() &&
|
||||
!self.is_auto_trait_item() &&
|
||||
!self.is_async_fn() {
|
||||
if self.token.is_path_start()
|
||||
&& !self.token.is_qpath_start()
|
||||
&& !self.is_union_item() // `union::b::c` - path, `union U { ... }` - not a path.
|
||||
&& !self.is_crate_vis() // `crate::b::c` - path, `crate struct S;` - not a path.
|
||||
&& !self.is_auto_trait_item()
|
||||
&& !self.is_async_fn()
|
||||
{
|
||||
let path = self.parse_path(PathStyle::Expr)?;
|
||||
|
||||
if !self.eat(&token::Not) {
|
||||
let expr = if self.check(&token::OpenDelim(token::Brace)) {
|
||||
self.parse_struct_expr(lo, path, ThinVec::new())?
|
||||
} else {
|
||||
let hi = self.prev_span;
|
||||
self.mk_expr(lo.to(hi), ExprKind::Path(None, path), ThinVec::new())
|
||||
};
|
||||
|
||||
let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
|
||||
let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
|
||||
this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
|
||||
})?;
|
||||
|
||||
return Ok(Some(Stmt {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: StmtKind::Expr(expr),
|
||||
span: lo.to(self.prev_span),
|
||||
}));
|
||||
if self.eat(&token::Not) {
|
||||
return self.parse_stmt_mac(lo, attrs.into(), path, macro_legacy_warnings);
|
||||
}
|
||||
|
||||
let args = self.parse_mac_args()?;
|
||||
let delim = args.delim();
|
||||
let hi = self.prev_span;
|
||||
|
||||
let style = if delim == token::Brace {
|
||||
MacStmtStyle::Braces
|
||||
let expr = if self.check(&token::OpenDelim(token::Brace)) {
|
||||
self.parse_struct_expr(lo, path, AttrVec::new())?
|
||||
} else {
|
||||
MacStmtStyle::NoBraces
|
||||
let hi = self.prev_span;
|
||||
self.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new())
|
||||
};
|
||||
|
||||
let mac = Mac {
|
||||
path,
|
||||
args,
|
||||
prior_type_ascription: self.last_type_ascription,
|
||||
};
|
||||
let kind = if delim == token::Brace ||
|
||||
self.token == token::Semi || self.token == token::Eof {
|
||||
StmtKind::Mac(P((mac, style, attrs.into())))
|
||||
}
|
||||
// We used to incorrectly stop parsing macro-expanded statements here.
|
||||
// If the next token will be an error anyway but could have parsed with the
|
||||
// earlier behavior, stop parsing here and emit a warning to avoid breakage.
|
||||
else if macro_legacy_warnings && self.token.can_begin_expr() &&
|
||||
match self.token.kind {
|
||||
// These can continue an expression, so we can't stop parsing and warn.
|
||||
token::OpenDelim(token::Paren) | token::OpenDelim(token::Bracket) |
|
||||
token::BinOp(token::Minus) | token::BinOp(token::Star) |
|
||||
token::BinOp(token::And) | token::BinOp(token::Or) |
|
||||
token::AndAnd | token::OrOr |
|
||||
token::DotDot | token::DotDotDot | token::DotDotEq => false,
|
||||
_ => true,
|
||||
}
|
||||
{
|
||||
self.warn_missing_semicolon();
|
||||
StmtKind::Mac(P((mac, style, attrs.into())))
|
||||
} else {
|
||||
let e = self.mk_expr(lo.to(hi), ExprKind::Mac(mac), ThinVec::new());
|
||||
let e = self.maybe_recover_from_bad_qpath(e, true)?;
|
||||
let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
|
||||
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
|
||||
StmtKind::Expr(e)
|
||||
};
|
||||
Stmt {
|
||||
id: DUMMY_NODE_ID,
|
||||
span: lo.to(hi),
|
||||
kind,
|
||||
let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
|
||||
let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
|
||||
this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
|
||||
})?;
|
||||
return Ok(Some(self.mk_stmt(lo.to(self.prev_span), StmtKind::Expr(expr))));
|
||||
}
|
||||
|
||||
// FIXME: Bad copy of attrs
|
||||
let old_directory_ownership =
|
||||
mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock);
|
||||
let item = self.parse_item_(attrs.clone(), false, true)?;
|
||||
self.directory.ownership = old_directory_ownership;
|
||||
|
||||
if let Some(item) = item {
|
||||
return Ok(Some(self.mk_stmt(lo.to(item.span), StmtKind::Item(item))));
|
||||
}
|
||||
|
||||
// Do not attempt to parse an expression if we're done here.
|
||||
if self.token == token::Semi {
|
||||
self.error_outer_attrs(&attrs);
|
||||
self.bump();
|
||||
let mut last_semi = lo;
|
||||
while self.token == token::Semi {
|
||||
last_semi = self.token.span;
|
||||
self.bump();
|
||||
}
|
||||
// We are encoding a string of semicolons as an an empty tuple that spans
|
||||
// the excess semicolons to preserve this info until the lint stage.
|
||||
let kind = StmtKind::Semi(self.mk_expr(
|
||||
lo.to(last_semi),
|
||||
ExprKind::Tup(Vec::new()),
|
||||
AttrVec::new()
|
||||
));
|
||||
return Ok(Some(self.mk_stmt(lo.to(last_semi), kind)));
|
||||
}
|
||||
|
||||
if self.token == token::CloseDelim(token::Brace) {
|
||||
self.error_outer_attrs(&attrs);
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// Remainder are line-expr stmts.
|
||||
let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?;
|
||||
Ok(Some(self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))))
|
||||
}
|
||||
|
||||
/// Parses a statement macro `mac!(args)` provided a `path` representing `mac`.
|
||||
/// At this point, the `!` token after the path has already been eaten.
|
||||
fn parse_stmt_mac(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
attrs: AttrVec,
|
||||
path: ast::Path,
|
||||
legacy_warnings: bool,
|
||||
) -> PResult<'a, Option<Stmt>> {
|
||||
let args = self.parse_mac_args()?;
|
||||
let delim = args.delim();
|
||||
let hi = self.prev_span;
|
||||
|
||||
let style = if delim == token::Brace {
|
||||
MacStmtStyle::Braces
|
||||
} else {
|
||||
// FIXME: Bad copy of attrs
|
||||
let old_directory_ownership =
|
||||
mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock);
|
||||
let item = self.parse_item_(attrs.clone(), false, true)?;
|
||||
self.directory.ownership = old_directory_ownership;
|
||||
MacStmtStyle::NoBraces
|
||||
};
|
||||
|
||||
match item {
|
||||
Some(i) => Stmt {
|
||||
id: DUMMY_NODE_ID,
|
||||
span: lo.to(i.span),
|
||||
kind: StmtKind::Item(i),
|
||||
},
|
||||
None => {
|
||||
let unused_attrs = |attrs: &[Attribute], s: &mut Self| {
|
||||
if !attrs.is_empty() {
|
||||
if s.prev_token_kind == PrevTokenKind::DocComment {
|
||||
s.span_fatal_err(s.prev_span, Error::UselessDocComment).emit();
|
||||
} else if attrs.iter().any(|a| a.style == AttrStyle::Outer) {
|
||||
s.span_err(
|
||||
s.token.span, "expected statement after outer attribute"
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
let mac = Mac {
|
||||
path,
|
||||
args,
|
||||
prior_type_ascription: self.last_type_ascription,
|
||||
};
|
||||
|
||||
// Do not attempt to parse an expression if we're done here.
|
||||
if self.token == token::Semi {
|
||||
unused_attrs(&attrs, self);
|
||||
self.bump();
|
||||
let mut last_semi = lo;
|
||||
while self.token == token::Semi {
|
||||
last_semi = self.token.span;
|
||||
self.bump();
|
||||
}
|
||||
// We are encoding a string of semicolons as an
|
||||
// an empty tuple that spans the excess semicolons
|
||||
// to preserve this info until the lint stage
|
||||
return Ok(Some(Stmt {
|
||||
id: DUMMY_NODE_ID,
|
||||
span: lo.to(last_semi),
|
||||
kind: StmtKind::Semi(self.mk_expr(lo.to(last_semi),
|
||||
ExprKind::Tup(Vec::new()),
|
||||
ThinVec::new()
|
||||
)),
|
||||
}));
|
||||
}
|
||||
|
||||
if self.token == token::CloseDelim(token::Brace) {
|
||||
unused_attrs(&attrs, self);
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// Remainder are line-expr stmts.
|
||||
let e = self.parse_expr_res(
|
||||
Restrictions::STMT_EXPR, Some(attrs.into()))?;
|
||||
Stmt {
|
||||
id: DUMMY_NODE_ID,
|
||||
span: lo.to(e.span),
|
||||
kind: StmtKind::Expr(e),
|
||||
}
|
||||
}
|
||||
let kind = if delim == token::Brace
|
||||
|| self.token == token::Semi
|
||||
|| self.token == token::Eof
|
||||
{
|
||||
StmtKind::Mac(P((mac, style, attrs.into())))
|
||||
}
|
||||
// We used to incorrectly stop parsing macro-expanded statements here.
|
||||
// If the next token will be an error anyway but could have parsed with the
|
||||
// earlier behavior, stop parsing here and emit a warning to avoid breakage.
|
||||
else if legacy_warnings
|
||||
&& self.token.can_begin_expr()
|
||||
&& match self.token.kind {
|
||||
// These can continue an expression, so we can't stop parsing and warn.
|
||||
token::OpenDelim(token::Paren) | token::OpenDelim(token::Bracket) |
|
||||
token::BinOp(token::Minus) | token::BinOp(token::Star) |
|
||||
token::BinOp(token::And) | token::BinOp(token::Or) |
|
||||
token::AndAnd | token::OrOr |
|
||||
token::DotDot | token::DotDotDot | token::DotDotEq => false,
|
||||
_ => true,
|
||||
}
|
||||
}))
|
||||
{
|
||||
self.warn_missing_semicolon();
|
||||
StmtKind::Mac(P((mac, style, attrs)))
|
||||
} else {
|
||||
// Since none of the above applied, this is an expression statement macro.
|
||||
let e = self.mk_expr(lo.to(hi), ExprKind::Mac(mac), AttrVec::new());
|
||||
let e = self.maybe_recover_from_bad_qpath(e, true)?;
|
||||
let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?;
|
||||
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
|
||||
StmtKind::Expr(e)
|
||||
};
|
||||
Ok(Some(self.mk_stmt(lo.to(hi), kind)))
|
||||
}
|
||||
|
||||
/// Error on outer attributes in this context.
|
||||
/// Also error if the previous token was a doc comment.
|
||||
fn error_outer_attrs(&self, attrs: &[Attribute]) {
|
||||
if !attrs.is_empty() {
|
||||
if self.prev_token_kind == PrevTokenKind::DocComment {
|
||||
self.span_fatal_err(self.prev_span, Error::UselessDocComment).emit();
|
||||
} else if attrs.iter().any(|a| a.style == AttrStyle::Outer) {
|
||||
self.span_err(self.token.span, "expected statement after outer attribute");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool {
|
||||
self.token.is_keyword(kw)
|
||||
&& self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident())
|
||||
}
|
||||
|
||||
fn recover_stmt_local(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
attrs: AttrVec,
|
||||
msg: &str,
|
||||
sugg: &str,
|
||||
) -> PResult<'a, Option<Stmt>> {
|
||||
let stmt = self.parse_local_mk(lo, attrs)?;
|
||||
self.struct_span_err(lo, "invalid variable declaration")
|
||||
.span_suggestion(lo, msg, sugg.to_string(), Applicability::MachineApplicable)
|
||||
.emit();
|
||||
Ok(Some(stmt))
|
||||
}
|
||||
|
||||
fn parse_local_mk(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> {
|
||||
let local = self.parse_local(attrs.into())?;
|
||||
Ok(self.mk_stmt(lo.to(self.prev_span), StmtKind::Local(local)))
|
||||
}
|
||||
|
||||
/// Parses a local variable declaration.
|
||||
fn parse_local(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Local>> {
|
||||
fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
|
||||
let lo = self.prev_span;
|
||||
let pat = self.parse_top_pat(GateOr::Yes)?;
|
||||
|
||||
|
|
@ -307,72 +326,60 @@ impl<'a> Parser<'a> {
|
|||
let lo = self.token.span;
|
||||
|
||||
if !self.eat(&token::OpenDelim(token::Brace)) {
|
||||
let sp = self.token.span;
|
||||
let tok = self.this_token_descr();
|
||||
let mut e = self.span_fatal(sp, &format!("expected `{{`, found {}", tok));
|
||||
let do_not_suggest_help =
|
||||
self.token.is_keyword(kw::In) || self.token == token::Colon;
|
||||
|
||||
if self.token.is_ident_named(sym::and) {
|
||||
e.span_suggestion_short(
|
||||
self.token.span,
|
||||
"use `&&` instead of `and` for the boolean operator",
|
||||
"&&".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
if self.token.is_ident_named(sym::or) {
|
||||
e.span_suggestion_short(
|
||||
self.token.span,
|
||||
"use `||` instead of `or` for the boolean operator",
|
||||
"||".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
// Check to see if the user has written something like
|
||||
//
|
||||
// if (cond)
|
||||
// bar;
|
||||
//
|
||||
// which is valid in other languages, but not Rust.
|
||||
match self.parse_stmt_without_recovery(false) {
|
||||
Ok(Some(stmt)) => {
|
||||
if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace))
|
||||
|| do_not_suggest_help {
|
||||
// If the next token is an open brace (e.g., `if a b {`), the place-
|
||||
// inside-a-block suggestion would be more likely wrong than right.
|
||||
e.span_label(sp, "expected `{`");
|
||||
return Err(e);
|
||||
}
|
||||
let mut stmt_span = stmt.span;
|
||||
// Expand the span to include the semicolon, if it exists.
|
||||
if self.eat(&token::Semi) {
|
||||
stmt_span = stmt_span.with_hi(self.prev_span.hi());
|
||||
}
|
||||
if let Ok(snippet) = self.span_to_snippet(stmt_span) {
|
||||
e.span_suggestion(
|
||||
stmt_span,
|
||||
"try placing this code inside a block",
|
||||
format!("{{ {} }}", snippet),
|
||||
// Speculative; has been misleading in the past (#46836).
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(mut e) => {
|
||||
self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
|
||||
e.cancel();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
e.span_label(sp, "expected `{`");
|
||||
return Err(e);
|
||||
return self.error_block_no_opening_brace();
|
||||
}
|
||||
|
||||
self.parse_block_tail(lo, BlockCheckMode::Default)
|
||||
}
|
||||
|
||||
fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
|
||||
let sp = self.token.span;
|
||||
let tok = self.this_token_descr();
|
||||
let mut e = self.span_fatal(sp, &format!("expected `{{`, found {}", tok));
|
||||
let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon;
|
||||
|
||||
// Check to see if the user has written something like
|
||||
//
|
||||
// if (cond)
|
||||
// bar;
|
||||
//
|
||||
// which is valid in other languages, but not Rust.
|
||||
match self.parse_stmt_without_recovery(false) {
|
||||
Ok(Some(stmt)) => {
|
||||
if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace))
|
||||
|| do_not_suggest_help
|
||||
{
|
||||
// If the next token is an open brace (e.g., `if a b {`), the place-
|
||||
// inside-a-block suggestion would be more likely wrong than right.
|
||||
e.span_label(sp, "expected `{`");
|
||||
return Err(e);
|
||||
}
|
||||
let stmt_span = if self.eat(&token::Semi) {
|
||||
// Expand the span to include the semicolon.
|
||||
stmt.span.with_hi(self.prev_span.hi())
|
||||
} else {
|
||||
stmt.span
|
||||
};
|
||||
if let Ok(snippet) = self.span_to_snippet(stmt_span) {
|
||||
e.span_suggestion(
|
||||
stmt_span,
|
||||
"try placing this code inside a block",
|
||||
format!("{{ {} }}", snippet),
|
||||
// Speculative; has been misleading in the past (#46836).
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(mut e) => {
|
||||
self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
|
||||
e.cancel();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
e.span_label(sp, "expected `{`");
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
/// Parses a block. Inner attributes are allowed.
|
||||
pub(super) fn parse_inner_attrs_and_block(
|
||||
&mut self
|
||||
|
|
@ -402,11 +409,10 @@ impl<'a> Parser<'a> {
|
|||
self.maybe_annotate_with_ascription(&mut err, false);
|
||||
err.emit();
|
||||
self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
|
||||
Some(Stmt {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: StmtKind::Expr(self.mk_expr_err(self.token.span)),
|
||||
span: self.token.span,
|
||||
})
|
||||
Some(self.mk_stmt(
|
||||
self.token.span,
|
||||
StmtKind::Expr(self.mk_expr_err(self.token.span)),
|
||||
))
|
||||
}
|
||||
Ok(stmt) => stmt,
|
||||
};
|
||||
|
|
@ -478,4 +484,8 @@ impl<'a> Parser<'a> {
|
|||
"this was erroneously allowed and will become a hard error in a future release"
|
||||
}).emit();
|
||||
}
|
||||
|
||||
fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt {
|
||||
Stmt { id: DUMMY_NODE_ID, kind, span }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -338,7 +338,7 @@ pub enum GenericParamKind {
|
|||
pub struct GenericParam {
|
||||
pub id: NodeId,
|
||||
pub ident: Ident,
|
||||
pub attrs: ThinVec<Attribute>,
|
||||
pub attrs: AttrVec,
|
||||
pub bounds: GenericBounds,
|
||||
pub is_placeholder: bool,
|
||||
pub kind: GenericParamKind,
|
||||
|
|
@ -599,7 +599,7 @@ pub struct FieldPat {
|
|||
/// The pattern the field is destructured to
|
||||
pub pat: P<Pat>,
|
||||
pub is_shorthand: bool,
|
||||
pub attrs: ThinVec<Attribute>,
|
||||
pub attrs: AttrVec,
|
||||
pub id: NodeId,
|
||||
pub span: Span,
|
||||
pub is_placeholder: bool,
|
||||
|
|
@ -911,7 +911,7 @@ pub enum StmtKind {
|
|||
/// Expr with a trailing semi-colon.
|
||||
Semi(P<Expr>),
|
||||
/// Macro.
|
||||
Mac(P<(Mac, MacStmtStyle, ThinVec<Attribute>)>),
|
||||
Mac(P<(Mac, MacStmtStyle, AttrVec)>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug)]
|
||||
|
|
@ -936,7 +936,7 @@ pub struct Local {
|
|||
/// Initializer expression to set the value, if any.
|
||||
pub init: Option<P<Expr>>,
|
||||
pub span: Span,
|
||||
pub attrs: ThinVec<Attribute>,
|
||||
pub attrs: AttrVec,
|
||||
}
|
||||
|
||||
/// An arm of a 'match'.
|
||||
|
|
@ -966,7 +966,7 @@ pub struct Arm {
|
|||
/// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct field.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub struct Field {
|
||||
pub attrs: ThinVec<Attribute>,
|
||||
pub attrs: AttrVec,
|
||||
pub id: NodeId,
|
||||
pub span: Span,
|
||||
pub ident: Ident,
|
||||
|
|
@ -1004,7 +1004,7 @@ pub struct Expr {
|
|||
pub id: NodeId,
|
||||
pub kind: ExprKind,
|
||||
pub span: Span,
|
||||
pub attrs: ThinVec<Attribute>,
|
||||
pub attrs: AttrVec,
|
||||
}
|
||||
|
||||
// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||
|
|
@ -1961,7 +1961,7 @@ pub struct InlineAsm {
|
|||
/// E.g., `bar: usize` as in `fn foo(bar: usize)`.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub struct Param {
|
||||
pub attrs: ThinVec<Attribute>,
|
||||
pub attrs: AttrVec,
|
||||
pub ty: P<Ty>,
|
||||
pub pat: P<Pat>,
|
||||
pub id: NodeId,
|
||||
|
|
@ -2014,7 +2014,7 @@ impl Param {
|
|||
}
|
||||
|
||||
/// Builds a `Param` object from `ExplicitSelf`.
|
||||
pub fn from_self(attrs: ThinVec<Attribute>, eself: ExplicitSelf, eself_ident: Ident) -> Param {
|
||||
pub fn from_self(attrs: AttrVec, eself: ExplicitSelf, eself_ident: Ident) -> Param {
|
||||
let span = eself.span.to(eself_ident.span);
|
||||
let infer_ty = P(Ty {
|
||||
id: DUMMY_NODE_ID,
|
||||
|
|
@ -2332,6 +2332,9 @@ pub struct AttrItem {
|
|||
pub args: MacArgs,
|
||||
}
|
||||
|
||||
/// A list of attributes.
|
||||
pub type AttrVec = ThinVec<Attribute>;
|
||||
|
||||
/// Metadata associated with an item.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub struct Attribute {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ pub use StabilityLevel::*;
|
|||
pub use crate::ast::Attribute;
|
||||
|
||||
use crate::ast;
|
||||
use crate::ast::{AttrItem, AttrId, AttrKind, AttrStyle, Name, Ident, Path, PathSegment};
|
||||
use crate::ast::{AttrVec, AttrItem, AttrId, AttrKind, AttrStyle, Name, Ident, Path, PathSegment};
|
||||
use crate::ast::{MacArgs, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem};
|
||||
use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam};
|
||||
use crate::mut_visit::visit_clobber;
|
||||
|
|
@ -17,7 +17,6 @@ use crate::source_map::{BytePos, Spanned};
|
|||
use crate::token::{self, Token};
|
||||
use crate::ptr::P;
|
||||
use crate::symbol::{sym, Symbol};
|
||||
use crate::ThinVec;
|
||||
use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
|
||||
use crate::GLOBALS;
|
||||
|
||||
|
|
@ -665,7 +664,7 @@ impl HasAttrs for Vec<Attribute> {
|
|||
}
|
||||
}
|
||||
|
||||
impl HasAttrs for ThinVec<Attribute> {
|
||||
impl HasAttrs for AttrVec {
|
||||
fn attrs(&self) -> &[Attribute] {
|
||||
self
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
pub use errors;
|
||||
use rustc_data_structures::sync::Lock;
|
||||
use rustc_index::bit_set::GrowableBitSet;
|
||||
pub use rustc_data_structures::thin_vec::ThinVec;
|
||||
use ast::AttrId;
|
||||
use syntax_pos::edition::Edition;
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ use crate::ast::*;
|
|||
use crate::source_map::{Spanned, respan};
|
||||
use crate::token::{self, Token};
|
||||
use crate::ptr::P;
|
||||
use crate::ThinVec;
|
||||
use crate::tokenstream::*;
|
||||
use crate::util::map_in_place::MapInPlace;
|
||||
|
||||
|
|
@ -337,7 +336,7 @@ pub fn visit_attrs<T: MutVisitor>(attrs: &mut Vec<Attribute>, vis: &mut T) {
|
|||
}
|
||||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
pub fn visit_thin_attrs<T: MutVisitor>(attrs: &mut ThinVec<Attribute>, vis: &mut T) {
|
||||
pub fn visit_thin_attrs<T: MutVisitor>(attrs: &mut AttrVec, vis: &mut T) {
|
||||
for attr in attrs.iter_mut() {
|
||||
vis.visit_attribute(attr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ use syntax::mut_visit::{self, MutVisitor};
|
|||
use syntax::ptr::P;
|
||||
use syntax::sess::ParseSess;
|
||||
use syntax::symbol::{kw, sym, Ident, Symbol};
|
||||
use syntax::ThinVec;
|
||||
use syntax::token;
|
||||
use syntax::tokenstream::{self, TokenStream};
|
||||
use syntax::visit::Visitor;
|
||||
|
|
@ -552,7 +551,7 @@ impl DummyResult {
|
|||
id: ast::DUMMY_NODE_ID,
|
||||
kind: if is_error { ast::ExprKind::Err } else { ast::ExprKind::Tup(Vec::new()) },
|
||||
span: sp,
|
||||
attrs: ThinVec::new(),
|
||||
attrs: ast::AttrVec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
use crate::base::ExtCtxt;
|
||||
|
||||
use syntax::ast::{self, Ident, Expr, BlockCheckMode, UnOp, PatKind};
|
||||
use syntax::ast::{self, AttrVec, Ident, Expr, BlockCheckMode, UnOp, PatKind};
|
||||
use syntax::attr;
|
||||
use syntax::source_map::{respan, Spanned};
|
||||
use syntax::ptr::P;
|
||||
use syntax::symbol::{kw, sym, Symbol};
|
||||
use syntax::ThinVec;
|
||||
|
||||
use syntax_pos::{Pos, Span};
|
||||
|
||||
|
|
@ -81,7 +80,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
id: ast::DUMMY_NODE_ID,
|
||||
kind,
|
||||
span,
|
||||
attrs: ThinVec::new(),
|
||||
attrs: AttrVec::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -190,7 +189,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
init: Some(ex),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: sp,
|
||||
attrs: ThinVec::new(),
|
||||
attrs: AttrVec::new(),
|
||||
});
|
||||
ast::Stmt {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
|
|
@ -207,7 +206,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
init: None,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span,
|
||||
attrs: ThinVec::new(),
|
||||
attrs: AttrVec::new(),
|
||||
});
|
||||
ast::Stmt {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
|
|
@ -245,7 +244,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
id: ast::DUMMY_NODE_ID,
|
||||
kind,
|
||||
span,
|
||||
attrs: ThinVec::new(),
|
||||
attrs: AttrVec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -304,7 +303,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
expr: e,
|
||||
span,
|
||||
is_shorthand: false,
|
||||
attrs: ThinVec::new(),
|
||||
attrs: AttrVec::new(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
is_placeholder: false,
|
||||
}
|
||||
|
|
@ -549,7 +548,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
pub fn param(&self, span: Span, ident: ast::Ident, ty: P<ast::Ty>) -> ast::Param {
|
||||
let arg_pat = self.pat_ident(span, ident);
|
||||
ast::Param {
|
||||
attrs: ThinVec::default(),
|
||||
attrs: AttrVec::default(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
pat: arg_pat,
|
||||
span,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,30 @@ crate fn annotate_err_with_kind(
|
|||
};
|
||||
}
|
||||
|
||||
/// Instead of e.g. `vec![a, b, c]` in a pattern context, suggest `[a, b, c]`.
|
||||
fn suggest_slice_pat(e: &mut DiagnosticBuilder<'_>, site_span: Span, parser: &Parser<'_>) {
|
||||
let mut suggestion = None;
|
||||
if let Ok(code) = parser.sess.source_map().span_to_snippet(site_span) {
|
||||
if let Some(bang) = code.find('!') {
|
||||
suggestion = Some(code[bang + 1..].to_string());
|
||||
}
|
||||
}
|
||||
if let Some(suggestion) = suggestion {
|
||||
e.span_suggestion(
|
||||
site_span,
|
||||
"use a slice pattern here instead",
|
||||
suggestion,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
e.span_label(site_span, "use a slice pattern here instead");
|
||||
}
|
||||
e.help(
|
||||
"for more information, see https://doc.rust-lang.org/edition-guide/\
|
||||
rust-2018/slice-patterns.html"
|
||||
);
|
||||
}
|
||||
|
||||
impl<'a> ParserAnyMacro<'a> {
|
||||
crate fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
|
||||
let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self;
|
||||
|
|
@ -92,27 +116,7 @@ impl<'a> ParserAnyMacro<'a> {
|
|||
}
|
||||
match kind {
|
||||
AstFragmentKind::Pat if macro_ident.name == sym::vec => {
|
||||
let mut suggestion = None;
|
||||
if let Ok(code) = parser.sess.source_map().span_to_snippet(site_span) {
|
||||
if let Some(bang) = code.find('!') {
|
||||
suggestion = Some(code[bang + 1..].to_string());
|
||||
}
|
||||
}
|
||||
if let Some(suggestion) = suggestion {
|
||||
e.span_suggestion(
|
||||
site_span,
|
||||
"use a slice pattern here instead",
|
||||
suggestion,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
e.span_label(
|
||||
site_span,
|
||||
"use a slice pattern here instead",
|
||||
);
|
||||
}
|
||||
e.help("for more information, see https://doc.rust-lang.org/edition-guide/\
|
||||
rust-2018/slice-patterns.html");
|
||||
suggest_slice_pat(&mut e, site_span, parser);
|
||||
}
|
||||
_ => annotate_err_with_kind(&mut e, kind, site_span),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ use syntax::ast;
|
|||
use syntax::source_map::{DUMMY_SP, dummy_spanned};
|
||||
use syntax::mut_visit::*;
|
||||
use syntax::ptr::P;
|
||||
use syntax::ThinVec;
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
|
|
@ -28,7 +27,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId, vis: Option<ast::Visi
|
|||
let span = DUMMY_SP;
|
||||
let expr_placeholder = || P(ast::Expr {
|
||||
id, span,
|
||||
attrs: ThinVec::new(),
|
||||
attrs: ast::AttrVec::new(),
|
||||
kind: ast::ExprKind::Mac(mac_placeholder()),
|
||||
});
|
||||
let ty = || P(ast::Ty {
|
||||
|
|
@ -75,7 +74,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId, vis: Option<ast::Visi
|
|||
id, span, kind: ast::TyKind::Mac(mac_placeholder()),
|
||||
})),
|
||||
AstFragmentKind::Stmts => AstFragment::Stmts(smallvec![{
|
||||
let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ThinVec::new()));
|
||||
let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ast::AttrVec::new()));
|
||||
ast::Stmt { id, span, kind: ast::StmtKind::Mac(mac) }
|
||||
}]),
|
||||
AstFragmentKind::Arms => AstFragment::Arms(smallvec![
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
use State::*;
|
||||
|
||||
use errors::{DiagnosticBuilder, PResult};
|
||||
use rustc_data_structures::thin_vec::ThinVec;
|
||||
use rustc_parse::parser::Parser;
|
||||
use syntax_expand::base::*;
|
||||
use syntax_pos::Span;
|
||||
|
|
@ -63,7 +62,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt<'_>,
|
|||
id: ast::DUMMY_NODE_ID,
|
||||
kind: ast::ExprKind::InlineAsm(P(inline_asm)),
|
||||
span: cx.with_def_site_ctxt(sp),
|
||||
attrs: ThinVec::new(),
|
||||
attrs: ast::AttrVec::new(),
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
use rustc_data_structures::thin_vec::ThinVec;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax_expand::base::{self, *};
|
||||
use syntax::token::{self, Token};
|
||||
|
|
@ -49,7 +47,7 @@ pub fn expand_concat_idents<'cx>(cx: &'cx mut ExtCtxt<'_>,
|
|||
id: ast::DUMMY_NODE_ID,
|
||||
kind: ast::ExprKind::Path(None, ast::Path::from_ident(self.ident)),
|
||||
span: self.ident.span,
|
||||
attrs: ThinVec::new(),
|
||||
attrs: ast::AttrVec::new(),
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ use crate::deriving::path_std;
|
|||
use crate::deriving::generic::*;
|
||||
use crate::deriving::generic::ty::*;
|
||||
|
||||
use rustc_data_structures::thin_vec::ThinVec;
|
||||
|
||||
use syntax::ast::{self, Ident};
|
||||
use syntax::ast::{Expr, MetaItem};
|
||||
use syntax_expand::base::{Annotatable, ExtCtxt};
|
||||
|
|
@ -127,7 +125,7 @@ fn stmt_let_undescore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P<ast::Expr>) -> ast
|
|||
init: Some(expr),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: sp,
|
||||
attrs: ThinVec::new(),
|
||||
attrs: ast::AttrVec::new(),
|
||||
});
|
||||
ast::Stmt {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
|
|
|
|||
|
|
@ -181,7 +181,6 @@ use std::cell::RefCell;
|
|||
use std::iter;
|
||||
use std::vec;
|
||||
|
||||
use rustc_data_structures::thin_vec::ThinVec;
|
||||
use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind};
|
||||
use syntax::ast::{VariantData, GenericParamKind, GenericArg};
|
||||
use syntax::attr;
|
||||
|
|
@ -919,7 +918,7 @@ impl<'a> MethodDef<'a> {
|
|||
let args = {
|
||||
let self_args = explicit_self.map(|explicit_self| {
|
||||
let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(trait_.span);
|
||||
ast::Param::from_self(ThinVec::default(), explicit_self, ident)
|
||||
ast::Param::from_self(ast::AttrVec::default(), explicit_self, ident)
|
||||
});
|
||||
let nonself_args = arg_types.into_iter()
|
||||
.map(|(name, ty)| cx.param(trait_.span, name, ty));
|
||||
|
|
@ -1608,7 +1607,7 @@ impl<'a> TraitDef<'a> {
|
|||
ast::FieldPat {
|
||||
ident: ident.unwrap(),
|
||||
is_shorthand: false,
|
||||
attrs: ThinVec::new(),
|
||||
attrs: ast::AttrVec::new(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: pat.span.with_ctxt(self.span.ctxt()),
|
||||
pat,
|
||||
|
|
|
|||
|
|
@ -773,6 +773,7 @@ symbols! {
|
|||
usize,
|
||||
v1,
|
||||
val,
|
||||
var,
|
||||
vec,
|
||||
Vec,
|
||||
vis,
|
||||
|
|
|
|||
175
src/test/pretty/ast-stmt-expr-attr.rs
Normal file
175
src/test/pretty/ast-stmt-expr-attr.rs
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
// pp-exact
|
||||
|
||||
fn main() { }
|
||||
|
||||
#[cfg(FALSE)]
|
||||
fn syntax() {
|
||||
let _ = #[attr] box 0;
|
||||
let _ = #[attr] [#![attr] ];
|
||||
let _ = #[attr] [#![attr] 0];
|
||||
let _ = #[attr] [#![attr] 0; 0];
|
||||
let _ = #[attr] [#![attr] 0, 0, 0];
|
||||
let _ = #[attr] foo();
|
||||
let _ = #[attr] x.foo();
|
||||
let _ = #[attr] (#![attr] );
|
||||
let _ = #[attr] (#![attr] #[attr] 0,);
|
||||
let _ = #[attr] (#![attr] #[attr] 0, 0);
|
||||
let _ = #[attr] 0 + #[attr] 0;
|
||||
let _ = #[attr] 0 / #[attr] 0;
|
||||
let _ = #[attr] 0 & #[attr] 0;
|
||||
let _ = #[attr] 0 % #[attr] 0;
|
||||
let _ = #[attr] (0 + 0);
|
||||
let _ = #[attr] !0;
|
||||
let _ = #[attr] -0;
|
||||
let _ = #[attr] false;
|
||||
let _ = #[attr] 0;
|
||||
let _ = #[attr] 'c';
|
||||
let _ = #[attr] x as Y;
|
||||
let _ = #[attr] (x as Y);
|
||||
let _ =
|
||||
#[attr] while true {
|
||||
#![attr]
|
||||
};
|
||||
let _ =
|
||||
#[attr] while let Some(false) = true {
|
||||
#![attr]
|
||||
};
|
||||
let _ =
|
||||
#[attr] for x in y {
|
||||
#![attr]
|
||||
};
|
||||
let _ =
|
||||
#[attr] loop {
|
||||
#![attr]
|
||||
};
|
||||
let _ =
|
||||
#[attr] match true {
|
||||
#![attr]
|
||||
#[attr]
|
||||
_ => false,
|
||||
};
|
||||
let _ = #[attr] || #[attr] foo;
|
||||
let _ = #[attr] move || #[attr] foo;
|
||||
let _ =
|
||||
#[attr] ||
|
||||
#[attr] {
|
||||
#![attr]
|
||||
foo
|
||||
};
|
||||
let _ =
|
||||
#[attr] move ||
|
||||
#[attr] {
|
||||
#![attr]
|
||||
foo
|
||||
};
|
||||
let _ =
|
||||
#[attr] ||
|
||||
{
|
||||
#![attr]
|
||||
foo
|
||||
};
|
||||
let _ =
|
||||
#[attr] move ||
|
||||
{
|
||||
#![attr]
|
||||
foo
|
||||
};
|
||||
let _ =
|
||||
#[attr] {
|
||||
#![attr]
|
||||
};
|
||||
let _ =
|
||||
#[attr] {
|
||||
#![attr]
|
||||
let _ = ();
|
||||
};
|
||||
let _ =
|
||||
#[attr] {
|
||||
#![attr]
|
||||
let _ = ();
|
||||
foo
|
||||
};
|
||||
let _ = #[attr] x = y;
|
||||
let _ = #[attr] (x = y);
|
||||
let _ = #[attr] x += y;
|
||||
let _ = #[attr] (x += y);
|
||||
let _ = #[attr] foo.bar;
|
||||
let _ = (#[attr] foo).bar;
|
||||
let _ = #[attr] foo.0;
|
||||
let _ = (#[attr] foo).0;
|
||||
let _ = #[attr] foo[bar];
|
||||
let _ = (#[attr] foo)[bar];
|
||||
let _ = #[attr] 0..#[attr] 0;
|
||||
let _ = #[attr] 0..;
|
||||
let _ = #[attr] (0..0);
|
||||
let _ = #[attr] (0..);
|
||||
let _ = #[attr] (..0);
|
||||
let _ = #[attr] (..);
|
||||
let _ = #[attr] foo::bar::baz;
|
||||
let _ = #[attr] &0;
|
||||
let _ = #[attr] &mut 0;
|
||||
let _ = #[attr] &#[attr] 0;
|
||||
let _ = #[attr] &mut #[attr] 0;
|
||||
let _ = #[attr] break ;
|
||||
let _ = #[attr] continue ;
|
||||
let _ = #[attr] return;
|
||||
let _ = #[attr] foo!();
|
||||
let _ = #[attr] foo!(# ! [attr]);
|
||||
let _ = #[attr] foo![];
|
||||
let _ = #[attr] foo![# ! [attr]];
|
||||
let _ = #[attr] foo! { };
|
||||
let _ = #[attr] foo! { # ! [attr] };
|
||||
let _ = #[attr] Foo{#![attr] bar: baz,};
|
||||
let _ = #[attr] Foo{#![attr] ..foo};
|
||||
let _ = #[attr] Foo{#![attr] bar: baz, ..foo};
|
||||
let _ = #[attr] (#![attr] 0);
|
||||
|
||||
{
|
||||
#[attr]
|
||||
let _ = 0;
|
||||
|
||||
#[attr]
|
||||
0;
|
||||
|
||||
#[attr]
|
||||
foo!();
|
||||
|
||||
#[attr]
|
||||
foo! { }
|
||||
|
||||
#[attr]
|
||||
foo![];
|
||||
}
|
||||
|
||||
{
|
||||
#[attr]
|
||||
let _ = 0;
|
||||
}
|
||||
{
|
||||
|
||||
#[attr]
|
||||
0
|
||||
}
|
||||
{
|
||||
|
||||
#[attr]
|
||||
{
|
||||
#![attr]
|
||||
}
|
||||
}
|
||||
{
|
||||
|
||||
#[attr]
|
||||
foo!()
|
||||
}
|
||||
{
|
||||
|
||||
#[attr]
|
||||
foo![]
|
||||
}
|
||||
{
|
||||
|
||||
#[attr]
|
||||
foo! { }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,311 +0,0 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(unused_imports)]
|
||||
// ignore-cross-compile
|
||||
|
||||
#![feature(rustc_private)]
|
||||
|
||||
extern crate syntax;
|
||||
extern crate syntax_expand;
|
||||
extern crate rustc_parse;
|
||||
extern crate rustc_errors;
|
||||
|
||||
use rustc_errors::PResult;
|
||||
use rustc_parse::parser::attr::*;
|
||||
use rustc_parse::new_parser_from_source_str;
|
||||
use rustc_parse::parser::Parser;
|
||||
use syntax::ast::*;
|
||||
use syntax::attr::*;
|
||||
use syntax::ast;
|
||||
use syntax::sess::ParseSess;
|
||||
use syntax::source_map::{FilePathMapping, FileName};
|
||||
use syntax::ptr::P;
|
||||
use syntax::print::pprust;
|
||||
use syntax::token;
|
||||
use std::fmt;
|
||||
|
||||
// Copied out of syntax::util::parser_testing
|
||||
|
||||
pub fn string_to_parser<'a>(ps: &'a ParseSess, source_str: String) -> Parser<'a> {
|
||||
new_parser_from_source_str(ps, FileName::Custom(source_str.clone()), source_str)
|
||||
}
|
||||
|
||||
fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> PResult<'a, T> where
|
||||
F: FnOnce(&mut Parser<'a>) -> PResult<'a, T>,
|
||||
{
|
||||
let mut p = string_to_parser(&ps, s);
|
||||
let x = f(&mut p);
|
||||
|
||||
if ps.span_diagnostic.has_errors() || p.token != token::Eof {
|
||||
if let Err(mut e) = x {
|
||||
e.cancel();
|
||||
}
|
||||
return Err(p.fatal("parse error"));
|
||||
}
|
||||
|
||||
x
|
||||
}
|
||||
|
||||
fn expr<'a>(s: &str, ps: &'a ParseSess) -> PResult<'a, P<ast::Expr>> {
|
||||
with_error_checking_parse(s.to_string(), ps, |p| {
|
||||
p.parse_expr()
|
||||
})
|
||||
}
|
||||
|
||||
fn stmt<'a>(s: &str, ps: &'a ParseSess) -> PResult<'a, ast::Stmt> {
|
||||
with_error_checking_parse(s.to_string(), ps, |p| {
|
||||
p.parse_stmt().map(|s| s.unwrap())
|
||||
})
|
||||
}
|
||||
|
||||
fn attr<'a>(s: &str, ps: &'a ParseSess) -> PResult<'a, ast::Attribute> {
|
||||
with_error_checking_parse(s.to_string(), ps, |p| {
|
||||
p.parse_attribute(true)
|
||||
})
|
||||
}
|
||||
|
||||
fn str_compare<T, F: Fn(&T) -> String>(e: &str, expected: &[T], actual: &[T], f: F) {
|
||||
let expected: Vec<_> = expected.iter().map(|e| f(e)).collect();
|
||||
let actual: Vec<_> = actual.iter().map(|e| f(e)).collect();
|
||||
|
||||
if expected != actual {
|
||||
panic!("parsed `{}` as {:?}, expected {:?}", e, actual, expected);
|
||||
}
|
||||
}
|
||||
|
||||
fn sess() -> ParseSess {
|
||||
ParseSess::new(FilePathMapping::empty())
|
||||
}
|
||||
|
||||
fn check_expr_attrs(es: &str, expected: &[&str]) {
|
||||
let ps = sess();
|
||||
let e = expr(es, &ps).expect("parse error");
|
||||
let actual = &e.attrs;
|
||||
str_compare(es,
|
||||
&expected.iter().map(|r| attr(r, &ps).unwrap()).collect::<Vec<_>>(),
|
||||
&actual,
|
||||
pprust::attribute_to_string);
|
||||
}
|
||||
|
||||
fn check_stmt_attrs(es: &str, expected: &[&str]) {
|
||||
let ps = sess();
|
||||
let e = stmt(es, &ps).expect("parse error");
|
||||
let actual = e.kind.attrs();
|
||||
str_compare(es,
|
||||
&expected.iter().map(|r| attr(r, &ps).unwrap()).collect::<Vec<_>>(),
|
||||
actual,
|
||||
pprust::attribute_to_string);
|
||||
}
|
||||
|
||||
fn reject_expr_parse(es: &str) {
|
||||
let ps = sess();
|
||||
match expr(es, &ps) {
|
||||
Ok(_) => panic!("parser did not reject `{}`", es),
|
||||
Err(mut e) => e.cancel(),
|
||||
};
|
||||
}
|
||||
|
||||
fn reject_stmt_parse(es: &str) {
|
||||
let ps = sess();
|
||||
match stmt(es, &ps) {
|
||||
Ok(_) => panic!("parser did not reject `{}`", es),
|
||||
Err(mut e) => e.cancel(),
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
syntax::with_default_globals(|| run());
|
||||
}
|
||||
|
||||
fn run() {
|
||||
let both = &["#[attr]", "#![attr]"];
|
||||
let outer = &["#[attr]"];
|
||||
let none = &[];
|
||||
|
||||
check_expr_attrs("#[attr] box 0", outer);
|
||||
reject_expr_parse("box #![attr] 0");
|
||||
|
||||
check_expr_attrs("#[attr] [#![attr]]", both);
|
||||
check_expr_attrs("#[attr] [#![attr] 0]", both);
|
||||
check_expr_attrs("#[attr] [#![attr] 0; 0]", both);
|
||||
check_expr_attrs("#[attr] [#![attr] 0, 0, 0]", both);
|
||||
reject_expr_parse("[#[attr]]");
|
||||
|
||||
check_expr_attrs("#[attr] foo()", outer);
|
||||
check_expr_attrs("#[attr] x.foo()", outer);
|
||||
reject_expr_parse("foo#[attr]()");
|
||||
reject_expr_parse("foo(#![attr])");
|
||||
reject_expr_parse("x.foo(#![attr])");
|
||||
reject_expr_parse("x.#[attr]foo()");
|
||||
reject_expr_parse("x.#![attr]foo()");
|
||||
|
||||
check_expr_attrs("#[attr] (#![attr])", both);
|
||||
check_expr_attrs("#[attr] (#![attr] #[attr] 0,)", both);
|
||||
check_expr_attrs("#[attr] (#![attr] #[attr] 0, 0)", both);
|
||||
|
||||
check_expr_attrs("#[attr] 0 + #[attr] 0", none);
|
||||
check_expr_attrs("#[attr] 0 / #[attr] 0", none);
|
||||
check_expr_attrs("#[attr] 0 & #[attr] 0", none);
|
||||
check_expr_attrs("#[attr] 0 % #[attr] 0", none);
|
||||
check_expr_attrs("#[attr] (0 + 0)", outer);
|
||||
reject_expr_parse("0 + #![attr] 0");
|
||||
|
||||
check_expr_attrs("#[attr] !0", outer);
|
||||
check_expr_attrs("#[attr] -0", outer);
|
||||
reject_expr_parse("!#![attr] 0");
|
||||
reject_expr_parse("-#![attr] 0");
|
||||
|
||||
check_expr_attrs("#[attr] false", outer);
|
||||
check_expr_attrs("#[attr] 0", outer);
|
||||
check_expr_attrs("#[attr] 'c'", outer);
|
||||
|
||||
check_expr_attrs("#[attr] x as Y", none);
|
||||
check_expr_attrs("#[attr] (x as Y)", outer);
|
||||
reject_expr_parse("x #![attr] as Y");
|
||||
|
||||
reject_expr_parse("#[attr] if false {}");
|
||||
reject_expr_parse("if false #[attr] {}");
|
||||
reject_expr_parse("if false {#![attr]}");
|
||||
reject_expr_parse("if false {} #[attr] else {}");
|
||||
reject_expr_parse("if false {} else #[attr] {}");
|
||||
reject_expr_parse("if false {} else {#![attr]}");
|
||||
reject_expr_parse("if false {} else #[attr] if true {}");
|
||||
reject_expr_parse("if false {} else if true #[attr] {}");
|
||||
reject_expr_parse("if false {} else if true {#![attr]}");
|
||||
|
||||
reject_expr_parse("#[attr] if let Some(false) = false {}");
|
||||
reject_expr_parse("if let Some(false) = false #[attr] {}");
|
||||
reject_expr_parse("if let Some(false) = false {#![attr]}");
|
||||
reject_expr_parse("if let Some(false) = false {} #[attr] else {}");
|
||||
reject_expr_parse("if let Some(false) = false {} else #[attr] {}");
|
||||
reject_expr_parse("if let Some(false) = false {} else {#![attr]}");
|
||||
reject_expr_parse("if let Some(false) = false {} else #[attr] if let Some(false) = true {}");
|
||||
reject_expr_parse("if let Some(false) = false {} else if let Some(false) = true #[attr] {}");
|
||||
reject_expr_parse("if let Some(false) = false {} else if let Some(false) = true {#![attr]}");
|
||||
|
||||
check_expr_attrs("#[attr] while true {#![attr]}", both);
|
||||
|
||||
check_expr_attrs("#[attr] while let Some(false) = true {#![attr]}", both);
|
||||
|
||||
check_expr_attrs("#[attr] for x in y {#![attr]}", both);
|
||||
|
||||
check_expr_attrs("#[attr] loop {#![attr]}", both);
|
||||
|
||||
check_expr_attrs("#[attr] match true {#![attr] #[attr] _ => false}", both);
|
||||
|
||||
check_expr_attrs("#[attr] || #[attr] foo", outer);
|
||||
check_expr_attrs("#[attr] move || #[attr] foo", outer);
|
||||
check_expr_attrs("#[attr] || #[attr] { #![attr] foo }", outer);
|
||||
check_expr_attrs("#[attr] move || #[attr] { #![attr] foo }", outer);
|
||||
check_expr_attrs("#[attr] || { #![attr] foo }", outer);
|
||||
check_expr_attrs("#[attr] move || { #![attr] foo }", outer);
|
||||
reject_expr_parse("|| #![attr] foo");
|
||||
reject_expr_parse("move || #![attr] foo");
|
||||
reject_expr_parse("|| #![attr] {foo}");
|
||||
reject_expr_parse("move || #![attr] {foo}");
|
||||
|
||||
check_expr_attrs("#[attr] { #![attr] }", both);
|
||||
check_expr_attrs("#[attr] { #![attr] let _ = (); }", both);
|
||||
check_expr_attrs("#[attr] { #![attr] let _ = (); foo }", both);
|
||||
|
||||
check_expr_attrs("#[attr] x = y", none);
|
||||
check_expr_attrs("#[attr] (x = y)", outer);
|
||||
|
||||
check_expr_attrs("#[attr] x += y", none);
|
||||
check_expr_attrs("#[attr] (x += y)", outer);
|
||||
|
||||
check_expr_attrs("#[attr] foo.bar", outer);
|
||||
check_expr_attrs("(#[attr] foo).bar", none);
|
||||
|
||||
check_expr_attrs("#[attr] foo.0", outer);
|
||||
check_expr_attrs("(#[attr] foo).0", none);
|
||||
|
||||
check_expr_attrs("#[attr] foo[bar]", outer);
|
||||
check_expr_attrs("(#[attr] foo)[bar]", none);
|
||||
|
||||
check_expr_attrs("#[attr] 0..#[attr] 0", none);
|
||||
check_expr_attrs("#[attr] 0..", none);
|
||||
reject_expr_parse("#[attr] ..#[attr] 0");
|
||||
reject_expr_parse("#[attr] ..");
|
||||
|
||||
check_expr_attrs("#[attr] (0..0)", outer);
|
||||
check_expr_attrs("#[attr] (0..)", outer);
|
||||
check_expr_attrs("#[attr] (..0)", outer);
|
||||
check_expr_attrs("#[attr] (..)", outer);
|
||||
|
||||
check_expr_attrs("#[attr] foo::bar::baz", outer);
|
||||
|
||||
check_expr_attrs("#[attr] &0", outer);
|
||||
check_expr_attrs("#[attr] &mut 0", outer);
|
||||
check_expr_attrs("#[attr] & #[attr] 0", outer);
|
||||
check_expr_attrs("#[attr] &mut #[attr] 0", outer);
|
||||
reject_expr_parse("#[attr] &#![attr] 0");
|
||||
reject_expr_parse("#[attr] &mut #![attr] 0");
|
||||
|
||||
check_expr_attrs("#[attr] break", outer);
|
||||
check_expr_attrs("#[attr] continue", outer);
|
||||
check_expr_attrs("#[attr] return", outer);
|
||||
|
||||
check_expr_attrs("#[attr] foo!()", outer);
|
||||
check_expr_attrs("#[attr] foo!(#![attr])", outer);
|
||||
check_expr_attrs("#[attr] foo![]", outer);
|
||||
check_expr_attrs("#[attr] foo![#![attr]]", outer);
|
||||
check_expr_attrs("#[attr] foo!{}", outer);
|
||||
check_expr_attrs("#[attr] foo!{#![attr]}", outer);
|
||||
|
||||
check_expr_attrs("#[attr] Foo { #![attr] bar: baz }", both);
|
||||
check_expr_attrs("#[attr] Foo { #![attr] ..foo }", both);
|
||||
check_expr_attrs("#[attr] Foo { #![attr] bar: baz, ..foo }", both);
|
||||
|
||||
check_expr_attrs("#[attr] (#![attr] 0)", both);
|
||||
|
||||
// Look at statements in their natural habitat...
|
||||
check_expr_attrs("{
|
||||
#[attr] let _ = 0;
|
||||
#[attr] 0;
|
||||
#[attr] foo!();
|
||||
#[attr] foo!{}
|
||||
#[attr] foo![];
|
||||
}", none);
|
||||
|
||||
check_stmt_attrs("#[attr] let _ = 0", outer);
|
||||
check_stmt_attrs("#[attr] 0", outer);
|
||||
check_stmt_attrs("#[attr] {#![attr]}", both);
|
||||
check_stmt_attrs("#[attr] foo!()", outer);
|
||||
check_stmt_attrs("#[attr] foo![]", outer);
|
||||
check_stmt_attrs("#[attr] foo!{}", outer);
|
||||
|
||||
reject_stmt_parse("#[attr] #![attr] let _ = 0");
|
||||
reject_stmt_parse("#[attr] #![attr] 0");
|
||||
reject_stmt_parse("#[attr] #![attr] foo!()");
|
||||
reject_stmt_parse("#[attr] #![attr] foo![]");
|
||||
reject_stmt_parse("#[attr] #![attr] foo!{}");
|
||||
|
||||
// FIXME: Allow attributes in pattern constexprs?
|
||||
// note: requires parens in patterns to allow disambiguation
|
||||
|
||||
reject_expr_parse("match 0 {
|
||||
0..=#[attr] 10 => ()
|
||||
}");
|
||||
reject_expr_parse("match 0 {
|
||||
0..=#[attr] -10 => ()
|
||||
}");
|
||||
reject_expr_parse("match 0 {
|
||||
0..=-#[attr] 10 => ()
|
||||
}");
|
||||
reject_expr_parse("match 0 {
|
||||
0..=#[attr] FOO => ()
|
||||
}");
|
||||
|
||||
// make sure we don't catch this bug again...
|
||||
reject_expr_parse("{
|
||||
fn foo() {
|
||||
#[attr];
|
||||
}
|
||||
}");
|
||||
reject_expr_parse("{
|
||||
fn foo() {
|
||||
#[attr]
|
||||
}
|
||||
}");
|
||||
}
|
||||
|
|
@ -1,17 +1,25 @@
|
|||
fn main() {}
|
||||
|
||||
fn test_and() {
|
||||
let a = true;
|
||||
let b = false;
|
||||
if a and b {
|
||||
//~^ ERROR expected `{`, found `and`
|
||||
|
||||
let _ = a and b; //~ ERROR `and` is not a logical operator
|
||||
|
||||
if a and b { //~ ERROR `and` is not a logical operator
|
||||
println!("both");
|
||||
}
|
||||
|
||||
let _recovery_witness: () = 0; //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn test_or() {
|
||||
let a = true;
|
||||
let b = false;
|
||||
if a or b {
|
||||
//~^ ERROR expected `{`, found `or`
|
||||
|
||||
let _ = a or b; //~ ERROR `or` is not a logical operator
|
||||
|
||||
if a or b { //~ ERROR `or` is not a logical operator
|
||||
println!("both");
|
||||
}
|
||||
}
|
||||
|
|
@ -19,8 +27,7 @@ fn test_or() {
|
|||
fn test_and_par() {
|
||||
let a = true;
|
||||
let b = false;
|
||||
if (a and b) {
|
||||
//~^ ERROR expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `and`
|
||||
if (a and b) { //~ ERROR `and` is not a logical operator
|
||||
println!("both");
|
||||
}
|
||||
}
|
||||
|
|
@ -28,8 +35,7 @@ fn test_and_par() {
|
|||
fn test_or_par() {
|
||||
let a = true;
|
||||
let b = false;
|
||||
if (a or b) {
|
||||
//~^ ERROR expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `or`
|
||||
if (a or b) { //~ ERROR `or` is not a logical operator
|
||||
println!("both");
|
||||
}
|
||||
}
|
||||
|
|
@ -37,8 +43,7 @@ fn test_or_par() {
|
|||
fn test_while_and() {
|
||||
let a = true;
|
||||
let b = false;
|
||||
while a and b {
|
||||
//~^ ERROR expected one of `!`, `.`, `::`, `?`, `{`, or an operator, found `and`
|
||||
while a and b { //~ ERROR `and` is not a logical operator
|
||||
println!("both");
|
||||
}
|
||||
}
|
||||
|
|
@ -46,11 +51,7 @@ fn test_while_and() {
|
|||
fn test_while_or() {
|
||||
let a = true;
|
||||
let b = false;
|
||||
while a or b {
|
||||
//~^ ERROR expected one of `!`, `.`, `::`, `?`, `{`, or an operator, found `or`
|
||||
while a or b { //~ ERROR `or` is not a logical operator
|
||||
println!("both");
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,58 +1,75 @@
|
|||
error: expected `{`, found `and`
|
||||
--> $DIR/issue-54109-and_instead_of_ampersands.rs:4:10
|
||||
error: `and` is not a logical operator
|
||||
--> $DIR/issue-54109-and_instead_of_ampersands.rs:7:15
|
||||
|
|
||||
LL | let _ = a and b;
|
||||
| ^^^ help: use `&&` to perform logical conjunction
|
||||
|
|
||||
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
|
||||
|
||||
error: `and` is not a logical operator
|
||||
--> $DIR/issue-54109-and_instead_of_ampersands.rs:9:10
|
||||
|
|
||||
LL | if a and b {
|
||||
| -- ^^^
|
||||
| | |
|
||||
| | expected `{`
|
||||
| | help: use `&&` instead of `and` for the boolean operator
|
||||
| this `if` statement has a condition, but no block
|
||||
| ^^^ help: use `&&` to perform logical conjunction
|
||||
|
|
||||
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
|
||||
|
||||
error: expected `{`, found `or`
|
||||
--> $DIR/issue-54109-and_instead_of_ampersands.rs:13:10
|
||||
error: `or` is not a logical operator
|
||||
--> $DIR/issue-54109-and_instead_of_ampersands.rs:20:15
|
||||
|
|
||||
LL | let _ = a or b;
|
||||
| ^^ help: use `||` to perform logical disjunction
|
||||
|
|
||||
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
|
||||
|
||||
error: `or` is not a logical operator
|
||||
--> $DIR/issue-54109-and_instead_of_ampersands.rs:22:10
|
||||
|
|
||||
LL | if a or b {
|
||||
| -- ^^
|
||||
| | |
|
||||
| | expected `{`
|
||||
| | help: use `||` instead of `or` for the boolean operator
|
||||
| this `if` statement has a condition, but no block
|
||||
| ^^ help: use `||` to perform logical disjunction
|
||||
|
|
||||
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
|
||||
|
||||
error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `and`
|
||||
--> $DIR/issue-54109-and_instead_of_ampersands.rs:22:11
|
||||
error: `and` is not a logical operator
|
||||
--> $DIR/issue-54109-and_instead_of_ampersands.rs:30:11
|
||||
|
|
||||
LL | if (a and b) {
|
||||
| ^^^
|
||||
| |
|
||||
| expected one of 8 possible tokens
|
||||
| help: use `&&` instead of `and` for the boolean operator
|
||||
| ^^^ help: use `&&` to perform logical conjunction
|
||||
|
|
||||
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
|
||||
|
||||
error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `or`
|
||||
--> $DIR/issue-54109-and_instead_of_ampersands.rs:31:11
|
||||
error: `or` is not a logical operator
|
||||
--> $DIR/issue-54109-and_instead_of_ampersands.rs:38:11
|
||||
|
|
||||
LL | if (a or b) {
|
||||
| ^^
|
||||
| |
|
||||
| expected one of 8 possible tokens
|
||||
| help: use `||` instead of `or` for the boolean operator
|
||||
| ^^ help: use `||` to perform logical disjunction
|
||||
|
|
||||
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
|
||||
|
||||
error: expected one of `!`, `.`, `::`, `?`, `{`, or an operator, found `and`
|
||||
--> $DIR/issue-54109-and_instead_of_ampersands.rs:40:13
|
||||
error: `and` is not a logical operator
|
||||
--> $DIR/issue-54109-and_instead_of_ampersands.rs:46:13
|
||||
|
|
||||
LL | while a and b {
|
||||
| ^^^
|
||||
| |
|
||||
| expected one of `!`, `.`, `::`, `?`, `{`, or an operator
|
||||
| help: use `&&` instead of `and` for the boolean operator
|
||||
| ^^^ help: use `&&` to perform logical conjunction
|
||||
|
|
||||
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
|
||||
|
||||
error: expected one of `!`, `.`, `::`, `?`, `{`, or an operator, found `or`
|
||||
--> $DIR/issue-54109-and_instead_of_ampersands.rs:49:13
|
||||
error: `or` is not a logical operator
|
||||
--> $DIR/issue-54109-and_instead_of_ampersands.rs:54:13
|
||||
|
|
||||
LL | while a or b {
|
||||
| ^^
|
||||
| |
|
||||
| expected one of `!`, `.`, `::`, `?`, `{`, or an operator
|
||||
| help: use `||` instead of `or` for the boolean operator
|
||||
| ^^ help: use `||` to perform logical disjunction
|
||||
|
|
||||
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-54109-and_instead_of_ampersands.rs:13:33
|
||||
|
|
||||
LL | let _recovery_witness: () = 0;
|
||||
| -- ^ expected `()`, found integer
|
||||
| |
|
||||
| expected due to this
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
|
|
|||
2
src/test/ui/parser/attr-stmt-expr-attr-bad-2.rs
Normal file
2
src/test/ui/parser/attr-stmt-expr-attr-bad-2.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
|
||||
//~^ ERROR unexpected token: `#`
|
||||
8
src/test/ui/parser/attr-stmt-expr-attr-bad-2.stderr
Normal file
8
src/test/ui/parser/attr-stmt-expr-attr-bad-2.stderr
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
error: unexpected token: `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad-2.rs:1:34
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
2
src/test/ui/parser/attr-stmt-expr-attr-bad-3.rs
Normal file
2
src/test/ui/parser/attr-stmt-expr-attr-bad-3.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
|
||||
//~^ ERROR unexpected token: `#`
|
||||
8
src/test/ui/parser/attr-stmt-expr-attr-bad-3.stderr
Normal file
8
src/test/ui/parser/attr-stmt-expr-attr-bad-3.stderr
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
error: unexpected token: `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad-3.rs:1:34
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
107
src/test/ui/parser/attr-stmt-expr-attr-bad.rs
Normal file
107
src/test/ui/parser/attr-stmt-expr-attr-bad.rs
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
fn main() {}
|
||||
|
||||
#[cfg(FALSE)] fn e() { let _ = box #![attr] 0; }
|
||||
//~^ ERROR an inner attribute is not permitted in this context
|
||||
#[cfg(FALSE)] fn e() { let _ = [#[attr]]; }
|
||||
//~^ ERROR expected expression, found `]`
|
||||
#[cfg(FALSE)] fn e() { let _ = foo#[attr](); }
|
||||
//~^ ERROR expected one of
|
||||
#[cfg(FALSE)] fn e() { let _ = foo(#![attr]); }
|
||||
//~^ ERROR an inner attribute is not permitted in this context
|
||||
//~| ERROR expected expression, found `)`
|
||||
#[cfg(FALSE)] fn e() { let _ = x.foo(#![attr]); }
|
||||
//~^ ERROR an inner attribute is not permitted in this context
|
||||
//~| ERROR expected expression, found `)`
|
||||
#[cfg(FALSE)] fn e() { let _ = 0 + #![attr] 0; }
|
||||
//~^ ERROR an inner attribute is not permitted in this context
|
||||
#[cfg(FALSE)] fn e() { let _ = !#![attr] 0; }
|
||||
//~^ ERROR an inner attribute is not permitted in this context
|
||||
#[cfg(FALSE)] fn e() { let _ = -#![attr] 0; }
|
||||
//~^ ERROR an inner attribute is not permitted in this context
|
||||
#[cfg(FALSE)] fn e() { let _ = x #![attr] as Y; }
|
||||
//~^ ERROR expected one of
|
||||
#[cfg(FALSE)] fn e() { let _ = || #![attr] foo; }
|
||||
//~^ 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] {foo}; }
|
||||
//~^ 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; }
|
||||
//~^ ERROR expected expression, found `..`
|
||||
#[cfg(FALSE)] fn e() { let _ = #[attr] ..; }
|
||||
//~^ ERROR expected expression, found `..`
|
||||
#[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; }
|
||||
//~^ ERROR an inner attribute is not permitted in this context
|
||||
#[cfg(FALSE)] fn e() { let _ = #[attr] if 0 {}; }
|
||||
//~^ ERROR attributes are not yet allowed on `if` expressions
|
||||
#[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; }
|
||||
//~^ ERROR expected `{`, found `#`
|
||||
#[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; }
|
||||
//~^ ERROR an inner attribute is not permitted in this context
|
||||
#[cfg(FALSE)] fn e() { let _ = if 0 {} #[attr] else {}; }
|
||||
//~^ ERROR expected one of
|
||||
#[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; }
|
||||
//~^ ERROR expected `{`, found `#`
|
||||
#[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; }
|
||||
//~^ ERROR an inner attribute is not permitted in this context
|
||||
#[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
|
||||
//~^ ERROR attributes are not yet allowed on `if` expressions
|
||||
//~| ERROR expected `{`, found `#`
|
||||
#[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
|
||||
//~^ ERROR expected `{`, found `#`
|
||||
#[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; }
|
||||
//~^ ERROR an inner attribute is not permitted in this context
|
||||
#[cfg(FALSE)] fn e() { let _ = #[attr] if let _ = 0 {}; }
|
||||
//~^ ERROR attributes are not yet allowed on `if` expressions
|
||||
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; }
|
||||
//~^ ERROR expected `{`, found `#`
|
||||
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; }
|
||||
//~^ ERROR an inner attribute is not permitted in this context
|
||||
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; }
|
||||
//~^ ERROR expected one of
|
||||
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; }
|
||||
//~^ ERROR expected `{`, found `#`
|
||||
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; }
|
||||
//~^ ERROR an inner attribute is not permitted in this context
|
||||
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
|
||||
//~^ ERROR attributes are not yet allowed on `if` expressions
|
||||
//~| ERROR expected `{`, found `#`
|
||||
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; }
|
||||
//~^ ERROR expected `{`, found `#`
|
||||
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; }
|
||||
//~^ ERROR an inner attribute is not permitted in this context
|
||||
|
||||
#[cfg(FALSE)] fn s() { #[attr] #![attr] let _ = 0; }
|
||||
//~^ ERROR an inner attribute is not permitted following an outer attribute
|
||||
#[cfg(FALSE)] fn s() { #[attr] #![attr] 0; }
|
||||
//~^ ERROR an inner attribute is not permitted following an outer attribute
|
||||
#[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); }
|
||||
//~^ ERROR an inner attribute is not permitted following an outer attribute
|
||||
#[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; }
|
||||
//~^ ERROR an inner attribute is not permitted following an outer attribute
|
||||
#[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; }
|
||||
//~^ ERROR an inner attribute is not permitted following an outer attribute
|
||||
|
||||
// FIXME: Allow attributes in pattern constexprs?
|
||||
// note: requires parens in patterns to allow disambiguation
|
||||
|
||||
#[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
|
||||
//~^ ERROR `X..=` range patterns are not supported
|
||||
//~| ERROR expected one of `=>`, `if`, or `|`, found `#`
|
||||
#[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
|
||||
//~^ ERROR `X..=` range patterns are not supported
|
||||
//~| ERROR expected one of `=>`, `if`, or `|`, found `#`
|
||||
#[cfg(FALSE)] fn e() { match 0 { 0..=-#[attr] 10 => () } }
|
||||
//~^ ERROR unexpected token: `#`
|
||||
#[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
|
||||
//~^ ERROR `X..=` range patterns are not supported
|
||||
//~| ERROR expected one of `=>`, `if`, or `|`, found `#`
|
||||
|
||||
// make sure we don't catch this bug again...
|
||||
#[cfg(FALSE)] fn e() { { fn foo() { #[attr]; } } }
|
||||
//~^ ERROR expected statement after outer attribute
|
||||
#[cfg(FALSE)] fn e() { { fn foo() { #[attr] } } }
|
||||
390
src/test/ui/parser/attr-stmt-expr-attr-bad.stderr
Normal file
390
src/test/ui/parser/attr-stmt-expr-attr-bad.stderr
Normal file
|
|
@ -0,0 +1,390 @@
|
|||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:3:36
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = box #![attr] 0; }
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: expected expression, found `]`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:5:40
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = [#[attr]]; }
|
||||
| ^ expected expression
|
||||
|
||||
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:7:35
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = foo#[attr](); }
|
||||
| ^ expected one of 7 possible tokens
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:9:36
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); }
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: expected expression, found `)`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:9:44
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); }
|
||||
| ^ expected expression
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:12:38
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = x.foo(#![attr]); }
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: expected expression, found `)`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:12:46
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = x.foo(#![attr]); }
|
||||
| ^ expected expression
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:15:36
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = 0 + #![attr] 0; }
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:17:33
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = !#![attr] 0; }
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:19:33
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = -#![attr] 0; }
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:21:34
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = x #![attr] as Y; }
|
||||
| ^ expected one of 7 possible tokens
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:23:35
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = || #![attr] foo; }
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:25:40
|
||||
|
|
||||
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. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:27:35
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = || #![attr] {foo}; }
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:29:40
|
||||
|
|
||||
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. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: expected expression, found `..`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:31:40
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = #[attr] ..#[attr] 0; }
|
||||
| ^^ expected expression
|
||||
|
||||
error: expected expression, found `..`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:33: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:35:41
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &#![attr] 0; }
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:37:45
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; }
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: attributes are not yet allowed on `if` expressions
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:39:32
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = #[attr] if 0 {}; }
|
||||
| ^^^^^^^
|
||||
|
||||
error: expected `{`, found `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:41:37
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; }
|
||||
| -- ^ --- help: try placing this code inside a block: `{ {}; }`
|
||||
| | |
|
||||
| | expected `{`
|
||||
| this `if` statement has a condition, but no block
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:43:38
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; }
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:45:40
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} #[attr] else {}; }
|
||||
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
|
||||
|
||||
error: expected `{`, found `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:47:45
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; }
|
||||
| ^ --- help: try placing this code inside a block: `{ {}; }`
|
||||
| |
|
||||
| expected `{`
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:49:46
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; }
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: attributes are not yet allowed on `if` expressions
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:51:45
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
|
||||
| ^^^^^^^
|
||||
|
||||
error: expected `{`, found `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:51:45
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
|
||||
| ^ -------- help: try placing this code inside a block: `{ if 0 {}; }`
|
||||
| |
|
||||
| expected `{`
|
||||
|
||||
error: expected `{`, found `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:54:50
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
|
||||
| -- ^ --- help: try placing this code inside a block: `{ {}; }`
|
||||
| | |
|
||||
| | expected `{`
|
||||
| this `if` statement has a condition, but no block
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:56:51
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; }
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: attributes are not yet allowed on `if` expressions
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:58:32
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = #[attr] if let _ = 0 {}; }
|
||||
| ^^^^^^^
|
||||
|
||||
error: expected `{`, found `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:60:45
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; }
|
||||
| -- ^ --- help: try placing this code inside a block: `{ {}; }`
|
||||
| | |
|
||||
| | expected `{`
|
||||
| this `if` statement has a condition, but no block
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:62:46
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; }
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:64:48
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; }
|
||||
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
|
||||
|
||||
error: expected `{`, found `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:66:53
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; }
|
||||
| ^ --- help: try placing this code inside a block: `{ {}; }`
|
||||
| |
|
||||
| expected `{`
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:68:54
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; }
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: attributes are not yet allowed on `if` expressions
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:70:53
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
|
||||
| ^^^^^^^
|
||||
|
||||
error: expected `{`, found `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:70:53
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
|
||||
| ^ ---------------- help: try placing this code inside a block: `{ if let _ = 0 {}; }`
|
||||
| |
|
||||
| expected `{`
|
||||
|
||||
error: expected `{`, found `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:73:66
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; }
|
||||
| -- ^ --- help: try placing this code inside a block: `{ {}; }`
|
||||
| | |
|
||||
| | expected `{`
|
||||
| this `if` statement has a condition, but no block
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:75:67
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; }
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: an inner attribute is not permitted following an outer attribute
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:78:32
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] let _ = 0; }
|
||||
| ------- ^^^^^^^^ not permitted following an outer attibute
|
||||
| |
|
||||
| previous outer attribute
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: an inner attribute is not permitted following an outer attribute
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:80:32
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] 0; }
|
||||
| ------- ^^^^^^^^ not permitted following an outer attibute
|
||||
| |
|
||||
| previous outer attribute
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: an inner attribute is not permitted following an outer attribute
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:82:32
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); }
|
||||
| ------- ^^^^^^^^ not permitted following an outer attibute
|
||||
| |
|
||||
| previous outer attribute
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: an inner attribute is not permitted following an outer attribute
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:84:32
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; }
|
||||
| ------- ^^^^^^^^ not permitted following an outer attibute
|
||||
| |
|
||||
| previous outer attribute
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: an inner attribute is not permitted following an outer attribute
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:86:32
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; }
|
||||
| ------- ^^^^^^^^ not permitted following an outer attibute
|
||||
| |
|
||||
| previous outer attribute
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: `X..=` range patterns are not supported
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:92:34
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
|
||||
| ^^^^ help: try using the maximum value for the type: `0..=MAX`
|
||||
|
||||
error: expected one of `=>`, `if`, or `|`, found `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:92:38
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
|
||||
| ^ expected one of `=>`, `if`, or `|`
|
||||
|
||||
error: `X..=` range patterns are not supported
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:95:34
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
|
||||
| ^^^^ help: try using the maximum value for the type: `0..=MAX`
|
||||
|
||||
error: expected one of `=>`, `if`, or `|`, found `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:95:38
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
|
||||
| ^ expected one of `=>`, `if`, or `|`
|
||||
|
||||
error: unexpected token: `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:98:39
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { match 0 { 0..=-#[attr] 10 => () } }
|
||||
| ^
|
||||
|
||||
error: `X..=` range patterns are not supported
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:100:34
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
|
||||
| ^^^^ help: try using the maximum value for the type: `0..=MAX`
|
||||
|
||||
error: expected one of `=>`, `if`, or `|`, found `#`
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:100:38
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
|
||||
| ^ expected one of `=>`, `if`, or `|`
|
||||
|
||||
error: expected statement after outer attribute
|
||||
--> $DIR/attr-stmt-expr-attr-bad.rs:105:44
|
||||
|
|
||||
LL | #[cfg(FALSE)] fn e() { { fn foo() { #[attr]; } } }
|
||||
| ^
|
||||
|
||||
error: aborting due to 52 previous errors
|
||||
|
||||
|
|
@ -1,5 +1,10 @@
|
|||
#![feature(try_blocks)]
|
||||
|
||||
fn main() {
|
||||
let _: Option<()> = do catch {};
|
||||
//~^ ERROR found removed `do catch` syntax
|
||||
//~^^ HELP following RFC #2388, the new non-placeholder syntax is `try`
|
||||
//~| replace with the new syntax
|
||||
//~| following RFC #2388, the new non-placeholder syntax is `try`
|
||||
|
||||
let _recovery_witness: () = 1; //~ ERROR mismatched types
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,19 @@
|
|||
error: found removed `do catch` syntax
|
||||
--> $DIR/do-catch-suggests-try.rs:2:25
|
||||
--> $DIR/do-catch-suggests-try.rs:4:25
|
||||
|
|
||||
LL | let _: Option<()> = do catch {};
|
||||
| ^^
|
||||
| ^^^^^^^^ help: replace with the new syntax: `try`
|
||||
|
|
||||
= help: following RFC #2388, the new non-placeholder syntax is `try`
|
||||
= note: following RFC #2388, the new non-placeholder syntax is `try`
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/do-catch-suggests-try.rs:9:33
|
||||
|
|
||||
LL | let _recovery_witness: () = 1;
|
||||
| -- ^ expected `()`, found integer
|
||||
| |
|
||||
| expected due to this
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
|
|
|||
21
src/test/ui/parser/issue-65257-invalid-var-decl-recovery.rs
Normal file
21
src/test/ui/parser/issue-65257-invalid-var-decl-recovery.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
fn main() {
|
||||
auto n = 0;//~ ERROR invalid variable declaration
|
||||
//~^ HELP write `let` instead of `auto` to introduce a new variable
|
||||
auto m;//~ ERROR invalid variable declaration
|
||||
//~^ HELP write `let` instead of `auto` to introduce a new variable
|
||||
m = 0;
|
||||
|
||||
var n = 0;//~ ERROR invalid variable declaration
|
||||
//~^ HELP write `let` instead of `var` to introduce a new variable
|
||||
var m;//~ ERROR invalid variable declaration
|
||||
//~^ HELP write `let` instead of `var` to introduce a new variable
|
||||
m = 0;
|
||||
|
||||
mut n = 0;//~ ERROR invalid variable declaration
|
||||
//~^ HELP missing keyword
|
||||
mut var;//~ ERROR invalid variable declaration
|
||||
//~^ HELP missing keyword
|
||||
var = 0;
|
||||
|
||||
let _recovery_witness: () = 0; //~ ERROR mismatched types
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
error: invalid variable declaration
|
||||
--> $DIR/issue-65257-invalid-var-decl-recovery.rs:2:5
|
||||
|
|
||||
LL | auto n = 0;
|
||||
| ^^^^
|
||||
|
|
||||
help: write `let` instead of `auto` to introduce a new variable
|
||||
|
|
||||
LL | let n = 0;
|
||||
| ^^^
|
||||
|
||||
error: invalid variable declaration
|
||||
--> $DIR/issue-65257-invalid-var-decl-recovery.rs:4:5
|
||||
|
|
||||
LL | auto m;
|
||||
| ^^^^
|
||||
|
|
||||
help: write `let` instead of `auto` to introduce a new variable
|
||||
|
|
||||
LL | let m;
|
||||
| ^^^
|
||||
|
||||
error: invalid variable declaration
|
||||
--> $DIR/issue-65257-invalid-var-decl-recovery.rs:8:5
|
||||
|
|
||||
LL | var n = 0;
|
||||
| ^^^
|
||||
|
|
||||
help: write `let` instead of `var` to introduce a new variable
|
||||
|
|
||||
LL | let n = 0;
|
||||
| ^^^
|
||||
|
||||
error: invalid variable declaration
|
||||
--> $DIR/issue-65257-invalid-var-decl-recovery.rs:10:5
|
||||
|
|
||||
LL | var m;
|
||||
| ^^^
|
||||
|
|
||||
help: write `let` instead of `var` to introduce a new variable
|
||||
|
|
||||
LL | let m;
|
||||
| ^^^
|
||||
|
||||
error: invalid variable declaration
|
||||
--> $DIR/issue-65257-invalid-var-decl-recovery.rs:14:5
|
||||
|
|
||||
LL | mut n = 0;
|
||||
| ^^^ help: missing keyword: `let mut`
|
||||
|
||||
error: invalid variable declaration
|
||||
--> $DIR/issue-65257-invalid-var-decl-recovery.rs:16:5
|
||||
|
|
||||
LL | mut var;
|
||||
| ^^^ help: missing keyword: `let mut`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-65257-invalid-var-decl-recovery.rs:20:33
|
||||
|
|
||||
LL | let _recovery_witness: () = 0;
|
||||
| -- ^ expected `()`, found integer
|
||||
| |
|
||||
| expected due to this
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
5
src/test/ui/parser/recover-labeled-non-block-expr.rs
Normal file
5
src/test/ui/parser/recover-labeled-non-block-expr.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
fn main() {
|
||||
'label: 1 + 1; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
|
||||
|
||||
let _recovery_witness: () = 0; //~ ERROR mismatched types
|
||||
}
|
||||
17
src/test/ui/parser/recover-labeled-non-block-expr.stderr
Normal file
17
src/test/ui/parser/recover-labeled-non-block-expr.stderr
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
error: expected `while`, `for`, `loop` or `{` after a label
|
||||
--> $DIR/recover-labeled-non-block-expr.rs:2:13
|
||||
|
|
||||
LL | 'label: 1 + 1;
|
||||
| ^ expected `while`, `for`, `loop` or `{` after a label
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/recover-labeled-non-block-expr.rs:4:33
|
||||
|
|
||||
LL | let _recovery_witness: () = 0;
|
||||
| -- ^ expected `()`, found integer
|
||||
| |
|
||||
| expected due to this
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
9
src/test/ui/parser/recovery-attr-on-if.rs
Normal file
9
src/test/ui/parser/recovery-attr-on-if.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
fn main() {
|
||||
#[attr] if true {};
|
||||
//~^ ERROR cannot find attribute
|
||||
//~| ERROR attributes are not yet allowed on `if` expressions
|
||||
#[attr] if true {};
|
||||
//~^ ERROR cannot find attribute
|
||||
//~| ERROR attributes are not yet allowed on `if` expressions
|
||||
let _recovery_witness: () = 0; //~ ERROR mismatched types
|
||||
}
|
||||
35
src/test/ui/parser/recovery-attr-on-if.stderr
Normal file
35
src/test/ui/parser/recovery-attr-on-if.stderr
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
error: attributes are not yet allowed on `if` expressions
|
||||
--> $DIR/recovery-attr-on-if.rs:2:5
|
||||
|
|
||||
LL | #[attr] if true {};
|
||||
| ^^^^^^^
|
||||
|
||||
error: attributes are not yet allowed on `if` expressions
|
||||
--> $DIR/recovery-attr-on-if.rs:5:5
|
||||
|
|
||||
LL | #[attr] if true {};
|
||||
| ^^^^^^^
|
||||
|
||||
error: cannot find attribute `attr` in this scope
|
||||
--> $DIR/recovery-attr-on-if.rs:5:7
|
||||
|
|
||||
LL | #[attr] if true {};
|
||||
| ^^^^
|
||||
|
||||
error: cannot find attribute `attr` in this scope
|
||||
--> $DIR/recovery-attr-on-if.rs:2:7
|
||||
|
|
||||
LL | #[attr] if true {};
|
||||
| ^^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/recovery-attr-on-if.rs:8:33
|
||||
|
|
||||
LL | let _recovery_witness: () = 0;
|
||||
| -- ^ expected `()`, found integer
|
||||
| |
|
||||
| expected due to this
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
22
src/test/ui/parser/stmt_expr_attrs_placement.rs
Normal file
22
src/test/ui/parser/stmt_expr_attrs_placement.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#![feature(stmt_expr_attributes)]
|
||||
|
||||
// Test that various placements of the inner attribute are parsed correctly,
|
||||
// or not.
|
||||
|
||||
fn main() {
|
||||
let a = #![allow(warnings)] (1, 2);
|
||||
//~^ ERROR an inner attribute is not permitted in this context
|
||||
|
||||
let b = (#![allow(warnings)] 1, 2);
|
||||
|
||||
let c = {
|
||||
#![allow(warnings)]
|
||||
(#![allow(warnings)] 1, 2)
|
||||
};
|
||||
|
||||
let d = {
|
||||
#![allow(warnings)]
|
||||
let e = (#![allow(warnings)] 1, 2);
|
||||
e
|
||||
};
|
||||
}
|
||||
10
src/test/ui/parser/stmt_expr_attrs_placement.stderr
Normal file
10
src/test/ui/parser/stmt_expr_attrs_placement.stderr
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/stmt_expr_attrs_placement.rs:7:13
|
||||
|
|
||||
LL | let a = #![allow(warnings)] (1, 2);
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue