diff --git a/src/Cargo.lock b/src/Cargo.lock index 0a584ac6b01c4..659feef80a4b9 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -269,7 +269,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "mdbook" -version = "0.0.19" +version = "0.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -425,7 +425,7 @@ name = "rustbook" version = "0.1.0" dependencies = [ "clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mdbook 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "mdbook 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1001,7 +1001,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4732c563b9a21a406565c4747daa7b46742f082911ae4753f390dc9ec7ee1a97" "checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135" "checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" -"checksum mdbook 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "2598843aeda0c5bb2e8e4d714564f1c3fc40f7844157e34563bf96ae3866b56e" +"checksum mdbook 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "f1e2e9d848514dcfad4195788d0d42ae5153a477c191d75d5b84fab10f222fbd" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" "checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99" "checksum num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca313f1862c7ec3e0dfe8ace9fa91b1d9cb5c84ace3d00f5ec4216238e93c167" diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 677eca10d7bae..9db6dffb0e8cc 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -451,7 +451,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // So peel off one-level, turning the &T into T. match base_ty.builtin_deref(false, ty::NoPreference) { Some(t) => t.ty, - None => { return Err(()); } + None => { + debug!("By-ref binding of non-derefable type {:?}", base_ty); + return Err(()); + } } } _ => base_ty, @@ -1039,6 +1042,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { match base_cmt.ty.builtin_index() { Some(ty) => (ty, ElementKind::VecElement), None => { + debug!("Explicit index of non-indexable type {:?}", base_cmt); return Err(()); } } @@ -1154,7 +1158,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) | PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => { match path.def { - Def::Err => return Err(()), + Def::Err => { + debug!("access to unresolvable pattern {:?}", pat); + return Err(()) + } Def::Variant(variant_did) | Def::VariantCtor(variant_did, ..) => { // univariant enums do not need downcasts diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 3678c2e55c1fd..ebe2de5840954 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -11,6 +11,7 @@ use borrowck::BorrowckCtxt; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; +use rustc::middle::mem_categorization::NoteClosureEnv; use rustc::middle::mem_categorization::InteriorOffsetKind as Kind; use rustc::ty; use syntax::ast; @@ -71,10 +72,12 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, let mut err = report_cannot_move_out_of(bccx, error.move_from.clone()); let mut is_first_note = true; for move_to in &error.move_to_places { - err = note_move_destination(err, move_to.span, - move_to.name, is_first_note); + err = note_move_destination(err, move_to.span, move_to.name, is_first_note); is_first_note = false; } + if let NoteClosureEnv(upvar_id) = error.move_from.note { + err.span_label(bccx.tcx.hir.span(upvar_id.var_id), &"captured outer variable"); + } err.emit(); } } diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index da29e354a7014..cc8012d965a76 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -375,6 +375,9 @@ impl Handler { panic!(ExplicitBug); } pub fn delay_span_bug>(&self, sp: S, msg: &str) { + if self.treat_err_as_bug { + self.span_bug(sp, msg); + } let mut delayed = self.delayed_span_bug.borrow_mut(); *delayed = Some((sp.into(), msg.to_string())); } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index f0a74ea4be92c..e81805b96609b 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -516,6 +516,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { }; let index_expr_ty = self.node_ty(index_expr.id); + let adjusted_base_ty = self.resolve_type_vars_if_possible(&adjusted_base_ty); + let index_expr_ty = self.resolve_type_vars_if_possible(&index_expr_ty); let result = self.try_index_step(ty::MethodCall::expr(expr.id), expr, @@ -531,6 +533,15 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let expr_ty = self.node_ty(expr.id); self.demand_suptype(expr.span, expr_ty, return_ty); + } else { + // We could not perform a mutable index. Re-apply the + // immutable index adjustments - borrowck will detect + // this as an error. + if let Some(adjustment) = adjustment { + self.apply_adjustment(expr.id, adjustment); + } + self.tcx.sess.delay_span_bug( + expr.span, "convert_lvalue_derefs_to_mutable failed"); } } hir::ExprUnary(hir::UnDeref, ref base_expr) => { diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 8def11295fda8..34229f80769ab 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -72,24 +72,23 @@ pub struct TcpStream(net_imp::TcpStream); /// /// # Examples /// -/// ```no_run +/// ``` +/// # use std::io; /// use std::net::{TcpListener, TcpStream}; /// -/// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); -/// /// fn handle_client(stream: TcpStream) { /// // ... /// } /// +/// # fn process() -> io::Result<()> { +/// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); +/// /// // accept connections and process them serially /// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// handle_client(stream); -/// } -/// Err(e) => { /* connection failed */ } -/// } +/// handle_client(stream?); /// } +/// # Ok(()) +/// # } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct TcpListener(net_imp::TcpListener); diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 6c8839224f77d..2cb649ce67b9c 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -297,12 +297,14 @@ mod sync; mod mpsc_queue; mod spsc_queue; -/// The receiving-half of Rust's channel type. This half can only be owned by -/// one thread. +/// The receiving half of Rust's [`channel`][] (or [`sync_channel`]) type. +/// This half can only be owned by one thread. /// /// Messages sent to the channel can be retrieved using [`recv`]. /// -/// [`recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv +/// [`channel`]: fn.channel.html +/// [`sync_channel`]: fn.sync_channel.html +/// [`recv`]: struct.Receiver.html#method.recv /// /// # Examples /// @@ -336,51 +338,128 @@ unsafe impl Send for Receiver { } #[stable(feature = "rust1", since = "1.0.0")] impl !Sync for Receiver { } -/// An iterator over messages on a receiver, this iterator will block whenever -/// [`next`] is called, waiting for a new message, and [`None`] will be returned +/// An iterator over messages on a [`Receiver`], created by [`iter`]. +/// +/// This iterator will block whenever [`next`] is called, +/// waiting for a new message, and [`None`] will be returned /// when the corresponding channel has hung up. /// +/// [`iter`]: struct.Receiver.html#method.iter +/// [`Receiver`]: struct.Receiver.html /// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next /// [`None`]: ../../../std/option/enum.Option.html#variant.None +/// +/// # Examples +/// +/// ```rust +/// use std::sync::mpsc::channel; +/// use std::thread; +/// +/// let (send, recv) = channel(); +/// +/// thread::spawn(move || { +/// send.send(1u8).unwrap(); +/// send.send(2u8).unwrap(); +/// send.send(3u8).unwrap(); +/// }); +/// +/// for x in recv.iter() { +/// println!("Got: {}", x); +/// } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Iter<'a, T: 'a> { rx: &'a Receiver } -/// An iterator that attempts to yield all pending values for a receiver. -/// [`None`] will be returned when there are no pending values remaining or if -/// the corresponding channel has hung up. +/// An iterator that attempts to yield all pending values for a [`Receiver`], +/// created by [`try_iter`]. +/// +/// [`None`] will be returned when there are no pending values remaining or +/// if the corresponding channel has hung up. /// -/// This Iterator will never block the caller in order to wait for data to +/// This iterator will never block the caller in order to wait for data to /// become available. Instead, it will return [`None`]. /// +/// [`Receiver`]: struct.Receiver.html +/// [`try_iter`]: struct.Receiver.html#method.try_iter /// [`None`]: ../../../std/option/enum.Option.html#variant.None +/// +/// # Examples +/// +/// ```rust +/// use std::sync::mpsc::channel; +/// use std::thread; +/// use std::time::Duration; +/// +/// let (sender, receiver) = channel(); +/// +/// // Nothing is in the buffer yet +/// assert!(receiver.try_iter().next().is_none()); +/// println!("Nothing in the buffer..."); +/// +/// thread::spawn(move || { +/// sender.send(1).unwrap(); +/// sender.send(2).unwrap(); +/// sender.send(3).unwrap(); +/// }); +/// +/// println!("Going to sleep..."); +/// thread::sleep(Duration::from_secs(2)); // block for two seconds +/// +/// for x in receiver.try_iter() { +/// println!("Got: {}", x); +/// } +/// ``` #[stable(feature = "receiver_try_iter", since = "1.15.0")] #[derive(Debug)] pub struct TryIter<'a, T: 'a> { rx: &'a Receiver } -/// An owning iterator over messages on a receiver, this iterator will block -/// whenever [`next`] is called, waiting for a new message, and [`None`] will be -/// returned when the corresponding channel has hung up. +/// An owning iterator over messages on a [`Receiver`], +/// created by **Receiver::into_iter**. +/// +/// This iterator will block whenever [`next`] +/// is called, waiting for a new message, and [`None`] will be +/// returned if the corresponding channel has hung up. /// +/// [`Receiver`]: struct.Receiver.html /// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next /// [`None`]: ../../../std/option/enum.Option.html#variant.None /// +/// # Examples +/// +/// ```rust +/// use std::sync::mpsc::channel; +/// use std::thread; +/// +/// let (send, recv) = channel(); +/// +/// thread::spawn(move || { +/// send.send(1u8).unwrap(); +/// send.send(2u8).unwrap(); +/// send.send(3u8).unwrap(); +/// }); +/// +/// for x in recv.into_iter() { +/// println!("Got: {}", x); +/// } +/// ``` #[stable(feature = "receiver_into_iter", since = "1.1.0")] #[derive(Debug)] pub struct IntoIter { rx: Receiver } -/// The sending-half of Rust's asynchronous channel type. This half can only be +/// The sending-half of Rust's asynchronous [`channel`] type. This half can only be /// owned by one thread, but it can be cloned to send to other threads. /// /// Messages can be sent through this channel with [`send`]. /// -/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send +/// [`channel`]: fn.channel.html +/// [`send`]: struct.Sender.html#method.send /// /// # Examples /// @@ -419,12 +498,55 @@ unsafe impl Send for Sender { } #[stable(feature = "rust1", since = "1.0.0")] impl !Sync for Sender { } -/// The sending-half of Rust's synchronous channel type. This half can only be -/// owned by one thread, but it can be cloned to send to other threads. +/// The sending-half of Rust's synchronous [`sync_channel`] type. +/// This half can only be owned by one thread, but it can be cloned +/// to send to other threads. +/// +/// Messages can be sent through this channel with [`send`] or [`try_send`]. +/// +/// [`send`] will block if there is no space in the internal buffer. +/// +/// [`sync_channel`]: fn.sync_channel.html +/// [`send`]: struct.SyncSender.html#method.send +/// [`try_send`]: struct.SyncSender.html#method.try_send +/// +/// # Examples +/// +/// ```rust +/// use std::sync::mpsc::sync_channel; +/// use std::thread; /// -/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send -/// [`SyncSender::send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send +/// // Create a sync_channel with buffer size 2 +/// let (sync_sender, receiver) = sync_channel(2); +/// let sync_sender2 = sync_sender.clone(); /// +/// // First thread owns sync_sender +/// thread::spawn(move || { +/// sync_sender.send(1).unwrap(); +/// sync_sender.send(2).unwrap(); +/// }); +/// +/// // Second thread owns sync_sender2 +/// thread::spawn(move || { +/// sync_sender2.send(3).unwrap(); +/// // thread will now block since the buffer is full +/// println!("Thread unblocked!"); +/// }); +/// +/// let mut msg; +/// +/// msg = receiver.recv().unwrap(); +/// println!("message {} received", msg); +/// +/// // "Thread unblocked!" will be printed now +/// +/// msg = receiver.recv().unwrap(); +/// println!("message {} received", msg); +/// +/// msg = receiver.recv().unwrap(); +/// +/// println!("message {} received", msg); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct SyncSender { inner: Arc>, @@ -823,8 +945,9 @@ impl SyncSender { /// Note that a successful send does *not* guarantee that the receiver will /// ever see the data if there is a buffer on this channel. Items may be /// enqueued in the internal buffer for the receiver to receive at a later - /// time. If the buffer size is 0, however, it can be guaranteed that the - /// receiver has indeed received the data if this function returns success. + /// time. If the buffer size is 0, however, the channel becomes a rendezvous + /// channel and it guarantees that the receiver has indeed received + /// the data if this function returns success. /// /// This function will never panic, but it may return [`Err`] if the /// [`Receiver`] has disconnected and is no longer able to receive @@ -832,6 +955,27 @@ impl SyncSender { /// /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err /// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html + /// + /// # Examples + /// + /// ```rust + /// use std::sync::mpsc::sync_channel; + /// use std::thread; + /// + /// // Create a rendezvous sync_channel with buffer size 0 + /// let (sync_sender, receiver) = sync_channel(0); + /// + /// thread::spawn(move || { + /// println!("sending message..."); + /// sync_sender.send(1).unwrap(); + /// // Thread is now blocked until the message is received + /// + /// println!("...message received!"); + /// }); + /// + /// let msg = receiver.recv().unwrap(); + /// assert_eq!(1, msg); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn send(&self, t: T) -> Result<(), SendError> { self.inner.send(t).map_err(SendError) @@ -844,11 +988,48 @@ impl SyncSender { /// data. Compared with [`send`], this function has two failure cases /// instead of one (one for disconnection, one for a full buffer). /// - /// See [`SyncSender::send`] for notes about guarantees of whether the + /// See [`send`] for notes about guarantees of whether the /// receiver has received the data or not if this function is successful. /// - /// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send - /// [`SyncSender::send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send + /// [`send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send + /// + /// # Examples + /// + /// ```rust + /// use std::sync::mpsc::sync_channel; + /// use std::thread; + /// + /// // Create a sync_channel with buffer size 1 + /// let (sync_sender, receiver) = sync_channel(1); + /// let sync_sender2 = sync_sender.clone(); + /// + /// // First thread owns sync_sender + /// thread::spawn(move || { + /// sync_sender.send(1).unwrap(); + /// sync_sender.send(2).unwrap(); + /// // Thread blocked + /// }); + /// + /// // Second thread owns sync_sender2 + /// thread::spawn(move || { + /// // This will return an error and send + /// // no message if the buffer is full + /// sync_sender2.try_send(3).is_err(); + /// }); + /// + /// let mut msg; + /// msg = receiver.recv().unwrap(); + /// println!("message {} received", msg); + /// + /// msg = receiver.recv().unwrap(); + /// println!("message {} received", msg); + /// + /// // Third message may have never been sent + /// match receiver.try_recv() { + /// Ok(msg) => println!("message {} received", msg), + /// Err(_) => println!("the third message was never sent"), + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn try_send(&self, t: T) -> Result<(), TrySendError> { self.inner.try_send(t) @@ -894,6 +1075,21 @@ impl Receiver { /// /// This is useful for a flavor of "optimistic check" before deciding to /// block on a receiver. + /// + /// Compared with [`recv`], this function has two failure cases instead of one + /// (one for disconnection, one for an empty buffer). + /// + /// [`recv`]: struct.Receiver.html#method.recv + /// + /// # Examples + /// + /// ```rust + /// use std::sync::mpsc::{Receiver, channel}; + /// + /// let (_, receiver): (_, Receiver) = channel(); + /// + /// assert!(receiver.try_recv().is_err()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn try_recv(&self) -> Result { loop { @@ -949,8 +1145,8 @@ impl Receiver { /// /// This function will always block the current thread if there is no data /// available and it's possible for more data to be sent. Once a message is - /// sent to the corresponding [`Sender`], then this receiver will wake up and - /// return that message. + /// sent to the corresponding [`Sender`][] (or [`SyncSender`]), then this + /// receiver will wake up and return that message. /// /// If the corresponding [`Sender`] has disconnected, or it disconnects while /// this call is blocking, this call will wake up and return [`Err`] to @@ -958,7 +1154,8 @@ impl Receiver { /// However, since channels are buffered, messages sent before the disconnect /// will still be properly received. /// - /// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html + /// [`Sender`]: struct.Sender.html + /// [`SyncSender`]: struct.SyncSender.html /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err /// /// # Examples @@ -1040,8 +1237,8 @@ impl Receiver { /// /// This function will always block the current thread if there is no data /// available and it's possible for more data to be sent. Once a message is - /// sent to the corresponding [`Sender`], then this receiver will wake up and - /// return that message. + /// sent to the corresponding [`Sender`][] (or [`SyncSender`]), then this + /// receiver will wake up and return that message. /// /// If the corresponding [`Sender`] has disconnected, or it disconnects while /// this call is blocking, this call will wake up and return [`Err`] to @@ -1049,7 +1246,8 @@ impl Receiver { /// However, since channels are buffered, messages sent before the disconnect /// will still be properly received. /// - /// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html + /// [`Sender`]: struct.Sender.html + /// [`SyncSender`]: struct.SyncSender.html /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err /// /// # Examples @@ -1163,6 +1361,33 @@ impl Receiver { /// user by waiting for values. /// /// [`panic!`]: ../../../std/macro.panic.html + /// + /// # Examples + /// + /// ```rust + /// use std::sync::mpsc::channel; + /// use std::thread; + /// use std::time::Duration; + /// + /// let (sender, receiver) = channel(); + /// + /// // Nothing is in the buffer yet + /// assert!(receiver.try_iter().next().is_none()); + /// println!("Nothing in the buffer..."); + /// + /// thread::spawn(move || { + /// sender.send(1).unwrap(); + /// sender.send(2).unwrap(); + /// sender.send(3).unwrap(); + /// }); + /// + /// println!("Going to sleep..."); + /// thread::sleep(Duration::from_secs(2)); // block for two seconds + /// + /// for x in receiver.try_iter() { + /// println!("Got: {}", x); + /// } + /// ``` #[stable(feature = "receiver_try_iter", since = "1.15.0")] pub fn try_iter(&self) -> TryIter { TryIter { rx: self } diff --git a/src/llvm b/src/llvm index 878af191434cd..15745af768384 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 878af191434cd716eeb13c2be7a2b1e21abf2749 +Subproject commit 15745af7683844e43bdec966072b8e7b44772450 diff --git a/src/rustllvm/llvm-rebuild-trigger b/src/rustllvm/llvm-rebuild-trigger index 52ebf449d6007..1006445ade6a1 100644 --- a/src/rustllvm/llvm-rebuild-trigger +++ b/src/rustllvm/llvm-rebuild-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be (optionally) cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2017-04-25 +2017-04-26 diff --git a/src/test/run-pass/issue-41498.rs b/src/test/run-pass/issue-41498.rs new file mode 100644 index 0000000000000..66fd30bdbbbe4 --- /dev/null +++ b/src/test/run-pass/issue-41498.rs @@ -0,0 +1,26 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// regression test for issue #41498. + +struct S; +impl S { + fn mutate(&mut self) {} +} + +fn call_and_ref T>(x: &mut Option, f: F) -> &mut T { + *x = Some(f()); + x.as_mut().unwrap() +} + +fn main() { + let mut n = None; + call_and_ref(&mut n, || [S])[0].mutate(); +} diff --git a/src/test/compile-fail/borrowck/borrowck-in-static.rs b/src/test/ui/borrowck/borrowck-in-static.rs similarity index 94% rename from src/test/compile-fail/borrowck/borrowck-in-static.rs rename to src/test/ui/borrowck/borrowck-in-static.rs index 16b0e8638de39..9244c12347d95 100644 --- a/src/test/compile-fail/borrowck/borrowck-in-static.rs +++ b/src/test/ui/borrowck/borrowck-in-static.rs @@ -11,7 +11,7 @@ // check that borrowck looks inside consts/statics static FN : &'static (Fn() -> (BoxBox>) + Sync) = &|| { - let x = Box::new(0); + let x = Box::new(0); //~ NOTE moved Box::new(|| x) //~ ERROR cannot move out of captured outer variable }; diff --git a/src/test/ui/borrowck/borrowck-in-static.stderr b/src/test/ui/borrowck/borrowck-in-static.stderr new file mode 100644 index 0000000000000..6083a82b1b6de --- /dev/null +++ b/src/test/ui/borrowck/borrowck-in-static.stderr @@ -0,0 +1,10 @@ +error[E0507]: cannot move out of captured outer variable in an `Fn` closure + --> $DIR/borrowck-in-static.rs:15:17 + | +14 | let x = Box::new(0); //~ NOTE moved + | - captured outer variable +15 | Box::new(|| x) //~ ERROR cannot move out of captured outer variable + | ^ cannot move out of captured outer variable in an `Fn` closure + +error: aborting due to previous error + diff --git a/src/test/compile-fail/unboxed-closures-move-upvar-from-non-once-ref-closure.rs b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.rs similarity index 93% rename from src/test/compile-fail/unboxed-closures-move-upvar-from-non-once-ref-closure.rs rename to src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.rs index cd9f1636c3f4d..9c89c26de006a 100644 --- a/src/test/compile-fail/unboxed-closures-move-upvar-from-non-once-ref-closure.rs +++ b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.rs @@ -16,7 +16,7 @@ fn call(f: F) where F : Fn() { } fn main() { - let y = vec![format!("World")]; + let y = vec![format!("World")]; //~ NOTE moved call(|| { y.into_iter(); //~^ ERROR cannot move out of captured outer variable in an `Fn` closure diff --git a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr new file mode 100644 index 0000000000000..dbfcb2e0c2f95 --- /dev/null +++ b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr @@ -0,0 +1,11 @@ +error[E0507]: cannot move out of captured outer variable in an `Fn` closure + --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:21:9 + | +19 | let y = vec![format!("World")]; //~ NOTE moved + | - captured outer variable +20 | call(|| { +21 | y.into_iter(); + | ^ cannot move out of captured outer variable in an `Fn` closure + +error: aborting due to previous error + diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs index 6264d11186452..29fea052b06c2 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs @@ -21,8 +21,11 @@ struct Test<'a> { fn call(mut f: F) where F: FnMut(Fn) { f(Box::new(|| { //~^ ERROR: cannot borrow `f` as mutable more than once + //~| NOTE first mutable borrow occurs here + //~| NOTE second mutable borrow occurs here f((Box::new(|| {}))) })); + //~^ NOTE first borrow ends here } fn test1() { @@ -32,7 +35,10 @@ fn test1() { } fn test2(f: &F) where F: FnMut() { - (*f)(); //~ ERROR: cannot borrow immutable borrowed content `*f` as mutable + //~^ NOTE use `&mut F` here to make mutable + (*f)(); + //~^ ERROR cannot borrow immutable borrowed content `*f` as mutable + //~| NOTE cannot borrow as mutable } fn test3(f: &mut F) where F: FnMut() { @@ -40,7 +46,10 @@ fn test3(f: &mut F) where F: FnMut() { } fn test4(f: &Test) { - f.f.call_mut(()) //~ ERROR: cannot borrow immutable `Box` content `*f.f` as mutable + //~^ NOTE use `&mut Test` here to make mutable + f.f.call_mut(()) + //~^ ERROR: cannot borrow immutable `Box` content `*f.f` as mutable + //~| NOTE cannot borrow as mutable } fn test5(f: &mut Test) { @@ -57,10 +66,14 @@ fn test6() { fn test7() { fn foo(_: F) where F: FnMut(Box, isize) {} let mut f = |g: Box, b: isize| {}; + //~^ NOTE moved f(Box::new(|a| { + //~^ NOTE borrow of `f` occurs here foo(f); //~^ ERROR cannot move `f` into closure because it is borrowed //~| ERROR cannot move out of captured outer variable in an `FnMut` closure + //~| NOTE move into closure occurs here + //~| NOTE cannot move out of captured outer variable in an `FnMut` closure }), 3); } diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr index 58b3f205fe352..4ece8bc6af10f 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr @@ -5,40 +5,46 @@ error[E0499]: cannot borrow `f` as mutable more than once at a time | - ^^ second mutable borrow occurs here | | | first mutable borrow occurs here -23 | //~^ ERROR: cannot borrow `f` as mutable more than once -24 | f((Box::new(|| {}))) +... +26 | f((Box::new(|| {}))) | - borrow occurs due to use of `f` in closure -25 | })); +27 | })); | - first borrow ends here error: cannot borrow immutable borrowed content `*f` as mutable - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:35:5 + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:39:5 | -34 | fn test2(f: &F) where F: FnMut() { +37 | fn test2(f: &F) where F: FnMut() { | -- use `&mut F` here to make mutable -35 | (*f)(); //~ ERROR: cannot borrow immutable borrowed content `*f` as mutable +38 | //~^ NOTE use `&mut F` here to make mutable +39 | (*f)(); | ^^^^ cannot borrow as mutable error: cannot borrow immutable `Box` content `*f.f` as mutable - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:43:5 + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:50:5 | -42 | fn test4(f: &Test) { +48 | fn test4(f: &Test) { | ----- use `&mut Test` here to make mutable -43 | f.f.call_mut(()) //~ ERROR: cannot borrow immutable `Box` content `*f.f` as mutable +49 | //~^ NOTE use `&mut Test` here to make mutable +50 | f.f.call_mut(()) | ^^^ cannot borrow as mutable error[E0504]: cannot move `f` into closure because it is borrowed - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:61:13 + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:72:13 | -60 | f(Box::new(|a| { +70 | f(Box::new(|a| { | - borrow of `f` occurs here -61 | foo(f); +71 | //~^ NOTE borrow of `f` occurs here +72 | foo(f); | ^ move into closure occurs here error[E0507]: cannot move out of captured outer variable in an `FnMut` closure - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:61:13 + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:72:13 | -61 | foo(f); +68 | let mut f = |g: Box, b: isize| {}; + | ----- captured outer variable +... +72 | foo(f); | ^ cannot move out of captured outer variable in an `FnMut` closure error: aborting due to 5 previous errors diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index e320933067226..2d5d163d40305 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -8,5 +8,5 @@ license = "MIT/Apache-2.0" clap = "2.19.3" [dependencies.mdbook] -version = "0.0.19" +version = "0.0.21" default-features = false diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs index b77baed532677..33326de9c1cc3 100644 --- a/src/tools/rustbook/src/main.rs +++ b/src/tools/rustbook/src/main.rs @@ -53,8 +53,7 @@ fn main() { // Build command implementation fn build(args: &ArgMatches) -> Result<(), Box> { - let book_dir = get_book_dir(args); - let book = MDBook::new(&book_dir).read_config(); + let book = build_mdbook_struct(args); let mut book = match args.value_of("dest-dir") { Some(dest_dir) => book.set_dest(Path::new(dest_dir)), @@ -67,14 +66,26 @@ fn build(args: &ArgMatches) -> Result<(), Box> { } fn test(args: &ArgMatches) -> Result<(), Box> { - let book_dir = get_book_dir(args); - let mut book = MDBook::new(&book_dir).read_config(); + let mut book = build_mdbook_struct(args); try!(book.test()); Ok(()) } +fn build_mdbook_struct(args: &ArgMatches) -> mdbook::MDBook { + let book_dir = get_book_dir(args); + let mut book = MDBook::new(&book_dir).read_config(); + + // By default mdbook will attempt to create non-existent files referenced + // from SUMMARY.md files. This is problematic on CI where we mount the + // source directory as readonly. To avoid any issues, we'll disabled + // mdbook's implicit file creation feature. + book.create_missing = false; + + book +} + fn get_book_dir(args: &ArgMatches) -> PathBuf { if let Some(dir) = args.value_of("dir") { // Check if path is relative from current dir, or absolute...