Auto merge of #48203 - kennytm:rollup, r=kennytm
Rollup of 23 pull requests - Successful merges: #47784, #47806, #47846, #48005, #48033, #48065, #48087, #48114, #48126, #48130, #48133, #48151, #48154, #48156, #48162, #48163, #48165, #48167, #48181, #48186, #48195, #48035, #48210 - Failed merges:
This commit is contained in:
commit
1670a532dd
@ -56,7 +56,7 @@ matrix:
|
||||
NO_LLVM_ASSERTIONS=1
|
||||
NO_DEBUG_ASSERTIONS=1
|
||||
os: osx
|
||||
osx_image: xcode8.3
|
||||
osx_image: xcode9.2
|
||||
if: branch = auto
|
||||
|
||||
- env: >
|
||||
@ -70,7 +70,7 @@ matrix:
|
||||
NO_LLVM_ASSERTIONS=1
|
||||
NO_DEBUG_ASSERTIONS=1
|
||||
os: osx
|
||||
osx_image: xcode8.3
|
||||
osx_image: xcode9.2
|
||||
if: branch = auto
|
||||
|
||||
# OSX builders producing releases. These do not run the full test suite and
|
||||
|
@ -78,6 +78,7 @@ Compatibility Notes
|
||||
- [`column!()` macro is one-based instead of zero-based][46977]
|
||||
- [`fmt::Arguments` can no longer be shared across threads][45198]
|
||||
- [Access to `#[repr(packed)]` struct fields is now unsafe][44884]
|
||||
- [Cargo sets a different working directory for the compiler][cargo/4788]
|
||||
|
||||
[44884]: https://github.com/rust-lang/rust/pull/44884
|
||||
[45198]: https://github.com/rust-lang/rust/pull/45198
|
||||
@ -106,6 +107,7 @@ Compatibility Notes
|
||||
[47080]: https://github.com/rust-lang/rust/pull/47080
|
||||
[47084]: https://github.com/rust-lang/rust/pull/47084
|
||||
[cargo/4743]: https://github.com/rust-lang/cargo/pull/4743
|
||||
[cargo/4788]: https://github.com/rust-lang/cargo/pull/4788
|
||||
[cargo/4817]: https://github.com/rust-lang/cargo/pull/4817
|
||||
[`RefCell::replace`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.replace
|
||||
[`RefCell::swap`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.swap
|
||||
|
@ -157,6 +157,14 @@ impl Step for Llvm {
|
||||
.define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
|
||||
.define("LLVM_DEFAULT_TARGET_TRIPLE", target);
|
||||
|
||||
// By default, LLVM will automatically find OCaml and, if it finds it,
|
||||
// install the LLVM bindings in LLVM_OCAML_INSTALL_PATH, which defaults
|
||||
// to /usr/bin/ocaml.
|
||||
// This causes problem for non-root builds of Rust. Side-step the issue
|
||||
// by setting LLVM_OCAML_INSTALL_PATH to a relative path, so it installs
|
||||
// in the prefix.
|
||||
cfg.define("LLVM_OCAML_INSTALL_PATH",
|
||||
env::var_os("LLVM_OCAML_INSTALL_PATH").unwrap_or_else(|| "usr/lib/ocaml".into()));
|
||||
|
||||
// This setting makes the LLVM tools link to the dynamic LLVM library,
|
||||
// which saves both memory during parallel links and overall disk space
|
||||
|
@ -805,22 +805,7 @@ impl<T> Vec<T> {
|
||||
pub fn retain<F>(&mut self, mut f: F)
|
||||
where F: FnMut(&T) -> bool
|
||||
{
|
||||
let len = self.len();
|
||||
let mut del = 0;
|
||||
{
|
||||
let v = &mut **self;
|
||||
|
||||
for i in 0..len {
|
||||
if !f(&v[i]) {
|
||||
del += 1;
|
||||
} else if del > 0 {
|
||||
v.swap(i - del, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
if del > 0 {
|
||||
self.truncate(len - del);
|
||||
}
|
||||
self.drain_filter(|x| !f(x));
|
||||
}
|
||||
|
||||
/// Removes all but the first of consecutive elements in the vector that resolve to the same
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 345447948f7a51eca970fa036cefd613d54a4f79
|
||||
Subproject commit 266ea0740a5bdd262a38bbd88fb55fc3d2a7a96e
|
@ -333,6 +333,8 @@ pub use self::range::Step;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::sources::{Repeat, repeat};
|
||||
#[unstable(feature = "iterator_repeat_with", issue = "48169")]
|
||||
pub use self::sources::{RepeatWith, repeat_with};
|
||||
#[stable(feature = "iter_empty", since = "1.2.0")]
|
||||
pub use self::sources::{Empty, empty};
|
||||
#[stable(feature = "iter_once", since = "1.2.0")]
|
||||
|
@ -57,6 +57,12 @@ unsafe impl<A: Clone> TrustedLen for Repeat<A> {}
|
||||
///
|
||||
/// [`take`]: trait.Iterator.html#method.take
|
||||
///
|
||||
/// If the element type of the iterator you need does not implement `Clone`,
|
||||
/// or if you do not want to keep the repeated element in memory, you can
|
||||
/// instead use the [`repeat_with`] function.
|
||||
///
|
||||
/// [`repeat_with`]: fn.repeat_with.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
@ -99,6 +105,115 @@ pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {
|
||||
Repeat{element: elt}
|
||||
}
|
||||
|
||||
/// An iterator that repeats elements of type `A` endlessly by
|
||||
/// applying the provided closure `F: FnMut() -> A`.
|
||||
///
|
||||
/// This `struct` is created by the [`repeat_with`] function.
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`repeat_with`]: fn.repeat_with.html
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[unstable(feature = "iterator_repeat_with", issue = "48169")]
|
||||
pub struct RepeatWith<F> {
|
||||
repeater: F
|
||||
}
|
||||
|
||||
#[unstable(feature = "iterator_repeat_with", issue = "48169")]
|
||||
impl<A, F: FnMut() -> A> Iterator for RepeatWith<F> {
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> { Some((self.repeater)()) }
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) { (usize::MAX, None) }
|
||||
}
|
||||
|
||||
#[unstable(feature = "iterator_repeat_with", issue = "48169")]
|
||||
impl<A, F: FnMut() -> A> DoubleEndedIterator for RepeatWith<F> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<A> { self.next() }
|
||||
}
|
||||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl<A, F: FnMut() -> A> FusedIterator for RepeatWith<F> {}
|
||||
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl<A, F: FnMut() -> A> TrustedLen for RepeatWith<F> {}
|
||||
|
||||
/// Creates a new iterator that repeats elements of type `A` endlessly by
|
||||
/// applying the provided closure, the repeater, `F: FnMut() -> A`.
|
||||
///
|
||||
/// The `repeat_with()` function calls the repeater over and over and over and
|
||||
/// over and over and 🔁.
|
||||
///
|
||||
/// Infinite iterators like `repeat_with()` are often used with adapters like
|
||||
/// [`take`], in order to make them finite.
|
||||
///
|
||||
/// [`take`]: trait.Iterator.html#method.take
|
||||
///
|
||||
/// If the element type of the iterator you need implements `Clone`, and
|
||||
/// it is OK to keep the source element in memory, you should instead use
|
||||
/// the [`repeat`] function.
|
||||
///
|
||||
/// [`repeat`]: fn.repeat.html
|
||||
///
|
||||
/// An iterator produced by `repeat_with()` is a `DoubleEndedIterator`.
|
||||
/// It is important to not that reversing `repeat_with(f)` will produce
|
||||
/// the exact same sequence as the non-reversed iterator. In other words,
|
||||
/// `repeat_with(f).rev().collect::<Vec<_>>()` is equivalent to
|
||||
/// `repeat_with(f).collect::<Vec<_>>()`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iterator_repeat_with)]
|
||||
///
|
||||
/// use std::iter;
|
||||
///
|
||||
/// // let's assume we have some value of a type that is not `Clone`
|
||||
/// // or which don't want to have in memory just yet because it is expensive:
|
||||
/// #[derive(PartialEq, Debug)]
|
||||
/// struct Expensive;
|
||||
///
|
||||
/// // a particular value forever:
|
||||
/// let mut things = iter::repeat_with(|| Expensive);
|
||||
///
|
||||
/// assert_eq!(Some(Expensive), things.next());
|
||||
/// assert_eq!(Some(Expensive), things.next());
|
||||
/// assert_eq!(Some(Expensive), things.next());
|
||||
/// assert_eq!(Some(Expensive), things.next());
|
||||
/// assert_eq!(Some(Expensive), things.next());
|
||||
/// ```
|
||||
///
|
||||
/// Using mutation and going finite:
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(iterator_repeat_with)]
|
||||
///
|
||||
/// use std::iter;
|
||||
///
|
||||
/// // From the zeroth to the third power of two:
|
||||
/// let mut curr = 1;
|
||||
/// let mut pow2 = iter::repeat_with(|| { let tmp = curr; curr *= 2; tmp })
|
||||
/// .take(4);
|
||||
///
|
||||
/// assert_eq!(Some(1), pow2.next());
|
||||
/// assert_eq!(Some(2), pow2.next());
|
||||
/// assert_eq!(Some(4), pow2.next());
|
||||
/// assert_eq!(Some(8), pow2.next());
|
||||
///
|
||||
/// // ... and now we're done
|
||||
/// assert_eq!(None, pow2.next());
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "iterator_repeat_with", issue = "48169")]
|
||||
pub fn repeat_with<A, F: FnMut() -> A>(repeater: F) -> RepeatWith<F> {
|
||||
RepeatWith { repeater }
|
||||
}
|
||||
|
||||
/// An iterator that yields nothing.
|
||||
///
|
||||
/// This `struct` is created by the [`empty`] function. See its documentation for more.
|
||||
|
@ -706,7 +706,7 @@ pub trait ExactSizeIterator: Iterator {
|
||||
/// ```
|
||||
/// #![feature(exact_size_is_empty)]
|
||||
///
|
||||
/// let mut one_element = 0..1;
|
||||
/// let mut one_element = std::iter::once(0);
|
||||
/// assert!(!one_element.is_empty());
|
||||
///
|
||||
/// assert_eq!(one_element.next(), Some(0));
|
||||
|
@ -92,6 +92,7 @@
|
||||
#![feature(unwind_attributes)]
|
||||
#![feature(doc_spotlight)]
|
||||
#![feature(rustc_const_unstable)]
|
||||
#![feature(iterator_repeat_with)]
|
||||
|
||||
#[prelude_import]
|
||||
#[allow(unused)]
|
||||
|
@ -63,9 +63,13 @@ impl<T: ?Sized> !Send for *mut T { }
|
||||
/// struct BarUse(Bar<[i32]>); // OK
|
||||
/// ```
|
||||
///
|
||||
/// The one exception is the implicit `Self` type of a trait, which does not
|
||||
/// get an implicit `Sized` bound. This is because a `Sized` bound prevents
|
||||
/// the trait from being used to form a [trait object]:
|
||||
/// The one exception is the implicit `Self` type of a trait. A trait does not
|
||||
/// have an implicit `Sized` bound as this is incompatible with [trait object]s
|
||||
/// where, by definition, the trait needs to work with all possible implementors,
|
||||
/// and thus could be any size.
|
||||
///
|
||||
/// Although Rust will let you bind `Sized` to a trait, you won't
|
||||
/// be able to use it to form a trait object later:
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(unused_variables)]
|
||||
|
@ -2881,7 +2881,7 @@ pub enum FpCategory {
|
||||
issue = "32110")]
|
||||
pub trait Float: Sized {
|
||||
/// Type used by `to_bits` and `from_bits`.
|
||||
#[stable(feature = "core_float_bits", since = "1.24.0")]
|
||||
#[stable(feature = "core_float_bits", since = "1.25.0")]
|
||||
type Bits;
|
||||
|
||||
/// Returns `true` if this value is NaN and false otherwise.
|
||||
@ -2947,10 +2947,10 @@ pub trait Float: Sized {
|
||||
fn min(self, other: Self) -> Self;
|
||||
|
||||
/// Raw transmutation to integer.
|
||||
#[stable(feature = "core_float_bits", since="1.24.0")]
|
||||
#[stable(feature = "core_float_bits", since="1.25.0")]
|
||||
fn to_bits(self) -> Self::Bits;
|
||||
/// Raw transmutation from integer.
|
||||
#[stable(feature = "core_float_bits", since="1.24.0")]
|
||||
#[stable(feature = "core_float_bits", since="1.25.0")]
|
||||
fn from_bits(v: Self::Bits) -> Self;
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ impl fmt::Debug for RangeFull {
|
||||
/// (`start..end`).
|
||||
///
|
||||
/// The `Range` `start..end` contains all values with `x >= start` and
|
||||
/// `x < end`.
|
||||
/// `x < end`. It is empty unless `start < end`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -68,11 +68,11 @@ impl fmt::Debug for RangeFull {
|
||||
/// assert_eq!((3..5), std::ops::Range { start: 3, end: 5 });
|
||||
/// assert_eq!(3 + 4 + 5, (3..6).sum());
|
||||
///
|
||||
/// let arr = [0, 1, 2, 3];
|
||||
/// assert_eq!(arr[ .. ], [0,1,2,3]);
|
||||
/// assert_eq!(arr[ ..3], [0,1,2 ]);
|
||||
/// assert_eq!(arr[1.. ], [ 1,2,3]);
|
||||
/// assert_eq!(arr[1..3], [ 1,2 ]); // Range
|
||||
/// let arr = ['a', 'b', 'c', 'd'];
|
||||
/// assert_eq!(arr[ .. ], ['a', 'b', 'c', 'd']);
|
||||
/// assert_eq!(arr[ ..3], ['a', 'b', 'c', ]);
|
||||
/// assert_eq!(arr[1.. ], [ 'b', 'c', 'd']);
|
||||
/// assert_eq!(arr[1..3], [ 'b', 'c' ]); // Range
|
||||
/// ```
|
||||
#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -92,7 +92,6 @@ impl<Idx: fmt::Debug> fmt::Debug for Range<Idx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
|
||||
impl<Idx: PartialOrd<Idx>> Range<Idx> {
|
||||
/// Returns `true` if `item` is contained in the range.
|
||||
///
|
||||
@ -109,9 +108,37 @@ impl<Idx: PartialOrd<Idx>> Range<Idx> {
|
||||
/// assert!(!(3..3).contains(3));
|
||||
/// assert!(!(3..2).contains(3));
|
||||
/// ```
|
||||
#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
|
||||
pub fn contains(&self, item: Idx) -> bool {
|
||||
(self.start <= item) && (item < self.end)
|
||||
}
|
||||
|
||||
/// Returns `true` if the range contains no items.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(range_is_empty)]
|
||||
///
|
||||
/// assert!(!(3..5).is_empty());
|
||||
/// assert!( (3..3).is_empty());
|
||||
/// assert!( (3..2).is_empty());
|
||||
/// ```
|
||||
///
|
||||
/// The range is empty if either side is incomparable:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(range_is_empty,inclusive_range_syntax)]
|
||||
///
|
||||
/// use std::f32::NAN;
|
||||
/// assert!(!(3.0..5.0).is_empty());
|
||||
/// assert!( (3.0..NAN).is_empty());
|
||||
/// assert!( (NAN..5.0).is_empty());
|
||||
/// ```
|
||||
#[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
!(self.start < self.end)
|
||||
}
|
||||
}
|
||||
|
||||
/// A range only bounded inclusively below (`start..`).
|
||||
@ -244,7 +271,14 @@ impl<Idx: PartialOrd<Idx>> RangeTo<Idx> {
|
||||
/// An range bounded inclusively below and above (`start..=end`).
|
||||
///
|
||||
/// The `RangeInclusive` `start..=end` contains all values with `x >= start`
|
||||
/// and `x <= end`.
|
||||
/// and `x <= end`. It is empty unless `start <= end`.
|
||||
///
|
||||
/// This iterator is [fused], but the specific values of `start` and `end` after
|
||||
/// iteration has finished are **unspecified** other than that [`.is_empty()`]
|
||||
/// will return `true` once no more values will be produced.
|
||||
///
|
||||
/// [fused]: ../iter/trait.FusedIterator.html
|
||||
/// [`.is_empty()`]: #method.is_empty
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -280,7 +314,6 @@ impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
|
||||
impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
|
||||
/// Returns `true` if `item` is contained in the range.
|
||||
///
|
||||
@ -298,9 +331,48 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
|
||||
/// assert!( (3..=3).contains(3));
|
||||
/// assert!(!(3..=2).contains(3));
|
||||
/// ```
|
||||
#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
|
||||
pub fn contains(&self, item: Idx) -> bool {
|
||||
self.start <= item && item <= self.end
|
||||
}
|
||||
|
||||
/// Returns `true` if the range contains no items.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(range_is_empty,inclusive_range_syntax)]
|
||||
///
|
||||
/// assert!(!(3..=5).is_empty());
|
||||
/// assert!(!(3..=3).is_empty());
|
||||
/// assert!( (3..=2).is_empty());
|
||||
/// ```
|
||||
///
|
||||
/// The range is empty if either side is incomparable:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(range_is_empty,inclusive_range_syntax)]
|
||||
///
|
||||
/// use std::f32::NAN;
|
||||
/// assert!(!(3.0..=5.0).is_empty());
|
||||
/// assert!( (3.0..=NAN).is_empty());
|
||||
/// assert!( (NAN..=5.0).is_empty());
|
||||
/// ```
|
||||
///
|
||||
/// This method returns `true` after iteration has finished:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(range_is_empty,inclusive_range_syntax)]
|
||||
///
|
||||
/// let mut r = 3..=5;
|
||||
/// for _ in r.by_ref() {}
|
||||
/// // Precise field values are unspecified here
|
||||
/// assert!(r.is_empty());
|
||||
/// ```
|
||||
#[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
!(self.start <= self.end)
|
||||
}
|
||||
}
|
||||
|
||||
/// A range only bounded inclusively above (`..=end`).
|
||||
|
@ -2573,7 +2573,7 @@ impl<T: ?Sized> Clone for NonNull<T> {
|
||||
#[stable(feature = "nonnull", since = "1.25.0")]
|
||||
impl<T: ?Sized> Copy for NonNull<T> { }
|
||||
|
||||
#[stable(feature = "nonnull", since = "1.25.0")]
|
||||
#[unstable(feature = "coerce_unsized", issue = "27732")]
|
||||
impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> { }
|
||||
|
||||
#[stable(feature = "nonnull", since = "1.25.0")]
|
||||
@ -2621,7 +2621,7 @@ impl<T: ?Sized> hash::Hash for NonNull<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "nonnull", since = "1.25.0")]
|
||||
#[unstable(feature = "ptr_internals", issue = "0")]
|
||||
impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
|
||||
fn from(unique: Unique<T>) -> Self {
|
||||
NonNull { pointer: unique.pointer }
|
||||
|
@ -1322,42 +1322,84 @@ fn test_range() {
|
||||
(isize::MAX as usize + 2, Some(isize::MAX as usize + 2)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_exhaustion() {
|
||||
let mut r = 10..10;
|
||||
assert!(r.is_empty());
|
||||
assert_eq!(r.next(), None);
|
||||
assert_eq!(r.next_back(), None);
|
||||
assert_eq!(r, 10..10);
|
||||
|
||||
let mut r = 10..12;
|
||||
assert_eq!(r.next(), Some(10));
|
||||
assert_eq!(r.next(), Some(11));
|
||||
assert!(r.is_empty());
|
||||
assert_eq!(r, 12..12);
|
||||
assert_eq!(r.next(), None);
|
||||
|
||||
let mut r = 10..12;
|
||||
assert_eq!(r.next_back(), Some(11));
|
||||
assert_eq!(r.next_back(), Some(10));
|
||||
assert!(r.is_empty());
|
||||
assert_eq!(r, 10..10);
|
||||
assert_eq!(r.next_back(), None);
|
||||
|
||||
let mut r = 100..10;
|
||||
assert!(r.is_empty());
|
||||
assert_eq!(r.next(), None);
|
||||
assert_eq!(r.next_back(), None);
|
||||
assert_eq!(r, 100..10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_inclusive_exhaustion() {
|
||||
let mut r = 10..=10;
|
||||
assert_eq!(r.next(), Some(10));
|
||||
assert_eq!(r, 1..=0);
|
||||
assert!(r.is_empty());
|
||||
assert_eq!(r.next(), None);
|
||||
assert_eq!(r.next(), None);
|
||||
|
||||
let mut r = 10..=10;
|
||||
assert_eq!(r.next_back(), Some(10));
|
||||
assert_eq!(r, 1..=0);
|
||||
assert!(r.is_empty());
|
||||
assert_eq!(r.next_back(), None);
|
||||
|
||||
let mut r = 10..=12;
|
||||
assert_eq!(r.next(), Some(10));
|
||||
assert_eq!(r.next(), Some(11));
|
||||
assert_eq!(r.next(), Some(12));
|
||||
assert_eq!(r, 1..=0);
|
||||
assert!(r.is_empty());
|
||||
assert_eq!(r.next(), None);
|
||||
|
||||
let mut r = 10..=12;
|
||||
assert_eq!(r.next_back(), Some(12));
|
||||
assert_eq!(r.next_back(), Some(11));
|
||||
assert_eq!(r.next_back(), Some(10));
|
||||
assert_eq!(r, 1..=0);
|
||||
assert!(r.is_empty());
|
||||
assert_eq!(r.next_back(), None);
|
||||
|
||||
let mut r = 10..=12;
|
||||
assert_eq!(r.nth(2), Some(12));
|
||||
assert_eq!(r, 1..=0);
|
||||
assert!(r.is_empty());
|
||||
assert_eq!(r.next(), None);
|
||||
|
||||
let mut r = 10..=12;
|
||||
assert_eq!(r.nth(5), None);
|
||||
assert_eq!(r, 1..=0);
|
||||
assert!(r.is_empty());
|
||||
assert_eq!(r.next(), None);
|
||||
|
||||
let mut r = 100..=10;
|
||||
assert_eq!(r.next(), None);
|
||||
assert!(r.is_empty());
|
||||
assert_eq!(r.next(), None);
|
||||
assert_eq!(r.next(), None);
|
||||
assert_eq!(r, 100..=10);
|
||||
|
||||
let mut r = 100..=10;
|
||||
assert_eq!(r.next_back(), None);
|
||||
assert!(r.is_empty());
|
||||
assert_eq!(r.next_back(), None);
|
||||
assert_eq!(r.next_back(), None);
|
||||
assert_eq!(r, 100..=10);
|
||||
}
|
||||
|
||||
@ -1428,9 +1470,10 @@ fn test_range_inclusive_nth() {
|
||||
assert_eq!(r.nth(2), Some(15));
|
||||
assert_eq!(r, 16..=20);
|
||||
assert_eq!(r.is_empty(), false);
|
||||
assert_eq!(ExactSizeIterator::is_empty(&r), false);
|
||||
assert_eq!(r.nth(10), None);
|
||||
assert_eq!(r.is_empty(), true);
|
||||
assert_eq!(r, 1..=0); // We may not want to document/promise this detail
|
||||
assert_eq!(ExactSizeIterator::is_empty(&r), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1514,11 +1557,11 @@ fn test_range_inclusive_folds() {
|
||||
|
||||
let mut it = 10..=20;
|
||||
assert_eq!(it.try_fold(0, |a,b| Some(a+b)), Some(165));
|
||||
assert_eq!(it, 1..=0);
|
||||
assert!(it.is_empty());
|
||||
|
||||
let mut it = 10..=20;
|
||||
assert_eq!(it.try_rfold(0, |a,b| Some(a+b)), Some(165));
|
||||
assert_eq!(it, 1..=0);
|
||||
assert!(it.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1549,6 +1592,51 @@ fn test_repeat_take_collect() {
|
||||
assert_eq!(v, vec![42, 42, 42]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_repeat_with() {
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct NotClone(usize);
|
||||
let mut it = repeat_with(|| NotClone(42));
|
||||
assert_eq!(it.next(), Some(NotClone(42)));
|
||||
assert_eq!(it.next(), Some(NotClone(42)));
|
||||
assert_eq!(it.next(), Some(NotClone(42)));
|
||||
assert_eq!(repeat_with(|| NotClone(42)).size_hint(), (usize::MAX, None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_repeat_with_rev() {
|
||||
let mut curr = 1;
|
||||
let mut pow2 = repeat_with(|| { let tmp = curr; curr *= 2; tmp })
|
||||
.rev().take(4);
|
||||
assert_eq!(pow2.next(), Some(1));
|
||||
assert_eq!(pow2.next(), Some(2));
|
||||
assert_eq!(pow2.next(), Some(4));
|
||||
assert_eq!(pow2.next(), Some(8));
|
||||
assert_eq!(pow2.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_repeat_with_take() {
|
||||
let mut it = repeat_with(|| 42).take(3);
|
||||
assert_eq!(it.next(), Some(42));
|
||||
assert_eq!(it.next(), Some(42));
|
||||
assert_eq!(it.next(), Some(42));
|
||||
assert_eq!(it.next(), None);
|
||||
is_trusted_len(repeat_with(|| 42).take(3));
|
||||
assert_eq!(repeat_with(|| 42).take(3).size_hint(), (3, Some(3)));
|
||||
assert_eq!(repeat_with(|| 42).take(0).size_hint(), (0, Some(0)));
|
||||
assert_eq!(repeat_with(|| 42).take(usize::MAX).size_hint(),
|
||||
(usize::MAX, Some(usize::MAX)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_repeat_with_take_collect() {
|
||||
let mut curr = 1;
|
||||
let v: Vec<_> = repeat_with(|| { let tmp = curr; curr *= 2; tmp })
|
||||
.take(5).collect();
|
||||
assert_eq!(v, vec![1, 2, 4, 8, 16]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fuse() {
|
||||
let mut it = 0..3;
|
||||
|
@ -27,8 +27,10 @@
|
||||
#![feature(iterator_try_fold)]
|
||||
#![feature(iter_rfind)]
|
||||
#![feature(iter_rfold)]
|
||||
#![feature(iterator_repeat_with)]
|
||||
#![feature(nonzero)]
|
||||
#![feature(pattern)]
|
||||
#![feature(range_is_empty)]
|
||||
#![feature(raw)]
|
||||
#![feature(refcell_replace_swap)]
|
||||
#![feature(sip_hash_13)]
|
||||
|
@ -68,3 +68,27 @@ fn test_range_inclusive() {
|
||||
assert_eq!(r.size_hint(), (0, Some(0)));
|
||||
assert_eq!(r.next(), None);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_range_is_empty() {
|
||||
use core::f32::*;
|
||||
|
||||
assert!(!(0.0 .. 10.0).is_empty());
|
||||
assert!( (-0.0 .. 0.0).is_empty());
|
||||
assert!( (10.0 .. 0.0).is_empty());
|
||||
|
||||
assert!(!(NEG_INFINITY .. INFINITY).is_empty());
|
||||
assert!( (EPSILON .. NAN).is_empty());
|
||||
assert!( (NAN .. EPSILON).is_empty());
|
||||
assert!( (NAN .. NAN).is_empty());
|
||||
|
||||
assert!(!(0.0 ..= 10.0).is_empty());
|
||||
assert!(!(-0.0 ..= 0.0).is_empty());
|
||||
assert!( (10.0 ..= 0.0).is_empty());
|
||||
|
||||
assert!(!(NEG_INFINITY ..= INFINITY).is_empty());
|
||||
assert!( (EPSILON ..= NAN).is_empty());
|
||||
assert!( (NAN ..= EPSILON).is_empty());
|
||||
assert!( (NAN ..= NAN).is_empty());
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
#![stable(feature = "duration_core", since = "1.24.0")]
|
||||
#![stable(feature = "duration_core", since = "1.25.0")]
|
||||
|
||||
//! Temporal quantification.
|
||||
//!
|
||||
@ -58,7 +58,7 @@ const MICROS_PER_SEC: u64 = 1_000_000;
|
||||
///
|
||||
/// let ten_millis = Duration::from_millis(10);
|
||||
/// ```
|
||||
#[stable(feature = "duration_core", since = "1.24.0")]
|
||||
#[stable(feature = "duration", since = "1.3.0")]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)]
|
||||
pub struct Duration {
|
||||
secs: u64,
|
||||
|
@ -9,14 +9,15 @@
|
||||
// except according to those terms.
|
||||
|
||||
use super::*;
|
||||
|
||||
use dep_graph::{DepGraph, DepKind, DepNodeIndex};
|
||||
use hir::def_id::{LOCAL_CRATE, CrateNum};
|
||||
use hir::intravisit::{Visitor, NestedVisitorMap};
|
||||
use hir::svh::Svh;
|
||||
use middle::cstore::CrateStore;
|
||||
use session::CrateDisambiguator;
|
||||
use std::iter::repeat;
|
||||
use syntax::ast::{NodeId, CRATE_NODE_ID};
|
||||
use syntax::codemap::CodeMap;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use ich::StableHashingContext;
|
||||
@ -123,6 +124,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
|
||||
pub(super) fn finalize_and_compute_crate_hash(self,
|
||||
crate_disambiguator: CrateDisambiguator,
|
||||
cstore: &CrateStore,
|
||||
codemap: &CodeMap,
|
||||
commandline_args_hash: u64)
|
||||
-> (Vec<MapEntry<'hir>>, Svh) {
|
||||
let mut node_hashes: Vec<_> = self
|
||||
@ -147,11 +149,25 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
|
||||
(name1, dis1).cmp(&(name2, dis2))
|
||||
});
|
||||
|
||||
// We hash the final, remapped names of all local source files so we
|
||||
// don't have to include the path prefix remapping commandline args.
|
||||
// If we included the full mapping in the SVH, we could only have
|
||||
// reproducible builds by compiling from the same directory. So we just
|
||||
// hash the result of the mapping instead of the mapping itself.
|
||||
let mut source_file_names: Vec<_> = codemap
|
||||
.files()
|
||||
.iter()
|
||||
.filter(|filemap| CrateNum::from_u32(filemap.crate_of_origin) == LOCAL_CRATE)
|
||||
.map(|filemap| filemap.name_hash)
|
||||
.collect();
|
||||
|
||||
source_file_names.sort_unstable();
|
||||
|
||||
let (_, crate_dep_node_index) = self
|
||||
.dep_graph
|
||||
.with_task(DepNode::new_no_params(DepKind::Krate),
|
||||
&self.hcx,
|
||||
((node_hashes, upstream_crates),
|
||||
(((node_hashes, upstream_crates), source_file_names),
|
||||
(commandline_args_hash,
|
||||
crate_disambiguator.to_fingerprint())),
|
||||
identity_fn);
|
||||
|
@ -1065,6 +1065,7 @@ pub fn map_crate<'hir>(sess: &::session::Session,
|
||||
let cmdline_args = sess.opts.dep_tracking_hash();
|
||||
collector.finalize_and_compute_crate_hash(crate_disambiguator,
|
||||
cstore,
|
||||
sess.codemap(),
|
||||
cmdline_args)
|
||||
};
|
||||
|
||||
|
@ -1269,9 +1269,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||
"set the optimization fuel quota for a crate"),
|
||||
print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
|
||||
"make Rustc print the total optimization fuel used by a crate"),
|
||||
remap_path_prefix_from: Vec<PathBuf> = (vec![], parse_pathbuf_push, [TRACKED],
|
||||
remap_path_prefix_from: Vec<PathBuf> = (vec![], parse_pathbuf_push, [UNTRACKED],
|
||||
"add a source pattern to the file path remapping config"),
|
||||
remap_path_prefix_to: Vec<PathBuf> = (vec![], parse_pathbuf_push, [TRACKED],
|
||||
remap_path_prefix_to: Vec<PathBuf> = (vec![], parse_pathbuf_push, [UNTRACKED],
|
||||
"add a mapping target to the file path remapping config"),
|
||||
force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
|
||||
"force all crates to be `rustc_private` unstable"),
|
||||
@ -1320,6 +1320,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||
"The epoch to build Rust with. Newer epochs may include features
|
||||
that require breaking changes. The default epoch is 2015 (the first
|
||||
epoch). Crates compiled with different epochs can be linked together."),
|
||||
run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"run `dsymutil` and delete intermediate object files"),
|
||||
}
|
||||
|
||||
pub fn default_lib_output() -> CrateType {
|
||||
@ -1717,7 +1719,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
|
||||
}
|
||||
|
||||
let remap_path_prefix_sources = debugging_opts.remap_path_prefix_from.len();
|
||||
let remap_path_prefix_targets = debugging_opts.remap_path_prefix_from.len();
|
||||
let remap_path_prefix_targets = debugging_opts.remap_path_prefix_to.len();
|
||||
|
||||
if remap_path_prefix_targets < remap_path_prefix_sources {
|
||||
for source in &debugging_opts.remap_path_prefix_from[remap_path_prefix_targets..] {
|
||||
|
@ -660,6 +660,15 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session,
|
||||
disambiguator,
|
||||
);
|
||||
|
||||
if sess.opts.incremental.is_some() {
|
||||
time(time_passes, "garbage collect incremental cache directory", || {
|
||||
if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) {
|
||||
warn!("Error while trying to garbage collect incremental \
|
||||
compilation cache directory: {}", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// If necessary, compute the dependency graph (in the background).
|
||||
let future_dep_graph = if sess.opts.build_dep_graph() {
|
||||
Some(rustc_incremental::load_dep_graph(sess, time_passes))
|
||||
|
@ -46,3 +46,4 @@ pub use persist::in_incr_comp_dir;
|
||||
pub use persist::prepare_session_directory;
|
||||
pub use persist::finalize_session_directory;
|
||||
pub use persist::delete_workproduct_files;
|
||||
pub use persist::garbage_collect_session_directories;
|
||||
|
@ -603,7 +603,7 @@ fn timestamp_to_string(timestamp: SystemTime) -> String {
|
||||
}
|
||||
|
||||
fn string_to_timestamp(s: &str) -> Result<SystemTime, ()> {
|
||||
let micros_since_unix_epoch = u64::from_str_radix(s, 36);
|
||||
let micros_since_unix_epoch = u64::from_str_radix(s, INT_ENCODE_BASE as u32);
|
||||
|
||||
if micros_since_unix_epoch.is_err() {
|
||||
return Err(())
|
||||
@ -733,6 +733,20 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> {
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Delete all session directories that don't have a lock file.
|
||||
for directory_name in session_directories {
|
||||
if !lock_file_to_session_dir.values().any(|dir| *dir == directory_name) {
|
||||
let path = crate_directory.join(directory_name);
|
||||
if let Err(err) = safe_remove_dir_all(&path) {
|
||||
sess.warn(&format!("Failed to garbage collect invalid incremental \
|
||||
compilation session directory `{}`: {}",
|
||||
path.display(),
|
||||
err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now garbage collect the valid session directories.
|
||||
let mut deletion_candidates = vec![];
|
||||
let mut definitely_delete = vec![];
|
||||
|
||||
|
@ -20,9 +20,10 @@ mod save;
|
||||
mod work_product;
|
||||
mod file_format;
|
||||
|
||||
pub use self::fs::prepare_session_directory;
|
||||
pub use self::fs::finalize_session_directory;
|
||||
pub use self::fs::garbage_collect_session_directories;
|
||||
pub use self::fs::in_incr_comp_dir;
|
||||
pub use self::fs::prepare_session_directory;
|
||||
pub use self::load::dep_graph_tcx_init;
|
||||
pub use self::load::load_dep_graph;
|
||||
pub use self::load::load_query_result_cache;
|
||||
|
@ -11,6 +11,7 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{self, AdtKind, Ty, TyCtxt};
|
||||
use rustc::ty::layout::{self, LayoutOf};
|
||||
@ -176,6 +177,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
|
||||
_ => bug!(),
|
||||
};
|
||||
if lit_val < min || lit_val > max {
|
||||
let parent_id = cx.tcx.hir.get_parent_node(e.id);
|
||||
if let hir_map::NodeExpr(parent_expr) = cx.tcx.hir.get(parent_id) {
|
||||
if let hir::ExprCast(..) = parent_expr.node {
|
||||
if let ty::TyChar = cx.tables.expr_ty(parent_expr).sty {
|
||||
let mut err = cx.struct_span_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
parent_expr.span,
|
||||
"only u8 can be casted into char");
|
||||
err.span_suggestion(parent_expr.span,
|
||||
&"use a char literal instead",
|
||||
format!("'\\u{{{:X}}}'", lit_val));
|
||||
err.emit();
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
cx.span_lint(OVERFLOWING_LITERALS,
|
||||
e.span,
|
||||
&format!("literal out of range for {:?}", t));
|
||||
|
@ -155,6 +155,7 @@ fn main() {
|
||||
cfg.file("../rustllvm/PassWrapper.cpp")
|
||||
.file("../rustllvm/RustWrapper.cpp")
|
||||
.file("../rustllvm/ArchiveWrapper.cpp")
|
||||
.file("../rustllvm/Linker.cpp")
|
||||
.cpp(true)
|
||||
.cpp_link_stdlib(None) // we handle this below
|
||||
.compile("rustllvm");
|
||||
|
@ -444,6 +444,9 @@ pub type RustArchiveMemberRef = *mut RustArchiveMember_opaque;
|
||||
#[allow(missing_copy_implementations)]
|
||||
pub enum OperandBundleDef_opaque {}
|
||||
pub type OperandBundleDefRef = *mut OperandBundleDef_opaque;
|
||||
#[allow(missing_copy_implementations)]
|
||||
pub enum Linker_opaque {}
|
||||
pub type LinkerRef = *mut Linker_opaque;
|
||||
|
||||
pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void);
|
||||
pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint);
|
||||
@ -1608,7 +1611,6 @@ extern "C" {
|
||||
pub fn LLVMRustPrintPasses();
|
||||
pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *const c_char);
|
||||
pub fn LLVMRustAddAlwaysInlinePass(P: PassManagerBuilderRef, AddLifetimes: bool);
|
||||
pub fn LLVMRustLinkInExternalBitcode(M: ModuleRef, bc: *const c_char, len: size_t) -> bool;
|
||||
pub fn LLVMRustRunRestrictionPass(M: ModuleRef, syms: *const *const c_char, len: size_t);
|
||||
pub fn LLVMRustMarkAllFunctionsNounwind(M: ModuleRef);
|
||||
|
||||
@ -1724,4 +1726,10 @@ extern "C" {
|
||||
CU2: *mut *mut c_void);
|
||||
pub fn LLVMRustThinLTOPatchDICompileUnit(M: ModuleRef, CU: *mut c_void);
|
||||
pub fn LLVMRustThinLTORemoveAvailableExternally(M: ModuleRef);
|
||||
|
||||
pub fn LLVMRustLinkerNew(M: ModuleRef) -> LinkerRef;
|
||||
pub fn LLVMRustLinkerAdd(linker: LinkerRef,
|
||||
bytecode: *const c_char,
|
||||
bytecode_len: usize) -> bool;
|
||||
pub fn LLVMRustLinkerFree(linker: LinkerRef);
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
||||
self.tcx.data_layout.pointer_size.bytes()
|
||||
}
|
||||
|
||||
pub fn endianess(&self) -> layout::Endian {
|
||||
pub fn endianness(&self) -> layout::Endian {
|
||||
self.tcx.data_layout.endian
|
||||
}
|
||||
|
||||
@ -722,7 +722,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
||||
|
||||
pub fn read_primval(&self, ptr: MemoryPointer, ptr_align: Align, size: u64, signed: bool) -> EvalResult<'tcx, PrimVal> {
|
||||
self.check_relocation_edges(ptr, size)?; // Make sure we don't read part of a pointer as a pointer
|
||||
let endianess = self.endianess();
|
||||
let endianness = self.endianness();
|
||||
let bytes = self.get_bytes_unchecked(ptr, size, ptr_align.min(self.int_align(size)))?;
|
||||
// Undef check happens *after* we established that the alignment is correct.
|
||||
// We must not return Ok() for unaligned pointers!
|
||||
@ -731,9 +731,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
||||
}
|
||||
// Now we do the actual reading
|
||||
let bytes = if signed {
|
||||
read_target_int(endianess, bytes).unwrap() as u128
|
||||
read_target_int(endianness, bytes).unwrap() as u128
|
||||
} else {
|
||||
read_target_uint(endianess, bytes).unwrap()
|
||||
read_target_uint(endianness, bytes).unwrap()
|
||||
};
|
||||
// See if we got a pointer
|
||||
if size != self.pointer_size() {
|
||||
@ -756,7 +756,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
||||
}
|
||||
|
||||
pub fn write_primval(&mut self, ptr: MemoryPointer, ptr_align: Align, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> {
|
||||
let endianess = self.endianess();
|
||||
let endianness = self.endianness();
|
||||
|
||||
let bytes = match val {
|
||||
PrimVal::Ptr(val) => {
|
||||
@ -788,9 +788,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
||||
let align = self.int_align(size);
|
||||
let dst = self.get_bytes_mut(ptr, size, ptr_align.min(align))?;
|
||||
if signed {
|
||||
write_target_int(endianess, dst, bytes as i128).unwrap();
|
||||
write_target_int(endianness, dst, bytes as i128).unwrap();
|
||||
} else {
|
||||
write_target_uint(endianess, dst, bytes).unwrap();
|
||||
write_target_uint(endianness, dst, bytes).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@ -941,41 +941,41 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Methods to access integers in the target endianess
|
||||
// Methods to access integers in the target endianness
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
fn write_target_uint(
|
||||
endianess: layout::Endian,
|
||||
endianness: layout::Endian,
|
||||
mut target: &mut [u8],
|
||||
data: u128,
|
||||
) -> Result<(), io::Error> {
|
||||
let len = target.len();
|
||||
match endianess {
|
||||
match endianness {
|
||||
layout::Endian::Little => target.write_uint128::<LittleEndian>(data, len),
|
||||
layout::Endian::Big => target.write_uint128::<BigEndian>(data, len),
|
||||
}
|
||||
}
|
||||
fn write_target_int(
|
||||
endianess: layout::Endian,
|
||||
endianness: layout::Endian,
|
||||
mut target: &mut [u8],
|
||||
data: i128,
|
||||
) -> Result<(), io::Error> {
|
||||
let len = target.len();
|
||||
match endianess {
|
||||
match endianness {
|
||||
layout::Endian::Little => target.write_int128::<LittleEndian>(data, len),
|
||||
layout::Endian::Big => target.write_int128::<BigEndian>(data, len),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_target_uint(endianess: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
|
||||
match endianess {
|
||||
fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
|
||||
match endianness {
|
||||
layout::Endian::Little => source.read_uint128::<LittleEndian>(source.len()),
|
||||
layout::Endian::Big => source.read_uint128::<BigEndian>(source.len()),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_target_int(endianess: layout::Endian, mut source: &[u8]) -> Result<i128, io::Error> {
|
||||
match endianess {
|
||||
fn read_target_int(endianness: layout::Endian, mut source: &[u8]) -> Result<i128, io::Error> {
|
||||
match endianness {
|
||||
layout::Endian::Little => source.read_int128::<LittleEndian>(source.len()),
|
||||
layout::Endian::Big => source.read_int128::<BigEndian>(source.len()),
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ pub fn provide(providers: &mut Providers) {
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
Rc::new(llvm_util::target_feature_whitelist(tcx.sess)
|
||||
.iter()
|
||||
.map(|c| c.to_str().unwrap().to_string())
|
||||
.map(|c| c.to_string())
|
||||
.collect())
|
||||
};
|
||||
|
||||
@ -212,7 +212,8 @@ fn from_target_feature(
|
||||
let value = value.as_str();
|
||||
for feature in value.split(',') {
|
||||
if whitelist.contains(feature) {
|
||||
target_features.push(format!("+{}", feature));
|
||||
let llvm_feature = llvm_util::to_llvm_feature(feature);
|
||||
target_features.push(format!("+{}", llvm_feature));
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -166,7 +166,9 @@ pub(crate) fn link_binary(sess: &Session,
|
||||
|
||||
// Remove the temporary object file and metadata if we aren't saving temps
|
||||
if !sess.opts.cg.save_temps {
|
||||
if sess.opts.output_types.should_trans() {
|
||||
if sess.opts.output_types.should_trans() &&
|
||||
!preserve_objects_for_their_debuginfo(sess)
|
||||
{
|
||||
for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) {
|
||||
remove(sess, obj);
|
||||
}
|
||||
@ -190,6 +192,52 @@ pub(crate) fn link_binary(sess: &Session,
|
||||
out_filenames
|
||||
}
|
||||
|
||||
/// Returns a boolean indicating whether we should preserve the object files on
|
||||
/// the filesystem for their debug information. This is often useful with
|
||||
/// split-dwarf like schemes.
|
||||
fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
|
||||
// If the objects don't have debuginfo there's nothing to preserve.
|
||||
if sess.opts.debuginfo == NoDebugInfo {
|
||||
return false
|
||||
}
|
||||
|
||||
// If we're only producing artifacts that are archives, no need to preserve
|
||||
// the objects as they're losslessly contained inside the archives.
|
||||
let output_linked = sess.crate_types.borrow()
|
||||
.iter()
|
||||
.any(|x| *x != config::CrateTypeRlib && *x != config::CrateTypeStaticlib);
|
||||
if !output_linked {
|
||||
return false
|
||||
}
|
||||
|
||||
// If we're on OSX then the equivalent of split dwarf is turned on by
|
||||
// default. The final executable won't actually have any debug information
|
||||
// except it'll have pointers to elsewhere. Historically we've always run
|
||||
// `dsymutil` to "link all the dwarf together" but this is actually sort of
|
||||
// a bummer for incremental compilation! (the whole point of split dwarf is
|
||||
// that you don't do this sort of dwarf link).
|
||||
//
|
||||
// Basically as a result this just means that if we're on OSX and we're
|
||||
// *not* running dsymutil then the object files are the only source of truth
|
||||
// for debug information, so we must preserve them.
|
||||
if sess.target.target.options.is_like_osx {
|
||||
match sess.opts.debugging_opts.run_dsymutil {
|
||||
// dsymutil is not being run, preserve objects
|
||||
Some(false) => return true,
|
||||
|
||||
// dsymutil is being run, no need to preserve the objects
|
||||
Some(true) => return false,
|
||||
|
||||
// The default historical behavior was to always run dsymutil, so
|
||||
// we're preserving that temporarily, but we're likely to switch the
|
||||
// default soon.
|
||||
None => return false,
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn filename_for_metadata(sess: &Session, crate_name: &str, outputs: &OutputFilenames) -> PathBuf {
|
||||
let out_filename = outputs.single_output_file.clone()
|
||||
.unwrap_or(outputs
|
||||
@ -736,8 +784,12 @@ fn link_natively(sess: &Session,
|
||||
|
||||
|
||||
// On macOS, debuggers need this utility to get run to do some munging of
|
||||
// the symbols
|
||||
if sess.target.target.options.is_like_osx && sess.opts.debuginfo != NoDebugInfo {
|
||||
// the symbols. Note, though, that if the object files are being preserved
|
||||
// for their debug information there's no need for us to run dsymutil.
|
||||
if sess.target.target.options.is_like_osx &&
|
||||
sess.opts.debuginfo != NoDebugInfo &&
|
||||
!preserve_objects_for_their_debuginfo(sess)
|
||||
{
|
||||
match Command::new("dsymutil").arg(out_filename).output() {
|
||||
Ok(..) => {}
|
||||
Err(e) => sess.fatal(&format!("failed to run dsymutil: {}", e)),
|
||||
|
@ -247,22 +247,20 @@ fn fat_lto(cgcx: &CodegenContext,
|
||||
// know much about the memory management here so we err on the side of being
|
||||
// save and persist everything with the original module.
|
||||
let mut serialized_bitcode = Vec::new();
|
||||
let mut linker = Linker::new(llmod);
|
||||
for (bc_decoded, name) in serialized_modules {
|
||||
info!("linking {:?}", name);
|
||||
time(cgcx.time_passes, &format!("ll link {:?}", name), || unsafe {
|
||||
time(cgcx.time_passes, &format!("ll link {:?}", name), || {
|
||||
let data = bc_decoded.data();
|
||||
if llvm::LLVMRustLinkInExternalBitcode(llmod,
|
||||
data.as_ptr() as *const libc::c_char,
|
||||
data.len() as libc::size_t) {
|
||||
Ok(())
|
||||
} else {
|
||||
linker.add(&data).map_err(|()| {
|
||||
let msg = format!("failed to load bc of {:?}", name);
|
||||
Err(write::llvm_err(&diag_handler, msg))
|
||||
}
|
||||
write::llvm_err(&diag_handler, msg)
|
||||
})
|
||||
})?;
|
||||
timeline.record(&format!("link {:?}", name));
|
||||
serialized_bitcode.push(bc_decoded);
|
||||
}
|
||||
drop(linker);
|
||||
cgcx.save_temp_bitcode(&module, "lto.input");
|
||||
|
||||
// Internalize everything that *isn't* in our whitelist to help strip out
|
||||
@ -289,6 +287,32 @@ fn fat_lto(cgcx: &CodegenContext,
|
||||
}])
|
||||
}
|
||||
|
||||
struct Linker(llvm::LinkerRef);
|
||||
|
||||
impl Linker {
|
||||
fn new(llmod: ModuleRef) -> Linker {
|
||||
unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) }
|
||||
}
|
||||
|
||||
fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> {
|
||||
unsafe {
|
||||
if llvm::LLVMRustLinkerAdd(self.0,
|
||||
bytecode.as_ptr() as *const libc::c_char,
|
||||
bytecode.len()) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Linker {
|
||||
fn drop(&mut self) {
|
||||
unsafe { llvm::LLVMRustLinkerFree(self.0); }
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepare "thin" LTO to get run on these modules.
|
||||
///
|
||||
/// The general structure of ThinLTO is quite different from the structure of
|
||||
|
@ -14,7 +14,7 @@ use llvm;
|
||||
use rustc::session::Session;
|
||||
use rustc::session::config::PrintRequest;
|
||||
use libc::c_int;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::ffi::CString;
|
||||
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Once;
|
||||
@ -79,46 +79,53 @@ unsafe fn configure_llvm(sess: &Session) {
|
||||
// detection code will walk past the end of the feature array,
|
||||
// leading to crashes.
|
||||
|
||||
const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "v7\0", "vfp2\0", "vfp3\0", "vfp4\0"];
|
||||
const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"];
|
||||
|
||||
const AARCH64_WHITELIST: &'static [&'static str] = &["neon\0", "v7\0"];
|
||||
const AARCH64_WHITELIST: &'static [&'static str] = &["neon", "v7"];
|
||||
|
||||
const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0",
|
||||
"sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0",
|
||||
"ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0",
|
||||
"sse4a\0", "rdrnd\0", "rdseed\0", "fma\0",
|
||||
"xsave\0", "xsaveopt\0", "xsavec\0",
|
||||
"xsaves\0", "aes\0",
|
||||
"avx512bw\0", "avx512cd\0",
|
||||
"avx512dq\0", "avx512er\0",
|
||||
"avx512f\0", "avx512ifma\0",
|
||||
"avx512pf\0", "avx512vbmi\0",
|
||||
"avx512vl\0", "avx512vpopcntdq\0",
|
||||
"mmx\0", "fxsr\0"];
|
||||
const X86_WHITELIST: &'static [&'static str] = &["avx", "avx2", "bmi", "bmi2", "sse",
|
||||
"sse2", "sse3", "sse4.1", "sse4.2",
|
||||
"ssse3", "tbm", "lzcnt", "popcnt",
|
||||
"sse4a", "rdrnd", "rdseed", "fma",
|
||||
"xsave", "xsaveopt", "xsavec",
|
||||
"xsaves", "aes", "pclmulqdq",
|
||||
"avx512bw", "avx512cd",
|
||||
"avx512dq", "avx512er",
|
||||
"avx512f", "avx512ifma",
|
||||
"avx512pf", "avx512vbmi",
|
||||
"avx512vl", "avx512vpopcntdq",
|
||||
"mmx", "fxsr"];
|
||||
|
||||
const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx\0", "hvx-double\0"];
|
||||
const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx", "hvx-double"];
|
||||
|
||||
const POWERPC_WHITELIST: &'static [&'static str] = &["altivec\0",
|
||||
"power8-altivec\0", "power9-altivec\0",
|
||||
"power8-vector\0", "power9-vector\0",
|
||||
"vsx\0"];
|
||||
const POWERPC_WHITELIST: &'static [&'static str] = &["altivec",
|
||||
"power8-altivec", "power9-altivec",
|
||||
"power8-vector", "power9-vector",
|
||||
"vsx"];
|
||||
|
||||
const MIPS_WHITELIST: &'static [&'static str] = &["msa\0"];
|
||||
const MIPS_WHITELIST: &'static [&'static str] = &["msa"];
|
||||
|
||||
pub fn target_features(sess: &Session) -> Vec<Symbol> {
|
||||
let whitelist = target_feature_whitelist(sess);
|
||||
let target_machine = create_target_machine(sess);
|
||||
let mut features = Vec::new();
|
||||
for feat in whitelist {
|
||||
if unsafe { llvm::LLVMRustHasFeature(target_machine, feat.as_ptr()) } {
|
||||
features.push(Symbol::intern(feat.to_str().unwrap()));
|
||||
}
|
||||
pub fn to_llvm_feature(s: &str) -> &str {
|
||||
match s {
|
||||
"pclmulqdq" => "pclmul",
|
||||
s => s,
|
||||
}
|
||||
features
|
||||
}
|
||||
|
||||
pub fn target_feature_whitelist(sess: &Session) -> Vec<&CStr> {
|
||||
let whitelist = match &*sess.target.target.arch {
|
||||
pub fn target_features(sess: &Session) -> Vec<Symbol> {
|
||||
let target_machine = create_target_machine(sess);
|
||||
target_feature_whitelist(sess)
|
||||
.iter()
|
||||
.filter(|feature| {
|
||||
let llvm_feature = to_llvm_feature(feature);
|
||||
let cstr = CString::new(llvm_feature).unwrap();
|
||||
unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
|
||||
})
|
||||
.map(|feature| Symbol::intern(feature)).collect()
|
||||
}
|
||||
|
||||
pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] {
|
||||
match &*sess.target.target.arch {
|
||||
"arm" => ARM_WHITELIST,
|
||||
"aarch64" => AARCH64_WHITELIST,
|
||||
"x86" | "x86_64" => X86_WHITELIST,
|
||||
@ -126,10 +133,7 @@ pub fn target_feature_whitelist(sess: &Session) -> Vec<&CStr> {
|
||||
"mips" | "mips64" => MIPS_WHITELIST,
|
||||
"powerpc" | "powerpc64" => POWERPC_WHITELIST,
|
||||
_ => &[],
|
||||
};
|
||||
whitelist.iter().map(|m| {
|
||||
CStr::from_bytes_with_nul(m.as_bytes()).unwrap()
|
||||
}).collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_version() {
|
||||
|
@ -130,7 +130,7 @@ pre {
|
||||
.content .highlighted.primitive { background-color: #00708a; }
|
||||
|
||||
.content span.enum, .content a.enum, .block a.current.enum { color: #82b089; }
|
||||
.content span.struct, .content a.struct, .block a.current.struct { color: #ff794d; }
|
||||
.content span.struct, .content a.struct, .block a.current.struct { color: #2dbfb8; }
|
||||
.content span.type, .content a.type, .block a.current.type { color: #ff7f00; }
|
||||
.content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #dd7de8; }
|
||||
.content span.macro, .content a.macro, .block a.current.macro { color: #09bd00; }
|
||||
|
@ -130,7 +130,7 @@ pre {
|
||||
.content .highlighted.primitive { background-color: #9aecff; }
|
||||
|
||||
.content span.enum, .content a.enum, .block a.current.enum { color: #508157; }
|
||||
.content span.struct, .content a.struct, .block a.current.struct { color: #df3600; }
|
||||
.content span.struct, .content a.struct, .block a.current.struct { color: #ad448e; }
|
||||
.content span.type, .content a.type, .block a.current.type { color: #ba5d00; }
|
||||
.content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #cd00e2; }
|
||||
.content span.macro, .content a.macro, .block a.current.macro { color: #068000; }
|
||||
|
@ -398,8 +398,9 @@ pub struct HashMap<K, V, S = RandomState> {
|
||||
}
|
||||
|
||||
/// Search for a pre-hashed key.
|
||||
/// If you don't already know the hash, use search or search_mut instead
|
||||
#[inline]
|
||||
fn search_hashed<K, V, M, F>(table: M, hash: SafeHash, mut is_match: F) -> InternalEntry<K, V, M>
|
||||
fn search_hashed<K, V, M, F>(table: M, hash: SafeHash, is_match: F) -> InternalEntry<K, V, M>
|
||||
where M: Deref<Target = RawTable<K, V>>,
|
||||
F: FnMut(&K) -> bool
|
||||
{
|
||||
@ -410,6 +411,18 @@ fn search_hashed<K, V, M, F>(table: M, hash: SafeHash, mut is_match: F) -> Inter
|
||||
return InternalEntry::TableIsEmpty;
|
||||
}
|
||||
|
||||
search_hashed_nonempty(table, hash, is_match)
|
||||
}
|
||||
|
||||
/// Search for a pre-hashed key when the hash map is known to be non-empty.
|
||||
#[inline]
|
||||
fn search_hashed_nonempty<K, V, M, F>(table: M, hash: SafeHash, mut is_match: F)
|
||||
-> InternalEntry<K, V, M>
|
||||
where M: Deref<Target = RawTable<K, V>>,
|
||||
F: FnMut(&K) -> bool
|
||||
{
|
||||
// Do not check the capacity as an extra branch could slow the lookup.
|
||||
|
||||
let size = table.size();
|
||||
let mut probe = Bucket::new(table, hash);
|
||||
let mut displacement = 0;
|
||||
@ -543,24 +556,36 @@ impl<K, V, S> HashMap<K, V, S>
|
||||
}
|
||||
|
||||
/// Search for a key, yielding the index if it's found in the hashtable.
|
||||
/// If you already have the hash for the key lying around, use
|
||||
/// search_hashed.
|
||||
/// If you already have the hash for the key lying around, or if you need an
|
||||
/// InternalEntry, use search_hashed or search_hashed_nonempty.
|
||||
#[inline]
|
||||
fn search<'a, Q: ?Sized>(&'a self, q: &Q) -> InternalEntry<K, V, &'a RawTable<K, V>>
|
||||
fn search<'a, Q: ?Sized>(&'a self, q: &Q)
|
||||
-> Option<FullBucket<K, V, &'a RawTable<K, V>>>
|
||||
where K: Borrow<Q>,
|
||||
Q: Eq + Hash
|
||||
{
|
||||
if self.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let hash = self.make_hash(q);
|
||||
search_hashed(&self.table, hash, |k| q.eq(k.borrow()))
|
||||
search_hashed_nonempty(&self.table, hash, |k| q.eq(k.borrow()))
|
||||
.into_occupied_bucket()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) -> InternalEntry<K, V, &'a mut RawTable<K, V>>
|
||||
fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q)
|
||||
-> Option<FullBucket<K, V, &'a mut RawTable<K, V>>>
|
||||
where K: Borrow<Q>,
|
||||
Q: Eq + Hash
|
||||
{
|
||||
if self.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let hash = self.make_hash(q);
|
||||
search_hashed(&mut self.table, hash, |k| q.eq(k.borrow()))
|
||||
search_hashed_nonempty(&mut self.table, hash, |k| q.eq(k.borrow()))
|
||||
.into_occupied_bucket()
|
||||
}
|
||||
|
||||
// The caller should ensure that invariants by Robin Hood Hashing hold
|
||||
@ -1118,7 +1143,7 @@ impl<K, V, S> HashMap<K, V, S>
|
||||
where K: Borrow<Q>,
|
||||
Q: Hash + Eq
|
||||
{
|
||||
self.search(k).into_occupied_bucket().map(|bucket| bucket.into_refs().1)
|
||||
self.search(k).map(|bucket| bucket.into_refs().1)
|
||||
}
|
||||
|
||||
/// Returns true if the map contains a value for the specified key.
|
||||
@ -1145,7 +1170,7 @@ impl<K, V, S> HashMap<K, V, S>
|
||||
where K: Borrow<Q>,
|
||||
Q: Hash + Eq
|
||||
{
|
||||
self.search(k).into_occupied_bucket().is_some()
|
||||
self.search(k).is_some()
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the value corresponding to the key.
|
||||
@ -1174,7 +1199,7 @@ impl<K, V, S> HashMap<K, V, S>
|
||||
where K: Borrow<Q>,
|
||||
Q: Hash + Eq
|
||||
{
|
||||
self.search_mut(k).into_occupied_bucket().map(|bucket| bucket.into_mut_refs().1)
|
||||
self.search_mut(k).map(|bucket| bucket.into_mut_refs().1)
|
||||
}
|
||||
|
||||
/// Inserts a key-value pair into the map.
|
||||
@ -1234,11 +1259,7 @@ impl<K, V, S> HashMap<K, V, S>
|
||||
where K: Borrow<Q>,
|
||||
Q: Hash + Eq
|
||||
{
|
||||
if self.table.size() == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.search_mut(k).into_occupied_bucket().map(|bucket| pop_internal(bucket).1)
|
||||
self.search_mut(k).map(|bucket| pop_internal(bucket).1)
|
||||
}
|
||||
|
||||
/// Removes a key from the map, returning the stored key and value if the
|
||||
@ -1269,12 +1290,7 @@ impl<K, V, S> HashMap<K, V, S>
|
||||
where K: Borrow<Q>,
|
||||
Q: Hash + Eq
|
||||
{
|
||||
if self.table.size() == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.search_mut(k)
|
||||
.into_occupied_bucket()
|
||||
.map(|bucket| {
|
||||
let (k, v, _) = pop_internal(bucket);
|
||||
(k, v)
|
||||
@ -2632,15 +2648,11 @@ impl<K, S, Q: ?Sized> super::Recover<Q> for HashMap<K, (), S>
|
||||
|
||||
#[inline]
|
||||
fn get(&self, key: &Q) -> Option<&K> {
|
||||
self.search(key).into_occupied_bucket().map(|bucket| bucket.into_refs().0)
|
||||
self.search(key).map(|bucket| bucket.into_refs().0)
|
||||
}
|
||||
|
||||
fn take(&mut self, key: &Q) -> Option<K> {
|
||||
if self.table.size() == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.search_mut(key).into_occupied_bucket().map(|bucket| pop_internal(bucket).0)
|
||||
self.search_mut(key).map(|bucket| pop_internal(bucket).0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -723,6 +723,12 @@ pub fn args_os() -> ArgsOs {
|
||||
ArgsOs { inner: sys::args::args() }
|
||||
}
|
||||
|
||||
#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")]
|
||||
impl !Send for Args {}
|
||||
|
||||
#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")]
|
||||
impl !Sync for Args {}
|
||||
|
||||
#[stable(feature = "env", since = "1.0.0")]
|
||||
impl Iterator for Args {
|
||||
type Item = String;
|
||||
@ -754,6 +760,12 @@ impl fmt::Debug for Args {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")]
|
||||
impl !Send for ArgsOs {}
|
||||
|
||||
#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")]
|
||||
impl !Sync for ArgsOs {}
|
||||
|
||||
#[stable(feature = "env", since = "1.0.0")]
|
||||
impl Iterator for ArgsOs {
|
||||
type Item = OsString;
|
||||
|
@ -1023,7 +1023,7 @@ impl f32 {
|
||||
/// This is currently identical to `transmute::<u32, f32>(v)` on all platforms.
|
||||
/// It turns out this is incredibly portable, for two reasons:
|
||||
///
|
||||
/// * Floats and Ints have the same endianess on all supported platforms.
|
||||
/// * Floats and Ints have the same endianness on all supported platforms.
|
||||
/// * IEEE-754 very precisely specifies the bit layout of floats.
|
||||
///
|
||||
/// However there is one caveat: prior to the 2008 version of IEEE-754, how
|
||||
|
@ -978,7 +978,7 @@ impl f64 {
|
||||
/// This is currently identical to `transmute::<u64, f64>(v)` on all platforms.
|
||||
/// It turns out this is incredibly portable, for two reasons:
|
||||
///
|
||||
/// * Floats and Ints have the same endianess on all supported platforms.
|
||||
/// * Floats and Ints have the same endianness on all supported platforms.
|
||||
/// * IEEE-754 very precisely specifies the bit layout of floats.
|
||||
///
|
||||
/// However there is one caveat: prior to the 2008 version of IEEE-754, how
|
||||
|
@ -296,7 +296,7 @@ impl<'a> Write for Cursor<&'a mut [u8]> {
|
||||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
||||
}
|
||||
|
||||
#[unstable(feature = "cursor_mut_vec", issue = "30132")]
|
||||
#[stable(feature = "cursor_mut_vec", since = "1.25.0")]
|
||||
impl<'a> Write for Cursor<&'a mut Vec<u8>> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
vec_write(&mut self.pos, self.inner, buf)
|
||||
|
@ -576,7 +576,7 @@ impl<'a> AsRef<OsStr> for Component<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "path_component_asref", since = "1.24.0")]
|
||||
#[stable(feature = "path_component_asref", since = "1.25.0")]
|
||||
impl<'a> AsRef<Path> for Component<'a> {
|
||||
fn as_ref(&self) -> &Path {
|
||||
self.as_os_str().as_ref()
|
||||
|
@ -690,14 +690,16 @@ impl CodeMap {
|
||||
return 1;
|
||||
}
|
||||
|
||||
let src = local_begin.fm.external_src.borrow();
|
||||
|
||||
// We need to extend the snippet to the end of the src rather than to end_index so when
|
||||
// searching forwards for boundaries we've got somewhere to search.
|
||||
let snippet = if let Some(ref src) = local_begin.fm.src {
|
||||
let len = src.len();
|
||||
(&src[start_index..len]).to_string()
|
||||
} else if let Some(src) = local_begin.fm.external_src.borrow().get_source() {
|
||||
(&src[start_index..len])
|
||||
} else if let Some(src) = src.get_source() {
|
||||
let len = src.len();
|
||||
(&src[start_index..len]).to_string()
|
||||
(&src[start_index..len])
|
||||
} else {
|
||||
return 1;
|
||||
};
|
||||
|
@ -541,7 +541,7 @@ declare_features! (
|
||||
// instead of just the platforms on which it is the C ABI
|
||||
(accepted, abi_sysv64, "1.24.0", Some(36167)),
|
||||
// Allows `repr(align(16))` struct attribute (RFC 1358)
|
||||
(accepted, repr_align, "1.24.0", Some(33626)),
|
||||
(accepted, repr_align, "1.25.0", Some(33626)),
|
||||
// allow '|' at beginning of match arms (RFC 1925)
|
||||
(accepted, match_beginning_vert, "1.25.0", Some(44101)),
|
||||
// Nested groups in `use` (RFC 2128)
|
||||
|
@ -4859,19 +4859,30 @@ impl<'a> Parser<'a> {
|
||||
|p| {
|
||||
if p.token == token::DotDotDot {
|
||||
p.bump();
|
||||
variadic = true;
|
||||
if allow_variadic {
|
||||
if p.token != token::CloseDelim(token::Paren) {
|
||||
let span = p.span;
|
||||
p.span_err(span,
|
||||
"`...` must be last in argument list for variadic function");
|
||||
}
|
||||
Ok(None)
|
||||
} else {
|
||||
let span = p.span;
|
||||
p.span_err(span,
|
||||
"only foreign functions are allowed to be variadic");
|
||||
let span = p.prev_span;
|
||||
if p.token == token::CloseDelim(token::Paren) {
|
||||
// continue parsing to present any further errors
|
||||
p.struct_span_err(
|
||||
span,
|
||||
"only foreign functions are allowed to be variadic"
|
||||
).emit();
|
||||
Ok(Some(dummy_arg(span)))
|
||||
} else {
|
||||
// this function definition looks beyond recovery, stop parsing
|
||||
p.span_err(span,
|
||||
"only foreign functions are allowed to be variadic");
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
variadic = true;
|
||||
Ok(None)
|
||||
} else {
|
||||
match p.parse_arg_general(named_args) {
|
||||
Ok(arg) => Ok(Some(arg)),
|
||||
|
72
src/rustllvm/Linker.cpp
Normal file
72
src/rustllvm/Linker.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#include "llvm/Linker/Linker.h"
|
||||
|
||||
#include "rustllvm.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
struct RustLinker {
|
||||
Linker L;
|
||||
LLVMContext &Ctx;
|
||||
|
||||
RustLinker(Module &M) :
|
||||
L(M),
|
||||
Ctx(M.getContext())
|
||||
{}
|
||||
};
|
||||
|
||||
extern "C" RustLinker*
|
||||
LLVMRustLinkerNew(LLVMModuleRef DstRef) {
|
||||
Module *Dst = unwrap(DstRef);
|
||||
|
||||
auto Ret = llvm::make_unique<RustLinker>(*Dst);
|
||||
return Ret.release();
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
LLVMRustLinkerFree(RustLinker *L) {
|
||||
delete L;
|
||||
}
|
||||
|
||||
extern "C" bool
|
||||
LLVMRustLinkerAdd(RustLinker *L, char *BC, size_t Len) {
|
||||
std::unique_ptr<MemoryBuffer> Buf =
|
||||
MemoryBuffer::getMemBufferCopy(StringRef(BC, Len));
|
||||
|
||||
#if LLVM_VERSION_GE(4, 0)
|
||||
Expected<std::unique_ptr<Module>> SrcOrError =
|
||||
llvm::getLazyBitcodeModule(Buf->getMemBufferRef(), L->Ctx);
|
||||
if (!SrcOrError) {
|
||||
LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto Src = std::move(*SrcOrError);
|
||||
#else
|
||||
ErrorOr<std::unique_ptr<Module>> Src =
|
||||
llvm::getLazyBitcodeModule(std::move(Buf), L->Ctx);
|
||||
if (!Src) {
|
||||
LLVMRustSetLastError(Src.getError().message().c_str());
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_GE(4, 0)
|
||||
if (L->L.linkInModule(std::move(Src))) {
|
||||
#else
|
||||
if (L->L.linkInModule(std::move(Src.get()))) {
|
||||
#endif
|
||||
LLVMRustSetLastError("");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
@ -916,46 +916,6 @@ extern "C" void LLVMRustWriteValueToString(LLVMValueRef V,
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" bool LLVMRustLinkInExternalBitcode(LLVMModuleRef DstRef, char *BC,
|
||||
size_t Len) {
|
||||
Module *Dst = unwrap(DstRef);
|
||||
|
||||
std::unique_ptr<MemoryBuffer> Buf =
|
||||
MemoryBuffer::getMemBufferCopy(StringRef(BC, Len));
|
||||
|
||||
#if LLVM_VERSION_GE(4, 0)
|
||||
Expected<std::unique_ptr<Module>> SrcOrError =
|
||||
llvm::getLazyBitcodeModule(Buf->getMemBufferRef(), Dst->getContext());
|
||||
if (!SrcOrError) {
|
||||
LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto Src = std::move(*SrcOrError);
|
||||
#else
|
||||
ErrorOr<std::unique_ptr<Module>> Src =
|
||||
llvm::getLazyBitcodeModule(std::move(Buf), Dst->getContext());
|
||||
if (!Src) {
|
||||
LLVMRustSetLastError(Src.getError().message().c_str());
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string Err;
|
||||
|
||||
raw_string_ostream Stream(Err);
|
||||
DiagnosticPrinterRawOStream DP(Stream);
|
||||
#if LLVM_VERSION_GE(4, 0)
|
||||
if (Linker::linkModules(*Dst, std::move(Src))) {
|
||||
#else
|
||||
if (Linker::linkModules(*Dst, std::move(Src.get()))) {
|
||||
#endif
|
||||
LLVMRustSetLastError(Err.c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Note that the two following functions look quite similar to the
|
||||
// LLVMGetSectionName function. Sadly, it appears that this function only
|
||||
// returns a char* pointer, which isn't guaranteed to be null-terminated. The
|
||||
|
20
src/test/ui/cast_char.rs
Normal file
20
src/test/ui/cast_char.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![deny(overflowing_literals)]
|
||||
|
||||
fn main() {
|
||||
const XYZ: char = 0x1F888 as char;
|
||||
//~^ ERROR only u8 can be casted into char
|
||||
const XY: char = 129160 as char;
|
||||
//~^ ERROR only u8 can be casted into char
|
||||
const ZYX: char = '\u{01F888}';
|
||||
println!("{}", XYZ);
|
||||
}
|
20
src/test/ui/cast_char.stderr
Normal file
20
src/test/ui/cast_char.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
error: only u8 can be casted into char
|
||||
--> $DIR/cast_char.rs:14:23
|
||||
|
|
||||
14 | const XYZ: char = 0x1F888 as char;
|
||||
| ^^^^^^^^^^^^^^^ help: use a char literal instead: `'/u{1F888}'`
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/cast_char.rs:11:9
|
||||
|
|
||||
11 | #![deny(overflowing_literals)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: only u8 can be casted into char
|
||||
--> $DIR/cast_char.rs:16:22
|
||||
|
|
||||
16 | const XY: char = 129160 as char;
|
||||
| ^^^^^^^^^^^^^^ help: use a char literal instead: `'/u{1F888}'`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
13
src/test/ui/invalid-variadic-function.rs
Normal file
13
src/test/ui/invalid-variadic-function.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern "C" fn foo(x: u8, ...);
|
||||
//~^ ERROR only foreign functions are allowed to be variadic
|
||||
//~| ERROR expected one of `->`, `where`, or `{`, found `;`
|
14
src/test/ui/invalid-variadic-function.stderr
Normal file
14
src/test/ui/invalid-variadic-function.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error: only foreign functions are allowed to be variadic
|
||||
--> $DIR/invalid-variadic-function.rs:11:26
|
||||
|
|
||||
11 | extern "C" fn foo(x: u8, ...);
|
||||
| ^^^
|
||||
|
||||
error: expected one of `->`, `where`, or `{`, found `;`
|
||||
--> $DIR/invalid-variadic-function.rs:11:30
|
||||
|
|
||||
11 | extern "C" fn foo(x: u8, ...);
|
||||
| ^ expected one of `->`, `where`, or `{` here
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
@ -58,9 +58,12 @@ mod imp {
|
||||
fds[0].events = libc::POLLIN;
|
||||
fds[1].fd = err_pipe.as_raw_fd();
|
||||
fds[1].events = libc::POLLIN;
|
||||
loop {
|
||||
let mut nfds = 2;
|
||||
let mut errfd = 1;
|
||||
|
||||
while nfds > 0 {
|
||||
// wait for either pipe to become readable using `select`
|
||||
let r = unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) };
|
||||
let r = unsafe { libc::poll(fds.as_mut_ptr(), nfds, -1) };
|
||||
if r == -1 {
|
||||
let err = io::Error::last_os_error();
|
||||
if err.kind() == io::ErrorKind::Interrupted {
|
||||
@ -86,19 +89,20 @@ mod imp {
|
||||
}
|
||||
}
|
||||
};
|
||||
if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? {
|
||||
out_done = true;
|
||||
}
|
||||
data(true, &mut out, out_done);
|
||||
if !err_done && fds[1].revents != 0 && handle(err_pipe.read_to_end(&mut err))? {
|
||||
if !err_done && fds[errfd].revents != 0 && handle(err_pipe.read_to_end(&mut err))? {
|
||||
err_done = true;
|
||||
nfds -= 1;
|
||||
}
|
||||
data(false, &mut err, err_done);
|
||||
|
||||
if out_done && err_done {
|
||||
return Ok(())
|
||||
if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? {
|
||||
out_done = true;
|
||||
fds[0].fd = err_pipe.as_raw_fd();
|
||||
errfd = 0;
|
||||
nfds -= 1;
|
||||
}
|
||||
data(true, &mut out, out_done);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user