about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-02-22 21:32:15 +0000
committerbors <bors@rust-lang.org>2019-02-22 21:32:15 +0000
commit082c86175fcf72c355e6a889956fbea59e65bcdb (patch)
tree1b8297e021423bd2069bb1654985bf52602e9ef1 /src
parente1c6d00574494499f63c1e460ef886768643e7db (diff)
parenta8a343a78706a1d90ebd451046b76d176bab937d (diff)
downloadrust-082c86175fcf72c355e6a889956fbea59e65bcdb.tar.gz
rust-082c86175fcf72c355e6a889956fbea59e65bcdb.zip
Auto merge of #58644 - Centril:rollup, r=Centril
Rollup of 17 pull requests

Successful merges:

 - #57656 (Deprecate the unstable Vec::resize_default)
 - #58059 (deprecate before_exec in favor of unsafe pre_exec)
 - #58064 (override `VecDeque::try_rfold`, also update iterator)
 - #58198 (Suggest removing parentheses surrounding lifetimes)
 - #58431 (fix overlapping references in BTree)
 - #58555 (Add a note about 2018e if someone uses `try {` in 2015e)
 - #58588 (remove a bit of dead code)
 - #58589 (cleanup macro after 2018 transition)
 - #58591 (Dedup a rustdoc diagnostic construction)
 - #58600 (fix small documentation typo)
 - #58601 (Search for target_triple.json only if builtin target not found)
 - #58606 (Docs: put Future trait into spotlight)
 - #58607 (Fixes #58586: Make E0505 erronous example fail for the 2018 edition)
 - #58615 (miri: explain why we use static alignment in ref-to-place conversion)
 - #58620 (introduce benchmarks of BTreeSet.intersection)
 - #58621 (Update miri links)
 - #58632 (Make std feature list sorted)

Failed merges:

r? @ghost
Diffstat (limited to 'src')
-rw-r--r--src/doc/rustdoc/src/documentation-tests.md2
-rw-r--r--src/liballoc/benches/btree/mod.rs1
-rw-r--r--src/liballoc/benches/btree/set.rs88
-rw-r--r--src/liballoc/benches/vec_deque.rs7
-rw-r--r--src/liballoc/collections/btree/map.rs32
-rw-r--r--src/liballoc/collections/btree/node.rs25
-rw-r--r--src/liballoc/collections/vec_deque.rs51
-rw-r--r--src/liballoc/tests/vec_deque.rs64
-rw-r--r--src/liballoc/vec.rs4
-rw-r--r--src/libcore/future/future.rs1
-rw-r--r--src/librustc_mir/diagnostics.rs37
-rw-r--r--src/librustc_mir/interpret/place.rs10
-rw-r--r--src/librustc_resolve/error_reporting.rs4
-rw-r--r--src/librustc_target/spec/mod.rs22
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs30
-rw-r--r--src/libstd/lib.rs49
-rw-r--r--src/libstd/sys/redox/ext/process.rs28
-rw-r--r--src/libstd/sys/redox/process.rs6
-rw-r--r--src/libstd/sys/unix/ext/process.rs28
-rw-r--r--src/libstd/sys/unix/process/process_common.rs6
-rw-r--r--src/libsyntax/ext/build.rs6
-rw-r--r--src/libsyntax/ext/expand.rs6
-rw-r--r--src/libsyntax/parse/parser.rs17
-rw-r--r--src/test/run-pass/command-before-exec.rs83
-rw-r--r--src/test/run-pass/command-pre-exec.rs115
-rw-r--r--src/test/ui/parser/trait-object-lifetime-parens.stderr8
-rw-r--r--src/test/ui/try-block/try-block-in-edition2015.stderr2
-rwxr-xr-xsrc/tools/publish_toolstate.py2
28 files changed, 533 insertions, 201 deletions
diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md
index 242167aa917..c9acd3c307b 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>(())
 /// ```
 ```
 
diff --git a/src/liballoc/benches/btree/mod.rs b/src/liballoc/benches/btree/mod.rs
index 4dc2dfd9153..095ca5dd2e2 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 00000000000..08e1db5fbb7
--- /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<usize>; 2] {
+    let mut rng = thread_rng();
+    let mut set1 = BTreeSet::new();
+    let mut set2 = BTreeSet::new();
+    for _ in 0..n1 {
+        let i = rng.gen::<usize>();
+        set1.insert(i);
+    }
+    for _ in 0..n2 {
+        let i = rng.gen::<usize>();
+        set2.insert(i);
+    }
+    [set1, set2]
+}
+
+fn staggered(n1: u32, n2: u32) -> [BTreeSet<u32>; 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<i32>; 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<i32>; 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)}
diff --git a/src/liballoc/benches/vec_deque.rs b/src/liballoc/benches/vec_deque.rs
index f7aadbdbd82..7d2d3cfa612 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/btree/map.rs b/src/liballoc/collections/btree/map.rs
index 250927138b3..ce29978856f 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 fc1c1878924..66d619b1298 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<marker::Mut<'a>, 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::<K>() > mem::align_of::<LeafNode<(), ()>>() && self.is_shared_root() {
             &mut []
         } else {
@@ -667,9 +669,26 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, 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 (and even the values, for ZST 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)
+        }
     }
 }
 
diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs
index f778c4cbfde..4e90f783ec6 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<B, F, R>(&mut self, init: B, mut f: F) -> R where
-        Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
+    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Ok = B>,
     {
-        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<B, F, R>(&mut self, init: B, mut f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Ok = B>,
+    {
+        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 e0cb0e7a9e7..16ddc1444fc 100644
--- a/src/liballoc/tests/vec_deque.rs
+++ b/src/liballoc/tests/vec_deque.rs
@@ -1465,6 +1465,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();
@@ -1477,3 +1486,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));
+}
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index a351d482fed..dddfa3f158e 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -1365,6 +1365,7 @@ impl<T: Default> Vec<T> {
     /// # Examples
     ///
     /// ```
+    /// # #![allow(deprecated)]
     /// #![feature(vec_resize_default)]
     ///
     /// let mut vec = vec![1, 2, 3];
@@ -1381,6 +1382,9 @@ impl<T: Default> Vec<T> {
     /// [`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();
 
diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs
index 84e7147153e..a143b54a61f 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.
diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs
index 4df3004a9ad..f369324157a 100644
--- a/src/librustc_mir/diagnostics.rs
+++ b/src/librustc_mir/diagnostics.rs
@@ -1545,20 +1545,22 @@ Erroneous code example:
 ```compile_fail,E0505
 struct Value {}
 
+fn borrow(val: &Value) {}
+
 fn eat(val: Value) {}
 
 fn main() {
     let x = Value{};
-    {
-        let _ref_to_val: &Value = &x;
-        eat(x);
-    }
+    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,14 +1571,15 @@ Examples:
 ```
 struct Value {}
 
+fn borrow(val: &Value) {}
+
 fn eat(val: &Value) {}
 
 fn main() {
     let x = Value{};
-    {
-        let _ref_to_val: &Value = &x;
-        eat(&x); // pass by reference, if it's possible
-    }
+    let _ref_to_val: &Value = &x;
+    eat(&x); // pass by reference, if it's possible
+    borrow(_ref_to_val);
 }
 ```
 
@@ -1585,12 +1588,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,14 +1608,15 @@ Or:
 #[derive(Clone, Copy)] // implement Copy trait
 struct Value {}
 
+fn borrow(val: &Value) {}
+
 fn eat(val: Value) {}
 
 fn main() {
     let x = Value{};
-    {
-        let _ref_to_val: &Value = &x;
-        eat(x); // it will be copied here.
-    }
+    let _ref_to_val: &Value = &x;
+    eat(x); // it will be copied here.
+    borrow(_ref_to_val);
 }
 ```
 
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index b29e09900f6..ec701a939f2 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()?,
         };
@@ -385,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 =>
diff --git a/src/librustc_resolve/error_reporting.rs b/src/librustc_resolve/error_reporting.rs
index c8b3e2f4e4c..cd771d93e00 100644
--- a/src/librustc_resolve/error_reporting.rs
+++ b/src/librustc_resolve/error_reporting.rs
@@ -259,6 +259,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/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index 7cbf24402d7..bef2afc7b62 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<LinkerFlavor, Vec<String>>;
 pub type TargetResult = Result<Target, String>;
 
@@ -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<Target, LoadTargetError> {
             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
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 62b79646f6b..7f7fffbba10 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<Range<usize>>,
 ) {
     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 `\\]`");
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index f849daf2079..6dd3a6cc0fd 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]
 
diff --git a/src/libstd/sys/redox/ext/process.rs b/src/libstd/sys/redox/ext/process.rs
index 1dcc1169510..020075531dd 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<F>(&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 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")]
+    #[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")]
     fn before_exec<F>(&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<F>(&mut self, f: F) -> &mut process::Command
+    unsafe fn pre_exec<F>(&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 9e23c537f22..81af8eb553d 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 fn before_exec(&mut self,
-                       f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>) {
+    pub unsafe fn pre_exec(
+        &mut self,
+        f: Box<dyn FnMut() -> 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 2c5943fdac3..b487bb889ba 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
@@ -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<F>(&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 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")]
+    #[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")]
     fn before_exec<F>(&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<F>(&mut self, f: F) -> &mut process::Command
+    unsafe fn pre_exec<F>(&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 2c55813c5cd..7fa256e59b2 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 fn before_exec(&mut self,
-                       f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>) {
+    pub unsafe fn pre_exec(
+        &mut self,
+        f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>,
+    ) {
         self.closures.push(f);
     }
 
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 48f6e4c0c82..27b0cfb1630 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::Ident> ) -> ast::Path;
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index d398437d7af..f50663f9785 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;
         })*
     ) => {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index b1fb38d8eaf..e6a48912c48 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -5503,6 +5503,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 {
@@ -5511,9 +5512,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/run-pass/command-before-exec.rs b/src/test/run-pass/command-before-exec.rs
deleted file mode 100644
index 91d2636b2ae..00000000000
--- a/src/test/run-pass/command-before-exec.rs
+++ /dev/null
@@ -1,83 +0,0 @@
-#![allow(stable_features)]
-// ignore-windows - this is a unix-specific test
-// ignore-cloudabi no processes
-// ignore-emscripten no processes
-
-#![feature(process_exec, rustc_private)]
-
-extern crate libc;
-
-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};
-
-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(), "/"),
-            "empty" => {}
-            _ => panic!("unknown argument: {}", arg),
-        }
-        return
-    }
-
-    let me = env::current_exe().unwrap();
-
-    let output = Command::new(&me).arg("test1").before_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 = Command::new(&me).arg("test2").before_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 = Command::new(&me).arg("test3").before_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 = Command::new(&me).arg("bad").before_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 = Command::new(&me).arg("empty").before_exec(move || {
-        let child = unsafe { 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 = Command::new(&me).arg("empty").before_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());
-    assert_eq!(mem.load(Ordering::SeqCst), 0);
-}
diff --git a/src/test/run-pass/command-pre-exec.rs b/src/test/run-pass/command-pre-exec.rs
new file mode 100644
index 00000000000..21783fedd39
--- /dev/null
+++ b/src/test/run-pass/command-pre-exec.rs
@@ -0,0 +1,115 @@
+#![allow(stable_features)]
+// ignore-windows - this is a unix-specific test
+// ignore-cloudabi no processes
+// ignore-emscripten no processes
+#![feature(process_exec, rustc_private)]
+
+extern crate libc;
+
+use std::env;
+use std::io::Error;
+use std::os::unix::process::CommandExt;
+use std::process::Command;
+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(), "/"),
+            "empty" => {}
+            _ => panic!("unknown argument: {}", arg),
+        }
+        return;
+    }
+
+    let me = env::current_exe().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()
+    };
+    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()
+    };
+    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()
+    };
+    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()
+    };
+    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()
+    };
+    assert!(output.status.success());
+    assert!(output.stderr.is_empty());
+    assert!(output.stdout.is_empty());
+    assert_eq!(mem.load(Ordering::SeqCst), 0);
+}
diff --git a/src/test/ui/parser/trait-object-lifetime-parens.stderr b/src/test/ui/parser/trait-object-lifetime-parens.stderr
index a9b542ddcc4..94ca66aef72 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<Trait + ('a)>; //~ ERROR parenthesized lifetime bounds are not supported
-   |                           ^
+   |                        ^^^^ help: remove the parentheses
 
 error: expected type, found `'a`
   --> $DIR/trait-object-lifetime-parens.rs:9:17
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 a7b81060d3d..7394fec6f36 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
 
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index abcf14d90be..fb6132a5358 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -25,7 +25,7 @@ MAINTAINERS = {
 }
 
 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',