From 76b8fd81e299498266923f1470c216f553b2927b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 18 Oct 2019 19:00:09 +0200 Subject: [PATCH 01/12] Add long error explanation for E0587 --- src/librustc_typeck/error_codes.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs index 3d41c6e09c6bc..6405b77c1054b 100644 --- a/src/librustc_typeck/error_codes.rs +++ b/src/librustc_typeck/error_codes.rs @@ -3891,6 +3891,25 @@ details. [issue #33685]: https://github.com/rust-lang/rust/issues/33685 "##, +E0587: r##" +A type has both `packed` and `align` representation hints. + +Erroneous code example: + +```compile_fail,E0587 +#[repr(packed, align(8))] // error! +struct Umbrella(i32); +``` + +You cannot use `packed` and `align` hints on a same type. If you want to pack a +type to a given size, you should provide a size to packed: + +``` +#[repr(packed)] // ok! +struct Umbrella(i32); +``` +"##, + E0588: r##" A type with `packed` representation hint has a field with `align` representation hint. @@ -5073,7 +5092,6 @@ the future, [RFC 2091] prohibits their implementation without a follow-up RFC. // E0563, // cannot determine a type for this `impl Trait` removed in 6383de15 // E0564, // only named lifetimes are allowed in `impl Trait`, // but `{}` was found in the type `{}` - E0587, // type has conflicting packed and align representation hints // E0611, // merged into E0616 // E0612, // merged into E0609 // E0613, // Removed (merged with E0609) From 42a805e4d2b057f58f5ad72b35afaee1bf8358ef Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 18 Oct 2019 19:00:35 +0200 Subject: [PATCH 02/12] Update ui tests --- src/test/ui/conflicting-repr-hints.stderr | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/ui/conflicting-repr-hints.stderr b/src/test/ui/conflicting-repr-hints.stderr index 832f5c3ac2bb7..414c15f93bc18 100644 --- a/src/test/ui/conflicting-repr-hints.stderr +++ b/src/test/ui/conflicting-repr-hints.stderr @@ -66,4 +66,5 @@ LL | | } error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0566`. +Some errors have detailed explanations: E0566, E0587. +For more information about an error, try `rustc --explain E0566`. From 6661db006a85bdb1530716da26fb5b2829643f2a Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 20 Oct 2019 23:44:41 +0100 Subject: [PATCH 03/12] Correct handling of type flags with `ConstValue::Placeholder` --- src/librustc/ty/flags.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index d3a3f51cfa47b..dad7144a6e969 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -114,6 +114,7 @@ impl FlagComputation { } &ty::Placeholder(..) => { + self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER); } @@ -123,8 +124,7 @@ impl FlagComputation { match infer { ty::FreshTy(_) | ty::FreshIntTy(_) | - ty::FreshFloatTy(_) => { - } + ty::FreshFloatTy(_) => {} ty::TyVar(_) | ty::IntVar(_) | @@ -245,14 +245,16 @@ impl FlagComputation { } } ConstValue::Param(_) => { - self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES | TypeFlags::HAS_PARAMS); + self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); + self.add_flags(TypeFlags::HAS_PARAMS); } ConstValue::Placeholder(_) => { - self.add_flags(TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_CT_PLACEHOLDER); + self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); + self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER); } - ConstValue::Scalar(_) => { } - ConstValue::Slice { data: _, start: _, end: _ } => { } - ConstValue::ByRef { alloc: _, offset: _ } => { } + ConstValue::Scalar(_) => {} + ConstValue::Slice { .. } => {} + ConstValue::ByRef { .. } => {} } } From 9c4f60eecf1c9a0d90e6e2ea1e089fd77fd2c20f Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 28 Oct 2019 03:22:59 +0000 Subject: [PATCH 04/12] doc: introduce `once` in `iter::chain` document --- src/libcore/iter/traits/iterator.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index a272035150a15..7ffc8b3729cb4 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -384,6 +384,9 @@ pub trait Iterator { /// /// In other words, it links two iterators together, in a chain. 🔗 /// + /// [`once`] is commonly used to adapt a single value into a chain of + /// other kinds of iteration. + /// /// # Examples /// /// Basic usage: @@ -408,9 +411,6 @@ pub trait Iterator { /// [`Iterator`] itself. For example, slices (`&[T]`) implement /// [`IntoIterator`], and so can be passed to `chain()` directly: /// - /// [`IntoIterator`]: trait.IntoIterator.html - /// [`Iterator`]: trait.Iterator.html - /// /// ``` /// let s1 = &[1, 2, 3]; /// let s2 = &[4, 5, 6]; @@ -425,6 +425,21 @@ pub trait Iterator { /// assert_eq!(iter.next(), Some(&6)); /// assert_eq!(iter.next(), None); /// ``` + /// + /// If you work with Windows API, you may wish to convert [`OsStr`] to `Vec`: + /// + /// ``` + /// #[cfg(windows)] + /// fn os_str_to_utf16(s: &std::ffi::OsStr) -> Vec { + /// use std::os::windows::ffi::OsStrExt; + /// s.encode_wide().chain(std::iter::once(0)).collect() + /// } + /// ``` + /// + /// [`once`]: fn.once.html + /// [`Iterator`]: trait.Iterator.html + /// [`IntoIterator`]: trait.IntoIterator.html + /// [`OsStr`]: ../../std/ffi/struct.OsStr.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn chain(self, other: U) -> Chain where From e2c450b8dacd6edce4bdc66db9da4ddfc81f4dc1 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 28 Oct 2019 05:39:37 +0000 Subject: [PATCH 05/12] doc: mention `get(_mut)` in Vec --- src/liballoc/vec.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 641f9eafa8d23..272150110eba9 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -154,8 +154,8 @@ use crate::raw_vec::RawVec; /// println!("{}", v[6]); // it will panic! /// ``` /// -/// In conclusion: always check if the index you want to get really exists -/// before doing it. +/// Use [`get`] and [`get_mut`] if you want to check whether the index is in +/// the `Vec`. /// /// # Slicing /// @@ -277,6 +277,8 @@ use crate::raw_vec::RawVec; /// The order has changed in the past and may change again. /// /// [`vec!`]: ../../std/macro.vec.html +/// [`get`]: ../../std/vec/struct.Vec.html#method.get +/// [`get_mut`]: ../../std/vec/struct.Vec.html#method.get_mut /// [`Index`]: ../../std/ops/trait.Index.html /// [`String`]: ../../std/string/struct.String.html /// [`&str`]: ../../std/primitive.str.html From cc575a6ad50c3b15f4073b3ac210ed6e5423230d Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 25 Oct 2019 20:30:11 +0300 Subject: [PATCH 06/12] rustc: use IndexVec instead of Vec. --- src/librustc/hir/map/collector.rs | 8 ++------ src/librustc/hir/map/definitions.rs | 18 +++++++++--------- src/librustc/hir/map/mod.rs | 14 ++++++-------- 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 307dbe7dab080..b0fa844c81881 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -149,7 +149,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { let mut collector = NodeCollector { krate, source_map: sess.source_map(), - map: vec![None; definitions.def_index_count()], + map: IndexVec::from_elem_n(IndexVec::new(), definitions.def_index_count()), parent_node: hir::CRATE_HIR_ID, current_signature_dep_index: root_mod_sig_dep_index, current_full_dep_index: root_mod_full_dep_index, @@ -227,12 +227,8 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { fn insert_entry(&mut self, id: HirId, entry: Entry<'hir>) { debug!("hir_map: {:?} => {:?}", id, entry); - let local_map = &mut self.map[id.owner.index()]; + let local_map = &mut self.map[id.owner]; let i = id.local_id.as_u32() as usize; - if local_map.is_none() { - *local_map = Some(IndexVec::with_capacity(i + 1)); - } - let local_map = local_map.as_mut().unwrap(); let len = local_map.len(); if i >= len { local_map.extend(repeat(None).take(i - len + 1)); diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 4e163314f6b07..be8d82173e481 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -27,8 +27,8 @@ use syntax_pos::{Span, DUMMY_SP}; /// There is one `DefPathTable` for each crate. #[derive(Clone, Default, RustcDecodable, RustcEncodable)] pub struct DefPathTable { - index_to_key: Vec, - def_path_hashes: Vec, + index_to_key: IndexVec, + def_path_hashes: IndexVec, } impl DefPathTable { @@ -53,14 +53,14 @@ impl DefPathTable { #[inline(always)] pub fn def_key(&self, index: DefIndex) -> DefKey { - self.index_to_key[index.index()] + self.index_to_key[index] } #[inline(always)] pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash { - let ret = self.def_path_hashes[index.index()]; - debug!("def_path_hash({:?}) = {:?}", index, ret); - return ret + let hash = self.def_path_hashes[index]; + debug!("def_path_hash({:?}) = {:?}", index, hash); + hash } pub fn add_def_path_hashes_to(&self, @@ -92,7 +92,7 @@ impl DefPathTable { pub struct Definitions { table: DefPathTable, node_to_def_index: NodeMap, - def_index_to_node: Vec, + def_index_to_node: IndexVec, pub(super) node_to_hir_id: IndexVec, /// If `ExpnId` is an ID of some macro expansion, /// then `DefId` is the normal module (`mod`) in which the expanded macro was defined. @@ -375,7 +375,7 @@ impl Definitions { #[inline] pub fn as_local_node_id(&self, def_id: DefId) -> Option { if def_id.krate == LOCAL_CRATE { - let node_id = self.def_index_to_node[def_id.index.index()]; + let node_id = self.def_index_to_node[def_id.index]; if node_id != ast::DUMMY_NODE_ID { return Some(node_id); } @@ -404,7 +404,7 @@ impl Definitions { #[inline] pub fn def_index_to_hir_id(&self, def_index: DefIndex) -> hir::HirId { - let node_id = self.def_index_to_node[def_index.index()]; + let node_id = self.def_index_to_node[def_index]; self.node_to_hir_id[node_id] } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index cd36944253dbb..acadd77cc36c0 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -156,9 +156,9 @@ impl Forest { /// This type is effectively a `HashMap>`, /// but it is implemented as 2 layers of arrays. -/// - first we have `A = Vec>` mapping a `DefIndex`'s index to an inner value +/// - first we have `A = IndexVec` mapping `DefIndex`s to an inner value /// - which is `B = IndexVec>` which gives you the `Entry`. -pub(super) type HirEntryMap<'hir> = Vec>>>>; +pub(super) type HirEntryMap<'hir> = IndexVec>>>; /// Represents a mapping from `NodeId`s to AST elements and their parent `NodeId`s. #[derive(Clone)] @@ -222,8 +222,8 @@ impl<'map> Iterator for ParentHirIterator<'map> { impl<'hir> Map<'hir> { #[inline] fn lookup(&self, id: HirId) -> Option<&Entry<'hir>> { - let local_map = self.map.get(id.owner.index())?; - local_map.as_ref()?.get(id.local_id)?.as_ref() + let local_map = self.map.get(id.owner)?; + local_map.get(id.local_id)?.as_ref() } /// Registers a read in the dependency graph of the AST node with @@ -1031,14 +1031,12 @@ impl<'hir> Map<'hir> { // see the comment on `HirEntryMap`. // Iterate over all the indices and return a reference to // local maps and their index given that they exist. - self.map.iter().enumerate().filter_map(|(i, local_map)| { - local_map.as_ref().map(|m| (i, m)) - }).flat_map(move |(array_index, local_map)| { + self.map.iter_enumerated().flat_map(move |(owner, local_map)| { // Iterate over each valid entry in the local map. local_map.iter_enumerated().filter_map(move |(i, entry)| entry.map(move |_| { // Reconstruct the `HirId` based on the 3 indices we used to find it. HirId { - owner: DefIndex::from(array_index), + owner, local_id: i, } })) From 46a39a2d424cefb2d0c56fae9682cfa253a79d47 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 28 Oct 2019 10:57:54 +0100 Subject: [PATCH 07/12] self-profiling: Record something more useful for crate metadata generation event. Before this commit, we had an event that would only track the compression step for proc-macros and Rust dylibs. After the commit we measure the time for acutally generating the crate metadata bytes. --- src/librustc/ty/context.rs | 1 + src/librustc_codegen_ssa/base.rs | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 0f7d5d9a25e61..bdf9b2d7f3f27 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1408,6 +1408,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn encode_metadata(self)-> EncodedMetadata { + let _prof_timer = self.prof.generic_activity("generate_crate_metadata"); self.cstore.encode_metadata(self) } diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index bf687f846357e..ee4ec7fb41eac 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -574,8 +574,6 @@ pub fn codegen_crate( if need_metadata_module { // Codegen the encoded metadata. - let _prof_timer = tcx.prof.generic_activity("codegen_crate_metadata"); - let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata")).as_str() From d673d0ac8462bd30612b0cce719ac0bf15dfaf86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 20 Oct 2019 14:35:46 -0700 Subject: [PATCH 08/12] Use heuristics to recover parsing of missing `;` - Detect `,` and `:` typos where `;` was intended. - When the next token could have been the start of a new statement, detect a missing semicolon. --- src/libsyntax/parse/parser/diagnostics.rs | 91 +++++++++++-------- src/libsyntax/parse/parser/item.rs | 24 ++--- src/libsyntax/parse/parser/stmt.rs | 6 +- src/libsyntax/parse/token.rs | 51 ++++++----- src/test/ui/parser/import-from-path.stderr | 2 +- src/test/ui/parser/import-from-rename.stderr | 4 +- src/test/ui/parser/import-glob-path.stderr | 2 +- src/test/ui/parser/import-glob-rename.stderr | 4 +- src/test/ui/parser/issue-3036.rs | 4 +- src/test/ui/parser/issue-3036.stderr | 8 +- src/test/ui/parser/recover-missing-semi.rs | 4 +- .../ui/parser/recover-missing-semi.stderr | 20 ++-- 12 files changed, 120 insertions(+), 100 deletions(-) diff --git a/src/libsyntax/parse/parser/diagnostics.rs b/src/libsyntax/parse/parser/diagnostics.rs index 06982c789db8b..677d16a40d9fc 100644 --- a/src/libsyntax/parse/parser/diagnostics.rs +++ b/src/libsyntax/parse/parser/diagnostics.rs @@ -6,7 +6,7 @@ use crate::ast::{ self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, }; -use crate::parse::token::{self, TokenKind}; +use crate::parse::token::{self, TokenKind, token_can_begin_expr}; use crate::print::pprust; use crate::ptr::P; use crate::symbol::{kw, sym}; @@ -326,34 +326,8 @@ impl<'a> Parser<'a> { } } - let is_semi_suggestable = expected.iter().any(|t| match t { - TokenType::Token(token::Semi) => true, // We expect a `;` here. - _ => false, - }) && ( // A `;` would be expected before the current keyword. - self.token.is_keyword(kw::Break) || - self.token.is_keyword(kw::Continue) || - self.token.is_keyword(kw::For) || - self.token.is_keyword(kw::If) || - self.token.is_keyword(kw::Let) || - self.token.is_keyword(kw::Loop) || - self.token.is_keyword(kw::Match) || - self.token.is_keyword(kw::Return) || - self.token.is_keyword(kw::While) - ); let sm = self.sess.source_map(); match (sm.lookup_line(self.token.span.lo()), sm.lookup_line(sp.lo())) { - (Ok(ref a), Ok(ref b)) if a.line != b.line && is_semi_suggestable => { - // The spans are in different lines, expected `;` and found `let` or `return`. - // High likelihood that it is only a missing `;`. - err.span_suggestion_short( - label_sp, - "a semicolon may be missing here", - ";".to_string(), - Applicability::MaybeIncorrect, - ); - err.emit(); - return Ok(true); - } (Ok(ref a), Ok(ref b)) if a.line == b.line => { // When the spans are in the same line, it means that the only content between // them is whitespace, point at the found token in that case: @@ -902,18 +876,61 @@ impl<'a> Parser<'a> { } } let sm = self.sess.source_map(); - match (sm.lookup_line(prev_sp.lo()), sm.lookup_line(sp.lo())) { - (Ok(ref a), Ok(ref b)) if a.line == b.line => { - // When the spans are in the same line, it means that the only content - // between them is whitespace, point only at the found token. - err.span_label(sp, label_exp); + if !sm.is_multiline(prev_sp.until(sp)) { + // When the spans are in the same line, it means that the only content + // between them is whitespace, point only at the found token. + err.span_label(sp, label_exp); + } else { + err.span_label(prev_sp, label_exp); + err.span_label(sp, "unexpected token"); + } + Err(err) + } + + pub(super) fn expect_semi(&mut self) -> PResult<'a, ()> { + if self.eat(&token::Semi) { + return Ok(()); + } + let sm = self.sess.source_map(); + let msg = format!("expected `;`, found `{}`", self.this_token_descr()); + let appl = Applicability::MachineApplicable; + if self.look_ahead(1, |t| t == &token::CloseDelim(token::Brace) + || token_can_begin_expr(t) && t.kind != token::Colon + ) && [token::Comma, token::Colon].contains(&self.token.kind) { + // Likely typo: `,` → `;` or `:` → `;`. This is triggered if the current token is + // either `,` or `:`, and the next token could either start a new statement or is a + // block close. For example: + // + // let x = 32: + // let y = 42; + if sm.is_multiline(self.prev_span.until(self.token.span)) { + self.bump(); + let sp = self.prev_span; + self.struct_span_err(sp, &msg) + .span_suggestion(sp, "change this to `;`", ";".to_string(), appl) + .emit(); + return Ok(()) } - _ => { - err.span_label(prev_sp, label_exp); - err.span_label(sp, "unexpected token"); + } else if self.look_ahead(0, |t| t == &token::CloseDelim(token::Brace) || ( + token_can_begin_expr(t) + && t != &token::Semi + && t != &token::Pound // Avoid triggering with too many trailing `#` in raw string. + )) { + // Missing semicolon typo. This is triggered if the next token could either start a + // new statement or is a block close. For example: + // + // let x = 32 + // let y = 42; + if sm.is_multiline(self.prev_span.until(self.token.span)) { + let sp = self.prev_span.shrink_to_hi(); + self.struct_span_err(sp, &msg) + .span_label(self.token.span, "unexpected token") + .span_suggestion_short(sp, "add `;` here", ";".to_string(), appl) + .emit(); + return Ok(()) } } - Err(err) + self.expect(&token::Semi).map(|_| ()) // Error unconditionally } pub(super) fn parse_semi_or_incorrect_foreign_fn_body( @@ -943,7 +960,7 @@ impl<'a> Parser<'a> { Err(mut err) => { err.cancel(); mem::replace(self, parser_snapshot); - self.expect(&token::Semi)?; + self.expect_semi()?; } } } else { diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 506a1a2a27a34..fe12533619033 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -98,7 +98,7 @@ impl<'a> Parser<'a> { if self.eat_keyword(kw::Use) { // USE ITEM let item_ = ItemKind::Use(P(self.parse_use_tree()?)); - self.expect(&token::Semi)?; + self.expect_semi()?; let span = lo.to(self.prev_span); let item = self.mk_item(span, Ident::invalid(), item_, vis, attrs); @@ -526,7 +526,7 @@ impl<'a> Parser<'a> { // eat a matched-delimiter token tree: let (delim, tts) = self.expect_delimited_token_tree()?; if delim != MacDelimiter::Brace { - self.expect(&token::Semi)?; + self.expect_semi()?; } Ok(Some(Mac { @@ -776,7 +776,7 @@ impl<'a> Parser<'a> { let typ = self.parse_ty()?; self.expect(&token::Eq)?; let expr = self.parse_expr()?; - self.expect(&token::Semi)?; + self.expect_semi()?; Ok((name, ImplItemKind::Const(typ, expr), Generics::default())) } @@ -813,7 +813,7 @@ impl<'a> Parser<'a> { let bounds = self.parse_generic_bounds(None)?; tps.where_clause = self.parse_where_clause()?; - self.expect(&token::Semi)?; + self.expect_semi()?; let whole_span = lo.to(self.prev_span); if is_auto == IsAuto::Yes { @@ -927,7 +927,7 @@ impl<'a> Parser<'a> { } else { None }; - self.expect(&token::Semi)?; + self.expect_semi()?; Ok((ident, TraitItemKind::Const(ty, default), Generics::default())) } @@ -951,7 +951,7 @@ impl<'a> Parser<'a> { } else { None }; - self.expect(&token::Semi)?; + self.expect_semi()?; Ok((ident, TraitItemKind::Type(bounds, default), generics)) } @@ -1054,7 +1054,7 @@ impl<'a> Parser<'a> { } else { (orig_name, None) }; - self.expect(&token::Semi)?; + self.expect_semi()?; let span = lo.to(self.prev_span); Ok(self.mk_item(span, item_name, ItemKind::ExternCrate(orig_name), visibility, attrs)) @@ -1217,7 +1217,7 @@ impl<'a> Parser<'a> { self.expect(&token::Colon)?; let ty = self.parse_ty()?; let hi = self.token.span; - self.expect(&token::Semi)?; + self.expect_semi()?; Ok(ForeignItem { ident, attrs, @@ -1235,7 +1235,7 @@ impl<'a> Parser<'a> { let ident = self.parse_ident()?; let hi = self.token.span; - self.expect(&token::Semi)?; + self.expect_semi()?; Ok(ast::ForeignItem { ident, attrs, @@ -1282,7 +1282,7 @@ impl<'a> Parser<'a> { self.expect(&token::Eq)?; let e = self.parse_expr()?; - self.expect(&token::Semi)?; + self.expect_semi()?; let item = match m { Some(m) => ItemKind::Static(ty, m, e), None => ItemKind::Const(ty, e), @@ -1344,7 +1344,7 @@ impl<'a> Parser<'a> { let ty = self.parse_ty()?; AliasKind::Weak(ty) }; - self.expect(&token::Semi)?; + self.expect_semi()?; Ok((ident, alias, tps)) } @@ -1468,7 +1468,7 @@ impl<'a> Parser<'a> { } else if self.token == token::OpenDelim(token::Paren) { let body = VariantData::Tuple(self.parse_tuple_struct_body()?, DUMMY_NODE_ID); generics.where_clause = self.parse_where_clause()?; - self.expect(&token::Semi)?; + self.expect_semi()?; body } else { let token_str = self.this_token_descr(); diff --git a/src/libsyntax/parse/parser/stmt.rs b/src/libsyntax/parse/parser/stmt.rs index ea7e4c05ea1ae..4f51fefe66fba 100644 --- a/src/libsyntax/parse/parser/stmt.rs +++ b/src/libsyntax/parse/parser/stmt.rs @@ -432,6 +432,7 @@ impl<'a> Parser<'a> { None => return Ok(None), }; + let mut eat_semi = true; match stmt.kind { StmtKind::Expr(ref expr) if self.token != token::Eof => { // expression without semicolon @@ -453,13 +454,14 @@ impl<'a> Parser<'a> { if macro_legacy_warnings && self.token != token::Semi { self.warn_missing_semicolon(); } else { - self.expect_one_of(&[], &[token::Semi])?; + self.expect_semi()?; + eat_semi = false; } } _ => {} } - if self.eat(&token::Semi) { + if eat_semi && self.eat(&token::Semi) { stmt = stmt.add_trailing_semicolon(); } stmt.span = stmt.span.to(self.prev_span); diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 4a8b25c61079b..03e77b199cc3b 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -143,34 +143,35 @@ impl Lit { pub(crate) fn ident_can_begin_expr(name: ast::Name, span: Span, is_raw: bool) -> bool { let ident_token = Token::new(Ident(name, is_raw), span); + token_can_begin_expr(&ident_token) +} +pub(crate) fn token_can_begin_expr(ident_token: &Token) -> bool { !ident_token.is_reserved_ident() || ident_token.is_path_segment_keyword() || - [ - kw::Async, - - // FIXME: remove when `await!(..)` syntax is removed - // https://github.com/rust-lang/rust/issues/60610 - kw::Await, - - kw::Do, - kw::Box, - kw::Break, - kw::Continue, - kw::False, - kw::For, - kw::If, - kw::Let, - kw::Loop, - kw::Match, - kw::Move, - kw::Return, - kw::True, - kw::Unsafe, - kw::While, - kw::Yield, - kw::Static, - ].contains(&name) + match ident_token.kind { + TokenKind::Ident(ident, _) => [ + kw::Async, + kw::Do, + kw::Box, + kw::Break, + kw::Continue, + kw::False, + kw::For, + kw::If, + kw::Let, + kw::Loop, + kw::Match, + kw::Move, + kw::Return, + kw::True, + kw::Unsafe, + kw::While, + kw::Yield, + kw::Static, + ].contains(&ident), + _=> false, + } } fn ident_can_begin_type(name: ast::Name, span: Span, is_raw: bool) -> bool { diff --git a/src/test/ui/parser/import-from-path.stderr b/src/test/ui/parser/import-from-path.stderr index 5842037fb8050..84c3b31df20be 100644 --- a/src/test/ui/parser/import-from-path.stderr +++ b/src/test/ui/parser/import-from-path.stderr @@ -2,7 +2,7 @@ error: expected `;`, found `::` --> $DIR/import-from-path.rs:2:15 | LL | use foo::{bar}::baz - | ^^ expected `;` + | ^^ expected `;` here error: aborting due to previous error diff --git a/src/test/ui/parser/import-from-rename.stderr b/src/test/ui/parser/import-from-rename.stderr index a966e9937373a..53ceb0280f987 100644 --- a/src/test/ui/parser/import-from-rename.stderr +++ b/src/test/ui/parser/import-from-rename.stderr @@ -1,8 +1,8 @@ -error: expected `;`, found keyword `as` +error: expected `;`, found `as` --> $DIR/import-from-rename.rs:3:16 | LL | use foo::{bar} as baz; - | ^^ expected `;` + | ^^ expected `;` here error: aborting due to previous error diff --git a/src/test/ui/parser/import-glob-path.stderr b/src/test/ui/parser/import-glob-path.stderr index ebca2db8305c3..44f4fc57a4a95 100644 --- a/src/test/ui/parser/import-glob-path.stderr +++ b/src/test/ui/parser/import-glob-path.stderr @@ -2,7 +2,7 @@ error: expected `;`, found `::` --> $DIR/import-glob-path.rs:2:11 | LL | use foo::*::bar - | ^^ expected `;` + | ^^ expected `;` here error: aborting due to previous error diff --git a/src/test/ui/parser/import-glob-rename.stderr b/src/test/ui/parser/import-glob-rename.stderr index 2853873278251..56f021c29d45f 100644 --- a/src/test/ui/parser/import-glob-rename.stderr +++ b/src/test/ui/parser/import-glob-rename.stderr @@ -1,8 +1,8 @@ -error: expected `;`, found keyword `as` +error: expected `;`, found `as` --> $DIR/import-glob-rename.rs:3:12 | LL | use foo::* as baz; - | ^^ expected `;` + | ^^ expected `;` here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-3036.rs b/src/test/ui/parser/issue-3036.rs index 00b241b9054cd..6a8b67fefa780 100644 --- a/src/test/ui/parser/issue-3036.rs +++ b/src/test/ui/parser/issue-3036.rs @@ -2,5 +2,5 @@ fn main() { - let x = 3 -} //~ ERROR: expected one of `.`, `;`, `?`, or an operator, found `}` + let x = 3 //~ ERROR: expected `;` +} diff --git a/src/test/ui/parser/issue-3036.stderr b/src/test/ui/parser/issue-3036.stderr index 18947b8fa401e..b6557163d4520 100644 --- a/src/test/ui/parser/issue-3036.stderr +++ b/src/test/ui/parser/issue-3036.stderr @@ -1,10 +1,10 @@ -error: expected one of `.`, `;`, `?`, or an operator, found `}` - --> $DIR/issue-3036.rs:6:1 +error: expected `;`, found ``}`` + --> $DIR/issue-3036.rs:5:14 | LL | let x = 3 - | - expected one of `.`, `;`, `?`, or an operator here + | ^ help: add `;` here LL | } - | ^ unexpected token + | - unexpected token error: aborting due to previous error diff --git a/src/test/ui/parser/recover-missing-semi.rs b/src/test/ui/parser/recover-missing-semi.rs index 1893dc716bedc..f47d5e6805f88 100644 --- a/src/test/ui/parser/recover-missing-semi.rs +++ b/src/test/ui/parser/recover-missing-semi.rs @@ -1,13 +1,13 @@ fn main() { let _: usize = () //~^ ERROR mismatched types + //~| ERROR expected `;` let _ = 3; - //~^ ERROR expected one of } fn foo() -> usize { let _: usize = () //~^ ERROR mismatched types + //~| ERROR expected `;` return 3; - //~^ ERROR expected one of } diff --git a/src/test/ui/parser/recover-missing-semi.stderr b/src/test/ui/parser/recover-missing-semi.stderr index 99339e4dd5025..c40918ee2bd5f 100644 --- a/src/test/ui/parser/recover-missing-semi.stderr +++ b/src/test/ui/parser/recover-missing-semi.stderr @@ -1,20 +1,20 @@ -error: expected one of `.`, `;`, `?`, or an operator, found `let` - --> $DIR/recover-missing-semi.rs:4:5 +error: expected `;`, found `keyword `let`` + --> $DIR/recover-missing-semi.rs:2:22 | LL | let _: usize = () - | - help: a semicolon may be missing here -LL | + | ^ help: add `;` here +... LL | let _ = 3; - | ^^^ + | --- unexpected token -error: expected one of `.`, `;`, `?`, or an operator, found `return` - --> $DIR/recover-missing-semi.rs:11:5 +error: expected `;`, found `keyword `return`` + --> $DIR/recover-missing-semi.rs:9:22 | LL | let _: usize = () - | - help: a semicolon may be missing here -LL | + | ^ help: add `;` here +... LL | return 3; - | ^^^^^^ + | ------ unexpected token error[E0308]: mismatched types --> $DIR/recover-missing-semi.rs:2:20 From 1b0836df6f633eb1a4c02d15a8d942bfe885f172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 22 Oct 2019 11:46:19 -0700 Subject: [PATCH 09/12] Tweak unexpected token wording --- src/libsyntax/parse/parser/diagnostics.rs | 10 +++++----- src/test/ui/async-await/no-async-const.rs | 2 +- src/test/ui/async-await/no-async-const.stderr | 2 +- src/test/ui/async-await/no-unsafe-async.rs | 4 ++-- src/test/ui/async-await/no-unsafe-async.stderr | 4 ++-- src/test/ui/can-begin-expr-check.rs | 2 +- src/test/ui/can-begin-expr-check.stderr | 2 +- src/test/ui/issues/issue-43196.stderr | 2 +- .../extern/keyword-extern-as-identifier-type.stderr | 2 +- src/test/ui/macros/issue-54441.stderr | 2 +- src/test/ui/parser/default.stderr | 2 +- src/test/ui/parser/duplicate-visibility.stderr | 2 +- src/test/ui/parser/extern-expected-fn-or-brace.rs | 2 +- src/test/ui/parser/extern-expected-fn-or-brace.stderr | 2 +- src/test/ui/parser/impl-parsing.stderr | 2 +- src/test/ui/parser/import-from-path.stderr | 2 +- src/test/ui/parser/import-from-rename.stderr | 4 ++-- src/test/ui/parser/import-glob-path.stderr | 2 +- src/test/ui/parser/import-glob-rename.stderr | 4 ++-- src/test/ui/parser/issue-15980.rs | 2 +- src/test/ui/parser/issue-15980.stderr | 2 +- src/test/ui/parser/issue-19398.rs | 2 +- src/test/ui/parser/issue-19398.stderr | 4 ++-- src/test/ui/parser/raw/raw-literal-keywords.rs | 2 +- src/test/ui/parser/raw/raw-literal-keywords.stderr | 2 +- .../ui/parser/recover-for-loop-parens-around-head.rs | 2 +- .../parser/recover-for-loop-parens-around-head.stderr | 2 +- src/test/ui/parser/removed-syntax-static-fn.stderr | 2 +- src/test/ui/parser/removed-syntax-uniq-mut-ty.rs | 3 ++- src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr | 2 +- src/test/ui/parser/underscore_item_not_const.rs | 2 +- src/test/ui/parser/underscore_item_not_const.stderr | 2 +- 32 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/libsyntax/parse/parser/diagnostics.rs b/src/libsyntax/parse/parser/diagnostics.rs index 677d16a40d9fc..49949b775750d 100644 --- a/src/libsyntax/parse/parser/diagnostics.rs +++ b/src/libsyntax/parse/parser/diagnostics.rs @@ -274,23 +274,23 @@ impl<'a> Parser<'a> { expected.sort_by_cached_key(|x| x.to_string()); expected.dedup(); let expect = tokens_to_string(&expected[..]); - let actual = self.this_token_to_string(); + let actual = self.this_token_descr(); let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { let short_expect = if expected.len() > 6 { format!("{} possible tokens", expected.len()) } else { expect.clone() }; - (format!("expected one of {}, found `{}`", expect, actual), + (format!("expected one of {}, found {}", expect, actual), (self.sess.source_map().next_point(self.prev_span), format!("expected one of {} here", short_expect))) } else if expected.is_empty() { - (format!("unexpected token: `{}`", actual), + (format!("unexpected token: {}", actual), (self.prev_span, "unexpected token after this".to_string())) } else { - (format!("expected {}, found `{}`", expect, actual), + (format!("expected {}, found {}", expect, actual), (self.sess.source_map().next_point(self.prev_span), - format!("expected {} here", expect))) + format!("expected {}", expect))) }; self.last_unexpected_token_span = Some(self.token.span); let mut err = self.fatal(&msg_exp); diff --git a/src/test/ui/async-await/no-async-const.rs b/src/test/ui/async-await/no-async-const.rs index 7a6eb498b2ee0..44f02d1a7b19b 100644 --- a/src/test/ui/async-await/no-async-const.rs +++ b/src/test/ui/async-await/no-async-const.rs @@ -3,4 +3,4 @@ // compile-flags: --crate-type lib pub async const fn x() {} -//~^ ERROR expected one of `fn` or `unsafe`, found `const` +//~^ ERROR expected one of `fn` or `unsafe`, found keyword `const` diff --git a/src/test/ui/async-await/no-async-const.stderr b/src/test/ui/async-await/no-async-const.stderr index edbdfb5652281..f89d1810ba449 100644 --- a/src/test/ui/async-await/no-async-const.stderr +++ b/src/test/ui/async-await/no-async-const.stderr @@ -1,4 +1,4 @@ -error: expected one of `fn` or `unsafe`, found `const` +error: expected one of `fn` or `unsafe`, found keyword `const` --> $DIR/no-async-const.rs:5:11 | LL | pub async const fn x() {} diff --git a/src/test/ui/async-await/no-unsafe-async.rs b/src/test/ui/async-await/no-unsafe-async.rs index 81e0cd799ad70..1ac1bdffda947 100644 --- a/src/test/ui/async-await/no-unsafe-async.rs +++ b/src/test/ui/async-await/no-unsafe-async.rs @@ -4,8 +4,8 @@ struct S; impl S { #[cfg(FALSE)] - unsafe async fn g() {} //~ ERROR expected one of `extern` or `fn`, found `async` + unsafe async fn g() {} //~ ERROR expected one of `extern` or `fn`, found keyword `async` } #[cfg(FALSE)] -unsafe async fn f() {} //~ ERROR expected one of `extern`, `fn`, or `{`, found `async` +unsafe async fn f() {} //~ ERROR expected one of `extern`, `fn`, or `{`, found keyword `async` diff --git a/src/test/ui/async-await/no-unsafe-async.stderr b/src/test/ui/async-await/no-unsafe-async.stderr index c339c7c3bf5bf..79d9f1befd66a 100644 --- a/src/test/ui/async-await/no-unsafe-async.stderr +++ b/src/test/ui/async-await/no-unsafe-async.stderr @@ -1,10 +1,10 @@ -error: expected one of `extern` or `fn`, found `async` +error: expected one of `extern` or `fn`, found keyword `async` --> $DIR/no-unsafe-async.rs:7:12 | LL | unsafe async fn g() {} | ^^^^^ expected one of `extern` or `fn` here -error: expected one of `extern`, `fn`, or `{`, found `async` +error: expected one of `extern`, `fn`, or `{`, found keyword `async` --> $DIR/no-unsafe-async.rs:11:8 | LL | unsafe async fn f() {} diff --git a/src/test/ui/can-begin-expr-check.rs b/src/test/ui/can-begin-expr-check.rs index 35aed067c697a..8974d9f48c1e3 100644 --- a/src/test/ui/can-begin-expr-check.rs +++ b/src/test/ui/can-begin-expr-check.rs @@ -16,5 +16,5 @@ pub fn main() { return break as (); } - return enum; //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `enum` + return enum; //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found keyword `enum` } diff --git a/src/test/ui/can-begin-expr-check.stderr b/src/test/ui/can-begin-expr-check.stderr index 676c2cb661e7b..0e03e9915fca2 100644 --- a/src/test/ui/can-begin-expr-check.stderr +++ b/src/test/ui/can-begin-expr-check.stderr @@ -1,4 +1,4 @@ -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `enum` +error: expected one of `.`, `;`, `?`, `}`, or an operator, found keyword `enum` --> $DIR/can-begin-expr-check.rs:19:12 | LL | return enum; diff --git a/src/test/ui/issues/issue-43196.stderr b/src/test/ui/issues/issue-43196.stderr index 32efe23c72b58..4f7ed5cc6fdd8 100644 --- a/src/test/ui/issues/issue-43196.stderr +++ b/src/test/ui/issues/issue-43196.stderr @@ -2,7 +2,7 @@ error: expected `|`, found `}` --> $DIR/issue-43196.rs:3:1 | LL | | - | - expected `|` here + | - expected `|` LL | } | ^ unexpected token diff --git a/src/test/ui/keyword/extern/keyword-extern-as-identifier-type.stderr b/src/test/ui/keyword/extern/keyword-extern-as-identifier-type.stderr index 447c76a5bbceb..48c2f556f1dd9 100644 --- a/src/test/ui/keyword/extern/keyword-extern-as-identifier-type.stderr +++ b/src/test/ui/keyword/extern/keyword-extern-as-identifier-type.stderr @@ -2,7 +2,7 @@ error: expected `fn`, found `::` --> $DIR/keyword-extern-as-identifier-type.rs:1:16 | LL | type A = extern::foo::bar; - | ^^ expected `fn` here + | ^^ expected `fn` error: aborting due to previous error diff --git a/src/test/ui/macros/issue-54441.stderr b/src/test/ui/macros/issue-54441.stderr index af0ee3ae8eca3..9d18d1d517fc4 100644 --- a/src/test/ui/macros/issue-54441.stderr +++ b/src/test/ui/macros/issue-54441.stderr @@ -1,4 +1,4 @@ -error: expected one of `crate`, `fn`, `pub`, `static`, or `type`, found `let` +error: expected one of `crate`, `fn`, `pub`, `static`, or `type`, found keyword `let` --> $DIR/issue-54441.rs:3:9 | LL | let diff --git a/src/test/ui/parser/default.stderr b/src/test/ui/parser/default.stderr index e199045134e78..8843fd303ec0c 100644 --- a/src/test/ui/parser/default.stderr +++ b/src/test/ui/parser/default.stderr @@ -1,4 +1,4 @@ -error: expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub` +error: expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, found keyword `pub` --> $DIR/default.rs:22:13 | LL | default pub fn foo() -> T { T::default() } diff --git a/src/test/ui/parser/duplicate-visibility.stderr b/src/test/ui/parser/duplicate-visibility.stderr index 880b536cd18c5..675adb88d2084 100644 --- a/src/test/ui/parser/duplicate-visibility.stderr +++ b/src/test/ui/parser/duplicate-visibility.stderr @@ -1,4 +1,4 @@ -error: expected one of `(`, `fn`, `static`, or `type`, found `pub` +error: expected one of `(`, `fn`, `static`, or `type`, found keyword `pub` --> $DIR/duplicate-visibility.rs:3:9 | LL | pub pub fn foo(); diff --git a/src/test/ui/parser/extern-expected-fn-or-brace.rs b/src/test/ui/parser/extern-expected-fn-or-brace.rs index dd46b87fa426f..907de0d8f91d8 100644 --- a/src/test/ui/parser/extern-expected-fn-or-brace.rs +++ b/src/test/ui/parser/extern-expected-fn-or-brace.rs @@ -1,4 +1,4 @@ // Verifies that the expected token errors for `extern crate` are // raised -extern "C" mod foo; //~ERROR expected one of `fn` or `{`, found `mod` +extern "C" mod foo; //~ERROR expected one of `fn` or `{`, found keyword `mod` diff --git a/src/test/ui/parser/extern-expected-fn-or-brace.stderr b/src/test/ui/parser/extern-expected-fn-or-brace.stderr index 0fb993553417d..691f4cddff291 100644 --- a/src/test/ui/parser/extern-expected-fn-or-brace.stderr +++ b/src/test/ui/parser/extern-expected-fn-or-brace.stderr @@ -1,4 +1,4 @@ -error: expected one of `fn` or `{`, found `mod` +error: expected one of `fn` or `{`, found keyword `mod` --> $DIR/extern-expected-fn-or-brace.rs:4:12 | LL | extern "C" mod foo; diff --git a/src/test/ui/parser/impl-parsing.stderr b/src/test/ui/parser/impl-parsing.stderr index 935e93963e1e6..e929fa53620f6 100644 --- a/src/test/ui/parser/impl-parsing.stderr +++ b/src/test/ui/parser/impl-parsing.stderr @@ -26,7 +26,7 @@ error: expected `impl`, found `FAIL` --> $DIR/impl-parsing.rs:11:16 | LL | default unsafe FAIL - | ^^^^ expected `impl` here + | ^^^^ expected `impl` error: aborting due to 5 previous errors diff --git a/src/test/ui/parser/import-from-path.stderr b/src/test/ui/parser/import-from-path.stderr index 84c3b31df20be..5842037fb8050 100644 --- a/src/test/ui/parser/import-from-path.stderr +++ b/src/test/ui/parser/import-from-path.stderr @@ -2,7 +2,7 @@ error: expected `;`, found `::` --> $DIR/import-from-path.rs:2:15 | LL | use foo::{bar}::baz - | ^^ expected `;` here + | ^^ expected `;` error: aborting due to previous error diff --git a/src/test/ui/parser/import-from-rename.stderr b/src/test/ui/parser/import-from-rename.stderr index 53ceb0280f987..a966e9937373a 100644 --- a/src/test/ui/parser/import-from-rename.stderr +++ b/src/test/ui/parser/import-from-rename.stderr @@ -1,8 +1,8 @@ -error: expected `;`, found `as` +error: expected `;`, found keyword `as` --> $DIR/import-from-rename.rs:3:16 | LL | use foo::{bar} as baz; - | ^^ expected `;` here + | ^^ expected `;` error: aborting due to previous error diff --git a/src/test/ui/parser/import-glob-path.stderr b/src/test/ui/parser/import-glob-path.stderr index 44f4fc57a4a95..ebca2db8305c3 100644 --- a/src/test/ui/parser/import-glob-path.stderr +++ b/src/test/ui/parser/import-glob-path.stderr @@ -2,7 +2,7 @@ error: expected `;`, found `::` --> $DIR/import-glob-path.rs:2:11 | LL | use foo::*::bar - | ^^ expected `;` here + | ^^ expected `;` error: aborting due to previous error diff --git a/src/test/ui/parser/import-glob-rename.stderr b/src/test/ui/parser/import-glob-rename.stderr index 56f021c29d45f..2853873278251 100644 --- a/src/test/ui/parser/import-glob-rename.stderr +++ b/src/test/ui/parser/import-glob-rename.stderr @@ -1,8 +1,8 @@ -error: expected `;`, found `as` +error: expected `;`, found keyword `as` --> $DIR/import-glob-rename.rs:3:12 | LL | use foo::* as baz; - | ^^ expected `;` here + | ^^ expected `;` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-15980.rs b/src/test/ui/parser/issue-15980.rs index ba874fb4476f0..beb94c8042d5f 100644 --- a/src/test/ui/parser/issue-15980.rs +++ b/src/test/ui/parser/issue-15980.rs @@ -11,7 +11,7 @@ fn main(){ } //~^ NOTE expected one of `.`, `=>`, `?`, or an operator here _ => {} - //~^ ERROR expected one of `.`, `=>`, `?`, or an operator, found `_` + //~^ ERROR expected one of `.`, `=>`, `?`, or an operator, found reserved identifier `_` //~| NOTE unexpected token } } diff --git a/src/test/ui/parser/issue-15980.stderr b/src/test/ui/parser/issue-15980.stderr index 47c275110b429..26f75d45fa241 100644 --- a/src/test/ui/parser/issue-15980.stderr +++ b/src/test/ui/parser/issue-15980.stderr @@ -12,7 +12,7 @@ help: you can escape reserved keywords to use them as identifiers LL | r#return | -error: expected one of `.`, `=>`, `?`, or an operator, found `_` +error: expected one of `.`, `=>`, `?`, or an operator, found reserved identifier `_` --> $DIR/issue-15980.rs:13:9 | LL | } diff --git a/src/test/ui/parser/issue-19398.rs b/src/test/ui/parser/issue-19398.rs index 822f4a6fde2c7..90221039b4148 100644 --- a/src/test/ui/parser/issue-19398.rs +++ b/src/test/ui/parser/issue-19398.rs @@ -1,5 +1,5 @@ trait T { - extern "Rust" unsafe fn foo(); //~ ERROR expected `fn`, found `unsafe` + extern "Rust" unsafe fn foo(); //~ ERROR expected `fn`, found keyword `unsafe` } fn main() {} diff --git a/src/test/ui/parser/issue-19398.stderr b/src/test/ui/parser/issue-19398.stderr index d5f1f972d553d..41ec4f3ced4e9 100644 --- a/src/test/ui/parser/issue-19398.stderr +++ b/src/test/ui/parser/issue-19398.stderr @@ -1,8 +1,8 @@ -error: expected `fn`, found `unsafe` +error: expected `fn`, found keyword `unsafe` --> $DIR/issue-19398.rs:2:19 | LL | extern "Rust" unsafe fn foo(); - | ^^^^^^ expected `fn` here + | ^^^^^^ expected `fn` error: aborting due to previous error diff --git a/src/test/ui/parser/raw/raw-literal-keywords.rs b/src/test/ui/parser/raw/raw-literal-keywords.rs index 6b055fbb11749..bf9cbcdab2e89 100644 --- a/src/test/ui/parser/raw/raw-literal-keywords.rs +++ b/src/test/ui/parser/raw/raw-literal-keywords.rs @@ -1,5 +1,5 @@ fn test_if() { - r#if true { } //~ ERROR found `true` + r#if true { } //~ ERROR found keyword `true` } fn test_struct() { diff --git a/src/test/ui/parser/raw/raw-literal-keywords.stderr b/src/test/ui/parser/raw/raw-literal-keywords.stderr index f39e29cfaa800..4cea605be6f5e 100644 --- a/src/test/ui/parser/raw/raw-literal-keywords.stderr +++ b/src/test/ui/parser/raw/raw-literal-keywords.stderr @@ -1,4 +1,4 @@ -error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `true` +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found keyword `true` --> $DIR/raw-literal-keywords.rs:2:10 | LL | r#if true { } diff --git a/src/test/ui/parser/recover-for-loop-parens-around-head.rs b/src/test/ui/parser/recover-for-loop-parens-around-head.rs index c6be2c90667c2..779e164634478 100644 --- a/src/test/ui/parser/recover-for-loop-parens-around-head.rs +++ b/src/test/ui/parser/recover-for-loop-parens-around-head.rs @@ -8,7 +8,7 @@ fn main() { let vec = vec![1, 2, 3]; for ( elem in vec ) { - //~^ ERROR expected one of `)`, `,`, `@`, or `|`, found `in` + //~^ ERROR expected one of `)`, `,`, `@`, or `|`, found keyword `in` //~| ERROR unexpected closing `)` const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types } diff --git a/src/test/ui/parser/recover-for-loop-parens-around-head.stderr b/src/test/ui/parser/recover-for-loop-parens-around-head.stderr index 1b5b6cca09243..1a1f395ee213e 100644 --- a/src/test/ui/parser/recover-for-loop-parens-around-head.stderr +++ b/src/test/ui/parser/recover-for-loop-parens-around-head.stderr @@ -1,4 +1,4 @@ -error: expected one of `)`, `,`, `@`, or `|`, found `in` +error: expected one of `)`, `,`, `@`, or `|`, found keyword `in` --> $DIR/recover-for-loop-parens-around-head.rs:10:16 | LL | for ( elem in vec ) { diff --git a/src/test/ui/parser/removed-syntax-static-fn.stderr b/src/test/ui/parser/removed-syntax-static-fn.stderr index 21cb71df65751..af148e697118c 100644 --- a/src/test/ui/parser/removed-syntax-static-fn.stderr +++ b/src/test/ui/parser/removed-syntax-static-fn.stderr @@ -1,4 +1,4 @@ -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `static` +error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found keyword `static` --> $DIR/removed-syntax-static-fn.rs:4:5 | LL | impl S { diff --git a/src/test/ui/parser/removed-syntax-uniq-mut-ty.rs b/src/test/ui/parser/removed-syntax-uniq-mut-ty.rs index 79d51f5595d26..f9a9d071a3d1b 100644 --- a/src/test/ui/parser/removed-syntax-uniq-mut-ty.rs +++ b/src/test/ui/parser/removed-syntax-uniq-mut-ty.rs @@ -1 +1,2 @@ -type mut_box = Box; //~ ERROR expected one of `>`, const, lifetime, or type, found `mut` +type mut_box = Box; +//~^ ERROR expected one of `>`, const, lifetime, or type, found keyword `mut` diff --git a/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr b/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr index b6c5749c031e0..9c47e3db67dd3 100644 --- a/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr +++ b/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr @@ -1,4 +1,4 @@ -error: expected one of `>`, const, lifetime, or type, found `mut` +error: expected one of `>`, const, lifetime, or type, found keyword `mut` --> $DIR/removed-syntax-uniq-mut-ty.rs:1:20 | LL | type mut_box = Box; diff --git a/src/test/ui/parser/underscore_item_not_const.rs b/src/test/ui/parser/underscore_item_not_const.rs index 375bdc3a46369..7b0d128f06f8a 100644 --- a/src/test/ui/parser/underscore_item_not_const.rs +++ b/src/test/ui/parser/underscore_item_not_const.rs @@ -25,6 +25,6 @@ use _ as g; //~ ERROR expected identifier, found reserved identifier `_` trait _ {} //~ ERROR expected identifier, found reserved identifier `_` trait _ = Copy; //~ ERROR expected identifier, found reserved identifier `_` macro_rules! _ { () => {} } //~ ERROR expected identifier, found reserved identifier `_` -union _ { f: u8 } //~ ERROR expected one of `!` or `::`, found `_` +union _ { f: u8 } //~ ERROR expected one of `!` or `::`, found reserved identifier `_` fn main() {} diff --git a/src/test/ui/parser/underscore_item_not_const.stderr b/src/test/ui/parser/underscore_item_not_const.stderr index deb4a012e32ab..8814aa3527153 100644 --- a/src/test/ui/parser/underscore_item_not_const.stderr +++ b/src/test/ui/parser/underscore_item_not_const.stderr @@ -82,7 +82,7 @@ error: expected identifier, found reserved identifier `_` LL | macro_rules! _ { () => {} } | ^ expected identifier, found reserved identifier -error: expected one of `!` or `::`, found `_` +error: expected one of `!` or `::`, found reserved identifier `_` --> $DIR/underscore_item_not_const.rs:28:7 | LL | union _ { f: u8 } From e8016c2b13a7e16b6eed9e30b4b6bfe304750566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 24 Oct 2019 15:57:43 -0700 Subject: [PATCH 10/12] review comments --- src/libsyntax/parse/parser/diagnostics.rs | 81 +++++++++---------- src/test/ui/macros/issue-54441.stderr | 2 +- .../parser/macro/trait-non-item-macros.stderr | 2 +- 3 files changed, 41 insertions(+), 44 deletions(-) diff --git a/src/libsyntax/parse/parser/diagnostics.rs b/src/libsyntax/parse/parser/diagnostics.rs index 49949b775750d..ab2b4519cb72a 100644 --- a/src/libsyntax/parse/parser/diagnostics.rs +++ b/src/libsyntax/parse/parser/diagnostics.rs @@ -327,31 +327,27 @@ impl<'a> Parser<'a> { } let sm = self.sess.source_map(); - match (sm.lookup_line(self.token.span.lo()), sm.lookup_line(sp.lo())) { - (Ok(ref a), Ok(ref b)) if a.line == b.line => { - // When the spans are in the same line, it means that the only content between - // them is whitespace, point at the found token in that case: - // - // X | () => { syntax error }; - // | ^^^^^ expected one of 8 possible tokens here - // - // instead of having: - // - // X | () => { syntax error }; - // | -^^^^^ unexpected token - // | | - // | expected one of 8 possible tokens here - err.span_label(self.token.span, label_exp); - } - _ if self.prev_span == syntax_pos::DUMMY_SP => { - // Account for macro context where the previous span might not be - // available to avoid incorrect output (#54841). - err.span_label(self.token.span, "unexpected token"); - } - _ => { - err.span_label(sp, label_exp); - err.span_label(self.token.span, "unexpected token"); - } + if self.prev_span == DUMMY_SP { + // Account for macro context where the previous span might not be + // available to avoid incorrect output (#54841). + err.span_label(self.token.span, label_exp); + } else if !sm.is_multiline(self.token.span.shrink_to_hi().until(sp.shrink_to_lo())) { + // When the spans are in the same line, it means that the only content between + // them is whitespace, point at the found token in that case: + // + // X | () => { syntax error }; + // | ^^^^^ expected one of 8 possible tokens here + // + // instead of having: + // + // X | () => { syntax error }; + // | -^^^^^ unexpected token + // | | + // | expected one of 8 possible tokens here + err.span_label(self.token.span, label_exp); + } else { + err.span_label(sp, label_exp); + err.span_label(self.token.span, "unexpected token"); } self.maybe_annotate_with_ascription(&mut err, false); Err(err) @@ -894,7 +890,12 @@ impl<'a> Parser<'a> { let sm = self.sess.source_map(); let msg = format!("expected `;`, found `{}`", self.this_token_descr()); let appl = Applicability::MachineApplicable; - if self.look_ahead(1, |t| t == &token::CloseDelim(token::Brace) + if self.token.span == DUMMY_SP || self.prev_span == DUMMY_SP { + // Likely inside a macro, can't provide meaninful suggestions. + return self.expect(&token::Semi).map(|_| ()); + } else if !sm.is_multiline(self.prev_span.until(self.token.span)) { + // The current token is in the same line as the prior token, not recoverable. + } else if self.look_ahead(1, |t| t == &token::CloseDelim(token::Brace) || token_can_begin_expr(t) && t.kind != token::Colon ) && [token::Comma, token::Colon].contains(&self.token.kind) { // Likely typo: `,` → `;` or `:` → `;`. This is triggered if the current token is @@ -903,14 +904,12 @@ impl<'a> Parser<'a> { // // let x = 32: // let y = 42; - if sm.is_multiline(self.prev_span.until(self.token.span)) { - self.bump(); - let sp = self.prev_span; - self.struct_span_err(sp, &msg) - .span_suggestion(sp, "change this to `;`", ";".to_string(), appl) - .emit(); - return Ok(()) - } + self.bump(); + let sp = self.prev_span; + self.struct_span_err(sp, &msg) + .span_suggestion(sp, "change this to `;`", ";".to_string(), appl) + .emit(); + return Ok(()) } else if self.look_ahead(0, |t| t == &token::CloseDelim(token::Brace) || ( token_can_begin_expr(t) && t != &token::Semi @@ -921,14 +920,12 @@ impl<'a> Parser<'a> { // // let x = 32 // let y = 42; - if sm.is_multiline(self.prev_span.until(self.token.span)) { - let sp = self.prev_span.shrink_to_hi(); - self.struct_span_err(sp, &msg) - .span_label(self.token.span, "unexpected token") - .span_suggestion_short(sp, "add `;` here", ";".to_string(), appl) - .emit(); - return Ok(()) - } + let sp = self.prev_span.shrink_to_hi(); + self.struct_span_err(sp, &msg) + .span_label(self.token.span, "unexpected token") + .span_suggestion_short(sp, "add `;` here", ";".to_string(), appl) + .emit(); + return Ok(()) } self.expect(&token::Semi).map(|_| ()) // Error unconditionally } diff --git a/src/test/ui/macros/issue-54441.stderr b/src/test/ui/macros/issue-54441.stderr index 9d18d1d517fc4..287d579c76d5f 100644 --- a/src/test/ui/macros/issue-54441.stderr +++ b/src/test/ui/macros/issue-54441.stderr @@ -2,7 +2,7 @@ error: expected one of `crate`, `fn`, `pub`, `static`, or `type`, found keyword --> $DIR/issue-54441.rs:3:9 | LL | let - | ^^^ unexpected token + | ^^^ expected one of `crate`, `fn`, `pub`, `static`, or `type` here ... LL | m!(); | ----- in this macro invocation diff --git a/src/test/ui/parser/macro/trait-non-item-macros.stderr b/src/test/ui/parser/macro/trait-non-item-macros.stderr index 76670e0bde06a..a953e23a710fa 100644 --- a/src/test/ui/parser/macro/trait-non-item-macros.stderr +++ b/src/test/ui/parser/macro/trait-non-item-macros.stderr @@ -2,7 +2,7 @@ error: expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, fo --> $DIR/trait-non-item-macros.rs:2:19 | LL | ($a:expr) => ($a) - | ^^ unexpected token + | ^^ expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe` here ... LL | bah!(2); | -------- in this macro invocation From 92b151287fcda73db8e95eeca8be97d66905626d Mon Sep 17 00:00:00 2001 From: David Wood Date: Sat, 26 Oct 2019 23:59:24 +0100 Subject: [PATCH 11/12] suggest `const_in_array_repeat_expression` flag This commit adds a suggestion to add the `#![feature(const_in_array_repeat_expression)]` attribute to the crate when a promotable expression is used in a repeat expression. Signed-off-by: David Wood --- src/librustc/traits/error_reporting.rs | 11 +++++++- src/librustc/traits/mod.rs | 5 ++-- src/librustc/traits/structural_impls.rs | 2 +- .../borrow_check/nll/type_check/mod.rs | 10 +++++++- src/librustc_mir/transform/promote_consts.rs | 25 +++++++++++++++++++ src/librustc_mir/transform/qualify_consts.rs | 21 ++++++++++------ ...-gate-const_in_array_repeat_expressions.rs | 7 ++++++ ...e-const_in_array_repeat_expressions.stderr | 16 ++++++++++-- 8 files changed, 83 insertions(+), 14 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index b2e5624f4760c..b55c0f29a70ec 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -2112,9 +2112,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.note(&format!("required by cast to type `{}`", self.ty_to_string(target))); } - ObligationCauseCode::RepeatVec => { + ObligationCauseCode::RepeatVec(suggest_const_in_array_repeat_expression) => { err.note("the `Copy` trait is required because the \ repeated element will be copied"); + if suggest_const_in_array_repeat_expression { + err.note("this array initializer can be evaluated at compile-time, for more \ + information, see issue \ + https://github.com/rust-lang/rust/issues/49147"); + if tcx.sess.opts.unstable_features.is_nightly_build() { + err.help("add `#![feature(const_in_array_repeat_expression)]` to the \ + crate attributes to enable"); + } + } } ObligationCauseCode::VariableType(_) => { err.note("all local variables must have a statically known size"); diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 04c1b4d927a9c..b8275299562ce 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -206,8 +206,9 @@ pub enum ObligationCauseCode<'tcx> { SizedReturnType, /// Yield type must be Sized SizedYieldType, - /// [T,..n] --> T must be Copy - RepeatVec, + /// [T,..n] --> T must be Copy. If `true`, suggest `const_in_array_repeat_expression` feature + /// flag. + RepeatVec(bool), /// Types of fields (other than the last, except for packed structs) in a struct must be sized. FieldSized { adt_kind: AdtKind, last: bool }, diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index d9b796d063e26..109e884f8bd16 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -494,7 +494,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::SizedArgumentType => Some(super::SizedArgumentType), super::SizedReturnType => Some(super::SizedReturnType), super::SizedYieldType => Some(super::SizedYieldType), - super::RepeatVec => Some(super::RepeatVec), + super::RepeatVec(suggest_flag) => Some(super::RepeatVec(suggest_flag)), super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }), super::ConstSized => Some(super::ConstSized), super::ConstPatternStructural => Some(super::ConstPatternStructural), diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index b5560fe6751bd..9f2f174553f03 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -16,6 +16,7 @@ use crate::borrow_check::nll::type_check::free_region_relations::{ }; use crate::borrow_check::nll::universal_regions::{DefiningTy, UniversalRegions}; use crate::borrow_check::nll::ToRegionVid; +use crate::transform::promote_consts::should_suggest_const_in_array_repeat_expressions_attribute; use crate::dataflow::move_paths::MoveData; use crate::dataflow::FlowAtLocation; use crate::dataflow::MaybeInitializedPlaces; @@ -1983,12 +1984,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let span = body.source_info(location).span; let ty = operand.ty(body, tcx); if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) { + // To determine if `const_in_array_repeat_expression` feature gate should + // be mentioned, need to check if the rvalue is promotable. + let should_suggest = + should_suggest_const_in_array_repeat_expressions_attribute( + tcx, self.mir_def_id, body, operand); + debug!("check_rvalue: should_suggest={:?}", should_suggest); + self.infcx.report_selection_error( &traits::Obligation::new( ObligationCause::new( span, self.tcx().hir().def_index_to_hir_id(self.mir_def_id.index), - traits::ObligationCauseCode::RepeatVec, + traits::ObligationCauseCode::RepeatVec(should_suggest), ), self.param_env, ty::Predicate::Trait(ty::Binder::bind(ty::TraitPredicate { diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 3af08090853a6..8def717f1580a 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -1110,3 +1110,28 @@ pub fn promote_candidates<'tcx>( promotions } + +/// This function returns `true` if the `const_in_array_repeat_expression` feature attribute should +/// be suggested. This function is probably quite expensive, it shouldn't be run in the happy path. +/// Feature attribute should be suggested if `operand` can be promoted and the feature is not +/// enabled. +crate fn should_suggest_const_in_array_repeat_expressions_attribute<'tcx>( + tcx: TyCtxt<'tcx>, + mir_def_id: DefId, + body: &Body<'tcx>, + operand: &Operand<'tcx>, +) -> bool { + let mut rpo = traversal::reverse_postorder(body); + let (temps, _) = collect_temps_and_candidates(tcx, body, &mut rpo); + let validator = Validator { + item: Item::new(tcx, mir_def_id, body), + temps: &temps, + explicit: false, + }; + + let should_promote = validator.validate_operand(operand).is_ok(); + let feature_flag = tcx.features().const_in_array_repeat_expressions; + debug!("should_suggest_const_in_array_repeat_expressions_flag: mir_def_id={:?} \ + should_promote={:?} feature_flag={:?}", mir_def_id, should_promote, feature_flag); + should_promote && !feature_flag +} diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 2f77cd5ddf716..3702dd9ad493f 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -878,13 +878,11 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { } }, ValueSource::Rvalue(&Rvalue::Repeat(ref operand, _)) => { - let candidate = Candidate::Repeat(location); - let not_promotable = IsNotImplicitlyPromotable::in_operand(self, operand) || - IsNotPromotable::in_operand(self, operand); - debug!("assign: self.def_id={:?} operand={:?}", self.def_id, operand); - if !not_promotable && self.tcx.features().const_in_array_repeat_expressions { - debug!("assign: candidate={:?}", candidate); - self.promotion_candidates.push(candidate); + debug!("assign: self.cx.mode={:?} self.def_id={:?} location={:?} operand={:?}", + self.cx.mode, self.def_id, location, operand); + if self.should_promote_repeat_expression(operand) && + self.tcx.features().const_in_array_repeat_expressions { + self.promotion_candidates.push(Candidate::Repeat(location)); } }, _ => {}, @@ -1149,6 +1147,15 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { candidates } + + /// Returns `true` if the operand of a repeat expression is promotable. + fn should_promote_repeat_expression(&self, operand: &Operand<'tcx>) -> bool { + let not_promotable = IsNotImplicitlyPromotable::in_operand(self, operand) || + IsNotPromotable::in_operand(self, operand); + debug!("should_promote_repeat_expression: operand={:?} not_promotable={:?}", + operand, not_promotable); + !not_promotable + } } impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { diff --git a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs index be195271c10ce..c3c554d7d27f9 100644 --- a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs +++ b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs @@ -3,9 +3,16 @@ struct Bar; +// This function would compile with the feature gate, and tests that it is suggested. fn foo() { let arr: [Option; 2] = [None::; 2]; //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] } +// This function would not compile with the feature gate, and tests that it is not suggested. +fn bar() { + let arr: [Option; 2] = [Some("foo".to_string()); 2]; + //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] +} + fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr index eed69a0c28db8..cd9242de88f25 100644 --- a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied - --> $DIR/feature-gate-const_in_array_repeat_expressions.rs:7:36 + --> $DIR/feature-gate-const_in_array_repeat_expressions.rs:8:36 | LL | let arr: [Option; 2] = [None::; 2]; | ^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` @@ -7,7 +7,19 @@ LL | let arr: [Option; 2] = [None::; 2]; = help: the following implementations were found: as std::marker::Copy> = note: the `Copy` trait is required because the repeated element will be copied + = note: this array initializer can be evaluated at compile-time, for more information, see issue https://github.com/rust-lang/rust/issues/49147 + = help: add `#![feature(const_in_array_repeat_expression)]` to the crate attributes to enable -error: aborting due to previous error +error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied + --> $DIR/feature-gate-const_in_array_repeat_expressions.rs:14:36 + | +LL | let arr: [Option; 2] = [Some("foo".to_string()); 2]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | + = help: the following implementations were found: + as std::marker::Copy> + = note: the `Copy` trait is required because the repeated element will be copied + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. From f1aa8b2c01a97b0114f84b2d557e4598e6070515 Mon Sep 17 00:00:00 2001 From: Agustin Fernandez Date: Mon, 28 Oct 2019 09:15:46 -0400 Subject: [PATCH 12/12] Output previous stable error messaging when using stable build. --- src/librustc/hir/lowering/expr.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/librustc/hir/lowering/expr.rs b/src/librustc/hir/lowering/expr.rs index d5fcc0ef6ede8..73db762a64bda 100644 --- a/src/librustc/hir/lowering/expr.rs +++ b/src/librustc/hir/lowering/expr.rs @@ -235,11 +235,20 @@ impl LoweringContext<'_> { /// ``` fn lower_expr_let(&mut self, span: Span, pat: &Pat, scrutinee: &Expr) -> hir::ExprKind { // If we got here, the `let` expression is not allowed. - self.sess - .struct_span_err(span, "`let` expressions are not supported here") - .note("only supported directly in conditions of `if`- and `while`-expressions") - .note("as well as when nested within `&&` and parenthesis in those conditions") - .emit(); + + if self.sess.opts.unstable_features.is_nightly_build() { + self.sess + .struct_span_err(span, "`let` expressions are not supported here") + .note("only supported directly in conditions of `if`- and `while`-expressions") + .note("as well as when nested within `&&` and parenthesis in those conditions") + .emit(); + } + else { + self.sess + .struct_span_err(span, "expected expression, found statement (`let`)") + .note("variable declaration using `let` is a statement") + .emit(); + } // For better recovery, we emit: // ```