diff options
47 files changed, 591 insertions, 321 deletions
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 6976999c0e4..809d6447908 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -453,7 +453,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; for elem in place_ref.projection[base..].iter() { cg_base = match elem.clone() { - mir::ProjectionElem::Deref => bx.load_operand(cg_base).deref(bx.cx()), + mir::ProjectionElem::Deref => { + // custom allocators can change box's abi, making it unable to be derefed directly + if cg_base.layout.ty.is_box() + && matches!(cg_base.layout.abi, Abi::Aggregate { .. } | Abi::Uninhabited) + { + let ptr = cg_base.project_field(bx, 0).project_field(bx, 0); + + bx.load_operand(ptr).deref(bx.cx()) + } else { + bx.load_operand(cg_base).deref(bx.cx()) + } + } mir::ProjectionElem::Field(ref field, _) => { cg_base.project_field(bx, field.index()) } diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index a72681dbf4e..a185902123d 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -429,6 +429,7 @@ E0720: include_str!("./error_codes/E0720.md"), E0722: include_str!("./error_codes/E0722.md"), E0724: include_str!("./error_codes/E0724.md"), E0725: include_str!("./error_codes/E0725.md"), +E0726: include_str!("./error_codes/E0726.md"), E0727: include_str!("./error_codes/E0727.md"), E0728: include_str!("./error_codes/E0728.md"), E0729: include_str!("./error_codes/E0729.md"), @@ -641,6 +642,5 @@ E0787: include_str!("./error_codes/E0787.md"), E0717, // rustc_promotable without stability attribute // E0721, // `await` keyword // E0723, // unstable feature in `const` context - E0726, // non-explicit (not `'_`) elided lifetime in unsupported position // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. } diff --git a/compiler/rustc_error_codes/src/error_codes/E0726.md b/compiler/rustc_error_codes/src/error_codes/E0726.md new file mode 100644 index 00000000000..e3794327f2d --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0726.md @@ -0,0 +1,46 @@ +An argument lifetime was elided in an async function. + +Erroneous code example: + +When a struct or a type is bound/declared with a lifetime it is important for +the Rust compiler to know, on usage, the lifespan of the type. When the +lifetime is not explicitly mentioned and the Rust Compiler cannot determine +the lifetime of your type, the following error occurs. + +```compile_fail,E0726 +use futures::executor::block_on; +struct Content<'a> { + title: &'a str, + body: &'a str, +} +async fn create(content: Content) { // error: implicit elided + // lifetime not allowed here + println!("title: {}", content.title); + println!("body: {}", content.body); +} +let content = Content { title: "Rust", body: "is great!" }; +let future = create(content); +block_on(future); +``` + +Specify desired lifetime of parameter `content` or indicate the anonymous +lifetime like `content: Content<'_>`. The anonymous lifetime tells the Rust +compiler that `content` is only needed until create function is done with +it's execution. + +The `implicit elision` meaning the omission of suggested lifetime that is +`pub async fn create<'a>(content: Content<'a>) {}` is not allowed here as +lifetime of the `content` can differ from current context: + +```ignore (needs futures dependency) +async fn create(content: Content<'_>) { // ok! + println!("title: {}", content.title); + println!("body: {}", content.body); +} +``` + +Know more about lifetime elision in this [chapter][lifetime-elision] and a +chapter on lifetimes can be found [here][lifetimes]. + +[lifetime-elision]: https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#lifetime-elision +[lifetimes]: https://doc.rust-lang.org/rust-by-example/scope/lifetime.html diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index bdc9c064a6f..ab3951d7683 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -20,7 +20,7 @@ use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, PResult}; use rustc_feature::Features; use rustc_parse::parser::{ - AttemptLocalParseRecovery, ForceCollect, Parser, RecoverColon, RecoverComma, + AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma, }; use rustc_parse::validate_attr; use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS}; @@ -911,6 +911,7 @@ pub fn parse_ast_fragment<'a>( None, RecoverComma::No, RecoverColon::Yes, + CommaRecoveryMode::LikelyTuple, )?), AstFragmentKind::Crate => AstFragment::Crate(this.parse_crate_mod()?), AstFragmentKind::Arms diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index 6233549dc85..8318aec8726 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -282,14 +282,13 @@ struct TokenStreamBuilder { impl TokenStreamBuilder { fn push(&mut self, (tree, joint): TreeAndSpacing) { - if let Some((TokenTree::Token(prev_token), Joint)) = self.buf.last() { - if let TokenTree::Token(token) = &tree { - if let Some(glued) = prev_token.glue(token) { - self.buf.pop(); - self.buf.push((TokenTree::Token(glued), joint)); - return; - } - } + if let Some((TokenTree::Token(prev_token), Joint)) = self.buf.last() + && let TokenTree::Token(token) = &tree + && let Some(glued) = prev_token.glue(token) + { + self.buf.pop(); + self.buf.push((TokenTree::Token(glued), joint)); + return; } self.buf.push((tree, joint)) } diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index eb0d1a12c77..5c95a9e7bb6 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -1,9 +1,10 @@ //! The main parser interface. #![feature(array_windows)] +#![feature(box_patterns)] #![feature(crate_visibility_modifier)] #![feature(if_let_guard)] -#![feature(box_patterns)] +#![feature(let_chains)] #![feature(let_else)] #![recursion_limit = "256"] diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 50310b28f9a..c92785bd9af 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1,8 +1,8 @@ use super::pat::Expected; use super::ty::{AllowPlus, IsAsCast}; use super::{ - BlockMode, Parser, PathStyle, RecoverColon, RecoverComma, Restrictions, SemiColonMode, SeqSep, - TokenExpectType, TokenType, + BlockMode, CommaRecoveryMode, Parser, PathStyle, RecoverColon, RecoverComma, Restrictions, + SemiColonMode, SeqSep, TokenExpectType, TokenType, }; use rustc_ast as ast; @@ -732,43 +732,42 @@ impl<'a> Parser<'a> { mut e: DiagnosticBuilder<'a, ErrorReported>, expr: &mut P<Expr>, ) -> PResult<'a, ()> { - if let ExprKind::Binary(binop, _, _) = &expr.kind { - if let ast::BinOpKind::Lt = binop.node { - if self.eat(&token::Comma) { - let x = self.parse_seq_to_before_end( - &token::Gt, - SeqSep::trailing_allowed(token::Comma), - |p| p.parse_generic_arg(None), - ); - match x { - Ok((_, _, false)) => { - if self.eat(&token::Gt) { - e.span_suggestion_verbose( - binop.span.shrink_to_lo(), - TURBOFISH_SUGGESTION_STR, - "::".to_string(), - Applicability::MaybeIncorrect, - ) - .emit(); - match self.parse_expr() { - Ok(_) => { - *expr = - self.mk_expr_err(expr.span.to(self.prev_token.span)); - return Ok(()); - } - Err(err) => { - *expr = self.mk_expr_err(expr.span); - err.cancel(); - } - } + if let ExprKind::Binary(binop, _, _) = &expr.kind + && let ast::BinOpKind::Lt = binop.node + && self.eat(&token::Comma) + { + let x = self.parse_seq_to_before_end( + &token::Gt, + SeqSep::trailing_allowed(token::Comma), + |p| p.parse_generic_arg(None), + ); + match x { + Ok((_, _, false)) => { + if self.eat(&token::Gt) { + e.span_suggestion_verbose( + binop.span.shrink_to_lo(), + TURBOFISH_SUGGESTION_STR, + "::".to_string(), + Applicability::MaybeIncorrect, + ) + .emit(); + match self.parse_expr() { + Ok(_) => { + *expr = + self.mk_expr_err(expr.span.to(self.prev_token.span)); + return Ok(()); + } + Err(err) => { + *expr = self.mk_expr_err(expr.span); + err.cancel(); } } - Err(err) => { - err.cancel(); - } - _ => {} } } + Err(err) => { + err.cancel(); + } + _ => {} } } Err(e) @@ -784,12 +783,13 @@ impl<'a> Parser<'a> { outer_op: &Spanned<AssocOp>, ) -> bool /* advanced the cursor */ { if let ExprKind::Binary(op, ref l1, ref r1) = inner_op.kind { - if let ExprKind::Field(_, ident) = l1.kind { - if ident.as_str().parse::<i32>().is_err() && !matches!(r1.kind, ExprKind::Lit(_)) { - // The parser has encountered `foo.bar<baz`, the likelihood of the turbofish - // suggestion being the only one to apply is high. - return false; - } + if let ExprKind::Field(_, ident) = l1.kind + && ident.as_str().parse::<i32>().is_err() + && !matches!(r1.kind, ExprKind::Lit(_)) + { + // The parser has encountered `foo.bar<baz`, the likelihood of the turbofish + // suggestion being the only one to apply is high. + return false; } let mut enclose = |left: Span, right: Span| { err.multipart_suggestion( @@ -2245,12 +2245,32 @@ impl<'a> Parser<'a> { first_pat } + crate fn maybe_recover_unexpected_block_label(&mut self) -> bool { + let Some(label) = self.eat_label().filter(|_| { + self.eat(&token::Colon) && self.token.kind == token::OpenDelim(token::Brace) + }) else { + return false; + }; + let span = label.ident.span.to(self.prev_token.span); + let mut err = self.struct_span_err(span, "block label not supported here"); + err.span_label(span, "not supported here"); + err.tool_only_span_suggestion( + label.ident.span.until(self.token.span), + "remove this block label", + String::new(), + Applicability::MachineApplicable, + ); + err.emit(); + true + } + /// Some special error handling for the "top-level" patterns in a match arm, /// `for` loop, `let`, &c. (in contrast to subpatterns within such). crate fn maybe_recover_unexpected_comma( &mut self, lo: Span, rc: RecoverComma, + rt: CommaRecoveryMode, ) -> PResult<'a, ()> { if rc == RecoverComma::No || self.token != token::Comma { return Ok(()); @@ -2270,20 +2290,25 @@ impl<'a> Parser<'a> { let seq_span = lo.to(self.prev_token.span); let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { - const MSG: &str = "try adding parentheses to match on a tuple..."; - - err.span_suggestion( - seq_span, - MSG, - format!("({})", seq_snippet), - Applicability::MachineApplicable, - ); - err.span_suggestion( - seq_span, - "...or a vertical bar to match on multiple alternatives", - seq_snippet.replace(',', " |"), + err.multipart_suggestion( + &format!( + "try adding parentheses to match on a tuple{}", + if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." }, + ), + vec![ + (seq_span.shrink_to_lo(), "(".to_string()), + (seq_span.shrink_to_hi(), ")".to_string()), + ], Applicability::MachineApplicable, ); + if let CommaRecoveryMode::EitherTupleOrPipe = rt { + err.span_suggestion( + seq_span, + "...or a vertical bar to match on multiple alternatives", + seq_snippet.replace(',', " |"), + Applicability::MachineApplicable, + ); + } } Err(err) } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index a11cb3f5677..a54ab4a92e1 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,4 +1,4 @@ -use super::pat::{RecoverColon, RecoverComma, PARAM_EXPECTED}; +use super::pat::{CommaRecoveryMode, RecoverColon, RecoverComma, PARAM_EXPECTED}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{ AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions, TokenType, @@ -1286,18 +1286,27 @@ impl<'a> Parser<'a> { } else if let Some(label) = self.eat_label() { self.parse_labeled_expr(label, attrs, true) } else if self.eat_keyword(kw::Loop) { - self.parse_loop_expr(None, self.prev_token.span, attrs) + let sp = self.prev_token.span; + self.parse_loop_expr(None, self.prev_token.span, attrs).map_err(|mut err| { + err.span_label(sp, "while parsing this `loop` expression"); + err + }) } else if self.eat_keyword(kw::Continue) { let kind = ExprKind::Continue(self.eat_label()); Ok(self.mk_expr(lo.to(self.prev_token.span), kind, attrs)) } else if self.eat_keyword(kw::Match) { let match_sp = self.prev_token.span; self.parse_match_expr(attrs).map_err(|mut err| { - err.span_label(match_sp, "while parsing this match expression"); + err.span_label(match_sp, "while parsing this `match` expression"); err }) } else if self.eat_keyword(kw::Unsafe) { + let sp = self.prev_token.span; self.parse_block_expr(None, lo, BlockCheckMode::Unsafe(ast::UserProvided), attrs) + .map_err(|mut err| { + err.span_label(sp, "while parsing this `unsafe` expression"); + err + }) } else if self.check_inline_const(0) { self.parse_const_block(lo.to(self.token.span), false) } else if self.is_do_catch_block() { @@ -2160,7 +2169,12 @@ impl<'a> Parser<'a> { /// The `let` token has already been eaten. fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> { let lo = self.prev_token.span; - let pat = self.parse_pat_allow_top_alt(None, RecoverComma::Yes, RecoverColon::Yes)?; + let pat = self.parse_pat_allow_top_alt( + None, + RecoverComma::Yes, + RecoverColon::Yes, + CommaRecoveryMode::LikelyTuple, + )?; self.expect(&token::Eq)?; let expr = self.with_res(self.restrictions | Restrictions::NO_STRUCT_LITERAL, |this| { this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into()) @@ -2223,7 +2237,12 @@ impl<'a> Parser<'a> { _ => None, }; - let pat = self.parse_pat_allow_top_alt(None, RecoverComma::Yes, RecoverColon::Yes)?; + let pat = self.parse_pat_allow_top_alt( + None, + RecoverComma::Yes, + RecoverColon::Yes, + CommaRecoveryMode::LikelyTuple, + )?; if !self.eat_keyword(kw::In) { self.error_missing_in_for_loop(); } @@ -2266,8 +2285,15 @@ impl<'a> Parser<'a> { lo: Span, mut attrs: AttrVec, ) -> PResult<'a, P<Expr>> { - let cond = self.parse_cond_expr()?; - let (iattrs, body) = self.parse_inner_attrs_and_block()?; + let cond = self.parse_cond_expr().map_err(|mut err| { + err.span_label(lo, "while parsing the condition of this `while` expression"); + err + })?; + let (iattrs, body) = self.parse_inner_attrs_and_block().map_err(|mut err| { + err.span_label(lo, "while parsing the body of this `while` expression"); + err.span_label(cond.span, "this `while` condition successfully parsed"); + err + })?; attrs.extend(iattrs); Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::While(cond, body, opt_label), attrs)) } @@ -2284,7 +2310,7 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::Loop(body, opt_label), attrs)) } - fn eat_label(&mut self) -> Option<Label> { + crate fn eat_label(&mut self) -> Option<Label> { self.token.lifetime().map(|ident| { self.bump(); Label { ident } @@ -2305,7 +2331,12 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, // speculative ); } - return Err(e); + if self.maybe_recover_unexpected_block_label() { + e.cancel(); + self.bump(); + } else { + return Err(e); + } } attrs.extend(self.parse_inner_attributes()?); @@ -2441,7 +2472,12 @@ impl<'a> Parser<'a> { let attrs = self.parse_outer_attributes()?; self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { let lo = this.token.span; - let pat = this.parse_pat_allow_top_alt(None, RecoverComma::Yes, RecoverColon::Yes)?; + let pat = this.parse_pat_allow_top_alt( + None, + RecoverComma::Yes, + RecoverColon::Yes, + CommaRecoveryMode::EitherTupleOrPipe, + )?; let guard = if this.eat_keyword(kw::If) { let if_span = this.prev_token.span; let cond = this.parse_expr()?; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index bd349e89482..af5cc0e0948 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -102,14 +102,12 @@ impl<'a> Parser<'a> { ) -> PResult<'a, Option<Item>> { // Don't use `maybe_whole` so that we have precise control // over when we bump the parser - if let token::Interpolated(nt) = &self.token.kind { - if let token::NtItem(item) = &**nt { - let mut item = item.clone(); - self.bump(); + if let token::Interpolated(nt) = &self.token.kind && let token::NtItem(item) = &**nt { + let mut item = item.clone(); + self.bump(); - attrs.prepend_to_nt_inner(&mut item.attrs); - return Ok(Some(item.into_inner())); - } + attrs.prepend_to_nt_inner(&mut item.attrs); + return Ok(Some(item.into_inner())); }; let mut unclosed_delims = vec![]; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index d8e6d5037bb..9d85be93b1d 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -15,7 +15,7 @@ pub use attr_wrapper::AttrWrapper; pub use diagnostics::AttemptLocalParseRecovery; use diagnostics::Error; pub(crate) use item::FnParseMode; -pub use pat::{RecoverColon, RecoverComma}; +pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; pub use path::PathStyle; use rustc_ast::ptr::P; @@ -97,15 +97,15 @@ macro_rules! maybe_whole { #[macro_export] macro_rules! maybe_recover_from_interpolated_ty_qpath { ($self: expr, $allow_qpath_recovery: expr) => { - if $allow_qpath_recovery && $self.look_ahead(1, |t| t == &token::ModSep) { - if let token::Interpolated(nt) = &$self.token.kind { - if let token::NtTy(ty) = &**nt { + if $allow_qpath_recovery + && $self.look_ahead(1, |t| t == &token::ModSep) + && let token::Interpolated(nt) = &$self.token.kind + && let token::NtTy(ty) = &**nt + { let ty = ty.clone(); $self.bump(); return $self.maybe_recover_from_bad_qpath_stage_2($self.prev_token.span, ty); } - } - } }; } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 72e6f8a1bc8..83e0a4997ad 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -5,7 +5,7 @@ use rustc_ast_pretty::pprust; use rustc_errors::PResult; use rustc_span::symbol::{kw, Ident}; -use crate::parser::pat::{RecoverColon, RecoverComma}; +use crate::parser::pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; use crate::parser::{FollowedByType, ForceCollect, Parser, PathStyle}; impl<'a> Parser<'a> { @@ -125,7 +125,7 @@ impl<'a> Parser<'a> { token::NtPat(self.collect_tokens_no_attrs(|this| match kind { NonterminalKind::PatParam { .. } => this.parse_pat_no_top_alt(None), NonterminalKind::PatWithOr { .. } => { - this.parse_pat_allow_top_alt(None, RecoverComma::No, RecoverColon::No) + this.parse_pat_allow_top_alt(None, RecoverComma::No, RecoverColon::No, CommaRecoveryMode::EitherTupleOrPipe) } _ => unreachable!(), })?) diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index d4129871145..ff536d15cbf 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -33,6 +33,13 @@ pub enum RecoverColon { No, } +/// Whether or not to recover a `a, b` when parsing patterns as `(a, b)` or that *and* `a | b`. +#[derive(PartialEq, Copy, Clone)] +pub enum CommaRecoveryMode { + LikelyTuple, + EitherTupleOrPipe, +} + /// The result of `eat_or_separator`. We want to distinguish which case we are in to avoid /// emitting duplicate diagnostics. #[derive(Debug, Clone, Copy)] @@ -68,8 +75,9 @@ impl<'a> Parser<'a> { expected: Expected, rc: RecoverComma, ra: RecoverColon, + rt: CommaRecoveryMode, ) -> PResult<'a, P<Pat>> { - self.parse_pat_allow_top_alt_inner(expected, rc, ra).map(|(pat, _)| pat) + self.parse_pat_allow_top_alt_inner(expected, rc, ra, rt).map(|(pat, _)| pat) } /// Returns the pattern and a bool indicating whether we recovered from a trailing vert (true = @@ -79,6 +87,7 @@ impl<'a> Parser<'a> { expected: Expected, rc: RecoverComma, ra: RecoverColon, + rt: CommaRecoveryMode, ) -> PResult<'a, (P<Pat>, bool)> { // Keep track of whether we recovered from a trailing vert so that we can avoid duplicated // suggestions (which bothers rustfix). @@ -92,7 +101,7 @@ impl<'a> Parser<'a> { // Parse the first pattern (`p_0`). let first_pat = self.parse_pat_no_top_alt(expected)?; - self.maybe_recover_unexpected_comma(first_pat.span, rc)?; + self.maybe_recover_unexpected_comma(first_pat.span, rc, rt)?; // If the next token is not a `|`, // this is not an or-pattern and we should exit here. @@ -130,7 +139,7 @@ impl<'a> Parser<'a> { err.span_label(lo, WHILE_PARSING_OR_MSG); err })?; - self.maybe_recover_unexpected_comma(pat.span, rc)?; + self.maybe_recover_unexpected_comma(pat.span, rc, rt)?; pats.push(pat); } let or_pattern_span = lo.to(self.prev_token.span); @@ -155,8 +164,12 @@ impl<'a> Parser<'a> { // We use `parse_pat_allow_top_alt` regardless of whether we actually want top-level // or-patterns so that we can detect when a user tries to use it. This allows us to print a // better error message. - let (pat, trailing_vert) = - self.parse_pat_allow_top_alt_inner(expected, rc, RecoverColon::No)?; + let (pat, trailing_vert) = self.parse_pat_allow_top_alt_inner( + expected, + rc, + RecoverColon::No, + CommaRecoveryMode::LikelyTuple, + )?; let colon = self.eat(&token::Colon); if let PatKind::Or(pats) = &pat.kind { @@ -315,7 +328,12 @@ impl<'a> Parser<'a> { } else if self.check(&token::OpenDelim(token::Bracket)) { // Parse `[pat, pat,...]` as a slice pattern. let (pats, _) = self.parse_delim_comma_seq(token::Bracket, |p| { - p.parse_pat_allow_top_alt(None, RecoverComma::No, RecoverColon::No) + p.parse_pat_allow_top_alt( + None, + RecoverComma::No, + RecoverColon::No, + CommaRecoveryMode::EitherTupleOrPipe, + ) })?; PatKind::Slice(pats) } else if self.check(&token::DotDot) && !self.is_pat_range_end_start(1) { @@ -529,7 +547,12 @@ impl<'a> Parser<'a> { /// Parse a tuple or parenthesis pattern. fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> { let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| { - p.parse_pat_allow_top_alt(None, RecoverComma::No, RecoverColon::No) + p.parse_pat_allow_top_alt( + None, + RecoverComma::No, + RecoverColon::No, + CommaRecoveryMode::LikelyTuple, + ) })?; // Here, `(pat,)` is a tuple pattern. @@ -873,7 +896,12 @@ impl<'a> Parser<'a> { /// Parse tuple struct or tuple variant pattern (e.g. `Foo(...)` or `Foo::Bar(...)`). fn parse_pat_tuple_struct(&mut self, qself: Option<QSelf>, path: Path) -> PResult<'a, PatKind> { let (fields, _) = self.parse_paren_comma_seq(|p| { - p.parse_pat_allow_top_alt(None, RecoverComma::No, RecoverColon::No) + p.parse_pat_allow_top_alt( + None, + RecoverComma::No, + RecoverColon::No, + CommaRecoveryMode::EitherTupleOrPipe, + ) })?; if qself.is_some() { self.sess.gated_spans.gate(sym::more_qualified_paths, path.span); @@ -1033,7 +1061,12 @@ impl<'a> Parser<'a> { // Parsing a pattern of the form `fieldname: pat`. let fieldname = self.parse_field_name()?; self.bump(); - let pat = self.parse_pat_allow_top_alt(None, RecoverComma::No, RecoverColon::No)?; + let pat = self.parse_pat_allow_top_alt( + None, + RecoverComma::No, + RecoverColon::No, + CommaRecoveryMode::EitherTupleOrPipe, + )?; hi = pat.span; (pat, fieldname, false) } else { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 0ffc9d09355..5e537d7b95c 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -658,13 +658,13 @@ impl<'a> Parser<'a> { &self, gen_arg: GenericArg, ) -> Result<(Ident, Option<GenericArgs>), GenericArg> { - if let GenericArg::Type(ty) = &gen_arg { - if let ast::TyKind::Path(qself, path) = &ty.kind { - if qself.is_none() && path.segments.len() == 1 { - let seg = &path.segments[0]; - return Ok((seg.ident, seg.args.as_deref().cloned())); - } - } + if let GenericArg::Type(ty) = &gen_arg + && let ast::TyKind::Path(qself, path) = &ty.kind + && qself.is_none() + && path.segments.len() == 1 + { + let seg = &path.segments[0]; + return Ok((seg.ident, seg.args.as_deref().cloned())); } Err(gen_arg) } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 6b195285243..e39e32ff364 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -48,15 +48,13 @@ impl<'a> Parser<'a> { // Don't use `maybe_whole` so that we have precise control // over when we bump the parser - if let token::Interpolated(nt) = &self.token.kind { - if let token::NtStmt(stmt) = &**nt { - let mut stmt = stmt.clone(); - self.bump(); - stmt.visit_attrs(|stmt_attrs| { - attrs.prepend_to_nt_inner(stmt_attrs); - }); - return Ok(Some(stmt)); - } + if let token::Interpolated(nt) = &self.token.kind && let token::NtStmt(stmt) = &**nt { + let mut stmt = stmt.clone(); + self.bump(); + stmt.visit_attrs(|stmt_attrs| { + attrs.prepend_to_nt_inner(stmt_attrs); + }); + return Ok(Some(stmt)); } Ok(Some(if self.token.is_keyword(kw::Let) { @@ -434,6 +432,8 @@ impl<'a> Parser<'a> { Ok(Some(_)) if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace)) || do_not_suggest_help => {} + // Do not suggest `if foo println!("") {;}` (as would be seen in test for #46836). + Ok(Some(Stmt { kind: StmtKind::Empty, .. })) => {} 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) { @@ -442,15 +442,15 @@ impl<'a> Parser<'a> { } 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, - ); - } + e.multipart_suggestion( + "try placing this code inside a block", + vec![ + (stmt_span.shrink_to_lo(), "{ ".to_string()), + (stmt_span.shrink_to_hi(), " }".to_string()), + ], + // Speculative; has been misleading in the past (#46836). + Applicability::MaybeIncorrect, + ); } Err(e) => { self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); @@ -483,15 +483,15 @@ impl<'a> Parser<'a> { ) -> PResult<'a, (Vec<Attribute>, P<Block>)> { maybe_whole!(self, NtBlock, |x| (Vec::new(), x)); + self.maybe_recover_unexpected_block_label(); if !self.eat(&token::OpenDelim(token::Brace)) { return self.error_block_no_opening_brace(); } let attrs = self.parse_inner_attributes()?; - let tail = if let Some(tail) = self.maybe_suggest_struct_literal(lo, blk_mode) { - tail? - } else { - self.parse_block_tail(lo, blk_mode, AttemptLocalParseRecovery::Yes)? + let tail = match self.maybe_suggest_struct_literal(lo, blk_mode) { + Some(tail) => tail?, + None => self.parse_block_tail(lo, blk_mode, AttemptLocalParseRecovery::Yes)?, }; Ok((attrs, tail)) } @@ -587,11 +587,11 @@ impl<'a> Parser<'a> { // We might be at the `,` in `let x = foo<bar, baz>;`. Try to recover. match &mut local.kind { LocalKind::Init(expr) | LocalKind::InitElse(expr, _) => { - self.check_mistyped_turbofish_with_multiple_type_params(e, expr)?; - // We found `foo<bar, baz>`, have we fully recovered? - self.expect_semi()?; - } - LocalKind::Decl => return Err(e), + self.check_mistyped_turbofish_with_multiple_type_params(e, expr)?; + // We found `foo<bar, baz>`, have we fully recovered? + self.expect_semi()?; + } + LocalKind::Decl => return Err(e), } eat_semi = false; } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 14a1318517a..f3aa40b9ad1 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -840,7 +840,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); err.span_label(lhs.span, "cannot assign to this expression"); - let mut parent = self.tcx.hir().get_parent_node(lhs.hir_id); + self.comes_from_while_condition(lhs.hir_id, |expr| { + err.span_suggestion_verbose( + expr.span.shrink_to_lo(), + "you might have meant to use pattern destructuring", + "let ".to_string(), + Applicability::MachineApplicable, + ); + }); + + err.emit(); + } + + // Check if an expression `original_expr_id` comes from the condition of a while loop, + // as opposed from the body of a while loop, which we can naively check by iterating + // parents until we find a loop... + pub(super) fn comes_from_while_condition( + &self, + original_expr_id: HirId, + then: impl FnOnce(&hir::Expr<'_>), + ) { + let mut parent = self.tcx.hir().get_parent_node(original_expr_id); while let Some(node) = self.tcx.hir().find(parent) { match node { hir::Node::Expr(hir::Expr { @@ -861,8 +881,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), .. }) => { - // Check if our lhs is a child of the condition of a while loop - let expr_is_ancestor = std::iter::successors(Some(lhs.hir_id), |id| { + // Check if our original expression is a child of the condition of a while loop + let expr_is_ancestor = std::iter::successors(Some(original_expr_id), |id| { self.tcx.hir().find_parent_node(*id) }) .take_while(|id| *id != parent) @@ -870,12 +890,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // if it is, then we have a situation like `while Some(0) = value.get(0) {`, // where `while let` was more likely intended. if expr_is_ancestor { - err.span_suggestion_verbose( - expr.span.shrink_to_lo(), - "you might have meant to use pattern destructuring", - "let ".to_string(), - Applicability::MachineApplicable, - ); + then(expr); } break; } @@ -888,8 +903,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - - err.emit(); } // A generic function for checking the 'then' and 'else' clauses in an 'if' diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 76339998a2f..f5d110903e6 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -768,55 +768,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let prev_diverges = self.diverges.get(); let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false }; - let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || { - for (pos, s) in blk.stmts.iter().enumerate() { - self.check_stmt(s, blk.stmts.len() - 1 == pos); - } + let (ctxt, ()) = + self.with_breakable_ctxt(blk.hir_id, ctxt, || { + for (pos, s) in blk.stmts.iter().enumerate() { + self.check_stmt(s, blk.stmts.len() - 1 == pos); + } - // check the tail expression **without** holding the - // `enclosing_breakables` lock below. - let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected)); - - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - let ctxt = enclosing_breakables.find_breakable(blk.hir_id); - let coerce = ctxt.coerce.as_mut().unwrap(); - if let Some(tail_expr_ty) = tail_expr_ty { - let tail_expr = tail_expr.unwrap(); - let span = self.get_expr_coercion_span(tail_expr); - let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id)); - coerce.coerce(self, &cause, tail_expr, tail_expr_ty); - } else { - // Subtle: if there is no explicit tail expression, - // that is typically equivalent to a tail expression - // of `()` -- except if the block diverges. In that - // case, there is no value supplied from the tail - // expression (assuming there are no other breaks, - // this implies that the type of the block will be - // `!`). - // - // #41425 -- label the implicit `()` as being the - // "found type" here, rather than the "expected type". - if !self.diverges.get().is_always() { - // #50009 -- Do not point at the entire fn block span, point at the return type - // span, as it is the cause of the requirement, and - // `consider_hint_about_removing_semicolon` will point at the last expression - // if it were a relevant part of the error. This improves usability in editors - // that highlight errors inline. - let mut sp = blk.span; - let mut fn_span = None; - if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) { - let ret_sp = decl.output.span(); - if let Some(block_sp) = self.parent_item_span(blk.hir_id) { - // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the - // output would otherwise be incorrect and even misleading. Make sure - // the span we're aiming at correspond to a `fn` body. - if block_sp == blk.span { - sp = ret_sp; - fn_span = Some(ident.span); + // check the tail expression **without** holding the + // `enclosing_breakables` lock below. + let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected)); + + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + let ctxt = enclosing_breakables.find_breakable(blk.hir_id); + let coerce = ctxt.coerce.as_mut().unwrap(); + if let Some(tail_expr_ty) = tail_expr_ty { + let tail_expr = tail_expr.unwrap(); + let span = self.get_expr_coercion_span(tail_expr); + let cause = + self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id)); + coerce.coerce(self, &cause, tail_expr, tail_expr_ty); + } else { + // Subtle: if there is no explicit tail expression, + // that is typically equivalent to a tail expression + // of `()` -- except if the block diverges. In that + // case, there is no value supplied from the tail + // expression (assuming there are no other breaks, + // this implies that the type of the block will be + // `!`). + // + // #41425 -- label the implicit `()` as being the + // "found type" here, rather than the "expected type". + if !self.diverges.get().is_always() { + // #50009 -- Do not point at the entire fn block span, point at the return type + // span, as it is the cause of the requirement, and + // `consider_hint_about_removing_semicolon` will point at the last expression + // if it were a relevant part of the error. This improves usability in editors + // that highlight errors inline. + let mut sp = blk.span; + let mut fn_span = None; + if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) { + let ret_sp = decl.output.span(); + if let Some(block_sp) = self.parent_item_span(blk.hir_id) { + // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the + // output would otherwise be incorrect and even misleading. Make sure + // the span we're aiming at correspond to a `fn` body. + if block_sp == blk.span { + sp = ret_sp; + fn_span = Some(ident.span); + } } } - } - coerce.coerce_forced_unit( + coerce.coerce_forced_unit( self, &self.misc(sp), &mut |err| { @@ -825,19 +827,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if expected_ty == self.tcx.types.bool { // If this is caused by a missing `let` in a `while let`, // silence this redundant error, as we already emit E0070. - let parent = self.tcx.hir().get_parent_node(blk.hir_id); - let parent = self.tcx.hir().get_parent_node(parent); - let parent = self.tcx.hir().get_parent_node(parent); - let parent = self.tcx.hir().get_parent_node(parent); - let parent = self.tcx.hir().get_parent_node(parent); - match self.tcx.hir().find(parent) { - Some(hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Loop(_, _, hir::LoopSource::While, _), - .. - })) => { + + // Our block must be a `assign desugar local; assignment` + if let Some(hir::Node::Block(hir::Block { + stmts: + [hir::Stmt { + kind: + hir::StmtKind::Local(hir::Local { + source: hir::LocalSource::AssignDesugar(_), + .. + }), + .. + }, hir::Stmt { + kind: + hir::StmtKind::Expr(hir::Expr { + kind: hir::ExprKind::Assign(..), + .. + }), + .. + }], + .. + })) = self.tcx.hir().find(blk.hir_id) + { + self.comes_from_while_condition(blk.hir_id, |_| { err.downgrade_to_delayed_bug(); - } - _ => {} + }) } } } @@ -851,9 +865,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, false, ); + } } - } - }); + }); if ctxt.may_break { // If we can break from the block, then the block's exit is always reachable diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 67f5b386ecd..7890c1040f0 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -986,7 +986,7 @@ impl<K, V> BTreeMap<K, V> { self.drain_filter(|k, v| !f(k, v)); } - /// Moves all elements from `other` into `Self`, leaving `other` empty. + /// Moves all elements from `other` into `self`, leaving `other` empty. /// /// # Examples /// diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 3031bf86a7b..bab6af82698 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -895,7 +895,7 @@ impl<T> BTreeSet<T> { self.drain_filter(|v| !f(v)); } - /// Moves all elements from `other` into `Self`, leaving `other` empty. + /// Moves all elements from `other` into `self`, leaving `other` empty. /// /// # Examples /// diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index c29aa0fec5b..c4c393f55ee 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1763,7 +1763,7 @@ impl<T, A: Allocator> Vec<T, A> { } } - /// Moves all the elements of `other` into `Self`, leaving `other` empty. + /// Moves all the elements of `other` into `self`, leaving `other` empty. /// /// # Panics /// @@ -1788,7 +1788,7 @@ impl<T, A: Allocator> Vec<T, A> { } } - /// Appends elements to `Self` from other buffer. + /// Appends elements to `self` from other buffer. #[cfg(not(no_global_oom_handling))] #[inline] unsafe fn append_elements(&mut self, other: *const [T]) { diff --git a/src/test/ui/async-await/async-fn-path-elision.stderr b/src/test/ui/async-await/async-fn-path-elision.stderr index 36fb73a8dde..3d18d9c4125 100644 --- a/src/test/ui/async-await/async-fn-path-elision.stderr +++ b/src/test/ui/async-await/async-fn-path-elision.stderr @@ -8,3 +8,4 @@ LL | async fn error(lt: HasLifetime) { error: aborting due to previous error +For more information about this error, try `rustc --explain E0726`. diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr index b4323c314ba..b30f2883732 100644 --- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -132,7 +132,7 @@ error: expected one of `.`, `?`, `{`, or an operator, found `}` LL | match await { await => () } | ----- - expected one of `.`, `?`, `{`, or an operator | | - | while parsing this match expression + | while parsing this `match` expression ... LL | } | ^ unexpected token diff --git a/src/test/ui/box/issue-78459-ice.rs b/src/test/ui/box/issue-78459-ice.rs deleted file mode 100644 index 89f75fea15b..00000000000 --- a/src/test/ui/box/issue-78459-ice.rs +++ /dev/null @@ -1,6 +0,0 @@ -// check-pass -#![feature(allocator_api)] - -fn main() { - Box::new_in((), &std::alloc::Global); -} diff --git a/src/test/ui/box/large-allocator-ice.rs b/src/test/ui/box/large-allocator-ice.rs new file mode 100644 index 00000000000..3ef1171ff50 --- /dev/null +++ b/src/test/ui/box/large-allocator-ice.rs @@ -0,0 +1,23 @@ +// build-pass +#![feature(allocator_api)] + +use std::alloc::Allocator; + +struct BigAllocator([usize; 2]); + +unsafe impl Allocator for BigAllocator { + fn allocate( + &self, + _: std::alloc::Layout, + ) -> Result<std::ptr::NonNull<[u8]>, std::alloc::AllocError> { + todo!() + } + unsafe fn deallocate(&self, _: std::ptr::NonNull<u8>, _: std::alloc::Layout) { + todo!() + } +} + +fn main() { + Box::new_in((), &std::alloc::Global); + Box::new_in((), BigAllocator([0; 2])); +} diff --git a/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr b/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr index 8025886a9eb..609a5efd46f 100644 --- a/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr +++ b/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr @@ -28,10 +28,7 @@ error: expected `{`, found `;` LL | if not // lack of braces is [sic] | -- this `if` expression has a condition, but no block LL | println!("Then when?"); - | ^ - | | - | expected `{` - | help: try placing this code inside a block: `{ ; }` + | ^ expected `{` error: unexpected `2` after identifier --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:26:24 diff --git a/src/test/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr b/src/test/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr index c2e3ead7ec7..a3c607b5903 100644 --- a/src/test/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr +++ b/src/test/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr @@ -2,16 +2,14 @@ error: unexpected `,` in pattern --> $DIR/issue-48492-tuple-destructure-missing-parens.rs:38:17 | LL | while let b1, b2, b3 = reading_frame.next().expect("there should be a start codon") { - | ^ + | ----- ^ + | | + | while parsing the condition of this `while` expression | -help: try adding parentheses to match on a tuple... +help: try adding parentheses to match on a tuple | LL | while let (b1, b2, b3) = reading_frame.next().expect("there should be a start codon") { - | ~~~~~~~~~~~~ -help: ...or a vertical bar to match on multiple alternatives - | -LL | while let b1 | b2 | b3 = reading_frame.next().expect("there should be a start codon") { - | ~~~~~~~~~~~~ + | + + error: unexpected `,` in pattern --> $DIR/issue-48492-tuple-destructure-missing-parens.rs:49:14 @@ -19,14 +17,10 @@ error: unexpected `,` in pattern LL | if let b1, b2, b3 = reading_frame.next().unwrap() { | ^ | -help: try adding parentheses to match on a tuple... +help: try adding parentheses to match on a tuple | LL | if let (b1, b2, b3) = reading_frame.next().unwrap() { - | ~~~~~~~~~~~~ -help: ...or a vertical bar to match on multiple alternatives - | -LL | if let b1 | b2 | b3 = reading_frame.next().unwrap() { - | ~~~~~~~~~~~~ + | + + error: unexpected `,` in pattern --> $DIR/issue-48492-tuple-destructure-missing-parens.rs:59:28 @@ -37,7 +31,7 @@ LL | Nucleotide::Adenine, Nucleotide::Cytosine, _ => true help: try adding parentheses to match on a tuple... | LL | (Nucleotide::Adenine, Nucleotide::Cytosine, _) => true - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | + + help: ...or a vertical bar to match on multiple alternatives | LL | Nucleotide::Adenine | Nucleotide::Cytosine | _ => true @@ -49,14 +43,10 @@ error: unexpected `,` in pattern LL | for x, _barr_body in women.iter().map(|woman| woman.allosomes.clone()) { | ^ | -help: try adding parentheses to match on a tuple... +help: try adding parentheses to match on a tuple | LL | for (x, _barr_body) in women.iter().map(|woman| woman.allosomes.clone()) { - | ~~~~~~~~~~~~~~~ -help: ...or a vertical bar to match on multiple alternatives - | -LL | for x | _barr_body in women.iter().map(|woman| woman.allosomes.clone()) { - | ~~~~~~~~~~~~~~ + | + + error: unexpected `,` in pattern --> $DIR/issue-48492-tuple-destructure-missing-parens.rs:75:10 @@ -64,14 +54,10 @@ error: unexpected `,` in pattern LL | for x, y @ Allosome::Y(_) in men.iter().map(|man| man.allosomes.clone()) { | ^ | -help: try adding parentheses to match on a tuple... +help: try adding parentheses to match on a tuple | LL | for (x, y @ Allosome::Y(_)) in men.iter().map(|man| man.allosomes.clone()) { - | ~~~~~~~~~~~~~~~~~~~~~~~ -help: ...or a vertical bar to match on multiple alternatives - | -LL | for x | y @ Allosome::Y(_) in men.iter().map(|man| man.allosomes.clone()) { - | ~~~~~~~~~~~~~~~~~~~~~~ + | + + error: unexpected `,` in pattern --> $DIR/issue-48492-tuple-destructure-missing-parens.rs:84:14 @@ -79,14 +65,10 @@ error: unexpected `,` in pattern LL | let women, men: (Vec<Genome>, Vec<Genome>) = genomes.iter().cloned() | ^ | -help: try adding parentheses to match on a tuple... +help: try adding parentheses to match on a tuple | LL | let (women, men): (Vec<Genome>, Vec<Genome>) = genomes.iter().cloned() - | ~~~~~~~~~~~~ -help: ...or a vertical bar to match on multiple alternatives - | -LL | let women | men: (Vec<Genome>, Vec<Genome>) = genomes.iter().cloned() - | ~~~~~~~~~~~ + | + + error: aborting due to 6 previous errors diff --git a/src/test/ui/impl-header-lifetime-elision/path-elided.stderr b/src/test/ui/impl-header-lifetime-elision/path-elided.stderr index 1c81c696201..90522a885ab 100644 --- a/src/test/ui/impl-header-lifetime-elision/path-elided.stderr +++ b/src/test/ui/impl-header-lifetime-elision/path-elided.stderr @@ -8,3 +8,4 @@ LL | impl MyTrait for Foo { error: aborting due to previous error +For more information about this error, try `rustc --explain E0726`. diff --git a/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr b/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr index 735f01379f0..15bc3f106b9 100644 --- a/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr +++ b/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr @@ -8,3 +8,4 @@ LL | impl MyTrait for u32 { error: aborting due to previous error +For more information about this error, try `rustc --explain E0726`. diff --git a/src/test/ui/issues/issue-10412.stderr b/src/test/ui/issues/issue-10412.stderr index 053a93e6cd8..a91b3c90ebb 100644 --- a/src/test/ui/issues/issue-10412.stderr +++ b/src/test/ui/issues/issue-10412.stderr @@ -67,4 +67,5 @@ LL | trait Serializable<'self, T: ?Sized> { error: aborting due to 9 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0726. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-39848.stderr b/src/test/ui/issues/issue-39848.stderr index 08faed24bc7..feabe3814dc 100644 --- a/src/test/ui/issues/issue-39848.stderr +++ b/src/test/ui/issues/issue-39848.stderr @@ -2,16 +2,18 @@ error: expected `{`, found `foo` --> $DIR/issue-39848.rs:3:21 | LL | if $tgt.has_$field() {} - | -- ^^^^^^-- - | | | - | | expected `{` - | | help: try placing this code inside a block: `{ $field() }` + | -- ^^^^^^ expected `{` + | | | this `if` expression has a condition, but no block ... LL | get_opt!(bar, foo); | ------------------ in this macro invocation | = note: this error originates in the macro `get_opt` (in Nightly builds, run with -Z macro-backtrace for more info) +help: try placing this code inside a block + | +LL | if $tgt.has_{ $field() } {} + | + + error: aborting due to previous error diff --git a/src/test/ui/label/label_break_value_illegal_uses.fixed b/src/test/ui/label/label_break_value_illegal_uses.fixed new file mode 100644 index 00000000000..c1d2023a216 --- /dev/null +++ b/src/test/ui/label/label_break_value_illegal_uses.fixed @@ -0,0 +1,30 @@ +// run-rustfix +#![feature(label_break_value)] + +// These are forbidden occurrences of label-break-value + +#[allow(unused_unsafe)] +fn labeled_unsafe() { + unsafe {} //~ ERROR block label not supported here +} + +fn labeled_if() { + if true {} //~ ERROR block label not supported here +} + +fn labeled_else() { + if true {} else {} //~ ERROR block label not supported here +} + +fn labeled_match() { + match false { //~ ERROR block label not supported here + _ => {} + } +} + +fn main() { + labeled_unsafe(); + labeled_if(); + labeled_else(); + labeled_match(); +} diff --git a/src/test/ui/label/label_break_value_illegal_uses.rs b/src/test/ui/label/label_break_value_illegal_uses.rs index 9d4c72410a6..5b20c95e581 100644 --- a/src/test/ui/label/label_break_value_illegal_uses.rs +++ b/src/test/ui/label/label_break_value_illegal_uses.rs @@ -1,21 +1,30 @@ +// run-rustfix #![feature(label_break_value)] // These are forbidden occurrences of label-break-value +#[allow(unused_unsafe)] fn labeled_unsafe() { - unsafe 'b: {} //~ ERROR expected `{`, found `'b` + unsafe 'b: {} //~ ERROR block label not supported here } fn labeled_if() { - if true 'b: {} //~ ERROR expected `{`, found `'b` + if true 'b: {} //~ ERROR block label not supported here } fn labeled_else() { - if true {} else 'b: {} //~ ERROR expected `{`, found `'b` + if true {} else 'b: {} //~ ERROR block label not supported here } fn labeled_match() { - match false 'b: {} //~ ERROR expected one of `.`, `?`, `{`, or an operator + match false 'b: { //~ ERROR block label not supported here + _ => {} + } } -pub fn main() {} +fn main() { + labeled_unsafe(); + labeled_if(); + labeled_else(); + labeled_match(); +} diff --git a/src/test/ui/label/label_break_value_illegal_uses.stderr b/src/test/ui/label/label_break_value_illegal_uses.stderr index a2c75882be0..24b733fec53 100644 --- a/src/test/ui/label/label_break_value_illegal_uses.stderr +++ b/src/test/ui/label/label_break_value_illegal_uses.stderr @@ -1,38 +1,26 @@ -error: expected `{`, found `'b` - --> $DIR/label_break_value_illegal_uses.rs:6:12 +error: block label not supported here + --> $DIR/label_break_value_illegal_uses.rs:8:12 | LL | unsafe 'b: {} - | ^^---- - | | - | expected `{` - | help: try placing this code inside a block: `{ 'b: {} }` + | ^^^ not supported here -error: expected `{`, found `'b` - --> $DIR/label_break_value_illegal_uses.rs:10:13 +error: block label not supported here + --> $DIR/label_break_value_illegal_uses.rs:12:13 | LL | if true 'b: {} - | -- ^^---- - | | | - | | expected `{` - | | help: try placing this code inside a block: `{ 'b: {} }` - | this `if` expression has a condition, but no block + | ^^^ not supported here -error: expected `{`, found `'b` - --> $DIR/label_break_value_illegal_uses.rs:14:21 +error: block label not supported here + --> $DIR/label_break_value_illegal_uses.rs:16:21 | LL | if true {} else 'b: {} - | ^^---- - | | - | expected `{` - | help: try placing this code inside a block: `{ 'b: {} }` + | ^^^ not supported here -error: expected one of `.`, `?`, `{`, or an operator, found `'b` - --> $DIR/label_break_value_illegal_uses.rs:18:17 +error: block label not supported here + --> $DIR/label_break_value_illegal_uses.rs:20:17 | -LL | match false 'b: {} - | ----- ^^ expected one of `.`, `?`, `{`, or an operator - | | - | while parsing this match expression +LL | match false 'b: { + | ^^^ not supported here error: aborting due to 4 previous errors diff --git a/src/test/ui/let-else/let-else-if.stderr b/src/test/ui/let-else/let-else-if.stderr index 38c739fd850..a0324565673 100644 --- a/src/test/ui/let-else/let-else-if.stderr +++ b/src/test/ui/let-else/let-else-if.stderr @@ -7,10 +7,10 @@ LL | let Some(_) = Some(()) else if true { help: try placing this code inside a block | LL ~ let Some(_) = Some(()) else { if true { -LL + -LL + return; -LL + } else { -LL + return; +LL | +LL | return; +LL | } else { +LL | return; LL ~ } }; | diff --git a/src/test/ui/missing/missing-block-hint.stderr b/src/test/ui/missing/missing-block-hint.stderr index 0f635817bf4..148e214e58e 100644 --- a/src/test/ui/missing/missing-block-hint.stderr +++ b/src/test/ui/missing/missing-block-hint.stderr @@ -12,10 +12,12 @@ error: expected `{`, found `bar` LL | if (foo) | -- this `if` expression has a condition, but no block LL | bar; - | ^^^- - | | - | expected `{` - | help: try placing this code inside a block: `{ bar; }` + | ^^^ expected `{` + | +help: try placing this code inside a block + | +LL | { bar; } + | + + error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/block-no-opening-brace.stderr b/src/test/ui/parser/block-no-opening-brace.stderr index e32c8bdc73a..f232f480ce9 100644 --- a/src/test/ui/parser/block-no-opening-brace.stderr +++ b/src/test/ui/parser/block-no-opening-brace.stderr @@ -1,29 +1,41 @@ error: expected `{`, found keyword `let` --> $DIR/block-no-opening-brace.rs:9:9 | +LL | loop + | ---- while parsing this `loop` expression LL | let x = 0; - | ^^^------- - | | - | expected `{` - | help: try placing this code inside a block: `{ let x = 0; }` + | ^^^ expected `{` + | +help: try placing this code inside a block + | +LL | { let x = 0; } + | + + error: expected `{`, found keyword `let` --> $DIR/block-no-opening-brace.rs:15:9 | +LL | while true + | ----- ---- this `while` condition successfully parsed + | | + | while parsing the body of this `while` expression LL | let x = 0; - | ^^^------- - | | - | expected `{` - | help: try placing this code inside a block: `{ let x = 0; }` + | ^^^ expected `{` + | +help: try placing this code inside a block + | +LL | { 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; }` + | ^^^ expected `{` + | +help: try placing this code inside a block + | +LL | { let x = 0; } + | + + error: expected expression, found reserved keyword `try` --> $DIR/block-no-opening-brace.rs:24:5 diff --git a/src/test/ui/parser/closure-return-syntax.stderr b/src/test/ui/parser/closure-return-syntax.stderr index 1ccdd977305..3d16a2067cc 100644 --- a/src/test/ui/parser/closure-return-syntax.stderr +++ b/src/test/ui/parser/closure-return-syntax.stderr @@ -2,10 +2,12 @@ error: expected `{`, found `22` --> $DIR/closure-return-syntax.rs:5:23 | LL | let x = || -> i32 22; - | ^^ - | | - | expected `{` - | help: try placing this code inside a block: `{ 22 }` + | ^^ expected `{` + | +help: try placing this code inside a block + | +LL | let x = || -> i32 { 22 }; + | + + error: aborting due to previous error diff --git a/src/test/ui/parser/issues/issue-62554.stderr b/src/test/ui/parser/issues/issue-62554.stderr index 5dc9a9675bc..3589016e1dc 100644 --- a/src/test/ui/parser/issues/issue-62554.stderr +++ b/src/test/ui/parser/issues/issue-62554.stderr @@ -63,9 +63,8 @@ LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s | help: try placing this code inside a block | -LL ~ fn foo(u: u8) { if u8 { macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 { -LL + } - | +LL | fn foo(u: u8) { if u8 { macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 { } + | + + error: aborting due to 6 previous errors diff --git a/src/test/ui/parser/issues/issue-62973.stderr b/src/test/ui/parser/issues/issue-62973.stderr index 51d835e7329..871b5d59651 100644 --- a/src/test/ui/parser/issues/issue-62973.stderr +++ b/src/test/ui/parser/issues/issue-62973.stderr @@ -50,7 +50,7 @@ error: expected one of `.`, `?`, `{`, or an operator, found `}` --> $DIR/issue-62973.rs:8:2 | LL | fn p() { match s { v, E { [) {) } - | ----- while parsing this match expression + | ----- while parsing this `match` expression LL | LL | | ^ expected one of `.`, `?`, `{`, or an operator diff --git a/src/test/ui/parser/match-refactor-to-expr.fixed b/src/test/ui/parser/match-refactor-to-expr.fixed index f21024235a5..423147b27aa 100644 --- a/src/test/ui/parser/match-refactor-to-expr.fixed +++ b/src/test/ui/parser/match-refactor-to-expr.fixed @@ -2,7 +2,7 @@ fn main() { let foo = - //~ NOTE while parsing this match expression + //~ NOTE while parsing this `match` expression Some(4).unwrap_or(5) //~^ NOTE expected one of `.`, `?`, `{`, or an operator ; //~ NOTE unexpected token diff --git a/src/test/ui/parser/match-refactor-to-expr.rs b/src/test/ui/parser/match-refactor-to-expr.rs index e02d74e2f7e..fcba5d0447e 100644 --- a/src/test/ui/parser/match-refactor-to-expr.rs +++ b/src/test/ui/parser/match-refactor-to-expr.rs @@ -2,7 +2,7 @@ fn main() { let foo = - match //~ NOTE while parsing this match expression + match //~ NOTE while parsing this `match` expression Some(4).unwrap_or(5) //~^ NOTE expected one of `.`, `?`, `{`, or an operator ; //~ NOTE unexpected token diff --git a/src/test/ui/parser/match-refactor-to-expr.stderr b/src/test/ui/parser/match-refactor-to-expr.stderr index 15107ab9a25..851bef8f2c7 100644 --- a/src/test/ui/parser/match-refactor-to-expr.stderr +++ b/src/test/ui/parser/match-refactor-to-expr.stderr @@ -4,7 +4,7 @@ error: expected one of `.`, `?`, `{`, or an operator, found `;` LL | match | ----- | | - | while parsing this match expression + | while parsing this `match` expression | help: try removing this `match` LL | Some(4).unwrap_or(5) | - expected one of `.`, `?`, `{`, or an operator diff --git a/src/test/ui/parser/while-if-let-without-body.rs b/src/test/ui/parser/while-if-let-without-body.rs new file mode 100644 index 00000000000..063c0145c85 --- /dev/null +++ b/src/test/ui/parser/while-if-let-without-body.rs @@ -0,0 +1,13 @@ +fn main() { + let container = vec![Some(1), Some(2), None]; + + let mut i = 0; + while if let Some(thing) = container.get(i) { + //~^ NOTE while parsing the body of this `while` expression + //~| NOTE this `while` condition successfully parsed + println!("{:?}", thing); + i += 1; + } +} +//~^ ERROR expected `{`, found `}` +//~| NOTE expected `{` diff --git a/src/test/ui/parser/while-if-let-without-body.stderr b/src/test/ui/parser/while-if-let-without-body.stderr new file mode 100644 index 00000000000..2dac45c115d --- /dev/null +++ b/src/test/ui/parser/while-if-let-without-body.stderr @@ -0,0 +1,18 @@ +error: expected `{`, found `}` + --> $DIR/while-if-let-without-body.rs:11:1 + | +LL | while if let Some(thing) = container.get(i) { + | _____-----_- + | | | + | | while parsing the body of this `while` expression +LL | | +LL | | +LL | | println!("{:?}", thing); +LL | | i += 1; +LL | | } + | |_____- this `while` condition successfully parsed +LL | } + | ^ expected `{` + +error: aborting due to previous error + diff --git a/src/test/ui/typeck/while-loop-block-cond.rs b/src/test/ui/typeck/while-loop-block-cond.rs new file mode 100644 index 00000000000..929759766f2 --- /dev/null +++ b/src/test/ui/typeck/while-loop-block-cond.rs @@ -0,0 +1,4 @@ +fn main() { + while {} {} + //~^ ERROR mismatched types [E0308] +} diff --git a/src/test/ui/typeck/while-loop-block-cond.stderr b/src/test/ui/typeck/while-loop-block-cond.stderr new file mode 100644 index 00000000000..598273af9cf --- /dev/null +++ b/src/test/ui/typeck/while-loop-block-cond.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/while-loop-block-cond.rs:2:11 + | +LL | while {} {} + | ^^ expected `bool`, found `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/unsafe/unsafe-block-without-braces.stderr b/src/test/ui/unsafe/unsafe-block-without-braces.stderr index 895f33638f9..44f77b99c56 100644 --- a/src/test/ui/unsafe/unsafe-block-without-braces.stderr +++ b/src/test/ui/unsafe/unsafe-block-without-braces.stderr @@ -1,11 +1,15 @@ error: expected `{`, found `std` --> $DIR/unsafe-block-without-braces.rs:3:9 | +LL | unsafe //{ + | ------ while parsing this `unsafe` expression LL | std::mem::transmute::<f32, u32>(1.0); - | ^^^---------------------------------- - | | - | expected `{` - | help: try placing this code inside a block: `{ std::mem::transmute::<f32, u32>(1.0); }` + | ^^^ expected `{` + | +help: try placing this code inside a block + | +LL | { std::mem::transmute::<f32, u32>(1.0); } + | + + error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr b/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr index d3593d8c1eb..ba624507c21 100644 --- a/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr +++ b/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr @@ -30,3 +30,4 @@ LL | impl Trait for Ref {} error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0726`. |
