diff --git a/.travis.yml b/.travis.yml index db34f1404481b..33982838eae32 100644 --- a/.travis.yml +++ b/.travis.yml @@ -253,7 +253,14 @@ after_failure: # Random attempt at debugging currently. Just poking around in here to see if # anything shows up. - - ls $HOME/Library/Logs/DiagnosticReports/ + - ls -lat $HOME/Library/Logs/DiagnosticReports/ + - find $HOME/Library/Logs/DiagnosticReports/ ! \( + -name '*.stage2-*.crash' + -name 'com.apple.CoreSimulator.CoreSimulatorService-*.crash' + \) + -exec echo -e travis_fold":start:crashlog\n\033[31;1m" {} "\033[0m" \; + -exec head -750 {} \; + -exec echo travis_fold":"end:crashlog \; # attempt to debug anything killed by the oom killer on linux, just to see if # it happened @@ -286,6 +293,7 @@ before_deploy: rm -rf obj/build/dist/doc && cp -r obj/build/dist/* deploy/$TRAVIS_COMMIT; fi + - travis_retry gem update --system deploy: - provider: s3 diff --git a/src/Cargo.lock b/src/Cargo.lock index 79aea99a5a98a..ff97de681a1a3 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -348,7 +348,9 @@ dependencies = [ "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index adce6a00d4623..922deba7367e9 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -22,6 +22,48 @@ Images will output artifacts in an `obj` dir at the root of a repository. - `scripts` contains files shared by docker images - `disabled` contains images that are not built on travis +## Docker Toolbox on Windows + +For Windows before Windows 10, the docker images can be run on Windows via +[Docker Toolbox]. There are several preparation needs to be made before running +a Docker image. + +1. Stop the virtual machine from the terminal with `docker-machine stop` + +2. If your Rust source is placed outside of `C:\Users\**`, e.g. if you place the + repository in the `E:\rust` folder, please add a shared folder from + VirtualBox by: + + 1. Select the "default" virtual machine inside VirtualBox, then click + "Settings" + 2. Go to "Shared Folders", click "Add shared foldrer" (the folder icon with + a plus sign), fill in the following information, then click "OK": + + * Folder path: `E:\rust` + * Folder name: `e/rust` + * Read-only: ☐ *unchecked* + * Auto-mount: ☑ *checked* + * Make Permanant: ☑ *checked* + +3. VirtualBox might not support creating symbolic links inside a shared folder + by default. You can enable it manually by running these from `cmd.exe`: + + ```bat + cd "C:\Program Files\Oracle\VirtualBox" + VBoxManage setextradata default VBoxInternal2/SharedFoldersEnableSymlinksCreate/e/rust 1 + :: ^~~~~~ + :: folder name + ``` + +4. Restart the virtual machine from terminal with `docker-machine start`. + +To run the image, + +1. Launch the "Docker Quickstart Terminal". +2. Execute `./src/ci/docker/run.sh $image_name` as explained at the beginning. + +[Docker Toolbox]: https://www.docker.com/products/docker-toolbox + ## Cross toolchains A number of these images take quite a long time to compile as they're building @@ -137,7 +179,7 @@ For targets: `armv7-unknown-linux-gnueabihf` libraries like jemalloc. See the mk/cfg/arm(v7)-uknown-linux-gnueabi{,hf}.mk file in Rust's source code. -## `aarch64-linux-gnu.config` +### `aarch64-linux-gnu.config` For targets: `aarch64-unknown-linux-gnu` @@ -150,7 +192,7 @@ For targets: `aarch64-unknown-linux-gnu` - C compiler > gcc version = 5.2.0 - C compiler > C++ = ENABLE -- to cross compile LLVM -## `powerpc-linux-gnu.config` +### `powerpc-linux-gnu.config` For targets: `powerpc-unknown-linux-gnu` @@ -165,7 +207,7 @@ For targets: `powerpc-unknown-linux-gnu` - C compiler > gcc version = 4.9.3 - C compiler > C++ = ENABLE -- to cross compile LLVM -## `powerpc64-linux-gnu.config` +### `powerpc64-linux-gnu.config` For targets: `powerpc64-unknown-linux-gnu` @@ -184,7 +226,7 @@ For targets: `powerpc64-unknown-linux-gnu` (+) These CPU options match the configuration of the toolchains in RHEL6. -## `s390x-linux-gnu.config` +### `s390x-linux-gnu.config` For targets: `s390x-unknown-linux-gnu` diff --git a/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh b/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh index f231d20b19753..5f556b67081a3 100755 --- a/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh +++ b/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh @@ -23,9 +23,9 @@ SYSROOT=/usr/local/$TARGET/sysroot mkdir -p $SYSROOT pushd $SYSROOT -centos_base=http://mirror.centos.org/altarch/7/os/ppc64le/Packages -glibc_v=2.17-196.el7 -kernel_v=3.10.0-693.el7 +centos_base=http://vault.centos.org/altarch/7.3.1611/os/ppc64le/Packages/ +glibc_v=2.17-157.el7 +kernel_v=3.10.0-514.el7 for package in glibc{,-devel,-headers}-$glibc_v kernel-headers-$kernel_v; do curl $centos_base/$package.ppc64le.rpm | \ rpm2cpio - | cpio -idm diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index b2560c6b95b4c..dc02310b4f21f 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -11,6 +11,8 @@ set -e +export MSYS_NO_PATHCONV=1 + script=`cd $(dirname $0) && pwd`/`basename $0` image=$1 @@ -25,12 +27,19 @@ travis_fold start build_docker travis_time_start if [ -f "$docker_dir/$image/Dockerfile" ]; then + dockerfile="$docker_dir/$image/Dockerfile" + if [ -x /usr/bin/cygpath ]; then + context="`cygpath -w $docker_dir`" + dockerfile="`cygpath -w $dockerfile`" + else + context="$docker_dir" + fi retry docker \ build \ --rm \ -t rust-ci \ - -f "$docker_dir/$image/Dockerfile" \ - "$docker_dir" + -f "$dockerfile" \ + "$context" elif [ -f "$docker_dir/disabled/$image/Dockerfile" ]; then if [ -n "$TRAVIS_OS_NAME" ]; then echo Cannot run disabled images on travis! diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 5f0b4088fc07e..a167b2e57c078 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -363,16 +363,16 @@ impl str { /// # Examples /// /// ``` - /// let mut v = String::from("🗻∈🌏"); + /// let v = String::from("🗻∈🌏"); /// /// assert_eq!(Some("🗻"), v.get(0..4)); /// /// // indices not on UTF-8 sequence boundaries - /// assert!(v.get_mut(1..).is_none()); - /// assert!(v.get_mut(..8).is_none()); + /// assert!(v.get(1..).is_none()); + /// assert!(v.get(..8).is_none()); /// /// // out of bounds - /// assert!(v.get_mut(..42).is_none()); + /// assert!(v.get(..42).is_none()); /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 1e45af5b105c9..e2d61890c3096 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -525,6 +525,26 @@ impl<'a> Display for Arguments<'a> { #[lang = "debug_trait"] pub trait Debug { /// Formats the value using the given formatter. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Position { + /// longitude: f32, + /// latitude: f32, + /// } + /// + /// impl fmt::Debug for Position { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "({:?}, {:?})", self.longitude, self.latitude) + /// } + /// } + /// + /// assert_eq!("(1.987, 2.983)".to_owned(), + /// format!("{:?}", Position { longitude: 1.987, latitude: 2.983, })); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn fmt(&self, f: &mut Formatter) -> Result; } diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 12667036444e6..c410c2d900470 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -120,6 +120,9 @@ macro_rules! assert_eq { } } }); + ($left:expr, $right:expr,) => ({ + assert_eq!($left, $right) + }); ($left:expr, $right:expr, $($arg:tt)+) => ({ match (&($left), &($right)) { (left_val, right_val) => { @@ -168,6 +171,9 @@ macro_rules! assert_ne { } } }); + ($left:expr, $right:expr,) => { + assert_ne!($left, $right) + }; ($left:expr, $right:expr, $($arg:tt)+) => ({ match (&($left), &($right)) { (left_val, right_val) => { diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 980ea551f0806..63c846b25eca5 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -607,6 +607,45 @@ impl Option { } } + /// Returns `None` if the option is `None`, otherwise calls `predicate` + /// with the wrapped value and returns: + /// + /// - `Some(t)` if `predicate` returns `true` (where `t` is the wrapped + /// value), and + /// - `None` if `predicate` returns `false`. + /// + /// This function works similar to `Iterator::filter()`. You can imagine + /// the `Option` being an iterator over one or zero elements. `filter()` + /// lets you decide which elements to keep. + /// + /// # Examples + /// + /// ```rust + /// #![feature(option_filter)] + /// + /// fn is_even(n: &i32) -> bool { + /// n % 2 == 0 + /// } + /// + /// assert_eq!(None.filter(is_even), None); + /// assert_eq!(Some(3).filter(is_even), None); + /// assert_eq!(Some(4).filter(is_even), Some(4)); + /// ``` + #[inline] + #[unstable(feature = "option_filter", issue = "45860")] + pub fn filter bool>(self, predicate: P) -> Self { + match self { + Some(x) => { + if predicate(&x) { + Some(x) + } else { + None + } + } + None => None, + } + } + /// Returns the option if it contains a value, otherwise returns `optb`. /// /// # Examples diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index cd3dd9ce1399e..b7cf6d778a2f9 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -927,6 +927,7 @@ impl AtomicPtr { } } +#[cfg(target_has_atomic = "ptr")] #[stable(feature = "atomic_from", since = "1.23.0")] impl From<*mut T> for AtomicPtr { #[inline] diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index f2453d3946172..95e9c8f6df882 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -37,7 +37,7 @@ const UNKNOWN_SIZE_COST: usize = 10; pub struct Inline; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] struct CallSite<'tcx> { callee: DefId, substs: &'tcx Substs<'tcx>, @@ -113,7 +113,9 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { loop { local_change = false; while let Some(callsite) = callsites.pop_front() { + debug!("checking whether to inline callsite {:?}", callsite); if !self.tcx.is_mir_available(callsite.callee) { + debug!("checking whether to inline callsite {:?} - MIR unavailable", callsite); continue; } @@ -133,10 +135,12 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { }; let start = caller_mir.basic_blocks().len(); - + debug!("attempting to inline callsite {:?} - mir={:?}", callsite, callee_mir); if !self.inline_call(callsite, caller_mir, callee_mir) { + debug!("attempting to inline callsite {:?} - failure", callsite); continue; } + debug!("attempting to inline callsite {:?} - success", callsite); // Add callsites from inlined function for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated().skip(start) { @@ -180,16 +184,19 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { callee_mir: &Mir<'tcx>) -> bool { + debug!("should_inline({:?})", callsite); let tcx = self.tcx; // Don't inline closures that have captures // FIXME: Handle closures better if callee_mir.upvar_decls.len() > 0 { + debug!(" upvar decls present - not inlining"); return false; } // Cannot inline generators which haven't been transformed yet if callee_mir.yield_ty.is_some() { + debug!(" yield ty present - not inlining"); return false; } @@ -201,7 +208,10 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // there are cases that prevent inlining that we // need to check for first. attr::InlineAttr::Always => true, - attr::InlineAttr::Never => return false, + attr::InlineAttr::Never => { + debug!("#[inline(never)] present - not inlining"); + return false + } attr::InlineAttr::Hint => true, attr::InlineAttr::None => false, }; @@ -211,6 +221,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // reference unexported symbols if callsite.callee.is_local() { if callsite.substs.types().count() == 0 && !hinted { + debug!(" callee is an exported function - not inlining"); return false; } } @@ -232,6 +243,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { if callee_mir.basic_blocks().len() <= 3 { threshold += threshold / 4; } + debug!(" final inline threshold = {}", threshold); // FIXME: Give a bonus to functions with only a single caller @@ -327,12 +339,17 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } } - debug!("Inline cost for {:?} is {}", callsite.callee, cost); - if let attr::InlineAttr::Always = hint { + debug!("INLINING {:?} because inline(always) [cost={}]", callsite, cost); true } else { - cost <= threshold + if cost <= threshold { + debug!("INLINING {:?} [cost={} <= threshold={}]", callsite, cost, threshold); + true + } else { + debug!("NOT inlining {:?} [cost={} > threshold={}]", callsite, cost, threshold); + false + } } } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index a10bce2934226..b30fc38fcbcdf 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -250,7 +250,7 @@ impl<'a> Resolver<'a> { } } - ItemKind::ExternCrate(_) => { + ItemKind::ExternCrate(as_name) => { self.crate_loader.process_item(item, &self.definitions); // n.b. we don't need to look at the path option here, because cstore already did @@ -265,7 +265,7 @@ impl<'a> Resolver<'a> { id: item.id, parent, imported_module: Cell::new(Some(module)), - subclass: ImportDirectiveSubclass::ExternCrate, + subclass: ImportDirectiveSubclass::ExternCrate(as_name), span: item.span, module_path: Vec::new(), vis: Cell::new(vis), diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index a66d1ce0859b7..5820acf1b9006 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -120,7 +120,7 @@ pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) { _ if directive.used.get() || directive.vis.get() == ty::Visibility::Public || directive.span.source_equal(&DUMMY_SP) => {} - ImportDirectiveSubclass::ExternCrate => { + ImportDirectiveSubclass::ExternCrate(_) => { resolver.maybe_unused_extern_crates.push((directive.id, directive.span)); } ImportDirectiveSubclass::MacroUse => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index f3d4e0a784808..58bdf542fc9d4 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1118,7 +1118,7 @@ impl<'a> NameBinding<'a> { match self.kind { NameBindingKind::Import { directive: &ImportDirective { - subclass: ImportDirectiveSubclass::ExternCrate, .. + subclass: ImportDirectiveSubclass::ExternCrate(_), .. }, .. } => true, _ => false, @@ -1132,6 +1132,15 @@ impl<'a> NameBinding<'a> { } } + fn is_renamed_extern_crate(&self) -> bool { + if let NameBindingKind::Import { directive, ..} = self.kind { + if let ImportDirectiveSubclass::ExternCrate(Some(_)) = directive.subclass { + return true; + } + } + false + } + fn is_glob_import(&self) -> bool { match self.kind { NameBindingKind::Import { directive, .. } => directive.is_glob(), @@ -3700,7 +3709,8 @@ impl<'a> Resolver<'a> { let cm = self.session.codemap(); let rename_msg = "You can use `as` to change the binding name of the import"; - if let Ok(snippet) = cm.span_to_snippet(binding.span) { + if let (Ok(snippet), false) = (cm.span_to_snippet(binding.span), + binding.is_renamed_extern_crate()) { err.span_suggestion(binding.span, rename_msg, format!("{} as Other{}", snippet, name)); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index b85bf18ea800c..bcbabd700946a 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -23,7 +23,7 @@ use rustc::hir::def_id::DefId; use rustc::hir::def::*; use rustc::util::nodemap::{FxHashMap, FxHashSet}; -use syntax::ast::{Ident, SpannedIdent, NodeId}; +use syntax::ast::{Ident, Name, SpannedIdent, NodeId}; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::ext::hygiene::Mark; use syntax::parse::token; @@ -48,7 +48,7 @@ pub enum ImportDirectiveSubclass<'a> { max_vis: Cell, // The visibility of the greatest reexport. // n.b. `max_vis` is only used in `finalize_import` to check for reexport errors. }, - ExternCrate, + ExternCrate(Option), MacroUse, } @@ -923,7 +923,7 @@ fn import_directive_subclass_to_string(subclass: &ImportDirectiveSubclass) -> St match *subclass { SingleImport { source, .. } => source.to_string(), GlobImport { .. } => "*".to_string(), - ExternCrate => "".to_string(), + ExternCrate(_) => "".to_string(), MacroUse => "#[macro_use]".to_string(), } } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 907693ea8a379..1961acf53a695 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -671,11 +671,12 @@ fn link_natively(sess: &Session, break } - sess.struct_warn("looks like the linker segfaulted when we tried to \ - call it, automatically retrying again") - .note(&format!("{:?}", cmd)) - .note(&out) - .emit(); + warn!( + "looks like the linker segfaulted when we tried to call it, \ + automatically retrying again. cmd = {:?}, out = {}.", + cmd, + out, + ); } match prog { diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index e8a1242c8145f..76abcb83edc53 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -71,6 +71,7 @@ use std::thread; use std::time::{Instant, Duration}; const TEST_WARN_TIMEOUT_S: u64 = 60; +const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in quiet mode // to be used by rustc to compile tests in libtest pub mod test { @@ -614,7 +615,14 @@ impl ConsoleTestState { pub fn write_short_result(&mut self, verbose: &str, quiet: &str, color: term::color::Color) -> io::Result<()> { if self.quiet { - self.write_pretty(quiet, color) + self.write_pretty(quiet, color)?; + if self.current_test_count() % QUIET_MODE_MAX_COLUMN == QUIET_MODE_MAX_COLUMN - 1 { + // we insert a new line every 100 dots in order to flush the + // screen when dealing with line-buffered output (e.g. piping to + // `stamp` in the rust CI). + self.write_plain("\n")?; + } + Ok(()) } else { self.write_pretty(verbose, color)?; self.write_plain("\n") @@ -771,9 +779,12 @@ impl ConsoleTestState { Ok(()) } + fn current_test_count(&self) -> usize { + self.passed + self.failed + self.ignored + self.measured + self.allowed_fail + } + pub fn write_run_finish(&mut self) -> io::Result { - assert!(self.passed + self.failed + self.ignored + self.measured + - self.allowed_fail == self.total); + assert!(self.current_test_count() == self.total); if self.options.display_output { self.write_outputs()?; diff --git a/src/test/compile-fail/E0259.rs b/src/test/compile-fail/E0259.rs index c285c4d9e00c1..e125cc0c19c37 100644 --- a/src/test/compile-fail/E0259.rs +++ b/src/test/compile-fail/E0259.rs @@ -18,5 +18,6 @@ extern crate libc as alloc; //~^ ERROR E0259 //~| NOTE `alloc` reimported here //~| NOTE `alloc` must be defined only once in the type namespace of this module +//~| NOTE You can use `as` to change the binding name of the import fn main() {} diff --git a/src/test/ui/macros/assert_eq_trailing_comma.rs b/src/test/run-pass/assert-eq-trailing-comma.rs similarity index 100% rename from src/test/ui/macros/assert_eq_trailing_comma.rs rename to src/test/run-pass/assert-eq-trailing-comma.rs diff --git a/src/test/ui/macros/assert_ne_trailing_comma.rs b/src/test/run-pass/assert-ne-trailing-comma.rs similarity index 100% rename from src/test/ui/macros/assert_ne_trailing_comma.rs rename to src/test/run-pass/assert-ne-trailing-comma.rs diff --git a/src/test/run-pass/saturating-float-casts.rs b/src/test/run-pass/saturating-float-casts.rs index 6db4d7635f07f..010ecebb1bbe3 100644 --- a/src/test/run-pass/saturating-float-casts.rs +++ b/src/test/run-pass/saturating-float-casts.rs @@ -48,8 +48,8 @@ macro_rules! test_c { }); ($fval:expr, f* -> $ity:ident, $ival:expr) => ( - test!($fval, f32 -> $ity, $ival); - test!($fval, f64 -> $ity, $ival); + test_c!($fval, f32 -> $ity, $ival); + test_c!($fval, f64 -> $ity, $ival); ) } diff --git a/src/test/ui/macros/assert_eq_trailing_comma.stderr b/src/test/ui/macros/assert_eq_trailing_comma.stderr deleted file mode 100644 index 1b46e94584e6b..0000000000000 --- a/src/test/ui/macros/assert_eq_trailing_comma.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: unexpected end of macro invocation - --> $DIR/assert_eq_trailing_comma.rs:12:20 - | -12 | assert_eq!(1, 1,); - | ^ - -error: aborting due to previous error - diff --git a/src/test/ui/macros/assert_ne_trailing_comma.stderr b/src/test/ui/macros/assert_ne_trailing_comma.stderr deleted file mode 100644 index 33d2cb0ed8242..0000000000000 --- a/src/test/ui/macros/assert_ne_trailing_comma.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: unexpected end of macro invocation - --> $DIR/assert_ne_trailing_comma.rs:12:20 - | -12 | assert_ne!(1, 2,); - | ^ - -error: aborting due to previous error - diff --git a/src/test/ui/suggestions/auxiliary/m1.rs b/src/test/ui/suggestions/auxiliary/m1.rs new file mode 100644 index 0000000000000..b61667cfd882c --- /dev/null +++ b/src/test/ui/suggestions/auxiliary/m1.rs @@ -0,0 +1,11 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn foo() {} diff --git a/src/test/ui/suggestions/auxiliary/m2.rs b/src/test/ui/suggestions/auxiliary/m2.rs new file mode 100644 index 0000000000000..94ff5e4497fe9 --- /dev/null +++ b/src/test/ui/suggestions/auxiliary/m2.rs @@ -0,0 +1,11 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn bar() {} diff --git a/src/test/ui/suggestions/extern-crate-rename.rs b/src/test/ui/suggestions/extern-crate-rename.rs new file mode 100644 index 0000000000000..b3fa5871a82f5 --- /dev/null +++ b/src/test/ui/suggestions/extern-crate-rename.rs @@ -0,0 +1,18 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:m1.rs +// aux-build:m2.rs + + +extern crate m1; +extern crate m2 as m1; + +fn main() {} diff --git a/src/test/ui/suggestions/extern-crate-rename.stderr b/src/test/ui/suggestions/extern-crate-rename.stderr new file mode 100644 index 0000000000000..c15e238e8b0a3 --- /dev/null +++ b/src/test/ui/suggestions/extern-crate-rename.stderr @@ -0,0 +1,15 @@ +error[E0259]: the name `m1` is defined multiple times + --> $DIR/extern-crate-rename.rs:16:1 + | +15 | extern crate m1; + | ---------------- previous import of the extern crate `m1` here +16 | extern crate m2 as m1; + | ^^^^^^^^^^^^^^^^^^^^^^ + | | + | `m1` reimported here + | You can use `as` to change the binding name of the import + | + = note: `m1` must be defined only once in the type namespace of this module + +error: aborting due to previous error + diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index f8282cc5f8d9b..d4d567e63c017 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -11,3 +11,7 @@ getopts = "0.2" log = "0.3" rustc-serialize = "0.3" libc = "0.2" + +[target.'cfg(windows)'.dependencies] +miow = "0.2" +winapi = "0.2" diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 1701c8a3e43ee..9fb6a3f5e0753 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -11,10 +11,11 @@ #![crate_name = "compiletest"] #![feature(test)] +#![feature(slice_rotate)] #![deny(warnings)] -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(unix)] extern crate libc; extern crate test; extern crate getopts; @@ -47,6 +48,7 @@ pub mod runtest; pub mod common; pub mod errors; mod raise_fd_limit; +mod read2; fn main() { env_logger::init().unwrap(); diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs new file mode 100644 index 0000000000000..1d8816c7db132 --- /dev/null +++ b/src/tools/compiletest/src/read2.rs @@ -0,0 +1,208 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// FIXME: This is a complete copy of `cargo/src/cargo/util/read2.rs` +// Consider unify the read2() in libstd, cargo and this to prevent further code duplication. + +pub use self::imp::read2; + +#[cfg(not(any(unix, windows)))] +mod imp { + use std::io::{self, Read}; + use std::process::{ChildStdout, ChildStderr}; + + pub fn read2(out_pipe: ChildStdout, + err_pipe: ChildStderr, + data: &mut FnMut(bool, &mut Vec, bool)) -> io::Result<()> { + let mut buffer = Vec::new(); + out_pipe.read_to_end(&mut buffer)?; + data(true, &mut buffer, true); + buffer.clear(); + err_pipe.read_to_end(&mut buffer)?; + data(false, &mut buffer, true); + Ok(()) + } +} + +#[cfg(unix)] +mod imp { + use std::io::prelude::*; + use std::io; + use std::mem; + use std::os::unix::prelude::*; + use std::process::{ChildStdout, ChildStderr}; + use libc; + + pub fn read2(mut out_pipe: ChildStdout, + mut err_pipe: ChildStderr, + data: &mut FnMut(bool, &mut Vec, bool)) -> io::Result<()> { + unsafe { + libc::fcntl(out_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK); + libc::fcntl(err_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK); + } + + let mut out_done = false; + let mut err_done = false; + let mut out = Vec::new(); + let mut err = Vec::new(); + + let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() }; + fds[0].fd = out_pipe.as_raw_fd(); + fds[0].events = libc::POLLIN; + fds[1].fd = err_pipe.as_raw_fd(); + fds[1].events = libc::POLLIN; + loop { + // wait for either pipe to become readable using `select` + let r = unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) }; + if r == -1 { + let err = io::Error::last_os_error(); + if err.kind() == io::ErrorKind::Interrupted { + continue + } + return Err(err) + } + + // Read as much as we can from each pipe, ignoring EWOULDBLOCK or + // EAGAIN. If we hit EOF, then this will happen because the underlying + // reader will return Ok(0), in which case we'll see `Ok` ourselves. In + // this case we flip the other fd back into blocking mode and read + // whatever's leftover on that file descriptor. + let handle = |res: io::Result<_>| { + match res { + Ok(_) => Ok(true), + Err(e) => { + if e.kind() == io::ErrorKind::WouldBlock { + Ok(false) + } else { + Err(e) + } + } + } + }; + if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? { + out_done = true; + } + data(true, &mut out, out_done); + if !err_done && fds[1].revents != 0 && handle(err_pipe.read_to_end(&mut err))? { + err_done = true; + } + data(false, &mut err, err_done); + + if out_done && err_done { + return Ok(()) + } + } + } +} + +#[cfg(windows)] +mod imp { + extern crate miow; + extern crate winapi; + + use std::io; + use std::os::windows::prelude::*; + use std::process::{ChildStdout, ChildStderr}; + use std::slice; + + use self::miow::iocp::{CompletionPort, CompletionStatus}; + use self::miow::pipe::NamedPipe; + use self::miow::Overlapped; + use self::winapi::ERROR_BROKEN_PIPE; + + struct Pipe<'a> { + dst: &'a mut Vec, + overlapped: Overlapped, + pipe: NamedPipe, + done: bool, + } + + pub fn read2(out_pipe: ChildStdout, + err_pipe: ChildStderr, + data: &mut FnMut(bool, &mut Vec, bool)) -> io::Result<()> { + let mut out = Vec::new(); + let mut err = Vec::new(); + + let port = CompletionPort::new(1)?; + port.add_handle(0, &out_pipe)?; + port.add_handle(1, &err_pipe)?; + + unsafe { + let mut out_pipe = Pipe::new(out_pipe, &mut out); + let mut err_pipe = Pipe::new(err_pipe, &mut err); + + out_pipe.read()?; + err_pipe.read()?; + + let mut status = [CompletionStatus::zero(), CompletionStatus::zero()]; + + while !out_pipe.done || !err_pipe.done { + for status in port.get_many(&mut status, None)? { + if status.token() == 0 { + out_pipe.complete(status); + data(true, out_pipe.dst, out_pipe.done); + out_pipe.read()?; + } else { + err_pipe.complete(status); + data(false, err_pipe.dst, err_pipe.done); + err_pipe.read()?; + } + } + } + + Ok(()) + } + } + + impl<'a> Pipe<'a> { + unsafe fn new(p: P, dst: &'a mut Vec) -> Pipe<'a> { + Pipe { + dst: dst, + pipe: NamedPipe::from_raw_handle(p.into_raw_handle()), + overlapped: Overlapped::zero(), + done: false, + } + } + + unsafe fn read(&mut self) -> io::Result<()> { + let dst = slice_to_end(self.dst); + match self.pipe.read_overlapped(dst, self.overlapped.raw()) { + Ok(_) => Ok(()), + Err(e) => { + if e.raw_os_error() == Some(ERROR_BROKEN_PIPE as i32) { + self.done = true; + Ok(()) + } else { + Err(e) + } + } + } + } + + unsafe fn complete(&mut self, status: &CompletionStatus) { + let prev = self.dst.len(); + self.dst.set_len(prev + status.bytes_transferred() as usize); + if status.bytes_transferred() == 0 { + self.done = true; + } + } + } + + unsafe fn slice_to_end(v: &mut Vec) -> &mut [u8] { + if v.capacity() == 0 { + v.reserve(16); + } + if v.capacity() == v.len() { + v.reserve(1); + } + slice::from_raw_parts_mut(v.as_mut_ptr().offset(v.len() as isize), + v.capacity() - v.len()) + } +} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index f02525c118a89..80ca0afe72b50 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -29,7 +29,7 @@ use std::fmt; use std::io::prelude::*; use std::io::{self, BufReader}; use std::path::{Path, PathBuf}; -use std::process::{Command, Output, ExitStatus, Stdio}; +use std::process::{Command, Output, ExitStatus, Stdio, Child}; use std::str; use extract_gdb_version; @@ -1344,12 +1344,14 @@ actual:\n\ if let Some(input) = input { child.stdin.as_mut().unwrap().write_all(input.as_bytes()).unwrap(); } - let Output { status, stdout, stderr } = child.wait_with_output().unwrap(); + + let Output { status, stdout, stderr } = read2_abbreviated(child) + .expect("failed to read output"); let result = ProcRes { status, - stdout: String::from_utf8(stdout).unwrap(), - stderr: String::from_utf8(stderr).unwrap(), + stdout: String::from_utf8_lossy(&stdout).into_owned(), + stderr: String::from_utf8_lossy(&stderr).into_owned(), cmdline, }; @@ -1635,7 +1637,9 @@ actual:\n\ cmd.arg("-a").arg("-u"); cmd.arg(filename); cmd.arg("-nobanner"); - let output = match cmd.output() { + cmd.stdout(Stdio::piped()); + cmd.stderr(Stdio::piped()); + let output = match cmd.spawn().and_then(read2_abbreviated) { Ok(output) => output, Err(_) => return, }; @@ -2095,6 +2099,8 @@ actual:\n\ let mut cmd = Command::new(make); cmd.current_dir(&self.testpaths.file) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) .env("TARGET", &self.config.target) .env("PYTHON", &self.config.docck_python) .env("S", src_root) @@ -2143,7 +2149,7 @@ actual:\n\ } } - let output = cmd.output().expect("failed to spawn `make`"); + let output = cmd.spawn().and_then(read2_abbreviated).expect("failed to spawn `make`"); if !output.status.success() { let res = ProcRes { status: output.status, @@ -2536,3 +2542,76 @@ fn nocomment_mir_line(line: &str) -> &str { line } } + +fn read2_abbreviated(mut child: Child) -> io::Result { + use std::mem::replace; + use read2::read2; + + const HEAD_LEN: usize = 160 * 1024; + const TAIL_LEN: usize = 256 * 1024; + + enum ProcOutput { + Full(Vec), + Abbreviated { + head: Vec, + skipped: usize, + tail: Box<[u8]>, + } + } + + impl ProcOutput { + fn extend(&mut self, data: &[u8]) { + let new_self = match *self { + ProcOutput::Full(ref mut bytes) => { + bytes.extend_from_slice(data); + let new_len = bytes.len(); + if new_len <= HEAD_LEN + TAIL_LEN { + return; + } + let tail = bytes.split_off(new_len - TAIL_LEN).into_boxed_slice(); + let head = replace(bytes, Vec::new()); + let skipped = new_len - HEAD_LEN - TAIL_LEN; + ProcOutput::Abbreviated { head, skipped, tail } + } + ProcOutput::Abbreviated { ref mut skipped, ref mut tail, .. } => { + *skipped += data.len(); + if data.len() <= TAIL_LEN { + tail[..data.len()].copy_from_slice(data); + tail.rotate(data.len()); + } else { + tail.copy_from_slice(&data[(data.len() - TAIL_LEN)..]); + } + return; + } + }; + *self = new_self; + } + + fn into_bytes(self) -> Vec { + match self { + ProcOutput::Full(bytes) => bytes, + ProcOutput::Abbreviated { mut head, skipped, tail } => { + write!(&mut head, "\n\n<<<<<< SKIPPED {} BYTES >>>>>>\n\n", skipped).unwrap(); + head.extend_from_slice(&tail); + head + } + } + } + } + + let mut stdout = ProcOutput::Full(Vec::new()); + let mut stderr = ProcOutput::Full(Vec::new()); + + drop(child.stdin.take()); + read2(child.stdout.take().unwrap(), child.stderr.take().unwrap(), &mut |is_stdout, data, _| { + if is_stdout { &mut stdout } else { &mut stderr }.extend(data); + data.clear(); + })?; + let status = child.wait()?; + + Ok(Output { + status, + stdout: stdout.into_bytes(), + stderr: stderr.into_bytes(), + }) +} \ No newline at end of file diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index 11d5dbe736e81..f6e42c8dc17b1 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -31,9 +31,9 @@ pub fn check(path: &Path, bad: &mut bool) { if let Ok(mut file) = fs::File::open("/proc/version") { let mut contents = String::new(); file.read_to_string(&mut contents).unwrap(); - // Probably on Windows Linux Subsystem, all files will be marked as - // executable, so skip checking. - if contents.contains("Microsoft") { + // Probably on Windows Linux Subsystem or Docker via VirtualBox, + // all files will be marked as executable, so skip checking. + if contents.contains("Microsoft") || contents.contains("boot2docker") { return; } }