Auto merge of #49684 - kennytm:rollup, r=kennytm
Rollup of 9 pull requests Successful merges: - #48658 (Add a generic CAS loop to std::sync::Atomic*) - #49253 (Take the original extra-filename passed to a crate into account when resolving it as a dependency) - #49345 (RFC 2008: Finishing Touches) - #49432 (Flush executables to disk after linkage) - #49496 (Add more vec![... ; n] optimizations) - #49563 (add a dist builder to build rust-std components for the THUMB targets) - #49654 (Host compiler documentation: Include private items) - #49667 (Add more features to rust_2018_preview) - #49674 (ci: Remove x86_64-gnu-incremental builder) Failed merges:
This commit is contained in:
commit
56714acc5e
@ -171,8 +171,6 @@ matrix:
|
||||
if: branch = auto
|
||||
- env: IMAGE=x86_64-gnu-distcheck
|
||||
if: branch = auto
|
||||
- env: IMAGE=x86_64-gnu-incremental
|
||||
if: branch = auto
|
||||
|
||||
- stage: publish toolstate
|
||||
if: branch = master AND type = push
|
||||
|
@ -140,48 +140,58 @@ pub fn std_cargo(build: &Builder,
|
||||
compiler: &Compiler,
|
||||
target: Interned<String>,
|
||||
cargo: &mut Command) {
|
||||
let mut features = build.std_features();
|
||||
|
||||
if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {
|
||||
cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
|
||||
}
|
||||
|
||||
// When doing a local rebuild we tell cargo that we're stage1 rather than
|
||||
// stage0. This works fine if the local rust and being-built rust have the
|
||||
// same view of what the default allocator is, but fails otherwise. Since
|
||||
// we don't have a way to express an allocator preference yet, work
|
||||
// around the issue in the case of a local rebuild with jemalloc disabled.
|
||||
if compiler.stage == 0 && build.local_rebuild && !build.config.use_jemalloc {
|
||||
features.push_str(" force_alloc_system");
|
||||
}
|
||||
if build.no_std(target) == Some(true) {
|
||||
// for no-std targets we only compile a few no_std crates
|
||||
cargo.arg("--features").arg("c mem")
|
||||
.args(&["-p", "alloc"])
|
||||
.args(&["-p", "compiler_builtins"])
|
||||
.args(&["-p", "std_unicode"])
|
||||
.arg("--manifest-path")
|
||||
.arg(build.src.join("src/rustc/compiler_builtins_shim/Cargo.toml"));
|
||||
} else {
|
||||
let mut features = build.std_features();
|
||||
|
||||
if compiler.stage != 0 && build.config.sanitizers {
|
||||
// This variable is used by the sanitizer runtime crates, e.g.
|
||||
// rustc_lsan, to build the sanitizer runtime from C code
|
||||
// When this variable is missing, those crates won't compile the C code,
|
||||
// so we don't set this variable during stage0 where llvm-config is
|
||||
// missing
|
||||
// We also only build the runtimes when --enable-sanitizers (or its
|
||||
// config.toml equivalent) is used
|
||||
let llvm_config = build.ensure(native::Llvm {
|
||||
target: build.config.build,
|
||||
emscripten: false,
|
||||
});
|
||||
cargo.env("LLVM_CONFIG", llvm_config);
|
||||
}
|
||||
|
||||
cargo.arg("--features").arg(features)
|
||||
.arg("--manifest-path")
|
||||
.arg(build.src.join("src/libstd/Cargo.toml"));
|
||||
|
||||
if let Some(target) = build.config.target_config.get(&target) {
|
||||
if let Some(ref jemalloc) = target.jemalloc {
|
||||
cargo.env("JEMALLOC_OVERRIDE", jemalloc);
|
||||
// When doing a local rebuild we tell cargo that we're stage1 rather than
|
||||
// stage0. This works fine if the local rust and being-built rust have the
|
||||
// same view of what the default allocator is, but fails otherwise. Since
|
||||
// we don't have a way to express an allocator preference yet, work
|
||||
// around the issue in the case of a local rebuild with jemalloc disabled.
|
||||
if compiler.stage == 0 && build.local_rebuild && !build.config.use_jemalloc {
|
||||
features.push_str(" force_alloc_system");
|
||||
}
|
||||
}
|
||||
if target.contains("musl") {
|
||||
if let Some(p) = build.musl_root(target) {
|
||||
cargo.env("MUSL_ROOT", p);
|
||||
|
||||
if compiler.stage != 0 && build.config.sanitizers {
|
||||
// This variable is used by the sanitizer runtime crates, e.g.
|
||||
// rustc_lsan, to build the sanitizer runtime from C code
|
||||
// When this variable is missing, those crates won't compile the C code,
|
||||
// so we don't set this variable during stage0 where llvm-config is
|
||||
// missing
|
||||
// We also only build the runtimes when --enable-sanitizers (or its
|
||||
// config.toml equivalent) is used
|
||||
let llvm_config = build.ensure(native::Llvm {
|
||||
target: build.config.build,
|
||||
emscripten: false,
|
||||
});
|
||||
cargo.env("LLVM_CONFIG", llvm_config);
|
||||
}
|
||||
|
||||
cargo.arg("--features").arg(features)
|
||||
.arg("--manifest-path")
|
||||
.arg(build.src.join("src/libstd/Cargo.toml"));
|
||||
|
||||
if let Some(target) = build.config.target_config.get(&target) {
|
||||
if let Some(ref jemalloc) = target.jemalloc {
|
||||
cargo.env("JEMALLOC_OVERRIDE", jemalloc);
|
||||
}
|
||||
}
|
||||
if target.contains("musl") {
|
||||
if let Some(p) = build.musl_root(target) {
|
||||
cargo.env("MUSL_ROOT", p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -161,6 +161,7 @@ pub struct Target {
|
||||
pub crt_static: Option<bool>,
|
||||
pub musl_root: Option<PathBuf>,
|
||||
pub qemu_rootfs: Option<PathBuf>,
|
||||
pub no_std: bool,
|
||||
}
|
||||
|
||||
/// Structure of the `config.toml` file that configuration is read from.
|
||||
|
@ -642,7 +642,12 @@ impl Step for Std {
|
||||
if build.hosts.iter().any(|t| t == target) {
|
||||
builder.ensure(compile::Rustc { compiler, target });
|
||||
} else {
|
||||
builder.ensure(compile::Test { compiler, target });
|
||||
if build.no_std(target) == Some(true) {
|
||||
// the `test` doesn't compile for no-std targets
|
||||
builder.ensure(compile::Std { compiler, target });
|
||||
} else {
|
||||
builder.ensure(compile::Test { compiler, target });
|
||||
}
|
||||
}
|
||||
|
||||
let image = tmpdir(build).join(format!("{}-{}-image", name, target));
|
||||
|
@ -698,6 +698,7 @@ impl Step for Rustc {
|
||||
t!(symlink_dir_force(&builder.config, &out, &out_dir));
|
||||
|
||||
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc");
|
||||
cargo.env("RUSTDOCFLAGS", "--document-private-items");
|
||||
compile::rustc_cargo(build, &mut cargo);
|
||||
|
||||
// Only include compiler crates, no dependencies of those, such as `libc`.
|
||||
|
@ -750,6 +750,12 @@ impl Build {
|
||||
.map(|p| &**p)
|
||||
}
|
||||
|
||||
/// Returns true if this is a no-std `target`, if defined
|
||||
fn no_std(&self, target: Interned<String>) -> Option<bool> {
|
||||
self.config.target_config.get(&target)
|
||||
.map(|t| t.no_std)
|
||||
}
|
||||
|
||||
/// Returns whether the target will be tested using the `remote-test-client`
|
||||
/// and `remote-test-server` binaries.
|
||||
fn remote_tested(&self, target: Interned<String>) -> bool {
|
||||
|
@ -169,6 +169,19 @@ pub fn check(build: &mut Build) {
|
||||
panic!("the iOS target is only supported on macOS");
|
||||
}
|
||||
|
||||
if target.contains("-none-") {
|
||||
if build.no_std(*target).is_none() {
|
||||
let target = build.config.target_config.entry(target.clone())
|
||||
.or_insert(Default::default());
|
||||
|
||||
target.no_std = true;
|
||||
}
|
||||
|
||||
if build.no_std(*target) == Some(false) {
|
||||
panic!("All the *-none-* targets are no-std targets")
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure musl-root is valid
|
||||
if target.contains("musl") {
|
||||
// If this is a native target (host is also musl) and no musl-root is given,
|
||||
|
@ -20,7 +20,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
bzip2 \
|
||||
patch \
|
||||
libssl-dev \
|
||||
pkg-config
|
||||
pkg-config \
|
||||
gcc-arm-none-eabi \
|
||||
libnewlib-arm-none-eabi
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
@ -86,6 +88,10 @@ ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabihf
|
||||
ENV TARGETS=$TARGETS,aarch64-unknown-linux-musl
|
||||
ENV TARGETS=$TARGETS,sparc64-unknown-linux-gnu
|
||||
ENV TARGETS=$TARGETS,x86_64-unknown-redox
|
||||
ENV TARGETS=$TARGETS,thumbv6m-none-eabi
|
||||
ENV TARGETS=$TARGETS,thumbv7m-none-eabi
|
||||
ENV TARGETS=$TARGETS,thumbv7em-none-eabi
|
||||
ENV TARGETS=$TARGETS,thumbv7em-none-eabihf
|
||||
|
||||
# FIXME: remove armv5te vars after https://github.com/alexcrichton/cc-rs/issues/271
|
||||
# get fixed and cc update
|
||||
|
@ -1,22 +0,0 @@
|
||||
FROM ubuntu:16.04
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
g++ \
|
||||
make \
|
||||
file \
|
||||
curl \
|
||||
ca-certificates \
|
||||
python2.7 \
|
||||
git \
|
||||
cmake \
|
||||
sudo \
|
||||
gdb \
|
||||
xz-utils
|
||||
|
||||
COPY scripts/sccache.sh /scripts/
|
||||
RUN sh /scripts/sccache.sh
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
|
||||
ENV RUSTFLAGS -Zincremental=/tmp/rust-incr-cache
|
||||
ENV RUST_CHECK_TARGET check
|
||||
ENV CARGO_INCREMENTAL 0
|
@ -1594,40 +1594,69 @@ impl SpecFromElem for u8 {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_spec_from_elem {
|
||||
($t: ty, $is_zero: expr) => {
|
||||
impl SpecFromElem for $t {
|
||||
#[inline]
|
||||
fn from_elem(elem: $t, n: usize) -> Vec<$t> {
|
||||
if $is_zero(elem) {
|
||||
return Vec {
|
||||
buf: RawVec::with_capacity_zeroed(n),
|
||||
len: n,
|
||||
}
|
||||
}
|
||||
let mut v = Vec::with_capacity(n);
|
||||
v.extend_with(n, ExtendElement(elem));
|
||||
v
|
||||
impl<T: Clone + IsZero> SpecFromElem for T {
|
||||
#[inline]
|
||||
fn from_elem(elem: T, n: usize) -> Vec<T> {
|
||||
if elem.is_zero() {
|
||||
return Vec {
|
||||
buf: RawVec::with_capacity_zeroed(n),
|
||||
len: n,
|
||||
}
|
||||
}
|
||||
};
|
||||
let mut v = Vec::with_capacity(n);
|
||||
v.extend_with(n, ExtendElement(elem));
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
impl_spec_from_elem!(i8, |x| x == 0);
|
||||
impl_spec_from_elem!(i16, |x| x == 0);
|
||||
impl_spec_from_elem!(i32, |x| x == 0);
|
||||
impl_spec_from_elem!(i64, |x| x == 0);
|
||||
impl_spec_from_elem!(i128, |x| x == 0);
|
||||
impl_spec_from_elem!(isize, |x| x == 0);
|
||||
unsafe trait IsZero {
|
||||
/// Whether this value is zero
|
||||
fn is_zero(&self) -> bool;
|
||||
}
|
||||
|
||||
impl_spec_from_elem!(u16, |x| x == 0);
|
||||
impl_spec_from_elem!(u32, |x| x == 0);
|
||||
impl_spec_from_elem!(u64, |x| x == 0);
|
||||
impl_spec_from_elem!(u128, |x| x == 0);
|
||||
impl_spec_from_elem!(usize, |x| x == 0);
|
||||
macro_rules! impl_is_zero {
|
||||
($t: ty, $is_zero: expr) => {
|
||||
unsafe impl IsZero for $t {
|
||||
#[inline]
|
||||
fn is_zero(&self) -> bool {
|
||||
$is_zero(*self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_is_zero!(i8, |x| x == 0);
|
||||
impl_is_zero!(i16, |x| x == 0);
|
||||
impl_is_zero!(i32, |x| x == 0);
|
||||
impl_is_zero!(i64, |x| x == 0);
|
||||
impl_is_zero!(i128, |x| x == 0);
|
||||
impl_is_zero!(isize, |x| x == 0);
|
||||
|
||||
impl_is_zero!(u16, |x| x == 0);
|
||||
impl_is_zero!(u32, |x| x == 0);
|
||||
impl_is_zero!(u64, |x| x == 0);
|
||||
impl_is_zero!(u128, |x| x == 0);
|
||||
impl_is_zero!(usize, |x| x == 0);
|
||||
|
||||
impl_is_zero!(char, |x| x == '\0');
|
||||
|
||||
impl_is_zero!(f32, |x: f32| x.to_bits() == 0);
|
||||
impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
|
||||
|
||||
unsafe impl<T: ?Sized> IsZero for *const T {
|
||||
#[inline]
|
||||
fn is_zero(&self) -> bool {
|
||||
(*self).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: ?Sized> IsZero for *mut T {
|
||||
#[inline]
|
||||
fn is_zero(&self) -> bool {
|
||||
(*self).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
impl_spec_from_elem!(f32, |x: f32| x.to_bits() == 0);
|
||||
impl_spec_from_elem!(f64, |x: f64| x.to_bits() == 0);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Common trait implementations for Vec
|
||||
|
@ -952,6 +952,7 @@ macro_rules! atomic_int {
|
||||
$stable_nand:meta,
|
||||
$s_int_type:expr, $int_ref:expr,
|
||||
$extra_feature:expr,
|
||||
$min_fn:ident, $max_fn:ident,
|
||||
$int_type:ident $atomic_type:ident $atomic_init:ident) => {
|
||||
/// An integer type which can be safely shared between threads.
|
||||
///
|
||||
@ -1421,6 +1422,128 @@ assert_eq!(foo.load(Ordering::SeqCst), 0b011110);
|
||||
unsafe { atomic_xor(self.v.get(), val, order) }
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!("Fetches the value, and applies a function to it that returns an optional
|
||||
new value. Returns a `Result` (`Ok(_)` if the function returned `Some(_)`, else `Err(_)`) of the
|
||||
previous value.
|
||||
|
||||
Note: This may call the function multiple times if the value has been changed from other threads in
|
||||
the meantime, as long as the function returns `Some(_)`, but the function will have been applied
|
||||
but once to the stored value.
|
||||
|
||||
# Examples
|
||||
|
||||
```rust
|
||||
#![feature(no_more_cas)]
|
||||
", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
|
||||
|
||||
let x = ", stringify!($atomic_type), "::new(7);
|
||||
assert_eq!(x.fetch_update(|_| None, Ordering::SeqCst, Ordering::SeqCst), Err(7));
|
||||
assert_eq!(x.fetch_update(|x| Some(x + 1), Ordering::SeqCst, Ordering::SeqCst), Ok(7));
|
||||
assert_eq!(x.fetch_update(|x| Some(x + 1), Ordering::SeqCst, Ordering::SeqCst), Ok(8));
|
||||
assert_eq!(x.load(Ordering::SeqCst), 9);
|
||||
```"),
|
||||
#[inline]
|
||||
#[unstable(feature = "no_more_cas",
|
||||
reason = "no more CAS loops in user code",
|
||||
issue = "48655")]
|
||||
pub fn fetch_update<F>(&self,
|
||||
mut f: F,
|
||||
fetch_order: Ordering,
|
||||
set_order: Ordering) -> Result<$int_type, $int_type>
|
||||
where F: FnMut($int_type) -> Option<$int_type> {
|
||||
let mut prev = self.load(fetch_order);
|
||||
while let Some(next) = f(prev) {
|
||||
match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
|
||||
x @ Ok(_) => return x,
|
||||
Err(next_prev) => prev = next_prev
|
||||
}
|
||||
}
|
||||
Err(prev)
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!("Maximum with the current value.
|
||||
|
||||
Finds the maximum of the current value and the argument `val`, and
|
||||
sets the new value to the result.
|
||||
|
||||
Returns the previous value.
|
||||
|
||||
# Examples
|
||||
|
||||
```
|
||||
#![feature(atomic_min_max)]
|
||||
", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
|
||||
|
||||
let foo = ", stringify!($atomic_type), "::new(23);
|
||||
assert_eq!(foo.fetch_max(42, Ordering::SeqCst), 23);
|
||||
assert_eq!(foo.load(Ordering::SeqCst), 42);
|
||||
```
|
||||
|
||||
If you want to obtain the maximum value in one step, you can use the following:
|
||||
|
||||
```
|
||||
#![feature(atomic_min_max)]
|
||||
", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
|
||||
|
||||
let foo = ", stringify!($atomic_type), "::new(23);
|
||||
let bar = 42;
|
||||
let max_foo = foo.fetch_max(bar, Ordering::SeqCst).max(bar);
|
||||
assert!(max_foo == 42);
|
||||
```"),
|
||||
#[inline]
|
||||
#[unstable(feature = "atomic_min_max",
|
||||
reason = "easier and faster min/max than writing manual CAS loop",
|
||||
issue = "48655")]
|
||||
pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type {
|
||||
unsafe { $max_fn(self.v.get(), val, order) }
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!("Minimum with the current value.
|
||||
|
||||
Finds the minimum of the current value and the argument `val`, and
|
||||
sets the new value to the result.
|
||||
|
||||
Returns the previous value.
|
||||
|
||||
# Examples
|
||||
|
||||
```
|
||||
#![feature(atomic_min_max)]
|
||||
", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
|
||||
|
||||
let foo = ", stringify!($atomic_type), "::new(23);
|
||||
assert_eq!(foo.fetch_min(42, Ordering::Relaxed), 23);
|
||||
assert_eq!(foo.load(Ordering::Relaxed), 23);
|
||||
assert_eq!(foo.fetch_min(22, Ordering::Relaxed), 23);
|
||||
assert_eq!(foo.load(Ordering::Relaxed), 22);
|
||||
```
|
||||
|
||||
If you want to obtain the minimum value in one step, you can use the following:
|
||||
|
||||
```
|
||||
#![feature(atomic_min_max)]
|
||||
", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
|
||||
|
||||
let foo = ", stringify!($atomic_type), "::new(23);
|
||||
let bar = 12;
|
||||
let min_foo = foo.fetch_min(bar, Ordering::SeqCst).min(bar);
|
||||
assert_eq!(min_foo, 12);
|
||||
```"),
|
||||
#[inline]
|
||||
#[unstable(feature = "atomic_min_max",
|
||||
reason = "easier and faster min/max than writing manual CAS loop",
|
||||
issue = "48655")]
|
||||
pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
|
||||
unsafe { $min_fn(self.v.get(), val, order) }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1435,6 +1558,7 @@ atomic_int! {
|
||||
unstable(feature = "atomic_nand", issue = "13226"),
|
||||
"i8", "../../../std/primitive.i8.html",
|
||||
"#![feature(integer_atomics)]\n\n",
|
||||
atomic_min, atomic_max,
|
||||
i8 AtomicI8 ATOMIC_I8_INIT
|
||||
}
|
||||
#[cfg(target_has_atomic = "8")]
|
||||
@ -1447,6 +1571,7 @@ atomic_int! {
|
||||
unstable(feature = "atomic_nand", issue = "13226"),
|
||||
"u8", "../../../std/primitive.u8.html",
|
||||
"#![feature(integer_atomics)]\n\n",
|
||||
atomic_umin, atomic_umax,
|
||||
u8 AtomicU8 ATOMIC_U8_INIT
|
||||
}
|
||||
#[cfg(target_has_atomic = "16")]
|
||||
@ -1459,6 +1584,7 @@ atomic_int! {
|
||||
unstable(feature = "atomic_nand", issue = "13226"),
|
||||
"i16", "../../../std/primitive.i16.html",
|
||||
"#![feature(integer_atomics)]\n\n",
|
||||
atomic_min, atomic_max,
|
||||
i16 AtomicI16 ATOMIC_I16_INIT
|
||||
}
|
||||
#[cfg(target_has_atomic = "16")]
|
||||
@ -1471,6 +1597,7 @@ atomic_int! {
|
||||
unstable(feature = "atomic_nand", issue = "13226"),
|
||||
"u16", "../../../std/primitive.u16.html",
|
||||
"#![feature(integer_atomics)]\n\n",
|
||||
atomic_umin, atomic_umax,
|
||||
u16 AtomicU16 ATOMIC_U16_INIT
|
||||
}
|
||||
#[cfg(target_has_atomic = "32")]
|
||||
@ -1483,6 +1610,7 @@ atomic_int! {
|
||||
unstable(feature = "atomic_nand", issue = "13226"),
|
||||
"i32", "../../../std/primitive.i32.html",
|
||||
"#![feature(integer_atomics)]\n\n",
|
||||
atomic_min, atomic_max,
|
||||
i32 AtomicI32 ATOMIC_I32_INIT
|
||||
}
|
||||
#[cfg(target_has_atomic = "32")]
|
||||
@ -1495,6 +1623,7 @@ atomic_int! {
|
||||
unstable(feature = "atomic_nand", issue = "13226"),
|
||||
"u32", "../../../std/primitive.u32.html",
|
||||
"#![feature(integer_atomics)]\n\n",
|
||||
atomic_umin, atomic_umax,
|
||||
u32 AtomicU32 ATOMIC_U32_INIT
|
||||
}
|
||||
#[cfg(target_has_atomic = "64")]
|
||||
@ -1507,6 +1636,7 @@ atomic_int! {
|
||||
unstable(feature = "atomic_nand", issue = "13226"),
|
||||
"i64", "../../../std/primitive.i64.html",
|
||||
"#![feature(integer_atomics)]\n\n",
|
||||
atomic_min, atomic_max,
|
||||
i64 AtomicI64 ATOMIC_I64_INIT
|
||||
}
|
||||
#[cfg(target_has_atomic = "64")]
|
||||
@ -1519,6 +1649,7 @@ atomic_int! {
|
||||
unstable(feature = "atomic_nand", issue = "13226"),
|
||||
"u64", "../../../std/primitive.u64.html",
|
||||
"#![feature(integer_atomics)]\n\n",
|
||||
atomic_umin, atomic_umax,
|
||||
u64 AtomicU64 ATOMIC_U64_INIT
|
||||
}
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
@ -1531,6 +1662,7 @@ atomic_int!{
|
||||
unstable(feature = "atomic_nand", issue = "13226"),
|
||||
"isize", "../../../std/primitive.isize.html",
|
||||
"",
|
||||
atomic_min, atomic_max,
|
||||
isize AtomicIsize ATOMIC_ISIZE_INIT
|
||||
}
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
@ -1543,6 +1675,7 @@ atomic_int!{
|
||||
unstable(feature = "atomic_nand", issue = "13226"),
|
||||
"usize", "../../../std/primitive.usize.html",
|
||||
"",
|
||||
atomic_umin, atomic_umax,
|
||||
usize AtomicUsize ATOMIC_USIZE_INIT
|
||||
}
|
||||
|
||||
@ -1720,6 +1853,58 @@ unsafe fn atomic_xor<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
}
|
||||
}
|
||||
|
||||
/// returns the max value (signed comparison)
|
||||
#[inline]
|
||||
unsafe fn atomic_max<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
match order {
|
||||
Acquire => intrinsics::atomic_max_acq(dst, val),
|
||||
Release => intrinsics::atomic_max_rel(dst, val),
|
||||
AcqRel => intrinsics::atomic_max_acqrel(dst, val),
|
||||
Relaxed => intrinsics::atomic_max_relaxed(dst, val),
|
||||
SeqCst => intrinsics::atomic_max(dst, val),
|
||||
__Nonexhaustive => panic!("invalid memory ordering"),
|
||||
}
|
||||
}
|
||||
|
||||
/// returns the min value (signed comparison)
|
||||
#[inline]
|
||||
unsafe fn atomic_min<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
match order {
|
||||
Acquire => intrinsics::atomic_min_acq(dst, val),
|
||||
Release => intrinsics::atomic_min_rel(dst, val),
|
||||
AcqRel => intrinsics::atomic_min_acqrel(dst, val),
|
||||
Relaxed => intrinsics::atomic_min_relaxed(dst, val),
|
||||
SeqCst => intrinsics::atomic_min(dst, val),
|
||||
__Nonexhaustive => panic!("invalid memory ordering"),
|
||||
}
|
||||
}
|
||||
|
||||
/// returns the max value (signed comparison)
|
||||
#[inline]
|
||||
unsafe fn atomic_umax<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
match order {
|
||||
Acquire => intrinsics::atomic_umax_acq(dst, val),
|
||||
Release => intrinsics::atomic_umax_rel(dst, val),
|
||||
AcqRel => intrinsics::atomic_umax_acqrel(dst, val),
|
||||
Relaxed => intrinsics::atomic_umax_relaxed(dst, val),
|
||||
SeqCst => intrinsics::atomic_umax(dst, val),
|
||||
__Nonexhaustive => panic!("invalid memory ordering"),
|
||||
}
|
||||
}
|
||||
|
||||
/// returns the min value (signed comparison)
|
||||
#[inline]
|
||||
unsafe fn atomic_umin<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
match order {
|
||||
Acquire => intrinsics::atomic_umin_acq(dst, val),
|
||||
Release => intrinsics::atomic_umin_rel(dst, val),
|
||||
AcqRel => intrinsics::atomic_umin_acqrel(dst, val),
|
||||
Relaxed => intrinsics::atomic_umin_relaxed(dst, val),
|
||||
SeqCst => intrinsics::atomic_umin(dst, val),
|
||||
__Nonexhaustive => panic!("invalid memory ordering"),
|
||||
}
|
||||
}
|
||||
|
||||
/// An atomic fence.
|
||||
///
|
||||
/// Depending on the specified order, a fence prevents the compiler and CPU from
|
||||
|
@ -589,6 +589,7 @@ define_dep_nodes!( <'tcx>
|
||||
[input] CrateDisambiguator(CrateNum),
|
||||
[input] CrateHash(CrateNum),
|
||||
[input] OriginalCrateName(CrateNum),
|
||||
[input] ExtraFileName(CrateNum),
|
||||
|
||||
[] ImplementationsOfTrait { krate: CrateNum, trait_id: DefId },
|
||||
[] AllTraitImplementations(CrateNum),
|
||||
|
@ -2058,6 +2058,33 @@ where 'x: 'y
|
||||
```
|
||||
"##,
|
||||
|
||||
E0910: r##"
|
||||
This error indicates that a `#[non_exhaustive]` attribute was incorrectly placed
|
||||
on something other than a struct or enum.
|
||||
|
||||
Examples of erroneous code:
|
||||
|
||||
```compile_fail,E0910
|
||||
# #![feature(non_exhaustive)]
|
||||
|
||||
#[non_exhaustive]
|
||||
trait Foo { }
|
||||
```
|
||||
"##,
|
||||
|
||||
E0911: r##"
|
||||
This error indicates that a `#[non_exhaustive]` attribute had a value. The
|
||||
`#[non_exhaustive]` should be empty.
|
||||
|
||||
Examples of erroneous code:
|
||||
|
||||
```compile_fail,E0911
|
||||
# #![feature(non_exhaustive)]
|
||||
|
||||
#[non_exhaustive(anything)]
|
||||
struct Foo;
|
||||
```
|
||||
"##,
|
||||
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,8 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
|
||||
for attr in &item.attrs {
|
||||
if attr.check_name("inline") {
|
||||
self.check_inline(attr, &item.span, target)
|
||||
} else if attr.check_name("non_exhaustive") {
|
||||
self.check_non_exhaustive(attr, item, target)
|
||||
} else if attr.check_name("wasm_import_module") {
|
||||
has_wasm_import_module = true;
|
||||
if attr.value_str().is_none() {
|
||||
@ -113,6 +115,31 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the `#[non_exhaustive]` attribute on an `item` is valid.
|
||||
fn check_non_exhaustive(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) {
|
||||
match target {
|
||||
Target::Struct | Target::Enum => { /* Valid */ },
|
||||
_ => {
|
||||
struct_span_err!(self.tcx.sess,
|
||||
attr.span,
|
||||
E0910,
|
||||
"attribute can only be applied to a struct or enum")
|
||||
.span_label(item.span, "not a struct or enum")
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if attr.meta_item_list().is_some() || attr.value_str().is_some() {
|
||||
struct_span_err!(self.tcx.sess,
|
||||
attr.span,
|
||||
E0911,
|
||||
"attribute should be empty")
|
||||
.span_label(item.span, "not empty")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the `#[repr]` attributes on `item` are valid.
|
||||
fn check_repr(&self, item: &hir::Item, target: Target) {
|
||||
// Extract the names of all repr hints, e.g., [foo, bar, align] for:
|
||||
|
@ -353,8 +353,8 @@ pub struct ScopeTree {
|
||||
/// the result of `g()` occurs after the yield (and therefore
|
||||
/// doesn't). If we want to infer that, we can look at the
|
||||
/// postorder traversal:
|
||||
/// ```
|
||||
/// `foo` `f` Call#1 `y` Yield `bar` `g` Call#3 Call#2 Call#0
|
||||
/// ```plain,ignore
|
||||
/// `foo` `f` Call#1 `y` Yield `bar` `g` Call#3 Call#2 Call#0
|
||||
/// ```
|
||||
///
|
||||
/// In which we can easily see that `Call#1` occurs before the yield,
|
||||
|
@ -362,7 +362,9 @@ enum EvaluationResult {
|
||||
/// When checking `foo`, we have to prove `T: Trait`. This basically
|
||||
/// translates into this:
|
||||
///
|
||||
/// ```plain,ignore
|
||||
/// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait
|
||||
/// ```
|
||||
///
|
||||
/// When we try to prove it, we first go the first option, which
|
||||
/// recurses. This shows us that the impl is "useless" - it won't
|
||||
|
@ -466,6 +466,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::original_crate_name<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::extra_filename<'tcx> {
|
||||
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
|
||||
format!("looking up the extra filename for a crate")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::implementations_of_trait<'tcx> {
|
||||
fn describe(_tcx: TyCtxt, _: (CrateNum, DefId)) -> String {
|
||||
format!("looking up implementations of a trait in a crate")
|
||||
|
@ -328,6 +328,7 @@ define_maps! { <'tcx>
|
||||
[] fn crate_disambiguator: CrateDisambiguator(CrateNum) -> CrateDisambiguator,
|
||||
[] fn crate_hash: CrateHash(CrateNum) -> Svh,
|
||||
[] fn original_crate_name: OriginalCrateName(CrateNum) -> Symbol,
|
||||
[] fn extra_filename: ExtraFileName(CrateNum) -> String,
|
||||
|
||||
[] fn implementations_of_trait: implementations_of_trait_node((CrateNum, DefId))
|
||||
-> Lrc<Vec<DefId>>,
|
||||
|
@ -881,6 +881,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
|
||||
DepKind::CrateDisambiguator => { force!(crate_disambiguator, krate!()); }
|
||||
DepKind::CrateHash => { force!(crate_hash, krate!()); }
|
||||
DepKind::OriginalCrateName => { force!(original_crate_name, krate!()); }
|
||||
DepKind::ExtraFileName => { force!(extra_filename, krate!()); }
|
||||
|
||||
DepKind::AllTraitImplementations => {
|
||||
force!(all_trait_implementations, krate!());
|
||||
|
@ -262,6 +262,7 @@ impl<'a> CrateLoader<'a> {
|
||||
ident: Symbol,
|
||||
name: Symbol,
|
||||
hash: Option<&Svh>,
|
||||
extra_filename: Option<&str>,
|
||||
span: Span,
|
||||
path_kind: PathKind,
|
||||
mut dep_kind: DepKind)
|
||||
@ -277,6 +278,7 @@ impl<'a> CrateLoader<'a> {
|
||||
ident,
|
||||
crate_name: name,
|
||||
hash: hash.map(|a| &*a),
|
||||
extra_filename: extra_filename,
|
||||
filesearch: self.sess.target_filesearch(path_kind),
|
||||
target: &self.sess.target.target,
|
||||
triple: &self.sess.opts.target_triple,
|
||||
@ -409,7 +411,8 @@ impl<'a> CrateLoader<'a> {
|
||||
::std::iter::once(krate).chain(crate_root.crate_deps
|
||||
.decode(metadata)
|
||||
.map(|dep| {
|
||||
debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash);
|
||||
info!("resolving dep crate {} hash: `{}` extra filename: `{}`", dep.name, dep.hash,
|
||||
dep.extra_filename);
|
||||
if dep.kind == DepKind::UnexportedMacrosOnly {
|
||||
return krate;
|
||||
}
|
||||
@ -418,7 +421,8 @@ impl<'a> CrateLoader<'a> {
|
||||
_ => dep.kind,
|
||||
};
|
||||
let (local_cnum, ..) = self.resolve_crate(
|
||||
root, dep.name, dep.name, Some(&dep.hash), span, PathKind::Dependency, dep_kind,
|
||||
root, dep.name, dep.name, Some(&dep.hash), Some(&dep.extra_filename), span,
|
||||
PathKind::Dependency, dep_kind,
|
||||
);
|
||||
local_cnum
|
||||
})).collect()
|
||||
@ -437,6 +441,7 @@ impl<'a> CrateLoader<'a> {
|
||||
ident: orig_name,
|
||||
crate_name: rename,
|
||||
hash: None,
|
||||
extra_filename: None,
|
||||
filesearch: self.sess.host_filesearch(PathKind::Crate),
|
||||
target: &self.sess.host,
|
||||
triple: &host_triple,
|
||||
@ -664,7 +669,7 @@ impl<'a> CrateLoader<'a> {
|
||||
|
||||
let dep_kind = DepKind::Implicit;
|
||||
let (cnum, data) =
|
||||
self.resolve_crate(&None, name, name, None, DUMMY_SP, PathKind::Crate, dep_kind);
|
||||
self.resolve_crate(&None, name, name, None, None, DUMMY_SP, PathKind::Crate, dep_kind);
|
||||
|
||||
// Sanity check the loaded crate to ensure it is indeed a panic runtime
|
||||
// and the panic strategy is indeed what we thought it was.
|
||||
@ -771,7 +776,7 @@ impl<'a> CrateLoader<'a> {
|
||||
let symbol = Symbol::intern(name);
|
||||
let dep_kind = DepKind::Explicit;
|
||||
let (_, data) =
|
||||
self.resolve_crate(&None, symbol, symbol, None, DUMMY_SP,
|
||||
self.resolve_crate(&None, symbol, symbol, None, None, DUMMY_SP,
|
||||
PathKind::Crate, dep_kind);
|
||||
|
||||
// Sanity check the loaded crate to ensure it is indeed a sanitizer runtime
|
||||
@ -794,7 +799,7 @@ impl<'a> CrateLoader<'a> {
|
||||
let symbol = Symbol::intern("profiler_builtins");
|
||||
let dep_kind = DepKind::Implicit;
|
||||
let (_, data) =
|
||||
self.resolve_crate(&None, symbol, symbol, None, DUMMY_SP,
|
||||
self.resolve_crate(&None, symbol, symbol, None, None, DUMMY_SP,
|
||||
PathKind::Crate, dep_kind);
|
||||
|
||||
// Sanity check the loaded crate to ensure it is indeed a profiler runtime
|
||||
@ -909,6 +914,7 @@ impl<'a> CrateLoader<'a> {
|
||||
name,
|
||||
name,
|
||||
None,
|
||||
None,
|
||||
DUMMY_SP,
|
||||
PathKind::Crate,
|
||||
DepKind::Implicit);
|
||||
@ -1059,7 +1065,8 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
|
||||
};
|
||||
|
||||
let (cnum, ..) = self.resolve_crate(
|
||||
&None, item.ident.name, orig_name, None, item.span, PathKind::Crate, dep_kind,
|
||||
&None, item.ident.name, orig_name, None, None,
|
||||
item.span, PathKind::Crate, dep_kind,
|
||||
);
|
||||
|
||||
let def_id = definitions.opt_local_def_id(item.id).unwrap();
|
||||
@ -1074,6 +1081,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
|
||||
}
|
||||
|
||||
fn resolve_crate_from_path(&mut self, name: Symbol, span: Span) -> CrateNum {
|
||||
self.resolve_crate(&None, name, name, None, span, PathKind::Crate, DepKind::Explicit).0
|
||||
self.resolve_crate(&None, name, name, None, None, span, PathKind::Crate,
|
||||
DepKind::Explicit).0
|
||||
}
|
||||
}
|
||||
|
@ -213,6 +213,9 @@ provide! { <'tcx> tcx, def_id, other, cdata,
|
||||
crate_hash => { cdata.hash() }
|
||||
original_crate_name => { cdata.name() }
|
||||
|
||||
extra_filename => { cdata.root.extra_filename.clone() }
|
||||
|
||||
|
||||
implementations_of_trait => {
|
||||
let mut result = vec![];
|
||||
let filter = Some(other);
|
||||
|
@ -462,6 +462,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
let has_global_allocator = tcx.sess.has_global_allocator.get();
|
||||
let root = self.lazy(&CrateRoot {
|
||||
name: tcx.crate_name(LOCAL_CRATE),
|
||||
extra_filename: tcx.sess.opts.cg.extra_filename.clone(),
|
||||
triple: tcx.sess.opts.target_triple.clone(),
|
||||
hash: link_meta.crate_hash,
|
||||
disambiguator: tcx.sess.local_crate_disambiguator(),
|
||||
@ -1357,6 +1358,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
|
||||
name: self.tcx.original_crate_name(cnum),
|
||||
hash: self.tcx.crate_hash(cnum),
|
||||
kind: self.tcx.dep_kind(cnum),
|
||||
extra_filename: self.tcx.extra_filename(cnum),
|
||||
};
|
||||
(cnum, dep)
|
||||
})
|
||||
|
@ -83,7 +83,10 @@
|
||||
//! 1. Does the filename match an rlib/dylib pattern? That is to say, does the
|
||||
//! filename have the right prefix/suffix?
|
||||
//! 2. Does the filename have the right prefix for the crate name being queried?
|
||||
//! This is filtering for files like `libfoo*.rlib` and such.
|
||||
//! This is filtering for files like `libfoo*.rlib` and such. If the crate
|
||||
//! we're looking for was originally compiled with -C extra-filename, the
|
||||
//! extra filename will be included in this prefix to reduce reading
|
||||
//! metadata from crates that would otherwise share our prefix.
|
||||
//! 3. Is the file an actual rust library? This is done by loading the metadata
|
||||
//! from the library and making sure it's actually there.
|
||||
//! 4. Does the name in the metadata agree with the name of the library?
|
||||
@ -236,6 +239,7 @@ use syntax_pos::Span;
|
||||
use rustc_back::target::{Target, TargetTriple};
|
||||
|
||||
use std::cmp;
|
||||
use std::collections::HashSet;
|
||||
use std::fmt;
|
||||
use std::fs;
|
||||
use std::io::{self, Read};
|
||||
@ -256,6 +260,7 @@ pub struct Context<'a> {
|
||||
pub ident: Symbol,
|
||||
pub crate_name: Symbol,
|
||||
pub hash: Option<&'a Svh>,
|
||||
pub extra_filename: Option<&'a str>,
|
||||
// points to either self.sess.target.target or self.sess.host, must match triple
|
||||
pub target: &'a Target,
|
||||
pub triple: &'a TargetTriple,
|
||||
@ -303,7 +308,12 @@ impl CratePaths {
|
||||
|
||||
impl<'a> Context<'a> {
|
||||
pub fn maybe_load_library_crate(&mut self) -> Option<Library> {
|
||||
self.find_library_crate()
|
||||
let mut seen_paths = HashSet::new();
|
||||
match self.extra_filename {
|
||||
Some(s) => self.find_library_crate(s, &mut seen_paths)
|
||||
.or_else(|| self.find_library_crate("", &mut seen_paths)),
|
||||
None => self.find_library_crate("", &mut seen_paths)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn report_errs(&mut self) -> ! {
|
||||
@ -419,7 +429,10 @@ impl<'a> Context<'a> {
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
fn find_library_crate(&mut self) -> Option<Library> {
|
||||
fn find_library_crate(&mut self,
|
||||
extra_prefix: &str,
|
||||
seen_paths: &mut HashSet<PathBuf>)
|
||||
-> Option<Library> {
|
||||
// If an SVH is specified, then this is a transitive dependency that
|
||||
// must be loaded via -L plus some filtering.
|
||||
if self.hash.is_none() {
|
||||
@ -434,9 +447,9 @@ impl<'a> Context<'a> {
|
||||
let staticpair = self.staticlibname();
|
||||
|
||||
// want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
|
||||
let dylib_prefix = format!("{}{}", dypair.0, self.crate_name);
|
||||
let rlib_prefix = format!("lib{}", self.crate_name);
|
||||
let staticlib_prefix = format!("{}{}", staticpair.0, self.crate_name);
|
||||
let dylib_prefix = format!("{}{}{}", dypair.0, self.crate_name, extra_prefix);
|
||||
let rlib_prefix = format!("lib{}{}", self.crate_name, extra_prefix);
|
||||
let staticlib_prefix = format!("{}{}{}", staticpair.0, self.crate_name, extra_prefix);
|
||||
|
||||
let mut candidates = FxHashMap();
|
||||
let mut staticlibs = vec![];
|
||||
@ -476,6 +489,7 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
return FileDoesntMatch;
|
||||
};
|
||||
|
||||
info!("lib candidate: {}", path.display());
|
||||
|
||||
let hash_str = hash.to_string();
|
||||
@ -484,6 +498,10 @@ impl<'a> Context<'a> {
|
||||
let (ref mut rlibs, ref mut rmetas, ref mut dylibs) = *slot;
|
||||
fs::canonicalize(path)
|
||||
.map(|p| {
|
||||
if seen_paths.contains(&p) {
|
||||
return FileDoesntMatch
|
||||
};
|
||||
seen_paths.insert(p.clone());
|
||||
match found_kind {
|
||||
CrateFlavor::Rlib => { rlibs.insert(p, kind); }
|
||||
CrateFlavor::Rmeta => { rmetas.insert(p, kind); }
|
||||
|
@ -188,6 +188,7 @@ pub enum LazyState {
|
||||
pub struct CrateRoot {
|
||||
pub name: Symbol,
|
||||
pub triple: TargetTriple,
|
||||
pub extra_filename: String,
|
||||
pub hash: hir::svh::Svh,
|
||||
pub disambiguator: CrateDisambiguator,
|
||||
pub panic_strategy: PanicStrategy,
|
||||
@ -216,12 +217,14 @@ pub struct CrateDep {
|
||||
pub name: ast::Name,
|
||||
pub hash: hir::svh::Svh,
|
||||
pub kind: DepKind,
|
||||
pub extra_filename: String,
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct CrateDep {
|
||||
name,
|
||||
hash,
|
||||
kind
|
||||
kind,
|
||||
extra_filename
|
||||
});
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
|
@ -427,14 +427,14 @@ fn generate_fn_name_span(cm: &CodeMap, span: Span) -> Option<Span> {
|
||||
/// a new local type parameter.
|
||||
///
|
||||
/// For instance:
|
||||
/// ```
|
||||
/// ```rust,ignore (pseudo-Rust)
|
||||
/// // Given span
|
||||
/// fn my_function(param: T)
|
||||
/// ^ Original span
|
||||
/// // ^ Original span
|
||||
///
|
||||
/// // Result
|
||||
/// fn my_function(param: T)
|
||||
/// ^^^^^^^^^^^ Generated span with snippet `my_function<T>`
|
||||
/// // ^^^^^^^^^^^ Generated span with snippet `my_function<T>`
|
||||
/// ```
|
||||
///
|
||||
/// Attention: The method used is very fragile since it essentially duplicates the work of the
|
||||
|
@ -694,7 +694,7 @@ fn link_natively(sess: &Session,
|
||||
loop {
|
||||
i += 1;
|
||||
prog = time(sess, "running linker", || {
|
||||
exec_linker(sess, &mut cmd, tmpdir)
|
||||
exec_linker(sess, &mut cmd, out_filename, tmpdir)
|
||||
});
|
||||
let output = match prog {
|
||||
Ok(ref output) => output,
|
||||
@ -822,7 +822,7 @@ fn link_natively(sess: &Session,
|
||||
}
|
||||
}
|
||||
|
||||
fn exec_linker(sess: &Session, cmd: &mut Command, tmpdir: &Path)
|
||||
fn exec_linker(sess: &Session, cmd: &mut Command, out_filename: &Path, tmpdir: &Path)
|
||||
-> io::Result<Output>
|
||||
{
|
||||
// When attempting to spawn the linker we run a risk of blowing out the
|
||||
@ -836,7 +836,11 @@ fn exec_linker(sess: &Session, cmd: &mut Command, tmpdir: &Path)
|
||||
// there instead of looking at the command line.
|
||||
if !cmd.very_likely_to_exceed_some_spawn_limit() {
|
||||
match cmd.command().stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() {
|
||||
Ok(child) => return child.wait_with_output(),
|
||||
Ok(child) => {
|
||||
let output = child.wait_with_output();
|
||||
flush_linked_file(&output, out_filename)?;
|
||||
return output;
|
||||
}
|
||||
Err(ref e) if command_line_too_big(e) => {
|
||||
info!("command line to linker was too big: {}", e);
|
||||
}
|
||||
@ -870,7 +874,37 @@ fn exec_linker(sess: &Session, cmd: &mut Command, tmpdir: &Path)
|
||||
fs::write(&file, &bytes)?;
|
||||
cmd2.arg(format!("@{}", file.display()));
|
||||
info!("invoking linker {:?}", cmd2);
|
||||
return cmd2.output();
|
||||
let output = cmd2.output();
|
||||
flush_linked_file(&output, out_filename)?;
|
||||
return output;
|
||||
|
||||
#[cfg(unix)]
|
||||
fn flush_linked_file(_: &io::Result<Output>, _: &Path) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn flush_linked_file(command_output: &io::Result<Output>, out_filename: &Path)
|
||||
-> io::Result<()>
|
||||
{
|
||||
// On Windows, under high I/O load, output buffers are sometimes not flushed,
|
||||
// even long after process exit, causing nasty, non-reproducible output bugs.
|
||||
//
|
||||
// File::sync_all() calls FlushFileBuffers() down the line, which solves the problem.
|
||||
//
|
||||
// А full writeup of the original Chrome bug can be found at
|
||||
// randomascii.wordpress.com/2018/02/25/compiler-bug-linker-bug-windows-kernel-bug/amp
|
||||
|
||||
if let &Ok(ref out) = command_output {
|
||||
if out.status.success() {
|
||||
if let Ok(of) = fs::OpenOptions::new().write(true).open(out_filename) {
|
||||
of.sync_all()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn command_line_too_big(err: &io::Error) -> bool {
|
||||
|
@ -1164,10 +1164,12 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
/// constraint that `'z <= 'a`. Given this setup, let's clarify the
|
||||
/// parameters in (roughly) terms of the example:
|
||||
///
|
||||
/// ```plain,ignore (pseudo-Rust)
|
||||
/// A borrow of: `& 'z bk * r` where `r` has type `& 'a bk T`
|
||||
/// borrow_region ^~ ref_region ^~
|
||||
/// borrow_kind ^~ ref_kind ^~
|
||||
/// ref_cmt ^
|
||||
/// ```
|
||||
///
|
||||
/// Here `bk` stands for some borrow-kind (e.g., `mut`, `uniq`, etc).
|
||||
///
|
||||
|
@ -42,21 +42,21 @@ use syntax_pos::Span;
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```
|
||||
/// ```rust,ignore (pseudo-Rust)
|
||||
/// impl<T> Trait<Foo> for Bar { ... }
|
||||
/// ^ T does not appear in `Foo` or `Bar`, error!
|
||||
/// // ^ T does not appear in `Foo` or `Bar`, error!
|
||||
///
|
||||
/// impl<T> Trait<Foo<T>> for Bar { ... }
|
||||
/// ^ T appears in `Foo<T>`, ok.
|
||||
/// // ^ T appears in `Foo<T>`, ok.
|
||||
///
|
||||
/// impl<T> Trait<Foo> for Bar where Bar: Iterator<Item=T> { ... }
|
||||
/// ^ T is bound to `<Bar as Iterator>::Item`, ok.
|
||||
/// // ^ T is bound to `<Bar as Iterator>::Item`, ok.
|
||||
///
|
||||
/// impl<'a> Trait<Foo> for Bar { }
|
||||
/// ^ 'a is unused, but for back-compat we allow it
|
||||
/// // ^ 'a is unused, but for back-compat we allow it
|
||||
///
|
||||
/// impl<'a> Trait<Foo> for Bar { type X = &'a i32; }
|
||||
/// ^ 'a is unused and appears in assoc type, error
|
||||
/// // ^ 'a is unused and appears in assoc type, error
|
||||
/// ```
|
||||
pub fn impl_wf_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
// We will tag this as part of the WF check -- logically, it is,
|
||||
|
@ -193,7 +193,7 @@ declare_features! (
|
||||
(active, rustc_attrs, "1.0.0", Some(29642), None),
|
||||
|
||||
// Allows the use of non lexical lifetimes; RFC 2094
|
||||
(active, nll, "1.0.0", Some(43234), None),
|
||||
(active, nll, "1.0.0", Some(43234), Some(Edition::Edition2018)),
|
||||
|
||||
// Allows the use of #[allow_internal_unstable]. This is an
|
||||
// attribute on macro_rules! and can't use the attribute handling
|
||||
@ -388,7 +388,7 @@ declare_features! (
|
||||
(active, dyn_trait, "1.22.0", Some(44662), Some(Edition::Edition2018)),
|
||||
|
||||
// `crate` as visibility modifier, synonymous to `pub(crate)`
|
||||
(active, crate_visibility_modifier, "1.23.0", Some(45388), None),
|
||||
(active, crate_visibility_modifier, "1.23.0", Some(45388), Some(Edition::Edition2018)),
|
||||
|
||||
// extern types
|
||||
(active, extern_types, "1.23.0", Some(43467), None),
|
||||
@ -397,10 +397,10 @@ declare_features! (
|
||||
(active, arbitrary_self_types, "1.23.0", Some(44874), None),
|
||||
|
||||
// `crate` in paths
|
||||
(active, crate_in_paths, "1.23.0", Some(45477), None),
|
||||
(active, crate_in_paths, "1.23.0", Some(45477), Some(Edition::Edition2018)),
|
||||
|
||||
// In-band lifetime bindings (e.g. `fn foo(x: &'a u8) -> &'a u8`)
|
||||
(active, in_band_lifetimes, "1.23.0", Some(44524), None),
|
||||
(active, in_band_lifetimes, "1.23.0", Some(44524), Some(Edition::Edition2018)),
|
||||
|
||||
// generic associated types (RFC 1598)
|
||||
(active, generic_associated_types, "1.23.0", Some(44265), None),
|
||||
@ -409,10 +409,10 @@ declare_features! (
|
||||
(active, extern_absolute_paths, "1.24.0", Some(44660), None),
|
||||
|
||||
// `foo.rs` as an alternative to `foo/mod.rs`
|
||||
(active, non_modrs_mods, "1.24.0", Some(44660), None),
|
||||
(active, non_modrs_mods, "1.24.0", Some(44660), Some(Edition::Edition2018)),
|
||||
|
||||
// Termination trait in tests (RFC 1937)
|
||||
(active, termination_trait_test, "1.24.0", Some(48854), None),
|
||||
(active, termination_trait_test, "1.24.0", Some(48854), Some(Edition::Edition2018)),
|
||||
|
||||
// Allows use of the :lifetime macro fragment specifier
|
||||
(active, macro_lifetime_matcher, "1.24.0", Some(46895), None),
|
||||
|
@ -35,5 +35,6 @@ cc = "1.0.1"
|
||||
[features]
|
||||
c = []
|
||||
default = ["c", "rustbuild", "compiler-builtins"]
|
||||
mem = []
|
||||
rustbuild = []
|
||||
compiler-builtins = []
|
||||
|
@ -0,0 +1,28 @@
|
||||
// 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.
|
||||
|
||||
#![feature(non_exhaustive)]
|
||||
|
||||
#[non_exhaustive(anything)]
|
||||
//~^ ERROR attribute should be empty [E0911]
|
||||
struct Foo;
|
||||
|
||||
#[non_exhaustive]
|
||||
//~^ ERROR attribute can only be applied to a struct or enum [E0910]
|
||||
trait Bar { }
|
||||
|
||||
#[non_exhaustive]
|
||||
//~^ ERROR attribute can only be applied to a struct or enum [E0910]
|
||||
union Baz {
|
||||
f1: u16,
|
||||
f2: u16
|
||||
}
|
||||
|
||||
fn main() { }
|
7
src/test/run-make-fulldeps/resolve-rename/Makefile
Normal file
7
src/test/run-make-fulldeps/resolve-rename/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
-include ../tools.mk
|
||||
|
||||
all:
|
||||
$(RUSTC) -C extra-filename=-hash foo.rs
|
||||
$(RUSTC) bar.rs
|
||||
mv $(TMPDIR)/libfoo-hash.rlib $(TMPDIR)/libfoo-another-hash.rlib
|
||||
$(RUSTC) baz.rs
|
15
src/test/run-make-fulldeps/resolve-rename/bar.rs
Normal file
15
src/test/run-make-fulldeps/resolve-rename/bar.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
extern crate foo;
|
||||
|
||||
pub fn bar() { foo::foo() }
|
15
src/test/run-make-fulldeps/resolve-rename/baz.rs
Normal file
15
src/test/run-make-fulldeps/resolve-rename/baz.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
extern crate bar;
|
||||
|
||||
pub fn baz() { bar::bar() }
|
13
src/test/run-make-fulldeps/resolve-rename/foo.rs
Normal file
13
src/test/run-make-fulldeps/resolve-rename/foo.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
pub fn foo() {}
|
Loading…
x
Reference in New Issue
Block a user