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:
bors 2018-02-15 13:35:20 +00:00
commit 1670a532dd
50 changed files with 806 additions and 212 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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")]

View File

@ -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.

View File

@ -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));

View File

@ -92,6 +92,7 @@
#![feature(unwind_attributes)]
#![feature(doc_spotlight)]
#![feature(rustc_const_unstable)]
#![feature(iterator_repeat_with)]
#[prelude_import]
#[allow(unused)]

View File

@ -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)]

View File

@ -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;
}

View File

@ -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`).

View File

@ -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 }

View File

@ -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;

View File

@ -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)]

View File

@ -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());
}

View File

@ -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,

View File

@ -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);

View File

@ -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)
};

View File

@ -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..] {

View File

@ -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))

View File

@ -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;

View File

@ -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![];

View File

@ -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;

View File

@ -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));

View File

@ -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");

View File

@ -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);
}

View File

@ -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()),
}

View File

@ -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
}

View File

@ -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)),

View File

@ -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

View File

@ -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() {

View File

@ -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; }

View File

@ -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; }

View File

@ -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]

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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()

View File

@ -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;
};

View File

@ -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)

View File

@ -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
View 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;
}

View File

@ -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
View 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);
}

View 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

View 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 `;`

View 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

View File

@ -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(())
}
}