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:
bors 2019-12-21 11:05:03 +00:00
commit c64eecf4d0
47 changed files with 1771 additions and 1194 deletions

View file

@ -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>,

View file

@ -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 }
}

View file

@ -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()))
})
}

View file

@ -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,
}

View file

@ -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 {

View file

@ -2,6 +2,7 @@
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(slice_patterns)]
use syntax::ast;
use syntax::print::pprust;

View file

@ -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())
}
}

View file

@ -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

View file

@ -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 {

View file

@ -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 {

View file

@ -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()
}

View file

@ -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,

View file

@ -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 }
}
}

View file

@ -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 {

View file

@ -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
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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(),
})
}

View file

@ -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,

View file

@ -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),
};

View file

@ -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![

View file

@ -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(),
}))
}

View file

@ -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(),
}))
}

View file

@ -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,

View file

@ -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,

View file

@ -773,6 +773,7 @@ symbols! {
usize,
v1,
val,
var,
vec,
Vec,
vis,

View 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! { }
}
}

View file

@ -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]
}
}");
}

View file

@ -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() {
}

View file

@ -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`.

View file

@ -0,0 +1,2 @@
#[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
//~^ ERROR unexpected token: `#`

View 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

View file

@ -0,0 +1,2 @@
#[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
//~^ ERROR unexpected token: `#`

View 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

View 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] } } }

View 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

View file

@ -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
}

View file

@ -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`.

View 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
}

View file

@ -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`.

View 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
}

View 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`.

View 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
}

View 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`.

View 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
};
}

View 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