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
This commit is contained in:
commit
082c86175f
29 changed files with 544 additions and 212 deletions
|
@ -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)
|
||||
* [miri](https://github.com/solson/miri)
|
||||
* [rustfmt](https://github.com/rust-lang-nursery/rustfmt)
|
||||
* [rls](https://github.com/rust-lang-nursery/rls/)
|
||||
* [clippy](https://github.com/rust-lang/rust-clippy)
|
||||
* [miri](https://github.com/rust-lang/miri)
|
||||
* [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
|
||||
```
|
||||
|
||||
|
|
|
@ -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>(())
|
||||
/// ```
|
||||
```
|
||||
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
mod map;
|
||||
mod set;
|
||||
|
|
88
src/liballoc/benches/btree/set.rs
Normal file
88
src/liballoc/benches/btree/set.rs
Normal file
|
@ -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)}
|
|
@ -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))))
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -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 =>
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 `\\]`");
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -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,13 +45,33 @@ 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_exec", since = "1.15.0")]
|
||||
fn before_exec<F>(&mut self, f: F) -> &mut process::Command
|
||||
#[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
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,13 +45,33 @@ 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_exec", since = "1.15.0")]
|
||||
fn before_exec<F>(&mut self, f: F) -> &mut process::Command
|
||||
#[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
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
})*
|
||||
) => {
|
||||
|
|
|
@ -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()?;
|
||||
|
|
|
@ -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);
|
||||
}
|
115
src/test/run-pass/command-pre-exec.rs
Normal file
115
src/test/run-pass/command-pre-exec.rs
Normal file
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Add table
Reference in a new issue