From 81cd1e64f38299276ce131db37994086ec94ad35 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 15 Jan 2019 20:48:52 -0800 Subject: [PATCH 01/28] Deprecate the unstable Vec::resize_default --- src/liballoc/vec.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index ba3b3dfbfc2e1..198d1ee4bb4fc 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1368,6 +1368,7 @@ impl Vec { /// # Examples /// /// ``` + /// # #![allow(deprecated)] /// #![feature(vec_resize_default)] /// /// let mut vec = vec![1, 2, 3]; @@ -1384,6 +1385,9 @@ impl Vec { /// [`Default`]: ../../std/default/trait.Default.html /// [`Clone`]: ../../std/clone/trait.Clone.html #[unstable(feature = "vec_resize_default", issue = "41758")] + #[rustc_deprecated(reason = "This is moving towards being removed in favor \ + of `.resize_with(Default::default)`. If you disagree, please comment \ + in the tracking issue.", since = "1.33.0")] pub fn resize_default(&mut self, new_len: usize) { let len = self.len(); From 6bfb280189ef6960525f18364c1b4644a913f4ce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Feb 2019 19:53:32 +0100 Subject: [PATCH 02/28] deprecate before_exec in favor of unsafe pre_exec --- src/libstd/sys/unix/ext/process.rs | 26 ++++++++++++++++--- src/libstd/sys/unix/process/process_common.rs | 2 +- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index 0282aaae90923..f5fc26dc9cca6 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -45,12 +45,32 @@ pub trait CommandExt { /// like `malloc` or acquiring a mutex are not guaranteed to work (due to /// other threads perhaps still running when the `fork` was run). /// + /// This also means that all resources such as file descriptors and + /// memory-mapped regions got duplicated. It is your responsibility to make + /// sure that the closure does not violate library invariants by making + /// invalid use of these duplicates. + /// /// When this closure is run, aspects such as the stdio file descriptors and /// working directory have successfully been changed, so output to these /// locations may not appear where intended. + #[stable(feature = "process_pre_exec", since = "1.34.0")] + unsafe fn pre_exec(&mut self, f: F) -> &mut process::Command + where F: FnMut() -> io::Result<()> + Send + Sync + 'static; + + /// Schedules a closure to be run just before the `exec` function is + /// invoked. + /// + /// This method should be unsafe, so it got deprecated in favor of the + /// unsafe [`pre_exec`]. + /// + /// [`pre_exec`]: #tymethod.pre_exec #[stable(feature = "process_exec", since = "1.15.0")] + #[rustc_deprecated(since = "1.34.0", reason = "should be unsafe, use `pre_exec` instead")] fn before_exec(&mut self, f: F) -> &mut process::Command - where F: FnMut() -> io::Result<()> + Send + Sync + 'static; + where F: FnMut() -> io::Result<()> + Send + Sync + 'static + { + unsafe { self.pre_exec(f) } + } /// Performs all the required setup by this `Command`, followed by calling /// the `execvp` syscall. @@ -97,10 +117,10 @@ impl CommandExt for process::Command { self } - fn before_exec(&mut self, f: F) -> &mut process::Command + unsafe fn pre_exec(&mut self, f: F) -> &mut process::Command where F: FnMut() -> io::Result<()> + Send + Sync + 'static { - self.as_inner_mut().before_exec(Box::new(f)); + self.as_inner_mut().pre_exec(Box::new(f)); self } diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index 2c55813c5cd39..9975064ca655f 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -149,7 +149,7 @@ impl Command { &mut self.closures } - pub fn before_exec(&mut self, + pub unsafe fn pre_exec(&mut self, f: Box io::Result<()> + Send + Sync>) { self.closures.push(f); } From d48433d920ad27ab57a27f087bcdec79ab36bfdc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Feb 2019 19:57:06 +0100 Subject: [PATCH 03/28] also replace before_exec by pre_exec on redox --- src/libstd/sys/redox/ext/process.rs | 28 ++++++++++++++++++++++++---- src/libstd/sys/redox/process.rs | 2 +- src/libstd/sys/unix/ext/process.rs | 2 +- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/libstd/sys/redox/ext/process.rs b/src/libstd/sys/redox/ext/process.rs index 941fba8755b4a..78917ea91886b 100644 --- a/src/libstd/sys/redox/ext/process.rs +++ b/src/libstd/sys/redox/ext/process.rs @@ -36,7 +36,7 @@ pub trait CommandExt { /// will be called and the spawn operation will immediately return with a /// failure. /// - /// # Notes + /// # Notes and Safety /// /// This closure will be run in the context of the child process after a /// `fork`. This primarily means that any modifications made to memory on @@ -45,12 +45,32 @@ pub trait CommandExt { /// like `malloc` or acquiring a mutex are not guaranteed to work (due to /// other threads perhaps still running when the `fork` was run). /// + /// This also means that all resources such as file descriptors and + /// memory-mapped regions got duplicated. It is your responsibility to make + /// sure that the closure does not violate library invariants by making + /// invalid use of these duplicates. + /// /// When this closure is run, aspects such as the stdio file descriptors and /// working directory have successfully been changed, so output to these /// locations may not appear where intended. + #[stable(feature = "process_pre_exec", since = "1.34.0")] + unsafe fn pre_exec(&mut self, f: F) -> &mut process::Command + where F: FnMut() -> io::Result<()> + Send + Sync + 'static; + + /// Schedules a closure to be run just before the `exec` function is + /// invoked. + /// + /// This method should be unsafe, so it got deprecated in favor of the + /// unsafe [`pre_exec`]. + /// + /// [`pre_exec`]: #tymethod.pre_exec #[stable(feature = "process_exec", since = "1.15.0")] + #[rustc_deprecated(since = "1.34.0", reason = "should be unsafe, use `pre_exec` instead")] fn before_exec(&mut self, f: F) -> &mut process::Command - where F: FnMut() -> io::Result<()> + Send + Sync + 'static; + where F: FnMut() -> io::Result<()> + Send + Sync + 'static + { + unsafe { self.pre_exec(f) } + } /// Performs all the required setup by this `Command`, followed by calling /// the `execvp` syscall. @@ -87,10 +107,10 @@ impl CommandExt for process::Command { self } - fn before_exec(&mut self, f: F) -> &mut process::Command + unsafe fn pre_exec(&mut self, f: F) -> &mut process::Command where F: FnMut() -> io::Result<()> + Send + Sync + 'static { - self.as_inner_mut().before_exec(Box::new(f)); + self.as_inner_mut().pre_exec(Box::new(f)); self } diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 4199ab98cf17e..9b85fa41a0a4f 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -116,7 +116,7 @@ impl Command { self.gid = Some(id); } - pub fn before_exec(&mut self, + pub unsafe fn pre_exec(&mut self, f: Box io::Result<()> + Send + Sync>) { self.closures.push(f); } diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index f5fc26dc9cca6..7cc5e9945938d 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -36,7 +36,7 @@ pub trait CommandExt { /// will be called and the spawn operation will immediately return with a /// failure. /// - /// # Notes + /// # Notes and Safety /// /// This closure will be run in the context of the child process after a /// `fork`. This primarily means that any modifications made to memory on From b1709d25e12fbffca53c30d05c16854256185900 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Feb 2019 20:00:08 +0100 Subject: [PATCH 04/28] update test --- ...and-before-exec.rs => command-pre-exec.rs} | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) rename src/test/run-pass/{command-before-exec.rs => command-pre-exec.rs} (75%) diff --git a/src/test/run-pass/command-before-exec.rs b/src/test/run-pass/command-pre-exec.rs similarity index 75% rename from src/test/run-pass/command-before-exec.rs rename to src/test/run-pass/command-pre-exec.rs index 91d2636b2ae63..bca2b8410fa84 100644 --- a/src/test/run-pass/command-before-exec.rs +++ b/src/test/run-pass/command-pre-exec.rs @@ -29,53 +29,53 @@ fn main() { let me = env::current_exe().unwrap(); - let output = Command::new(&me).arg("test1").before_exec(|| { + let output = unsafe { Command::new(&me).arg("test1").pre_exec(|| { println!("hello"); Ok(()) - }).output().unwrap(); + }).output().unwrap() }; assert!(output.status.success()); assert!(output.stderr.is_empty()); assert_eq!(output.stdout, b"hello\nhello2\n"); - let output = Command::new(&me).arg("test2").before_exec(|| { + let output = unsafe { Command::new(&me).arg("test2").pre_exec(|| { env::set_var("FOO", "BAR"); Ok(()) - }).output().unwrap(); + }).output().unwrap() }; assert!(output.status.success()); assert!(output.stderr.is_empty()); assert!(output.stdout.is_empty()); - let output = Command::new(&me).arg("test3").before_exec(|| { + let output = unsafe { Command::new(&me).arg("test3").pre_exec(|| { env::set_current_dir("/").unwrap(); Ok(()) - }).output().unwrap(); + }).output().unwrap() }; assert!(output.status.success()); assert!(output.stderr.is_empty()); assert!(output.stdout.is_empty()); - let output = Command::new(&me).arg("bad").before_exec(|| { + let output = unsafe { Command::new(&me).arg("bad").pre_exec(|| { Err(Error::from_raw_os_error(102)) - }).output().unwrap_err(); + }).output().unwrap_err() }; assert_eq!(output.raw_os_error(), Some(102)); let pid = unsafe { libc::getpid() }; assert!(pid >= 0); - let output = Command::new(&me).arg("empty").before_exec(move || { - let child = unsafe { libc::getpid() }; + let output = unsafe { Command::new(&me).arg("empty").pre_exec(move || { + let child = libc::getpid(); assert!(child >= 0); assert!(pid != child); Ok(()) - }).output().unwrap(); + }).output().unwrap() }; assert!(output.status.success()); assert!(output.stderr.is_empty()); assert!(output.stdout.is_empty()); let mem = Arc::new(AtomicUsize::new(0)); let mem2 = mem.clone(); - let output = Command::new(&me).arg("empty").before_exec(move || { + let output = unsafe { Command::new(&me).arg("empty").pre_exec(move || { assert_eq!(mem2.fetch_add(1, Ordering::SeqCst), 0); Ok(()) - }).output().unwrap(); + }).output().unwrap() }; assert!(output.status.success()); assert!(output.stderr.is_empty()); assert!(output.stdout.is_empty()); From cbbf8a7ff932b599227b27d34e9b015374f5b37a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Feb 2019 11:00:55 +0100 Subject: [PATCH 05/28] deprecate things a bit slower --- src/libstd/sys/redox/ext/process.rs | 2 +- src/libstd/sys/unix/ext/process.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/redox/ext/process.rs b/src/libstd/sys/redox/ext/process.rs index 78917ea91886b..4e669bbb2d7dc 100644 --- a/src/libstd/sys/redox/ext/process.rs +++ b/src/libstd/sys/redox/ext/process.rs @@ -65,7 +65,7 @@ pub trait CommandExt { /// /// [`pre_exec`]: #tymethod.pre_exec #[stable(feature = "process_exec", since = "1.15.0")] - #[rustc_deprecated(since = "1.34.0", reason = "should be unsafe, use `pre_exec` instead")] + #[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")] fn before_exec(&mut self, f: F) -> &mut process::Command where F: FnMut() -> io::Result<()> + Send + Sync + 'static { diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index 7cc5e9945938d..da0507c65423d 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -65,7 +65,7 @@ pub trait CommandExt { /// /// [`pre_exec`]: #tymethod.pre_exec #[stable(feature = "process_exec", since = "1.15.0")] - #[rustc_deprecated(since = "1.34.0", reason = "should be unsafe, use `pre_exec` instead")] + #[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")] fn before_exec(&mut self, f: F) -> &mut process::Command where F: FnMut() -> io::Result<()> + Send + Sync + 'static { From 6c67a7625fbd38b4b986981c553dc7eb5a7a4765 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Feb 2019 11:05:43 +0100 Subject: [PATCH 06/28] pre_exec: expand docs --- src/libstd/sys/redox/ext/process.rs | 7 ++++--- src/libstd/sys/unix/ext/process.rs | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/libstd/sys/redox/ext/process.rs b/src/libstd/sys/redox/ext/process.rs index 4e669bbb2d7dc..55824dc4c059f 100644 --- a/src/libstd/sys/redox/ext/process.rs +++ b/src/libstd/sys/redox/ext/process.rs @@ -48,7 +48,8 @@ pub trait CommandExt { /// This also means that all resources such as file descriptors and /// memory-mapped regions got duplicated. It is your responsibility to make /// sure that the closure does not violate library invariants by making - /// invalid use of these duplicates. + /// invalid use of these duplicates. Moreover, POSIX demands that you only + /// perform operations that are explicitly documented as async-signal-safe. /// /// When this closure is run, aspects such as the stdio file descriptors and /// working directory have successfully been changed, so output to these @@ -60,8 +61,8 @@ pub trait CommandExt { /// Schedules a closure to be run just before the `exec` function is /// invoked. /// - /// This method should be unsafe, so it got deprecated in favor of the - /// unsafe [`pre_exec`]. + /// This method is stable and usable, but it should be unsafe. To fix + /// that, it got deprecated in favor of the unsafe [`pre_exec`]. /// /// [`pre_exec`]: #tymethod.pre_exec #[stable(feature = "process_exec", since = "1.15.0")] diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index da0507c65423d..ac0abc761ffb5 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -48,7 +48,8 @@ pub trait CommandExt { /// This also means that all resources such as file descriptors and /// memory-mapped regions got duplicated. It is your responsibility to make /// sure that the closure does not violate library invariants by making - /// invalid use of these duplicates. + /// invalid use of these duplicates. Moreover, POSIX demands that you only + /// perform operations that are explicitly documented as async-signal-safe. /// /// When this closure is run, aspects such as the stdio file descriptors and /// working directory have successfully been changed, so output to these @@ -60,8 +61,8 @@ pub trait CommandExt { /// Schedules a closure to be run just before the `exec` function is /// invoked. /// - /// This method should be unsafe, so it got deprecated in favor of the - /// unsafe [`pre_exec`]. + /// This method is stable and usable, but it should be unsafe. To fix + /// that, it got deprecated in favor of the unsafe [`pre_exec`]. /// /// [`pre_exec`]: #tymethod.pre_exec #[stable(feature = "process_exec", since = "1.15.0")] From 59da97d2b2d0e3d4baf70cd6fdf49c31c7def380 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Feb 2019 11:08:21 +0100 Subject: [PATCH 07/28] rustfmt the test --- src/test/run-pass/command-pre-exec.rs | 92 ++++++++++++++++++--------- 1 file changed, 62 insertions(+), 30 deletions(-) diff --git a/src/test/run-pass/command-pre-exec.rs b/src/test/run-pass/command-pre-exec.rs index bca2b8410fa84..21783fedd39c9 100644 --- a/src/test/run-pass/command-pre-exec.rs +++ b/src/test/run-pass/command-pre-exec.rs @@ -2,7 +2,6 @@ // ignore-windows - this is a unix-specific test // ignore-cloudabi no processes // ignore-emscripten no processes - #![feature(process_exec, rustc_private)] extern crate libc; @@ -11,71 +10,104 @@ use std::env; use std::io::Error; use std::os::unix::process::CommandExt; use std::process::Command; -use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; fn main() { if let Some(arg) = env::args().nth(1) { match &arg[..] { "test1" => println!("hello2"), "test2" => assert_eq!(env::var("FOO").unwrap(), "BAR"), - "test3" => assert_eq!(env::current_dir().unwrap() - .to_str().unwrap(), "/"), + "test3" => assert_eq!(env::current_dir().unwrap().to_str().unwrap(), "/"), "empty" => {} _ => panic!("unknown argument: {}", arg), } - return + return; } let me = env::current_exe().unwrap(); - let output = unsafe { Command::new(&me).arg("test1").pre_exec(|| { - println!("hello"); - Ok(()) - }).output().unwrap() }; + let output = unsafe { + Command::new(&me) + .arg("test1") + .pre_exec(|| { + println!("hello"); + Ok(()) + }) + .output() + .unwrap() + }; assert!(output.status.success()); assert!(output.stderr.is_empty()); assert_eq!(output.stdout, b"hello\nhello2\n"); - let output = unsafe { Command::new(&me).arg("test2").pre_exec(|| { - env::set_var("FOO", "BAR"); - Ok(()) - }).output().unwrap() }; + let output = unsafe { + Command::new(&me) + .arg("test2") + .pre_exec(|| { + env::set_var("FOO", "BAR"); + Ok(()) + }) + .output() + .unwrap() + }; assert!(output.status.success()); assert!(output.stderr.is_empty()); assert!(output.stdout.is_empty()); - let output = unsafe { Command::new(&me).arg("test3").pre_exec(|| { - env::set_current_dir("/").unwrap(); - Ok(()) - }).output().unwrap() }; + let output = unsafe { + Command::new(&me) + .arg("test3") + .pre_exec(|| { + env::set_current_dir("/").unwrap(); + Ok(()) + }) + .output() + .unwrap() + }; assert!(output.status.success()); assert!(output.stderr.is_empty()); assert!(output.stdout.is_empty()); - let output = unsafe { Command::new(&me).arg("bad").pre_exec(|| { - Err(Error::from_raw_os_error(102)) - }).output().unwrap_err() }; + let output = unsafe { + Command::new(&me) + .arg("bad") + .pre_exec(|| Err(Error::from_raw_os_error(102))) + .output() + .unwrap_err() + }; assert_eq!(output.raw_os_error(), Some(102)); let pid = unsafe { libc::getpid() }; assert!(pid >= 0); - let output = unsafe { Command::new(&me).arg("empty").pre_exec(move || { - let child = libc::getpid(); - assert!(child >= 0); - assert!(pid != child); - Ok(()) - }).output().unwrap() }; + let output = unsafe { + Command::new(&me) + .arg("empty") + .pre_exec(move || { + let child = libc::getpid(); + assert!(child >= 0); + assert!(pid != child); + Ok(()) + }) + .output() + .unwrap() + }; assert!(output.status.success()); assert!(output.stderr.is_empty()); assert!(output.stdout.is_empty()); let mem = Arc::new(AtomicUsize::new(0)); let mem2 = mem.clone(); - let output = unsafe { Command::new(&me).arg("empty").pre_exec(move || { - assert_eq!(mem2.fetch_add(1, Ordering::SeqCst), 0); - Ok(()) - }).output().unwrap() }; + let output = unsafe { + Command::new(&me) + .arg("empty") + .pre_exec(move || { + assert_eq!(mem2.fetch_add(1, Ordering::SeqCst), 0); + Ok(()) + }) + .output() + .unwrap() + }; assert!(output.status.success()); assert!(output.stderr.is_empty()); assert!(output.stdout.is_empty()); From 33ee99b26a499027546f88a7f4eeddd8d4985c39 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Feb 2019 11:16:37 +0100 Subject: [PATCH 08/28] more formatting --- src/libstd/sys/redox/process.rs | 6 ++++-- src/libstd/sys/unix/process/process_common.rs | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 9b85fa41a0a4f..62eb8cb23ab56 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -116,8 +116,10 @@ impl Command { self.gid = Some(id); } - pub unsafe fn pre_exec(&mut self, - f: Box io::Result<()> + Send + Sync>) { + pub unsafe fn pre_exec( + &mut self, + f: Box io::Result<()> + Send + Sync>, + ) { self.closures.push(f); } diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index 9975064ca655f..7fa256e59b2db 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -149,8 +149,10 @@ impl Command { &mut self.closures } - pub unsafe fn pre_exec(&mut self, - f: Box io::Result<()> + Send + Sync>) { + pub unsafe fn pre_exec( + &mut self, + f: Box io::Result<()> + Send + Sync>, + ) { self.closures.push(f); } From e023403da2da17ba7320c53c415b960c93348247 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Feb 2019 11:17:59 +0100 Subject: [PATCH 09/28] POSIX requires async signal safety for fork in signal handlers, not in general --- src/libstd/sys/redox/ext/process.rs | 3 +-- src/libstd/sys/unix/ext/process.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libstd/sys/redox/ext/process.rs b/src/libstd/sys/redox/ext/process.rs index 55824dc4c059f..18aef768b5db1 100644 --- a/src/libstd/sys/redox/ext/process.rs +++ b/src/libstd/sys/redox/ext/process.rs @@ -48,8 +48,7 @@ pub trait CommandExt { /// This also means that all resources such as file descriptors and /// memory-mapped regions got duplicated. It is your responsibility to make /// sure that the closure does not violate library invariants by making - /// invalid use of these duplicates. Moreover, POSIX demands that you only - /// perform operations that are explicitly documented as async-signal-safe. + /// invalid use of these duplicates. /// /// When this closure is run, aspects such as the stdio file descriptors and /// working directory have successfully been changed, so output to these diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index ac0abc761ffb5..d869a2013dc27 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -48,8 +48,7 @@ pub trait CommandExt { /// This also means that all resources such as file descriptors and /// memory-mapped regions got duplicated. It is your responsibility to make /// sure that the closure does not violate library invariants by making - /// invalid use of these duplicates. Moreover, POSIX demands that you only - /// perform operations that are explicitly documented as async-signal-safe. + /// invalid use of these duplicates. /// /// When this closure is run, aspects such as the stdio file descriptors and /// working directory have successfully been changed, so output to these From f753d304c6c5d7f2c10147d783d58db7db4ffc4c Mon Sep 17 00:00:00 2001 From: Igor Sadikov Date: Tue, 5 Feb 2019 15:21:03 -0500 Subject: [PATCH 10/28] Suggest removing parentheses surrounding lifetimes --- src/libsyntax/parse/parser.rs | 17 +++++++++++++++-- .../parser/trait-object-lifetime-parens.stderr | 8 ++++---- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index cacdab980facd..1dbe3fb7ea620 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5371,6 +5371,7 @@ impl<'a> Parser<'a> { if is_bound_start { let lo = self.span; let has_parens = self.eat(&token::OpenDelim(token::Paren)); + let inner_lo = self.span; let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; if self.token.is_lifetime() { if let Some(question_span) = question { @@ -5379,9 +5380,21 @@ impl<'a> Parser<'a> { } bounds.push(GenericBound::Outlives(self.expect_lifetime())); if has_parens { + let inner_span = inner_lo.to(self.prev_span); self.expect(&token::CloseDelim(token::Paren))?; - self.span_err(self.prev_span, - "parenthesized lifetime bounds are not supported"); + let mut err = self.struct_span_err( + lo.to(self.prev_span), + "parenthesized lifetime bounds are not supported" + ); + if let Ok(snippet) = self.sess.source_map().span_to_snippet(inner_span) { + err.span_suggestion_short( + lo.to(self.prev_span), + "remove the parentheses", + snippet.to_owned(), + Applicability::MachineApplicable + ); + } + err.emit(); } } else { let lifetime_defs = self.parse_late_bound_lifetime_defs()?; diff --git a/src/test/ui/parser/trait-object-lifetime-parens.stderr b/src/test/ui/parser/trait-object-lifetime-parens.stderr index a9b542ddcc4d3..94ca66aef729b 100644 --- a/src/test/ui/parser/trait-object-lifetime-parens.stderr +++ b/src/test/ui/parser/trait-object-lifetime-parens.stderr @@ -1,14 +1,14 @@ error: parenthesized lifetime bounds are not supported - --> $DIR/trait-object-lifetime-parens.rs:5:24 + --> $DIR/trait-object-lifetime-parens.rs:5:21 | LL | fn f<'a, T: Trait + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not supported - | ^ + | ^^^^ help: remove the parentheses error: parenthesized lifetime bounds are not supported - --> $DIR/trait-object-lifetime-parens.rs:8:27 + --> $DIR/trait-object-lifetime-parens.rs:8:24 | LL | let _: Box; //~ ERROR parenthesized lifetime bounds are not supported - | ^ + | ^^^^ help: remove the parentheses error: expected type, found `'a` --> $DIR/trait-object-lifetime-parens.rs:9:17 From d87df696b1811dc6da6a0be1d90b4398a67eb87e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Feb 2019 16:18:12 +0100 Subject: [PATCH 11/28] fix overlapping mutable and shared references in BTreeMap's into_slices_mut --- src/liballoc/collections/btree/node.rs | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index eb0667228d1ff..cb38e6470ab11 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -645,6 +645,8 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { } fn into_key_slice_mut(mut self) -> &'a mut [K] { + // Same as for `into_key_slice` above, we try to avoid a run-time check + // (the alignment comparison will usually be performed at compile-time). if mem::align_of::() > mem::align_of::>() && self.is_shared_root() { &mut [] } else { @@ -667,9 +669,26 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { } } - fn into_slices_mut(self) -> (&'a mut [K], &'a mut [V]) { - let k = unsafe { ptr::read(&self) }; - (k.into_key_slice_mut(), self.into_val_slice_mut()) + fn into_slices_mut(mut self) -> (&'a mut [K], &'a mut [V]) { + debug_assert!(!self.is_shared_root()); + // We cannot use the getters here, because calling the second one + // invalidates the reference returned by the first. + // More precisely, it is the call to `len` that is the culprit, + // because that creates a shared reference to the header, which *can* + // overlap with the keys. + unsafe { + let len = self.len(); + let leaf = self.as_leaf_mut(); + let keys = slice::from_raw_parts_mut( + MaybeUninit::first_ptr_mut(&mut (*leaf).keys), + len + ); + let vals = slice::from_raw_parts_mut( + MaybeUninit::first_ptr_mut(&mut (*leaf).vals), + len + ); + (keys, vals) + } } } From f0bef49cf10c19b72b7d025aedb407ab5745c365 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Feb 2019 17:13:50 +0100 Subject: [PATCH 12/28] fix invalidating references in BTree iterators --- src/liballoc/collections/btree/map.rs | 32 ++++++++++++++++---------- src/liballoc/collections/btree/node.rs | 2 +- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 5ec5064b73515..18fdc8ca2e418 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1634,9 +1634,11 @@ impl<'a, K, V> RangeMut<'a, K, V> { let mut cur_handle = match handle.right_kv() { Ok(kv) => { - let (k, v) = ptr::read(&kv).into_kv_mut(); - self.front = kv.right_edge(); - return (k, v); + self.front = ptr::read(&kv).right_edge(); + // Doing the descend invalidates the references returned by `into_kv_mut`, + // so we have to do this last. + let (k, v) = kv.into_kv_mut(); + return (k, v); // coerce k from `&mut K` to `&K` } Err(last_edge) => { let next_level = last_edge.into_node().ascend().ok(); @@ -1647,9 +1649,11 @@ impl<'a, K, V> RangeMut<'a, K, V> { loop { match cur_handle.right_kv() { Ok(kv) => { - let (k, v) = ptr::read(&kv).into_kv_mut(); - self.front = first_leaf_edge(kv.right_edge().descend()); - return (k, v); + self.front = first_leaf_edge(ptr::read(&kv).right_edge().descend()); + // Doing the descend invalidates the references returned by `into_kv_mut`, + // so we have to do this last. + let (k, v) = kv.into_kv_mut(); + return (k, v); // coerce k from `&mut K` to `&K` } Err(last_edge) => { let next_level = last_edge.into_node().ascend().ok(); @@ -1680,9 +1684,11 @@ impl<'a, K, V> RangeMut<'a, K, V> { let mut cur_handle = match handle.left_kv() { Ok(kv) => { - let (k, v) = ptr::read(&kv).into_kv_mut(); - self.back = kv.left_edge(); - return (k, v); + self.back = ptr::read(&kv).left_edge(); + // Doing the descend invalidates the references returned by `into_kv_mut`, + // so we have to do this last. + let (k, v) = kv.into_kv_mut(); + return (k, v); // coerce k from `&mut K` to `&K` } Err(last_edge) => { let next_level = last_edge.into_node().ascend().ok(); @@ -1693,9 +1699,11 @@ impl<'a, K, V> RangeMut<'a, K, V> { loop { match cur_handle.left_kv() { Ok(kv) => { - let (k, v) = ptr::read(&kv).into_kv_mut(); - self.back = last_leaf_edge(kv.left_edge().descend()); - return (k, v); + self.back = last_leaf_edge(ptr::read(&kv).left_edge().descend()); + // Doing the descend invalidates the references returned by `into_kv_mut`, + // so we have to do this last. + let (k, v) = kv.into_kv_mut(); + return (k, v); // coerce k from `&mut K` to `&K` } Err(last_edge) => { let next_level = last_edge.into_node().ascend().ok(); diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index cb38e6470ab11..1cdf4fdd2db20 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -675,7 +675,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { // invalidates the reference returned by the first. // More precisely, it is the call to `len` that is the culprit, // because that creates a shared reference to the header, which *can* - // overlap with the keys. + // overlap with the keys (and even the values, for ZST keys). unsafe { let len = self.len(); let leaf = self.as_leaf_mut(); From 9312ca10b6cd672c4fa1da4b4a3cc232f7d7dde6 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 17 Feb 2019 23:55:45 -0800 Subject: [PATCH 13/28] Add a note about 2018e if someone uses `try {` in 2015e --- src/librustc_resolve/error_reporting.rs | 4 ++++ src/test/ui/try-block/try-block-in-edition2015.stderr | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/librustc_resolve/error_reporting.rs b/src/librustc_resolve/error_reporting.rs index 8300e691bbea4..fe9ae8b83007e 100644 --- a/src/librustc_resolve/error_reporting.rs +++ b/src/librustc_resolve/error_reporting.rs @@ -251,6 +251,10 @@ impl<'a> Resolver<'a> { format!("{}!", path_str), Applicability::MaybeIncorrect, ); + if path_str == "try" && span.rust_2015() { + err.note("if you want the `try` keyword, \ + you need to be in the 2018 edition"); + } } (Def::TyAlias(..), PathSource::Trait(_)) => { err.span_label(span, "type aliases cannot be used as traits"); diff --git a/src/test/ui/try-block/try-block-in-edition2015.stderr b/src/test/ui/try-block/try-block-in-edition2015.stderr index a7b81060d3dc6..7394fec6f3660 100644 --- a/src/test/ui/try-block/try-block-in-edition2015.stderr +++ b/src/test/ui/try-block/try-block-in-edition2015.stderr @@ -16,6 +16,8 @@ error[E0574]: expected struct, variant or union type, found macro `try` | LL | let try_result: Option<_> = try { | ^^^ help: use `!` to invoke the macro: `try!` + | + = note: if you want the `try` keyword, you need to be in the 2018 edition error: aborting due to 2 previous errors From 64c915e3ade66d3335c445eed89509dc41502c13 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Sat, 2 Feb 2019 01:29:39 +0100 Subject: [PATCH 14/28] override `VecDeque::try_rfold`, also update iterator This keeps the slice based iteration and updates the iterator state after each slice. It also uses a loop to reduce the amount of code. This uses unsafe code, so some thorough review would be appreciated. --- src/liballoc/benches/vec_deque.rs | 7 +++ src/liballoc/collections/vec_deque.rs | 51 ++++++++++++++++++--- src/liballoc/tests/vec_deque.rs | 64 +++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 5 deletions(-) diff --git a/src/liballoc/benches/vec_deque.rs b/src/liballoc/benches/vec_deque.rs index f7aadbdbd8266..7d2d3cfa61225 100644 --- a/src/liballoc/benches/vec_deque.rs +++ b/src/liballoc/benches/vec_deque.rs @@ -45,3 +45,10 @@ fn bench_mut_iter_1000(b: &mut Bencher) { black_box(sum); }) } + +#[bench] +fn bench_try_fold(b: &mut Bencher) { + let ring: VecDeque<_> = (0..1000).collect(); + + b.iter(|| black_box(ring.iter().try_fold(0, |a, b| Some(a + b)))) +} diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 99fa54acb0836..3d91fd3daab86 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -2170,12 +2170,29 @@ impl<'a, T> Iterator for Iter<'a, T> { back.iter().fold(accum, &mut f) } - fn try_fold(&mut self, init: B, mut f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try + fn try_fold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, { - let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); - let accum = front.iter().try_fold(init, &mut f)?; - back.iter().try_fold(accum, &mut f) + let (mut iter, final_res); + if self.tail <= self.head { + // single slice self.ring[self.tail..self.head] + iter = self.ring[self.tail..self.head].iter(); + final_res = iter.try_fold(init, &mut f); + } else { + // two slices: self.ring[self.tail..], self.ring[..self.head] + let (front, back) = self.ring.split_at(self.tail); + let mut back_iter = back.iter(); + let res = back_iter.try_fold(init, &mut f); + let len = self.ring.len(); + self.tail = (self.ring.len() - back_iter.len()) & (len - 1); + iter = front[..self.head].iter(); + final_res = iter.try_fold(res?, &mut f); + } + self.tail = self.head - iter.len(); + final_res } } @@ -2197,6 +2214,30 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { accum = back.iter().rfold(accum, &mut f); front.iter().rfold(accum, &mut f) } + + fn try_rfold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + let (mut iter, final_res); + if self.tail <= self.head { + // single slice self.ring[self.tail..self.head] + iter = self.ring[self.tail..self.head].iter(); + final_res = iter.try_rfold(init, &mut f); + } else { + // two slices: self.ring[self.tail..], self.ring[..self.head] + let (front, back) = self.ring.split_at(self.tail); + let mut front_iter = front[..self.head].iter(); + let res = front_iter.try_rfold(init, &mut f); + self.head = front_iter.len(); + iter = back.iter(); + final_res = iter.try_rfold(res?, &mut f); + } + self.head = self.tail + iter.len(); + final_res + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index aa49bdb009086..f801e42006bbb 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -1459,6 +1459,15 @@ fn test_try_fold_unit() { assert_eq!(Some(()), v.into_iter().try_fold((), |(), ()| Some(()))); } + +#[test] +fn test_try_fold_unit_none() { + let v: std::collections::VecDeque<()> = [(); 10].iter().cloned().collect(); + let mut iter = v.into_iter(); + assert!(iter.try_fold((), |_, _| None).is_none()); + assert_eq!(iter.len(), 9); +} + #[test] fn test_try_fold_rotated() { let mut v: VecDeque<_> = (0..12).collect(); @@ -1471,3 +1480,58 @@ fn test_try_fold_rotated() { assert_eq!(Ok::<_, ()>(66), v.iter().try_fold(0, |a, b| Ok(a + b))); } } + +#[test] +fn test_try_fold_moves_iter() { + let v: VecDeque<_> = [10, 20, 30, 40, 100, 60, 70, 80, 90].iter().collect(); + let mut iter = v.into_iter(); + assert_eq!(iter.try_fold(0_i8, |acc, &x| acc.checked_add(x)), None); + assert_eq!(iter.next(), Some(&60)); +} + +#[test] +fn test_try_fold_exhaust_wrap() { + let mut v = VecDeque::with_capacity(7); + v.push_back(1); + v.push_back(1); + v.push_back(1); + v.pop_front(); + v.pop_front(); + let mut iter = v.iter(); + let _ = iter.try_fold(0, |_, _| Some(1)); + assert!(iter.is_empty()); +} + +#[test] +fn test_try_fold_wraparound() { + let mut v = VecDeque::with_capacity(8); + v.push_back(7); + v.push_back(8); + v.push_back(9); + v.push_front(2); + v.push_front(1); + let mut iter = v.iter(); + let _ = iter.find(|&&x| x == 2); + assert_eq!(Some(&7), iter.next()); +} + +#[test] +fn test_try_rfold_rotated() { + let mut v: VecDeque<_> = (0..12).collect(); + for n in 0..10 { + if n & 1 == 0 { + v.rotate_left(n); + } else { + v.rotate_right(n); + } + assert_eq!(Ok::<_, ()>(66), v.iter().try_rfold(0, |a, b| Ok(a + b))); + } +} + +#[test] +fn test_try_rfold_moves_iter() { + let v : VecDeque<_> = [10, 20, 30, 40, 100, 60, 70, 80, 90].iter().collect(); + let mut iter = v.into_iter(); + assert_eq!(iter.try_rfold(0_i8, |acc, &x| acc.checked_add(x)), None); + assert_eq!(iter.next_back(), Some(&70)); +} From abb07c42ecd364940c16ecd740116b847d7bcffc Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 20 Feb 2019 09:49:52 +0300 Subject: [PATCH 15/28] remove a bit of dead code --- src/libsyntax/ext/build.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 48f6e4c0c8203..27b0cfb163077 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -9,12 +9,6 @@ use crate::ThinVec; use rustc_target::spec::abi::Abi; use syntax_pos::{Pos, Span, DUMMY_SP}; -// Transitional re-exports so qquote can find the paths it is looking for -mod syntax { - pub use crate::ext; - pub use crate::parse; -} - pub trait AstBuilder { // paths fn path(&self, span: Span, strs: Vec ) -> ast::Path; From 65622e319e21d95bb7275109aecacb8e2526ce04 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 20 Feb 2019 10:10:11 +0300 Subject: [PATCH 16/28] cleanup macro after 2018 transition We can now use `?` --- src/libsyntax/ext/expand.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index d398437d7affc..f50663f97853f 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -36,10 +36,8 @@ macro_rules! ast_fragments { ( $($Kind:ident($AstTy:ty) { $kind_name:expr; - // FIXME: HACK: this should be `$(one ...)?` and `$(many ...)?` but `?` macro - // repetition was removed from 2015 edition in #51587 because of ambiguities. - $(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)* - $(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident;)* + $(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)? + $(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident;)? fn $make_ast:ident; })* ) => { From ad096d1a0e82ecb1174d92ea08eb223d7dc0117a Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 20 Feb 2019 10:17:23 +0000 Subject: [PATCH 17/28] Dedup a rustdoc diagnostic construction --- .../passes/collect_intra_doc_links.rs | 30 +++++-------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 62b79646f6b08..7f7fffbba100e 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -458,26 +458,18 @@ fn resolution_failure( link_range: Option>, ) { let sp = span_of_attrs(attrs); - let msg = format!("`[{}]` cannot be resolved, ignoring it...", path_str); - let mut diag = if let Some(link_range) = link_range { + let mut diag = cx.tcx.struct_span_lint_node( + lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, + NodeId::from_u32(0), + sp, + &format!("`[{}]` cannot be resolved, ignoring it...", path_str), + ); + if let Some(link_range) = link_range { if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs) { - let mut diag = cx.tcx.struct_span_lint_node( - lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, - NodeId::from_u32(0), - sp, - &msg, - ); + diag.set_span(sp); diag.span_label(sp, "cannot be resolved, ignoring"); - diag } else { - let mut diag = cx.tcx.struct_span_lint_node( - lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, - NodeId::from_u32(0), - sp, - &msg, - ); - // blah blah blah\nblah\nblah [blah] blah blah\nblah blah // ^ ~~~~ // | link_range @@ -494,13 +486,7 @@ fn resolution_failure( before=link_range.start - last_new_line_offset, found=link_range.len(), )); - diag } - } else { - cx.tcx.struct_span_lint_node(lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, - NodeId::from_u32(0), - sp, - &msg) }; diag.help("to escape `[` and `]` characters, just add '\\' before them like \ `\\[` or `\\]`"); From 8cf3605c50978a80668d834d8262b316edba60f0 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 20 Feb 2019 17:59:17 +0100 Subject: [PATCH 18/28] fix typo --- src/doc/rustdoc/src/documentation-tests.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md index 242167aa91786..c9acd3c307b54 100644 --- a/src/doc/rustdoc/src/documentation-tests.md +++ b/src/doc/rustdoc/src/documentation-tests.md @@ -244,7 +244,7 @@ disambiguate the error type: /// use std::io; /// let mut input = String::new(); /// io::stdin().read_line(&mut input)?; -/// # Ok::<(), io:Error>(()) +/// # Ok::<(), io::Error>(()) /// ``` ``` From 103ed0c347062967b8b5fe76a02f945da14aac72 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 20 Feb 2019 18:08:21 +0100 Subject: [PATCH 19/28] Search for target_triple.json only if builtin target not found Before this commit, if the builtin target was found, but an error happened when instantiating it (e.g. validating the target specification file failed, etc.), then we ignored those errors and proceeded to try to find a `target_triple.json` file, and if that failed, reported that as an error. With this commit, if rustc is supposed to provide the builtin target, and something fails while instantiating it, that error will get properly propagated. --- src/librustc_target/spec/mod.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 7cbf24402d742..bef2afc7b6292 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -259,6 +259,11 @@ impl ToJson for MergeFunctions { } } +pub enum LoadTargetError { + BuiltinTargetNotFound(String), + Other(String), +} + pub type LinkArgs = BTreeMap>; pub type TargetResult = Result; @@ -269,21 +274,24 @@ macro_rules! supported_targets { /// List of supported targets const TARGETS: &[&str] = &[$($triple),*]; - fn load_specific(target: &str) -> TargetResult { + fn load_specific(target: &str) -> Result { match target { $( $triple => { - let mut t = $module::target()?; + let mut t = $module::target() + .map_err(LoadTargetError::Other)?; t.options.is_builtin = true; // round-trip through the JSON parser to ensure at // run-time that the parser works correctly - t = Target::from_json(t.to_json())?; + t = Target::from_json(t.to_json()) + .map_err(LoadTargetError::Other)?; debug!("Got builtin target: {:?}", t); Ok(t) }, )+ - _ => Err(format!("Unable to find target: {}", target)) + _ => Err(LoadTargetError::BuiltinTargetNotFound( + format!("Unable to find target: {}", target))) } } @@ -1176,8 +1184,10 @@ impl Target { match *target_triple { TargetTriple::TargetTriple(ref target_triple) => { // check if triple is in list of supported targets - if let Ok(t) = load_specific(target_triple) { - return Ok(t) + match load_specific(target_triple) { + Ok(t) => return Ok(t), + Err(LoadTargetError::BuiltinTargetNotFound(_)) => (), + Err(LoadTargetError::Other(e)) => return Err(e), } // search for a file named `target_triple`.json in RUST_TARGET_PATH From b2a02c8d4aeb74fd6adc23e5eec935fc064e153a Mon Sep 17 00:00:00 2001 From: Alex Gurganus Date: Wed, 20 Feb 2019 13:03:52 -0600 Subject: [PATCH 20/28] Fixes #58586: Make E0505 explain example fail for 2018 edition --- src/librustc_mir/diagnostics.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 4df3004a9ada6..1aac78d8adca9 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -1545,6 +1545,8 @@ Erroneous code example: ```compile_fail,E0505 struct Value {} +fn borrow(val: &Value) {} + fn eat(val: Value) {} fn main() { @@ -1552,13 +1554,15 @@ fn main() { { let _ref_to_val: &Value = &x; eat(x); + borrow(_ref_to_val); } } ``` -Here, the function `eat` takes the ownership of `x`. However, -`x` cannot be moved because it was borrowed to `_ref_to_val`. -To fix that you can do few different things: +Here, the function `eat` takes ownership of `x`. However, +`x` cannot be moved because the borrow to `_ref_to_val` +needs to last till the function `borrow`. +To fix that you can do a few different things: * Try to avoid moving the variable. * Release borrow before move. @@ -1569,6 +1573,8 @@ Examples: ``` struct Value {} +fn borrow(val: &Value) {} + fn eat(val: &Value) {} fn main() { @@ -1576,6 +1582,7 @@ fn main() { { let _ref_to_val: &Value = &x; eat(&x); // pass by reference, if it's possible + borrow(_ref_to_val); } } ``` @@ -1585,12 +1592,15 @@ Or: ``` struct Value {} +fn borrow(val: &Value) {} + fn eat(val: Value) {} fn main() { let x = Value{}; { let _ref_to_val: &Value = &x; + borrow(_ref_to_val); } eat(x); // release borrow and then move it. } @@ -1602,6 +1612,8 @@ Or: #[derive(Clone, Copy)] // implement Copy trait struct Value {} +fn borrow(val: &Value) {} + fn eat(val: Value) {} fn main() { @@ -1609,6 +1621,7 @@ fn main() { { let _ref_to_val: &Value = &x; eat(x); // it will be copied here. + borrow(_ref_to_val); } } ``` From 102436d16a5e3d46fbd05afc7607e1a4b0209c8f Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Wed, 20 Feb 2019 21:59:13 +0100 Subject: [PATCH 21/28] Put Future trait into spotlight --- src/libcore/future/future.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs index 84e7147153e9e..a143b54a61f54 100644 --- a/src/libcore/future/future.rs +++ b/src/libcore/future/future.rs @@ -24,6 +24,7 @@ use task::{Poll, Waker}; /// /// When using a future, you generally won't call `poll` directly, but instead /// `await!` the value. +#[doc(spotlight)] #[must_use = "futures do nothing unless polled"] pub trait Future { /// The type of value produced on completion. From 6a5abea7092cf7ede5bb6b3489db94eb701cd04e Mon Sep 17 00:00:00 2001 From: Alex Gurganus Date: Wed, 20 Feb 2019 16:12:28 -0600 Subject: [PATCH 22/28] Remove braces from most E0505 examples The solution which uses braces to release the borrow before it is moved is only required to satisfy the 2015 edition borrow checker. All other examples give the expected results for both 2015 and 2018 editions. --- src/librustc_mir/diagnostics.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 1aac78d8adca9..f369324157a9e 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -1551,11 +1551,9 @@ fn eat(val: Value) {} fn main() { let x = Value{}; - { - let _ref_to_val: &Value = &x; - eat(x); - borrow(_ref_to_val); - } + let _ref_to_val: &Value = &x; + eat(x); + borrow(_ref_to_val); } ``` @@ -1579,11 +1577,9 @@ fn eat(val: &Value) {} fn main() { let x = Value{}; - { - let _ref_to_val: &Value = &x; - eat(&x); // pass by reference, if it's possible - borrow(_ref_to_val); - } + let _ref_to_val: &Value = &x; + eat(&x); // pass by reference, if it's possible + borrow(_ref_to_val); } ``` @@ -1618,11 +1614,9 @@ fn eat(val: Value) {} fn main() { let x = Value{}; - { - let _ref_to_val: &Value = &x; - eat(x); // it will be copied here. - borrow(_ref_to_val); - } + let _ref_to_val: &Value = &x; + eat(x); // it will be copied here. + borrow(_ref_to_val); } ``` From 0f6d36375f76f31a5252b8b8ab5faaafb374e721 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Feb 2019 13:15:59 +0100 Subject: [PATCH 23/28] explain why we use static alignment in ref-to-place conversion --- src/librustc_mir/interpret/place.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index b29e09900f6b1..637f1dcc4a4da 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -326,6 +326,10 @@ where let mplace = MemPlace { ptr: val.to_scalar_ptr()?, + // We could use the run-time alignment here. For now, we do not, because + // the point of tracking the alignment here is to make sure that the *static* + // alignment information emitted with the loads is correct. The run-time + // alignment can only be more restrictive. align: layout.align.abi, meta: val.to_meta()?, }; From b01f81be7445ca83a8a9fd51937e3047c22eea09 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Feb 2019 16:14:31 +0100 Subject: [PATCH 24/28] remark about the one place where place computation calls size_and_align_of --- src/librustc_mir/interpret/place.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 637f1dcc4a4da..ec701a939f225 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -389,9 +389,11 @@ where // above). In that case, all fields are equal. let field_layout = base.layout.field(self, usize::try_from(field).unwrap_or(0))?; - // Offset may need adjustment for unsized fields + // Offset may need adjustment for unsized fields. let (meta, offset) = if field_layout.is_unsized() { - // re-use parent metadata to determine dynamic field layout + // Re-use parent metadata to determine dynamic field layout. + // With custom DSTS, this *will* execute user-defined code, but the same + // happens at run-time so that's okay. let align = match self.size_and_align_of(base.meta, field_layout)? { Some((_, align)) => align, None if offset == Size::ZERO => From 09a24545a848f0d89bb6464c2af730095b816618 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Thu, 21 Feb 2019 17:26:10 +0100 Subject: [PATCH 25/28] introduce benchmarks of BTreeSet.intersection --- src/liballoc/benches/btree/mod.rs | 1 + src/liballoc/benches/btree/set.rs | 88 +++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 src/liballoc/benches/btree/set.rs diff --git a/src/liballoc/benches/btree/mod.rs b/src/liballoc/benches/btree/mod.rs index 4dc2dfd9153e7..095ca5dd2e21b 100644 --- a/src/liballoc/benches/btree/mod.rs +++ b/src/liballoc/benches/btree/mod.rs @@ -1 +1,2 @@ mod map; +mod set; diff --git a/src/liballoc/benches/btree/set.rs b/src/liballoc/benches/btree/set.rs new file mode 100644 index 0000000000000..08e1db5fbb74d --- /dev/null +++ b/src/liballoc/benches/btree/set.rs @@ -0,0 +1,88 @@ +use std::collections::BTreeSet; + +use rand::{thread_rng, Rng}; +use test::{black_box, Bencher}; + +fn random(n1: u32, n2: u32) -> [BTreeSet; 2] { + let mut rng = thread_rng(); + let mut set1 = BTreeSet::new(); + let mut set2 = BTreeSet::new(); + for _ in 0..n1 { + let i = rng.gen::(); + set1.insert(i); + } + for _ in 0..n2 { + let i = rng.gen::(); + set2.insert(i); + } + [set1, set2] +} + +fn staggered(n1: u32, n2: u32) -> [BTreeSet; 2] { + let mut even = BTreeSet::new(); + let mut odd = BTreeSet::new(); + for i in 0..n1 { + even.insert(i * 2); + } + for i in 0..n2 { + odd.insert(i * 2 + 1); + } + [even, odd] +} + +fn neg_vs_pos(n1: u32, n2: u32) -> [BTreeSet; 2] { + let mut neg = BTreeSet::new(); + let mut pos = BTreeSet::new(); + for i in -(n1 as i32)..=-1 { + neg.insert(i); + } + for i in 1..=(n2 as i32) { + pos.insert(i); + } + [neg, pos] +} + +fn pos_vs_neg(n1: u32, n2: u32) -> [BTreeSet; 2] { + let mut neg = BTreeSet::new(); + let mut pos = BTreeSet::new(); + for i in -(n1 as i32)..=-1 { + neg.insert(i); + } + for i in 1..=(n2 as i32) { + pos.insert(i); + } + [pos, neg] +} + +macro_rules! set_intersection_bench { + ($name: ident, $sets: expr) => { + #[bench] + pub fn $name(b: &mut Bencher) { + // setup + let sets = $sets; + + // measure + b.iter(|| { + let x = sets[0].intersection(&sets[1]).count(); + black_box(x); + }) + } + }; +} + +set_intersection_bench! {intersect_random_100, random(100, 100)} +set_intersection_bench! {intersect_random_10k, random(10_000, 10_000)} +set_intersection_bench! {intersect_random_10_vs_10k, random(10, 10_000)} +set_intersection_bench! {intersect_random_10k_vs_10, random(10_000, 10)} +set_intersection_bench! {intersect_staggered_100, staggered(100, 100)} +set_intersection_bench! {intersect_staggered_10k, staggered(10_000, 10_000)} +set_intersection_bench! {intersect_staggered_10_vs_10k, staggered(10, 10_000)} +set_intersection_bench! {intersect_staggered_10k_vs_10, staggered(10_000, 10)} +set_intersection_bench! {intersect_neg_vs_pos_100, neg_vs_pos(100, 100)} +set_intersection_bench! {intersect_neg_vs_pos_10k, neg_vs_pos(10_000, 10_000)} +set_intersection_bench! {intersect_neg_vs_pos_10_vs_10k,neg_vs_pos(10, 10_000)} +set_intersection_bench! {intersect_neg_vs_pos_10k_vs_10,neg_vs_pos(10_000, 10)} +set_intersection_bench! {intersect_pos_vs_neg_100, pos_vs_neg(100, 100)} +set_intersection_bench! {intersect_pos_vs_neg_10k, pos_vs_neg(10_000, 10_000)} +set_intersection_bench! {intersect_pos_vs_neg_10_vs_10k,pos_vs_neg(10, 10_000)} +set_intersection_bench! {intersect_pos_vs_neg_10k_vs_10,pos_vs_neg(10_000, 10)} From 4867a8c4fa1d5da99e9e6e61b86b4ce85e0572d0 Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Thu, 21 Feb 2019 19:26:45 +0100 Subject: [PATCH 26/28] Update miri links Miri has been moved to `rust-lang` a couple of days ago. --- CONTRIBUTING.md | 2 +- src/tools/publish_toolstate.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9924055ca45ea..54344f688f99f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -162,7 +162,7 @@ it can be found [here][rctd]. Currently building Rust will also build the following external projects: * [clippy](https://github.com/rust-lang-nursery/rust-clippy) -* [miri](https://github.com/solson/miri) +* [miri](https://github.com/rust-lang/miri) * [rustfmt](https://github.com/rust-lang-nursery/rustfmt) * [rls](https://github.com/rust-lang-nursery/rls/) diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index abcf14d90be15..fb6132a5358ef 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -25,7 +25,7 @@ } REPOS = { - 'miri': 'https://github.com/solson/miri', + 'miri': 'https://github.com/rust-lang/miri', 'clippy-driver': 'https://github.com/rust-lang/rust-clippy', 'rls': 'https://github.com/rust-lang/rls', 'rustfmt': 'https://github.com/rust-lang/rustfmt', From 36f665239d123a2be71c2968995f8c30b95c8c9c Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Thu, 21 Feb 2019 20:58:56 +0100 Subject: [PATCH 27/28] Fix more nursery links in CONTRIBUTING.md --- CONTRIBUTING.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 54344f688f99f..e785f03d7de2b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -161,10 +161,10 @@ it can be found [here][rctd]. Currently building Rust will also build the following external projects: -* [clippy](https://github.com/rust-lang-nursery/rust-clippy) +* [clippy](https://github.com/rust-lang/rust-clippy) * [miri](https://github.com/rust-lang/miri) -* [rustfmt](https://github.com/rust-lang-nursery/rustfmt) -* [rls](https://github.com/rust-lang-nursery/rls/) +* [rustfmt](https://github.com/rust-lang/rustfmt) +* [rls](https://github.com/rust-lang/rls/) We allow breakage of these tools in the nightly channel. Maintainers of these projects will be notified of the breakages and should fix them as soon as @@ -191,9 +191,9 @@ before the PR is merged. Rust's build system builds a number of tools that make use of the internals of the compiler. This includes -[Clippy](https://github.com/rust-lang-nursery/rust-clippy), -[RLS](https://github.com/rust-lang-nursery/rls) and -[rustfmt](https://github.com/rust-lang-nursery/rustfmt). If these tools +[Clippy](https://github.com/rust-lang/rust-clippy), +[RLS](https://github.com/rust-lang/rls) and +[rustfmt](https://github.com/rust-lang/rustfmt). If these tools break because of your changes, you may run into a sort of "chicken and egg" problem. These tools rely on the latest compiler to be built so you can't update them to reflect your changes to the compiler until those changes are merged into @@ -253,10 +253,10 @@ to complete a few more steps which are outlined with their rationale below. *(This error may change in the future to include more information.)* ``` -error: failed to resolve patches for `https://github.com/rust-lang-nursery/rustfmt` +error: failed to resolve patches for `https://github.com/rust-lang/rustfmt` Caused by: - patch for `rustfmt-nightly` in `https://github.com/rust-lang-nursery/rustfmt` did not resolve to any crates + patch for `rustfmt-nightly` in `https://github.com/rust-lang/rustfmt` did not resolve to any crates failed to run: ~/rust/build/x86_64-unknown-linux-gnu/stage0/bin/cargo build --manifest-path ~/rust/src/bootstrap/Cargo.toml ``` From 88d55f537ddf6630aafb2e7755ebd9831b8031c0 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 22 Feb 2019 11:04:10 +0300 Subject: [PATCH 28/28] Make std feature list sorted This helps to avoid merge conflicts when concurrent PRs append features to the end of the list. --- src/libstd/lib.rs | 49 +++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index f849daf207967..6dd3a6cc0fdbd 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -215,16 +215,22 @@ // std may use features in a platform-specific way #![allow(unused_features)] +#![cfg_attr(test, feature(test, update_panic_count))] +#![cfg_attr(all(target_vendor = "fortanix", target_env = "sgx"), + feature(global_asm, range_contains, slice_index_methods, + decl_macro, coerce_unsized, sgx_platform, ptr_wrapping_offset_from))] + // std is implemented with unstable features, many of which are internal // compiler details that will never be stable -#![cfg_attr(test, feature(test, update_panic_count))] -#![feature(alloc)] +// NB: the following list is sorted to minimize merge conflicts. +#![feature(align_offset)] #![feature(alloc_error_handler)] +#![feature(alloc_layout_extra)] +#![feature(alloc)] #![feature(allocator_api)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] -#![feature(align_offset)] #![feature(arbitrary_self_types)] #![feature(array_error_internals)] #![feature(asm)] @@ -233,20 +239,28 @@ #![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] #![feature(char_error_internals)] +#![feature(checked_duration_since)] #![feature(compiler_builtins_lib)] #![feature(concat_idents)] -#![feature(const_raw_ptr_deref)] #![feature(const_cstr_unchecked)] +#![feature(const_raw_ptr_deref)] #![feature(core_intrinsics)] +#![feature(doc_alias)] +#![feature(doc_cfg)] +#![feature(doc_keyword)] +#![feature(doc_masked)] +#![feature(doc_spotlight)] #![feature(dropck_eyepatch)] #![feature(duration_constants)] #![feature(exact_size_is_empty)] +#![feature(exhaustive_patterns)] #![feature(external_doc)] #![feature(fixed_size_array)] #![feature(fn_traits)] #![feature(fnbox)] #![feature(futures_api)] #![feature(generator_trait)] +#![feature(hash_raw_entry)] #![feature(hashmap_internals)] #![feature(int_error_internals)] #![feature(integer_atomics)] @@ -254,31 +268,32 @@ #![feature(libc)] #![feature(link_args)] #![feature(linkage)] +#![feature(maybe_uninit)] #![feature(needs_panic_runtime)] #![feature(never_type)] #![feature(nll)] -#![feature(exhaustive_patterns)] +#![feature(non_exhaustive)] #![feature(on_unimplemented)] #![feature(optin_builtin_traits)] +#![feature(panic_info_message)] #![feature(panic_internals)] #![feature(panic_unwind)] #![feature(prelude_import)] #![feature(ptr_internals)] #![feature(raw)] -#![feature(hash_raw_entry)] +#![feature(renamed_spin_loop)] #![feature(rustc_attrs)] #![feature(rustc_const_unstable)] -#![feature(std_internals)] -#![feature(stdsimd)] +#![feature(rustc_private)] #![feature(shrink_to)] #![feature(slice_concat_ext)] #![feature(slice_internals)] #![feature(slice_patterns)] #![feature(staged_api)] +#![feature(std_internals)] +#![feature(stdsimd)] #![feature(stmt_expr_attributes)] #![feature(str_internals)] -#![feature(renamed_spin_loop)] -#![feature(rustc_private)] #![feature(thread_local)] #![feature(toowned_clone_into)] #![feature(try_from)] @@ -286,19 +301,7 @@ #![feature(unboxed_closures)] #![feature(untagged_unions)] #![feature(unwind_attributes)] -#![feature(doc_cfg)] -#![feature(doc_masked)] -#![feature(doc_spotlight)] -#![feature(doc_alias)] -#![feature(doc_keyword)] -#![feature(panic_info_message)] -#![feature(non_exhaustive)] -#![feature(alloc_layout_extra)] -#![feature(maybe_uninit)] -#![feature(checked_duration_since)] -#![cfg_attr(all(target_vendor = "fortanix", target_env = "sgx"), - feature(global_asm, range_contains, slice_index_methods, - decl_macro, coerce_unsized, sgx_platform, ptr_wrapping_offset_from))] +// NB: the above list is sorted to minimize merge conflicts. #![default_lib_allocator]