diff options
| author | bors <bors@rust-lang.org> | 2019-02-22 21:32:15 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-02-22 21:32:15 +0000 |
| commit | 082c86175fcf72c355e6a889956fbea59e65bcdb (patch) | |
| tree | 1b8297e021423bd2069bb1654985bf52602e9ef1 /src | |
| parent | e1c6d00574494499f63c1e460ef886768643e7db (diff) | |
| parent | a8a343a78706a1d90ebd451046b76d176bab937d (diff) | |
| download | rust-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')
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', |
