diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index da57881202d17..9cc18464fea09 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -140,48 +140,58 @@ pub fn std_cargo(build: &Builder, compiler: &Compiler, target: Interned, 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(); + + // 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 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); - } + 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")); + 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 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); + if target.contains("musl") { + if let Some(p) = build.musl_root(target) { + cargo.env("MUSL_ROOT", p); + } } } } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 76672df5c570d..863abd14935a8 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -161,6 +161,7 @@ pub struct Target { pub crt_static: Option, pub musl_root: Option, pub qemu_rootfs: Option, + pub no_std: bool, } /// Structure of the `config.toml` file that configuration is read from. diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index c9be17ff1ad2d..e1f5d34bf6723 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -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)); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 2eeb2691eaee4..ea4368c0323fb 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -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) -> Option { + 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) -> bool { diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 5184cca653c4b..1b1cec5f18c07 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -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, diff --git a/src/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile index 1b6ee44d87afc..00366301aa17a 100644 --- a/src/ci/docker/dist-various-1/Dockerfile +++ b/src/ci/docker/dist-various-1/Dockerfile @@ -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 diff --git a/src/ci/docker/wasm32-unknown/Dockerfile b/src/ci/docker/wasm32-unknown/Dockerfile index 6c0ec1ad9d4e1..28d11064c6bba 100644 --- a/src/ci/docker/wasm32-unknown/Dockerfile +++ b/src/ci/docker/wasm32-unknown/Dockerfile @@ -25,6 +25,12 @@ ENV RUST_CONFIGURE_ARGS \ --set build.nodejs=/node-v9.2.0-linux-x64/bin/node \ --set rust.lld +# Some run-make tests have assertions about code size, and enabling debug +# assertions in libstd causes the binary to be much bigger than it would +# otherwise normally be. We already test libstd with debug assertions in lots of +# other contexts as well +ENV NO_DEBUG_ASSERTIONS=1 + ENV SCRIPT python2.7 /checkout/x.py test --target $TARGETS \ src/test/run-make \ src/test/ui \ diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 51a7802540192..6ce2547ef6e6d 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -97,7 +97,7 @@ #![feature(fmt_internals)] #![feature(from_ref)] #![feature(fundamental)] -#![feature(generic_param_attrs)] +#![cfg_attr(stage0, feature(generic_param_attrs))] #![cfg_attr(stage0, feature(i128_type))] #![feature(lang_items)] #![feature(needs_allocator)] diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 02008310b8161..4b883b5bce79b 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1594,40 +1594,69 @@ impl SpecFromElem for u8 { } } -macro_rules! impl_spec_from_elem { +impl SpecFromElem for T { + #[inline] + fn from_elem(elem: T, n: usize) -> Vec { + 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 + } +} + +unsafe trait IsZero { + /// Whether this value is zero + fn is_zero(&self) -> bool; +} + +macro_rules! impl_is_zero { ($t: ty, $is_zero: expr) => { - impl SpecFromElem for $t { + unsafe impl IsZero 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 + fn is_zero(&self) -> bool { + $is_zero(*self) } } - }; + } } -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); +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); -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); +unsafe impl IsZero for *const T { + #[inline] + fn is_zero(&self) -> bool { + (*self).is_null() + } +} + +unsafe impl 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 diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 72fa3148fe54a..7eaf67e6ea66e 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -27,7 +27,7 @@ #![feature(alloc)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] -#![feature(generic_param_attrs)] +#![cfg_attr(stage0, feature(generic_param_attrs))] #![cfg_attr(test, feature(test))] #![allow(deprecated)] diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 4e72eaa57c73e..212139f1f7a41 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -249,3 +249,13 @@ impl<'a> fmt::Display for Location<'a> { write!(formatter, "{}:{}:{}", self.file, self.line, self.col) } } + +/// An internal trait used by libstd to pass data from libstd to `panic_unwind` +/// and other panic runtimes. Not intended to be stabilized any time soon, do +/// not use. +#[unstable(feature = "std_internals", issue = "0")] +#[doc(hidden)] +pub unsafe trait BoxMeUp { + fn box_me_up(&mut self) -> *mut (Any + Send); + fn get(&self) -> &(Any + Send); +} diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index 5f768ef4399e8..a1c4555d0b0e9 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -53,7 +53,7 @@ pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8), // now hopefully. #[no_mangle] #[rustc_std_internal_symbol] -pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 { +pub unsafe extern fn __rust_start_panic(_payload: usize) -> u32 { abort(); #[cfg(any(unix, target_os = "cloudabi"))] diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index a5cebc3e4d04b..cd7a643140239 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -30,6 +30,7 @@ issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] #![deny(warnings)] +#![feature(allocator_api)] #![feature(alloc)] #![feature(core_intrinsics)] #![feature(lang_items)] @@ -37,6 +38,7 @@ #![feature(panic_unwind)] #![feature(raw)] #![feature(staged_api)] +#![feature(std_internals)] #![feature(unwind_attributes)] #![cfg_attr(target_env = "msvc", feature(raw))] @@ -48,9 +50,11 @@ extern crate libc; #[cfg(not(any(target_env = "msvc", all(windows, target_arch = "x86_64", target_env = "gnu"))))] extern crate unwind; +use alloc::boxed::Box; use core::intrinsics; use core::mem; use core::raw; +use core::panic::BoxMeUp; // Rust runtime's startup objects depend on these symbols, so make them public. #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] @@ -114,9 +118,7 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8), #[no_mangle] #[cfg_attr(stage0, unwind)] #[cfg_attr(not(stage0), unwind(allowed))] -pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 { - imp::panic(mem::transmute(raw::TraitObject { - data: data as *mut (), - vtable: vtable as *mut (), - })) +pub unsafe extern "C" fn __rust_start_panic(payload: usize) -> u32 { + let payload = payload as *mut &mut BoxMeUp; + imp::panic(Box::from_raw((*payload).box_me_up())) } diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 007093981d3e1..6e7b14a9f3ab7 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -720,15 +720,17 @@ impl TokenTree { }).into(); }, TokenNode::Term(symbol) => { - let ident = ast::Ident { name: symbol.0, ctxt: self.span.0.ctxt() }; + let ident = ast::Ident::new(symbol.0, self.span.0); let sym_str = symbol.0.as_str(); - let token = - if sym_str.starts_with("'") { Lifetime(ident) } - else if sym_str.starts_with("r#") { - let name = Symbol::intern(&sym_str[2..]); - let ident = ast::Ident { name, ctxt: self.span.0.ctxt() }; - Ident(ident, true) - } else { Ident(ident, false) }; + let token = if sym_str.starts_with("'") { + Lifetime(ident) + } else if sym_str.starts_with("r#") { + let name = Symbol::intern(&sym_str[2..]); + let ident = ast::Ident::new(name, ident.span); + Ident(ident, true) + } else { + Ident(ident, false) + }; return TokenTree::Token(self.span.0, token).into(); } TokenNode::Literal(self::Literal(Literal(Lit::Integer(ref a), b))) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 42cda6a05a1a7..d1f3736556c5d 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -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), diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index c74ae2343b866..2662e70999196 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -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; +``` +"##, } diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 316ed07ca05d9..956cd17f38f21 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -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: diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 5f9f37094f579..d8c482ef7daed 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -909,7 +909,7 @@ impl<'a> LoweringContext<'a> { fn lower_ident(&mut self, ident: Ident) -> Name { let ident = ident.modern(); - if ident.ctxt == SyntaxContext::empty() { + if ident.span.ctxt() == SyntaxContext::empty() { return ident.name; } *self.name_map @@ -920,7 +920,7 @@ impl<'a> LoweringContext<'a> { fn lower_label(&mut self, label: Option