Auto merge of #48531 - kennytm:rollup, r=kennytm

Rollup of 17 pull requests

- Successful merges: #47964, #47970, #48076, #48115, #48166, #48281, #48297, #48302, #48362, #48369, #48489, #48491, #48494, #48517, #48529, #48235, #48330
- Failed merges:
This commit is contained in:
bors 2018-02-25 15:04:40 +00:00
commit 322d7f7b97
41 changed files with 1146 additions and 239 deletions

View File

@ -61,6 +61,11 @@ fn main() {
args.remove(n);
}
if let Some(s) = env::var_os("RUSTC_ERROR_FORMAT") {
args.push("--error-format".into());
args.push(s);
}
// Detect whether or not we're a build script depending on whether --target
// is passed (a bit janky...)
let target = args.windows(2)

View File

@ -294,7 +294,7 @@ def default_build_triple():
raise ValueError('unknown byteorder: {}'.format(sys.byteorder))
# only the n64 ABI is supported, indicate it
ostype += 'abi64'
elif cputype == 'sparcv9' or cputype == 'sparc64':
elif cputype == 'sparc' or cputype == 'sparcv9' or cputype == 'sparc64':
pass
else:
err = "unknown cpu type: {}".format(cputype)

View File

@ -444,10 +444,11 @@ impl<'a> Builder<'a> {
fn run(self, builder: &Builder) -> Interned<PathBuf> {
let compiler = self.compiler;
let lib = if compiler.stage >= 1 && builder.build.config.libdir.is_some() {
builder.build.config.libdir.clone().unwrap()
let config = &builder.build.config;
let lib = if compiler.stage >= 1 && config.libdir_relative().is_some() {
builder.build.config.libdir_relative().unwrap()
} else {
PathBuf::from("lib")
Path::new("lib")
};
let sysroot = builder.sysroot(self.compiler).join(lib)
.join("rustlib").join(self.target).join("lib");
@ -598,6 +599,9 @@ impl<'a> Builder<'a> {
if let Some(target_linker) = self.build.linker(target) {
cargo.env("RUSTC_TARGET_LINKER", target_linker);
}
if let Some(ref error_format) = self.config.rustc_error_format {
cargo.env("RUSTC_ERROR_FORMAT", error_format);
}
if cmd != "build" && cmd != "check" {
cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(self.compiler(2, self.build.build)));
}

View File

@ -516,8 +516,7 @@ fn rustc_cargo_env(build: &Build, cargo: &mut Command) {
.env("CFG_VERSION", build.rust_version())
.env("CFG_PREFIX", build.config.prefix.clone().unwrap_or_default());
let libdir_relative =
build.config.libdir.clone().unwrap_or(PathBuf::from("lib"));
let libdir_relative = build.config.libdir_relative().unwrap_or(Path::new("lib"));
cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative);
// If we're not building a compiler with debugging information then remove

View File

@ -17,7 +17,7 @@ use std::collections::{HashMap, HashSet};
use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::process;
use std::cmp;
@ -57,6 +57,7 @@ pub struct Config {
pub profiler: bool,
pub ignore_git: bool,
pub exclude: Vec<PathBuf>,
pub rustc_error_format: Option<String>,
pub run_host_only: bool,
@ -330,6 +331,7 @@ impl Config {
config.test_miri = false;
config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")];
config.rustc_error_format = flags.rustc_error_format;
config.on_fail = flags.on_fail;
config.stage = flags.stage;
config.src = flags.src;
@ -564,6 +566,17 @@ impl Config {
config
}
/// Try to find the relative path of `libdir`.
pub fn libdir_relative(&self) -> Option<&Path> {
let libdir = self.libdir.as_ref()?;
if libdir.is_relative() {
Some(libdir)
} else {
// Try to make it relative to the prefix.
libdir.strip_prefix(self.prefix.as_ref()?).ok()
}
}
pub fn verbose(&self) -> bool {
self.verbose > 0
}

View File

@ -43,6 +43,7 @@ pub struct Flags {
pub cmd: Subcommand,
pub incremental: bool,
pub exclude: Vec<PathBuf>,
pub rustc_error_format: Option<String>,
}
pub enum Subcommand {
@ -118,6 +119,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
opts.optflag("h", "help", "print this help message");
opts.optflag("", "error-format", "rustc error format");
// fn usage()
let usage = |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! {
@ -370,6 +372,7 @@ Arguments:
verbose: matches.opt_count("verbose"),
stage,
on_fail: matches.opt_str("on-fail"),
rustc_error_format: matches.opt_str("error-format"),
keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()),
build: matches.opt_str("build").map(|s| INTERNER.intern_string(s)),
host: split(matches.opt_strs("host"))

View File

@ -480,9 +480,11 @@ impl Step for Openssl {
"mips64el-unknown-linux-gnuabi64" => "linux64-mips64",
"mipsel-unknown-linux-gnu" => "linux-mips32",
"powerpc-unknown-linux-gnu" => "linux-ppc",
"powerpc-unknown-netbsd" => "BSD-generic32",
"powerpc64-unknown-linux-gnu" => "linux-ppc64",
"powerpc64le-unknown-linux-gnu" => "linux-ppc64le",
"s390x-unknown-linux-gnu" => "linux64-s390x",
"sparc-unknown-linux-gnu" => "linux-sparcv9",
"sparc64-unknown-linux-gnu" => "linux64-sparcv9",
"sparc64-unknown-netbsd" => "BSD-sparc64",
"x86_64-apple-darwin" => "darwin64-x86_64-cc",
@ -490,6 +492,7 @@ impl Step for Openssl {
"x86_64-unknown-freebsd" => "BSD-x86_64",
"x86_64-unknown-dragonfly" => "BSD-x86_64",
"x86_64-unknown-linux-gnu" => "linux-x86_64",
"x86_64-unknown-linux-gnux32" => "linux-x32",
"x86_64-unknown-linux-musl" => "linux-x86_64",
"x86_64-unknown-netbsd" => "BSD-x86_64",
_ => panic!("don't know how to configure OpenSSL for {}", target),

View File

@ -1,77 +0,0 @@
# `entry_and_modify`
The tracking issue for this feature is: [#44733]
[#44733]: https://github.com/rust-lang/rust/issues/44733
------------------------
This introduces a new method for the Entry API of maps
(`std::collections::HashMap` and `std::collections::BTreeMap`), so that
occupied entries can be modified before any potential inserts into the
map.
For example:
```rust
#![feature(entry_and_modify)]
# fn main() {
use std::collections::HashMap;
struct Foo {
new: bool,
}
let mut map: HashMap<&str, Foo> = HashMap::new();
map.entry("quux")
.and_modify(|e| e.new = false)
.or_insert(Foo { new: true });
# }
```
This is not possible with the stable API alone since inserting a default
_before_ modifying the `new` field would mean we would lose the default state:
```rust
# fn main() {
use std::collections::HashMap;
struct Foo {
new: bool,
}
let mut map: HashMap<&str, Foo> = HashMap::new();
map.entry("quux").or_insert(Foo { new: true }).new = false;
# }
```
In the above code the `new` field will never be `true`, even though we only
intended to update that field to `false` for previously extant entries.
To achieve the same effect as `and_modify` we would have to manually match
against the `Occupied` and `Vacant` variants of the `Entry` enum, which is
a little less user-friendly, and much more verbose:
```rust
# fn main() {
use std::collections::HashMap;
use std::collections::hash_map::Entry;
struct Foo {
new: bool,
}
let mut map: HashMap<&str, Foo> = HashMap::new();
match map.entry("quux") {
Entry::Occupied(entry) => {
entry.into_mut().new = false;
},
Entry::Vacant(entry) => {
entry.insert(Foo { new: true });
},
};
# }
```

View File

@ -2114,7 +2114,6 @@ impl<'a, K: Ord, V> Entry<'a, K, V> {
/// # Examples
///
/// ```
/// #![feature(entry_and_modify)]
/// use std::collections::BTreeMap;
///
/// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
@ -2129,7 +2128,7 @@ impl<'a, K: Ord, V> Entry<'a, K, V> {
/// .or_insert(42);
/// assert_eq!(map["poneyland"], 43);
/// ```
#[unstable(feature = "entry_and_modify", issue = "44733")]
#[stable(feature = "entry_and_modify", since = "1.26.0")]
pub fn and_modify<F>(self, mut f: F) -> Self
where F: FnMut(&mut V)
{

View File

@ -12,7 +12,8 @@ use cmp::Ordering;
use ops::Try;
use super::{AlwaysOk, LoopState};
use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, FlatMap, Fuse};
use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, Fuse};
use super::{Flatten, FlatMap, flatten_compat};
use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, Rev};
use super::{Zip, Sum, Product};
use super::{ChainState, FromIterator, ZipImpl};
@ -997,11 +998,15 @@ pub trait Iterator {
/// an extra layer of indirection. `flat_map()` will remove this extra layer
/// on its own.
///
/// You can think of [`flat_map(f)`][flat_map] as the semantic equivalent
/// of [`map`]ping, and then [`flatten`]ing as in `map(f).flatten()`.
///
/// Another way of thinking about `flat_map()`: [`map`]'s closure returns
/// one item for each element, and `flat_map()`'s closure returns an
/// iterator for each element.
///
/// [`map`]: #method.map
/// [`flatten`]: #method.flatten
///
/// # Examples
///
@ -1021,7 +1026,79 @@ pub trait Iterator {
fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
where Self: Sized, U: IntoIterator, F: FnMut(Self::Item) -> U,
{
FlatMap{iter: self, f: f, frontiter: None, backiter: None }
FlatMap { inner: flatten_compat(self.map(f)) }
}
/// Creates an iterator that flattens nested structure.
///
/// This is useful when you have an iterator of iterators or an iterator of
/// things that can be turned into iterators and you want to remove one
/// level of indirection.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(iterator_flatten)]
///
/// let data = vec![vec![1, 2, 3, 4], vec![5, 6]];
/// let flattened = data.into_iter().flatten().collect::<Vec<u8>>();
/// assert_eq!(flattened, &[1, 2, 3, 4, 5, 6]);
/// ```
///
/// Mapping and then flattening:
///
/// ```
/// #![feature(iterator_flatten)]
///
/// let words = ["alpha", "beta", "gamma"];
///
/// // chars() returns an iterator
/// let merged: String = words.iter()
/// .map(|s| s.chars())
/// .flatten()
/// .collect();
/// assert_eq!(merged, "alphabetagamma");
/// ```
///
/// You can also rewrite this in terms of [`flat_map()`] which is preferable
/// in this case since that conveys intent clearer:
///
/// ```
/// let words = ["alpha", "beta", "gamma"];
///
/// // chars() returns an iterator
/// let merged: String = words.iter()
/// .flat_map(|s| s.chars())
/// .collect();
/// assert_eq!(merged, "alphabetagamma");
/// ```
///
/// Flattening once only removes one level of nesting:
///
/// ```
/// #![feature(iterator_flatten)]
///
/// let d3 = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]];
///
/// let d2 = d3.iter().flatten().collect::<Vec<_>>();
/// assert_eq!(d2, [&[1, 2], &[3, 4], &[5, 6], &[7, 8]]);
///
/// let d1 = d3.iter().flatten().flatten().collect::<Vec<_>>();
/// assert_eq!(d1, [&1, &2, &3, &4, &5, &6, &7, &8]);
/// ```
///
/// Here we see that `flatten()` does not perform a "deep" flatten.
/// Instead, only one level of nesting is removed. That is, if you
/// `flatten()` a three-dimensional array the result will be
/// two-dimensional and not one-dimensional. To get a one-dimensional
/// structure, you have to `flatten()` again.
#[inline]
#[unstable(feature = "iterator_flatten", issue = "48213")]
fn flatten(self) -> Flatten<Self>
where Self: Sized, Self::Item: IntoIterator {
Flatten { inner: flatten_compat(self) }
}
/// Creates an iterator which ends after the first [`None`].

View File

@ -2410,12 +2410,15 @@ impl<B, I, St, F> Iterator for Scan<I, St, F> where
/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
pub struct FlatMap<I, U: IntoIterator, F> {
iter: I,
f: F,
frontiter: Option<U::IntoIter>,
backiter: Option<U::IntoIter>,
inner: FlattenCompat<Map<I, F>, <U as IntoIterator>::IntoIter>
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Clone, U: Clone + IntoIterator, F: Clone> Clone for FlatMap<I, U, F>
where <U as IntoIterator>::IntoIter: Clone
{
fn clone(&self) -> Self { FlatMap { inner: self.inner.clone() } }
}
#[stable(feature = "core_impl_debug", since = "1.9.0")]
@ -2423,11 +2426,7 @@ impl<I: fmt::Debug, U: IntoIterator, F> fmt::Debug for FlatMap<I, U, F>
where U::IntoIter: fmt::Debug
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("FlatMap")
.field("iter", &self.iter)
.field("frontiter", &self.frontiter)
.field("backiter", &self.backiter)
.finish()
f.debug_struct("FlatMap").field("inner", &self.inner).finish()
}
}
@ -2437,17 +2436,173 @@ impl<I: Iterator, U: IntoIterator, F> Iterator for FlatMap<I, U, F>
{
type Item = U::Item;
#[inline]
fn next(&mut self) -> Option<U::Item> { self.inner.next() }
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
#[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
{
self.inner.try_fold(init, fold)
}
#[inline]
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.inner.fold(init, fold)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F>
where F: FnMut(I::Item) -> U,
U: IntoIterator,
U::IntoIter: DoubleEndedIterator
{
#[inline]
fn next_back(&mut self) -> Option<U::Item> { self.inner.next_back() }
#[inline]
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
{
self.inner.try_rfold(init, fold)
}
#[inline]
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.inner.rfold(init, fold)
}
}
#[unstable(feature = "fused", issue = "35602")]
impl<I, U, F> FusedIterator for FlatMap<I, U, F>
where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {}
/// An iterator that flattens one level of nesting in an iterator of things
/// that can be turned into iterators.
///
/// This `struct` is created by the [`flatten`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`flatten`]: trait.Iterator.html#method.flatten
/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[unstable(feature = "iterator_flatten", issue = "48213")]
pub struct Flatten<I: Iterator>
where I::Item: IntoIterator {
inner: FlattenCompat<I, <I::Item as IntoIterator>::IntoIter>,
}
#[unstable(feature = "iterator_flatten", issue = "48213")]
impl<I, U> fmt::Debug for Flatten<I>
where I: Iterator + fmt::Debug, U: Iterator + fmt::Debug,
I::Item: IntoIterator<IntoIter = U, Item = U::Item>,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Flatten").field("inner", &self.inner).finish()
}
}
#[unstable(feature = "iterator_flatten", issue = "48213")]
impl<I, U> Clone for Flatten<I>
where I: Iterator + Clone, U: Iterator + Clone,
I::Item: IntoIterator<IntoIter = U, Item = U::Item>,
{
fn clone(&self) -> Self { Flatten { inner: self.inner.clone() } }
}
#[unstable(feature = "iterator_flatten", issue = "48213")]
impl<I, U> Iterator for Flatten<I>
where I: Iterator, U: Iterator,
I::Item: IntoIterator<IntoIter = U, Item = U::Item>
{
type Item = U::Item;
#[inline]
fn next(&mut self) -> Option<U::Item> { self.inner.next() }
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
#[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
{
self.inner.try_fold(init, fold)
}
#[inline]
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.inner.fold(init, fold)
}
}
#[unstable(feature = "iterator_flatten", issue = "48213")]
impl<I, U> DoubleEndedIterator for Flatten<I>
where I: DoubleEndedIterator, U: DoubleEndedIterator,
I::Item: IntoIterator<IntoIter = U, Item = U::Item>
{
#[inline]
fn next_back(&mut self) -> Option<U::Item> { self.inner.next_back() }
#[inline]
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
{
self.inner.try_rfold(init, fold)
}
#[inline]
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.inner.rfold(init, fold)
}
}
#[unstable(feature = "fused", issue = "35602")]
impl<I, U> FusedIterator for Flatten<I>
where I: FusedIterator, U: Iterator,
I::Item: IntoIterator<IntoIter = U, Item = U::Item> {}
/// Adapts an iterator by flattening it, for use in `flatten()` and `flat_map()`.
fn flatten_compat<I, U>(iter: I) -> FlattenCompat<I, U> {
FlattenCompat { iter, frontiter: None, backiter: None }
}
/// Real logic of both `Flatten` and `FlatMap` which simply delegate to
/// this type.
#[derive(Clone, Debug)]
struct FlattenCompat<I, U> {
iter: I,
frontiter: Option<U>,
backiter: Option<U>,
}
impl<I, U> Iterator for FlattenCompat<I, U>
where I: Iterator, U: Iterator,
I::Item: IntoIterator<IntoIter = U, Item = U::Item>
{
type Item = U::Item;
#[inline]
fn next(&mut self) -> Option<U::Item> {
loop {
if let Some(ref mut inner) = self.frontiter {
if let Some(x) = inner.by_ref().next() {
return Some(x)
}
if let elt@Some(_) = inner.next() { return elt }
}
match self.iter.next().map(&mut self.f) {
match self.iter.next() {
None => return self.backiter.as_mut().and_then(|it| it.next()),
next => self.frontiter = next.map(IntoIterator::into_iter),
Some(inner) => self.frontiter = Some(inner.into_iter()),
}
}
}
@ -2473,10 +2628,9 @@ impl<I: Iterator, U: IntoIterator, F> Iterator for FlatMap<I, U, F>
self.frontiter = None;
{
let f = &mut self.f;
let frontiter = &mut self.frontiter;
init = self.iter.try_fold(init, |acc, x| {
let mut mid = f(x).into_iter();
let mut mid = x.into_iter();
let r = mid.try_fold(acc, &mut fold);
*frontiter = Some(mid);
r
@ -2497,27 +2651,23 @@ impl<I: Iterator, U: IntoIterator, F> Iterator for FlatMap<I, U, F>
where Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.frontiter.into_iter()
.chain(self.iter.map(self.f).map(U::into_iter))
.chain(self.iter.map(IntoIterator::into_iter))
.chain(self.backiter)
.fold(init, |acc, iter| iter.fold(acc, &mut fold))
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F> where
F: FnMut(I::Item) -> U,
U: IntoIterator,
U::IntoIter: DoubleEndedIterator
impl<I, U> DoubleEndedIterator for FlattenCompat<I, U>
where I: DoubleEndedIterator, U: DoubleEndedIterator,
I::Item: IntoIterator<IntoIter = U, Item = U::Item>
{
#[inline]
fn next_back(&mut self) -> Option<U::Item> {
loop {
if let Some(ref mut inner) = self.backiter {
if let Some(y) = inner.next_back() {
return Some(y)
}
if let elt@Some(_) = inner.next_back() { return elt }
}
match self.iter.next_back().map(&mut self.f) {
match self.iter.next_back() {
None => return self.frontiter.as_mut().and_then(|it| it.next_back()),
next => self.backiter = next.map(IntoIterator::into_iter),
}
@ -2534,10 +2684,9 @@ impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F> wher
self.backiter = None;
{
let f = &mut self.f;
let backiter = &mut self.backiter;
init = self.iter.try_rfold(init, |acc, x| {
let mut mid = f(x).into_iter();
let mut mid = x.into_iter();
let r = mid.try_rfold(acc, &mut fold);
*backiter = Some(mid);
r
@ -2558,16 +2707,12 @@ impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F> wher
where Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.frontiter.into_iter()
.chain(self.iter.map(self.f).map(U::into_iter))
.chain(self.iter.map(IntoIterator::into_iter))
.chain(self.backiter)
.rfold(init, |acc, iter| iter.rfold(acc, &mut fold))
}
}
#[unstable(feature = "fused", issue = "35602")]
impl<I, U, F> FusedIterator for FlatMap<I, U, F>
where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {}
/// An iterator that yields `None` forever after the underlying iterator
/// yields `None` once.
///

View File

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

View File

@ -73,7 +73,8 @@ pub fn parse_decimal(s: &str) -> ParseResult {
}
Some(&b'.') => {
let (fractional, s) = eat_digits(&s[1..]);
if integral.is_empty() && fractional.is_empty() && s.is_empty() {
if integral.is_empty() && fractional.is_empty() {
// We require at least a single digit before or after the point.
return Invalid;
}

View File

@ -2892,7 +2892,7 @@ impl u8 {
}
/// Checks if the value is an ASCII graphic character:
/// U+0021 '@' ... U+007E '~'.
/// U+0021 '!' ... U+007E '~'.
///
/// # Examples
///

View File

@ -874,6 +874,44 @@ fn test_iterator_flat_map_fold() {
assert_eq!(i, 0);
}
#[test]
fn test_iterator_flatten() {
let xs = [0, 3, 6];
let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8];
let it = xs.iter().map(|&x| (x..).step_by(1).take(3)).flatten();
let mut i = 0;
for x in it {
assert_eq!(x, ys[i]);
i += 1;
}
assert_eq!(i, ys.len());
}
/// Test `Flatten::fold` with items already picked off the front and back,
/// to make sure all parts of the `Flatten` are folded correctly.
#[test]
fn test_iterator_flatten_fold() {
let xs = [0, 3, 6];
let ys = [1, 2, 3, 4, 5, 6, 7];
let mut it = xs.iter().map(|&x| x..x+3).flatten();
assert_eq!(it.next(), Some(0));
assert_eq!(it.next_back(), Some(8));
let i = it.fold(0, |i, x| {
assert_eq!(x, ys[i]);
i + 1
});
assert_eq!(i, ys.len());
let mut it = xs.iter().map(|&x| x..x+3).flatten();
assert_eq!(it.next(), Some(0));
assert_eq!(it.next_back(), Some(8));
let i = it.rfold(ys.len(), |i, x| {
assert_eq!(x, ys[i - 1]);
i - 1
});
assert_eq!(i, 0);
}
#[test]
fn test_inspect() {
let xs = [1, 2, 3, 4];
@ -1287,6 +1325,23 @@ fn test_double_ended_flat_map() {
assert_eq!(it.next_back(), None);
}
#[test]
fn test_double_ended_flatten() {
let u = [0,1];
let v = [5,6,7,8];
let mut it = u.iter().map(|x| &v[*x..v.len()]).flatten();
assert_eq!(it.next_back().unwrap(), &8);
assert_eq!(it.next().unwrap(), &5);
assert_eq!(it.next_back().unwrap(), &7);
assert_eq!(it.next_back().unwrap(), &6);
assert_eq!(it.next_back().unwrap(), &8);
assert_eq!(it.next().unwrap(), &6);
assert_eq!(it.next_back().unwrap(), &7);
assert_eq!(it.next_back(), None);
assert_eq!(it.next(), None);
assert_eq!(it.next_back(), None);
}
#[test]
fn test_double_ended_range() {
assert_eq!((11..14).rev().collect::<Vec<_>>(), [13, 12, 11]);
@ -1978,3 +2033,54 @@ fn test_flat_map_try_folds() {
assert_eq!(iter.try_rfold(0, i8::checked_add), None);
assert_eq!(iter.next_back(), Some(35));
}
#[test]
fn test_flatten_try_folds() {
let f = &|acc, x| i32::checked_add(acc*2/3, x);
let mr = &|x| (5*x)..(5*x + 5);
assert_eq!((0..10).map(mr).flatten().try_fold(7, f), (0..50).try_fold(7, f));
assert_eq!((0..10).map(mr).flatten().try_rfold(7, f), (0..50).try_rfold(7, f));
let mut iter = (0..10).map(mr).flatten();
iter.next(); iter.next_back(); // have front and back iters in progress
assert_eq!(iter.try_rfold(7, f), (1..49).try_rfold(7, f));
let mut iter = (0..10).map(|x| (4*x)..(4*x + 4)).flatten();
assert_eq!(iter.try_fold(0, i8::checked_add), None);
assert_eq!(iter.next(), Some(17));
assert_eq!(iter.try_rfold(0, i8::checked_add), None);
assert_eq!(iter.next_back(), Some(35));
}
#[test]
fn test_functor_laws() {
// identity:
fn identity<T>(x: T) -> T { x }
assert_eq!((0..10).map(identity).sum::<usize>(), (0..10).sum());
// composition:
fn f(x: usize) -> usize { x + 3 }
fn g(x: usize) -> usize { x * 2 }
fn h(x: usize) -> usize { g(f(x)) }
assert_eq!((0..10).map(f).map(g).sum::<usize>(), (0..10).map(h).sum());
}
#[test]
fn test_monad_laws_left_identity() {
fn f(x: usize) -> impl Iterator<Item = usize> {
(0..10).map(move |y| x * y)
}
assert_eq!(once(42).flat_map(f.clone()).sum::<usize>(), f(42).sum());
}
#[test]
fn test_monad_laws_right_identity() {
assert_eq!((0..10).flat_map(|x| once(x)).sum::<usize>(), (0..10).sum());
}
#[test]
fn test_monad_laws_associativity() {
fn f(x: usize) -> impl Iterator<Item = usize> { 0..x }
fn g(x: usize) -> impl Iterator<Item = usize> { (0..x).rev() }
assert_eq!((0..10).flat_map(f).flat_map(g).sum::<usize>(),
(0..10).flat_map(|x| f(x).flat_map(g)).sum::<usize>());
}

View File

@ -25,6 +25,8 @@
#![feature(inclusive_range)]
#![feature(inclusive_range_syntax)]
#![feature(iterator_try_fold)]
#![feature(iterator_flatten)]
#![feature(conservative_impl_trait)]
#![feature(iter_rfind)]
#![feature(iter_rfold)]
#![feature(iterator_repeat_with)]

View File

@ -101,6 +101,12 @@ fn lonely_dot() {
assert!(".".parse::<f64>().is_err());
}
#[test]
fn exponentiated_dot() {
assert!(".e0".parse::<f32>().is_err());
assert!(".e0".parse::<f64>().is_err());
}
#[test]
fn lonely_sign() {
assert!("+".parse::<f32>().is_err());

View File

@ -33,6 +33,7 @@ pub fn opts() -> TargetOptions {
has_rpath: true,
pre_link_args: args,
position_independent_executables: true,
eliminate_frame_pointer: false, // FIXME 43575
relro_level: RelroLevel::Full,
exe_allocation_crate: super::maybe_jemalloc(),
.. Default::default()

View File

@ -146,6 +146,7 @@ supported_targets! {
("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu),
("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu),
("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu),
("sparc-unknown-linux-gnu", sparc_unknown_linux_gnu),
("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu),
("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi),
("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf),
@ -186,6 +187,7 @@ supported_targets! {
("x86_64-unknown-openbsd", x86_64_unknown_openbsd),
("i686-unknown-netbsd", i686_unknown_netbsd),
("powerpc-unknown-netbsd", powerpc_unknown_netbsd),
("sparc64-unknown-netbsd", sparc64_unknown_netbsd),
("x86_64-unknown-netbsd", x86_64_unknown_netbsd),
("x86_64-rumprun-netbsd", x86_64_rumprun_netbsd),

View File

@ -0,0 +1,35 @@
// Copyright 2012 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.
use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::netbsd_base::opts();
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
base.max_atomic_width = Some(32);
// see #36994
base.exe_allocation_crate = None;
Ok(Target {
llvm_target: "powerpc-unknown-netbsd".to_string(),
target_endian: "big".to_string(),
target_pointer_width: "32".to_string(),
target_c_int_width: "32".to_string(),
data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
arch: "powerpc".to_string(),
target_os: "netbsd".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}

View File

@ -0,0 +1,34 @@
// 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.
use LinkerFlavor;
use target::{Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
base.cpu = "v9".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mv8plus".to_string());
base.exe_allocation_crate = None;
Ok(Target {
llvm_target: "sparc-unknown-linux-gnu".to_string(),
target_endian: "big".to_string(),
target_pointer_width: "32".to_string(),
target_c_int_width: "32".to_string(),
data_layout: "E-m:e-p:32:32-i64:64-f128:64-n32-S64".to_string(),
arch: "sparc".to_string(),
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}

View File

@ -40,7 +40,7 @@ use rustc::ty::layout::{self, Align, Size, TyLayout};
use rustc::ty::layout::{HasDataLayout, LayoutOf};
use libc::c_uint;
use std::{cmp, iter};
use std::cmp;
pub use syntax::abi::Abi;
pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
@ -279,30 +279,6 @@ impl Uniform {
pub fn align(&self, cx: &CodegenCx) -> Align {
self.unit.align(cx)
}
pub fn llvm_type(&self, cx: &CodegenCx) -> Type {
let llunit = self.unit.llvm_type(cx);
if self.total <= self.unit.size {
return llunit;
}
let count = self.total.bytes() / self.unit.size.bytes();
let rem_bytes = self.total.bytes() % self.unit.size.bytes();
if rem_bytes == 0 {
return Type::array(&llunit, count);
}
// Only integers can be really split further.
assert_eq!(self.unit.kind, RegKind::Integer);
let args: Vec<_> = (0..count).map(|_| llunit)
.chain(iter::once(Type::ix(cx, rem_bytes * 8)))
.collect();
Type::struct_(cx, &args, false)
}
}
pub trait LayoutExt<'tcx> {
@ -405,55 +381,81 @@ impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum CastTarget {
Uniform(Uniform),
Pair(Reg, Reg)
pub struct CastTarget {
pub prefix: [Option<RegKind>; 8],
pub prefix_chunk: Size,
pub rest: Uniform,
}
impl From<Reg> for CastTarget {
fn from(unit: Reg) -> CastTarget {
CastTarget::Uniform(Uniform::from(unit))
CastTarget::from(Uniform::from(unit))
}
}
impl From<Uniform> for CastTarget {
fn from(uniform: Uniform) -> CastTarget {
CastTarget::Uniform(uniform)
CastTarget {
prefix: [None; 8],
prefix_chunk: Size::from_bytes(0),
rest: uniform
}
}
}
impl CastTarget {
pub fn size(&self, cx: &CodegenCx) -> Size {
match *self {
CastTarget::Uniform(u) => u.total,
CastTarget::Pair(a, b) => {
(a.size.abi_align(a.align(cx)) + b.size)
.abi_align(self.align(cx))
}
pub fn pair(a: Reg, b: Reg) -> CastTarget {
CastTarget {
prefix: [Some(a.kind), None, None, None, None, None, None, None],
prefix_chunk: a.size,
rest: Uniform::from(b)
}
}
pub fn size(&self, cx: &CodegenCx) -> Size {
(self.prefix_chunk * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
.abi_align(self.rest.align(cx)) + self.rest.total
}
pub fn align(&self, cx: &CodegenCx) -> Align {
match *self {
CastTarget::Uniform(u) => u.align(cx),
CastTarget::Pair(a, b) => {
cx.data_layout().aggregate_align
.max(a.align(cx))
.max(b.align(cx))
}
}
self.prefix.iter()
.filter_map(|x| x.map(|kind| Reg { kind: kind, size: self.prefix_chunk }.align(cx)))
.fold(cx.data_layout().aggregate_align.max(self.rest.align(cx)),
|acc, align| acc.max(align))
}
pub fn llvm_type(&self, cx: &CodegenCx) -> Type {
match *self {
CastTarget::Uniform(u) => u.llvm_type(cx),
CastTarget::Pair(a, b) => {
Type::struct_(cx, &[
a.llvm_type(cx),
b.llvm_type(cx)
], false)
let rest_ll_unit = self.rest.unit.llvm_type(cx);
let rest_count = self.rest.total.bytes() / self.rest.unit.size.bytes();
let rem_bytes = self.rest.total.bytes() % self.rest.unit.size.bytes();
if self.prefix.iter().all(|x| x.is_none()) {
// Simplify to a single unit when there is no prefix and size <= unit size
if self.rest.total <= self.rest.unit.size {
return rest_ll_unit;
}
// Simplify to array when all chunks are the same size and type
if rem_bytes == 0 {
return Type::array(&rest_ll_unit, rest_count);
}
}
// Create list of fields in the main structure
let mut args: Vec<_> =
self.prefix.iter().flat_map(|option_kind| option_kind.map(
|kind| Reg { kind: kind, size: self.prefix_chunk }.llvm_type(cx)))
.chain((0..rest_count).map(|_| rest_ll_unit))
.collect();
// Append final integer
if rem_bytes != 0 {
// Only integers can be really split further.
assert_eq!(self.rest.unit.kind, RegKind::Integer);
args.push(Type::ix(cx, rem_bytes * 8));
}
Type::struct_(cx, &args, false)
}
}

View File

@ -109,6 +109,10 @@ impl Command {
// extensions
pub fn get_args(&self) -> &[OsString] {
&self.args
}
pub fn take_args(&mut self) -> Vec<OsString> {
mem::replace(&mut self.args, Vec::new())
}

View File

@ -700,9 +700,6 @@ fn link_natively(sess: &Session,
prog = time(sess.time_passes(), "running linker", || {
exec_linker(sess, &mut cmd, tmpdir)
});
if !retry_on_segfault || i > 3 {
break
}
let output = match prog {
Ok(ref output) => output,
Err(_) => break,
@ -713,6 +710,31 @@ fn link_natively(sess: &Session,
let mut out = output.stderr.clone();
out.extend(&output.stdout);
let out = String::from_utf8_lossy(&out);
// Check to see if the link failed with "unrecognized command line option:
// '-no-pie'" for gcc or "unknown argument: '-no-pie'" for clang. If so,
// reperform the link step without the -no-pie option. This is safe because
// if the linker doesn't support -no-pie then it should not default to
// linking executables as pie. Different versions of gcc seem to use
// different quotes in the error message so don't check for them.
if sess.target.target.options.linker_is_gnu &&
(out.contains("unrecognized command line option") ||
out.contains("unknown argument")) &&
out.contains("-no-pie") &&
cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie") {
info!("linker output: {:?}", out);
warn!("Linker does not support -no-pie command line option. Retrying without.");
for arg in cmd.take_args() {
if arg.to_string_lossy() != "-no-pie" {
cmd.arg(arg);
}
}
info!("{:?}", &cmd);
continue;
}
if !retry_on_segfault || i > 3 {
break
}
let msg_segv = "clang: error: unable to execute command: Segmentation fault: 11";
let msg_bus = "clang: error: unable to execute command: Bus error: 10";
if !(out.contains(msg_segv) || out.contains(msg_bus)) {
@ -949,16 +971,30 @@ fn link_args(cmd: &mut Linker,
let used_link_args = &trans.crate_info.link_args;
if crate_type == config::CrateTypeExecutable &&
t.options.position_independent_executables {
let empty_vec = Vec::new();
let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec);
let more_args = &sess.opts.cg.link_arg;
let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter());
if crate_type == config::CrateTypeExecutable {
let mut position_independent_executable = false;
if get_reloc_model(sess) == llvm::RelocMode::PIC
&& !sess.crt_static() && !args.any(|x| *x == "-static") {
if t.options.position_independent_executables {
let empty_vec = Vec::new();
let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec);
let more_args = &sess.opts.cg.link_arg;
let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter());
if get_reloc_model(sess) == llvm::RelocMode::PIC
&& !sess.crt_static() && !args.any(|x| *x == "-static") {
position_independent_executable = true;
}
}
if position_independent_executable {
cmd.position_independent_executable();
} else {
// recent versions of gcc can be configured to generate position
// independent executables by default. We have to pass -no-pie to
// explicitly turn that off.
if sess.target.target.options.linker_is_gnu {
cmd.no_position_independent_executable();
}
}
}

View File

@ -105,6 +105,7 @@ pub trait Linker {
fn add_object(&mut self, path: &Path);
fn gc_sections(&mut self, keep_metadata: bool);
fn position_independent_executable(&mut self);
fn no_position_independent_executable(&mut self);
fn partial_relro(&mut self);
fn full_relro(&mut self);
fn optimize(&mut self);
@ -179,6 +180,7 @@ impl<'a> Linker for GccLinker<'a> {
fn output_filename(&mut self, path: &Path) { self.cmd.arg("-o").arg(path); }
fn add_object(&mut self, path: &Path) { self.cmd.arg(path); }
fn position_independent_executable(&mut self) { self.cmd.arg("-pie"); }
fn no_position_independent_executable(&mut self) { self.cmd.arg("-no-pie"); }
fn partial_relro(&mut self) { self.linker_arg("-z,relro"); }
fn full_relro(&mut self) { self.linker_arg("-z,relro,-z,now"); }
fn build_static_executable(&mut self) { self.cmd.arg("-static"); }
@ -439,6 +441,10 @@ impl<'a> Linker for MsvcLinker<'a> {
// noop
}
fn no_position_independent_executable(&mut self) {
// noop
}
fn partial_relro(&mut self) {
// noop
}
@ -647,6 +653,10 @@ impl<'a> Linker for EmLinker<'a> {
// noop
}
fn no_position_independent_executable(&mut self) {
// noop
}
fn partial_relro(&mut self) {
// noop
}

View File

@ -8,50 +8,160 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use abi::{ArgType, FnType, LayoutExt, Reg, Uniform};
use abi::{ArgAttribute, ArgType, CastTarget, FnType, LayoutExt, PassMode, Reg, RegKind, Uniform};
use context::CodegenCx;
use rustc::ty::layout::{self, Size};
use rustc::ty::layout::Size;
fn extend_integer_width_mips(arg: &mut ArgType, bits: u64) {
// Always sign extend u32 values on 64-bit mips
if let layout::Abi::Scalar(ref scalar) = arg.layout.abi {
if let layout::Int(i, signed) = scalar.value {
if !signed && i.size().bits() == 32 {
if let PassMode::Direct(ref mut attrs) = arg.mode {
attrs.set(ArgAttribute::SExt);
return;
}
}
}
}
fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
ret: &mut ArgType<'tcx>,
offset: &mut Size) {
if !ret.layout.is_aggregate() {
ret.extend_integer_width_to(64);
arg.extend_integer_width_to(bits);
}
fn bits_to_int_reg(bits: u64) -> Reg {
if bits <= 8 {
Reg::i8()
} else if bits <= 16 {
Reg::i16()
} else if bits <= 32 {
Reg::i32()
} else {
ret.make_indirect();
*offset += cx.tcx.data_layout.pointer_size;
Reg::i64()
}
}
fn classify_arg_ty(cx: &CodegenCx, arg: &mut ArgType, offset: &mut Size) {
let dl = &cx.tcx.data_layout;
let size = arg.layout.size;
let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align);
fn float_reg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &ArgType<'tcx>, i: usize) -> Option<Reg> {
match ret.layout.field(cx, i).abi {
layout::Abi::Scalar(ref scalar) => match scalar.value {
layout::F32 => Some(Reg::f32()),
layout::F64 => Some(Reg::f64()),
_ => None
},
_ => None
}
}
if arg.layout.is_aggregate() {
arg.cast_to(Uniform {
unit: Reg::i64(),
total: size
});
if !offset.is_abi_aligned(align) {
arg.pad_with(Reg::i64());
}
} else {
arg.extend_integer_width_to(64);
fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
if !ret.layout.is_aggregate() {
extend_integer_width_mips(ret, 64);
return;
}
*offset = offset.abi_align(align) + size.abi_align(align);
let size = ret.layout.size;
let bits = size.bits();
if bits <= 128 {
// Unlike other architectures which return aggregates in registers, MIPS n64 limits the
// use of float registers to structures (not unions) containing exactly one or two
// float fields.
if let layout::FieldPlacement::Arbitrary { .. } = ret.layout.fields {
if ret.layout.fields.count() == 1 {
if let Some(reg) = float_reg(cx, ret, 0) {
ret.cast_to(reg);
return;
}
} else if ret.layout.fields.count() == 2 {
if let Some(reg0) = float_reg(cx, ret, 0) {
if let Some(reg1) = float_reg(cx, ret, 1) {
ret.cast_to(CastTarget::pair(reg0, reg1));
return;
}
}
}
}
// Cast to a uniform int structure
ret.cast_to(Uniform {
unit: bits_to_int_reg(bits),
total: size
});
} else {
ret.make_indirect();
}
}
fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
if !arg.layout.is_aggregate() {
extend_integer_width_mips(arg, 64);
return;
}
let dl = &cx.tcx.data_layout;
let size = arg.layout.size;
let mut prefix = [None; 8];
let mut prefix_index = 0;
match arg.layout.fields {
layout::FieldPlacement::Array { .. } => {
// Arrays are passed indirectly
arg.make_indirect();
return;
}
layout::FieldPlacement::Union(_) => {
// Unions and are always treated as a series of 64-bit integer chunks
},
layout::FieldPlacement::Arbitrary { .. } => {
// Structures are split up into a series of 64-bit integer chunks, but any aligned
// doubles not part of another aggregate are passed as floats.
let mut last_offset = Size::from_bytes(0);
for i in 0..arg.layout.fields.count() {
let field = arg.layout.field(cx, i);
let offset = arg.layout.fields.offset(i);
// We only care about aligned doubles
if let layout::Abi::Scalar(ref scalar) = field.abi {
if let layout::F64 = scalar.value {
if offset.is_abi_aligned(dl.f64_align) {
// Insert enough integers to cover [last_offset, offset)
assert!(last_offset.is_abi_aligned(dl.f64_align));
for _ in 0..((offset - last_offset).bits() / 64)
.min((prefix.len() - prefix_index) as u64) {
prefix[prefix_index] = Some(RegKind::Integer);
prefix_index += 1;
}
if prefix_index == prefix.len() {
break;
}
prefix[prefix_index] = Some(RegKind::Float);
prefix_index += 1;
last_offset = offset + Reg::f64().size;
}
}
}
}
}
};
// Extract first 8 chunks as the prefix
let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
arg.cast_to(CastTarget {
prefix: prefix,
prefix_chunk: Size::from_bytes(8),
rest: Uniform { unit: Reg::i64(), total: rest_size }
});
}
pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) {
let mut offset = Size::from_bytes(0);
if !fty.ret.is_ignore() {
classify_ret_ty(cx, &mut fty.ret, &mut offset);
classify_ret_ty(cx, &mut fty.ret);
}
for arg in &mut fty.args {
if arg.is_ignore() { continue; }
classify_arg_ty(cx, arg, &mut offset);
classify_arg_ty(cx, arg);
}
}

View File

@ -171,7 +171,7 @@ fn cast_target(cls: &[Option<Class>], size: Size) -> CastTarget {
let mut target = CastTarget::from(lo);
if size > offset {
if let Some(hi) = reg_component(cls, &mut i, size - offset) {
target = CastTarget::Pair(lo, hi);
target = CastTarget::pair(lo, hi);
}
}
assert_eq!(reg_component(cls, &mut i, Size::from_bytes(0)), None);

View File

@ -75,26 +75,25 @@ unsafe fn configure_llvm(sess: &Session) {
llvm_args.as_ptr());
}
// WARNING: the features must be known to LLVM or the feature
// detection code will walk past the end of the feature array,
// leading to crashes.
// WARNING: the features after applying `to_llvm_feature` must be known
// to LLVM or the feature detection code will walk past the end of the feature
// array, leading to crashes.
const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"];
const AARCH64_WHITELIST: &'static [&'static str] = &["neon", "v7"];
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 X86_WHITELIST: &'static [&'static str] = &["aes", "avx", "avx2", "avx512bw",
"avx512cd", "avx512dq", "avx512er",
"avx512f", "avx512ifma", "avx512pf",
"avx512vbmi", "avx512vl", "avx512vpopcntdq",
"bmi", "bmi2", "fma", "fxsr",
"lzcnt", "mmx", "pclmulqdq",
"popcnt", "rdrand", "rdseed",
"sse", "sse2", "sse3", "sse4.1",
"sse4.2", "sse4a", "ssse3",
"tbm", "xsave", "xsavec",
"xsaveopt", "xsaves"];
const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx", "hvx-double"];
@ -108,6 +107,7 @@ const MIPS_WHITELIST: &'static [&'static str] = &["msa"];
pub fn to_llvm_feature(s: &str) -> &str {
match s {
"pclmulqdq" => "pclmul",
"rdrand" => "rdrnd",
s => s,
}
}

View File

@ -245,7 +245,7 @@ pub trait AsciiExt {
fn is_ascii_punctuation(&self) -> bool { unimplemented!(); }
/// Checks if the value is an ASCII graphic character:
/// U+0021 '@' ... U+007E '~'.
/// U+0021 '!' ... U+007E '~'.
/// For strings, true if all characters in the string are
/// ASCII graphic characters.
///

View File

@ -2082,7 +2082,6 @@ impl<'a, K, V> Entry<'a, K, V> {
/// # Examples
///
/// ```
/// #![feature(entry_and_modify)]
/// use std::collections::HashMap;
///
/// let mut map: HashMap<&str, u32> = HashMap::new();
@ -2097,7 +2096,7 @@ impl<'a, K, V> Entry<'a, K, V> {
/// .or_insert(42);
/// assert_eq!(map["poneyland"], 43);
/// ```
#[unstable(feature = "entry_and_modify", issue = "44733")]
#[stable(feature = "entry_and_modify", since = "1.26.0")]
pub fn and_modify<F>(self, mut f: F) -> Self
where F: FnMut(&mut V)
{

View File

@ -1545,6 +1545,26 @@ mod tests {
drop(listener);
}
// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
// when passed zero Durations
#[test]
fn test_timeout_zero_duration() {
let addr = next_test_ip4();
let listener = t!(TcpListener::bind(&addr));
let stream = t!(TcpStream::connect(&addr));
let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
drop(listener);
}
#[test]
fn nodelay() {
let addr = next_test_ip4();

View File

@ -1024,6 +1024,23 @@ mod tests {
assert!(start.elapsed() > Duration::from_millis(400));
}
// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
// when passed zero Durations
#[test]
fn test_timeout_zero_duration() {
let addr = next_test_ip4();
let socket = t!(UdpSocket::bind(&addr));
let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
}
#[test]
fn connect_send_recv() {
let addr = next_test_ip4();

View File

@ -14,7 +14,7 @@ use sync::{mutex, MutexGuard, PoisonError};
use sys_common::condvar as sys;
use sys_common::mutex as sys_mutex;
use sys_common::poison::{self, LockResult};
use time::Duration;
use time::{Duration, Instant};
/// A type indicating whether a timed wait on a condition variable returned
/// due to a time out or not.
@ -221,6 +221,64 @@ impl Condvar {
}
}
/// Blocks the current thread until this condition variable receives a
/// notification and the required condition is met. Spurious wakeups are
/// ignored and this function will only return once the condition has been
/// met.
///
/// This function will atomically unlock the mutex specified (represented by
/// `guard`) and block the current thread. This means that any calls
/// to [`notify_one`] or [`notify_all`] which happen logically after the
/// mutex is unlocked are candidates to wake this thread up. When this
/// function call returns, the lock specified will have been re-acquired.
///
/// # Errors
///
/// This function will return an error if the mutex being waited on is
/// poisoned when this thread re-acquires the lock. For more information,
/// see information about [poisoning] on the [`Mutex`] type.
///
/// [`notify_one`]: #method.notify_one
/// [`notify_all`]: #method.notify_all
/// [poisoning]: ../sync/struct.Mutex.html#poisoning
/// [`Mutex`]: ../sync/struct.Mutex.html
///
/// # Examples
///
/// ```
/// #![feature(wait_until)]
///
/// use std::sync::{Arc, Mutex, Condvar};
/// use std::thread;
///
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = pair.clone();
///
/// thread::spawn(move|| {
/// let &(ref lock, ref cvar) = &*pair2;
/// let mut started = lock.lock().unwrap();
/// *started = true;
/// // We notify the condvar that the value has changed.
/// cvar.notify_one();
/// });
///
/// // Wait for the thread to start up.
/// let &(ref lock, ref cvar) = &*pair;
/// // As long as the value inside the `Mutex` is false, we wait.
/// let _guard = cvar.wait_until(lock.lock().unwrap(), |started| { *started }).unwrap();
/// ```
#[unstable(feature = "wait_until", issue = "47960")]
pub fn wait_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>,
mut condition: F)
-> LockResult<MutexGuard<'a, T>>
where F: FnMut(&mut T) -> bool {
while !condition(&mut *guard) {
guard = self.wait(guard)?;
}
Ok(guard)
}
/// Waits on this condition variable for a notification, timing out after a
/// specified duration.
///
@ -295,7 +353,15 @@ impl Condvar {
///
/// Note that the best effort is made to ensure that the time waited is
/// measured with a monotonic clock, and not affected by the changes made to
/// the system time.
/// the system time. This function is susceptible to spurious wakeups.
/// Condition variables normally have a boolean predicate associated with
/// them, and the predicate must always be checked each time this function
/// returns to protect against spurious wakeups. Additionally, it is
/// typically desirable for the time-out to not exceed some duration in
/// spite of spurious wakes, thus the sleep-duration is decremented by the
/// amount slept. Alternatively, use the `wait_timeout_until` method
/// to wait until a condition is met with a total time-out regardless
/// of spurious wakes.
///
/// The returned [`WaitTimeoutResult`] value indicates if the timeout is
/// known to have elapsed.
@ -304,6 +370,7 @@ impl Condvar {
/// returns, regardless of whether the timeout elapsed or not.
///
/// [`wait`]: #method.wait
/// [`wait_timeout_until`]: #method.wait_timeout_until
/// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html
///
/// # Examples
@ -355,6 +422,80 @@ impl Condvar {
}
}
/// Waits on this condition variable for a notification, timing out after a
/// specified duration. Spurious wakes will not cause this function to
/// return.
///
/// The semantics of this function are equivalent to [`wait_until`] except
/// that the thread will be blocked for roughly no longer than `dur`. This
/// method should not be used for precise timing due to anomalies such as
/// preemption or platform differences that may not cause the maximum
/// amount of time waited to be precisely `dur`.
///
/// Note that the best effort is made to ensure that the time waited is
/// measured with a monotonic clock, and not affected by the changes made to
/// the system time.
///
/// The returned [`WaitTimeoutResult`] value indicates if the timeout is
/// known to have elapsed without the condition being met.
///
/// Like [`wait_until`], the lock specified will be re-acquired when this
/// function returns, regardless of whether the timeout elapsed or not.
///
/// [`wait_until`]: #method.wait_until
/// [`wait_timeout`]: #method.wait_timeout
/// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html
///
/// # Examples
///
/// ```
/// #![feature(wait_timeout_until)]
///
/// use std::sync::{Arc, Mutex, Condvar};
/// use std::thread;
/// use std::time::Duration;
///
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = pair.clone();
///
/// thread::spawn(move|| {
/// let &(ref lock, ref cvar) = &*pair2;
/// let mut started = lock.lock().unwrap();
/// *started = true;
/// // We notify the condvar that the value has changed.
/// cvar.notify_one();
/// });
///
/// // wait for the thread to start up
/// let &(ref lock, ref cvar) = &*pair;
/// let result = cvar.wait_timeout_until(
/// lock.lock().unwrap(),
/// Duration::from_millis(100),
/// |&mut started| started,
/// ).unwrap();
/// if result.1.timed_out() {
/// // timed-out without the condition ever evaluating to true.
/// }
/// // access the locked mutex via result.0
/// ```
#[unstable(feature = "wait_timeout_until", issue = "47960")]
pub fn wait_timeout_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>,
dur: Duration, mut condition: F)
-> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
where F: FnMut(&mut T) -> bool {
let start = Instant::now();
loop {
if condition(&mut *guard) {
return Ok((guard, WaitTimeoutResult(false)));
}
let timeout = match dur.checked_sub(start.elapsed()) {
Some(timeout) => timeout,
None => return Ok((guard, WaitTimeoutResult(true))),
};
guard = self.wait_timeout(guard, timeout)?.0;
}
}
/// Wakes up one blocked thread on this condvar.
///
/// If there is a blocked thread on this condition variable, then it will
@ -480,6 +621,7 @@ impl Drop for Condvar {
#[cfg(test)]
mod tests {
/// #![feature(wait_until)]
use sync::mpsc::channel;
use sync::{Condvar, Mutex, Arc};
use sync::atomic::{AtomicBool, Ordering};
@ -548,6 +690,29 @@ mod tests {
}
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_until() {
let pair = Arc::new((Mutex::new(false), Condvar::new()));
let pair2 = pair.clone();
// Inside of our lock, spawn a new thread, and then wait for it to start.
thread::spawn(move|| {
let &(ref lock, ref cvar) = &*pair2;
let mut started = lock.lock().unwrap();
*started = true;
// We notify the condvar that the value has changed.
cvar.notify_one();
});
// Wait for the thread to start up.
let &(ref lock, ref cvar) = &*pair;
let guard = cvar.wait_until(lock.lock().unwrap(), |started| {
*started
});
assert!(*guard.unwrap());
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_wait() {
@ -567,6 +732,53 @@ mod tests {
}
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_until_wait() {
let m = Arc::new(Mutex::new(()));
let c = Arc::new(Condvar::new());
let g = m.lock().unwrap();
let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(1), |_| { false }).unwrap();
// no spurious wakeups. ensure it timed-out
assert!(wait.timed_out());
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_until_instant_satisfy() {
let m = Arc::new(Mutex::new(()));
let c = Arc::new(Condvar::new());
let g = m.lock().unwrap();
let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(0), |_| { true }).unwrap();
// ensure it didn't time-out even if we were not given any time.
assert!(!wait.timed_out());
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_until_wake() {
let pair = Arc::new((Mutex::new(false), Condvar::new()));
let pair_copy = pair.clone();
let &(ref m, ref c) = &*pair;
let g = m.lock().unwrap();
let _t = thread::spawn(move || {
let &(ref lock, ref cvar) = &*pair_copy;
let mut started = lock.lock().unwrap();
thread::sleep(Duration::from_millis(1));
*started = true;
cvar.notify_one();
});
let (g2, wait) = c.wait_timeout_until(g, Duration::from_millis(u64::MAX), |&mut notified| {
notified
}).unwrap();
// ensure it didn't time-out even if we were not given any time.
assert!(!wait.timed_out());
assert!(*g2);
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_wake() {

View File

@ -9,7 +9,7 @@
// except according to those terms.
use cmp;
use io::{Error, ErrorKind, Result};
use io::{self, Error, ErrorKind, Result};
use mem;
use net::{SocketAddr, Shutdown};
use path::Path;
@ -130,6 +130,10 @@ impl TcpStream {
pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
let file = self.0.dup(b"read_timeout")?;
if let Some(duration) = duration_option {
if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
return Err(io::Error::new(io::ErrorKind::InvalidInput,
"cannot set a 0 duration timeout"));
}
file.write(&TimeSpec {
tv_sec: duration.as_secs() as i64,
tv_nsec: duration.subsec_nanos() as i32
@ -143,6 +147,10 @@ impl TcpStream {
pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
let file = self.0.dup(b"write_timeout")?;
if let Some(duration) = duration_option {
if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
return Err(io::Error::new(io::ErrorKind::InvalidInput,
"cannot set a 0 duration timeout"));
}
file.write(&TimeSpec {
tv_sec: duration.as_secs() as i64,
tv_nsec: duration.subsec_nanos() as i32

View File

@ -10,7 +10,7 @@
use cell::UnsafeCell;
use cmp;
use io::{Error, ErrorKind, Result};
use io::{self, Error, ErrorKind, Result};
use mem;
use net::{SocketAddr, Ipv4Addr, Ipv6Addr};
use path::Path;
@ -179,6 +179,10 @@ impl UdpSocket {
pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
let file = self.0.dup(b"read_timeout")?;
if let Some(duration) = duration_option {
if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
return Err(io::Error::new(io::ErrorKind::InvalidInput,
"cannot set a 0 duration timeout"));
}
file.write(&TimeSpec {
tv_sec: duration.as_secs() as i64,
tv_nsec: duration.subsec_nanos() as i32
@ -192,6 +196,10 @@ impl UdpSocket {
pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
let file = self.0.dup(b"write_timeout")?;
if let Some(duration) = duration_option {
if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
return Err(io::Error::new(io::ErrorKind::InvalidInput,
"cannot set a 0 duration timeout"));
}
file.write(&TimeSpec {
tv_sec: duration.as_secs() as i64,
tv_nsec: duration.subsec_nanos() as i32

View File

@ -1410,7 +1410,7 @@ impl IntoRawFd for UnixDatagram {
#[cfg(all(test, not(target_os = "emscripten")))]
mod test {
use thread;
use io;
use io::{self, ErrorKind};
use io::prelude::*;
use time::Duration;
use sys_common::io::test::tmpdir;
@ -1613,6 +1613,27 @@ mod test {
assert!(kind == io::ErrorKind::WouldBlock || kind == io::ErrorKind::TimedOut);
}
// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
// when passed zero Durations
#[test]
fn test_unix_stream_timeout_zero_duration() {
let dir = tmpdir();
let socket_path = dir.path().join("sock");
let listener = or_panic!(UnixListener::bind(&socket_path));
let stream = or_panic!(UnixStream::connect(&socket_path));
let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
drop(listener);
}
#[test]
fn test_unix_datagram() {
let dir = tmpdir();
@ -1712,6 +1733,24 @@ mod test {
thread.join().unwrap();
}
// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
// when passed zero Durations
#[test]
fn test_unix_datagram_timeout_zero_duration() {
let dir = tmpdir();
let path = dir.path().join("sock");
let datagram = or_panic!(UnixDatagram::bind(&path));
let result = datagram.set_write_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
let result = datagram.set_read_timeout(Some(Duration::new(0, 0)));
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidInput);
}
#[test]
fn abstract_namespace_not_allowed() {
assert!(UnixStream::connect("\0asdf").is_err());

View File

@ -1332,7 +1332,7 @@ impl char {
}
/// Checks if the value is an ASCII graphic character:
/// U+0021 '@' ... U+007E '~'.
/// U+0021 '!' ... U+007E '~'.
///
/// # Examples
///

View File

@ -36,6 +36,8 @@ ifeq ($(filter powerpc,$(LLVM_COMPONENTS)),powerpc)
nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add
$(RUSTC) --target=powerpc64le-unknown-linux-gnu atomic_lock_free.rs
nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add
endif
ifeq ($(filter systemz,$(LLVM_COMPONENTS)),systemz)
$(RUSTC) --target=s390x-unknown-linux-gnu atomic_lock_free.rs
nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add
endif

View File

@ -0,0 +1,80 @@
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-ambig.rs:40:11
|
40 | foo!(a?a?a); //~ ERROR no rules expected the token `?`
| ^
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-ambig.rs:41:11
|
41 | foo!(a?a); //~ ERROR no rules expected the token `?`
| ^
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-ambig.rs:42:11
|
42 | foo!(a?); //~ ERROR no rules expected the token `?`
| ^
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-ambig.rs:43:11
|
43 | baz!(a?a?a); //~ ERROR no rules expected the token `?`
| ^
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-ambig.rs:44:11
|
44 | baz!(a?a); //~ ERROR no rules expected the token `?`
| ^
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-ambig.rs:45:11
|
45 | baz!(a?); //~ ERROR no rules expected the token `?`
| ^
error: unexpected end of macro invocation
--> $DIR/macro-at-most-once-rep-ambig.rs:46:11
|
46 | baz!(a,); //~ ERROR unexpected end of macro invocation
| ^
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-ambig.rs:47:11
|
47 | baz!(a?a?a,); //~ ERROR no rules expected the token `?`
| ^
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-ambig.rs:48:11
|
48 | baz!(a?a,); //~ ERROR no rules expected the token `?`
| ^
error: no rules expected the token `?`
--> $DIR/macro-at-most-once-rep-ambig.rs:49:11
|
49 | baz!(a?,); //~ ERROR no rules expected the token `?`
| ^
error: unexpected end of macro invocation
--> $DIR/macro-at-most-once-rep-ambig.rs:50:5
|
50 | barplus!(); //~ ERROR unexpected end of macro invocation
| ^^^^^^^^^^^
error: unexpected end of macro invocation
--> $DIR/macro-at-most-once-rep-ambig.rs:51:15
|
51 | barplus!(a?); //~ ERROR unexpected end of macro invocation
| ^
error: unexpected end of macro invocation
--> $DIR/macro-at-most-once-rep-ambig.rs:52:15
|
52 | barstar!(a?); //~ ERROR unexpected end of macro invocation
| ^
error: aborting due to 13 previous errors

View File

@ -86,6 +86,7 @@ static TARGETS: &'static [&'static str] = &[
"powerpc64-unknown-linux-gnu",
"powerpc64le-unknown-linux-gnu",
"s390x-unknown-linux-gnu",
"sparc-unknown-linux-gnu",
"sparc64-unknown-linux-gnu",
"sparcv9-sun-solaris",
"wasm32-unknown-emscripten",