diff --git a/.azure-pipelines/steps/run.yml b/.azure-pipelines/steps/run.yml index 1e49cc00921cd..ca32888b74c34 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 b197516403f78..c5198ca39fedf 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 70a87cfe5a78a..7713e5761d4bd 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 @@ impl<T> Option<T> { } } - /// 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 a7f6926de4263..a1f96905dc99b 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -1609,7 +1609,7 @@ impl<T: ?Sized> *const 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 @@ -2410,7 +2410,7 @@ impl<T: ?Sized> *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 4ecaa37460c66..4faf9ff4d2ee2 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -464,7 +464,7 @@ Section: Iterators /// /// [`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 @@ impl<'a> Iterator for Chars<'a> { } } +#[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 5acc3fd2fbcfd..73a76ebcb74f4 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 e2b1b54cef39f..f6c62d191fa62 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -2568,7 +2568,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { 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/query/mod.rs b/src/librustc/query/mod.rs index 67fc3520745dd..5ab1b90642a6a 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -461,7 +461,7 @@ rustc_queries! { } TypeChecking { - query check_match(key: DefId) -> () { + query check_match(key: DefId) -> SignalledError { cache_on_disk_if { key.is_local() } } diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index f4b99ca368874..fb2ad2aa54d7a 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -4,7 +4,7 @@ use crate::hir::def::{DefKind, Export}; use crate::hir::{self, TraitCandidate, ItemLocalId, CodegenFnAttrs}; use crate::infer::canonical::{self, Canonical}; use crate::lint; -use crate::middle::borrowck::BorrowCheckResult; +use crate::middle::borrowck::{BorrowCheckResult, SignalledError}; use crate::middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary, ForeignModule}; use crate::middle::cstore::{NativeLibraryKind, DepKind, CrateSource}; use crate::middle::privacy::AccessLevels; diff --git a/src/librustc_ast_borrowck/borrowck/mod.rs b/src/librustc_ast_borrowck/borrowck/mod.rs index f8ad8baa5974d..3bbd7ae5c352f 100644 --- a/src/librustc_ast_borrowck/borrowck/mod.rs +++ b/src/librustc_ast_borrowck/borrowck/mod.rs @@ -66,6 +66,13 @@ fn borrowck(tcx: TyCtxt<'_>, owner_def_id: DefId) -> &BorrowCheckResult { debug!("borrowck(body_owner_def_id={:?})", owner_def_id); + let signalled_error = tcx.check_match(owner_def_id); + if let SignalledError::SawSomeError = signalled_error { + return tcx.arena.alloc(BorrowCheckResult { + signalled_any_error: SignalledError::SawSomeError, + }) + } + let owner_id = tcx.hir().as_local_hir_id(owner_def_id).unwrap(); match tcx.hir().get(owner_id) { diff --git a/src/librustc_mir/error_codes.rs b/src/librustc_mir/error_codes.rs index a5e44a1933c9d..2afffd71fe206 100644 --- a/src/librustc_mir/error_codes.rs +++ b/src/librustc_mir/error_codes.rs @@ -1989,7 +1989,7 @@ When matching on a variable it cannot be mutated in the match guards, as this could cause the match to be non-exhaustive: ```compile_fail,E0510 -#![feature(nll, bind_by_move_pattern_guards)] +#![feature(bind_by_move_pattern_guards)] let mut x = Some(0); match x { None => (), diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 32a8c5cd3bb28..17fd9377a1629 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -4,6 +4,7 @@ use super::_match::WitnessPreference::*; use super::{Pattern, PatternContext, PatternError, PatternKind}; +use rustc::middle::borrowck::SignalledError; use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; use rustc::middle::expr_use_visitor::{LoanCause, MutateMode}; use rustc::middle::expr_use_visitor as euv; @@ -26,21 +27,24 @@ use std::slice; use syntax_pos::{Span, DUMMY_SP, MultiSpan}; -pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { +crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) -> SignalledError { let body_id = if let Some(id) = tcx.hir().as_local_hir_id(def_id) { tcx.hir().body_owned_by(id) } else { - return; + return SignalledError::NoErrorsSeen; }; - MatchVisitor { + let mut visitor = MatchVisitor { tcx, body_owner: def_id, tables: tcx.body_tables(body_id), region_scope_tree: &tcx.region_scope_tree(def_id), param_env: tcx.param_env(def_id), identity_substs: InternalSubsts::identity_for_item(tcx, def_id), - }.visit_body(tcx.hir().body(body_id)); + signalled_error: SignalledError::NoErrorsSeen, + }; + visitor.visit_body(tcx.hir().body(body_id)); + visitor.signalled_error } fn create_e0004(sess: &Session, sp: Span, error_message: String) -> DiagnosticBuilder<'_> { @@ -54,6 +58,7 @@ struct MatchVisitor<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, identity_substs: SubstsRef<'tcx>, region_scope_tree: &'a region::ScopeTree, + signalled_error: SignalledError, } impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> { @@ -64,11 +69,8 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> { fn visit_expr(&mut self, ex: &'tcx hir::Expr) { intravisit::walk_expr(self, ex); - match ex.node { - hir::ExprKind::Match(ref scrut, ref arms, source) => { - self.check_match(scrut, arms, source); - } - _ => {} + if let hir::ExprKind::Match(ref scrut, ref arms, source) = ex.node { + self.check_match(scrut, arms, source); } } @@ -130,7 +132,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { - fn check_patterns(&self, has_guard: bool, pats: &[P<Pat>]) { + fn check_patterns(&mut self, has_guard: bool, pats: &[P<Pat>]) { check_legality_of_move_bindings(self, has_guard, pats); for pat in pats { check_legality_of_bindings_in_at_patterns(self, pat); @@ -138,11 +140,11 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { } fn check_match( - &self, + &mut self, scrut: &hir::Expr, arms: &'tcx [hir::Arm], - source: hir::MatchSource) - { + source: hir::MatchSource + ) { for arm in arms { // First, check legality of move bindings. self.check_patterns(arm.guard.is_some(), &arm.pats); @@ -150,6 +152,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { // Second, if there is a guard on each arm, make sure it isn't // assigning or borrowing anything mutably. if let Some(ref guard) = arm.guard { + self.signalled_error = SignalledError::SawSomeError; if !self.tcx.features().bind_by_move_pattern_guards { check_for_mutation_in_guard(self, &guard); } @@ -548,7 +551,7 @@ fn maybe_point_at_variant( // Legality of move bindings checking fn check_legality_of_move_bindings( - cx: &MatchVisitor<'_, '_>, + cx: &mut MatchVisitor<'_, '_>, has_guard: bool, pats: &[P<Pat>], ) { @@ -565,7 +568,12 @@ fn check_legality_of_move_bindings( }) } let span_vec = &mut Vec::new(); - let check_move = |p: &Pat, sub: Option<&Pat>, span_vec: &mut Vec<Span>| { + let check_move = | + cx: &mut MatchVisitor<'_, '_>, + p: &Pat, + sub: Option<&Pat>, + span_vec: &mut Vec<Span>, + | { // check legality of moving out of the enum // x @ Foo(..) is legal, but x @ Foo(y) isn't. @@ -574,15 +582,17 @@ fn check_legality_of_move_bindings( "cannot bind by-move with sub-bindings") .span_label(p.span, "binds an already bound by-move value by moving it") .emit(); - } else if has_guard && !cx.tcx.features().bind_by_move_pattern_guards { - let mut err = struct_span_err!(cx.tcx.sess, p.span, E0008, - "cannot bind by-move into a pattern guard"); - err.span_label(p.span, "moves value into pattern guard"); - if cx.tcx.sess.opts.unstable_features.is_nightly_build() { - err.help("add `#![feature(bind_by_move_pattern_guards)]` to the \ - crate attributes to enable"); + } else if has_guard { + if !cx.tcx.features().bind_by_move_pattern_guards { + let mut err = struct_span_err!(cx.tcx.sess, p.span, E0008, + "cannot bind by-move into a pattern guard"); + err.span_label(p.span, "moves value into pattern guard"); + if cx.tcx.sess.opts.unstable_features.is_nightly_build() { + err.help("add `#![feature(bind_by_move_pattern_guards)]` to the \ + crate attributes to enable"); + } + err.emit(); } - err.emit(); } else if let Some(_by_ref_span) = by_ref_span { span_vec.push(p.span); } @@ -596,7 +606,7 @@ fn check_legality_of_move_bindings( ty::BindByValue(..) => { let pat_ty = cx.tables.node_type(p.hir_id); if !pat_ty.is_copy_modulo_regions(cx.tcx, cx.param_env, pat.span) { - check_move(p, sub.as_ref().map(|p| &**p), span_vec); + check_move(cx, p, sub.as_ref().map(|p| &**p), span_vec); } } _ => {} diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index bc5898fe78da7..c8dd8282fd0f9 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -869,8 +869,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { 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 @@ impl<'a> Resolver<'a> { 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 @@ impl<'a> Resolver<'a> { } } - 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 053ef1f8f8297..395e266ae46aa 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1664,6 +1664,7 @@ fn find_existential_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { 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 find_existential_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } } 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 find_existential_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } } 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 find_existential_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } 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 d41b3a3a1233f..f7c32a5c20d3d 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -3316,11 +3316,11 @@ mod tests { 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 4eb185c4d57ac..d537d2258fda7 100644 --- a/src/libstd/sys/vxworks/fs.rs +++ b/src/libstd/sys/vxworks/fs.rs @@ -287,22 +287,7 @@ impl File { 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<FileAttr> { diff --git a/src/libstd/sys/vxworks/net.rs b/src/libstd/sys/vxworks/net.rs index aa6b93c860069..56962e11dcf95 100644 --- a/src/libstd/sys/vxworks/net.rs +++ b/src/libstd/sys/vxworks/net.rs @@ -141,10 +141,6 @@ impl Socket { pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result<Socket> { - // 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 83637832ff327..e09dbe6e99ba8 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 39cb5042fbc11..9eb6aa303b06b 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -14,7 +14,7 @@ use crate::ThinVec; 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 @@ impl<'a> Parser<'a> { &self.sess.span_diagnostic } + crate fn span_to_snippet(&self, span: Span) -> Result<String, SpanSnippetError> { + 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 @@ impl<'a> Parser<'a> { 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 @@ impl<'a> Parser<'a> { 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 @@ impl<'a> Parser<'a> { 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 @@ impl<'a> Parser<'a> { } } + /// 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<Pat>, + expr: &Expr, + begin_paren: Option<Span>, + ) -> P<Pat> { + 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 @@ impl<'a> Parser<'a> { 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 @@ impl<'a> Parser<'a> { 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 @@ impl<'a> Parser<'a> { } 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 @@ impl<'a> Parser<'a> { 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 6cb965bf817d1..fb5ff7e8f9862 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2329,19 +2329,19 @@ impl<'a> Parser<'a> { // 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 @@ impl<'a> Parser<'a> { } } if self.token == token::Comma { - let mut err = self.sess.span_diagnostic.mut_span_err( + self.struct_span_err( exp_span.to(self.prev_span), "cannot use a comma after the base struct", - ); - err.span_suggestion_short( + ) + .span_suggestion_short( self.token.span, "remove this comma", String::new(), Applicability::MachineApplicable - ); - err.note("the base struct must always be the last field"); - err.emit(); + ) + .note("the base struct must always be the last field") + .emit(); self.recover_stmt(); } break; @@ -2736,15 +2736,14 @@ impl<'a> Parser<'a> { let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; let span_of_tilde = lo; - let mut err = self.diagnostic() - .struct_span_err(span_of_tilde, "`~` cannot be used as a unary operator"); - err.span_suggestion_short( - span_of_tilde, - "use `!` to perform bitwise negation", - "!".to_owned(), - Applicability::MachineApplicable - ); - err.emit(); + self.struct_span_err(span_of_tilde, "`~` cannot be used as a unary operator") + .span_suggestion_short( + span_of_tilde, + "use `!` to perform bitwise negation", + "!".to_owned(), + Applicability::MachineApplicable + ) + .emit(); (lo.to(span), self.mk_unary(UnOp::Not, e)) } token::BinOp(token::Minus) => { @@ -2792,21 +2791,20 @@ impl<'a> Parser<'a> { 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 @@ impl<'a> Parser<'a> { // 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 @@ impl<'a> Parser<'a> { // 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 @@ impl<'a> Parser<'a> { } /// Parse a 'for' .. 'in' expression ('for' token already eaten) - fn parse_for_expr(&mut self, opt_label: Option<Label>, - span_lo: Span, - mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { + fn parse_for_expr( + &mut self, + opt_label: Option<Label>, + span_lo: Span, + mut attrs: ThinVec<Attribute> + ) -> PResult<'a, P<Expr>> { // Parse: `for <src_pat> in <src_expr> <src_loop_block>` + // Record whether we are about to parse `for (`. + // This is used below for recovery in case of `for ( $stuff ) $block` + // in which case we will suggest `for $stuff $block`. + let begin_paren = match self.token.kind { + token::OpenDelim(token::Paren) => Some(self.token.span), + _ => None, + }; + let pat = self.parse_top_level_pat()?; if !self.eat_keyword(kw::In) { let in_span = self.prev_span.between(self.token.span); - let mut err = self.sess.span_diagnostic - .struct_span_err(in_span, "missing `in` in `for` loop"); - err.span_suggestion_short( - in_span, "try adding `in` here", " in ".into(), - // has been misleading, at least in the past (closed Issue #48492) - Applicability::MaybeIncorrect - ); - err.emit(); + self.struct_span_err(in_span, "missing `in` in `for` loop") + .span_suggestion_short( + in_span, + "try adding `in` here", " in ".into(), + // has been misleading, at least in the past (closed Issue #48492) + Applicability::MaybeIncorrect + ) + .emit(); } let in_span = self.prev_span; self.check_for_for_in_in_typo(in_span); let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; + + let pat = self.recover_parens_around_for_head(pat, &expr, begin_paren); + let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); @@ -3522,15 +3535,14 @@ impl<'a> Parser<'a> { pats.push(self.parse_top_level_pat()?); if self.token == token::OrOr { - let mut err = self.struct_span_err(self.token.span, - "unexpected token `||` after pattern"); - err.span_suggestion( - self.token.span, - "use a single `|` to specify multiple patterns", - "|".to_owned(), - Applicability::MachineApplicable - ); - err.emit(); + self.struct_span_err(self.token.span, "unexpected token `||` after pattern") + .span_suggestion( + self.token.span, + "use a single `|` to specify multiple patterns", + "|".to_owned(), + Applicability::MachineApplicable + ) + .emit(); self.bump(); } else if self.eat(&token::BinOp(token::Or)) { // This is a No-op. Continue the loop to parse the next @@ -3627,15 +3639,14 @@ impl<'a> Parser<'a> { if self.token == token::DotDotDot { // Issue #46718 // Accept `...` as if it were `..` to avoid further errors - let mut err = self.struct_span_err(self.token.span, - "expected field pattern, found `...`"); - err.span_suggestion( - self.token.span, - "to omit remaining fields, use one fewer `.`", - "..".to_owned(), - Applicability::MachineApplicable - ); - err.emit(); + self.struct_span_err(self.token.span, "expected field pattern, found `...`") + .span_suggestion( + self.token.span, + "to omit remaining fields, use one fewer `.`", + "..".to_owned(), + Applicability::MachineApplicable + ) + .emit(); } self.bump(); // `..` || `...` @@ -3788,7 +3799,7 @@ impl<'a> Parser<'a> { let seq_span = pat.span.to(self.prev_span); let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); - if let Ok(seq_snippet) = self.sess.source_map().span_to_snippet(seq_span) { + if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { err.span_suggestion( seq_span, "try adding parentheses to match on a tuple..", @@ -4137,7 +4148,7 @@ impl<'a> Parser<'a> { let parser_snapshot_after_type = self.clone(); mem::replace(self, parser_snapshot_before_type); - let snippet = self.sess.source_map().span_to_snippet(pat.span).unwrap(); + let snippet = self.span_to_snippet(pat.span).unwrap(); err.span_label(pat.span, format!("while parsing the type for `{}`", snippet)); (Some((parser_snapshot_after_type, colon_sp, err)), None) } @@ -4557,7 +4568,7 @@ impl<'a> Parser<'a> { if self.eat(&token::Semi) { stmt_span = stmt_span.with_hi(self.prev_span.hi()); } - if let Ok(snippet) = self.sess.source_map().span_to_snippet(stmt_span) { + if let Ok(snippet) = self.span_to_snippet(stmt_span) { e.span_suggestion( stmt_span, "try placing this code inside a block", @@ -4730,7 +4741,7 @@ impl<'a> Parser<'a> { lo.to(self.prev_span), "parenthesized lifetime bounds are not supported" ); - if let Ok(snippet) = self.sess.source_map().span_to_snippet(inner_span) { + if let Ok(snippet) = self.span_to_snippet(inner_span) { err.span_suggestion_short( lo.to(self.prev_span), "remove the parentheses", @@ -4788,7 +4799,7 @@ impl<'a> Parser<'a> { let mut new_bound_list = String::new(); if !bounds.is_empty() { let mut snippets = bounds.iter().map(|bound| bound.span()) - .map(|span| self.sess.source_map().span_to_snippet(span)); + .map(|span| self.span_to_snippet(span)); while let Some(Ok(snippet)) = snippets.next() { new_bound_list.push_str(" + "); new_bound_list.push_str(&snippet); @@ -5853,15 +5864,16 @@ impl<'a> Parser<'a> { if let token::DocComment(_) = self.token.kind { if self.look_ahead(1, |tok| tok == &token::CloseDelim(token::Brace)) { - let mut err = self.diagnostic().struct_span_err_with_code( + self.diagnostic().struct_span_err_with_code( self.token.span, "found a documentation comment that doesn't document anything", DiagnosticId::Error("E0584".into()), - ); - err.help("doc comments must come before what they document, maybe a \ + ) + .help( + "doc comments must come before what they document, maybe a \ comment was intended with `//`?", - ); - err.emit(); + ) + .emit(); self.bump(); continue; } @@ -6305,12 +6317,15 @@ impl<'a> Parser<'a> { let sp = path.span; let help_msg = format!("make this visible only to module `{}` with `in`", path); self.expect(&token::CloseDelim(token::Paren))?; // `)` - let mut err = struct_span_err!(self.sess.span_diagnostic, sp, E0704, "{}", msg); - err.help(suggestion); - err.span_suggestion( - sp, &help_msg, format!("in {}", path), Applicability::MachineApplicable - ); - err.emit(); // emit diagnostic, but continue with public visibility + struct_span_err!(self.sess.span_diagnostic, sp, E0704, "{}", msg) + .help(suggestion) + .span_suggestion( + sp, + &help_msg, + format!("in {}", path), + Applicability::MachineApplicable, + ) + .emit(); // emit diagnostic, but continue with public visibility } } @@ -6744,14 +6759,10 @@ impl<'a> Parser<'a> { } ident = Ident::from_str(&fixed_name).with_span_pos(fixed_name_sp); - let mut err = self.struct_span_err(fixed_name_sp, error_msg); - err.span_label(fixed_name_sp, "dash-separated idents are not valid"); - err.multipart_suggestion( - suggestion_msg, - replacement, - Applicability::MachineApplicable, - ); - err.emit(); + self.struct_span_err(fixed_name_sp, error_msg) + .span_label(fixed_name_sp, "dash-separated idents are not valid") + .multipart_suggestion(suggestion_msg, replacement, Applicability::MachineApplicable) + .emit(); } Ok(ident) } @@ -6906,14 +6917,14 @@ impl<'a> Parser<'a> { if !self.eat(&token::Comma) { if self.token.is_ident() && !self.token.is_reserved_ident() { let sp = self.sess.source_map().next_point(self.prev_span); - let mut err = self.struct_span_err(sp, "missing comma"); - err.span_suggestion_short( - sp, - "missing comma", - ",".to_owned(), - Applicability::MaybeIncorrect, - ); - err.emit(); + self.struct_span_err(sp, "missing comma") + .span_suggestion_short( + sp, + "missing comma", + ",".to_owned(), + Applicability::MaybeIncorrect, + ) + .emit(); } else { break; } @@ -6952,15 +6963,16 @@ impl<'a> Parser<'a> { Some(abi) => Ok(Some(abi)), None => { let prev_span = self.prev_span; - let mut err = struct_span_err!( + struct_span_err!( self.sess.span_diagnostic, prev_span, E0703, "invalid ABI: found `{}`", - symbol); - err.span_label(prev_span, "invalid ABI"); - err.help(&format!("valid ABIs: {}", abi::all_names().join(", "))); - err.emit(); + symbol + ) + .span_label(prev_span, "invalid ABI") + .help(&format!("valid ABIs: {}", abi::all_names().join(", "))) + .emit(); Ok(None) } } @@ -7130,16 +7142,15 @@ impl<'a> Parser<'a> { // CONST ITEM if self.eat_keyword(kw::Mut) { let prev_span = self.prev_span; - let mut err = self.diagnostic() - .struct_span_err(prev_span, "const globals cannot be mutable"); - err.span_label(prev_span, "cannot be mutable"); - err.span_suggestion( - const_span, - "you might want to declare a static instead", - "static".to_owned(), - Applicability::MaybeIncorrect, - ); - err.emit(); + self.struct_span_err(prev_span, "const globals cannot be mutable") + .span_label(prev_span, "cannot be mutable") + .span_suggestion( + const_span, + "you might want to declare a static instead", + "static".to_owned(), + Applicability::MaybeIncorrect, + ) + .emit(); } let (ident, item_, extra_attrs) = self.parse_item_const(None)?; let prev_span = self.prev_span; @@ -7407,7 +7418,7 @@ impl<'a> Parser<'a> { sp, &suggestion, format!(" {} ", kw), Applicability::MachineApplicable ); } else { - if let Ok(snippet) = self.sess.source_map().span_to_snippet(ident_sp) { + if let Ok(snippet) = self.span_to_snippet(ident_sp) { err.span_suggestion( full_sp, "if you meant to call a macro, try", diff --git a/src/test/run-make/thumb-none-qemu/example/Cargo.toml b/src/test/run-make/thumb-none-qemu/example/Cargo.toml index 499553304c681..73fdee71f0c0b 100644 --- a/src/test/run-make/thumb-none-qemu/example/Cargo.toml +++ b/src/test/run-make/thumb-none-qemu/example/Cargo.toml @@ -2,7 +2,7 @@ name = "example" version = "0.1.0" authors = ["Hideki Sekine <sekineh@me.com>"] -# edition = "2018" +edition = "2018" [dependencies] cortex-m = "0.5.4" diff --git a/src/test/run-make/thumb-none-qemu/example/src/main.rs b/src/test/run-make/thumb-none-qemu/example/src/main.rs index d88a327ef08b4..4a08419a07e14 100644 --- a/src/test/run-make/thumb-none-qemu/example/src/main.rs +++ b/src/test/run-make/thumb-none-qemu/example/src/main.rs @@ -1,16 +1,14 @@ // #![feature(stdsimd)] #![no_main] #![no_std] - -extern crate cortex_m; - -extern crate cortex_m_rt as rt; -extern crate cortex_m_semihosting as semihosting; -extern crate panic_halt; - use core::fmt::Write; use cortex_m::asm; -use rt::entry; +use cortex_m_rt::entry; +use cortex_m_semihosting as semihosting; + +//FIXME: This imports the provided #[panic_handler]. +#[allow(rust_2018_idioms)] +extern crate panic_halt; entry!(main); @@ -22,7 +20,7 @@ fn main() -> ! { // write something through semihosting interface let mut hstdout = semihosting::hio::hstdout().unwrap(); - write!(hstdout, "x = {}\n", x); + let _ = write!(hstdout, "x = {}\n", x); // exit from qemu semihosting::debug::exit(semihosting::debug::EXIT_SUCCESS); diff --git a/src/test/ui/borrowck/borrowck-migrate-to-nll.edition.stderr b/src/test/ui/borrowck/borrowck-migrate-to-nll.edition.stderr index d97883ad47a50..a33a1d00a5786 100644 --- a/src/test/ui/borrowck/borrowck-migrate-to-nll.edition.stderr +++ b/src/test/ui/borrowck/borrowck-migrate-to-nll.edition.stderr @@ -1,14 +1,14 @@ -warning[E0507]: cannot move out of `foo` in pattern guard - --> $DIR/borrowck-migrate-to-nll.rs:26:18 +warning[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-migrate-to-nll.rs:28:21 | -LL | (|| { let bar = foo; bar.take() })(); - | ^^ --- - | | | - | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait - | | move occurs due to use in closure - | move out of `foo` occurs here +LL | let x = &mut block; + | ---------- mutable borrow occurs here +LL | let p: &'a u8 = &*block.current; + | ^^^^^^^^^^^^^^^ immutable borrow occurs here +LL | // (use `x` and `p` so enabling NLL doesn't assign overly short lifetimes) +LL | drop(x); + | - mutable borrow later used here | - = note: variables bound in patterns cannot be moved from until after the end of the pattern guard = warning: this error has been downgraded to a warning for backwards compatibility with previous releases = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future = note: for more information, try `rustc --explain E0729` diff --git a/src/test/ui/borrowck/borrowck-migrate-to-nll.rs b/src/test/ui/borrowck/borrowck-migrate-to-nll.rs index a64df9df25948..6dda317e57efe 100644 --- a/src/test/ui/borrowck/borrowck-migrate-to-nll.rs +++ b/src/test/ui/borrowck/borrowck-migrate-to-nll.rs @@ -1,4 +1,4 @@ -// This is a test of the borrowck migrate mode. It leverages #27282, a +// This is a test of the borrowck migrate mode. It leverages #38899, a // bug that is fixed by NLL: this code is (unsoundly) accepted by // AST-borrowck, but is correctly rejected by the NLL borrowck. // @@ -18,15 +18,17 @@ //[zflag] run-pass //[edition] run-pass -fn main() { - match Some(&4) { - None => {}, - ref mut foo - if { - (|| { let bar = foo; bar.take() })(); - false - } => {}, - Some(ref _s) => println!("Note this arm is bogus; the `Some` became `None` in the guard."), - _ => println!("Here is some supposedly unreachable code."), - } +pub struct Block<'a> { + current: &'a u8, + unrelated: &'a u8, } + +fn bump<'a>(mut block: &mut Block<'a>) { + let x = &mut block; + let p: &'a u8 = &*block.current; + // (use `x` and `p` so enabling NLL doesn't assign overly short lifetimes) + drop(x); + drop(p); +} + +fn main() {} diff --git a/src/test/ui/borrowck/borrowck-migrate-to-nll.zflag.stderr b/src/test/ui/borrowck/borrowck-migrate-to-nll.zflag.stderr index d97883ad47a50..a33a1d00a5786 100644 --- a/src/test/ui/borrowck/borrowck-migrate-to-nll.zflag.stderr +++ b/src/test/ui/borrowck/borrowck-migrate-to-nll.zflag.stderr @@ -1,14 +1,14 @@ -warning[E0507]: cannot move out of `foo` in pattern guard - --> $DIR/borrowck-migrate-to-nll.rs:26:18 +warning[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-migrate-to-nll.rs:28:21 | -LL | (|| { let bar = foo; bar.take() })(); - | ^^ --- - | | | - | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait - | | move occurs due to use in closure - | move out of `foo` occurs here +LL | let x = &mut block; + | ---------- mutable borrow occurs here +LL | let p: &'a u8 = &*block.current; + | ^^^^^^^^^^^^^^^ immutable borrow occurs here +LL | // (use `x` and `p` so enabling NLL doesn't assign overly short lifetimes) +LL | drop(x); + | - mutable borrow later used here | - = note: variables bound in patterns cannot be moved from until after the end of the pattern guard = warning: this error has been downgraded to a warning for backwards compatibility with previous releases = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future = note: for more information, try `rustc --explain E0729` diff --git a/src/test/ui/borrowck/borrowck-mutate-in-guard.nll.stderr b/src/test/ui/borrowck/borrowck-mutate-in-guard.nll.stderr deleted file mode 100644 index 43b578e9f1eaf..0000000000000 --- a/src/test/ui/borrowck/borrowck-mutate-in-guard.nll.stderr +++ /dev/null @@ -1,41 +0,0 @@ -error[E0302]: cannot assign in a pattern guard - --> $DIR/borrowck-mutate-in-guard.rs:10:25 - | -LL | Enum::A(_) if { x = Enum::B(false); false } => 1, - | ^^^^^^^^^^^^^^^^^^ assignment in pattern guard - -error[E0301]: cannot mutably borrow in a pattern guard - --> $DIR/borrowck-mutate-in-guard.rs:15:38 - | -LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, - | ^ borrowed mutably in pattern guard - | - = help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable - -error[E0302]: cannot assign in a pattern guard - --> $DIR/borrowck-mutate-in-guard.rs:15:41 - | -LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, - | ^^^^^^^^^^^^^^^^^^^ assignment in pattern guard - -error[E0510]: cannot assign `x` in match guard - --> $DIR/borrowck-mutate-in-guard.rs:10:25 - | -LL | match x { - | - value is immutable in match guard -LL | Enum::A(_) if { x = Enum::B(false); false } => 1, - | ^^^^^^^^^^^^^^^^^^ cannot assign - -error[E0510]: cannot mutably borrow `x` in match guard - --> $DIR/borrowck-mutate-in-guard.rs:15:33 - | -LL | match x { - | - value is immutable in match guard -... -LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, - | ^^^^^^ cannot mutably borrow - -error: aborting due to 5 previous errors - -Some errors have detailed explanations: E0301, E0302, E0510. -For more information about an error, try `rustc --explain E0301`. diff --git a/src/test/ui/borrowck/borrowck-mutate-in-guard.rs b/src/test/ui/borrowck/borrowck-mutate-in-guard.rs index 9ea5e5cd145a0..5b6aa7a979be5 100644 --- a/src/test/ui/borrowck/borrowck-mutate-in-guard.rs +++ b/src/test/ui/borrowck/borrowck-mutate-in-guard.rs @@ -9,15 +9,11 @@ fn foo() -> isize { match x { Enum::A(_) if { x = Enum::B(false); false } => 1, //~^ ERROR cannot assign in a pattern guard - //~| WARN cannot assign `x` in match guard - //~| WARN this error has been downgraded to a warning for backwards compatibility - //~| WARN this represents potential undefined behavior in your code and this warning will + //~| ERROR cannot assign `x` in match guard Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, //~^ ERROR cannot mutably borrow in a pattern guard //~| ERROR cannot assign in a pattern guard - //~| WARN cannot mutably borrow `x` in match guard - //~| WARN this error has been downgraded to a warning for backwards compatibility - //~| WARN this represents potential undefined behavior in your code and this warning will + //~| ERROR cannot mutably borrow `x` in match guard Enum::A(p) => *p, Enum::B(_) => 2, } diff --git a/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr b/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr index d39f535d8e2f7..674f137dbb043 100644 --- a/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr +++ b/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr @@ -5,7 +5,7 @@ LL | Enum::A(_) if { x = Enum::B(false); false } => 1, | ^^^^^^^^^^^^^^^^^^ assignment in pattern guard error[E0301]: cannot mutably borrow in a pattern guard - --> $DIR/borrowck-mutate-in-guard.rs:15:38 + --> $DIR/borrowck-mutate-in-guard.rs:13:38 | LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, | ^ borrowed mutably in pattern guard @@ -13,37 +13,29 @@ LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, = help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable error[E0302]: cannot assign in a pattern guard - --> $DIR/borrowck-mutate-in-guard.rs:15:41 + --> $DIR/borrowck-mutate-in-guard.rs:13:41 | LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, | ^^^^^^^^^^^^^^^^^^^ assignment in pattern guard -warning[E0510]: cannot assign `x` in match guard +error[E0510]: cannot assign `x` in match guard --> $DIR/borrowck-mutate-in-guard.rs:10:25 | LL | match x { | - value is immutable in match guard LL | Enum::A(_) if { x = Enum::B(false); false } => 1, | ^^^^^^^^^^^^^^^^^^ cannot assign - | - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future - = note: for more information, try `rustc --explain E0729` -warning[E0510]: cannot mutably borrow `x` in match guard - --> $DIR/borrowck-mutate-in-guard.rs:15:33 +error[E0510]: cannot mutably borrow `x` in match guard + --> $DIR/borrowck-mutate-in-guard.rs:13:33 | LL | match x { | - value is immutable in match guard ... LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, | ^^^^^^ cannot mutably borrow - | - = warning: this error has been downgraded to a warning for backwards compatibility with previous releases - = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future - = note: for more information, try `rustc --explain E0729` -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0301, E0302, E0510. For more information about an error, try `rustc --explain E0301`. diff --git a/src/test/ui/borrowck/issue-27282-mutation-in-guard.rs b/src/test/ui/borrowck/issue-27282-mutation-in-guard.rs new file mode 100644 index 0000000000000..395c7d214d0ce --- /dev/null +++ b/src/test/ui/borrowck/issue-27282-mutation-in-guard.rs @@ -0,0 +1,13 @@ +fn main() { + match Some(&4) { + None => {}, + ref mut foo + if { + (|| { let bar = foo; bar.take() })(); + //~^ ERROR cannot move out of `foo` in pattern guard + false + } => {}, + Some(ref _s) => println!("Note this arm is bogus; the `Some` became `None` in the guard."), + _ => println!("Here is some supposedly unreachable code."), + } +} diff --git a/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr b/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr new file mode 100644 index 0000000000000..ea7df7d5a7b61 --- /dev/null +++ b/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr @@ -0,0 +1,15 @@ +error[E0507]: cannot move out of `foo` in pattern guard + --> $DIR/issue-27282-mutation-in-guard.rs:6:18 + | +LL | (|| { let bar = foo; bar.take() })(); + | ^^ --- + | | | + | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait + | | move occurs due to use in closure + | move out of `foo` occurs here + | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/issue-31287-drop-in-guard.rs b/src/test/ui/borrowck/issue-31287-drop-in-guard.rs new file mode 100644 index 0000000000000..07125b98a1f7d --- /dev/null +++ b/src/test/ui/borrowck/issue-31287-drop-in-guard.rs @@ -0,0 +1,8 @@ +fn main() { + let a = Some("...".to_owned()); + let b = match a { + Some(_) if { drop(a); false } => None, + x => x, //~ ERROR use of moved value: `a` + }; + println!("{:?}", b); +} diff --git a/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr b/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr new file mode 100644 index 0000000000000..85c83ec4d70ed --- /dev/null +++ b/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr @@ -0,0 +1,14 @@ +error[E0382]: use of moved value: `a` + --> $DIR/issue-31287-drop-in-guard.rs:5:9 + | +LL | let a = Some("...".to_owned()); + | - move occurs because `a` has type `std::option::Option<std::string::String>`, which does not implement the `Copy` trait +LL | let b = match a { +LL | Some(_) if { drop(a); false } => None, + | - value moved here +LL | x => x, + | ^ value used here after move + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/existential-type/issue-52843-closure-constrain.rs b/src/test/ui/existential-type/issue-52843-closure-constrain.rs new file mode 100644 index 0000000000000..b2bbc1f154998 --- /dev/null +++ b/src/test/ui/existential-type/issue-52843-closure-constrain.rs @@ -0,0 +1,12 @@ +// Checks to ensure that we properly detect when a closure constrains an existential type +#![feature(existential_type)] + +use std::fmt::Debug; + +fn main() { + existential type Existential: Debug; + fn _unused() -> Existential { String::new() } + //~^ ERROR: concrete type differs from previous defining existential type use + let null = || -> Existential { 0 }; + println!("{:?}", null()); +} diff --git a/src/test/ui/existential-type/issue-52843-closure-constrain.stderr b/src/test/ui/existential-type/issue-52843-closure-constrain.stderr new file mode 100644 index 0000000000000..424d65a193c92 --- /dev/null +++ b/src/test/ui/existential-type/issue-52843-closure-constrain.stderr @@ -0,0 +1,20 @@ +error: concrete type differs from previous defining existential type use + --> $DIR/issue-52843-closure-constrain.rs:8:5 + | +LL | fn _unused() -> Existential { String::new() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, got `std::string::String` + | +note: previous use here + --> $DIR/issue-52843-closure-constrain.rs:6:1 + | +LL | / fn main() { +LL | | existential type Existential: Debug; +LL | | fn _unused() -> Existential { String::new() } +LL | | +LL | | let null = || -> Existential { 0 }; +LL | | println!("{:?}", null()); +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/existential_type.rs b/src/test/ui/existential_types/existential_type-pass.rs similarity index 100% rename from src/test/ui/existential_type.rs rename to src/test/ui/existential_types/existential_type-pass.rs diff --git a/src/test/ui/existential_types/issue-53678-generator-and-const-fn.rs b/src/test/ui/existential_types/issue-53678-generator-and-const-fn.rs new file mode 100644 index 0000000000000..d964f2b74ff69 --- /dev/null +++ b/src/test/ui/existential_types/issue-53678-generator-and-const-fn.rs @@ -0,0 +1,19 @@ +// check-pass + +#![feature(const_fn, generators, generator_trait, existential_type)] + +use std::ops::Generator; + +existential type GenOnce<Y, R>: Generator<Yield = Y, Return = R>; + +const fn const_generator<Y, R>(yielding: Y, returning: R) -> GenOnce<Y, R> { + move || { + yield yielding; + + return returning; + } +} + +const FOO: GenOnce<usize, usize> = const_generator(10, 100); + +fn main() {} diff --git a/src/test/ui/existential-type/issue-58887.rs b/src/test/ui/existential_types/issue-58887.rs similarity index 100% rename from src/test/ui/existential-type/issue-58887.rs rename to src/test/ui/existential_types/issue-58887.rs diff --git a/src/test/ui/existential-type/issue-58887.stderr b/src/test/ui/existential_types/issue-58887.stderr similarity index 100% rename from src/test/ui/existential-type/issue-58887.stderr rename to src/test/ui/existential_types/issue-58887.stderr diff --git a/src/test/ui/existential-type/issue-60371.rs b/src/test/ui/existential_types/issue-60371.rs similarity index 100% rename from src/test/ui/existential-type/issue-60371.rs rename to src/test/ui/existential_types/issue-60371.rs diff --git a/src/test/ui/existential-type/issue-60371.stderr b/src/test/ui/existential_types/issue-60371.stderr similarity index 100% rename from src/test/ui/existential-type/issue-60371.stderr rename to src/test/ui/existential_types/issue-60371.stderr diff --git a/src/test/ui/existential_types/issue-60407.rs b/src/test/ui/existential_types/issue-60407.rs new file mode 100644 index 0000000000000..52162c491b5c8 --- /dev/null +++ b/src/test/ui/existential_types/issue-60407.rs @@ -0,0 +1,15 @@ +// check-pass + +#![feature(existential_type)] + +existential type Debuggable: core::fmt::Debug; + +static mut TEST: Option<Debuggable> = None; + +fn main() { + unsafe { TEST = Some(foo()) } +} + +fn foo() -> Debuggable { + 0u32 +} diff --git a/src/test/ui/existential_types/issue-60564.rs b/src/test/ui/existential_types/issue-60564.rs new file mode 100644 index 0000000000000..cb3914ddd1deb --- /dev/null +++ b/src/test/ui/existential_types/issue-60564.rs @@ -0,0 +1,26 @@ +#![feature(existential_type)] + +trait IterBits { + type BitsIter: Iterator<Item = u8>; + fn iter_bits(self, n: u8) -> Self::BitsIter; +} + +existential type IterBitsIter<T, E, I>: std::iter::Iterator<Item = I>; +//~^ ERROR could not find defining uses + +impl<T, E> IterBits for T +where + T: std::ops::Shr<Output = T> + + std::ops::BitAnd<T, Output = T> + + std::convert::From<u8> + + std::convert::TryInto<u8, Error = E>, + E: std::fmt::Debug, +{ + type BitsIter = IterBitsIter<T, E, u8>; + fn iter_bits(self, n: u8) -> Self::BitsIter { + //~^ ERROR type parameter `E` is part of concrete type but not used + (0u8..n) + .rev() + .map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap()) + } +} diff --git a/src/test/ui/existential_types/issue-60564.stderr b/src/test/ui/existential_types/issue-60564.stderr new file mode 100644 index 0000000000000..d8480b521570a --- /dev/null +++ b/src/test/ui/existential_types/issue-60564.stderr @@ -0,0 +1,25 @@ +error[E0601]: `main` function not found in crate `issue_60564` + | + = note: consider adding a `main` function to `$DIR/issue-60564.rs` + +error: type parameter `E` is part of concrete type but not used in parameter list for existential type + --> $DIR/issue-60564.rs:20:49 + | +LL | fn iter_bits(self, n: u8) -> Self::BitsIter { + | _________________________________________________^ +LL | | +LL | | (0u8..n) +LL | | .rev() +LL | | .map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap()) +LL | | } + | |_____^ + +error: could not find defining uses + --> $DIR/issue-60564.rs:8:1 + | +LL | existential type IterBitsIter<T, E, I>: std::iter::Iterator<Item = I>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/hygiene/duplicate_lifetimes.rs b/src/test/ui/hygiene/duplicate_lifetimes.rs new file mode 100644 index 0000000000000..e7312b51dbcb8 --- /dev/null +++ b/src/test/ui/hygiene/duplicate_lifetimes.rs @@ -0,0 +1,19 @@ +// Ensure that lifetime parameter names are modernized before we check for +// duplicates. + +#![feature(decl_macro, rustc_attrs)] + +#[rustc_macro_transparency = "semitransparent"] +macro m($a:lifetime) { + fn g<$a, 'a>() {} //~ ERROR lifetime name `'a` declared twice +} + +#[rustc_macro_transparency = "transparent"] +macro n($a:lifetime) { + fn h<$a, 'a>() {} //~ ERROR lifetime name `'a` declared twice +} + +m!('a); +n!('a); + +fn main() {} diff --git a/src/test/ui/hygiene/duplicate_lifetimes.stderr b/src/test/ui/hygiene/duplicate_lifetimes.stderr new file mode 100644 index 0000000000000..7aaea6ff24e39 --- /dev/null +++ b/src/test/ui/hygiene/duplicate_lifetimes.stderr @@ -0,0 +1,27 @@ +error[E0263]: lifetime name `'a` declared twice in the same scope + --> $DIR/duplicate_lifetimes.rs:8:14 + | +LL | fn g<$a, 'a>() {} + | ^^ declared twice +... +LL | m!('a); + | ------- + | | | + | | previous declaration here + | in this macro invocation + +error[E0263]: lifetime name `'a` declared twice in the same scope + --> $DIR/duplicate_lifetimes.rs:13:14 + | +LL | fn h<$a, 'a>() {} + | ^^ declared twice +... +LL | n!('a); + | ------- + | | | + | | previous declaration here + | in this macro invocation + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0263`. diff --git a/src/test/ui/hygiene/generic_params.rs b/src/test/ui/hygiene/generic_params.rs new file mode 100644 index 0000000000000..9dc5adfce478a --- /dev/null +++ b/src/test/ui/hygiene/generic_params.rs @@ -0,0 +1,104 @@ +// Ensure that generic parameters always have modern hygiene. + +// check-pass +// ignore-pretty pretty-printing is unhygienic + +#![feature(decl_macro, rustc_attrs, const_generics)] + +mod type_params { + macro m($T:ident) { + fn f<$T: Clone, T: PartialEq>(t1: $T, t2: T) -> ($T, bool) { + (t1.clone(), t2 == t2) + } + } + + #[rustc_macro_transparency = "semitransparent"] + macro n($T:ident) { + fn g<$T: Clone>(t1: $T, t2: T) -> (T, $T) { + (t1.clone(), t2.clone()) + } + fn h<T: Clone>(t1: $T, t2: T) -> (T, $T) { + (t1.clone(), t2.clone()) + } + } + + #[rustc_macro_transparency = "transparent"] + macro p($T:ident) { + fn j<$T: Clone>(t1: $T, t2: T) -> (T, $T) { + (t1.clone(), t2.clone()) + } + fn k<T: Clone>(t1: $T, t2: T) -> (T, $T) { + (t1.clone(), t2.clone()) + } + } + + m!(T); + n!(T); + p!(T); +} + +mod lifetime_params { + macro m($a:lifetime) { + fn f<'b, 'c, $a: 'b, 'a: 'c>(t1: &$a(), t2: &'a ()) -> (&'b (), &'c ()) { + (t1, t2) + } + } + + #[rustc_macro_transparency = "semitransparent"] + macro n($a:lifetime) { + fn g<$a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { + (t1, t2) + } + fn h<'a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { + (t1, t2) + } + } + + #[rustc_macro_transparency = "transparent"] + macro p($a:lifetime) { + fn j<$a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { + (t1, t2) + } + fn k<'a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { + (t1, t2) + } + } + + m!('a); + n!('a); + p!('a); +} + +mod const_params { + macro m($C:ident) { + fn f<const $C: usize, const C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); $C], [(); C]) { + (t1, t2) + } + } + + #[rustc_macro_transparency = "semitransparent"] + macro n($C:ident) { + fn g<const $C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { + (t1, t2) + } + fn h<const C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { + (t1, t2) + } + } + + #[rustc_macro_transparency = "transparent"] + macro p($C:ident) { + fn j<const $C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { + (t1, t2) + } + fn k<const C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { + (t1, t2) + } + } + + m!(C); + n!(C); + p!(C); +} + +fn main() {} diff --git a/src/test/ui/hygiene/generic_params.stderr b/src/test/ui/hygiene/generic_params.stderr new file mode 100644 index 0000000000000..ecd228a5db5c8 --- /dev/null +++ b/src/test/ui/hygiene/generic_params.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/generic_params.rs:6:37 + | +LL | #![feature(decl_macro, rustc_attrs, const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/hygiene/issue-61574-const-parameters.rs b/src/test/ui/hygiene/issue-61574-const-parameters.rs new file mode 100644 index 0000000000000..dcfb42287d5cb --- /dev/null +++ b/src/test/ui/hygiene/issue-61574-const-parameters.rs @@ -0,0 +1,32 @@ +// A more comprehensive test that const parameters have correctly implemented +// hygiene + +// check-pass + +#![feature(const_generics)] + +use std::ops::Add; + +struct VectorLike<T, const SIZE: usize>([T; {SIZE}]); + +macro_rules! impl_operator_overload { + ($trait_ident:ident, $method_ident:ident) => { + + impl<T, const SIZE: usize> $trait_ident for VectorLike<T, {SIZE}> + where + T: $trait_ident, + { + type Output = VectorLike<T, {SIZE}>; + + fn $method_ident(self, _: VectorLike<T, {SIZE}>) -> VectorLike<T, {SIZE}> { + let _ = SIZE; + unimplemented!() + } + } + + } +} + +impl_operator_overload!(Add, add); + +fn main() {} diff --git a/src/test/ui/hygiene/issue-61574-const-parameters.stderr b/src/test/ui/hygiene/issue-61574-const-parameters.stderr new file mode 100644 index 0000000000000..302b5fde8879c --- /dev/null +++ b/src/test/ui/hygiene/issue-61574-const-parameters.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-61574-const-parameters.rs:6:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/hygiene/ty_params.rs b/src/test/ui/hygiene/ty_params.rs deleted file mode 100644 index b296bfe598887..0000000000000 --- a/src/test/ui/hygiene/ty_params.rs +++ /dev/null @@ -1,14 +0,0 @@ -// check-pass -// ignore-pretty pretty-printing is unhygienic - -#![feature(decl_macro)] - -macro m($T:ident) { - fn f<T, $T>(t: T, t2: $T) -> (T, $T) { - (t, t2) - } -} - -m!(T); - -fn main() {} diff --git a/src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.rs b/src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.rs index c79b1873241c8..1ffb7f6fd4acd 100644 --- a/src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.rs +++ b/src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.rs @@ -5,9 +5,7 @@ // reject it. But I want to make sure that we continue to reject it // (under NLL) even when that conservaive check goes away. - #![feature(bind_by_move_pattern_guards)] -#![feature(nll)] fn main() { let mut b = &mut true; diff --git a/src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.stderr b/src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.stderr index 3a10928981c8b..a8eb78b7cc007 100644 --- a/src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.stderr +++ b/src/test/ui/issues/issue-27282-reborrow-ref-mut-in-guard.stderr @@ -1,5 +1,5 @@ error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard - --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:16:25 + --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:14:25 | LL | ref mut r if { (|| { let bar = &mut *r; **bar = false; })(); | ^^ - mutable borrow occurs due to use of `r` in closure diff --git a/src/test/ui/match/match-ref-mut-stability.rs b/src/test/ui/match/match-ref-mut-stability.rs index 795a3fc210f6a..49e0dfaa3eb84 100644 --- a/src/test/ui/match/match-ref-mut-stability.rs +++ b/src/test/ui/match/match-ref-mut-stability.rs @@ -3,7 +3,7 @@ // run-pass -#![feature(nll, bind_by_move_pattern_guards)] +#![feature(bind_by_move_pattern_guards)] // Test that z always point to the same temporary. fn referent_stability() { diff --git a/src/test/ui/nll/match-cfg-fake-edges.rs b/src/test/ui/nll/match-cfg-fake-edges.rs index a3add8856dfa1..94e4a763866f6 100644 --- a/src/test/ui/nll/match-cfg-fake-edges.rs +++ b/src/test/ui/nll/match-cfg-fake-edges.rs @@ -1,7 +1,7 @@ // Test that we have enough false edges to avoid exposing the exact matching // algorithm in borrow checking. -#![feature(nll, bind_by_move_pattern_guards)] +#![feature(bind_by_move_pattern_guards)] fn guard_always_precedes_arm(y: i32) { let mut x; @@ -41,18 +41,4 @@ fn guard_may_be_taken(y: bool) { }; } -fn all_previous_tests_may_be_done(y: &mut (bool, bool)) { - let r = &mut y.1; - // We don't actually test y.1 to select the second arm, but we don't want - // borrowck results to be based on the order we match patterns. - match y { - (false, true) => 1, //~ ERROR cannot use `y.1` because it was mutably borrowed - (true, _) => { - r; - 2 - } - (false, _) => 3, - }; -} - fn main() {} diff --git a/src/test/ui/nll/match-cfg-fake-edges.stderr b/src/test/ui/nll/match-cfg-fake-edges.stderr index d37c52444ac0d..b1e0fa739769a 100644 --- a/src/test/ui/nll/match-cfg-fake-edges.stderr +++ b/src/test/ui/nll/match-cfg-fake-edges.stderr @@ -16,19 +16,7 @@ LL | true => { LL | x; | ^ value used here after move -error[E0503]: cannot use `y.1` because it was mutably borrowed - --> $DIR/match-cfg-fake-edges.rs:49:17 - | -LL | let r = &mut y.1; - | -------- borrow of `y.1` occurs here -... -LL | (false, true) => 1, - | ^^^^ use of borrowed `y.1` -LL | (true, _) => { -LL | r; - | - borrow later used here - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0381, E0382, E0503. +Some errors have detailed explanations: E0381, E0382. For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/nll/match-cfg-fake-edges2.rs b/src/test/ui/nll/match-cfg-fake-edges2.rs new file mode 100644 index 0000000000000..84c0dec2fe5cd --- /dev/null +++ b/src/test/ui/nll/match-cfg-fake-edges2.rs @@ -0,0 +1,20 @@ +// Test that we have enough false edges to avoid exposing the exact matching +// algorithm in borrow checking. + +#![feature(nll)] + +fn all_previous_tests_may_be_done(y: &mut (bool, bool)) { + let r = &mut y.1; + // We don't actually test y.1 to select the second arm, but we don't want + // borrowck results to be based on the order we match patterns. + match y { + (false, true) => 1, //~ ERROR cannot use `y.1` because it was mutably borrowed + (true, _) => { + r; + 2 + } + (false, _) => 3, + }; +} + +fn main() {} diff --git a/src/test/ui/nll/match-cfg-fake-edges2.stderr b/src/test/ui/nll/match-cfg-fake-edges2.stderr new file mode 100644 index 0000000000000..eab89658e79be --- /dev/null +++ b/src/test/ui/nll/match-cfg-fake-edges2.stderr @@ -0,0 +1,15 @@ +error[E0503]: cannot use `y.1` because it was mutably borrowed + --> $DIR/match-cfg-fake-edges2.rs:11:17 + | +LL | let r = &mut y.1; + | -------- borrow of `y.1` occurs here +... +LL | (false, true) => 1, + | ^^^^ use of borrowed `y.1` +LL | (true, _) => { +LL | r; + | - borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0503`. diff --git a/src/test/ui/nll/match-guards-partially-borrow.rs b/src/test/ui/nll/match-guards-partially-borrow.rs index 6e158713146f1..601c46ff86cc7 100644 --- a/src/test/ui/nll/match-guards-partially-borrow.rs +++ b/src/test/ui/nll/match-guards-partially-borrow.rs @@ -5,9 +5,7 @@ // Test that we don't allow mutating the value being matched on in a way that // changes which patterns it matches, until we have chosen an arm. - #![feature(bind_by_move_pattern_guards)] -#![feature(nll)] fn ok_mutation_in_guard(mut q: i32) { match q { diff --git a/src/test/ui/nll/match-guards-partially-borrow.stderr b/src/test/ui/nll/match-guards-partially-borrow.stderr index 3d9b67b4ea660..b2951fd339da4 100644 --- a/src/test/ui/nll/match-guards-partially-borrow.stderr +++ b/src/test/ui/nll/match-guards-partially-borrow.stderr @@ -1,5 +1,5 @@ error[E0510]: cannot assign `q` in match guard - --> $DIR/match-guards-partially-borrow.rs:59:13 + --> $DIR/match-guards-partially-borrow.rs:57:13 | LL | match q { | - value is immutable in match guard @@ -8,7 +8,7 @@ LL | q = true; | ^^^^^^^^ cannot assign error[E0510]: cannot assign `r` in match guard - --> $DIR/match-guards-partially-borrow.rs:71:13 + --> $DIR/match-guards-partially-borrow.rs:69:13 | LL | match r { | - value is immutable in match guard @@ -17,7 +17,7 @@ LL | r = true; | ^^^^^^^^ cannot assign error[E0510]: cannot assign `t` in match guard - --> $DIR/match-guards-partially-borrow.rs:95:13 + --> $DIR/match-guards-partially-borrow.rs:93:13 | LL | match t { | - value is immutable in match guard @@ -26,7 +26,7 @@ LL | t = true; | ^^^^^^^^ cannot assign error[E0510]: cannot mutably borrow `x.0` in match guard - --> $DIR/match-guards-partially-borrow.rs:109:22 + --> $DIR/match-guards-partially-borrow.rs:107:22 | LL | match x { | - value is immutable in match guard @@ -35,7 +35,7 @@ LL | Some(ref mut r) => *r = None, | ^^^^^^^^^ cannot mutably borrow error[E0506]: cannot assign to `t` because it is borrowed - --> $DIR/match-guards-partially-borrow.rs:121:13 + --> $DIR/match-guards-partially-borrow.rs:119:13 | LL | s if { | - borrow of `t` occurs here @@ -46,7 +46,7 @@ LL | } => (), // What value should `s` have in the arm? | - borrow later used here error[E0510]: cannot assign `y` in match guard - --> $DIR/match-guards-partially-borrow.rs:132:13 + --> $DIR/match-guards-partially-borrow.rs:130:13 | LL | match *y { | -- value is immutable in match guard @@ -55,7 +55,7 @@ LL | y = &true; | ^^^^^^^^^ cannot assign error[E0510]: cannot assign `z` in match guard - --> $DIR/match-guards-partially-borrow.rs:143:13 + --> $DIR/match-guards-partially-borrow.rs:141:13 | LL | match z { | - value is immutable in match guard @@ -64,7 +64,7 @@ LL | z = &true; | ^^^^^^^^^ cannot assign error[E0510]: cannot assign `a` in match guard - --> $DIR/match-guards-partially-borrow.rs:155:13 + --> $DIR/match-guards-partially-borrow.rs:153:13 | LL | match a { | - value is immutable in match guard @@ -73,7 +73,7 @@ LL | a = &true; | ^^^^^^^^^ cannot assign error[E0510]: cannot assign `b` in match guard - --> $DIR/match-guards-partially-borrow.rs:166:13 + --> $DIR/match-guards-partially-borrow.rs:164:13 | LL | match b { | - value is immutable in match guard 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 new file mode 100644 index 0000000000000..e6c59fcf22dea --- /dev/null +++ b/src/test/ui/parser/recover-for-loop-parens-around-head.rs @@ -0,0 +1,15 @@ +// Here we test that the parser is able to recover in a situation like +// `for ( $pat in $expr )` since that is familiar syntax in other languages. +// Instead we suggest that the user writes `for $pat in $expr`. + +#![deny(unused)] // Make sure we don't trigger `unused_parens`. + +fn main() { + let vec = vec![1, 2, 3]; + + for ( elem in vec ) { + //~^ ERROR expected one of `)`, `,`, or `@`, found `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 new file mode 100644 index 0000000000000..c160e646c28b3 --- /dev/null +++ b/src/test/ui/parser/recover-for-loop-parens-around-head.stderr @@ -0,0 +1,27 @@ +error: expected one of `)`, `,`, or `@`, found `in` + --> $DIR/recover-for-loop-parens-around-head.rs:10:16 + | +LL | for ( elem in vec ) { + | ^^ expected one of `)`, `,`, or `@` here + +error: unexpected closing `)` + --> $DIR/recover-for-loop-parens-around-head.rs:10:23 + | +LL | for ( elem in vec ) { + | --------------^ + | | + | opening `(` + | help: remove parenthesis in `for` loop: `elem in vec` + +error[E0308]: mismatched types + --> $DIR/recover-for-loop-parens-around-head.rs:13:38 + | +LL | const RECOVERY_WITNESS: () = 0; + | ^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs index 6e75977b5900e..e43c8541e6d6d 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs @@ -2,7 +2,7 @@ // rust-lang/rust#2329), that starts passing with this feature in // place. -// build-pass (FIXME(62277): could be check-pass?) +// run-pass #![feature(bind_by_move_pattern_guards)] @@ -12,6 +12,7 @@ fn main() { let (tx, rx) = channel(); let x = Some(rx); tx.send(false); + tx.send(false); match x { Some(z) if z.recv().unwrap() => { panic!() }, Some(z) => { assert!(!z.recv().unwrap()); }, diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2015.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2015.stderr index 34e8b0e14399e..fe1f699074735 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2015.stderr +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2015.stderr @@ -1,5 +1,5 @@ error: compilation successful - --> $DIR/feature-gate.rs:41:1 + --> $DIR/feature-gate.rs:36:1 | LL | / fn main() { LL | | foo(107) diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2018.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2018.stderr index 34e8b0e14399e..fe1f699074735 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2018.stderr +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.gate_and_2018.stderr @@ -1,5 +1,5 @@ error: compilation successful - --> $DIR/feature-gate.rs:41:1 + --> $DIR/feature-gate.rs:36:1 | LL | / fn main() { LL | | foo(107) diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.no_gate.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.no_gate.stderr index c2f6edee05fa6..7a7b1c253528f 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.no_gate.stderr +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.no_gate.stderr @@ -1,5 +1,5 @@ error[E0008]: cannot bind by-move into a pattern guard - --> $DIR/feature-gate.rs:33:16 + --> $DIR/feature-gate.rs:28:16 | LL | A { a: v } if *v == 42 => v, | ^ moves value into pattern guard diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.rs index 97f90f7762a41..69fce0bc775f7 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.rs +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/feature-gate.rs @@ -6,7 +6,7 @@ // gate-test-bind_by_move_pattern_guards -// revisions: no_gate gate_and_2015 gate_and_2018 gate_and_znll gate_and_feature_nll +// revisions: no_gate gate_and_2015 gate_and_2018 // (We're already testing NLL behavior quite explicitly, no need for compare-mode=nll.) // ignore-compare-mode-nll @@ -15,14 +15,9 @@ #![cfg_attr(gate_and_2015, feature(bind_by_move_pattern_guards))] #![cfg_attr(gate_and_2018, feature(bind_by_move_pattern_guards))] -#![cfg_attr(gate_and_znll, feature(bind_by_move_pattern_guards))] -#![cfg_attr(gate_and_feature_nll, feature(bind_by_move_pattern_guards))] - -#![cfg_attr(gate_and_feature_nll, feature(nll))] //[gate_and_2015] edition:2015 //[gate_and_2018] edition:2018 -//[gate_and_znll] compile-flags: -Z borrowck=mir struct A { a: Box<i32> } @@ -43,5 +38,3 @@ fn main() { } //[gate_and_2015]~^^^ ERROR compilation successful //[gate_and_2018]~^^^^ ERROR compilation successful -//[gate_and_znll]~^^^^^ ERROR compilation successful -//[gate_and_feature_nll]~^^^^^^ ERROR compilation successful diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs index 40588ca331eba..eccb4e417b694 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs @@ -1,6 +1,6 @@ #![feature(bind_by_move_pattern_guards)] -// build-pass (FIXME(62277): could be check-pass?) +// run-pass struct A { a: Box<i32> } @@ -8,32 +8,38 @@ impl A { fn get(&self) -> i32 { *self.a } } -fn foo(n: i32) { +fn foo(n: i32) -> i32 { let x = A { a: Box::new(n) }; let y = match x { A { a: v } if *v == 42 => v, _ => Box::new(0), }; + *y } -fn bar(n: i32) { +fn bar(n: i32) -> i32 { let x = A { a: Box::new(n) }; let y = match x { A { a: v } if x.get() == 42 => v, _ => Box::new(0), }; + *y } -fn baz(n: i32) { +fn baz(n: i32) -> i32 { let x = A { a: Box::new(n) }; let y = match x { A { a: v } if *v.clone() == 42 => v, _ => Box::new(0), }; + *y } fn main() { - foo(107); - bar(107); - baz(107); + assert_eq!(foo(107), 0); + assert_eq!(foo(42), 42); + assert_eq!(bar(107), 0); + assert_eq!(bar(42), 42); + assert_eq!(baz(107), 0); + assert_eq!(baz(42), 42); } diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs index bf387d01b6b2e..602a8e15cb180 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs @@ -1,4 +1,3 @@ -#![feature(nll)] #![feature(bind_by_move_pattern_guards)] enum VecWrapper { A(Vec<i32>) } diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr index f6e4e5bd49bf8..c9e8fc8ee532b 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of `v` in pattern guard - --> $DIR/rfc-reject-double-move-across-arms.rs:8:36 + --> $DIR/rfc-reject-double-move-across-arms.rs:7:36 | LL | VecWrapper::A(v) if { drop(v); false } => 1, | ^ move occurs because `v` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs index ba999e9b3a4a3..77252a1ce1569 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs @@ -1,4 +1,3 @@ -#![feature(nll)] #![feature(bind_by_move_pattern_guards)] struct A { a: Box<i32> } diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr index ec133b028e8f8..a345022cee7c5 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of `v` in pattern guard - --> $DIR/rfc-reject-double-move-in-first-arm.rs:9:30 + --> $DIR/rfc-reject-double-move-in-first-arm.rs:8:30 | LL | A { a: v } if { drop(v); true } => v, | ^ move occurs because `v` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait diff --git a/src/tools/rustc-std-workspace-alloc/Cargo.toml b/src/tools/rustc-std-workspace-alloc/Cargo.toml index 05df1fddc7f1c..ef7dc812af9d4 100644 --- a/src/tools/rustc-std-workspace-alloc/Cargo.toml +++ b/src/tools/rustc-std-workspace-alloc/Cargo.toml @@ -6,6 +6,7 @@ license = 'MIT OR Apache-2.0' description = """ Hack for the compiler's own build system """ +edition = "2018" [lib] path = "lib.rs" diff --git a/src/tools/tidy/src/edition.rs b/src/tools/tidy/src/edition.rs new file mode 100644 index 0000000000000..4a2e49fd1c3c7 --- /dev/null +++ b/src/tools/tidy/src/edition.rs @@ -0,0 +1,45 @@ +//! Tidy check to ensure that crate `edition` is '2018' +//! + +use std::path::Path; + +fn filter_dirs(path: &Path) -> bool { + // FIXME: just use super::filter_dirs after the submodules are updated. + if super::filter_dirs(path) { + return true; + } + let skip = [ + "src/doc/book/second-edition", + "src/doc/book/2018-edition", + "src/doc/book/ci/stable-check", + "src/doc/reference/stable-check", + ]; + skip.iter().any(|p| path.ends_with(p)) +} + +fn is_edition_2018(mut line: &str) -> bool { + line = line.trim(); + line == "edition = \"2018\"" || line == "edition = \'2018\'" +} + +pub fn check(path: &Path, bad: &mut bool) { + super::walk( + path, + &mut |path| filter_dirs(path) || path.ends_with("src/test"), + &mut |entry, contents| { + let file = entry.path(); + let filename = file.file_name().unwrap(); + if filename != "Cargo.toml" { + return; + } + let has_edition = contents.lines().any(is_edition_2018); + if !has_edition { + tidy_error!( + bad, + "{} doesn't have `edition = \"2018\"` on a separate line", + file.display() + ); + } + }, + ); +} diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index eca8001a9d2a1..e01184e3658b5 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -34,6 +34,7 @@ pub mod style; pub mod errors; pub mod features; pub mod cargo; +pub mod edition; pub mod pal; pub mod deps; pub mod extdeps; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 3acb50547daf0..5deac52f08b5e 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -22,6 +22,7 @@ fn main() { style::check(&path, &mut bad); errors::check(&path, &mut bad); cargo::check(&path, &mut bad); + edition::check(&path, &mut bad); let collected = features::check(&path, &mut bad, verbose); pal::check(&path, &mut bad); unstable_book::check(&path, collected, &mut bad);