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:
bors 2018-04-05 13:07:45 +00:00
commit 56714acc5e
35 changed files with 571 additions and 125 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
```
"##,
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -35,5 +35,6 @@ cc = "1.0.1"
[features]
c = []
default = ["c", "rustbuild", "compiler-builtins"]
mem = []
rustbuild = []
compiler-builtins = []

View File

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

View 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

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

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

View 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() {}