From: bors Date: Tue, 30 Jul 2019 03:38:54 +0000 (+0000) Subject: Auto merge of #63124 - Centril:rollup-onohtqt, r=Centril X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=4eeaaa722d6ac6d24de6e4d3faefb7c44e674b37;hp=04b88a9eba8abbac87eddcb2998beea09589c2c9;p=rust.git Auto merge of #63124 - Centril:rollup-onohtqt, r=Centril Rollup of 12 pull requests Successful merges: - #61965 (Remove mentions of removed `offset_to` method from `align_offset` docs) - #62928 (Syntax: Recover on `for ( $pat in $expr ) $block`) - #63000 (Impl Debug for Chars) - #63083 (Make generic parameters always use modern hygiene) - #63087 (Add very simple edition check to tidy.) - #63093 (Properly check the defining scope of existential types) - #63096 (Add tests for some `existential_type` ICEs) - #63099 (vxworks: Remove Linux-specific comments.) - #63106 (ci: Skip installing SWIG/xz on OSX ) - #63108 (Add links to None in Option doc) - #63109 (std: Fix a failing `fs` test on Windows) - #63111 (Add syntactic and semantic tests for rest patterns, i.e. `..`) Failed merges: r? @ghost --- diff --git a/.azure-pipelines/steps/run.yml b/.azure-pipelines/steps/run.yml index 1e49cc00921..ca32888b74c 100644 --- a/.azure-pipelines/steps/run.yml +++ b/.azure-pipelines/steps/run.yml @@ -62,17 +62,6 @@ steps: - template: install-sccache.yml - template: install-clang.yml -# Install some dependencies needed to build LLDB/Clang, currently only needed -# during the `dist` target -- bash: | - set -e - brew update - brew install xz - brew install swig@3 - brew link --force swig@3 - displayName: Install build dependencies (OSX) - condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin'), eq(variables['SCRIPT'],'./x.py dist')) - # Switch to XCode 9.3 on OSX since it seems to be the last version that supports # i686-apple-darwin. We'll eventually want to upgrade this and it will probably # force us to drop i686-apple-darwin, but let's keep the wheels turning for now. diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index b197516403f..c5198ca39fe 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -1108,6 +1108,16 @@ fn test_iterator_last() { assert_eq!(it.last(), Some('m')); } +#[test] +fn test_chars_debug() { + let s = "ศไทย中华Việt Nam"; + let c = s.chars(); + assert_eq!( + format!("{:?}", c), + r#"Chars(['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm'])"# + ); +} + #[test] fn test_bytesator() { let s = "ศไทย中华Việt Nam"; diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 70a87cfe5a7..7713e5761d4 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -8,7 +8,7 @@ //! * Initial values //! * Return values for functions that are not defined //! over their entire input range (partial functions) -//! * Return value for otherwise reporting simple errors, where `None` is +//! * Return value for otherwise reporting simple errors, where [`None`] is //! returned on error //! * Optional struct fields //! * Struct fields that can be loaned or "taken" @@ -752,7 +752,7 @@ pub fn or_else Option>(self, f: F) -> Option { } } - /// Returns [`Some`] if exactly one of `self`, `optb` is [`Some`], otherwise returns `None`. + /// Returns [`Some`] if exactly one of `self`, `optb` is [`Some`], otherwise returns [`None`]. /// /// [`Some`]: #variant.Some /// [`None`]: #variant.None diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index a7f6926de42..a1f96905dc9 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -1609,7 +1609,7 @@ pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) /// `usize::max_value()`. /// /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be - /// used with the `offset` or `offset_to` methods. + /// used with the `add` method. /// /// There are no guarantees whatsover that offsetting the pointer will not overflow or go /// beyond the allocation that the pointer points into. It is up to the caller to ensure that @@ -2410,7 +2410,7 @@ pub unsafe fn swap(self, with: *mut T) /// `usize::max_value()`. /// /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be - /// used with the `offset` or `offset_to` methods. + /// used with the `add` method. /// /// There are no guarantees whatsover that offsetting the pointer will not overflow or go /// beyond the allocation that the pointer points into. It is up to the caller to ensure that diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 4ecaa37460c..4faf9ff4d2e 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -464,7 +464,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// /// [`chars`]: ../../std/primitive.str.html#method.chars /// [`str`]: ../../std/primitive.str.html -#[derive(Clone, Debug)] +#[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Chars<'a> { iter: slice::Iter<'a, u8> @@ -600,6 +600,16 @@ fn last(mut self) -> Option { } } +#[stable(feature = "chars_debug_impl", since = "1.38.0")] +impl fmt::Debug for Chars<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Chars(")?; + f.debug_list().entries(self.clone()).finish()?; + write!(f, ")")?; + Ok(()) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a> DoubleEndedIterator for Chars<'a> { #[inline] diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 5acc3fd2fbc..73a76ebcb74 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -1189,11 +1189,7 @@ pub fn may_define_existential_type( opaque_hir_id: hir::HirId, ) -> bool { let mut hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - trace!( - "may_define_existential_type(def={:?}, opaque_node={:?})", - tcx.hir().get(hir_id), - tcx.hir().get(opaque_hir_id) - ); + // Named existential types can be defined by any siblings or children of siblings. let scope = tcx.hir().get_defining_scope(opaque_hir_id).expect("could not get defining scope"); @@ -1202,5 +1198,12 @@ pub fn may_define_existential_type( hir_id = tcx.hir().get_parent_item(hir_id); } // Syntactically, we are allowed to define the concrete type if: - hir_id == scope + let res = hir_id == scope; + trace!( + "may_define_existential_type(def={:?}, opaque_node={:?}) = {}", + tcx.hir().get(hir_id), + tcx.hir().get(opaque_hir_id), + res + ); + res } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index e2b1b54cef3..f6c62d191fa 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -2568,7 +2568,7 @@ fn check_lifetime_params( let lifetimes: Vec<_> = params .iter() .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => Some((param, param.name)), + GenericParamKind::Lifetime { .. } => Some((param, param.name.modern())), _ => None, }) .collect(); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index bc5898fe78d..c8dd8282fd0 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -869,8 +869,7 @@ fn visit_fn(&mut self, debug!("(resolving function) entering function"); let rib_kind = match function_kind { FnKind::ItemFn(..) => FnItemRibKind, - FnKind::Method(..) => AssocItemRibKind, - FnKind::Closure(_) => NormalRibKind, + FnKind::Method(..) | FnKind::Closure(_) => NormalRibKind, }; // Create a value rib for the function. @@ -2307,21 +2306,32 @@ fn resolve_ident_in_lexical_scope(&mut self, if ident.name == kw::Invalid { return Some(LexicalScopeBinding::Res(Res::Err)); } - ident.span = if ident.name == kw::SelfUpper { + let (general_span, modern_span) = if ident.name == kw::SelfUpper { // FIXME(jseyfried) improve `Self` hygiene - ident.span.with_ctxt(SyntaxContext::empty()) + let empty_span = ident.span.with_ctxt(SyntaxContext::empty()); + (empty_span, empty_span) } else if ns == TypeNS { - ident.span.modern() + let modern_span = ident.span.modern(); + (modern_span, modern_span) } else { - ident.span.modern_and_legacy() + (ident.span.modern_and_legacy(), ident.span.modern()) }; + ident.span = general_span; + let modern_ident = Ident { span: modern_span, ..ident }; // Walk backwards up the ribs in scope. let record_used = record_used_id.is_some(); let mut module = self.graph_root; for i in (0 .. self.ribs[ns].len()).rev() { debug!("walk rib\n{:?}", self.ribs[ns][i].bindings); - if let Some(res) = self.ribs[ns][i].bindings.get(&ident).cloned() { + // Use the rib kind to determine whether we are resolving parameters + // (modern hygiene) or local variables (legacy hygiene). + let rib_ident = if let AssocItemRibKind | ItemRibKind = self.ribs[ns][i].kind { + modern_ident + } else { + ident + }; + if let Some(res) = self.ribs[ns][i].bindings.get(&rib_ident).cloned() { // The ident resolves to a type parameter or local variable. return Some(LexicalScopeBinding::Res( self.validate_res_from_ribs(ns, i, res, record_used, path_span), @@ -2357,7 +2367,7 @@ fn resolve_ident_in_lexical_scope(&mut self, } } - ident.span = ident.span.modern(); + ident = modern_ident; let mut poisoned = None; loop { let opt_module = if let Some(node_id) = record_used_id { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 053ef1f8f82..395e266ae46 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1664,6 +1664,7 @@ fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'thi intravisit::NestedVisitorMap::All(&self.tcx.hir()) } fn visit_item(&mut self, it: &'tcx Item) { + debug!("find_existential_constraints: visiting {:?}", it); let def_id = self.tcx.hir().local_def_id(it.hir_id); // The existential type itself or its children are not within its reveal scope. if def_id != self.def_id { @@ -1672,6 +1673,7 @@ fn visit_item(&mut self, it: &'tcx Item) { } } fn visit_impl_item(&mut self, it: &'tcx ImplItem) { + debug!("find_existential_constraints: visiting {:?}", it); let def_id = self.tcx.hir().local_def_id(it.hir_id); // The existential type itself or its children are not within its reveal scope. if def_id != self.def_id { @@ -1680,6 +1682,7 @@ fn visit_impl_item(&mut self, it: &'tcx ImplItem) { } } fn visit_trait_item(&mut self, it: &'tcx TraitItem) { + debug!("find_existential_constraints: visiting {:?}", it); let def_id = self.tcx.hir().local_def_id(it.hir_id); self.check(def_id); intravisit::walk_trait_item(self, it); @@ -1703,9 +1706,23 @@ fn visit_trait_item(&mut self, it: &'tcx TraitItem) { } else { debug!("find_existential_constraints: scope={:?}", tcx.hir().get(scope)); match tcx.hir().get(scope) { - Node::Item(ref it) => intravisit::walk_item(&mut locator, it), - Node::ImplItem(ref it) => intravisit::walk_impl_item(&mut locator, it), - Node::TraitItem(ref it) => intravisit::walk_trait_item(&mut locator, it), + // We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods + // This allows our visitor to process the defining item itself, causing + // it to pick up any 'sibling' defining uses. + // + // For example, this code: + // ``` + // fn foo() { + // existential type Blah: Debug; + // let my_closure = || -> Blah { true }; + // } + // ``` + // + // requires us to explicitly process `foo()` in order + // to notice the defining usage of `Blah`. + Node::Item(ref it) => locator.visit_item(it), + Node::ImplItem(ref it) => locator.visit_impl_item(it), + Node::TraitItem(ref it) => locator.visit_trait_item(it), other => bug!( "{:?} is not a valid scope for an existential type item", other diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index d41b3a3a123..f7c32a5c20d 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -3316,11 +3316,11 @@ fn realpath_works_tricky() { fs::create_dir_all(&d).unwrap(); File::create(&f).unwrap(); if cfg!(not(windows)) { - symlink_dir("../d/e", &c).unwrap(); + symlink_file("../d/e", &c).unwrap(); symlink_file("../f", &e).unwrap(); } if cfg!(windows) { - symlink_dir(r"..\d\e", &c).unwrap(); + symlink_file(r"..\d\e", &c).unwrap(); symlink_file(r"..\f", &e).unwrap(); } diff --git a/src/libstd/sys/vxworks/fs.rs b/src/libstd/sys/vxworks/fs.rs index 4eb185c4d57..d537d2258fd 100644 --- a/src/libstd/sys/vxworks/fs.rs +++ b/src/libstd/sys/vxworks/fs.rs @@ -287,22 +287,7 @@ pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result { let fd = cvt_r(|| unsafe { open(path.as_ptr(), flags, opts.mode as c_int) })?; - let fd = FileDesc::new(fd); - // Currently the standard library supports Linux 2.6.18 which did not - // have the O_CLOEXEC flag (passed above). If we're running on an older - // Linux kernel then the flag is just ignored by the OS. After we open - // the first file, we check whether it has CLOEXEC set. If it doesn't, - // we will explicitly ask for a CLOEXEC fd for every further file we - // open, if it does, we will skip that step. - // - // The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc - // that we support, so we only do this on Linux currently. - fn ensure_cloexec(_: &FileDesc) -> io::Result<()> { - Ok(()) - } - - ensure_cloexec(&fd)?; - Ok(File(fd)) + Ok(File(FileDesc::new(fd))) } pub fn file_attr(&self) -> io::Result { diff --git a/src/libstd/sys/vxworks/net.rs b/src/libstd/sys/vxworks/net.rs index aa6b93c8600..56962e11dcf 100644 --- a/src/libstd/sys/vxworks/net.rs +++ b/src/libstd/sys/vxworks/net.rs @@ -141,10 +141,6 @@ pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Resul pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result { - // Unfortunately the only known way right now to accept a socket and - // atomically set the CLOEXEC flag is to use the `accept4` syscall on - // Linux. This was added in 2.6.28, however, and because we support - // 2.6.18 we must detect this support dynamically. let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?; diff --git a/src/libstd/sys/vxworks/pipe.rs b/src/libstd/sys/vxworks/pipe.rs index 83637832ff3..e09dbe6e99b 100644 --- a/src/libstd/sys/vxworks/pipe.rs +++ b/src/libstd/sys/vxworks/pipe.rs @@ -11,11 +11,6 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { static INVALID: AtomicBool = AtomicBool::new(false); let mut fds = [0; 2]; - - // Unfortunately the only known way right now to create atomically set the - // CLOEXEC flag is to use the `pipe2` syscall on Linux. This was added in - // 2.6.27, however, and because we support 2.6.18 we must detect this - // support dynamically. cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?; let fd0 = FileDesc::new(fds[0]); diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index 39cb5042fbc..9eb6aa303b0 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -14,7 +14,7 @@ use crate::util::parser::AssocOp; use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_data_structures::fx::FxHashSet; -use syntax_pos::{Span, DUMMY_SP, MultiSpan}; +use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError}; use log::{debug, trace}; use std::mem; @@ -199,6 +199,10 @@ pub fn span_err>(&self, sp: S, m: &str) { &self.sess.span_diagnostic } + crate fn span_to_snippet(&self, span: Span) -> Result { + self.sess.source_map().span_to_snippet(span) + } + crate fn expected_ident_found(&self) -> DiagnosticBuilder<'a> { let mut err = self.struct_span_err( self.token.span, @@ -549,8 +553,10 @@ pub fn maybe_annotate_with_ascription( ExprKind::Binary(op, _, _) if op.node.is_comparison() => { // respan to include both operators let op_span = op.span.to(self.token.span); - let mut err = self.diagnostic().struct_span_err(op_span, - "chained comparison operators require parentheses"); + let mut err = self.struct_span_err( + op_span, + "chained comparison operators require parentheses", + ); if op.node == BinOpKind::Lt && *outer_op == AssocOp::Less || // Include `<` to provide this recommendation *outer_op == AssocOp::Greater // even in a case like the following: @@ -717,8 +723,6 @@ pub fn maybe_annotate_with_ascription( path.span = ty_span.to(self.prev_span); let ty_str = self - .sess - .source_map() .span_to_snippet(ty_span) .unwrap_or_else(|_| pprust::ty_to_string(&ty)); self.diagnostic() @@ -889,7 +893,7 @@ pub fn unexpected_try_recover( err.span_label(await_sp, "while parsing this incorrect await expression"); err })?; - let expr_str = self.sess.source_map().span_to_snippet(expr.span) + let expr_str = self.span_to_snippet(expr.span) .unwrap_or_else(|_| pprust::expr_to_string(&expr)); let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" }); let sp = lo.to(expr.span); @@ -923,6 +927,48 @@ pub fn unexpected_try_recover( } } + /// Recover a situation like `for ( $pat in $expr )` + /// and suggest writing `for $pat in $expr` instead. + /// + /// This should be called before parsing the `$block`. + crate fn recover_parens_around_for_head( + &mut self, + pat: P, + expr: &Expr, + begin_paren: Option, + ) -> P { + match (&self.token.kind, begin_paren) { + (token::CloseDelim(token::Paren), Some(begin_par_sp)) => { + self.bump(); + + let pat_str = self + // Remove the `(` from the span of the pattern: + .span_to_snippet(pat.span.trim_start(begin_par_sp).unwrap()) + .unwrap_or_else(|_| pprust::pat_to_string(&pat)); + + self.struct_span_err(self.prev_span, "unexpected closing `)`") + .span_label(begin_par_sp, "opening `(`") + .span_suggestion( + begin_par_sp.to(self.prev_span), + "remove parenthesis in `for` loop", + format!("{} in {}", pat_str, pprust::expr_to_string(&expr)), + // With e.g. `for (x) in y)` this would replace `(x) in y)` + // with `x) in y)` which is syntactically invalid. + // However, this is prevented before we get here. + Applicability::MachineApplicable, + ) + .emit(); + + // Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint. + pat.and_then(|pat| match pat.node { + PatKind::Paren(pat) => pat, + _ => P(pat), + }) + } + _ => pat, + } + } + crate fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool { self.token.is_ident() && if let ast::ExprKind::Path(..) = node { true } else { false } && @@ -1105,17 +1151,14 @@ pub fn unexpected_try_recover( crate fn check_for_for_in_in_typo(&mut self, in_span: Span) { if self.eat_keyword(kw::In) { // a common typo: `for _ in in bar {}` - let mut err = self.sess.span_diagnostic.struct_span_err( - self.prev_span, - "expected iterable, found keyword `in`", - ); - err.span_suggestion_short( - in_span.until(self.prev_span), - "remove the duplicated `in`", - String::new(), - Applicability::MachineApplicable, - ); - err.emit(); + self.struct_span_err(self.prev_span, "expected iterable, found keyword `in`") + .span_suggestion_short( + in_span.until(self.prev_span), + "remove the duplicated `in`", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); } } @@ -1128,12 +1171,12 @@ pub fn unexpected_try_recover( crate fn eat_incorrect_doc_comment_for_arg_type(&mut self) { if let token::DocComment(_) = self.token.kind { - let mut err = self.diagnostic().struct_span_err( + self.struct_span_err( self.token.span, "documentation comments cannot be applied to a function parameter's type", - ); - err.span_label(self.token.span, "doc comments are not allowed here"); - err.emit(); + ) + .span_label(self.token.span, "doc comments are not allowed here") + .emit(); self.bump(); } else if self.token == token::Pound && self.look_ahead(1, |t| { *t == token::OpenDelim(token::Bracket) @@ -1145,12 +1188,12 @@ pub fn unexpected_try_recover( } let sp = lo.to(self.token.span); self.bump(); - let mut err = self.diagnostic().struct_span_err( + self.struct_span_err( sp, "attributes cannot be applied to a function parameter's type", - ); - err.span_label(sp, "attributes are not allowed here"); - err.emit(); + ) + .span_label(sp, "attributes are not allowed here") + .emit(); } } @@ -1206,18 +1249,19 @@ pub fn unexpected_try_recover( self.expect(&token::Colon)?; let ty = self.parse_ty()?; - let mut err = self.diagnostic().struct_span_err_with_code( - pat.span, - "patterns aren't allowed in methods without bodies", - DiagnosticId::Error("E0642".into()), - ); - err.span_suggestion_short( - pat.span, - "give this argument a name or use an underscore to ignore it", - "_".to_owned(), - Applicability::MachineApplicable, - ); - err.emit(); + self.diagnostic() + .struct_span_err_with_code( + pat.span, + "patterns aren't allowed in methods without bodies", + DiagnosticId::Error("E0642".into()), + ) + .span_suggestion_short( + pat.span, + "give this argument a name or use an underscore to ignore it", + "_".to_owned(), + Applicability::MachineApplicable, + ) + .emit(); // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. let pat = P(Pat { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6cb965bf817..fb5ff7e8f98 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2329,19 +2329,19 @@ fn maybe_parse_struct_expr( // This is a struct literal, but we don't can't accept them here let expr = self.parse_struct_expr(lo, path.clone(), attrs.clone()); if let (Ok(expr), false) = (&expr, struct_allowed) { - let mut err = self.diagnostic().struct_span_err( + self.struct_span_err( expr.span, "struct literals are not allowed here", - ); - err.multipart_suggestion( + ) + .multipart_suggestion( "surround the struct literal with parentheses", vec![ (lo.shrink_to_lo(), "(".to_string()), (expr.span.shrink_to_hi(), ")".to_string()), ], Applicability::MachineApplicable, - ); - err.emit(); + ) + .emit(); } return Some(expr); } @@ -2370,18 +2370,18 @@ fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec { @@ -2792,21 +2791,20 @@ fn parse_prefix_expr(&mut self, if cannot_continue_expr { self.bump(); // Emit the error ... - let mut err = self.diagnostic() - .struct_span_err(self.token.span, - &format!("unexpected {} after identifier", - self.this_token_descr())); - // span the `not` plus trailing whitespace to avoid - // trailing whitespace after the `!` in our suggestion - let to_replace = self.sess.source_map() - .span_until_non_whitespace(lo.to(self.token.span)); - err.span_suggestion_short( - to_replace, + self.struct_span_err( + self.token.span, + &format!("unexpected {} after identifier",self.this_token_descr()) + ) + .span_suggestion_short( + // Span the `not` plus trailing whitespace to avoid + // trailing whitespace after the `!` in our suggestion + self.sess.source_map() + .span_until_non_whitespace(lo.to(self.token.span)), "use `!` to perform logical negation", "!".to_owned(), Applicability::MachineApplicable - ); - err.emit(); + ) + .emit(); // —and recover! (just as if we were in the block // for the `token::Not` arm) let e = self.parse_prefix_expr(None); @@ -2884,7 +2882,7 @@ fn parse_assoc_expr_with( // We've found an expression that would be parsed as a statement, but the next // token implies this should be parsed as an expression. // For example: `if let Some(x) = x { x } else { 0 } / 2` - let mut err = self.sess.span_diagnostic.struct_span_err(self.token.span, &format!( + let mut err = self.struct_span_err(self.token.span, &format!( "expected expression, found `{}`", pprust::token_to_string(&self.token), )); @@ -3072,28 +3070,29 @@ fn parse_assoc_op_cast(&mut self, lhs: P, lhs_span: Span, // in AST and continue parsing. let msg = format!("`<` is interpreted as a start of generic \ arguments for `{}`, not a {}", path, op_noun); - let mut err = - self.sess.span_diagnostic.struct_span_err(self.token.span, &msg); let span_after_type = parser_snapshot_after_type.token.span; - err.span_label(self.look_ahead(1, |t| t.span).to(span_after_type), - "interpreted as generic arguments"); - err.span_label(self.token.span, format!("not interpreted as {}", op_noun)); - let expr = mk_expr(self, P(Ty { span: path.span, node: TyKind::Path(None, path), id: ast::DUMMY_NODE_ID })); - let expr_str = self.sess.source_map().span_to_snippet(expr.span) - .unwrap_or_else(|_| pprust::expr_to_string(&expr)); - err.span_suggestion( - expr.span, - &format!("try {} the cast value", op_verb), - format!("({})", expr_str), - Applicability::MachineApplicable - ); - err.emit(); + let expr_str = self.span_to_snippet(expr.span) + .unwrap_or_else(|_| pprust::expr_to_string(&expr)); + + self.struct_span_err(self.token.span, &msg) + .span_label( + self.look_ahead(1, |t| t.span).to(span_after_type), + "interpreted as generic arguments" + ) + .span_label(self.token.span, format!("not interpreted as {}", op_noun)) + .span_suggestion( + expr.span, + &format!("try {} the cast value", op_verb), + format!("({})", expr_str), + Applicability::MachineApplicable + ) + .emit(); Ok(expr) } @@ -3276,26 +3275,40 @@ fn parse_else_expr(&mut self) -> PResult<'a, P> { } /// Parse a 'for' .. 'in' expression ('for' token already eaten) - fn parse_for_expr(&mut self, opt_label: Option