diff options
59 files changed, 926 insertions, 401 deletions
diff --git a/src/librustc_ast/token.rs b/src/librustc_ast/token.rs index b67b7d346f7..3fc6444168e 100644 --- a/src/librustc_ast/token.rs +++ b/src/librustc_ast/token.rs @@ -535,6 +535,16 @@ impl Token { false } + // Is the token an interpolated block (`$b:block`)? + pub fn is_whole_block(&self) -> bool { + if let Interpolated(ref nt) = self.kind { + if let NtBlock(..) = **nt { + return true; + } + } + false + } + /// Returns `true` if the token is either the `mut` or `const` keyword. pub fn is_mutability(&self) -> bool { self.is_keyword(kw::Mut) || self.is_keyword(kw::Const) diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 10d524776a1..fe75062ee50 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -2,6 +2,7 @@ #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] +#![feature(bindings_after_at)] use rustc_ast::ast; use rustc_ast::token::{self, Nonterminal}; diff --git a/src/librustc_parse/parser/attr.rs b/src/librustc_parse/parser/attr.rs index bdd78e671a8..b56dd30739d 100644 --- a/src/librustc_parse/parser/attr.rs +++ b/src/librustc_parse/parser/attr.rs @@ -1,4 +1,4 @@ -use super::{Parser, PathStyle, TokenType}; +use super::{Parser, PathStyle}; use rustc_ast::ast; use rustc_ast::attr; use rustc_ast::token::{self, Nonterminal}; @@ -10,14 +10,20 @@ use rustc_span::{Span, Symbol}; use log::debug; #[derive(Debug)] -enum InnerAttributeParsePolicy<'a> { +pub(super) enum InnerAttrPolicy<'a> { Permitted, - NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> }, + Forbidden { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> }, } const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \ permitted in this context"; +pub(super) const DEFAULT_INNER_ATTR_FORBIDDEN: InnerAttrPolicy<'_> = InnerAttrPolicy::Forbidden { + reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG, + saw_doc_comment: false, + prev_attr_sp: None, +}; + impl<'a> Parser<'a> { /// Parses attributes that appear before an item. pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> { @@ -25,48 +31,44 @@ impl<'a> Parser<'a> { let mut just_parsed_doc_comment = false; loop { debug!("parse_outer_attributes: self.token={:?}", self.token); - match self.token.kind { - token::Pound => { - let inner_error_reason = if just_parsed_doc_comment { - "an inner attribute is not permitted following an outer doc comment" - } else if !attrs.is_empty() { - "an inner attribute is not permitted following an outer attribute" - } else { - DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG - }; - let inner_parse_policy = InnerAttributeParsePolicy::NotPermitted { - reason: inner_error_reason, - saw_doc_comment: just_parsed_doc_comment, - prev_attr_sp: attrs.last().map(|a| a.span), - }; - let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?; - attrs.push(attr); - just_parsed_doc_comment = false; - } - token::DocComment(s) => { - let attr = self.mk_doc_comment(s); - if attr.style != ast::AttrStyle::Outer { - let span = self.token.span; - let mut err = self.struct_span_err(span, "expected outer doc comment"); - err.note( + if self.check(&token::Pound) { + let inner_error_reason = if just_parsed_doc_comment { + "an inner attribute is not permitted following an outer doc comment" + } else if !attrs.is_empty() { + "an inner attribute is not permitted following an outer attribute" + } else { + DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG + }; + let inner_parse_policy = InnerAttrPolicy::Forbidden { + reason: inner_error_reason, + saw_doc_comment: just_parsed_doc_comment, + prev_attr_sp: attrs.last().map(|a| a.span), + }; + let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?; + attrs.push(attr); + just_parsed_doc_comment = false; + } else if let token::DocComment(s) = self.token.kind { + let attr = self.mk_doc_comment(s); + if attr.style != ast::AttrStyle::Outer { + self.struct_span_err(self.token.span, "expected outer doc comment") + .note( "inner doc comments like this (starting with \ - `//!` or `/*!`) can only appear before items", - ); - return Err(err); - } - attrs.push(attr); - self.bump(); - just_parsed_doc_comment = true; + `//!` or `/*!`) can only appear before items", + ) + .emit(); } - _ => break, + attrs.push(attr); + self.bump(); + just_parsed_doc_comment = true; + } else { + break; } } Ok(attrs) } fn mk_doc_comment(&self, s: Symbol) -> ast::Attribute { - let style = comments::doc_comment_style(&s.as_str()); - attr::mk_doc_comment(style, s, self.token.span) + attr::mk_doc_comment(comments::doc_comment_style(&s.as_str()), s, self.token.span) } /// Matches `attribute = # ! [ meta_item ]`. @@ -75,96 +77,67 @@ impl<'a> Parser<'a> { /// attribute. pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> { debug!("parse_attribute: permit_inner={:?} self.token={:?}", permit_inner, self.token); - let inner_parse_policy = if permit_inner { - InnerAttributeParsePolicy::Permitted - } else { - InnerAttributeParsePolicy::NotPermitted { - reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG, - saw_doc_comment: false, - prev_attr_sp: None, - } - }; + let inner_parse_policy = + if permit_inner { InnerAttrPolicy::Permitted } else { DEFAULT_INNER_ATTR_FORBIDDEN }; self.parse_attribute_with_inner_parse_policy(inner_parse_policy) } - /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy` + /// The same as `parse_attribute`, except it takes in an `InnerAttrPolicy` /// that prescribes how to handle inner attributes. fn parse_attribute_with_inner_parse_policy( &mut self, - inner_parse_policy: InnerAttributeParsePolicy<'_>, + inner_parse_policy: InnerAttrPolicy<'_>, ) -> PResult<'a, ast::Attribute> { debug!( "parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}", inner_parse_policy, self.token ); - let (span, item, style) = match self.token.kind { - token::Pound => { - let lo = self.token.span; - self.bump(); - - if let InnerAttributeParsePolicy::Permitted = inner_parse_policy { - self.expected_tokens.push(TokenType::Token(token::Not)); - } - - let style = if self.token == token::Not { - self.bump(); - ast::AttrStyle::Inner - } else { - ast::AttrStyle::Outer - }; + let lo = self.token.span; + let (span, item, style) = if self.eat(&token::Pound) { + let style = + if self.eat(&token::Not) { ast::AttrStyle::Inner } else { ast::AttrStyle::Outer }; - self.expect(&token::OpenDelim(token::Bracket))?; - let item = self.parse_attr_item()?; - self.expect(&token::CloseDelim(token::Bracket))?; - let hi = self.prev_token.span; - - let attr_sp = lo.to(hi); - - // Emit error if inner attribute is encountered and not permitted - if style == ast::AttrStyle::Inner { - if let InnerAttributeParsePolicy::NotPermitted { - reason, - saw_doc_comment, - prev_attr_sp, - } = inner_parse_policy - { - let prev_attr_note = if saw_doc_comment { - "previous doc comment" - } else { - "previous outer attribute" - }; - - let mut diagnostic = self.struct_span_err(attr_sp, reason); - - if let Some(prev_attr_sp) = prev_attr_sp { - diagnostic - .span_label(attr_sp, "not permitted following an outer attribute") - .span_label(prev_attr_sp, prev_attr_note); - } - - diagnostic - .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.", - ) - .emit(); - } - } + self.expect(&token::OpenDelim(token::Bracket))?; + let item = self.parse_attr_item()?; + self.expect(&token::CloseDelim(token::Bracket))?; + let attr_sp = lo.to(self.prev_token.span); - (attr_sp, item, style) - } - _ => { - let token_str = pprust::token_to_string(&self.token); - let msg = &format!("expected `#`, found `{}`", token_str); - return Err(self.struct_span_err(self.token.span, msg)); + // Emit error if inner attribute is encountered and forbidden. + if style == ast::AttrStyle::Inner { + self.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy); } + + (attr_sp, item, style) + } else { + let token_str = pprust::token_to_string(&self.token); + let msg = &format!("expected `#`, found `{}`", token_str); + return Err(self.struct_span_err(self.token.span, msg)); }; Ok(attr::mk_attr_from_item(style, item, span)) } + pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy<'_>) { + if let InnerAttrPolicy::Forbidden { reason, saw_doc_comment, prev_attr_sp } = policy { + let prev_attr_note = + if saw_doc_comment { "previous doc comment" } else { "previous outer attribute" }; + + let mut diag = self.struct_span_err(attr_sp, reason); + + if let Some(prev_attr_sp) = prev_attr_sp { + diag.span_label(attr_sp, "not permitted following an outer attribute") + .span_label(prev_attr_sp, prev_attr_note); + } + + diag.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.", + ) + .emit(); + } + } + /// Parses an inner part of an attribute (the path and following tokens). /// The tokens must be either a delimited token stream, or empty token stream, /// or the "legacy" key-value form. @@ -200,28 +173,22 @@ impl<'a> Parser<'a> { crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> { let mut attrs: Vec<ast::Attribute> = vec![]; loop { - match self.token.kind { - token::Pound => { - // Don't even try to parse if it's not an inner attribute. - if !self.look_ahead(1, |t| t == &token::Not) { - break; - } - - let attr = self.parse_attribute(true)?; - assert_eq!(attr.style, ast::AttrStyle::Inner); + // Only try to parse if it is an inner attribute (has `!`). + if self.check(&token::Pound) && self.look_ahead(1, |t| t == &token::Not) { + let attr = self.parse_attribute(true)?; + assert_eq!(attr.style, ast::AttrStyle::Inner); + attrs.push(attr); + } else if let token::DocComment(s) = self.token.kind { + // We need to get the position of this token before we bump. + let attr = self.mk_doc_comment(s); + if attr.style == ast::AttrStyle::Inner { attrs.push(attr); + self.bump(); + } else { + break; } - token::DocComment(s) => { - // We need to get the position of this token before we bump. - let attr = self.mk_doc_comment(s); - if attr.style == ast::AttrStyle::Inner { - attrs.push(attr); - self.bump(); - } else { - break; - } - } - _ => break, + } else { + break; } } Ok(attrs) @@ -232,12 +199,10 @@ impl<'a> Parser<'a> { debug!("checking if {:?} is unusuffixed", lit); if !lit.kind.is_unsuffixed() { - let msg = "suffixed literals are not allowed in attributes"; - self.struct_span_err(lit.span, msg) + self.struct_span_err(lit.span, "suffixed literals are not allowed in attributes") .help( - "instead of using a suffixed literal \ - (`1u8`, `1.0f32`, etc.), use an unsuffixed version \ - (`1`, `1.0`, etc.)", + "instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), \ + use an unsuffixed version (`1`, `1.0`, etc.)", ) .emit(); } diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 16ea2773b20..7f6f90431fc 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -673,10 +673,28 @@ impl<'a> Parser<'a> { /// Parse `& mut? <expr>` or `& raw [ const | mut ] <expr>`. fn parse_borrow_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { self.expect_and()?; + let has_lifetime = self.token.is_lifetime() && self.look_ahead(1, |t| t != &token::Colon); + let lifetime = has_lifetime.then(|| self.expect_lifetime()); // For recovery, see below. let (borrow_kind, mutbl) = self.parse_borrow_modifiers(lo); let expr = self.parse_prefix_expr(None); - let (span, expr) = self.interpolated_or_expr_span(expr)?; - Ok((lo.to(span), ExprKind::AddrOf(borrow_kind, mutbl, expr))) + let (hi, expr) = self.interpolated_or_expr_span(expr)?; + let span = lo.to(hi); + if let Some(lt) = lifetime { + self.error_remove_borrow_lifetime(span, lt.ident.span); + } + Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr))) + } + + fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) { + self.struct_span_err(span, "borrow expressions cannot be annotated with lifetimes") + .span_label(lt_span, "annotated with lifetime here") + .span_suggestion( + lt_span, + "remove the lifetime annotation", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); } /// Parse `mut?` or `raw [ const | mut ]`. @@ -901,7 +919,7 @@ impl<'a> Parser<'a> { } else if self.eat_lt() { let (qself, path) = self.parse_qpath(PathStyle::Expr)?; Ok(self.mk_expr(lo.to(path.span), ExprKind::Path(Some(qself), path), attrs)) - } else if self.token.is_path_start() { + } else if self.check_path() { self.parse_path_start_expr(attrs) } else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) { self.parse_closure_expr(attrs) @@ -1067,26 +1085,44 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } + /// Parse `'label: $expr`. The label is already parsed. fn parse_labeled_expr(&mut self, label: Label, attrs: AttrVec) -> PResult<'a, P<Expr>> { let lo = label.ident.span; - self.expect(&token::Colon)?; - if self.eat_keyword(kw::While) { - return self.parse_while_expr(Some(label), lo, attrs); - } - if self.eat_keyword(kw::For) { - return self.parse_for_expr(Some(label), lo, attrs); - } - if self.eat_keyword(kw::Loop) { - return self.parse_loop_expr(Some(label), lo, attrs); - } - if self.token == token::OpenDelim(token::Brace) { - return self.parse_block_expr(Some(label), lo, BlockCheckMode::Default, attrs); + let label = Some(label); + let ate_colon = self.eat(&token::Colon); + let expr = if self.eat_keyword(kw::While) { + self.parse_while_expr(label, lo, attrs) + } else if self.eat_keyword(kw::For) { + self.parse_for_expr(label, lo, attrs) + } else if self.eat_keyword(kw::Loop) { + self.parse_loop_expr(label, lo, attrs) + } else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() { + self.parse_block_expr(label, lo, BlockCheckMode::Default, attrs) + } else { + let msg = "expected `while`, `for`, `loop` or `{` after a label"; + self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit(); + // Continue as an expression in an effort to recover on `'label: non_block_expr`. + self.parse_expr() + }?; + + if !ate_colon { + self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span); } - let msg = "expected `while`, `for`, `loop` or `{` after a label"; - self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit(); - // Continue as an expression in an effort to recover on `'label: non_block_expr`. - self.parse_expr() + Ok(expr) + } + + fn error_labeled_expr_must_be_followed_by_colon(&self, lo: Span, span: Span) { + self.struct_span_err(span, "labeled expression must be followed by `:`") + .span_label(lo, "the label") + .span_suggestion_short( + lo.shrink_to_hi(), + "add `:` after the label", + ": ".to_string(), + Applicability::MachineApplicable, + ) + .note("labels are used before loops and blocks, allowing e.g., `break 'label` to them") + .emit(); } /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead. @@ -1363,18 +1399,20 @@ impl<'a> Parser<'a> { opt_label: Option<Label>, lo: Span, blk_mode: BlockCheckMode, - outer_attrs: AttrVec, + mut attrs: AttrVec, ) -> PResult<'a, P<Expr>> { if let Some(label) = opt_label { self.sess.gated_spans.gate(sym::label_break_value, label.ident.span); } - self.expect(&token::OpenDelim(token::Brace))?; - - let mut attrs = outer_attrs; - attrs.extend(self.parse_inner_attributes()?); + if self.token.is_whole_block() { + self.struct_span_err(self.token.span, "cannot use a `block` macro fragment here") + .span_label(lo.to(self.token.span), "the `block` fragment is within this context") + .emit(); + } - let blk = self.parse_block_tail(lo, blk_mode)?; + let (inner_attrs, blk) = self.parse_block_common(lo, blk_mode)?; + attrs.extend(inner_attrs); Ok(self.mk_expr(blk.span, ExprKind::Block(blk, opt_label), attrs)) } @@ -1476,13 +1514,16 @@ impl<'a> Parser<'a> { let thn = if self.eat_keyword(kw::Else) || !cond.returns() { self.error_missing_if_cond(lo, cond.span) } else { + let attrs = self.parse_outer_attributes()?; // For recovery. let not_block = self.token != token::OpenDelim(token::Brace); - self.parse_block().map_err(|mut err| { + let block = self.parse_block().map_err(|mut err| { if not_block { err.span_label(lo, "this `if` expression has a condition, but no block"); } err - })? + })?; + self.error_on_if_block_attrs(lo, false, block.span, &attrs); + block }; let els = if self.eat_keyword(kw::Else) { Some(self.parse_else_expr()?) } else { None }; Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els), attrs)) @@ -1524,12 +1565,40 @@ impl<'a> Parser<'a> { /// Parses an `else { ... }` expression (`else` token already eaten). fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> { - if self.eat_keyword(kw::If) { - self.parse_if_expr(AttrVec::new()) + let ctx_span = self.prev_token.span; // `else` + let attrs = self.parse_outer_attributes()?; // For recovery. + let expr = if self.eat_keyword(kw::If) { + self.parse_if_expr(AttrVec::new())? } else { let blk = self.parse_block()?; - Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new())) - } + self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new()) + }; + self.error_on_if_block_attrs(ctx_span, true, expr.span, &attrs); + Ok(expr) + } + + fn error_on_if_block_attrs( + &self, + ctx_span: Span, + is_ctx_else: bool, + branch_span: Span, + attrs: &[ast::Attribute], + ) { + let (span, last) = match attrs { + [] => return, + [x0 @ xn] | [x0, .., xn] => (x0.span.to(xn.span), xn.span), + }; + let ctx = if is_ctx_else { "else" } else { "if" }; + self.struct_span_err(last, "outer attributes are not allowed on `if` and `else` branches") + .span_label(branch_span, "the attributes are attached to this branch") + .span_label(ctx_span, format!("the branch belongs to this `{}`", ctx)) + .span_suggestion( + span, + "remove the attributes", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); } /// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten). diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index a9c4de04c0a..3932bbd7564 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -218,7 +218,7 @@ impl<'a> Parser<'a> { } else if vis.node.is_pub() && self.isnt_macro_invocation() { self.recover_missing_kw_before_item()?; return Ok(None); - } else if macros_allowed && self.token.is_path_start() { + } else if macros_allowed && self.check_path() { // MACRO INVOCATION ITEM (Ident::invalid(), ItemKind::Mac(self.parse_item_macro(vis)?)) } else { @@ -352,8 +352,7 @@ impl<'a> Parser<'a> { fn recover_attrs_no_item(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> { let (start, end) = match attrs { [] => return Ok(()), - [x0] => (x0, x0), - [x0, .., xn] => (x0, xn), + [x0 @ xn] | [x0, .., xn] => (x0, xn), }; let msg = if end.is_doc_comment() { "expected item after doc comment" @@ -1411,23 +1410,28 @@ impl<'a> Parser<'a> { /// This can either be `;` when there's no body, /// or e.g. a block when the function is a provided one. fn parse_fn_body(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, Option<P<Block>>> { - let (inner_attrs, body) = match self.token.kind { - token::Semi => { - self.bump(); - (Vec::new(), None) - } - token::OpenDelim(token::Brace) => { - let (attrs, body) = self.parse_inner_attrs_and_block()?; - (attrs, Some(body)) - } - token::Interpolated(ref nt) => match **nt { - token::NtBlock(..) => { - let (attrs, body) = self.parse_inner_attrs_and_block()?; - (attrs, Some(body)) - } - _ => return self.expected_semi_or_open_brace(), - }, - _ => return self.expected_semi_or_open_brace(), + let (inner_attrs, body) = if self.check(&token::Semi) { + self.bump(); // `;` + (Vec::new(), None) + } else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() { + self.parse_inner_attrs_and_block().map(|(attrs, body)| (attrs, Some(body)))? + } else if self.token.kind == token::Eq { + // Recover `fn foo() = $expr;`. + self.bump(); // `=` + let eq_sp = self.prev_token.span; + let _ = self.parse_expr()?; + self.expect_semi()?; // `;` + let span = eq_sp.to(self.prev_token.span); + self.struct_span_err(span, "function body cannot be `= expression;`") + .multipart_suggestion( + "surround the expression with `{` and `}` instead of `=` and `;`", + vec![(eq_sp, "{".to_string()), (self.prev_token.span, " }".to_string())], + Applicability::MachineApplicable, + ) + .emit(); + (Vec::new(), Some(self.mk_block_err(span))) + } else { + return self.expected_semi_or_open_brace(); }; attrs.extend(inner_attrs); Ok(body) diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs index f52a91ff598..5f2b3b03488 100644 --- a/src/librustc_parse/parser/pat.rs +++ b/src/librustc_parse/parser/pat.rs @@ -704,7 +704,7 @@ impl<'a> Parser<'a> { } fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> { - if self.token.is_path_start() { + if self.check_path() { let lo = self.token.span; let (qself, path) = if self.eat_lt() { // Parse a qualified path diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index 3864ec3aaa1..489549a5750 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -1,3 +1,4 @@ +use super::attr::DEFAULT_INNER_ATTR_FORBIDDEN; use super::diagnostics::Error; use super::expr::LhsExpr; use super::pat::GateOr; @@ -47,10 +48,7 @@ impl<'a> Parser<'a> { self.bump(); // `var` let msg = "write `let` instead of `var` to introduce a new variable"; self.recover_stmt_local(lo, attrs.into(), msg, "let")? - } else if self.token.is_path_start() - && !self.token.is_qpath_start() - && !self.is_path_start_item() - { + } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() { // We have avoided contextual keywords like `union`, items with `crate` visibility, // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something // that starts like a path (1 token), but it fact not a path. @@ -238,15 +236,11 @@ impl<'a> Parser<'a> { /// Parses a block. No inner attributes are allowed. pub fn parse_block(&mut self) -> PResult<'a, P<Block>> { - maybe_whole!(self, NtBlock, |x| x); - - let lo = self.token.span; - - if !self.eat(&token::OpenDelim(token::Brace)) { - return self.error_block_no_opening_brace(); + let (attrs, block) = self.parse_inner_attrs_and_block()?; + if let [.., last] = &*attrs { + self.error_on_forbidden_inner_attr(last.span, DEFAULT_INNER_ATTR_FORBIDDEN); } - - self.parse_block_tail(lo, BlockCheckMode::Default) + Ok(block) } fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> { @@ -262,16 +256,14 @@ impl<'a> Parser<'a> { // // which is valid in other languages, but not Rust. match self.parse_stmt_without_recovery() { - Ok(Some(stmt)) => { + // 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. + Ok(Some(_)) 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) { + || do_not_suggest_help => {} + Ok(Some(stmt)) => { + let stmt_own_line = self.sess.source_map().is_line_before_span_empty(sp); + let stmt_span = if stmt_own_line && self.eat(&token::Semi) { // Expand the span to include the semicolon. stmt.span.with_hi(self.prev_token.span.hi()) } else { @@ -301,20 +293,27 @@ impl<'a> Parser<'a> { pub(super) fn parse_inner_attrs_and_block( &mut self, ) -> PResult<'a, (Vec<Attribute>, P<Block>)> { + self.parse_block_common(self.token.span, BlockCheckMode::Default) + } + + /// Parses a block. Inner attributes are allowed. + pub(super) fn parse_block_common( + &mut self, + lo: Span, + blk_mode: BlockCheckMode, + ) -> PResult<'a, (Vec<Attribute>, P<Block>)> { maybe_whole!(self, NtBlock, |x| (Vec::new(), x)); - let lo = self.token.span; - self.expect(&token::OpenDelim(token::Brace))?; - Ok((self.parse_inner_attributes()?, self.parse_block_tail(lo, BlockCheckMode::Default)?)) + if !self.eat(&token::OpenDelim(token::Brace)) { + return self.error_block_no_opening_brace(); + } + + Ok((self.parse_inner_attributes()?, self.parse_block_tail(lo, blk_mode)?)) } /// Parses the rest of a block expression or function body. /// Precondition: already parsed the '{'. - pub(super) fn parse_block_tail( - &mut self, - lo: Span, - s: BlockCheckMode, - ) -> PResult<'a, P<Block>> { + fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P<Block>> { let mut stmts = vec![]; while !self.eat(&token::CloseDelim(token::Brace)) { if self.token == token::Eof { diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 16adf5c05a4..3dd415bf372 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -142,24 +142,20 @@ impl<'a> Parser<'a> { } else { let path = self.parse_path(PathStyle::Type)?; let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); - self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? + self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)? } } else if self.eat_keyword(kw::Impl) { self.parse_impl_ty(&mut impl_dyn_multi)? } else if self.is_explicit_dyn_type() { self.parse_dyn_ty(&mut impl_dyn_multi)? - } else if self.check(&token::Question) - || self.check_lifetime() && self.look_ahead(1, |t| t.is_like_plus()) - { - // Bound list (trait object type) - let bounds = self.parse_generic_bounds_common(allow_plus, None)?; - TyKind::TraitObject(bounds, TraitObjectSyntax::None) } else if self.eat_lt() { // Qualified path let (qself, path) = self.parse_qpath(PathStyle::Type)?; TyKind::Path(Some(qself), path) - } else if self.token.is_path_start() { + } else if self.check_path() { self.parse_path_start_ty(lo, allow_plus)? + } else if self.can_begin_bound() { + self.parse_bare_trait_object(lo, allow_plus)? } else if self.eat(&token::DotDotDot) { if allow_c_variadic == AllowCVariadic::Yes { TyKind::CVarArgs @@ -203,21 +199,12 @@ impl<'a> Parser<'a> { match ty.kind { // `(TY_BOUND_NOPAREN) + BOUND + ...`. TyKind::Path(None, path) if maybe_bounds => { - self.parse_remaining_bounds(Vec::new(), path, lo, true) + self.parse_remaining_bounds_path(Vec::new(), path, lo, true) } - TyKind::TraitObject(mut bounds, TraitObjectSyntax::None) + TyKind::TraitObject(bounds, TraitObjectSyntax::None) if maybe_bounds && bounds.len() == 1 && !trailing_plus => { - let path = match bounds.remove(0) { - GenericBound::Trait(pt, ..) => pt.trait_ref.path, - GenericBound::Outlives(..) => { - return Err(self.struct_span_err( - ty.span, - "expected trait bound, not lifetime bound", - )); - } - }; - self.parse_remaining_bounds(Vec::new(), path, lo, true) + self.parse_remaining_bounds(bounds, true) } // `(TYPE)` _ => Ok(TyKind::Paren(P(ty))), @@ -227,18 +214,35 @@ impl<'a> Parser<'a> { } } - fn parse_remaining_bounds( + fn parse_bare_trait_object(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> { + let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus()); + let bounds = self.parse_generic_bounds_common(allow_plus, None)?; + if lt_no_plus { + self.struct_span_err(lo, "lifetime in trait object type must be followed by `+`").emit() + } + Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) + } + + fn parse_remaining_bounds_path( &mut self, generic_params: Vec<GenericParam>, path: ast::Path, lo: Span, parse_plus: bool, ) -> PResult<'a, TyKind> { - assert_ne!(self.token, token::Question); - let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_token.span)); - let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)]; - if parse_plus { + let bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)]; + self.parse_remaining_bounds(bounds, parse_plus) + } + + /// Parse the remainder of a bare trait object type given an already parsed list. + fn parse_remaining_bounds( + &mut self, + mut bounds: GenericBounds, + plus: bool, + ) -> PResult<'a, TyKind> { + assert_ne!(self.token, token::Question); + if plus { self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded bounds.append(&mut self.parse_generic_bounds(Some(self.prev_token.span))?); } @@ -358,7 +362,7 @@ impl<'a> Parser<'a> { })) } else if allow_plus == AllowPlus::Yes && self.check_plus() { // `Trait1 + Trait2 + 'a` - self.parse_remaining_bounds(Vec::new(), path, lo, true) + self.parse_remaining_bounds_path(Vec::new(), path, lo, true) } else { // Just a type path. Ok(TyKind::Path(None, path)) diff --git a/src/librustc_span/source_map.rs b/src/librustc_span/source_map.rs index 65095c6f131..353f7b3f52b 100644 --- a/src/librustc_span/source_map.rs +++ b/src/librustc_span/source_map.rs @@ -517,6 +517,13 @@ impl SourceMap { Ok((lo, hi)) } + pub fn is_line_before_span_empty(&self, sp: Span) -> bool { + match self.span_to_prev_source(sp) { + Ok(s) => s.split('\n').last().map(|l| l.trim_start().is_empty()).unwrap_or(false), + Err(_) => false, + } + } + pub fn span_to_lines(&self, sp: Span) -> FileLinesResult { debug!("span_to_lines(sp={:?})", sp); let (lo, hi) = self.is_valid_span(sp)?; diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr index 613d7eee594..76e87a3749c 100644 --- a/src/test/ui/did_you_mean/issue-40006.stderr +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -32,11 +32,11 @@ LL | X() {} LL | } | - the item list ends here -error: expected `[`, found `#` +error: expected one of `!` or `[`, found `#` --> $DIR/issue-40006.rs:19:17 | LL | fn xxx() { ### } - | ^ expected `[` + | ^ expected one of `!` or `[` error: expected one of `!` or `::`, found `=` --> $DIR/issue-40006.rs:22:7 diff --git a/src/test/ui/generic-associated-types/empty_generics.rs b/src/test/ui/generic-associated-types/empty_generics.rs index 522e23ca43d..6eb25a92f34 100644 --- a/src/test/ui/generic-associated-types/empty_generics.rs +++ b/src/test/ui/generic-associated-types/empty_generics.rs @@ -3,7 +3,7 @@ trait Foo { type Bar<,>; - //~^ ERROR expected one of `>`, `const`, identifier, or lifetime, found `,` + //~^ ERROR expected one of `#`, `>`, `const`, identifier, or lifetime, found `,` } fn main() {} diff --git a/src/test/ui/generic-associated-types/empty_generics.stderr b/src/test/ui/generic-associated-types/empty_generics.stderr index bd5708d8140..1599d683ad6 100644 --- a/src/test/ui/generic-associated-types/empty_generics.stderr +++ b/src/test/ui/generic-associated-types/empty_generics.stderr @@ -1,10 +1,10 @@ -error: expected one of `>`, `const`, identifier, or lifetime, found `,` +error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,` --> $DIR/empty_generics.rs:5:14 | LL | trait Foo { | - while parsing this item list starting here LL | type Bar<,>; - | ^ expected one of `>`, `const`, identifier, or lifetime + | ^ expected one of `#`, `>`, `const`, identifier, or lifetime LL | LL | } | - the item list ends here diff --git a/src/test/ui/if-attrs/else-attrs.rs b/src/test/ui/if-attrs/else-attrs.rs index 4394b2100c1..85da7cf6bb8 100644 --- a/src/test/ui/if-attrs/else-attrs.rs +++ b/src/test/ui/if-attrs/else-attrs.rs @@ -8,7 +8,7 @@ fn if_else_parse_error() { #[cfg(FALSE)] fn else_attr_ifparse_error() { if true { - } else #[attr] if false { //~ ERROR expected + } else #[attr] if false { //~ ERROR outer attributes are not allowed } else { } } diff --git a/src/test/ui/if-attrs/else-attrs.stderr b/src/test/ui/if-attrs/else-attrs.stderr index af25b6abc0a..2733377054d 100644 --- a/src/test/ui/if-attrs/else-attrs.stderr +++ b/src/test/ui/if-attrs/else-attrs.stderr @@ -4,18 +4,17 @@ error: expected expression, found keyword `else` LL | } #[attr] else if false { | ^^^^ expected expression -error: expected `{`, found `#` +error: outer attributes are not allowed on `if` and `else` branches --> $DIR/else-attrs.rs:11:12 | -LL | } else #[attr] if false { - | ^ expected `{` - | -help: try placing this code inside a block - | -LL | } else #[attr] { if false { -LL | } else { -LL | } } - | +LL | } else #[attr] if false { + | _______----_^^^^^^^_- + | | | | + | | | help: remove the attributes + | | the branch belongs to this `else` +LL | | } else { +LL | | } + | |_____- the attributes are attached to this branch error: expected expression, found keyword `else` --> $DIR/else-attrs.rs:20:15 diff --git a/src/test/ui/issues/issue-20616-8.rs b/src/test/ui/issues/issue-20616-8.rs index c9e8b61e50b..3ceb58d1252 100644 --- a/src/test/ui/issues/issue-20616-8.rs +++ b/src/test/ui/issues/issue-20616-8.rs @@ -29,7 +29,7 @@ type Type_5_<'a> = Type_1_<'a, ()>; type Type_8<'a,,> = &'a (); -//~^ error: expected one of `>`, `const`, identifier, or lifetime, found `,` +//~^ error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,` //type Type_9<T,,> = Box<T>; // error: expected identifier, found `,` diff --git a/src/test/ui/issues/issue-20616-8.stderr b/src/test/ui/issues/issue-20616-8.stderr index 479469634c5..e9f37e50fff 100644 --- a/src/test/ui/issues/issue-20616-8.stderr +++ b/src/test/ui/issues/issue-20616-8.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, `const`, identifier, or lifetime, found `,` +error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,` --> $DIR/issue-20616-8.rs:31:16 | LL | type Type_8<'a,,> = &'a (); - | ^ expected one of `>`, `const`, identifier, or lifetime + | ^ expected one of `#`, `>`, `const`, identifier, or lifetime error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-9.rs b/src/test/ui/issues/issue-20616-9.rs index 1c509f26fd6..7f84284481e 100644 --- a/src/test/ui/issues/issue-20616-9.rs +++ b/src/test/ui/issues/issue-20616-9.rs @@ -32,4 +32,4 @@ type Type_5_<'a> = Type_1_<'a, ()>; type Type_9<T,,> = Box<T>; -//~^ error: expected one of `>`, `const`, identifier, or lifetime, found `,` +//~^ error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,` diff --git a/src/test/ui/issues/issue-20616-9.stderr b/src/test/ui/issues/issue-20616-9.stderr index b7e3322b7aa..dc309d1bce1 100644 --- a/src/test/ui/issues/issue-20616-9.stderr +++ b/src/test/ui/issues/issue-20616-9.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, `const`, identifier, or lifetime, found `,` +error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,` --> $DIR/issue-20616-9.rs:34:15 | LL | type Type_9<T,,> = Box<T>; - | ^ expected one of `>`, `const`, identifier, or lifetime + | ^ expected one of `#`, `>`, `const`, identifier, or lifetime error: aborting due to previous error diff --git a/src/test/ui/issues/issue-66473.rs b/src/test/ui/issues/issue-66473.rs index cc298a28b97..9db4521bb42 100644 --- a/src/test/ui/issues/issue-66473.rs +++ b/src/test/ui/issues/issue-66473.rs Binary files differdiff --git a/src/test/ui/issues/issue-66473.stderr b/src/test/ui/issues/issue-66473.stderr index dbeef44bad0..b370b125cfe 100644 --- a/src/test/ui/issues/issue-66473.stderr +++ b/src/test/ui/issues/issue-66473.stderr Binary files differdiff --git a/src/test/ui/label/label_break_value_illegal_uses.stderr b/src/test/ui/label/label_break_value_illegal_uses.stderr index fd8850dd8da..a2c75882be0 100644 --- a/src/test/ui/label/label_break_value_illegal_uses.stderr +++ b/src/test/ui/label/label_break_value_illegal_uses.stderr @@ -2,7 +2,10 @@ error: expected `{`, found `'b` --> $DIR/label_break_value_illegal_uses.rs:6:12 | LL | unsafe 'b: {} - | ^^ expected `{` + | ^^---- + | | + | expected `{` + | help: try placing this code inside a block: `{ 'b: {} }` error: expected `{`, found `'b` --> $DIR/label_break_value_illegal_uses.rs:10:13 diff --git a/src/test/ui/parser/attr-stmt-expr-attr-bad.rs b/src/test/ui/parser/attr-stmt-expr-attr-bad.rs index f3980a59648..09f494bdc2f 100644 --- a/src/test/ui/parser/attr-stmt-expr-attr-bad.rs +++ b/src/test/ui/parser/attr-stmt-expr-attr-bad.rs @@ -39,35 +39,35 @@ fn main() {} #[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; } //~^ ERROR an inner attribute is not permitted in this context #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; } -//~^ ERROR expected `{`, found `#` +//~^ ERROR outer attributes are not allowed on `if` #[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 `#` +//~^ ERROR outer attributes are not allowed on `if` #[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 expected `{`, found `#` +//~^ ERROR outer attributes are not allowed on `if` #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } -//~^ ERROR expected `{`, found `#` +//~^ ERROR outer attributes are not allowed on `if` #[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 _ = if let _ = 0 #[attr] {}; } -//~^ ERROR expected `{`, found `#` +//~^ ERROR outer attributes are not allowed on `if` #[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 `#` +//~^ ERROR outer attributes are not allowed on `if` #[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 expected `{`, found `#` +//~^ ERROR outer attributes are not allowed on `if` #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } -//~^ ERROR expected `{`, found `#` +//~^ ERROR outer attributes are not allowed on `if` #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context diff --git a/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr b/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr index 4dcba27cb68..6dfe7aad6ea 100644 --- a/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr +++ b/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr @@ -136,14 +136,14 @@ 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: expected `{`, found `#` +error: outer attributes are not allowed on `if` and `else` branches --> $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: `{ {}; }` + | -- ^^^^^^^ -- the attributes are attached to this branch | | | - | | expected `{` - | this `if` expression has a condition, but no block + | | help: remove the attributes + | the branch belongs to this `if` error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:43:38 @@ -159,13 +159,14 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#` LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} #[attr] else {}; } | ^ expected one of `.`, `;`, `?`, `else`, or an operator -error: expected `{`, found `#` +error: outer attributes are not allowed on `if` and `else` branches --> $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 `{` + | ---- ^^^^^^^ -- the attributes are attached to this branch + | | | + | | help: remove the attributes + | the branch belongs to this `else` error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:49:46 @@ -175,22 +176,23 @@ 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: expected `{`, found `#` +error: outer attributes are not allowed on `if` and `else` branches --> $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 `{` + | ---- ^^^^^^^ ------- the attributes are attached to this branch + | | | + | | help: remove the attributes + | the branch belongs to this `else` -error: expected `{`, found `#` +error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:53:50 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } - | -- ^ --- help: try placing this code inside a block: `{ {}; }` + | -- ^^^^^^^ -- the attributes are attached to this branch | | | - | | expected `{` - | this `if` expression has a condition, but no block + | | help: remove the attributes + | the branch belongs to this `if` error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:55:51 @@ -200,14 +202,14 @@ 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: expected `{`, found `#` +error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:57:45 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; } - | -- ^ --- help: try placing this code inside a block: `{ {}; }` + | -- ^^^^^^^ -- the attributes are attached to this branch | | | - | | expected `{` - | this `if` expression has a condition, but no block + | | help: remove the attributes + | the branch belongs to this `if` error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:59:46 @@ -223,13 +225,14 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#` LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; } | ^ expected one of `.`, `;`, `?`, `else`, or an operator -error: expected `{`, found `#` +error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:63:53 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } - | ^ --- help: try placing this code inside a block: `{ {}; }` - | | - | expected `{` + | ---- ^^^^^^^ -- the attributes are attached to this branch + | | | + | | help: remove the attributes + | the branch belongs to this `else` error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:65:54 @@ -239,22 +242,23 @@ 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: expected `{`, found `#` +error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:67: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 `{` + | ---- ^^^^^^^ --------------- the attributes are attached to this branch + | | | + | | help: remove the attributes + | the branch belongs to this `else` -error: expected `{`, found `#` +error: outer attributes are not allowed on `if` and `else` branches --> $DIR/attr-stmt-expr-attr-bad.rs:69:66 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } - | -- ^ --- help: try placing this code inside a block: `{ {}; }` + | -- ^^^^^^^ -- the attributes are attached to this branch | | | - | | expected `{` - | this `if` expression has a condition, but no block + | | help: remove the attributes + | the branch belongs to this `if` error: an inner attribute is not permitted in this context --> $DIR/attr-stmt-expr-attr-bad.rs:71:67 diff --git a/src/test/ui/parser/bad-interpolated-block.rs b/src/test/ui/parser/bad-interpolated-block.rs new file mode 100644 index 00000000000..38d53a14bc0 --- /dev/null +++ b/src/test/ui/parser/bad-interpolated-block.rs @@ -0,0 +1,15 @@ +#![feature(label_break_value)] + +fn main() {} + +macro_rules! m { + ($b:block) => { + 'lab: $b; //~ ERROR cannot use a `block` macro fragment here + unsafe $b; //~ ERROR cannot use a `block` macro fragment here + |x: u8| -> () $b; //~ ERROR cannot use a `block` macro fragment here + } +} + +fn foo() { + m!({}); +} diff --git a/src/test/ui/parser/bad-interpolated-block.stderr b/src/test/ui/parser/bad-interpolated-block.stderr new file mode 100644 index 00000000000..2cbb6a13e74 --- /dev/null +++ b/src/test/ui/parser/bad-interpolated-block.stderr @@ -0,0 +1,39 @@ +error: cannot use a `block` macro fragment here + --> $DIR/bad-interpolated-block.rs:7:15 + | +LL | 'lab: $b; + | ------^^ + | | + | the `block` fragment is within this context +... +LL | m!({}); + | ------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot use a `block` macro fragment here + --> $DIR/bad-interpolated-block.rs:8:16 + | +LL | unsafe $b; + | -------^^ + | | + | the `block` fragment is within this context +... +LL | m!({}); + | ------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot use a `block` macro fragment here + --> $DIR/bad-interpolated-block.rs:9:23 + | +LL | |x: u8| -> () $b; + | ^^ the `block` fragment is within this context +... +LL | m!({}); + | ------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/parser/block-no-opening-brace.rs b/src/test/ui/parser/block-no-opening-brace.rs new file mode 100644 index 00000000000..e4bb39f6836 --- /dev/null +++ b/src/test/ui/parser/block-no-opening-brace.rs @@ -0,0 +1,31 @@ +// edition:2018 + +#![feature(try_blocks)] + +fn main() {} + +fn f1() { + loop + let x = 0; //~ ERROR expected `{`, found keyword `let` + drop(0); + } + +fn f2() { + while true + let x = 0; //~ ERROR expected `{`, found keyword `let` + } + +fn f3() { + for x in 0..1 + let x = 0; //~ ERROR expected `{`, found keyword `let` + } + +fn f4() { + try //~ ERROR expected expression, found reserved keyword `try` + let x = 0; + } + +fn f5() { + async //~ ERROR async closures are unstable + let x = 0; //~ ERROR expected one of `move`, `|`, or `||`, found keyword `let` + } diff --git a/src/test/ui/parser/block-no-opening-brace.stderr b/src/test/ui/parser/block-no-opening-brace.stderr new file mode 100644 index 00000000000..a88e4ac44cf --- /dev/null +++ b/src/test/ui/parser/block-no-opening-brace.stderr @@ -0,0 +1,53 @@ +error: expected `{`, found keyword `let` + --> $DIR/block-no-opening-brace.rs:9:9 + | +LL | let x = 0; + | ^^^------- + | | + | expected `{` + | help: try placing this code inside a block: `{ let x = 0; }` + +error: expected `{`, found keyword `let` + --> $DIR/block-no-opening-brace.rs:15:9 + | +LL | let x = 0; + | ^^^------- + | | + | expected `{` + | help: try placing this code inside a block: `{ let x = 0; }` + +error: expected `{`, found keyword `let` + --> $DIR/block-no-opening-brace.rs:20:9 + | +LL | let x = 0; + | ^^^------- + | | + | expected `{` + | help: try placing this code inside a block: `{ let x = 0; }` + +error: expected expression, found reserved keyword `try` + --> $DIR/block-no-opening-brace.rs:24:5 + | +LL | try + | ^^^ expected expression + +error: expected one of `move`, `|`, or `||`, found keyword `let` + --> $DIR/block-no-opening-brace.rs:30:9 + | +LL | async + | - expected one of `move`, `|`, or `||` +LL | let x = 0; + | ^^^ unexpected token + +error[E0658]: async closures are unstable + --> $DIR/block-no-opening-brace.rs:29:5 + | +LL | async + | ^^^^^ + | + = note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information + = help: add `#![feature(async_closure)]` to the crate attributes to enable + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/parser/bounds-lifetime.rs b/src/test/ui/parser/bounds-lifetime.rs index 9225cfce94e..c9251ac5321 100644 --- a/src/test/ui/parser/bounds-lifetime.rs +++ b/src/test/ui/parser/bounds-lifetime.rs @@ -6,6 +6,6 @@ type A = for<'a: 'b + 'c> fn(); // OK (rejected later by ast_validation) type A = for<'a: 'b,> fn(); // OK(rejected later by ast_validation) type A = for<'a: 'b +> fn(); // OK (rejected later by ast_validation) type A = for<'a, T> fn(); // OK (rejected later by ast_validation) -type A = for<,> fn(); //~ ERROR expected one of `>`, `const`, identifier, or lifetime, found `,` +type A = for<,> fn(); //~ ERROR expected one of `#`, `>`, `const`, identifier, or lifetime fn main() {} diff --git a/src/test/ui/parser/bounds-lifetime.stderr b/src/test/ui/parser/bounds-lifetime.stderr index 12b9b61ebd1..e47a21d892b 100644 --- a/src/test/ui/parser/bounds-lifetime.stderr +++ b/src/test/ui/parser/bounds-lifetime.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, `const`, identifier, or lifetime, found `,` +error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,` --> $DIR/bounds-lifetime.rs:9:14 | LL | type A = for<,> fn(); - | ^ expected one of `>`, `const`, identifier, or lifetime + | ^ expected one of `#`, `>`, `const`, identifier, or lifetime error: aborting due to previous error diff --git a/src/test/ui/parser/closure-return-syntax.rs b/src/test/ui/parser/closure-return-syntax.rs index 54eb791d2bc..c6a08abeff4 100644 --- a/src/test/ui/parser/closure-return-syntax.rs +++ b/src/test/ui/parser/closure-return-syntax.rs @@ -3,5 +3,5 @@ fn main() { let x = || -> i32 22; - //~^ ERROR expected one of `!`, `(`, `+`, `::`, `<`, or `{`, found `22` + //~^ ERROR expected `{`, found `22` } diff --git a/src/test/ui/parser/closure-return-syntax.stderr b/src/test/ui/parser/closure-return-syntax.stderr index bfb7f98c5f5..1ccdd977305 100644 --- a/src/test/ui/parser/closure-return-syntax.stderr +++ b/src/test/ui/parser/closure-return-syntax.stderr @@ -1,8 +1,11 @@ -error: expected one of `!`, `(`, `+`, `::`, `<`, or `{`, found `22` +error: expected `{`, found `22` --> $DIR/closure-return-syntax.rs:5:23 | LL | let x = || -> i32 22; - | ^^ expected one of `!`, `(`, `+`, `::`, `<`, or `{` + | ^^ + | | + | expected `{` + | help: try placing this code inside a block: `{ 22 }` error: aborting due to previous error diff --git a/src/test/ui/parser/column-offset-1-based.rs b/src/test/ui/parser/column-offset-1-based.rs index e158e5247db..0c24478c25c 100644 --- a/src/test/ui/parser/column-offset-1-based.rs +++ b/src/test/ui/parser/column-offset-1-based.rs @@ -1 +1 @@ -# //~ ERROR expected `[`, found `<eof>` +# //~ ERROR expected one of `!` or `[`, found `<eof>` diff --git a/src/test/ui/parser/column-offset-1-based.stderr b/src/test/ui/parser/column-offset-1-based.stderr index 5cbf3d3e959..766d72a0a5a 100644 --- a/src/test/ui/parser/column-offset-1-based.stderr +++ b/src/test/ui/parser/column-offset-1-based.stderr @@ -1,8 +1,8 @@ -error: expected `[`, found `<eof>` +error: expected one of `!` or `[`, found `<eof>` --> $DIR/column-offset-1-based.rs:1:1 | LL | # - | ^ expected `[` + | ^ expected one of `!` or `[` error: aborting due to previous error diff --git a/src/test/ui/parser/doc-comment-in-if-statement.rs b/src/test/ui/parser/doc-comment-in-if-statement.rs index c85fe25a7d0..343eac1b81f 100644 --- a/src/test/ui/parser/doc-comment-in-if-statement.rs +++ b/src/test/ui/parser/doc-comment-in-if-statement.rs @@ -1,4 +1,5 @@ fn main() { if true /*!*/ {} - //~^ ERROR expected `{`, found doc comment `/*!*/` + //~^ ERROR outer attributes are not allowed on + //~| ERROR expected outer doc comment } diff --git a/src/test/ui/parser/doc-comment-in-if-statement.stderr b/src/test/ui/parser/doc-comment-in-if-statement.stderr index a720dd68bd0..af21b78733f 100644 --- a/src/test/ui/parser/doc-comment-in-if-statement.stderr +++ b/src/test/ui/parser/doc-comment-in-if-statement.stderr @@ -1,10 +1,19 @@ -error: expected `{`, found doc comment `/*!*/` +error: expected outer doc comment --> $DIR/doc-comment-in-if-statement.rs:2:13 | LL | if true /*!*/ {} - | -- ^^^^^ expected `{` - | | - | this `if` expression has a condition, but no block + | ^^^^^ + | + = note: inner doc comments like this (starting with `//!` or `/*!`) can only appear before items + +error: outer attributes are not allowed on `if` and `else` branches + --> $DIR/doc-comment-in-if-statement.rs:2:13 + | +LL | if true /*!*/ {} + | -- ^^^^^ -- the attributes are attached to this branch + | | | + | | help: remove the attributes + | the branch belongs to this `if` -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/fn-body-eq-expr-semi.rs b/src/test/ui/parser/fn-body-eq-expr-semi.rs new file mode 100644 index 00000000000..09444079365 --- /dev/null +++ b/src/test/ui/parser/fn-body-eq-expr-semi.rs @@ -0,0 +1,23 @@ +fn main() {} + +fn syntax() { + fn foo() = 42; //~ ERROR function body cannot be `= expression;` + fn bar() -> u8 = 42; //~ ERROR function body cannot be `= expression;` +} + +extern { + fn foo() = 42; //~ ERROR function body cannot be `= expression;` + //~^ ERROR incorrect function inside `extern` block + fn bar() -> u8 = 42; //~ ERROR function body cannot be `= expression;` + //~^ ERROR incorrect function inside `extern` block +} + +trait Foo { + fn foo() = 42; //~ ERROR function body cannot be `= expression;` + fn bar() -> u8 = 42; //~ ERROR function body cannot be `= expression;` +} + +impl Foo for () { + fn foo() = 42; //~ ERROR function body cannot be `= expression;` + fn bar() -> u8 = 42; //~ ERROR function body cannot be `= expression;` +} diff --git a/src/test/ui/parser/fn-body-eq-expr-semi.stderr b/src/test/ui/parser/fn-body-eq-expr-semi.stderr new file mode 100644 index 00000000000..739133e0b40 --- /dev/null +++ b/src/test/ui/parser/fn-body-eq-expr-semi.stderr @@ -0,0 +1,117 @@ +error: function body cannot be `= expression;` + --> $DIR/fn-body-eq-expr-semi.rs:4:14 + | +LL | fn foo() = 42; + | ^^^^^ + | +help: surround the expression with `{` and `}` instead of `=` and `;` + | +LL | fn foo() { 42 } + | ^ ^ + +error: function body cannot be `= expression;` + --> $DIR/fn-body-eq-expr-semi.rs:5:20 + | +LL | fn bar() -> u8 = 42; + | ^^^^^ + | +help: surround the expression with `{` and `}` instead of `=` and `;` + | +LL | fn bar() -> u8 { 42 } + | ^ ^ + +error: function body cannot be `= expression;` + --> $DIR/fn-body-eq-expr-semi.rs:9:14 + | +LL | fn foo() = 42; + | ^^^^^ + | +help: surround the expression with `{` and `}` instead of `=` and `;` + | +LL | fn foo() { 42 } + | ^ ^ + +error: function body cannot be `= expression;` + --> $DIR/fn-body-eq-expr-semi.rs:11:20 + | +LL | fn bar() -> u8 = 42; + | ^^^^^ + | +help: surround the expression with `{` and `}` instead of `=` and `;` + | +LL | fn bar() -> u8 { 42 } + | ^ ^ + +error: function body cannot be `= expression;` + --> $DIR/fn-body-eq-expr-semi.rs:16:14 + | +LL | fn foo() = 42; + | ^^^^^ + | +help: surround the expression with `{` and `}` instead of `=` and `;` + | +LL | fn foo() { 42 } + | ^ ^ + +error: function body cannot be `= expression;` + --> $DIR/fn-body-eq-expr-semi.rs:17:20 + | +LL | fn bar() -> u8 = 42; + | ^^^^^ + | +help: surround the expression with `{` and `}` instead of `=` and `;` + | +LL | fn bar() -> u8 { 42 } + | ^ ^ + +error: function body cannot be `= expression;` + --> $DIR/fn-body-eq-expr-semi.rs:21:14 + | +LL | fn foo() = 42; + | ^^^^^ + | +help: surround the expression with `{` and `}` instead of `=` and `;` + | +LL | fn foo() { 42 } + | ^ ^ + +error: function body cannot be `= expression;` + --> $DIR/fn-body-eq-expr-semi.rs:22:20 + | +LL | fn bar() -> u8 = 42; + | ^^^^^ + | +help: surround the expression with `{` and `}` instead of `=` and `;` + | +LL | fn bar() -> u8 { 42 } + | ^ ^ + +error: incorrect function inside `extern` block + --> $DIR/fn-body-eq-expr-semi.rs:9:8 + | +LL | extern { + | ------ `extern` blocks define existing foreign functions and functions inside of them cannot have a body +LL | fn foo() = 42; + | ^^^ ----- help: remove the invalid body: `;` + | | + | cannot have a body + | + = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: incorrect function inside `extern` block + --> $DIR/fn-body-eq-expr-semi.rs:11:8 + | +LL | extern { + | ------ `extern` blocks define existing foreign functions and functions inside of them cannot have a body +... +LL | fn bar() -> u8 = 42; + | ^^^ ----- help: remove the invalid body: `;` + | | + | cannot have a body + | + = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/parser/issue-1655.rs b/src/test/ui/parser/issue-1655.rs index 3d0bf3c1c7b..e9fc6f15346 100644 --- a/src/test/ui/parser/issue-1655.rs +++ b/src/test/ui/parser/issue-1655.rs @@ -1,6 +1,5 @@ -// error-pattern:expected `[`, found `vec` mod blade_runner { - #vec[doc( + #vec[doc( //~ ERROR expected one of `!` or `[`, found `vec` brief = "Blade Runner is probably the best movie ever", desc = "I like that in the world of Blade Runner it is always raining, and that it's always night time. And Aliens diff --git a/src/test/ui/parser/issue-1655.stderr b/src/test/ui/parser/issue-1655.stderr index 3f656b63cdb..0c390a0ec56 100644 --- a/src/test/ui/parser/issue-1655.stderr +++ b/src/test/ui/parser/issue-1655.stderr @@ -1,8 +1,8 @@ -error: expected `[`, found `vec` - --> $DIR/issue-1655.rs:3:6 +error: expected one of `!` or `[`, found `vec` + --> $DIR/issue-1655.rs:2:6 | LL | #vec[doc( - | ^^^ expected `[` + | ^^^ expected one of `!` or `[` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-63116.stderr b/src/test/ui/parser/issue-63116.stderr index 2beb73d83d2..15cd3df860b 100644 --- a/src/test/ui/parser/issue-63116.stderr +++ b/src/test/ui/parser/issue-63116.stderr @@ -12,7 +12,7 @@ error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `;` LL | impl W <s(f;Y(;] | ^ expected one of 7 possible tokens -error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `->`, `...`, `::`, `<`, `>`, `?`, `[`, `_`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, or lifetime, found `;` +error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `->`, `...`, `::`, `<`, `>`, `?`, `[`, `_`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, lifetime, or path, found `;` --> $DIR/issue-63116.rs:3:15 | LL | impl W <s(f;Y(;] diff --git a/src/test/ui/parser/issue-63135.rs b/src/test/ui/parser/issue-63135.rs index 7d46b8904f0..a5a8de85466 100644 --- a/src/test/ui/parser/issue-63135.rs +++ b/src/test/ui/parser/issue-63135.rs @@ -1,3 +1,3 @@ -// error-pattern: aborting due to 7 previous errors +// error-pattern: aborting due to 5 previous errors fn i(n{...,f # diff --git a/src/test/ui/parser/issue-63135.stderr b/src/test/ui/parser/issue-63135.stderr index 04afae93be0..396aec8335d 100644 --- a/src/test/ui/parser/issue-63135.stderr +++ b/src/test/ui/parser/issue-63135.stderr @@ -31,23 +31,11 @@ LL | fn i(n{...,f # | | expected `}` | `..` must be at the end and cannot have a trailing comma -error: expected `[`, found `}` +error: expected one of `!` or `[`, found `}` --> $DIR/issue-63135.rs:3:16 | LL | fn i(n{...,f # - | ^ expected `[` + | ^ expected one of `!` or `[` -error: expected one of `:` or `|`, found `)` - --> $DIR/issue-63135.rs:3:16 - | -LL | fn i(n{...,f # - | ^ expected one of `:` or `|` - -error: expected `;` or `{`, found `<eof>` - --> $DIR/issue-63135.rs:3:16 - | -LL | fn i(n{...,f # - | ^ expected `;` or `{` - -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors diff --git a/src/test/ui/parser/issue-68730.rs b/src/test/ui/parser/issue-68730.rs index b570e941775..20e18b4bcbb 100644 --- a/src/test/ui/parser/issue-68730.rs +++ b/src/test/ui/parser/issue-68730.rs Binary files differdiff --git a/src/test/ui/parser/issue-68730.stderr b/src/test/ui/parser/issue-68730.stderr index 090b41d839f..9f8833e17fe 100644 --- a/src/test/ui/parser/issue-68730.stderr +++ b/src/test/ui/parser/issue-68730.stderr Binary files differdiff --git a/src/test/ui/parser/issue-68890-2.rs b/src/test/ui/parser/issue-68890-2.rs new file mode 100644 index 00000000000..ae022460468 --- /dev/null +++ b/src/test/ui/parser/issue-68890-2.rs @@ -0,0 +1,6 @@ +fn main() {} + +type X<'a> = (?'a) +; +//~^ ERROR `?` may only modify trait bounds, not lifetime bounds +//~| ERROR at least one trait is required for an object type +//~| WARN trait objects without an explicit `dyn` are deprecated diff --git a/src/test/ui/parser/issue-68890-2.stderr b/src/test/ui/parser/issue-68890-2.stderr new file mode 100644 index 00000000000..d475c79cb27 --- /dev/null +++ b/src/test/ui/parser/issue-68890-2.stderr @@ -0,0 +1,22 @@ +error: `?` may only modify trait bounds, not lifetime bounds + --> $DIR/issue-68890-2.rs:3:15 + | +LL | type X<'a> = (?'a) +; + | ^ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/issue-68890-2.rs:3:14 + | +LL | type X<'a> = (?'a) +; + | ^^^^^^^ help: use `dyn`: `dyn (?'a) +` + | + = note: `#[warn(bare_trait_objects)]` on by default + +error[E0224]: at least one trait is required for an object type + --> $DIR/issue-68890-2.rs:3:14 + | +LL | type X<'a> = (?'a) +; + | ^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/issue-68890.rs b/src/test/ui/parser/issue-68890.rs index a7c5a5e1300..bab4ed7f800 100644 --- a/src/test/ui/parser/issue-68890.rs +++ b/src/test/ui/parser/issue-68890.rs @@ -1,4 +1,4 @@ enum e{A((?'a a+?+l))} //~^ ERROR `?` may only modify trait bounds, not lifetime bounds //~| ERROR expected one of `)`, `+`, or `,` -//~| ERROR expected trait bound, not lifetime bound +//~| ERROR expected item, found `)` diff --git a/src/test/ui/parser/issue-68890.stderr b/src/test/ui/parser/issue-68890.stderr index 9bb8761b67b..2a3bf6b41f0 100644 --- a/src/test/ui/parser/issue-68890.stderr +++ b/src/test/ui/parser/issue-68890.stderr @@ -10,11 +10,11 @@ error: expected one of `)`, `+`, or `,`, found `a` LL | enum e{A((?'a a+?+l))} | ^ expected one of `)`, `+`, or `,` -error: expected trait bound, not lifetime bound - --> $DIR/issue-68890.rs:1:11 +error: expected item, found `)` + --> $DIR/issue-68890.rs:1:21 | LL | enum e{A((?'a a+?+l))} - | ^^^ + | ^ expected item error: aborting due to 3 previous errors diff --git a/src/test/ui/parser/labeled-no-colon-expr.rs b/src/test/ui/parser/labeled-no-colon-expr.rs new file mode 100644 index 00000000000..db9ef52c1ae --- /dev/null +++ b/src/test/ui/parser/labeled-no-colon-expr.rs @@ -0,0 +1,17 @@ +#![feature(label_break_value)] + +fn main() { + 'l0 while false {} //~ ERROR labeled expression must be followed by `:` + 'l1 for _ in 0..1 {} //~ ERROR labeled expression must be followed by `:` + 'l2 loop {} //~ ERROR labeled expression must be followed by `:` + 'l3 {} //~ ERROR labeled expression must be followed by `:` + 'l4 0; //~ ERROR labeled expression must be followed by `:` + //~^ ERROR expected `while`, `for`, `loop` or `{` + + macro_rules! m { + ($b:block) => { + 'l5 $b; //~ ERROR cannot use a `block` macro fragment here + } + } + m!({}); //~ ERROR labeled expression must be followed by `:` +} diff --git a/src/test/ui/parser/labeled-no-colon-expr.stderr b/src/test/ui/parser/labeled-no-colon-expr.stderr new file mode 100644 index 00000000000..4f5e8f78aa0 --- /dev/null +++ b/src/test/ui/parser/labeled-no-colon-expr.stderr @@ -0,0 +1,89 @@ +error: labeled expression must be followed by `:` + --> $DIR/labeled-no-colon-expr.rs:4:5 + | +LL | 'l0 while false {} + | ----^^^^^^^^^^^^^^ + | | | + | | help: add `:` after the label + | the label + | + = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them + +error: labeled expression must be followed by `:` + --> $DIR/labeled-no-colon-expr.rs:5:5 + | +LL | 'l1 for _ in 0..1 {} + | ----^^^^^^^^^^^^^^^^ + | | | + | | help: add `:` after the label + | the label + | + = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them + +error: labeled expression must be followed by `:` + --> $DIR/labeled-no-colon-expr.rs:6:5 + | +LL | 'l2 loop {} + | ----^^^^^^^ + | | | + | | help: add `:` after the label + | the label + | + = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them + +error: labeled expression must be followed by `:` + --> $DIR/labeled-no-colon-expr.rs:7:5 + | +LL | 'l3 {} + | ----^^ + | | | + | | help: add `:` after the label + | the label + | + = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them + +error: expected `while`, `for`, `loop` or `{` after a label + --> $DIR/labeled-no-colon-expr.rs:8:9 + | +LL | 'l4 0; + | ^ expected `while`, `for`, `loop` or `{` after a label + +error: labeled expression must be followed by `:` + --> $DIR/labeled-no-colon-expr.rs:8:9 + | +LL | 'l4 0; + | ----^ + | | | + | | help: add `:` after the label + | the label + | + = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them + +error: cannot use a `block` macro fragment here + --> $DIR/labeled-no-colon-expr.rs:13:17 + | +LL | 'l5 $b; + | ----^^ + | | + | the `block` fragment is within this context +... +LL | m!({}); + | ------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: labeled expression must be followed by `:` + --> $DIR/labeled-no-colon-expr.rs:16:8 + | +LL | 'l5 $b; + | ---- help: add `:` after the label + | | + | the label +... +LL | m!({}); + | ^^ + | + = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them + +error: aborting due to 8 previous errors + diff --git a/src/test/ui/parser/macro/trait-object-macro-matcher.rs b/src/test/ui/parser/macro/trait-object-macro-matcher.rs index 80d867d3b56..170ac22780b 100644 --- a/src/test/ui/parser/macro/trait-object-macro-matcher.rs +++ b/src/test/ui/parser/macro/trait-object-macro-matcher.rs @@ -2,9 +2,14 @@ // `ty` matcher in particular doesn't accept a single lifetime macro_rules! m { - ($t: ty) => ( let _: $t; ) + ($t: ty) => { + let _: $t; + }; } fn main() { - m!('static); //~ ERROR expected type, found `'static` + m!('static); + //~^ ERROR lifetime in trait object type must be followed by `+` + //~| ERROR at least one trait is required for an object type + //~| WARN trait objects without an explicit `dyn` are deprecated } diff --git a/src/test/ui/parser/macro/trait-object-macro-matcher.stderr b/src/test/ui/parser/macro/trait-object-macro-matcher.stderr index f02f60e4bfb..230733371dd 100644 --- a/src/test/ui/parser/macro/trait-object-macro-matcher.stderr +++ b/src/test/ui/parser/macro/trait-object-macro-matcher.stderr @@ -1,8 +1,22 @@ -error: expected type, found `'static` - --> $DIR/trait-object-macro-matcher.rs:9:8 +error: lifetime in trait object type must be followed by `+` + --> $DIR/trait-object-macro-matcher.rs:11:8 | LL | m!('static); - | ^^^^^^^ expected type + | ^^^^^^^ -error: aborting due to previous error +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/trait-object-macro-matcher.rs:11:8 + | +LL | m!('static); + | ^^^^^^^ help: use `dyn`: `dyn 'static` + | + = note: `#[warn(bare_trait_objects)]` on by default + +error[E0224]: at least one trait is required for an object type + --> $DIR/trait-object-macro-matcher.rs:11:8 + | +LL | m!('static); + | ^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/regions-out-of-scope-slice.rs b/src/test/ui/parser/regions-out-of-scope-slice.rs index 21369d0be61..d223619e1de 100644 --- a/src/test/ui/parser/regions-out-of-scope-slice.rs +++ b/src/test/ui/parser/regions-out-of-scope-slice.rs @@ -4,7 +4,7 @@ fn foo(cond: bool) { let mut x; if cond { - x = &'blk [1,2,3]; //~ ERROR expected `:`, found `[` + x = &'blk [1,2,3]; //~ ERROR borrow expressions cannot be annotated with lifetimes } } diff --git a/src/test/ui/parser/regions-out-of-scope-slice.stderr b/src/test/ui/parser/regions-out-of-scope-slice.stderr index 8d9bf0b7a04..bbc657ffd61 100644 --- a/src/test/ui/parser/regions-out-of-scope-slice.stderr +++ b/src/test/ui/parser/regions-out-of-scope-slice.stderr @@ -1,8 +1,11 @@ -error: expected `:`, found `[` - --> $DIR/regions-out-of-scope-slice.rs:7:19 +error: borrow expressions cannot be annotated with lifetimes + --> $DIR/regions-out-of-scope-slice.rs:7:13 | LL | x = &'blk [1,2,3]; - | ^ expected `:` + | ^----^^^^^^^^ + | | + | annotated with lifetime here + | help: remove the lifetime annotation error: aborting due to previous error diff --git a/src/test/ui/parser/trait-object-lifetime-parens.rs b/src/test/ui/parser/trait-object-lifetime-parens.rs index c8b0eb684f3..5a5c19f32e8 100644 --- a/src/test/ui/parser/trait-object-lifetime-parens.rs +++ b/src/test/ui/parser/trait-object-lifetime-parens.rs @@ -6,9 +6,7 @@ fn f<'a, T: Trait + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not s fn check<'a>() { let _: Box<Trait + ('a)>; //~ ERROR parenthesized lifetime bounds are not supported - let _: Box<('a) + Trait>; - //~^ ERROR expected type, found `'a` - //~| ERROR expected `:`, found `)` + let _: Box<('a) + Trait>; //~ ERROR lifetime in trait object type must be followed by `+` } fn main() {} diff --git a/src/test/ui/parser/trait-object-lifetime-parens.stderr b/src/test/ui/parser/trait-object-lifetime-parens.stderr index 319a308c013..1289c248275 100644 --- a/src/test/ui/parser/trait-object-lifetime-parens.stderr +++ b/src/test/ui/parser/trait-object-lifetime-parens.stderr @@ -10,19 +10,11 @@ error: parenthesized lifetime bounds are not supported LL | let _: Box<Trait + ('a)>; | ^^^^ help: remove the parentheses -error: expected `:`, found `)` - --> $DIR/trait-object-lifetime-parens.rs:9:19 - | -LL | let _: Box<('a) + Trait>; - | ^ expected `:` - -error: expected type, found `'a` +error: lifetime in trait object type must be followed by `+` --> $DIR/trait-object-lifetime-parens.rs:9:17 | LL | let _: Box<('a) + Trait>; - | - ^^ expected type - | | - | while parsing the type for `_` + | ^^ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/parser/trait-object-trait-parens.rs b/src/test/ui/parser/trait-object-trait-parens.rs index a113de14b6f..9fbc938c4dc 100644 --- a/src/test/ui/parser/trait-object-trait-parens.rs +++ b/src/test/ui/parser/trait-object-trait-parens.rs @@ -1,15 +1,20 @@ trait Trait<'a> {} +trait Obj {} + fn f<T: (Copy) + (?Sized) + (for<'a> Trait<'a>)>() {} fn main() { - let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>; + let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; + //~^ ERROR `?Trait` is not permitted in trait object types + //~| ERROR only auto traits can be used as additional traits + //~| WARN trait objects without an explicit `dyn` are deprecated + let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>; //~^ ERROR `?Trait` is not permitted in trait object types + //~| ERROR only auto traits can be used as additional traits //~| WARN trait objects without an explicit `dyn` are deprecated - let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Copy)>; - //~^ WARN trait objects without an explicit `dyn` are deprecated - let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>; - //~^ ERROR use of undeclared lifetime name `'a` - //~| ERROR `?Trait` is not permitted in trait object types + let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>; + //~^ ERROR `?Trait` is not permitted in trait object types + //~| ERROR only auto traits can be used as additional traits //~| WARN trait objects without an explicit `dyn` are deprecated } diff --git a/src/test/ui/parser/trait-object-trait-parens.stderr b/src/test/ui/parser/trait-object-trait-parens.stderr index 4b9f49423cb..7022a66ca1a 100644 --- a/src/test/ui/parser/trait-object-trait-parens.stderr +++ b/src/test/ui/parser/trait-object-trait-parens.stderr @@ -1,44 +1,74 @@ error: `?Trait` is not permitted in trait object types - --> $DIR/trait-object-trait-parens.rs:6:25 + --> $DIR/trait-object-trait-parens.rs:8:24 | -LL | let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>; - | ^^^^^^^^ +LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; + | ^^^^^^^^ error: `?Trait` is not permitted in trait object types - --> $DIR/trait-object-trait-parens.rs:11:47 + --> $DIR/trait-object-trait-parens.rs:12:17 | -LL | let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>; - | ^^^^^^^^ +LL | let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>; + | ^^^^^^ + +error: `?Trait` is not permitted in trait object types + --> $DIR/trait-object-trait-parens.rs:16:46 + | +LL | let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>; + | ^^^^^^^^ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/trait-object-trait-parens.rs:6:16 + --> $DIR/trait-object-trait-parens.rs:8:16 | -LL | let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (Copy) + (?Sized) + (for<'a> Trait<'a>)` +LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (Obj) + (?Sized) + (for<'a> Trait<'a>)` | = note: `#[warn(bare_trait_objects)]` on by default warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/trait-object-trait-parens.rs:9:16 + --> $DIR/trait-object-trait-parens.rs:12:16 | -LL | let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Copy)>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (?Sized) + (for<'a> Trait<'a>) + (Copy)` +LL | let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (?Sized) + (for<'a> Trait<'a>) + (Obj)` warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/trait-object-trait-parens.rs:11:16 + --> $DIR/trait-object-trait-parens.rs:16:16 + | +LL | let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (for<'a> Trait<'a>) + (Obj) + (?Sized)` + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-object-trait-parens.rs:8:35 + | +LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; + | ----- ^^^^^^^^^^^^^^^^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-object-trait-parens.rs:12:49 | -LL | let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (for<'a> Trait<'a>) + (Copy) + (?Sized)` +LL | let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>; + | ------------------- ^^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/trait-object-trait-parens.rs:11:31 +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-object-trait-parens.rs:16:38 | -LL | fn main() { - | - help: consider introducing lifetime `'a` here: `<'a>` -... -LL | let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>; - | ^^ undeclared lifetime +LL | let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>; + | ----------------- ^^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) -error: aborting due to 3 previous errors +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0261`. +For more information about this error, try `rustc --explain E0225`. diff --git a/src/test/ui/unsafe/unsafe-block-without-braces.stderr b/src/test/ui/unsafe/unsafe-block-without-braces.stderr index 13e0c3681fa..895f33638f9 100644 --- a/src/test/ui/unsafe/unsafe-block-without-braces.stderr +++ b/src/test/ui/unsafe/unsafe-block-without-braces.stderr @@ -1,10 +1,11 @@ error: expected `{`, found `std` --> $DIR/unsafe-block-without-braces.rs:3:9 | -LL | unsafe //{ - | - expected `{` LL | std::mem::transmute::<f32, u32>(1.0); - | ^^^ unexpected token + | ^^^---------------------------------- + | | + | expected `{` + | help: try placing this code inside a block: `{ std::mem::transmute::<f32, u32>(1.0); }` error: aborting due to previous error |
