]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #50464 - est31:master, r=rkruppe
authorkennytm <kennytm@gmail.com>
Wed, 9 May 2018 09:26:13 +0000 (17:26 +0800)
committerkennytm <kennytm@gmail.com>
Wed, 9 May 2018 12:29:44 +0000 (20:29 +0800)
Remove some transmutes

115 files changed:
.mailmap
config.toml.example
src/Cargo.lock
src/bootstrap/README.md
src/bootstrap/bin/rustc.rs
src/bootstrap/builder.rs
src/bootstrap/config.rs
src/bootstrap/flags.rs
src/bootstrap/job.rs
src/bootstrap/lib.rs
src/bootstrap/test.rs
src/bootstrap/tool.rs
src/ci/docker/mingw-check/Dockerfile
src/ci/docker/x86_64-gnu-debug/Dockerfile
src/ci/run.sh
src/doc/book
src/doc/nomicon
src/doc/reference
src/doc/rust-by-example
src/doc/rustc/src/lints/listing/deny-by-default.md
src/doc/rustc/src/lints/listing/warn-by-default.md
src/liballoc/binary_heap.rs
src/liballoc/boxed.rs
src/liballoc/lib.rs
src/liballoc/string.rs
src/libcore/fmt/mod.rs
src/libcore/lib.rs
src/libcore/marker.rs
src/libcore/mem.rs
src/libcore/num/f32.rs
src/libcore/num/f64.rs
src/libcore/slice/memchr.rs
src/libcore/tests/lib.rs
src/libcore/tests/num/uint_macros.rs
src/libcore/tests/slice.rs
src/libcore/tests/time.rs [new file with mode: 0644]
src/libcore/time.rs
src/libproc_macro/lib.rs
src/librustc/lint/builtin.rs
src/librustc/mir/mod.rs
src/librustc/session/config.rs
src/librustc/ty/layout.rs
src/librustc/util/common.rs
src/librustc_lint/builtin.rs
src/librustc_lint/lib.rs
src/librustc_lint/types.rs
src/librustc_lint/unused.rs
src/librustc_mir/borrow_check/location.rs [new file with mode: 0644]
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/nll/constraint_generation.rs
src/librustc_mir/borrow_check/nll/facts.rs [new file with mode: 0644]
src/librustc_mir/borrow_check/nll/mod.rs
src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs
src/librustc_mir/borrow_check/nll/type_check/input_output.rs
src/librustc_mir/borrow_check/nll/type_check/mod.rs
src/librustc_mir/interpret/eval_context.rs
src/librustc_mir/lib.rs
src/librustc_mir/transform/elaborate_drops.rs
src/librustc_plugin/lib.rs
src/librustc_plugin/registry.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/resolve_imports.rs
src/librustc_save_analysis/lib.rs
src/librustc_target/abi/mod.rs
src/librustc_trans/back/write.rs
src/librustc_trans/debuginfo/metadata.rs
src/librustc_trans/mir/place.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/libstd/lib.rs
src/libstd/primitive_docs.rs
src/libsyntax/edition.rs
src/libsyntax/feature_gate.rs
src/libsyntax/parse/mod.rs
src/libsyntax/print/pprust.rs
src/libsyntax_ext/assert.rs
src/stdsimd
src/test/compile-fail/issue-43355.rs
src/test/compile-fail/issue-50471.rs [new file with mode: 0644]
src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-1.rs
src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-2.rs
src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-3.rs
src/test/compile-fail/rfc-2126-extern-absolute-paths/single-segment.rs
src/test/compile-fail/unused-result.rs
src/test/run-make-fulldeps/libtest-json/Makefile
src/test/run-make-fulldeps/save-analysis-rfc2126/Makefile
src/test/run-make/cross-lang-lto/Makefile [new file with mode: 0644]
src/test/run-make/cross-lang-lto/lib.rs [new file with mode: 0644]
src/test/run-make/cross-lang-lto/main.rs [new file with mode: 0644]
src/test/run-pass/collections-const-new.rs [new file with mode: 0644]
src/test/run-pass/issue-43355.rs [deleted file]
src/test/run-pass/rfc-2126-extern-absolute-paths/basic.rs
src/test/run-pass/rfc-2126-extern-absolute-paths/test.rs
src/test/run-pass/vec-const-new.rs [deleted file]
src/test/rustdoc/auxiliary/mod-stackoverflow.rs [new file with mode: 0644]
src/test/rustdoc/mod-stackoverflow.rs [new file with mode: 0644]
src/test/ui-fulldeps/unnecessary-extern-crate.rs [new file with mode: 0644]
src/test/ui-fulldeps/unnecessary-extern-crate.stderr [new file with mode: 0644]
src/test/ui/const-eval/extern_fat_pointer.rs [new file with mode: 0644]
src/test/ui/fn_must_use.stderr
src/test/ui/on-unimplemented/no-debug.stderr
src/tools/cargo
src/tools/clippy
src/tools/compiletest/Cargo.toml
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/tools/miri
src/tools/publish_toolstate.py
src/tools/rls
src/tools/rustfmt
src/tools/tidy/src/deps.rs
src/tools/tidy/src/lib.rs
src/tools/tidy/src/libcoretest.rs [new file with mode: 0644]
src/tools/tidy/src/main.rs

index 3ff9e94ee5410d259b65120b13f7ba0f7ede9784..8f4287a438580315f099fb20566f3723e0e212af 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -51,6 +51,7 @@ Carol Willing <carolcode@willingconsulting.com>
 Chris C Cerami <chrisccerami@users.noreply.github.com> Chris C Cerami <chrisccerami@gmail.com>
 Chris Pressey <cpressey@gmail.com>
 Chris Thorn <chris@thorn.co> Chris Thorn <thorn@thoughtbot.com>
+Chris Vittal <christopher.vittal@gmail.com> Christopher Vittal <christopher.vittal@gmail.com>
 Clark Gaebel <cg.wowus.cg@gmail.com> <cgaebel@mozilla.com>
 Clinton Ryan <clint.ryan3@gmail.com>
 Corey Richardson <corey@octayn.net> Elaine "See More" Nemo <corey@octayn.net>
index effe00843810da1dcd993bfc48ec00f6df6e288c..34fcc755b3a49509d6f893e34df1b1988d94581c 100644 (file)
 # Whether to deny warnings in crates
 #deny-warnings = true
 
+# Print backtrace on internal compiler errors during bootstrap
+#backtrace-on-ice = false
+
 # =============================================================================
 # Options for specific targets
 #
index 0f08eaf596a8ff239ddbbed955cac8df6d22da51..21c35458398b7d1e98bc8d7e157225ab55f3aaa7 100644 (file)
@@ -305,11 +305,11 @@ dependencies = [
 
 [[package]]
 name = "clippy"
-version = "0.0.195"
+version = "0.0.197"
 dependencies = [
  "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "clippy-mini-macro-test 0.2.0",
- "clippy_lints 0.0.195",
+ "clippy_lints 0.0.197",
  "compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -325,8 +325,9 @@ version = "0.2.0"
 
 [[package]]
 name = "clippy_lints"
-version = "0.0.195"
+version = "0.0.197"
 dependencies = [
+ "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -390,6 +391,7 @@ dependencies = [
  "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1629,7 +1631,7 @@ version = "0.127.0"
 dependencies = [
  "cargo 0.28.0",
  "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "clippy_lints 0.0.195",
+ "clippy_lints 0.0.197",
  "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1640,7 +1642,7 @@ dependencies = [
  "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-analysis 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-analysis 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1655,7 +1657,7 @@ dependencies = [
 
 [[package]]
 name = "rls-analysis"
-version = "0.12.0"
+version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3143,7 +3145,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "aec3f58d903a7d2a9dc2bf0e41a746f4530e0cab6b615494e058f67a3ef947fb"
 "checksum regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bd90079345f4a4c3409214734ae220fd773c6f2e8a543d07370c6c1c369cfbfb"
 "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
-"checksum rls-analysis 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b339561571efd8d2d4ae1b16eb27f760cad46907d49e9726242844dbbde14e79"
+"checksum rls-analysis 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a41488cf5dc99d6ce383319d2978756567b70d4ed0539eb0d9ce07763e732e46"
 "checksum rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a9cc2545ccb7e05b355bfe047b8039a6ec12270d5f3c996b766b340a50f7d2"
 "checksum rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bea04462e94b5512a78499837eecb7db182ff082144cd1b4bc32ef5d43de6510"
 "checksum rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "885f66b92757420572cbb02e033d4a9558c7413ca9b7ac206f28fd58ffdb44ea"
index 9ff681ac680874b09b35122160f7807025d4b1cc..98c353eb6ec8c3fa967b317693d261948d0ed0b3 100644 (file)
@@ -64,6 +64,10 @@ The script accepts commands, flags, and arguments to determine what to do:
   # execute tests in the standard library in stage0
   ./x.py test --stage 0 src/libstd
 
+  # execute tests in the core and standard library in stage0,
+  # without running doc tests (thus avoid depending on building the compiler)
+  ./x.py test --stage 0 --no-doc src/libcore src/libstd
+
   # execute all doc tests
   ./x.py test src/doc
   ```
index b6ae824c376017e740d086bade325ed36847ba55..3f97accaa4d84088ecbd8524e359d653dda4aa6c 100644 (file)
@@ -107,6 +107,13 @@ fn main() {
              env::join_paths(&dylib_path).unwrap());
     let mut maybe_crate = None;
 
+    // Print backtrace in case of ICE
+    if env::var("RUSTC_BACKTRACE_ON_ICE").is_ok() && env::var("RUST_BACKTRACE").is_err() {
+        cmd.env("RUST_BACKTRACE", "1");
+    }
+
+    cmd.env("RUSTC_BREAK_ON_ICE", "1");
+
     if let Some(target) = target {
         // The stage0 compiler has a special sysroot distinct from what we
         // actually downloaded, so we just always pass the `--sysroot` option.
index 08bb8ab481513bbf803f3a657442cef390c0907f..9c35cb7f506f970a8370bf427a3bf1fe513e02ab 100644 (file)
@@ -25,7 +25,7 @@
 use install;
 use dist;
 use util::{exe, libdir, add_lib_path};
-use {Build, Mode};
+use {Build, Mode, DocTests};
 use cache::{INTERNER, Interned, Cache};
 use check;
 use test;
@@ -591,6 +591,8 @@ pub fn cargo(&self,
                 format!("{} {}", env::var("RUSTFLAGS").unwrap_or_default(), extra_args));
         }
 
+        let want_rustdoc = self.doc_tests != DocTests::No;
+
         // Customize the compiler we're running. Specify the compiler to cargo
         // as our shim and then pass it some various options used to configure
         // how the actual compiler itself is called.
@@ -607,7 +609,7 @@ pub fn cargo(&self,
              .env("RUSTC_LIBDIR", self.rustc_libdir(compiler))
              .env("RUSTC_RPATH", self.config.rust_rpath.to_string())
              .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
-             .env("RUSTDOC_REAL", if cmd == "doc" || cmd == "test" {
+             .env("RUSTDOC_REAL", if cmd == "doc" || (cmd == "test" && want_rustdoc) {
                  self.rustdoc(compiler.host)
              } else {
                  PathBuf::from("/path/to/nowhere/rustdoc/not/required")
@@ -624,7 +626,7 @@ pub fn cargo(&self,
         if let Some(ref error_format) = self.config.rustc_error_format {
             cargo.env("RUSTC_ERROR_FORMAT", error_format);
         }
-        if cmd != "build" && cmd != "check" {
+        if cmd != "build" && cmd != "check" && want_rustdoc {
             cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(self.compiler(2, self.config.build)));
         }
 
@@ -706,6 +708,10 @@ pub fn cargo(&self,
             cargo.env("RUSTC_PRINT_STEP_TIMINGS", "1");
         }
 
+        if self.config.backtrace_on_ice {
+            cargo.env("RUSTC_BACKTRACE_ON_ICE", "1");
+        }
+
         cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity));
 
         // in std, we want to avoid denying warnings for stage 0 as that makes cfg's painful.
@@ -1403,4 +1409,39 @@ fn build_with_target_flag() {
             },
         ]);
     }
+
+    #[test]
+    fn test_with_no_doc_stage0() {
+        let mut config = configure(&[], &[]);
+        config.stage = Some(0);
+        config.cmd = Subcommand::Test {
+            paths: vec!["src/libstd".into()],
+            test_args: vec![],
+            rustc_args: vec![],
+            fail_fast: true,
+            doc_tests: DocTests::No,
+        };
+
+        let build = Build::new(config);
+        let mut builder = Builder::new(&build);
+
+        let host = INTERNER.intern_str("A");
+
+        builder.run_step_descriptions(
+            &[StepDescription::from::<test::Crate>()],
+            &["src/libstd".into()],
+        );
+
+        // Ensure we don't build any compiler artifacts.
+        assert!(builder.cache.all::<compile::Rustc>().is_empty());
+        assert_eq!(first(builder.cache.all::<test::Crate>()), &[
+            test::Crate {
+                compiler: Compiler { host, stage: 0 },
+                target: host,
+                mode: Mode::Libstd,
+                test_kind: test::TestKind::Test,
+                krate: INTERNER.intern_str("std"),
+            },
+        ]);
+    }
 }
index 7175f6a67642bf37c6ae92384fe15e0f140184ae..6dd6291be2397cbb08960729a7584762b452ed43 100644 (file)
@@ -72,6 +72,7 @@ pub struct Config {
     pub dry_run: bool,
 
     pub deny_warnings: bool,
+    pub backtrace_on_ice: bool,
 
     // llvm codegen options
     pub llvm_enabled: bool,
@@ -306,6 +307,7 @@ struct Rust {
     wasm_syscall: Option<bool>,
     lld: Option<bool>,
     deny_warnings: Option<bool>,
+    backtrace_on_ice: Option<bool>,
 }
 
 /// TOML representation of how each build target is configured.
@@ -531,6 +533,7 @@ pub fn parse(args: &[String]) -> Config {
             config.musl_root = rust.musl_root.clone().map(PathBuf::from);
             config.save_toolstates = rust.save_toolstates.clone().map(PathBuf::from);
             set(&mut config.deny_warnings, rust.deny_warnings.or(flags.warnings));
+            set(&mut config.backtrace_on_ice, rust.backtrace_on_ice);
 
             if let Some(ref backends) = rust.codegen_backends {
                 config.rust_codegen_backends = backends.iter()
index 3eb9dca2aa835807fc663e85e88f736e4515087d..5315a3028ffa9c05fa8d3839ff52b223ddad9a4d 100644 (file)
@@ -19,7 +19,7 @@
 
 use getopts::Options;
 
-use Build;
+use {Build, DocTests};
 use config::Config;
 use metadata;
 use builder::Builder;
@@ -62,7 +62,7 @@ pub enum Subcommand {
         test_args: Vec<String>,
         rustc_args: Vec<String>,
         fail_fast: bool,
-        doc_tests: bool,
+        doc_tests: DocTests,
     },
     Bench {
         paths: Vec<PathBuf>,
@@ -171,7 +171,8 @@ pub fn parse(args: &[String]) -> Flags {
                     "extra options to pass the compiler when running tests",
                     "ARGS",
                 );
-                opts.optflag("", "doc", "run doc tests");
+                opts.optflag("", "no-doc", "do not run doc tests");
+                opts.optflag("", "doc", "only run doc tests");
             },
             "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
             "clean" => { opts.optflag("", "all", "clean all build artifacts"); },
@@ -324,7 +325,13 @@ pub fn parse(args: &[String]) -> Flags {
                     test_args: matches.opt_strs("test-args"),
                     rustc_args: matches.opt_strs("rustc-args"),
                     fail_fast: !matches.opt_present("no-fail-fast"),
-                    doc_tests: matches.opt_present("doc"),
+                    doc_tests: if matches.opt_present("doc") {
+                        DocTests::Only
+                    } else if matches.opt_present("no-doc") {
+                        DocTests::No
+                    } else {
+                        DocTests::Yes
+                    }
                 }
             }
             "bench" => {
@@ -411,10 +418,10 @@ pub fn fail_fast(&self) -> bool {
         }
     }
 
-    pub fn doc_tests(&self) -> bool {
+    pub fn doc_tests(&self) -> DocTests {
         match *self {
             Subcommand::Test { doc_tests, .. } => doc_tests,
-            _ => false,
+            _ => DocTests::Yes,
         }
     }
 }
index fa3ba02482f569b81903c27ff85f716ae8a3ede3..6445ce8da332ea95904fb6b8a7ebbfd16f09d029 100644 (file)
@@ -122,12 +122,10 @@ struct JOBOBJECT_BASIC_LIMIT_INFORMATION {
 }
 
 pub unsafe fn setup(build: &mut Build) {
-    // Tell Windows to not show any UI on errors (such as not finding a required dll
-    // during startup or terminating abnormally).  This is important for running tests,
-    // since some of them use abnormal termination by design.
-    // This mode is inherited by all child processes.
-    let mode = SetErrorMode(SEM_NOGPFAULTERRORBOX); // read inherited flags
-    SetErrorMode(mode | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+    // Enable the Windows Error Reporting dialog which msys disables,
+    // so we can JIT debug rustc
+    let mode = SetErrorMode(0);
+    SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX);
 
     // Create a new job object for us to use
     let job = CreateJobObjectW(0 as *mut _, 0 as *const _);
index 0a7f0e5ff4ee25c64116f80a23227dab368bf063..e53fef06786130e03c26611efb51998211c60b76 100644 (file)
@@ -210,6 +210,16 @@ pub struct Compiler {
     host: Interned<String>,
 }
 
+#[derive(PartialEq, Eq, Copy, Clone, Debug)]
+pub enum DocTests {
+    // Default, run normal tests and doc tests.
+    Yes,
+    // Do not run any doc tests.
+    No,
+    // Only run doc tests.
+    Only,
+}
+
 /// Global configuration for the build system.
 ///
 /// This structure transitively contains all configuration for the build system.
@@ -233,7 +243,7 @@ pub struct Build {
     rustfmt_info: channel::GitInfo,
     local_rebuild: bool,
     fail_fast: bool,
-    doc_tests: bool,
+    doc_tests: DocTests,
     verbosity: usize,
 
     // Targets for which to build.
@@ -294,7 +304,7 @@ fn local_path(&self, build: &Build) -> PathBuf {
 ///
 /// These entries currently correspond to the various output directories of the
 /// build system, with each mod generating output in a different directory.
-#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
+#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 pub enum Mode {
     /// Build the standard library, placing output in the "stageN-std" directory.
     Libstd,
index e8c40dfdb0ad2bcfdc877b9a269f26f6aca760e6..650e09feb0e6340d2905bf4854aafbad44c6b084 100644 (file)
 use native;
 use tool::{self, Tool};
 use util::{self, dylib_path, dylib_path_var};
-use Mode;
+use {Mode, DocTests};
 use toolstate::ToolState;
 
 const ADB_TEST_DIR: &str = "/data/tmp/work";
 
 /// The two modes of the test runner; tests or benchmarks.
-#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
+#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord)]
 pub enum TestKind {
     /// Run `cargo test`
     Test,
@@ -313,6 +313,9 @@ fn run(self, builder: &Builder) {
 
         // Don't build tests dynamically, just a pain to work with
         cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
+        let dir = testdir(builder, compiler.host);
+        t!(fs::create_dir_all(&dir));
+        cargo.env("RUSTFMT_TEST_DIR", dir);
 
         builder.add_rustc_lib_path(compiler, &mut cargo);
 
@@ -832,7 +835,7 @@ fn run(self, builder: &Builder) {
     host: true
 });
 
-default_test!(RunMake {
+host_test!(RunMake {
     path: "src/test/run-make",
     mode: "run-make",
     suite: "run-make"
@@ -1019,7 +1022,7 @@ fn run(self, builder: &Builder) {
 
             // Only pass correct values for these flags for the `run-make` suite as it
             // requires that a C++ compiler was configured which isn't always the case.
-            if !builder.config.dry_run && suite == "run-make-fulldeps" {
+            if !builder.config.dry_run && mode == "run-make" {
                 let llvm_components = output(Command::new(&llvm_config).arg("--components"));
                 let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags"));
                 cmd.arg("--cc").arg(builder.cc(target))
@@ -1032,13 +1035,13 @@ fn run(self, builder: &Builder) {
                 }
             }
         }
-        if suite == "run-make-fulldeps" && !builder.config.llvm_enabled {
+        if mode == "run-make" && !builder.config.llvm_enabled {
             builder.info(
                 &format!("Ignoring run-make test suite as they generally don't work without LLVM"));
             return;
         }
 
-        if suite != "run-make-fulldeps" {
+        if mode != "run-make" {
             cmd.arg("--cc").arg("")
                .arg("--cxx").arg("")
                .arg("--cflags").arg("")
@@ -1407,13 +1410,13 @@ fn run(self, builder: &Builder) {
 }
 
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct Crate {
-    compiler: Compiler,
-    target: Interned<String>,
-    mode: Mode,
-    test_kind: TestKind,
-    krate: Interned<String>,
+    pub compiler: Compiler,
+    pub target: Interned<String>,
+    pub mode: Mode,
+    pub test_kind: TestKind,
+    pub krate: Interned<String>,
 }
 
 impl Step for Crate {
@@ -1519,8 +1522,14 @@ fn run(self, builder: &Builder) {
         if test_kind.subcommand() == "test" && !builder.fail_fast {
             cargo.arg("--no-fail-fast");
         }
-        if builder.doc_tests {
-            cargo.arg("--doc");
+        match builder.doc_tests {
+            DocTests::Only => {
+                cargo.arg("--doc");
+            }
+            DocTests::No => {
+                cargo.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
+            }
+            DocTests::Yes => {}
         }
 
         cargo.arg("-p").arg(krate);
index 6c29bd84fe4673b407da036a821a3d3add99d55a..220af6bd6e4af02b7c8df1f64a7f427379b1c1ab 100644 (file)
@@ -10,6 +10,7 @@
 
 use std::fs;
 use std::env;
+use std::iter;
 use std::path::PathBuf;
 use std::process::{Command, exit};
 
@@ -593,7 +594,7 @@ pub fn tool_cmd(&self, tool: Tool) -> Command {
     /// right location to run `compiler`.
     fn prepare_tool_cmd(&self, compiler: Compiler, cmd: &mut Command) {
         let host = &compiler.host;
-        let mut paths: Vec<PathBuf> = vec![
+        let mut lib_paths: Vec<PathBuf> = vec![
             PathBuf::from(&self.sysroot_libdir(compiler, compiler.host)),
             self.cargo_out(compiler, Mode::Tool, *host).join("deps"),
         ];
@@ -610,11 +611,46 @@ fn prepare_tool_cmd(&self, compiler: Compiler, cmd: &mut Command) {
                 }
                 for path in env::split_paths(v) {
                     if !curpaths.contains(&path) {
-                        paths.push(path);
+                        lib_paths.push(path);
                     }
                 }
             }
         }
-        add_lib_path(paths, cmd);
+
+        // Add the llvm/bin directory to PATH since it contains lots of
+        // useful, platform-independent tools
+        if let Some(llvm_bin_path) = self.llvm_bin_path() {
+            if host.contains("windows") {
+                // On Windows, PATH and the dynamic library path are the same,
+                // so we just add the LLVM bin path to lib_path
+                lib_paths.push(llvm_bin_path);
+            } else {
+                let old_path = env::var_os("PATH").unwrap_or_default();
+                let new_path = env::join_paths(iter::once(llvm_bin_path)
+                        .chain(env::split_paths(&old_path)))
+                    .expect("Could not add LLVM bin path to PATH");
+                cmd.env("PATH", new_path);
+            }
+        }
+
+        add_lib_path(lib_paths, cmd);
+    }
+
+    fn llvm_bin_path(&self) -> Option<PathBuf> {
+        if self.config.llvm_enabled && !self.config.dry_run {
+            let llvm_config = self.ensure(native::Llvm {
+                target: self.config.build,
+                emscripten: false,
+            });
+
+            // Add the llvm/bin directory to PATH since it contains lots of
+            // useful, platform-independent tools
+            let llvm_bin_path = llvm_config.parent()
+                .expect("Expected llvm-config to be contained in directory");
+            assert!(llvm_bin_path.is_dir());
+            Some(llvm_bin_path.to_path_buf())
+        } else {
+            None
+        }
     }
 }
index ae4641009cf1dab0af2e28ab079d5223b255cafd..aab339f399c598504021faf3a444175324a91185 100644 (file)
@@ -19,4 +19,5 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
+ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
 ENV SCRIPT python2.7 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu
index ff6ab1013b4c22352c7ef29673099d5ca2755663..bdde7ad7fe854a0d29fad01b0a012433e82c9e54 100644 (file)
@@ -16,7 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-ENV PARALLEL_CHECK 1
+ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
 ENV RUST_CONFIGURE_ARGS \
       --build=x86_64-unknown-linux-gnu \
       --enable-debug \
index 119b239d6b290177ac4c41b9cb19ab0a9271ef18..456f8cc7317e78cb7802bd2b2cf602c473517db3 100755 (executable)
@@ -78,9 +78,9 @@ fi
 # sccache server at the start of the build, but no need to worry if this fails.
 SCCACHE_IDLE_TIMEOUT=10800 sccache --start-server || true
 
-if [ "$PARALLEL_CHECK" != "" ]; then
+if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then
   $SRC/configure --enable-experimental-parallel-queries
-  python2.7 ../x.py check
+  CARGO_INCREMENTAL=0 python2.7 ../x.py check
   rm -f config.toml
   rm -rf build
 fi
index 6237a75790cd2e0ca22961b55f64a83319e73464..f51127530d46b9acbf4747c859da185e771cfcf3 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 6237a75790cd2e0ca22961b55f64a83319e73464
+Subproject commit f51127530d46b9acbf4747c859da185e771cfcf3
index 3c56329d1bd9038e5341f1962bcd8d043312a712..748a5e6742db4a21c4c630a58087f818828e8a0a 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3c56329d1bd9038e5341f1962bcd8d043312a712
+Subproject commit 748a5e6742db4a21c4c630a58087f818828e8a0a
index 76296346e97c3702974d3398fdb94af9e10111a2..134f419ee62714590b04712fe6072253bc2a7822 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 76296346e97c3702974d3398fdb94af9e10111a2
+Subproject commit 134f419ee62714590b04712fe6072253bc2a7822
index d5ec87eabe5733cc2348c7dada89fc67c086f391..eebda16e4b45f2eed4310cf7b9872cc752278163 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d5ec87eabe5733cc2348c7dada89fc67c086f391
+Subproject commit eebda16e4b45f2eed4310cf7b9872cc752278163
index e7ec6af8be1e3752a89a2a1e5bc0eb8f2e05151f..ef76295f04d587a469fcfa38a2e0fbc4b35478fc 100644 (file)
@@ -239,3 +239,44 @@ error: invalid `crate_type` value
   | ^^^^^^^^^^^^^^^^^^^^
   |
 ```
+
+## incoherent-fundamental-impls
+
+This lint detects potentially-conflicting impls that were erroneously allowed. Some
+example code that triggers this lint:
+
+```rust,ignore
+pub trait Trait1<X> {
+    type Output;
+}
+
+pub trait Trait2<X> {}
+
+pub struct A;
+
+impl<X, T> Trait1<X> for T where T: Trait2<X> {
+    type Output = ();
+}
+
+impl<X> Trait1<Box<X>> for A {
+    type Output = i32;
+}
+```
+
+This will produce:
+
+```text
+error: conflicting implementations of trait `Trait1<std::boxed::Box<_>>` for type `A`: (E0119)
+  --> src/main.rs:13:1
+   |
+9  | impl<X, T> Trait1<X> for T where T: Trait2<X> {
+   | --------------------------------------------- first implementation here
+...
+13 | impl<X> Trait1<Box<X>> for A {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A`
+   |
+   = note: #[deny(incoherent_fundamental_impls)] on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #46205 <https://github.com/rust-lang/rust/issues/46205>
+   = note: downstream crates may implement trait `Trait2<std::boxed::Box<_>>` for type `A`
+```
index 1171f75caa1fdf69ac32e2c02ee562a85df2f7a4..b49708ff6adcd2e11fb0276eb318904b22ba082c 100644 (file)
@@ -117,47 +117,6 @@ warning: found struct without foreign-function-safe representation annotation in
   |
 ```
 
-## incoherent-fundamental-impls
-
-This lint detects potentially-conflicting impls that were erroneously allowed. Some
-example code that triggers this lint:
-
-```rust
-pub trait Trait1<X> {
-    type Output;
-}
-
-pub trait Trait2<X> {}
-
-pub struct A;
-
-impl<X, T> Trait1<X> for T where T: Trait2<X> {
-    type Output = ();
-}
-
-impl<X> Trait1<Box<X>> for A {
-    type Output = i32;
-}
-```
-
-This will produce:
-
-```text
-warning: conflicting implementations of trait `Trait1<std::boxed::Box<_>>` for type `A`: (E0119)
-  --> src/main.rs:13:1
-   |
-9  | impl<X, T> Trait1<X> for T where T: Trait2<X> {
-   | --------------------------------------------- first implementation here
-...
-13 | impl<X> Trait1<Box<X>> for A {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A`
-   |
-   = note: #[warn(incoherent_fundamental_impls)] on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #46205 <https://github.com/rust-lang/rust/issues/46205>
-   = note: downstream crates may implement trait `Trait2<std::boxed::Box<_>>` for type `A`
-```
-
 ## late-bound-lifetime-arguments
 
 This lint detects detects generic lifetime arguments in path segments with
index 668b61c51d8bc0f8e3a39e496ecc0c79b2d5ed4e..fcadcb544c431a9e9ede7bc00912ce3123b2533c 100644 (file)
 
 use core::ops::{Deref, DerefMut};
 use core::iter::{FromIterator, FusedIterator};
-use core::mem::{swap, size_of};
+use core::mem::{swap, size_of, ManuallyDrop};
 use core::ptr;
 use core::fmt;
 
@@ -864,8 +864,7 @@ fn better_to_rebuild(len1: usize, len2: usize) -> bool {
 /// position with the value that was originally removed.
 struct Hole<'a, T: 'a> {
     data: &'a mut [T],
-    /// `elt` is always `Some` from new until drop.
-    elt: Option<T>,
+    elt: ManuallyDrop<T>,
     pos: usize,
 }
 
@@ -879,7 +878,7 @@ unsafe fn new(data: &'a mut [T], pos: usize) -> Self {
         let elt = ptr::read(&data[pos]);
         Hole {
             data,
-            elt: Some(elt),
+            elt: ManuallyDrop::new(elt),
             pos,
         }
     }
@@ -892,7 +891,7 @@ fn pos(&self) -> usize {
     /// Returns a reference to the element removed.
     #[inline]
     fn element(&self) -> &T {
-        self.elt.as_ref().unwrap()
+        &self.elt
     }
 
     /// Returns a reference to the element at `index`.
@@ -925,7 +924,7 @@ fn drop(&mut self) {
         // fill the hole again
         unsafe {
             let pos = self.pos;
-            ptr::write(self.data.get_unchecked_mut(pos), self.elt.take().unwrap());
+            ptr::copy_nonoverlapping(&*self.elt, self.data.get_unchecked_mut(pos), 1);
         }
     }
 }
index 1b4f86dcfac1c07174e3efc4c8217b7824435a68..a15673442355125b5eb9e4c71647a3f70e6ce4a9 100644 (file)
@@ -62,7 +62,7 @@
 use core::hash::{Hash, Hasher};
 use core::iter::FusedIterator;
 use core::marker::{Unpin, Unsize};
-use core::mem::{self, Pin};
+use core::mem::{self, PinMut};
 use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState};
 use core::ptr::{self, NonNull, Unique};
 use core::convert::From;
@@ -771,8 +771,8 @@ pub fn new(data: T) -> PinBox<T> {
 #[unstable(feature = "pin", issue = "49150")]
 impl<T: ?Sized> PinBox<T> {
     /// Get a pinned reference to the data in this PinBox.
-    pub fn as_pin<'a>(&'a mut self) -> Pin<'a, T> {
-        unsafe { Pin::new_unchecked(&mut *self.inner) }
+    pub fn as_pin_mut<'a>(&'a mut self) -> PinMut<'a, T> {
+        unsafe { PinMut::new_unchecked(&mut *self.inner) }
     }
 
     /// Get a mutable reference to the data inside this PinBox.
index da4b76a4d527d41ee755812ffae464e780e2e4c4..bb78c14b90586fcb65a93559491662489b83813e 100644 (file)
 #![feature(inclusive_range_methods)]
 #![cfg_attr(stage0, feature(generic_param_attrs))]
 #![feature(rustc_const_unstable)]
+#![feature(const_vec_new)]
 
 #![cfg_attr(not(test), feature(fn_traits, i128))]
 #![cfg_attr(test, feature(test))]
index 2f84d5f7f8676877328dc57aa79155374886f6e6..da9afdd2ca37bcb410b70bcbab444bb06715eaa1 100644 (file)
@@ -380,7 +380,8 @@ impl String {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn new() -> String {
+    #[rustc_const_unstable(feature = "const_string_new")]
+    pub const fn new() -> String {
         String { vec: Vec::new() }
     }
 
index 99e3012c9bf8cd5e038310ca4205577cb71e569c..5820fe58932c6967b5797ca8112dd808e813d270 100644 (file)
@@ -542,10 +542,10 @@ fn fmt(&self, fmt: &mut Formatter) -> Result {
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(
-    on(crate_local, label="`{Self}` cannot be formatted using `:?`; \
-                            add `#[derive(Debug)]` or manually implement `{Debug}`"),
+    on(crate_local, label="`{Self}` cannot be formatted using `{{:?}}`",
+                    note="add `#[derive(Debug)]` or manually implement `{Debug}`"),
     message="`{Self}` doesn't implement `{Debug}`",
-    label="`{Self}` cannot be formatted using `:?` because it doesn't implement `{Debug}`",
+    label="`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{Debug}`",
 )]
 #[doc(alias = "{:?}")]
 #[lang = "debug_trait"]
@@ -610,8 +610,9 @@ pub trait Debug {
 /// ```
 #[rustc_on_unimplemented(
     message="`{Self}` doesn't implement `{Display}`",
-    label="`{Self}` cannot be formatted with the default formatter; \
-           try using `:?` instead if you are using a format string",
+    label="`{Self}` cannot be formatted with the default formatter",
+    note="in format strings you may be able to use `{{:?}}` \
+          (or {{:#?}} for pretty-print) instead",
 )]
 #[doc(alias = "{}")]
 #[stable(feature = "rust1", since = "1.0.0")]
index 04dd42583d406eb468e646e10bfd56dbcf81be8a..54f35d17974fb2412db5e25bdcb802d350ef96e6 100644 (file)
 
 // Since libcore defines many fundamental lang items, all tests live in a
 // separate crate, libcoretest, to avoid bizarre issues.
+//
+// Here we explicitly #[cfg]-out this whole crate when testing. If we don't do
+// this, both the generated test artifact and the linked libtest (which
+// transitively includes libcore) will both define the same set of lang items,
+// and this will cause the E0152 "duplicate lang item found" error. See
+// discussion in #50466 for details.
+//
+// This cfg won't affect doc tests.
+#![cfg(not(test))]
 
 #![stable(feature = "core", since = "1.6.0")]
 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
index c074adfd570e339adaa765b09080eb750fe4e44c..db5f50a99cadc3471b33d531670cbc2c8f016ddf 100644 (file)
@@ -595,15 +595,15 @@ unsafe impl<T: ?Sized> Freeze for *mut T {}
 unsafe impl<'a, T: ?Sized> Freeze for &'a T {}
 unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {}
 
-/// Types which can be moved out of a `Pin`.
+/// Types which can be moved out of a `PinMut`.
 ///
-/// The `Unpin` trait is used to control the behavior of the [`Pin`] type. If a
+/// The `Unpin` trait is used to control the behavior of the [`PinMut`] type. If a
 /// type implements `Unpin`, it is safe to move a value of that type out of the
-/// `Pin` pointer.
+/// `PinMut` pointer.
 ///
 /// This trait is automatically implemented for almost every type.
 ///
-/// [`Pin`]: ../mem/struct.Pin.html
+/// [`PinMut`]: ../mem/struct.PinMut.html
 #[unstable(feature = "pin", issue = "49150")]
 pub unsafe auto trait Unpin {}
 
index 10efab82ddff586d6c44671388968ecf8e8a318f..20445def634ecaa9127119259e4685544fe85d61 100644 (file)
@@ -959,8 +959,9 @@ impl<T> ManuallyDrop<T> {
     /// ManuallyDrop::new(Box::new(()));
     /// ```
     #[stable(feature = "manually_drop", since = "1.20.0")]
+    #[rustc_const_unstable(feature = "const_manually_drop_new")]
     #[inline]
-    pub fn new(value: T) -> ManuallyDrop<T> {
+    pub const fn new(value: T) -> ManuallyDrop<T> {
         ManuallyDrop { value: value }
     }
 
@@ -1101,53 +1102,56 @@ fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
 /// value implements the `Unpin` trait.
 #[unstable(feature = "pin", issue = "49150")]
 #[fundamental]
-pub struct Pin<'a, T: ?Sized + 'a> {
+pub struct PinMut<'a, T: ?Sized + 'a> {
     inner: &'a mut T,
 }
 
 #[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized + Unpin> Pin<'a, T> {
-    /// Construct a new `Pin` around a reference to some data of a type that
+impl<'a, T: ?Sized + Unpin> PinMut<'a, T> {
+    /// Construct a new `PinMut` around a reference to some data of a type that
     /// implements `Unpin`.
     #[unstable(feature = "pin", issue = "49150")]
-    pub fn new(reference: &'a mut T) -> Pin<'a, T> {
-        Pin { inner: reference }
+    pub fn new(reference: &'a mut T) -> PinMut<'a, T> {
+        PinMut { inner: reference }
     }
 }
 
 
 #[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized> Pin<'a, T> {
-    /// Construct a new `Pin` around a reference to some data of a type that
+impl<'a, T: ?Sized> PinMut<'a, T> {
+    /// Construct a new `PinMut` around a reference to some data of a type that
     /// may or may not implement `Unpin`.
     ///
     /// This constructor is unsafe because we do not know what will happen with
     /// that data after the reference ends. If you cannot guarantee that the
     /// data will never move again, calling this constructor is invalid.
     #[unstable(feature = "pin", issue = "49150")]
-    pub unsafe fn new_unchecked(reference: &'a mut T) -> Pin<'a, T> {
-        Pin { inner: reference }
+    pub unsafe fn new_unchecked(reference: &'a mut T) -> PinMut<'a, T> {
+        PinMut { inner: reference }
     }
 
-    /// Borrow a Pin for a shorter lifetime than it already has.
+    /// Reborrow a `PinMut` for a shorter lifetime.
+    ///
+    /// For example, `PinMut::get_mut(x.reborrow())` (unsafely) returns a
+    /// short-lived mutable reference reborrowing from `x`.
     #[unstable(feature = "pin", issue = "49150")]
-    pub fn borrow<'b>(this: &'b mut Pin<'a, T>) -> Pin<'b, T> {
-        Pin { inner: this.inner }
+    pub fn reborrow<'b>(&'b mut self) -> PinMut<'b, T> {
+        PinMut { inner: self.inner }
     }
 
-    /// Get a mutable reference to the data inside of this `Pin`.
+    /// Get a mutable reference to the data inside of this `PinMut`.
     ///
     /// This function is unsafe. You must guarantee that you will never move
     /// the data out of the mutable reference you receive when you call this
     /// function.
     #[unstable(feature = "pin", issue = "49150")]
-    pub unsafe fn get_mut<'b>(this: &'b mut Pin<'a, T>) -> &'b mut T {
+    pub unsafe fn get_mut(this: PinMut<'a, T>) -> &'a mut T {
         this.inner
     }
 
     /// Construct a new pin by mapping the interior value.
     ///
-    /// For example, if you  wanted to get a `Pin` of a field of something, you
+    /// For example, if you  wanted to get a `PinMut` of a field of something, you
     /// could use this to get access to that field in one line of code.
     ///
     /// This function is unsafe. You must guarantee that the data you return
@@ -1155,15 +1159,15 @@ pub unsafe fn get_mut<'b>(this: &'b mut Pin<'a, T>) -> &'b mut T {
     /// because it is one of the fields of that value), and also that you do
     /// not move out of the argument you receive to the interior function.
     #[unstable(feature = "pin", issue = "49150")]
-    pub unsafe fn map<'b, U, F>(this: &'b mut Pin<'a, T>, f: F) -> Pin<'b, U> where
+    pub unsafe fn map<U, F>(this: PinMut<'a, T>, f: F) -> PinMut<'a, U> where
         F: FnOnce(&mut T) -> &mut U
     {
-        Pin { inner: f(this.inner) }
+        PinMut { inner: f(this.inner) }
     }
 }
 
 #[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized> Deref for Pin<'a, T> {
+impl<'a, T: ?Sized> Deref for PinMut<'a, T> {
     type Target = T;
 
     fn deref(&self) -> &T {
@@ -1172,35 +1176,35 @@ fn deref(&self) -> &T {
 }
 
 #[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized + Unpin> DerefMut for Pin<'a, T> {
+impl<'a, T: ?Sized + Unpin> DerefMut for PinMut<'a, T> {
     fn deref_mut(&mut self) -> &mut T {
         self.inner
     }
 }
 
 #[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: fmt::Debug + ?Sized> fmt::Debug for Pin<'a, T> {
+impl<'a, T: fmt::Debug + ?Sized> fmt::Debug for PinMut<'a, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         fmt::Debug::fmt(&**self, f)
     }
 }
 
 #[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: fmt::Display + ?Sized> fmt::Display for Pin<'a, T> {
+impl<'a, T: fmt::Display + ?Sized> fmt::Display for PinMut<'a, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         fmt::Display::fmt(&**self, f)
     }
 }
 
 #[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized> fmt::Pointer for Pin<'a, T> {
+impl<'a, T: ?Sized> fmt::Pointer for PinMut<'a, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         fmt::Pointer::fmt(&(&*self.inner as *const T), f)
     }
 }
 
 #[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Pin<'a, U>> for Pin<'a, T> {}
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<PinMut<'a, U>> for PinMut<'a, T> {}
 
 #[unstable(feature = "pin", issue = "49150")]
-unsafe impl<'a, T: ?Sized> Unpin for Pin<'a, T> {}
+unsafe impl<'a, T: ?Sized> Unpin for PinMut<'a, T> {}
index 8d5f6f601daf8a3c0eebc46cadc9124c7219700c..672119eba7f9dc814739c2a93b4db903aecc23e4 100644 (file)
@@ -128,10 +128,18 @@ pub mod consts {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub const LOG2_E: f32 = 1.44269504088896340735992468100189214_f32;
 
+    /// log<sub>2</sub>(10)
+    #[unstable(feature = "extra_log_consts", issue = "50540")]
+    pub const LOG2_10: f32 = 3.32192809488736234787031942948939018_f32;
+
     /// log<sub>10</sub>(e)
     #[stable(feature = "rust1", since = "1.0.0")]
     pub const LOG10_E: f32 = 0.434294481903251827651128918916605082_f32;
 
+    /// log<sub>10</sub>(2)
+    #[unstable(feature = "extra_log_consts", issue = "50540")]
+    pub const LOG10_2: f32 = 0.301029995663981195213738894724493027_f32;
+
     /// ln(2)
     #[stable(feature = "rust1", since = "1.0.0")]
     pub const LN_2: f32 = 0.693147180559945309417232121458176568_f32;
index 08b869734d49627099a649553567dd660159b4ca..220b23a1e6a016fdd0a7ef5cd7165044e56c7811 100644 (file)
@@ -124,10 +124,18 @@ pub mod consts {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub const E: f64 = 2.71828182845904523536028747135266250_f64;
 
+    /// log<sub>2</sub>(10)
+    #[unstable(feature = "extra_log_consts", issue = "50540")]
+    pub const LOG2_10: f64 = 3.32192809488736234787031942948939018_f64;
+
     /// log<sub>2</sub>(e)
     #[stable(feature = "rust1", since = "1.0.0")]
     pub const LOG2_E: f64 = 1.44269504088896340735992468100189214_f64;
 
+    /// log<sub>10</sub>(2)
+    #[unstable(feature = "extra_log_consts", issue = "50540")]
+    pub const LOG10_2: f64 = 0.301029995663981195213738894724493027_f64;
+
     /// log<sub>10</sub>(e)
     #[stable(feature = "rust1", since = "1.0.0")]
     pub const LOG10_E: f64 = 0.434294481903251827651128918916605082_f64;
index 469404f7f6bb080d7c55209bc89cd6c884ff4597..7b62e7b0620fd4ddd51348f523139004d2a4a0ed 100644 (file)
@@ -135,85 +135,3 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
     // find the byte before the point the body loop stopped
     text[..offset].iter().rposition(|elt| *elt == x)
 }
-
-// test fallback implementations on all platforms
-#[test]
-fn matches_one() {
-    assert_eq!(Some(0), memchr(b'a', b"a"));
-}
-
-#[test]
-fn matches_begin() {
-    assert_eq!(Some(0), memchr(b'a', b"aaaa"));
-}
-
-#[test]
-fn matches_end() {
-    assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
-}
-
-#[test]
-fn matches_nul() {
-    assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
-}
-
-#[test]
-fn matches_past_nul() {
-    assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
-}
-
-#[test]
-fn no_match_empty() {
-    assert_eq!(None, memchr(b'a', b""));
-}
-
-#[test]
-fn no_match() {
-    assert_eq!(None, memchr(b'a', b"xyz"));
-}
-
-#[test]
-fn matches_one_reversed() {
-    assert_eq!(Some(0), memrchr(b'a', b"a"));
-}
-
-#[test]
-fn matches_begin_reversed() {
-    assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
-}
-
-#[test]
-fn matches_end_reversed() {
-    assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
-}
-
-#[test]
-fn matches_nul_reversed() {
-    assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
-}
-
-#[test]
-fn matches_past_nul_reversed() {
-    assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
-}
-
-#[test]
-fn no_match_empty_reversed() {
-    assert_eq!(None, memrchr(b'a', b""));
-}
-
-#[test]
-fn no_match_reversed() {
-    assert_eq!(None, memrchr(b'a', b"xyz"));
-}
-
-#[test]
-fn each_alignment_reversed() {
-    let mut data = [1u8; 64];
-    let needle = 2;
-    let pos = 40;
-    data[pos] = needle;
-    for start in 0..16 {
-        assert_eq!(Some(pos - start), memrchr(needle, &data[start..]));
-    }
-}
index f6750c590b33ab97303f7f5b3231bbd7caa334df..5e98e40e0d5e6b42f2e431152dd9bd59f89a3e84 100644 (file)
@@ -46,6 +46,7 @@
 #![feature(reverse_bits)]
 #![feature(inclusive_range_methods)]
 #![feature(iterator_find_map)]
+#![feature(slice_internals)]
 
 extern crate core;
 extern crate test;
@@ -74,4 +75,5 @@
 mod slice;
 mod str;
 mod str_lossy;
+mod time;
 mod tuple;
index ca6906f731047c62e0091c3a3212756cff2b5c23..257f6ea20d4eab7aa12a87ab53874d44bbefc86c 100644 (file)
@@ -98,6 +98,7 @@ fn test_swap_bytes() {
     }
 
     #[test]
+    #[cfg(not(stage0))]
     fn test_reverse_bits() {
         assert_eq!(A.reverse_bits().reverse_bits(), A);
         assert_eq!(B.reverse_bits().reverse_bits(), B);
index 53fdfa0682742454284a2ea9bdea79970d335a6c..c81e5e97cbb7acc5c43927e8d2fae22c14fa2969 100644 (file)
@@ -550,3 +550,89 @@ fn sort_unstable() {
     v.sort_unstable();
     assert!(v == [0xDEADBEEF]);
 }
+
+pub mod memchr {
+    use core::slice::memchr::{memchr, memrchr};
+
+    // test fallback implementations on all platforms
+    #[test]
+    fn matches_one() {
+        assert_eq!(Some(0), memchr(b'a', b"a"));
+    }
+
+    #[test]
+    fn matches_begin() {
+        assert_eq!(Some(0), memchr(b'a', b"aaaa"));
+    }
+
+    #[test]
+    fn matches_end() {
+        assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
+    }
+
+    #[test]
+    fn matches_nul() {
+        assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
+    }
+
+    #[test]
+    fn matches_past_nul() {
+        assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
+    }
+
+    #[test]
+    fn no_match_empty() {
+        assert_eq!(None, memchr(b'a', b""));
+    }
+
+    #[test]
+    fn no_match() {
+        assert_eq!(None, memchr(b'a', b"xyz"));
+    }
+
+    #[test]
+    fn matches_one_reversed() {
+        assert_eq!(Some(0), memrchr(b'a', b"a"));
+    }
+
+    #[test]
+    fn matches_begin_reversed() {
+        assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
+    }
+
+    #[test]
+    fn matches_end_reversed() {
+        assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
+    }
+
+    #[test]
+    fn matches_nul_reversed() {
+        assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
+    }
+
+    #[test]
+    fn matches_past_nul_reversed() {
+        assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
+    }
+
+    #[test]
+    fn no_match_empty_reversed() {
+        assert_eq!(None, memrchr(b'a', b""));
+    }
+
+    #[test]
+    fn no_match_reversed() {
+        assert_eq!(None, memrchr(b'a', b"xyz"));
+    }
+
+    #[test]
+    fn each_alignment_reversed() {
+        let mut data = [1u8; 64];
+        let needle = 2;
+        let pos = 40;
+        data[pos] = needle;
+        for start in 0..16 {
+            assert_eq!(Some(pos - start), memrchr(needle, &data[start..]));
+        }
+    }
+}
diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs
new file mode 100644 (file)
index 0000000..042c523
--- /dev/null
@@ -0,0 +1,124 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use core::time::Duration;
+
+#[test]
+fn creation() {
+    assert!(Duration::from_secs(1) != Duration::from_secs(0));
+    assert_eq!(Duration::from_secs(1) + Duration::from_secs(2),
+               Duration::from_secs(3));
+    assert_eq!(Duration::from_millis(10) + Duration::from_secs(4),
+               Duration::new(4, 10 * 1_000_000));
+    assert_eq!(Duration::from_millis(4000), Duration::new(4, 0));
+}
+
+#[test]
+fn secs() {
+    assert_eq!(Duration::new(0, 0).as_secs(), 0);
+    assert_eq!(Duration::from_secs(1).as_secs(), 1);
+    assert_eq!(Duration::from_millis(999).as_secs(), 0);
+    assert_eq!(Duration::from_millis(1001).as_secs(), 1);
+}
+
+#[test]
+fn nanos() {
+    assert_eq!(Duration::new(0, 0).subsec_nanos(), 0);
+    assert_eq!(Duration::new(0, 5).subsec_nanos(), 5);
+    assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1);
+    assert_eq!(Duration::from_secs(1).subsec_nanos(), 0);
+    assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000);
+    assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000);
+}
+
+#[test]
+fn add() {
+    assert_eq!(Duration::new(0, 0) + Duration::new(0, 1),
+               Duration::new(0, 1));
+    assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001),
+               Duration::new(1, 1));
+}
+
+#[test]
+fn checked_add() {
+    assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)),
+               Some(Duration::new(0, 1)));
+    assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)),
+               Some(Duration::new(1, 1)));
+    assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::core::u64::MAX, 0)), None);
+}
+
+#[test]
+fn sub() {
+    assert_eq!(Duration::new(0, 1) - Duration::new(0, 0),
+               Duration::new(0, 1));
+    assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000),
+               Duration::new(0, 1));
+    assert_eq!(Duration::new(1, 0) - Duration::new(0, 1),
+               Duration::new(0, 999_999_999));
+}
+
+#[test]
+fn checked_sub() {
+    let zero = Duration::new(0, 0);
+    let one_nano = Duration::new(0, 1);
+    let one_sec = Duration::new(1, 0);
+    assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1)));
+    assert_eq!(one_sec.checked_sub(one_nano),
+               Some(Duration::new(0, 999_999_999)));
+    assert_eq!(zero.checked_sub(one_nano), None);
+    assert_eq!(zero.checked_sub(one_sec), None);
+}
+
+#[test]
+#[should_panic]
+fn sub_bad1() {
+    let _ = Duration::new(0, 0) - Duration::new(0, 1);
+}
+
+#[test]
+#[should_panic]
+fn sub_bad2() {
+    let _ = Duration::new(0, 0) - Duration::new(1, 0);
+}
+
+#[test]
+fn mul() {
+    assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2));
+    assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3));
+    assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4));
+    assert_eq!(Duration::new(0, 500_000_001) * 4000,
+               Duration::new(2000, 4000));
+}
+
+#[test]
+fn checked_mul() {
+    assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2)));
+    assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3)));
+    assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4)));
+    assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000),
+               Some(Duration::new(2000, 4000)));
+    assert_eq!(Duration::new(::core::u64::MAX - 1, 0).checked_mul(2), None);
+}
+
+#[test]
+fn div() {
+    assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0));
+    assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333));
+    assert_eq!(Duration::new(99, 999_999_000) / 100,
+               Duration::new(0, 999_999_990));
+}
+
+#[test]
+fn checked_div() {
+    assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0)));
+    assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000)));
+    assert_eq!(Duration::new(2, 0).checked_div(0), None);
+}
index e22fe450bb1f6562ac0e5f8c3e13fbb4211521d1..8e8b1691c657a3bc0edaa12e336332e82f55a3db 100644 (file)
@@ -481,119 +481,3 @@ fn sum<I: Iterator<Item=&'a Duration>>(iter: I) -> Duration {
         iter.fold(Duration::new(0, 0), |a, b| a + *b)
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use super::Duration;
-
-    #[test]
-    fn creation() {
-        assert!(Duration::from_secs(1) != Duration::from_secs(0));
-        assert_eq!(Duration::from_secs(1) + Duration::from_secs(2),
-                   Duration::from_secs(3));
-        assert_eq!(Duration::from_millis(10) + Duration::from_secs(4),
-                   Duration::new(4, 10 * 1_000_000));
-        assert_eq!(Duration::from_millis(4000), Duration::new(4, 0));
-    }
-
-    #[test]
-    fn secs() {
-        assert_eq!(Duration::new(0, 0).as_secs(), 0);
-        assert_eq!(Duration::from_secs(1).as_secs(), 1);
-        assert_eq!(Duration::from_millis(999).as_secs(), 0);
-        assert_eq!(Duration::from_millis(1001).as_secs(), 1);
-    }
-
-    #[test]
-    fn nanos() {
-        assert_eq!(Duration::new(0, 0).subsec_nanos(), 0);
-        assert_eq!(Duration::new(0, 5).subsec_nanos(), 5);
-        assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1);
-        assert_eq!(Duration::from_secs(1).subsec_nanos(), 0);
-        assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000);
-        assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000);
-    }
-
-    #[test]
-    fn add() {
-        assert_eq!(Duration::new(0, 0) + Duration::new(0, 1),
-                   Duration::new(0, 1));
-        assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001),
-                   Duration::new(1, 1));
-    }
-
-    #[test]
-    fn checked_add() {
-        assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)),
-                   Some(Duration::new(0, 1)));
-        assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)),
-                   Some(Duration::new(1, 1)));
-        assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None);
-    }
-
-    #[test]
-    fn sub() {
-        assert_eq!(Duration::new(0, 1) - Duration::new(0, 0),
-                   Duration::new(0, 1));
-        assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000),
-                   Duration::new(0, 1));
-        assert_eq!(Duration::new(1, 0) - Duration::new(0, 1),
-                   Duration::new(0, 999_999_999));
-    }
-
-    #[test]
-    fn checked_sub() {
-        let zero = Duration::new(0, 0);
-        let one_nano = Duration::new(0, 1);
-        let one_sec = Duration::new(1, 0);
-        assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1)));
-        assert_eq!(one_sec.checked_sub(one_nano),
-                   Some(Duration::new(0, 999_999_999)));
-        assert_eq!(zero.checked_sub(one_nano), None);
-        assert_eq!(zero.checked_sub(one_sec), None);
-    }
-
-    #[test] #[should_panic]
-    fn sub_bad1() {
-        Duration::new(0, 0) - Duration::new(0, 1);
-    }
-
-    #[test] #[should_panic]
-    fn sub_bad2() {
-        Duration::new(0, 0) - Duration::new(1, 0);
-    }
-
-    #[test]
-    fn mul() {
-        assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2));
-        assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3));
-        assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4));
-        assert_eq!(Duration::new(0, 500_000_001) * 4000,
-                   Duration::new(2000, 4000));
-    }
-
-    #[test]
-    fn checked_mul() {
-        assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2)));
-        assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3)));
-        assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4)));
-        assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000),
-                   Some(Duration::new(2000, 4000)));
-        assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None);
-    }
-
-    #[test]
-    fn div() {
-        assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0));
-        assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333));
-        assert_eq!(Duration::new(99, 999_999_000) / 100,
-                   Duration::new(0, 999_999_990));
-    }
-
-    #[test]
-    fn checked_div() {
-        assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0)));
-        assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000)));
-        assert_eq!(Duration::new(2, 0).checked_div(0), None);
-    }
-}
index f51dbc3772f06ee1c3302304fe69f802b653c2e3..8451e5987e908d1a77067729428622723691395d 100644 (file)
 #[derive(Clone)]
 pub struct TokenStream(tokenstream::TokenStream);
 
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl !Send for TokenStream {}
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl !Sync for TokenStream {}
+
 /// Error returned from `TokenStream::from_str`.
 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
 #[derive(Debug)]
@@ -81,6 +86,11 @@ pub struct LexError {
     _inner: (),
 }
 
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl !Send for LexError {}
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl !Sync for LexError {}
+
 impl TokenStream {
     /// Returns an empty `TokenStream`.
     #[unstable(feature = "proc_macro", issue = "38356")]
@@ -231,6 +241,11 @@ pub fn quote_span(span: Span) -> TokenStream {
 #[derive(Copy, Clone)]
 pub struct Span(syntax_pos::Span);
 
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl !Send for Span {}
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl !Sync for Span {}
+
 macro_rules! diagnostic_method {
     ($name:ident, $level:expr) => (
         /// Create a new `Diagnostic` with the given `message` at the span
@@ -363,6 +378,11 @@ pub struct LineColumn {
     pub column: usize
 }
 
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl !Send for LineColumn {}
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl !Sync for LineColumn {}
+
 /// The source file of a given `Span`.
 #[unstable(feature = "proc_macro", issue = "38356")]
 #[derive(Clone)]
@@ -393,7 +413,7 @@ pub fn path(&self) -> &FileName {
 
     /// Returns `true` if this source file is a real source file, and not generated by an external
     /// macro's expansion.
-    # [unstable(feature = "proc_macro", issue = "38356")]
+    #[unstable(feature = "proc_macro", issue = "38356")]
     pub fn is_real(&self) -> bool {
         // This is a hack until intercrate spans are implemented and we can have real source files
         // for spans generated in external macros.
@@ -450,6 +470,11 @@ pub enum TokenTree {
     Literal(Literal),
 }
 
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl !Send for TokenTree {}
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl !Sync for TokenTree {}
+
 impl TokenTree {
     /// Returns the span of this token, accessing the `span` method of each of
     /// the internal tokens.
@@ -546,6 +571,11 @@ pub struct Group {
     span: Span,
 }
 
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl !Send for Group {}
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl !Sync for Group {}
+
 /// Describes how a sequence of token trees is delimited.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 #[unstable(feature = "proc_macro", issue = "38356")]
@@ -628,6 +658,11 @@ pub struct Op {
     span: Span,
 }
 
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl !Send for Op {}
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl !Sync for Op {}
+
 /// Whether an `Op` is either followed immediately by another `Op` or followed by whitespace.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 #[unstable(feature = "proc_macro", issue = "38356")]
@@ -694,6 +729,11 @@ pub struct Term {
     span: Span,
 }
 
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl !Send for Term {}
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl !Sync for Term {}
+
 impl Term {
     /// Creates a new `Term` with the given `string` as well as the specified
     /// `span`.
@@ -752,6 +792,11 @@ pub struct Literal {
     span: Span,
 }
 
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl !Send for Literal {}
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl !Sync for Literal {}
+
 macro_rules! suffixed_int_literals {
     ($($name:ident => $kind:ident,)*) => ($(
         /// Creates a new suffixed integer literal with the specified value.
index 109edffcde38a5d3cc9a22804c6b6e3b47ed5d7f..398d7d5704c7fb4be1f0ca15388f30546efe65d1 100644 (file)
@@ -14,7 +14,7 @@
 //! compiler code, rather than using their own custom pass. Those
 //! lints are all available in `rustc_lint::builtin`.
 
-use errors::DiagnosticBuilder;
+use errors::{Applicability, DiagnosticBuilder};
 use lint::{LintPass, LateLintPass, LintArray};
 use session::Session;
 use syntax::codemap::Span;
 
 declare_lint! {
     pub INCOHERENT_FUNDAMENTAL_IMPLS,
-    Warn,
+    Deny,
     "potentially-conflicting impls were erroneously allowed"
 }
 
@@ -341,15 +341,16 @@ pub fn run(self, sess: &Session, db: &mut DiagnosticBuilder) {
         match self {
             BuiltinLintDiagnostics::Normal => (),
             BuiltinLintDiagnostics::BareTraitObject(span, is_global) => {
-                let sugg = match sess.codemap().span_to_snippet(span) {
-                    Ok(ref s) if is_global => format!("dyn ({})", s),
-                    Ok(s) => format!("dyn {}", s),
-                    Err(_) => format!("dyn <type>")
+                let (sugg, app) = match sess.codemap().span_to_snippet(span) {
+                    Ok(ref s) if is_global => (format!("dyn ({})", s),
+                                               Applicability::MachineApplicable),
+                    Ok(s) => (format!("dyn {}", s), Applicability::MachineApplicable),
+                    Err(_) => (format!("dyn <type>"), Applicability::HasPlaceholders)
                 };
-                db.span_suggestion(span, "use `dyn`", sugg);
+                db.span_suggestion_with_applicability(span, "use `dyn`", sugg, app);
             }
             BuiltinLintDiagnostics::AbsPathWithModule(span) => {
-                let sugg = match sess.codemap().span_to_snippet(span) {
+                let (sugg, app) = match sess.codemap().span_to_snippet(span) {
                     Ok(ref s) => {
                         // FIXME(Manishearth) ideally the emitting code
                         // can tell us whether or not this is global
@@ -359,11 +360,11 @@ pub fn run(self, sess: &Session, db: &mut DiagnosticBuilder) {
                             "::"
                         };
 
-                        format!("crate{}{}", opt_colon, s)
+                        (format!("crate{}{}", opt_colon, s), Applicability::MachineApplicable)
                     }
-                    Err(_) => format!("crate::<path>")
+                    Err(_) => (format!("crate::<path>"), Applicability::HasPlaceholders)
                 };
-                db.span_suggestion(span, "use `crate`", sugg);
+                db.span_suggestion_with_applicability(span, "use `crate`", sugg, app);
             }
         }
     }
index 55bfbed0b393c0082b57ef16d5a86b7fecde1b47..37f6d47ff849d563d5ca3fae76dd616fa123bc50 100644 (file)
@@ -1978,6 +1978,11 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 }
 
 impl Location {
+    pub const START: Location = Location {
+        block: START_BLOCK,
+        statement_index: 0,
+    };
+
     /// Returns the location immediately after this one within the enclosing block.
     ///
     /// Note that if this location represents a terminator, then the
index dc97c941567059cd5912250a945af3fdc4f0e938..83dac033f940863377bbba0a791903bb51c9cfa4 100644 (file)
@@ -1250,6 +1250,8 @@ fn parse_lto(slot: &mut Lto, v: Option<&str>) -> bool {
         "choose which RELRO level to use"),
     nll_subminimal_causes: bool = (false, parse_bool, [UNTRACKED],
         "when tracking region error causes, accept subminimal results for faster execution."),
+    nll_facts: bool = (false, parse_bool, [UNTRACKED],
+                       "dump facts from NLL analysis into side files"),
     disable_nll_user_type_assert: bool = (false, parse_bool, [UNTRACKED],
         "disable user provided type assertion in NLL"),
     trans_time_graph: bool = (false, parse_bool, [UNTRACKED],
@@ -1293,6 +1295,8 @@ fn parse_lto(slot: &mut Lto, v: Option<&str>) -> bool {
           "make the current crate share its generic instantiations"),
     chalk: bool = (false, parse_bool, [TRACKED],
           "enable the experimental Chalk-based trait solving engine"),
+    cross_lang_lto: bool = (false, parse_bool, [TRACKED],
+          "generate build artifacts that are compatible with linker-based LTO."),
 }
 
 pub fn default_lib_output() -> CrateType {
index a319b341ebbf06ee2bbc82d07829668c31393ad8..02c4b73efa1465fc89f3c2a36260b720651b7d0b 100644 (file)
@@ -1057,7 +1057,7 @@ enum StructKind {
                 }
                 tcx.intern_layout(LayoutDetails {
                     variants: Variants::Tagged {
-                        discr: tag,
+                        tag,
                         variants: layout_variants,
                     },
                     fields: FieldPlacement::Arbitrary {
@@ -1218,7 +1218,7 @@ fn record_layout_for_printing_outlined(self, layout: TyLayout<'tcx>) {
                     })
                     .collect();
                 record(adt_kind.into(), adt_packed, match layout.variants {
-                    Variants::Tagged { ref discr, .. } => Some(discr.value.size(self)),
+                    Variants::Tagged { ref tag, .. } => Some(tag.value.size(self)),
                     _ => None
                 }, variant_infos);
             }
@@ -1622,7 +1622,7 @@ fn field(this: TyLayout<'tcx>, cx: C, i: usize) -> C::TyLayout {
                     }
 
                     // Discriminant field for enums (where applicable).
-                    Variants::Tagged { ref discr, .. } |
+                    Variants::Tagged { tag: ref discr, .. } |
                     Variants::NicheFilling { niche: ref discr, .. } => {
                         assert_eq!(i, 0);
                         let layout = LayoutDetails::scalar(tcx, discr.clone());
@@ -1736,10 +1736,10 @@ fn hash_stable<W: StableHasherResult>(&self,
                 index.hash_stable(hcx, hasher);
             }
             Tagged {
-                ref discr,
+                ref tag,
                 ref variants,
             } => {
-                discr.hash_stable(hcx, hasher);
+                tag.hash_stable(hcx, hasher);
                 variants.hash_stable(hcx, hasher);
             }
             NicheFilling {
index c74e42263ef1497aacee2fedeaceed19746487b1..85533caffce2eb9b634ad72e490a14d42226fe64 100644 (file)
@@ -58,6 +58,17 @@ fn panic_hook(info: &panic::PanicInfo) {
         if backtrace {
             TyCtxt::try_print_query_stack();
         }
+
+        #[cfg(windows)]
+        unsafe {
+            if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
+                extern "system" {
+                    fn DebugBreak();
+                }
+                // Trigger a debugger if we crashed during bootstrap
+                DebugBreak();
+            }
+        }
     }
 }
 
index f06062fa4ac83091dddc7945df8660ef7672d202..7ae13c803ddcaa794ec1f2b70be780eaa4f69a4c 100644 (file)
@@ -46,7 +46,7 @@
 use syntax::feature_gate::{AttributeGate, AttributeType, Stability, deprecated_attributes};
 use syntax_pos::{BytePos, Span, SyntaxContext};
 use syntax::symbol::keywords;
-use syntax::errors::DiagnosticBuilder;
+use syntax::errors::{Applicability, DiagnosticBuilder};
 
 use rustc::hir::{self, PatKind};
 use rustc::hir::intravisit::FnKind;
@@ -1300,7 +1300,19 @@ fn perform_lint(&self, cx: &LateContext, what: &str, id: ast::NodeId,
             } else {
                 "pub(crate)"
             }.to_owned();
-            err.span_suggestion(pub_span, "consider restricting its visibility", replacement);
+            let app = if span.ctxt().outer().expn_info().is_none() {
+                // even if macros aren't involved the suggestion
+                // may be incorrect -- the user may have mistakenly
+                // hidden it behind a private module and this lint is
+                // a helpful way to catch that. However, we're trying
+                // not to change the nature of the code with this lint
+                // so it's marked as machine applicable.
+                Applicability::MachineApplicable
+            } else {
+                Applicability::MaybeIncorrect
+            };
+            err.span_suggestion_with_applicability(pub_span, "consider restricting its visibility",
+                                                   replacement, app);
             if exportable {
                 err.help("or consider exporting it for use by other crates");
             }
@@ -1508,3 +1520,66 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
         }
     }
 }
+
+declare_lint! {
+    pub UNNECESSARY_EXTERN_CRATE,
+    Allow,
+    "suggest removing `extern crate` for the 2018 edition"
+}
+
+pub struct ExternCrate(/* depth */ u32);
+
+impl ExternCrate {
+    pub fn new() -> Self {
+        ExternCrate(0)
+    }
+}
+
+impl LintPass for ExternCrate {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(UNNECESSARY_EXTERN_CRATE)
+    }
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExternCrate {
+    fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
+        if let hir::ItemExternCrate(ref orig) =  it.node {
+            if it.attrs.iter().any(|a| a.check_name("macro_use")) {
+                return
+            }
+            let mut err = cx.struct_span_lint(UNNECESSARY_EXTERN_CRATE,
+                it.span, "`extern crate` is unnecessary in the new edition");
+            if it.vis == hir::Visibility::Public || self.0 > 1 || orig.is_some() {
+                let pub_ = if it.vis == hir::Visibility::Public {
+                    "pub "
+                } else {
+                    ""
+                };
+
+                let help = format!("use `{}use`", pub_);
+
+                if let Some(orig) = orig {
+                    err.span_suggestion(it.span, &help,
+                        format!("{}use {} as {}", pub_, orig, it.name));
+                } else {
+                    err.span_suggestion(it.span, &help,
+                        format!("{}use {}", pub_, it.name));
+                }
+            } else {
+                err.span_suggestion(it.span, "remove it", "".into());
+            }
+
+            err.emit();
+        }
+    }
+
+    fn check_mod(&mut self, _: &LateContext, _: &hir::Mod,
+                 _: Span, _: ast::NodeId) {
+        self.0 += 1;
+    }
+
+    fn check_mod_post(&mut self, _: &LateContext, _: &hir::Mod,
+                      _: Span, _: ast::NodeId) {
+        self.0 += 1;
+    }
+}
index 4f6d23dce6dbb835c27a520e48737323c3ff8d9c..4403e1e3358b288bc174d42211a887d1cc112da4 100644 (file)
@@ -143,6 +143,7 @@ macro_rules! add_lint_group {
                           TypeLimits,
                           MissingDoc,
                           MissingDebugImplementations,
+                          ExternCrate,
                           );
 
     add_lint_group!(sess,
@@ -178,9 +179,10 @@ macro_rules! add_lint_group {
                     UNUSED_PARENS);
 
     add_lint_group!(sess,
-                    "rust_2018_idioms",
+                    "rust_2018_migration",
                     BARE_TRAIT_OBJECT,
-                    UNREACHABLE_PUB);
+                    UNREACHABLE_PUB,
+                    UNNECESSARY_EXTERN_CRATE);
 
     // Guidelines for creating a future incompatibility lint:
     //
index 904a3e4c4274f47d55edc0ecaf11824e6165d517..9e0dc4d80c8e2a3a9dfca2435d0b43a90a8888d8 100644 (file)
@@ -820,8 +820,8 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
                     bug!("failed to get layout for `{}`: {}", t, e)
                 });
 
-                if let layout::Variants::Tagged { ref variants, ref discr, .. } = layout.variants {
-                    let discr_size = discr.value.size(cx.tcx).bytes();
+                if let layout::Variants::Tagged { ref variants, ref tag, .. } = layout.variants {
+                    let discr_size = tag.value.size(cx.tcx).bytes();
 
                     debug!("enum `{}` is {} bytes large with layout:\n{:#?}",
                       t, layout.size.bytes(), layout);
index 8df40b62ddd1253d66cfd874ecce18377502ba69..845c964b986dda3cb319b7ac12c38abe98702821 100644 (file)
@@ -135,12 +135,12 @@ fn check_must_use(cx: &LateContext, def_id: DefId, sp: Span, describe_path: &str
                 if attr.check_name("must_use") {
                     let mut msg = format!("unused {}`{}` which must be used",
                                           describe_path, cx.tcx.item_path_str(def_id));
-                    // check for #[must_use="..."]
-                    if let Some(s) = attr.value_str() {
-                        msg.push_str(": ");
-                        msg.push_str(&s.as_str());
+                    let mut err = cx.struct_span_lint(UNUSED_MUST_USE, sp, &msg);
+                    // check for #[must_use = "..."]
+                    if let Some(note) = attr.value_str() {
+                        err.note(&note.as_str());
                     }
-                    cx.span_lint(UNUSED_MUST_USE, sp, &msg);
+                    err.emit();
                     return true;
                 }
             }
diff --git a/src/librustc_mir/borrow_check/location.rs b/src/librustc_mir/borrow_check/location.rs
new file mode 100644 (file)
index 0000000..28da1b2
--- /dev/null
@@ -0,0 +1,123 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::mir::{BasicBlock, Location, Mir};
+use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+
+/// Maps between a MIR Location, which identifies the a particular
+/// statement within a basic block, to a "rich location", which
+/// identifies at a finer granularity. In particular, we distinguish
+/// the *start* of a statement and the *mid-point*. The mid-point is
+/// the point *just* before the statement takes effect; in particular,
+/// for an assignment `A = B`, it is the point where B is about to be
+/// written into A. This mid-point is a kind of hack to work around
+/// our inability to track the position information at sufficient
+/// granularity through outlives relations; however, the rich location
+/// table serves another purpose: it compresses locations from
+/// multiple words into a single u32.
+crate struct LocationTable {
+    num_points: usize,
+    statements_before_block: IndexVec<BasicBlock, usize>,
+}
+
+newtype_index!(LocationIndex { DEBUG_FORMAT = "LocationIndex({})" });
+
+#[derive(Copy, Clone, Debug)]
+crate enum RichLocation {
+    Start(Location),
+    Mid(Location),
+}
+
+impl LocationTable {
+    crate fn new(mir: &Mir<'_>) -> Self {
+        let mut num_points = 0;
+        let statements_before_block = mir.basic_blocks()
+            .iter()
+            .map(|block_data| {
+                let v = num_points;
+                num_points += (block_data.statements.len() + 1) * 2;
+                v
+            })
+            .collect();
+
+        debug!(
+            "LocationTable(statements_before_block={:#?})",
+            statements_before_block
+        );
+        debug!("LocationTable: num_points={:#?}", num_points);
+
+        Self {
+            num_points,
+            statements_before_block,
+        }
+    }
+
+    crate fn all_points(&self) -> impl Iterator<Item = LocationIndex> {
+        (0..self.num_points).map(LocationIndex::new)
+    }
+
+    crate fn start_index(&self, location: Location) -> LocationIndex {
+        let Location {
+            block,
+            statement_index,
+        } = location;
+        let start_index = self.statements_before_block[block];
+        LocationIndex::new(start_index + statement_index * 2)
+    }
+
+    crate fn mid_index(&self, location: Location) -> LocationIndex {
+        let Location {
+            block,
+            statement_index,
+        } = location;
+        let start_index = self.statements_before_block[block];
+        LocationIndex::new(start_index + statement_index * 2 + 1)
+    }
+
+    crate fn to_location(&self, index: LocationIndex) -> RichLocation {
+        let point_index = index.index();
+
+        // Find the basic block. We have a vector with the
+        // starting index of the statement in each block. Imagine
+        // we have statement #22, and we have a vector like:
+        //
+        // [0, 10, 20]
+        //
+        // In that case, this represents point_index 2 of
+        // basic block BB2. We know this because BB0 accounts for
+        // 0..10, BB1 accounts for 11..20, and BB2 accounts for
+        // 20...
+        //
+        // To compute this, we could do a binary search, but
+        // because I am lazy we instead iterate through to find
+        // the last point where the "first index" (0, 10, or 20)
+        // was less than the statement index (22). In our case, this will
+        // be (BB2, 20).
+        let (block, &first_index) = self.statements_before_block
+            .iter_enumerated()
+            .filter(|(_, first_index)| **first_index <= point_index)
+            .last()
+            .unwrap();
+
+        let statement_index = (point_index - first_index) / 2;
+        if index.is_start() {
+            RichLocation::Start(Location { block, statement_index })
+        } else {
+            RichLocation::Mid(Location { block, statement_index })
+        }
+    }
+}
+
+impl LocationIndex {
+    fn is_start(&self) -> bool {
+        // even indices are start points; odd indices are mid points
+        (self.index() % 2) == 0
+    }
+}
index c619f350f58de10da593624a17a31ce56eb50591..3e3f510e308c330b82fbd16e524aa2e033c2ce2a 100644 (file)
 
 use self::borrow_set::{BorrowSet, BorrowData};
 use self::flows::Flows;
+use self::location::LocationTable;
 use self::prefixes::PrefixSet;
 use self::MutateMode::{JustWrite, WriteAndRead};
 
 crate mod borrow_set;
 mod error_reporting;
 mod flows;
+mod location;
 crate mod place_ext;
 mod prefixes;
 
@@ -110,6 +112,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
     let mut mir: Mir<'tcx> = input_mir.clone();
     let free_regions = nll::replace_regions_in_mir(infcx, def_id, param_env, &mut mir);
     let mir = &mir; // no further changes
+    let location_table = &LocationTable::new(mir);
 
     let move_data: MoveData<'tcx> = match MoveData::gather_moves(mir, tcx) {
         Ok(move_data) => move_data,
@@ -199,6 +202,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
         def_id,
         free_regions,
         mir,
+        location_table,
         param_env,
         &mut flow_inits,
         &mdpe.move_data,
index afaedecdf0abe307400847586aebaf1c0a98a838..d34e9434fbf2a0352a5cc4ec36b796f5cf1436f0 100644 (file)
@@ -8,28 +8,37 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use borrow_check::borrow_set::BorrowSet;
+use borrow_check::location::LocationTable;
+use borrow_check::nll::facts::AllFacts;
 use rustc::hir;
-use rustc::mir::{BasicBlock, BasicBlockData, Location, Place, Mir, Rvalue};
+use rustc::infer::InferCtxt;
+use rustc::mir::visit::TyContext;
 use rustc::mir::visit::Visitor;
 use rustc::mir::Place::Projection;
-use rustc::mir::{Local, PlaceProjection, ProjectionElem};
-use rustc::mir::visit::TyContext;
-use rustc::infer::InferCtxt;
-use rustc::ty::{self, CanonicalTy, ClosureSubsts};
-use rustc::ty::subst::Substs;
+use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, Rvalue};
+use rustc::mir::{Local, PlaceProjection, ProjectionElem, Statement, Terminator};
 use rustc::ty::fold::TypeFoldable;
+use rustc::ty::subst::Substs;
+use rustc::ty::{self, CanonicalTy, ClosureSubsts};
 
+use super::region_infer::{Cause, RegionInferenceContext};
 use super::ToRegionVid;
-use super::region_infer::{RegionInferenceContext, Cause};
 
 pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
     infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
     regioncx: &mut RegionInferenceContext<'tcx>,
+    all_facts: &mut Option<AllFacts>,
+    location_table: &LocationTable,
     mir: &Mir<'tcx>,
+    borrow_set: &BorrowSet<'tcx>,
 ) {
     let mut cg = ConstraintGeneration {
+        borrow_set,
         infcx,
         regioncx,
+        location_table,
+        all_facts,
         mir,
     };
 
@@ -41,8 +50,11 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
 /// 'cg = the duration of the constraint generation process itself.
 struct ConstraintGeneration<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> {
     infcx: &'cg InferCtxt<'cx, 'gcx, 'tcx>,
+    all_facts: &'cg mut Option<AllFacts>,
+    location_table: &'cg LocationTable,
     regioncx: &'cg mut RegionInferenceContext<'tcx>,
     mir: &'cg Mir<'tcx>,
+    borrow_set: &'cg BorrowSet<'tcx>,
 }
 
 impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx, 'tcx> {
@@ -68,12 +80,14 @@ fn visit_region(&mut self, region: &ty::Region<'tcx>, location: Location) {
     /// call. Make them live at the location where they appear.
     fn visit_ty(&mut self, ty: &ty::Ty<'tcx>, ty_context: TyContext) {
         match ty_context {
-            TyContext::ReturnTy(source_info) |
-            TyContext::YieldTy(source_info) |
-            TyContext::LocalDecl { source_info, .. } => {
-                span_bug!(source_info.span,
-                          "should not be visiting outside of the CFG: {:?}",
-                          ty_context);
+            TyContext::ReturnTy(source_info)
+            | TyContext::YieldTy(source_info)
+            | TyContext::LocalDecl { source_info, .. } => {
+                span_bug!(
+                    source_info.span,
+                    "should not be visiting outside of the CFG: {:?}",
+                    ty_context
+                );
             }
             TyContext::Location(location) => {
                 self.add_regular_live_constraint(*ty, location, Cause::LiveOther(location));
@@ -90,25 +104,117 @@ fn visit_closure_substs(&mut self, substs: &ClosureSubsts<'tcx>, location: Locat
         self.super_closure_substs(substs);
     }
 
+    fn visit_statement(
+        &mut self,
+        block: BasicBlock,
+        statement: &Statement<'tcx>,
+        location: Location,
+    ) {
+        if let Some(all_facts) = self.all_facts {
+            all_facts.cfg_edge.push((
+                self.location_table.start_index(location),
+                self.location_table.mid_index(location),
+            ));
+
+            all_facts.cfg_edge.push((
+                self.location_table.mid_index(location),
+                self.location_table
+                    .start_index(location.successor_within_block()),
+            ));
+        }
+
+        self.super_statement(block, statement, location);
+    }
+
+    fn visit_assign(
+        &mut self,
+        block: BasicBlock,
+        place: &Place<'tcx>,
+        rvalue: &Rvalue<'tcx>,
+        location: Location,
+    ) {
+        // When we see `X = ...`, then kill borrows of
+        // `(*X).foo` and so forth.
+        if let Some(all_facts) = self.all_facts {
+            if let Place::Local(temp) = place {
+                if let Some(borrow_indices) = self.borrow_set.local_map.get(temp) {
+                    for &borrow_index in borrow_indices {
+                        let location_index = self.location_table.mid_index(location);
+                        all_facts.killed.push((borrow_index, location_index));
+                    }
+                }
+            }
+        }
+
+        self.super_assign(block, place, rvalue, location);
+    }
+
+    fn visit_terminator(
+        &mut self,
+        block: BasicBlock,
+        terminator: &Terminator<'tcx>,
+        location: Location,
+    ) {
+        if let Some(all_facts) = self.all_facts {
+            all_facts.cfg_edge.push((
+                self.location_table.start_index(location),
+                self.location_table.mid_index(location),
+            ));
+
+            for successor_block in terminator.successors() {
+                all_facts.cfg_edge.push((
+                    self.location_table.mid_index(location),
+                    self.location_table
+                        .start_index(successor_block.start_location()),
+                ));
+            }
+        }
+
+        self.super_terminator(block, terminator, location);
+    }
+
     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
         debug!("visit_rvalue(rvalue={:?}, location={:?})", rvalue, location);
 
-        // Look for an rvalue like:
-        //
-        //     & L
-        //
-        // where L is the path that is borrowed. In that case, we have
-        // to add the reborrow constraints (which don't fall out
-        // naturally from the type-checker).
-        if let Rvalue::Ref(region, _bk, ref borrowed_lv) = *rvalue {
-            self.add_reborrow_constraint(location, region, borrowed_lv);
+        match rvalue {
+            Rvalue::Ref(region, _borrow_kind, borrowed_place) => {
+                // In some cases, e.g. when borrowing from an unsafe
+                // place, we don't bother to create a loan, since
+                // there are no conditions to validate.
+                if let Some(all_facts) = self.all_facts {
+                    if let Some(borrow_index) = self.borrow_set.location_map.get(&location) {
+                        let region_vid = region.to_region_vid();
+                        all_facts.borrow_region.push((
+                            region_vid,
+                            *borrow_index,
+                            self.location_table.mid_index(location),
+                        ));
+                    }
+                }
+
+                // Look for an rvalue like:
+                //
+                //     & L
+                //
+                // where L is the path that is borrowed. In that case, we have
+                // to add the reborrow constraints (which don't fall out
+                // naturally from the type-checker).
+                self.add_reborrow_constraint(location, region, borrowed_place);
+            }
+
+            _ => { }
         }
 
         self.super_rvalue(rvalue, location);
     }
 
-    fn visit_user_assert_ty(&mut self, _c_ty: &CanonicalTy<'tcx>,
-                            _local: &Local, _location: Location) { }
+    fn visit_user_assert_ty(
+        &mut self,
+        _c_ty: &CanonicalTy<'tcx>,
+        _local: &Local,
+        _location: Location,
+    ) {
+    }
 }
 
 impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
@@ -122,8 +228,7 @@ fn add_regular_live_constraint<T>(&mut self, live_ty: T, location: Location, cau
     {
         debug!(
             "add_regular_live_constraint(live_ty={:?}, location={:?})",
-            live_ty,
-            location
+            live_ty, location
         );
 
         self.infcx
@@ -144,8 +249,10 @@ fn add_reborrow_constraint(
     ) {
         let mut borrowed_place = borrowed_place;
 
-        debug!("add_reborrow_constraint({:?}, {:?}, {:?})",
-               location, borrow_region, borrowed_place);
+        debug!(
+            "add_reborrow_constraint({:?}, {:?}, {:?})",
+            location, borrow_region, borrowed_place
+        );
         while let Projection(box PlaceProjection { base, elem }) = borrowed_place {
             debug!("add_reborrow_constraint - iteration {:?}", borrowed_place);
 
@@ -165,12 +272,20 @@ fn add_reborrow_constraint(
                                 location.successor_within_block(),
                             );
 
+                            if let Some(all_facts) = self.all_facts {
+                                all_facts.outlives.push((
+                                    ref_region.to_region_vid(),
+                                    borrow_region.to_region_vid(),
+                                    self.location_table.mid_index(location),
+                                ));
+                            }
+
                             match mutbl {
                                 hir::Mutability::MutImmutable => {
                                     // Immutable reference. We don't need the base
                                     // to be valid for the entire lifetime of
                                     // the borrow.
-                                    break
+                                    break;
                                 }
                                 hir::Mutability::MutMutable => {
                                     // Mutable reference. We *do* need the base
@@ -199,19 +314,19 @@ fn add_reborrow_constraint(
                         }
                         ty::TyRawPtr(..) => {
                             // deref of raw pointer, guaranteed to be valid
-                            break
+                            break;
                         }
                         ty::TyAdt(def, _) if def.is_box() => {
                             // deref of `Box`, need the base to be valid - propagate
                         }
-                        _ => bug!("unexpected deref ty {:?} in {:?}", base_ty, borrowed_place)
+                        _ => bug!("unexpected deref ty {:?} in {:?}", base_ty, borrowed_place),
                     }
                 }
-                ProjectionElem::Field(..) |
-                ProjectionElem::Downcast(..) |
-                ProjectionElem::Index(..) |
-                ProjectionElem::ConstantIndex { .. } |
-                ProjectionElem::Subslice { .. } => {
+                ProjectionElem::Field(..)
+                | ProjectionElem::Downcast(..)
+                | ProjectionElem::Index(..)
+                | ProjectionElem::ConstantIndex { .. }
+                ProjectionElem::Subslice { .. } => {
                     // other field access
                 }
             }
diff --git a/src/librustc_mir/borrow_check/nll/facts.rs b/src/librustc_mir/borrow_check/nll/facts.rs
new file mode 100644 (file)
index 0000000..2802aa0
--- /dev/null
@@ -0,0 +1,194 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use borrow_check::location::{LocationIndex, LocationTable};
+use dataflow::indexes::BorrowIndex;
+use rustc::ty::RegionVid;
+use std::error::Error;
+use std::fmt::Debug;
+use std::fs::{self, File};
+use std::io::Write;
+use std::path::Path;
+
+/// The "facts" which are the basis of the NLL borrow analysis.
+#[derive(Default)]
+crate struct AllFacts {
+    // `borrow_region(R, B, P)` -- the region R may refer to data from borrow B
+    // starting at the point P (this is usually the point *after* a borrow rvalue)
+    crate borrow_region: Vec<(RegionVid, BorrowIndex, LocationIndex)>,
+
+    // universal_region(R) -- this is a "free region" within fn body
+    crate universal_region: Vec<RegionVid>,
+
+    // `cfg_edge(P,Q)` for each edge P -> Q in the control flow
+    crate cfg_edge: Vec<(LocationIndex, LocationIndex)>,
+
+    // `killed(B,P)` when some prefix of the path borrowed at B is assigned at point P
+    crate killed: Vec<(BorrowIndex, LocationIndex)>,
+
+    // `outlives(R1, R2, P)` when we require `R1@P: R2@P`
+    crate outlives: Vec<(RegionVid, RegionVid, LocationIndex)>,
+
+    // `region_live_at(R, P)` when the region R appears in a live variable at P
+    crate region_live_at: Vec<(RegionVid, LocationIndex)>,
+}
+
+impl AllFacts {
+    crate fn write_to_dir(
+        &self,
+        dir: impl AsRef<Path>,
+        location_table: &LocationTable,
+    ) -> Result<(), Box<dyn Error>> {
+        let dir: &Path = dir.as_ref();
+        fs::create_dir_all(dir)?;
+        let wr = FactWriter { location_table, dir };
+        macro_rules! write_facts_to_path {
+            ($wr:ident . write_facts_to_path($this:ident . [
+                $($field:ident,)*
+            ])) => {
+                $(
+                    $wr.write_facts_to_path(
+                        &$this.$field,
+                        &format!("{}.facts", stringify!($field))
+                    )?;
+                )*
+            }
+        }
+        write_facts_to_path! {
+            wr.write_facts_to_path(self.[
+                borrow_region,
+                universal_region,
+                cfg_edge,
+                killed,
+                outlives,
+                region_live_at,
+            ])
+        }
+        Ok(())
+    }
+}
+
+struct FactWriter<'w> {
+    location_table: &'w LocationTable,
+    dir: &'w Path,
+}
+
+impl<'w> FactWriter<'w> {
+    fn write_facts_to_path<T>(
+        &self,
+        rows: &Vec<T>,
+        file_name: &str,
+    ) -> Result<(), Box<dyn Error>>
+    where
+        T: FactRow,
+    {
+        let file = &self.dir.join(file_name);
+        let mut file = File::create(file)?;
+        for row in rows {
+            row.write(&mut file, self.location_table)?;
+        }
+        Ok(())
+    }
+}
+
+trait FactRow {
+    fn write(
+        &self,
+        out: &mut File,
+        location_table: &LocationTable,
+    ) -> Result<(), Box<dyn Error>>;
+}
+
+impl FactRow for RegionVid {
+    fn write(
+        &self,
+        out: &mut File,
+        location_table: &LocationTable,
+    ) -> Result<(), Box<dyn Error>> {
+        write_row(out, location_table, &[self])
+    }
+}
+
+impl<A, B> FactRow for (A, B)
+where
+    A: FactCell,
+    B: FactCell,
+{
+    fn write(
+        &self,
+        out: &mut File,
+        location_table: &LocationTable,
+    ) -> Result<(), Box<dyn Error>> {
+        write_row(out, location_table, &[&self.0, &self.1])
+    }
+}
+
+impl<A, B, C> FactRow for (A, B, C)
+where
+    A: FactCell,
+    B: FactCell,
+    C: FactCell,
+{
+    fn write(
+        &self,
+        out: &mut File,
+        location_table: &LocationTable,
+    ) -> Result<(), Box<dyn Error>> {
+        write_row(out, location_table, &[&self.0, &self.1, &self.2])
+    }
+}
+
+impl<A, B, C, D> FactRow for (A, B, C, D)
+where
+    A: FactCell,
+    B: FactCell,
+    C: FactCell,
+    D: FactCell,
+{
+    fn write(
+        &self,
+        out: &mut File,
+        location_table: &LocationTable,
+    ) -> Result<(), Box<dyn Error>> {
+        write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3])
+    }
+}
+
+fn write_row(
+    out: &mut dyn Write,
+    location_table: &LocationTable,
+    columns: &[&dyn FactCell],
+) -> Result<(), Box<dyn Error>> {
+    for (index, c) in columns.iter().enumerate() {
+        let tail = if index == columns.len() - 1 {
+            "\n"
+        } else {
+            "\t"
+        };
+        write!(out, "{:?}{}", c.to_string(location_table), tail)?;
+    }
+    Ok(())
+}
+
+trait FactCell {
+    fn to_string(&self, location_table: &LocationTable) -> String;
+}
+
+impl<A: Debug> FactCell for A {
+    default fn to_string(&self, _location_table: &LocationTable) -> String {
+        format!("{:?}", self)
+    }
+}
+
+impl FactCell for LocationIndex {
+    fn to_string(&self, location_table: &LocationTable) -> String {
+        format!("{:?}", location_table.to_location(*self))
+    }
+}
index 3ca1bd23e86ef4c9556ebcc289dabd076a53354a..0b1729294d8494b3ba74e8c61b482015f0789977 100644 (file)
@@ -9,36 +9,39 @@
 // except according to those terms.
 
 use borrow_check::borrow_set::BorrowSet;
+use borrow_check::location::LocationTable;
+use dataflow::move_paths::MoveData;
+use dataflow::FlowAtLocation;
+use dataflow::MaybeInitializedPlaces;
 use rustc::hir::def_id::DefId;
-use rustc::mir::{ClosureRegionRequirements, ClosureOutlivesSubject, Mir};
 use rustc::infer::InferCtxt;
+use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Mir};
 use rustc::ty::{self, RegionKind, RegionVid};
 use rustc::util::nodemap::FxHashMap;
 use std::collections::BTreeSet;
 use std::fmt::Debug;
 use std::io;
+use std::path::PathBuf;
 use transform::MirSource;
 use util::liveness::{LivenessResults, LocalSet};
-use dataflow::FlowAtLocation;
-use dataflow::MaybeInitializedPlaces;
-use dataflow::move_paths::MoveData;
 
+use self::mir_util::PassWhere;
 use util as mir_util;
 use util::pretty::{self, ALIGN};
-use self::mir_util::PassWhere;
 
 mod constraint_generation;
 pub mod explain_borrow;
-pub(crate) mod region_infer;
+mod facts;
+crate mod region_infer;
 mod renumber;
 mod subtype_constraint_generation;
-pub(crate) mod type_check;
+crate mod type_check;
 mod universal_regions;
 
+use self::facts::AllFacts;
 use self::region_infer::RegionInferenceContext;
 use self::universal_regions::UniversalRegions;
 
-
 /// Rewrites the regions in the MIR to use NLL variables, also
 /// scraping out the set of universal regions (e.g., region parameters)
 /// declared on the function. That set will need to be given to
@@ -71,10 +74,11 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
     def_id: DefId,
     universal_regions: UniversalRegions<'tcx>,
     mir: &Mir<'tcx>,
+    location_table: &LocationTable,
     param_env: ty::ParamEnv<'gcx>,
     flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'cx, 'gcx, 'tcx>>,
     move_data: &MoveData<'tcx>,
-    _borrow_set: &BorrowSet<'tcx>,
+    borrow_set: &BorrowSet<'tcx>,
 ) -> (
     RegionInferenceContext<'tcx>,
     Option<ClosureRegionRequirements<'gcx>>,
@@ -92,15 +96,47 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
         move_data,
     );
 
+    let mut all_facts = if infcx.tcx.sess.opts.debugging_opts.nll_facts {
+        Some(AllFacts::default())
+    } else {
+        None
+    };
+
+    if let Some(all_facts) = &mut all_facts {
+        all_facts
+            .universal_region
+            .extend(universal_regions.universal_regions());
+    }
+
     // Create the region inference context, taking ownership of the region inference
     // data that was contained in `infcx`.
     let var_origins = infcx.take_region_var_origins();
-    let mut regioncx = RegionInferenceContext::new(var_origins, universal_regions, mir);
-    subtype_constraint_generation::generate(&mut regioncx, mir, constraint_sets);
-
+    let mut regioncx =
+        RegionInferenceContext::new(var_origins, universal_regions, mir);
+
+    // Generate various constraints.
+    subtype_constraint_generation::generate(
+        &mut regioncx,
+        &mut all_facts,
+        location_table,
+        mir,
+        constraint_sets,
+    );
+    constraint_generation::generate_constraints(
+        infcx,
+        &mut regioncx,
+        &mut all_facts,
+        location_table,
+        &mir,
+        borrow_set,
+    );
 
-    // Generate non-subtyping constraints.
-    constraint_generation::generate_constraints(infcx, &mut regioncx, &mir);
+    // Dump facts if requested.
+    if let Some(all_facts) = all_facts {
+        let def_path = infcx.tcx.hir.def_path(def_id);
+        let dir_path = PathBuf::from("nll-facts").join(def_path.to_filename_friendly_no_crate());
+        all_facts.write_to_dir(dir_path, location_table).unwrap();
+    }
 
     // Solve the region constraints.
     let closure_region_requirements = regioncx.solve(infcx, &mir, def_id);
index 32728145b29f682b8e733cde1d566acb373e394a..9db19085a39654b630dc4833d9a4b09fb2c45c70 100644 (file)
@@ -8,14 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::mir::Mir;
+use borrow_check::location::LocationTable;
+use borrow_check::nll::facts::AllFacts;
 use rustc::infer::region_constraints::Constraint;
 use rustc::infer::region_constraints::RegionConstraintData;
 use rustc::infer::region_constraints::{Verify, VerifyBound};
+use rustc::mir::{Location, Mir};
 use rustc::ty;
+use std::iter;
 use syntax::codemap::Span;
 
-use super::region_infer::{TypeTest, RegionInferenceContext, RegionTest};
+use super::region_infer::{RegionInferenceContext, RegionTest, TypeTest};
 use super::type_check::Locations;
 use super::type_check::MirTypeckRegionConstraints;
 use super::type_check::OutlivesSet;
 /// them into the NLL `RegionInferenceContext`.
 pub(super) fn generate<'tcx>(
     regioncx: &mut RegionInferenceContext<'tcx>,
+    all_facts: &mut Option<AllFacts>,
+    location_table: &LocationTable,
     mir: &Mir<'tcx>,
     constraints: &MirTypeckRegionConstraints<'tcx>,
 ) {
-    SubtypeConstraintGenerator { regioncx, mir }.generate(constraints);
+    SubtypeConstraintGenerator {
+        regioncx,
+        location_table,
+        mir,
+    }.generate(constraints, all_facts);
 }
 
 struct SubtypeConstraintGenerator<'cx, 'tcx: 'cx> {
     regioncx: &'cx mut RegionInferenceContext<'tcx>,
+    location_table: &'cx LocationTable,
     mir: &'cx Mir<'tcx>,
 }
 
 impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> {
-    fn generate(&mut self, constraints: &MirTypeckRegionConstraints<'tcx>) {
+    fn generate(
+        &mut self,
+        constraints: &MirTypeckRegionConstraints<'tcx>,
+        all_facts: &mut Option<AllFacts>,
+    ) {
         let MirTypeckRegionConstraints {
             liveness_set,
             outlives_sets,
@@ -57,6 +71,17 @@ fn generate(&mut self, constraints: &MirTypeckRegionConstraints<'tcx>) {
             self.regioncx.add_live_point(region_vid, *location, &cause);
         }
 
+        if let Some(all_facts) = all_facts {
+            all_facts
+                .region_live_at
+                .extend(liveness_set.into_iter().flat_map(|(region, location, _)| {
+                    let r = self.to_region_vid(region);
+                    let p1 = self.location_table.start_index(*location);
+                    let p2 = self.location_table.mid_index(*location);
+                    iter::once((r, p1)).chain(iter::once((r, p2)))
+                }));
+        }
+
         for OutlivesSet { locations, data } in outlives_sets {
             debug!("generate: constraints at: {:#?}", locations);
             let RegionConstraintData {
@@ -65,7 +90,11 @@ fn generate(&mut self, constraints: &MirTypeckRegionConstraints<'tcx>) {
                 givens,
             } = data;
 
-            let span = self.mir.source_info(locations.from_location).span;
+            let span = self.mir
+                .source_info(locations.from_location().unwrap_or(Location::START))
+                .span;
+
+            let at_location = locations.at_location().unwrap_or(Location::START);
 
             for constraint in constraints.keys() {
                 debug!("generate: constraint: {:?}", constraint);
@@ -83,8 +112,24 @@ fn generate(&mut self, constraints: &MirTypeckRegionConstraints<'tcx>) {
                 // reverse direction, because `regioncx` talks about
                 // "outlives" (`>=`) whereas the region constraints
                 // talk about `<=`.
-                self.regioncx
-                    .add_outlives(span, b_vid, a_vid, locations.at_location);
+                self.regioncx.add_outlives(span, b_vid, a_vid, at_location);
+
+                // In the new analysis, all outlives relations etc
+                // "take effect" at the mid point of the statement
+                // that requires them, so ignore the `at_location`.
+                if let Some(all_facts) = all_facts {
+                    if let Some(from_location) = locations.from_location() {
+                        all_facts.outlives.push((
+                            b_vid,
+                            a_vid,
+                            self.location_table.mid_index(from_location),
+                        ));
+                    } else {
+                        for location in self.location_table.all_points() {
+                            all_facts.outlives.push((b_vid, a_vid, location));
+                        }
+                    }
+                }
             }
 
             for verify in verifys {
@@ -109,7 +154,7 @@ fn verify_to_type_test(
 
         let lower_bound = self.to_region_vid(verify.region);
 
-        let point = locations.at_location;
+        let point = locations.at_location().unwrap_or(Location::START);
 
         let test = self.verify_bound_to_region_test(&verify.bound);
 
@@ -149,14 +194,6 @@ fn verify_bound_to_region_test(&self, verify_bound: &VerifyBound<'tcx>) -> Regio
     }
 
     fn to_region_vid(&self, r: ty::Region<'tcx>) -> ty::RegionVid {
-        // Every region that we see in the constraints came from the
-        // MIR or from the parameter environment. If the former, it
-        // will be a region variable.  If the latter, it will be in
-        // the set of universal regions *somewhere*.
-        if let ty::ReVar(vid) = r {
-            *vid
-        } else {
-            self.regioncx.to_region_vid(r)
-        }
+        self.regioncx.to_region_vid(r)
     }
 }
index b1aeae0b76bb112b48234a286e1909d050db9dd9..2b1878c33e90b78f877672427d6c7f6703fae1de 100644 (file)
@@ -29,7 +29,7 @@
 
 use rustc_data_structures::indexed_vec::Idx;
 
-use super::{AtLocation, TypeChecker};
+use super::{Locations, TypeChecker};
 
 impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
     pub(super) fn equate_inputs_and_outputs(
@@ -47,26 +47,21 @@ pub(super) fn equate_inputs_and_outputs(
         } = universal_regions;
         let infcx = self.infcx;
 
-        let start_position = Location {
-            block: START_BLOCK,
-            statement_index: 0,
-        };
-
         // Equate expected input tys with those in the MIR.
         let argument_locals = (1..).map(Local::new);
         for (&unnormalized_input_ty, local) in unnormalized_input_tys.iter().zip(argument_locals) {
-            let input_ty = self.normalize(&unnormalized_input_ty, start_position);
+            let input_ty = self.normalize(&unnormalized_input_ty, Locations::All);
             let mir_input_ty = mir.local_decls[local].ty;
-            self.equate_normalized_input_or_output(start_position, input_ty, mir_input_ty);
+            self.equate_normalized_input_or_output(input_ty, mir_input_ty);
         }
 
         assert!(
             mir.yield_ty.is_some() && universal_regions.yield_ty.is_some() ||
             mir.yield_ty.is_none() && universal_regions.yield_ty.is_none()
-            );
+        );
         if let Some(mir_yield_ty) = mir.yield_ty {
             let ur_yield_ty = universal_regions.yield_ty.unwrap();
-            self.equate_normalized_input_or_output(start_position, ur_yield_ty, mir_yield_ty);
+            self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty);
         }
 
         // Return types are a bit more complex. They may contain existential `impl Trait`
@@ -75,13 +70,13 @@ pub(super) fn equate_inputs_and_outputs(
             "equate_inputs_and_outputs: unnormalized_output_ty={:?}",
             unnormalized_output_ty
         );
-        let output_ty = self.normalize(&unnormalized_output_ty, start_position);
+        let output_ty = self.normalize(&unnormalized_output_ty, Locations::All);
         debug!(
             "equate_inputs_and_outputs: normalized output_ty={:?}",
             output_ty
         );
         let mir_output_ty = mir.local_decls[RETURN_PLACE].ty;
-        let anon_type_map = self.fully_perform_op(start_position.at_self(), |cx| {
+        let anon_type_map = self.fully_perform_op(Locations::All, |cx| {
             let mut obligations = ObligationAccumulator::default();
 
             let (output_ty, anon_type_map) = obligations.add(infcx.instantiate_anon_types(
@@ -112,7 +107,7 @@ pub(super) fn equate_inputs_and_outputs(
                 let anon_defn_ty = anon_defn_ty.subst(tcx, anon_decl.substs);
                 let anon_defn_ty = renumber::renumber_regions(
                     cx.infcx,
-                    TyContext::Location(start_position),
+                    TyContext::Location(Location::START),
                     &anon_defn_ty,
                 );
                 debug!(
@@ -134,7 +129,7 @@ pub(super) fn equate_inputs_and_outputs(
         }).unwrap_or_else(|terr| {
                 span_mirbug!(
                     self,
-                    start_position,
+                    Location::START,
                     "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
                     output_ty,
                     mir_output_ty,
@@ -148,7 +143,7 @@ pub(super) fn equate_inputs_and_outputs(
         // prove that `T: Iterator` where `T` is the type we
         // instantiated it with).
         if let Some(anon_type_map) = anon_type_map {
-            self.fully_perform_op(start_position.at_self(), |_cx| {
+            self.fully_perform_op(Locations::All, |_cx| {
                 infcx.constrain_anon_types(&anon_type_map, universal_regions);
                 Ok(InferOk {
                     value: (),
@@ -158,13 +153,13 @@ pub(super) fn equate_inputs_and_outputs(
         }
     }
 
-    fn equate_normalized_input_or_output(&mut self, location: Location, a: Ty<'tcx>, b: Ty<'tcx>) {
+    fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
         debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b);
 
-        if let Err(terr) = self.eq_types(a, b, location.at_self()) {
+        if let Err(terr) = self.eq_types(a, b, Locations::All) {
             span_mirbug!(
                 self,
-                location,
+                Location::START,
                 "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
                 a,
                 b,
index a21b9196badb5856b5fba5c3e8575114662bdf09..42a1745addff75de36333f0f7047e59e2af05aea 100644 (file)
@@ -618,17 +618,72 @@ pub struct OutlivesSet<'tcx> {
     pub data: RegionConstraintData<'tcx>,
 }
 
+/// The `Locations` type summarizes *where* region constraints are
+/// required to hold. Normally, this is at a particular point which
+/// created the obligation, but for constraints that the user gave, we
+/// want the constraint to hold at all points.
 #[derive(Copy, Clone, Debug)]
-pub struct Locations {
-    /// The location in the MIR that generated these constraints.
-    /// This is intended for error reporting and diagnosis; the
-    /// constraints may *take effect* at a distinct spot.
-    pub from_location: Location,
-
-    /// The constraints must be met at this location. In terms of the
-    /// NLL RFC, when you have a constraint `R1: R2 @ P`, this field
-    /// is the `P` value.
-    pub at_location: Location,
+pub enum Locations {
+    /// Indicates that a type constraint should always be true. This
+    /// is particularly important in the new borrowck analysis for
+    /// things like the type of the return slot. Consider this
+    /// example:
+    ///
+    /// ```
+    /// fn foo<'a>(x: &'a u32) -> &'a u32 {
+    ///     let y = 22;
+    ///     return &y; // error
+    /// }
+    /// ```
+    ///
+    /// Here, we wind up with the signature from the return type being
+    /// something like `&'1 u32` where `'1` is a universal region. But
+    /// the type of the return slot `_0` is something like `&'2 u32`
+    /// where `'2` is an existential region variable. The type checker
+    /// requires that `&'2 u32 = &'1 u32` -- but at what point? In the
+    /// older NLL analysis, we required this only at the entry point
+    /// to the function. By the nature of the constraints, this wound
+    /// up propagating to all points reachable from start (because
+    /// `'1` -- as a universal region -- is live everywhere).  In the
+    /// newer analysis, though, this doesn't work: `_0` is considered
+    /// dead at the start (it has no usable value) and hence this type
+    /// equality is basically a no-op. Then, later on, when we do `_0
+    /// = &'3 y`, that region `'3` never winds up related to the
+    /// universal region `'1` and hence no error occurs. Therefore, we
+    /// use Locations::All instead, which ensures that the `'1` and
+    /// `'2` are equal everything. We also use this for other
+    /// user-given type annotations; e.g., if the user wrote `let mut
+    /// x: &'static u32 = ...`, we would ensure that all values
+    /// assigned to `x` are of `'static` lifetime.
+    All,
+
+    Pair {
+        /// The location in the MIR that generated these constraints.
+        /// This is intended for error reporting and diagnosis; the
+        /// constraints may *take effect* at a distinct spot.
+        from_location: Location,
+
+        /// The constraints must be met at this location. In terms of the
+        /// NLL RFC, when you have a constraint `R1: R2 @ P`, this field
+        /// is the `P` value.
+        at_location: Location,
+    }
+}
+
+impl Locations {
+    pub fn from_location(&self) -> Option<Location> {
+        match self {
+            Locations::All => None,
+            Locations::Pair { from_location, .. } => Some(*from_location),
+        }
+    }
+
+    pub fn at_location(&self) -> Option<Location> {
+        match self {
+            Locations::All => None,
+            Locations::Pair { at_location, .. } => Some(*at_location),
+        }
+    }
 }
 
 impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
@@ -770,7 +825,7 @@ fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>, location: Loca
                     "check_stmt: user_assert_ty ty={:?} local_ty={:?}",
                     ty, local_ty
                 );
-                if let Err(terr) = self.eq_types(ty, local_ty, location.at_self()) {
+                if let Err(terr) = self.eq_types(ty, local_ty, Locations::All) {
                     span_mirbug!(
                         self,
                         stmt,
@@ -820,7 +875,7 @@ fn check_terminator(
                 let place_ty = location.ty(mir, tcx).to_ty(tcx);
                 let rv_ty = value.ty(mir, tcx);
 
-                let locations = Locations {
+                let locations = Locations::Pair {
                     from_location: term_location,
                     at_location: target.start_location(),
                 };
@@ -839,7 +894,7 @@ fn check_terminator(
                 // *both* blocks, so we need to ensure that it holds
                 // at both locations.
                 if let Some(unwind) = unwind {
-                    let locations = Locations {
+                    let locations = Locations::Pair {
                         from_location: term_location,
                         at_location: unwind.start_location(),
                     };
@@ -971,7 +1026,7 @@ fn check_call_dest(
         match *destination {
             Some((ref dest, target_block)) => {
                 let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
-                let locations = Locations {
+                let locations = Locations::Pair {
                     from_location: term_location,
                     at_location: target_block.start_location(),
                 };
@@ -1375,7 +1430,7 @@ fn check_aggregate_rvalue(
             };
             let operand_ty = operand.ty(mir, tcx);
             if let Err(terr) =
-                self.sub_types(operand_ty, field_ty, location.at_successor_within_block())
+                self.sub_types(operand_ty, field_ty, location.at_self())
             {
                 span_mirbug!(
                     self,
@@ -1514,12 +1569,12 @@ fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
         }
     }
 
-    fn normalize<T>(&mut self, value: &T, location: Location) -> T
+    fn normalize<T>(&mut self, value: &T, location: impl ToLocations) -> T
     where
         T: fmt::Debug + TypeFoldable<'tcx>,
     {
         debug!("normalize(value={:?}, location={:?})", value, location);
-        self.fully_perform_op(location.at_self(), |this| {
+        self.fully_perform_op(location.to_locations(), |this| {
             let Normalized { value, obligations } = this.infcx
                 .at(&this.misc(this.last_span), this.param_env)
                 .normalize(value)
@@ -1585,16 +1640,32 @@ trait AtLocation {
 
 impl AtLocation for Location {
     fn at_self(self) -> Locations {
-        Locations {
+        Locations::Pair {
             from_location: self,
             at_location: self,
         }
     }
 
     fn at_successor_within_block(self) -> Locations {
-        Locations {
+        Locations::Pair {
             from_location: self,
             at_location: self.successor_within_block(),
         }
     }
 }
+
+trait ToLocations: fmt::Debug + Copy {
+    fn to_locations(self) -> Locations;
+}
+
+impl ToLocations for Locations {
+    fn to_locations(self) -> Locations {
+        self
+    }
+}
+
+impl ToLocations for Location {
+    fn to_locations(self) -> Locations {
+        self.at_self()
+    }
+}
index bea29b6926aa63c1b48b1c6a5266a75b809885d7..d8f1324206500d2ba58c131c3bd12ec1f91fffd9 100644 (file)
@@ -654,6 +654,9 @@ pub(super) fn eval_rvalue_into_place(
                         if self.type_is_fat_ptr(src.ty) {
                             match (src.value, self.type_is_fat_ptr(dest_ty)) {
                                 (Value::ByRef { .. }, _) |
+                                // pointers to extern types
+                                (Value::ByVal(_),_) |
+                                // slices and trait objects to other slices/trait objects
                                 (Value::ByValPair(..), true) => {
                                     let valty = ValTy {
                                         value: src.value,
@@ -661,6 +664,7 @@ pub(super) fn eval_rvalue_into_place(
                                     };
                                     self.write_value(valty, dest)?;
                                 }
+                                // slices and trait objects to thin pointers (dropping the metadata)
                                 (Value::ByValPair(data, _), false) => {
                                     let valty = ValTy {
                                         value: Value::ByVal(data),
@@ -668,7 +672,6 @@ pub(super) fn eval_rvalue_into_place(
                                     };
                                     self.write_value(valty, dest)?;
                                 }
-                                (Value::ByVal(_), _) => bug!("expected fat ptr"),
                             }
                         } else {
                             let src_layout = self.layout_of(src.ty)?;
@@ -960,7 +963,7 @@ pub fn write_discriminant_value(
                                layout::Abi::Uninhabited);
                 }
             }
-            layout::Variants::Tagged { ref discr, .. } => {
+            layout::Variants::Tagged { ref tag, .. } => {
                 let discr_val = dest_ty.ty_adt_def().unwrap()
                     .discriminant_for_variant(*self.tcx, variant_index)
                     .val;
@@ -968,12 +971,12 @@ pub fn write_discriminant_value(
                 // raw discriminants for enums are isize or bigger during
                 // their computation, but the in-memory tag is the smallest possible
                 // representation
-                let size = discr.value.size(self.tcx.tcx).bits();
+                let size = tag.value.size(self.tcx.tcx).bits();
                 let amt = 128 - size;
                 let discr_val = (discr_val << amt) >> amt;
 
-                let (discr_dest, discr) = self.place_field(dest, mir::Field::new(0), layout)?;
-                self.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?;
+                let (discr_dest, tag) = self.place_field(dest, mir::Field::new(0), layout)?;
+                self.write_primval(discr_dest, PrimVal::Bytes(discr_val), tag.ty)?;
             }
             layout::Variants::NicheFilling {
                 dataful_variant,
index 95cf3b8ddc6ceace3095a749d965e07a3b36344e..2545ba3a94af12215c6a4a15437304944a2ee358 100644 (file)
@@ -34,6 +34,7 @@
 #![feature(inclusive_range_methods)]
 #![feature(crate_visibility_modifier)]
 #![feature(never_type)]
+#![feature(specialization)]
 #![cfg_attr(stage0, feature(try_trait))]
 
 extern crate arena;
index 8b771fcf4936b22cb3e463fbdcb88b4c93ea7c68..5397d18cdd720be1b0d185fe4359e88d10bb07d3 100644 (file)
@@ -550,7 +550,7 @@ fn set_drop_flag(&mut self, loc: Location, path: MovePathIndex, val: DropFlagSta
     }
 
     fn drop_flags_on_init(&mut self) {
-        let loc = Location { block: START_BLOCK, statement_index: 0 };
+        let loc = Location::START;
         let span = self.patch.source_info_for_location(self.mir, loc).span;
         let false_ = self.constant_bool(span, false);
         for flag in self.drop_flags.values() {
@@ -576,7 +576,7 @@ fn drop_flags_for_fn_rets(&mut self) {
     }
 
     fn drop_flags_for_args(&mut self) {
-        let loc = Location { block: START_BLOCK, statement_index: 0 };
+        let loc = Location::START;
         dataflow::drop_flag_effects_for_function_entry(
             self.tcx, self.mir, self.env, |path, ds| {
                 self.set_drop_flag(loc, path, ds);
index 622d8e51a6ca3a2cbcdfb2a960600d16ae66a934..348aa6a7cef4c7678c85c7e43dde9ca7ea9aef43 100644 (file)
@@ -65,7 +65,6 @@
        html_root_url = "https://doc.rust-lang.org/nightly/")]
 
 #![feature(rustc_diagnostic_macros)]
-#![feature(staged_api)]
 
 #[macro_use] extern crate syntax;
 
index ebfd8785a0a0c8e0866fae9b2a979d11158cc09d..7e3c411c1d2474d920d3cd2806dbde6672e4a86b 100644 (file)
@@ -128,8 +128,6 @@ pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxEx
     /// This can be used in place of `register_syntax_extension` to register legacy custom derives
     /// (i.e. attribute syntax extensions whose name begins with `derive_`). Legacy custom
     /// derives defined by this function do not trigger deprecation warnings when used.
-    #[unstable(feature = "rustc_private", issue = "27812")]
-    #[rustc_deprecated(since = "1.15.0", reason = "replaced by macros 1.1 (RFC 1861)")]
     pub fn register_custom_derive(&mut self, name: ast::Name, extension: SyntaxExtension) {
         assert!(name.as_str().starts_with("derive_"));
         self.whitelisted_custom_derives.push(name);
index d4b212a15d82f9ba637f3337f9431303448e3a42..0f931d4374e59337a7e43c78ff7f1cc6f579b030 100644 (file)
@@ -3277,9 +3277,8 @@ fn resolve_path(&mut self,
                     let prev_name = path[0].name;
                     if prev_name == keywords::Extern.name() ||
                        prev_name == keywords::CrateRoot.name() &&
-                       // Note: When this feature stabilizes, this should
-                       // be gated on sess.rust_2018()
-                       self.session.features_untracked().extern_absolute_paths {
+                       self.session.features_untracked().extern_absolute_paths &&
+                       self.session.rust_2018() {
                         // `::extern_crate::a::b`
                         let crate_id = self.crate_loader.process_path_extern(name, ident.span);
                         let crate_root =
index 17aa510b565e90805ea2ae54cd31d8b14f80f2ba..6a5a31a885fb9855c880239da9df6a23358da1cc 100644 (file)
@@ -646,7 +646,8 @@ fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Spa
         if module_path.len() == 1 && (module_path[0].name == keywords::CrateRoot.name() ||
                                       module_path[0].name == keywords::Extern.name()) {
             let is_extern = module_path[0].name == keywords::Extern.name() ||
-                            self.session.features_untracked().extern_absolute_paths;
+                            (self.session.features_untracked().extern_absolute_paths &&
+                             self.session.rust_2018());
             match directive.subclass {
                 GlobImport { .. } if is_extern => {
                     return Some((directive.span,
index 401a280412a114eb448d13d95d2231e6ce15b2d4..cf12302d9896978cf459ee5fb54f0e8b560ad3ef 100644 (file)
@@ -40,7 +40,7 @@
 
 use rustc::hir;
 use rustc::hir::def::Def as HirDef;
-use rustc::hir::map::{Node, NodeItem};
+use rustc::hir::map::{Node, NodeTraitItem, NodeImplItem};
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::middle::cstore::ExternCrate;
 use rustc::session::config::CrateType::CrateTypeExecutable;
@@ -418,34 +418,30 @@ pub fn get_method_data(&self, id: ast::NodeId, name: ast::Name, span: Span) -> O
                 Some(impl_id) => match self.tcx.hir.get_if_local(impl_id) {
                     Some(Node::NodeItem(item)) => match item.node {
                         hir::ItemImpl(.., ref ty, _) => {
-                            let mut result = String::from("<");
-                            result.push_str(&self.tcx.hir.node_to_pretty_string(ty.id));
+                            let mut qualname = String::from("<");
+                            qualname.push_str(&self.tcx.hir.node_to_pretty_string(ty.id));
 
                             let mut trait_id = self.tcx.trait_id_of_impl(impl_id);
                             let mut decl_id = None;
+                            let mut docs = String::new();
+                            let mut attrs = vec![];
+                            if let Some(NodeImplItem(item)) = self.tcx.hir.find(id) {
+                                docs = self.docs_for_attrs(&item.attrs);
+                                attrs = item.attrs.to_vec();
+                            }
+
                             if let Some(def_id) = trait_id {
-                                result.push_str(" as ");
-                                result.push_str(&self.tcx.item_path_str(def_id));
+                                // A method in a trait impl.
+                                qualname.push_str(" as ");
+                                qualname.push_str(&self.tcx.item_path_str(def_id));
                                 self.tcx
                                     .associated_items(def_id)
                                     .find(|item| item.name == name)
                                     .map(|item| decl_id = Some(item.def_id));
-                            } else {
-                                if let Some(NodeItem(item)) = self.tcx.hir.find(id) {
-                                    if let hir::ItemImpl(_, _, _, _, _, ref ty, _) = item.node {
-                                        trait_id = self.lookup_ref_id(ty.id);
-                                    }
-                                }
                             }
-                            result.push_str(">");
-
-                            (
-                                result,
-                                trait_id,
-                                decl_id,
-                                self.docs_for_attrs(&item.attrs),
-                                item.attrs.to_vec(),
-                            )
+                            qualname.push_str(">");
+
+                            (qualname, trait_id, decl_id, docs, attrs)
                         }
                         _ => {
                             span_bug!(
@@ -467,25 +463,23 @@ pub fn get_method_data(&self, id: ast::NodeId, name: ast::Name, span: Span) -> O
                     }
                 },
                 None => match self.tcx.trait_of_item(self.tcx.hir.local_def_id(id)) {
-                    Some(def_id) => match self.tcx.hir.get_if_local(def_id) {
-                        Some(Node::NodeItem(item)) => (
+                    Some(def_id) => {
+                        let mut docs = String::new();
+                        let mut attrs = vec![];
+
+                        if let Some(NodeTraitItem(item)) = self.tcx.hir.find(id) {
+                            docs = self.docs_for_attrs(&item.attrs);
+                            attrs = item.attrs.to_vec();
+                        }
+
+                        (
                             format!("::{}", self.tcx.item_path_str(def_id)),
                             Some(def_id),
                             None,
-                            self.docs_for_attrs(&item.attrs),
-                            item.attrs.to_vec(),
-                        ),
-                        r => {
-                            span_bug!(
-                                span,
-                                "Could not find container {:?} for \
-                                 method {}, got {:?}",
-                                def_id,
-                                id,
-                                r
-                            );
-                        }
-                    },
+                            docs,
+                            attrs,
+                        )
+                    }
                     None => {
                         debug!("Could not find container for method {} at {:?}", id, span);
                         // This is not necessarily a bug, if there was a compilation error,
index fd1f779f9ecc06168ee635e11907d2b576ed2dda..7ae4d990c8a4ec469a2ce3da7463343b1ec21119 100644 (file)
@@ -716,10 +716,10 @@ pub enum Variants {
     },
 
     /// General-case enums: for each case there is a struct, and they all have
-    /// all space reserved for the discriminant, and their first field starts
-    /// at a non-0 offset, after where the discriminant would go.
+    /// all space reserved for the tag, and their first field starts
+    /// at a non-0 offset, after where the tag would go.
     Tagged {
-        discr: Scalar,
+        tag: Scalar,
         variants: Vec<LayoutDetails>,
     },
 
index 148e3d0025c83e3cc443bf901d73fdb39553eaed..b6fae3eaff23a64cfd0cf62f5a207790562d76e8 100644 (file)
@@ -293,7 +293,8 @@ fn set_flags(&mut self, sess: &Session, no_builtins: bool) {
         self.inline_threshold = sess.opts.cg.inline_threshold;
         self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode;
         let embed_bitcode = sess.target.target.options.embed_bitcode ||
-            sess.opts.debugging_opts.embed_bitcode;
+                            sess.opts.debugging_opts.embed_bitcode ||
+                            sess.opts.debugging_opts.cross_lang_lto;
         if embed_bitcode {
             match sess.opts.optimize {
                 config::OptLevel::No |
@@ -841,13 +842,18 @@ unsafe fn embed_bitcode(cgcx: &CodegenContext,
         "rustc.embedded.module\0".as_ptr() as *const _,
     );
     llvm::LLVMSetInitializer(llglobal, llconst);
-    let section = if cgcx.opts.target_triple.triple().contains("-ios") {
+
+    let is_apple = cgcx.opts.target_triple.triple().contains("-ios") ||
+                   cgcx.opts.target_triple.triple().contains("-darwin");
+
+    let section = if is_apple {
         "__LLVM,__bitcode\0"
     } else {
         ".llvmbc\0"
     };
     llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _);
     llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
+    llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
 
     let llconst = C_bytes_in_context(llcx, &[]);
     let llglobal = llvm::LLVMAddGlobal(
@@ -856,7 +862,7 @@ unsafe fn embed_bitcode(cgcx: &CodegenContext,
         "rustc.embedded.cmdline\0".as_ptr() as *const _,
     );
     llvm::LLVMSetInitializer(llglobal, llconst);
-    let section = if cgcx.opts.target_triple.triple().contains("-ios") {
+    let section = if  is_apple {
         "__LLVM,__cmdline\0"
     } else {
         ".llvmcmd\0"
@@ -1350,6 +1356,10 @@ fn execute_work_item(cgcx: &CodegenContext,
             // settings.
             let needs_lto = needs_lto && mtrans.kind != ModuleKind::Metadata;
 
+            // Don't run LTO passes when cross-lang LTO is enabled. The linker
+            // will do that for us in this case.
+            let needs_lto = needs_lto && !cgcx.opts.debugging_opts.cross_lang_lto;
+
             if needs_lto {
                 Ok(WorkItemResult::NeedsLTO(mtrans))
             } else {
index 2fc6c9d4433016f74613225759412724916744cd..f16fef5ec1e843b269e7f19801cf50e7c2c07975 100644 (file)
@@ -1429,8 +1429,8 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
     let discriminant_type_metadata = match layout.variants {
         layout::Variants::Single { .. } |
         layout::Variants::NicheFilling { .. } => None,
-        layout::Variants::Tagged { ref discr, .. } => {
-            Some(discriminant_type_metadata(discr.value))
+        layout::Variants::Tagged { ref tag, .. } => {
+            Some(discriminant_type_metadata(tag.value))
         }
     };
 
index 79859aee64d874dfddbbb6333e6521d65bf6eaf7..d4abd5fa88d31bc496ca14830d22cb4e065ee4a8 100644 (file)
@@ -273,8 +273,8 @@ pub fn trans_get_discr(self, bx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> Value
         let lldiscr = discr.load(bx).immediate();
         match self.layout.variants {
             layout::Variants::Single { .. } => bug!(),
-            layout::Variants::Tagged { ref discr, .. } => {
-                let signed = match discr.value {
+            layout::Variants::Tagged { ref tag, .. } => {
+                let signed = match tag.value {
                     layout::Int(_, signed) => signed,
                     _ => false
                 };
index 23e0c2625eeeb6b0607d2d7fa8d63cdc1211e251..a8f4848bf89f2a0394aadc9b6bdd7863e827631d 100644 (file)
@@ -38,7 +38,7 @@
 ///
 /// The returned value is `None` if the definition could not be inlined,
 /// and `Some` of a vector of items if it was successfully expanded.
-pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name)
+pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name, visited: &mut FxHashSet<DefId>)
                   -> Option<Vec<clean::Item>> {
     if def == Def::Err { return None }
     let did = def.def_id();
@@ -87,7 +87,7 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name)
         Def::StructCtor(..) => return Some(Vec::new()),
         Def::Mod(did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Module);
-            clean::ModuleItem(build_module(cx, did))
+            clean::ModuleItem(build_module(cx, did, visited))
         }
         Def::Static(did, mtbl) => {
             record_extern_fqn(cx, did, clean::TypeKind::Static);
@@ -385,24 +385,24 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
     });
 }
 
-fn build_module(cx: &DocContext, did: DefId) -> clean::Module {
+fn build_module(cx: &DocContext, did: DefId, visited: &mut FxHashSet<DefId>) -> clean::Module {
     let mut items = Vec::new();
-    fill_in(cx, did, &mut items);
+    fill_in(cx, did, &mut items, visited);
     return clean::Module {
         items,
         is_crate: false,
     };
 
-    fn fill_in(cx: &DocContext, did: DefId, items: &mut Vec<clean::Item>) {
+    fn fill_in(cx: &DocContext, did: DefId, items: &mut Vec<clean::Item>,
+               visited: &mut FxHashSet<DefId>) {
         // If we're re-exporting a re-export it may actually re-export something in
         // two namespaces, so the target may be listed twice. Make sure we only
         // visit each node at most once.
-        let mut visited = FxHashSet();
         for &item in cx.tcx.item_children(did).iter() {
             let def_id = item.def.def_id();
             if item.vis == ty::Visibility::Public {
-                if !visited.insert(def_id) { continue }
-                if let Some(i) = try_inline(cx, item.def, item.ident.name) {
+                if did == def_id || !visited.insert(def_id) { continue }
+                if let Some(i) = try_inline(cx, item.def, item.ident.name, visited) {
                     items.extend(i)
                 }
             }
index edbf5f3abd25dc534494c5951c1746d711898f03..fb0bd0e42c57edf9a7442c528beb1d2051aec39d 100644 (file)
@@ -3686,7 +3686,8 @@ fn clean(&self, cx: &DocContext) -> Vec<Item> {
         } else {
             let name = self.name;
             if !denied {
-                if let Some(items) = inline::try_inline(cx, path.def, name) {
+                let mut visited = FxHashSet();
+                if let Some(items) = inline::try_inline(cx, path.def, name, &mut visited) {
                     return items;
                 }
             }
index fc05833e28503f7eeede377f3e40601cde3a40a9..d41739ab02c6ad90c19d55dbe7fe0d644a1dbb56 100644 (file)
 // with a rustc without jemalloc.
 // FIXME(#44236) shouldn't need MSVC logic
 #![cfg_attr(all(not(target_env = "msvc"),
-                any(stage0, feature = "force_alloc_system")),
+                any(all(stage0, not(test)), feature = "force_alloc_system")),
             feature(global_allocator))]
 #[cfg(all(not(target_env = "msvc"),
-          any(stage0, feature = "force_alloc_system")))]
+          any(all(stage0, not(test)), feature = "force_alloc_system")))]
 #[global_allocator]
 static ALLOC: alloc_system::System = alloc_system::System;
 
index 919d964829718f0c0653e88086137a579bb317bf..437d7d74cae0d7b3f1c52dc66398e2b3290f6b62 100644 (file)
@@ -116,6 +116,8 @@ mod prim_bool { }
 ///
 /// # `!` and generics
 ///
+/// ## Infallible errors
+///
 /// The main place you'll see `!` used explicitly is in generic code. Consider the [`FromStr`]
 /// trait:
 ///
@@ -144,9 +146,60 @@ mod prim_bool { }
 /// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain
 /// enum variants from generic types like `Result`.
 ///
+/// ## Infinite loops
+///
+/// While [`Result<T, !>`] is very useful for removing errors, `!` can also be used to remove
+/// successes as well. If we think of [`Result<T, !>`] as "if this function returns, it has not
+/// errored," we get a very intuitive idea of [`Result<!, E>`] as well: if the function returns, it
+/// *has* errored.
+///
+/// For example, consider the case of a simple web server, which can be simplified to:
+///
+/// ```ignore (hypothetical-example)
+/// loop {
+///     let (client, request) = get_request().expect("disconnected");
+///     let response = request.process();
+///     response.send(client);
+/// }
+/// ```
+///
+/// Currently, this isn't ideal, because we simply panic whenever we fail to get a new connection.
+/// Instead, we'd like to keep track of this error, like this:
+///
+/// ```ignore (hypothetical-example)
+/// loop {
+///     match get_request() {
+///         Err(err) => break err,
+///         Ok((client, request)) => {
+///             let response = request.process();
+///             response.send(client);
+///         },
+///     }
+/// }
+/// ```
+///
+/// Now, when the server disconnects, we exit the loop with an error instead of panicking. While it
+/// might be intuitive to simply return the error, we might want to wrap it in a [`Result<!, E>`]
+/// instead:
+///
+/// ```ignore (hypothetical-example)
+/// fn server_loop() -> Result<!, ConnectionError> {
+///     loop {
+///         let (client, request) = get_request()?;
+///         let response = request.process();
+///         response.send(client);
+///     }
+/// }
+/// ```
+///
+/// Now, we can use `?` instead of `match`, and the return type makes a lot more sense: if the loop
+/// ever stops, it means that an error occurred. We don't even have to wrap the loop in an `Ok`
+/// because `!` coerces to `Result<!, ConnectionError>` automatically.
+///
 /// [`String::from_str`]: str/trait.FromStr.html#tymethod.from_str
 /// [`Result<String, !>`]: result/enum.Result.html
 /// [`Result<T, !>`]: result/enum.Result.html
+/// [`Result<!, E>`]: result/enum.Result.html
 /// [`Ok`]: result/enum.Result.html#variant.Ok
 /// [`String`]: string/struct.String.html
 /// [`Err`]: result/enum.Result.html#variant.Err
index 3fc1c279f5a22ea971f55be431a2df2a0820e8b2..7341941c242a4a743092b4f125f6a4cf03fd87a9 100644 (file)
@@ -50,8 +50,8 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl Edition {
     pub fn lint_name(&self) -> &'static str {
         match *self {
-            Edition::Edition2015 => "edition_2015",
-            Edition::Edition2018 => "edition_2018",
+            Edition::Edition2015 => "rust_2015_breakage",
+            Edition::Edition2018 => "rust_2018_breakage",
         }
     }
 
index d8db76a95ff38ef1fde952f99658dd42e6d2d7b9..5155408ba63f3143372f4a1db5ea19b312dca792 100644 (file)
@@ -300,7 +300,7 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
     (active, abi_unadjusted, "1.16.0", None, None),
 
     // Procedural macros 2.0.
-    (active, proc_macro, "1.16.0", Some(38356), None),
+    (active, proc_macro, "1.16.0", Some(38356), Some(Edition::Edition2018)),
 
     // Declarative macros 2.0 (`macro`).
     (active, decl_macro, "1.17.0", Some(39412), None),
@@ -324,7 +324,7 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
 
 
     // Allows the `catch {...}` expression
-    (active, catch_expr, "1.17.0", Some(31436), None),
+    (active, catch_expr, "1.17.0", Some(31436), Some(Edition::Edition2018)),
 
     // Used to preserve symbols (see llvm.used)
     (active, used, "1.18.0", Some(40289), None),
@@ -1848,6 +1848,14 @@ fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) {
 
     let mut feature_checker = FeatureChecker::default();
 
+    for &(.., f_edition, set) in ACTIVE_FEATURES.iter() {
+        if let Some(f_edition) = f_edition {
+            if f_edition <= crate_edition {
+                set(&mut features, DUMMY_SP);
+            }
+        }
+    }
+
     for attr in krate_attrs {
         if !attr.check_name("feature") {
             continue
index f252020bc31698836dc454794a6a8588288a8327..f26a6a5307401cb8645517e69e6dda98862f0b22 100644 (file)
@@ -419,13 +419,24 @@ pub fn lit_token(lit: token::Lit, suf: Option<Symbol>, diag: Option<(Span, &Hand
         token::Integer(s) => (false, integer_lit(&s.as_str(), suf, diag)),
         token::Float(s) => (false, float_lit(&s.as_str(), suf, diag)),
 
-        token::Str_(s) => {
-            let s = Symbol::intern(&str_lit(&s.as_str(), diag));
-            (true, Some(LitKind::Str(s, ast::StrStyle::Cooked)))
+        token::Str_(mut sym) => {
+            // If there are no characters requiring special treatment we can
+            // reuse the symbol from the Token. Otherwise, we must generate a
+            // new symbol because the string in the LitKind is different to the
+            // string in the Token.
+            let s = &sym.as_str();
+            if s.as_bytes().iter().any(|&c| c == b'\\' || c == b'\r') {
+                sym = Symbol::intern(&str_lit(s, diag));
+            }
+            (true, Some(LitKind::Str(sym, ast::StrStyle::Cooked)))
         }
-        token::StrRaw(s, n) => {
-            let s = Symbol::intern(&raw_str_lit(&s.as_str()));
-            (true, Some(LitKind::Str(s, ast::StrStyle::Raw(n))))
+        token::StrRaw(mut sym, n) => {
+            // Ditto.
+            let s = &sym.as_str();
+            if s.contains('\r') {
+                sym = Symbol::intern(&raw_str_lit(s));
+            }
+            (true, Some(LitKind::Str(sym, ast::StrStyle::Raw(n))))
         }
         token::ByteStr(i) => {
             (true, Some(LitKind::ByteStr(byte_str_lit(&i.as_str()))))
index d8228e2b28be71ac39ed3dfdeb54ab0aef50805f..b8ddb063d98751fc94cead427f1527712adace3c 100644 (file)
@@ -656,7 +656,7 @@ fn print_string(&mut self, st: &str,
                     style: ast::StrStyle) -> io::Result<()> {
         let st = match style {
             ast::StrStyle::Cooked => {
-                (format!("\"{}\"", st.escape_default()))
+                (format!("\"{}\"", st.escape_debug()))
             }
             ast::StrStyle::Raw(n) => {
                 (format!("r{delim}\"{string}\"{delim}",
index 7352c494a426cf3c8468d1ee7c55861b5f45e32c..754f04a26e7ee038ed2eeaa5186841e6ae0850fd 100644 (file)
@@ -42,16 +42,13 @@ pub fn expand_assert<'cx>(
         tts: if let Some(ts) = custom_msg_args {
             ts.into()
         } else {
-            // `expr_to_string` escapes the string literals with `.escape_default()`
-            // which escapes all non-ASCII characters with `\u`.
-            let escaped_expr = escape_format_string(&unescape_printable_unicode(
-                &pprust::expr_to_string(&cond_expr),
-            ));
-
             TokenStream::from(TokenTree::Token(
                 DUMMY_SP,
                 token::Literal(
-                    token::Lit::Str_(Name::intern(&format!("assertion failed: {}", escaped_expr))),
+                    token::Lit::Str_(Name::intern(&format!(
+                        "assertion failed: {}",
+                        pprust::expr_to_string(&cond_expr).escape_debug()
+                    ))),
                     None,
                 ),
             )).into()
@@ -71,53 +68,3 @@ pub fn expand_assert<'cx>(
     );
     MacEager::expr(if_expr)
 }
-
-/// Escapes a string for use as a formatting string.
-fn escape_format_string(s: &str) -> String {
-    let mut res = String::with_capacity(s.len());
-    for c in s.chars() {
-        res.extend(c.escape_debug());
-        match c {
-            '{' | '}' => res.push(c),
-            _ => {}
-        }
-    }
-    res
-}
-
-#[test]
-fn test_escape_format_string() {
-    assert!(escape_format_string(r"foo{}\") == r"foo{{}}\\");
-}
-
-/// Unescapes the escaped unicodes (`\u{...}`) that are printable.
-fn unescape_printable_unicode(mut s: &str) -> String {
-    use std::{char, u32};
-
-    let mut res = String::with_capacity(s.len());
-
-    loop {
-        if let Some(start) = s.find(r"\u{") {
-            res.push_str(&s[0..start]);
-            s = &s[start..];
-            s.find('}')
-                .and_then(|end| {
-                    let v = u32::from_str_radix(&s[3..end], 16).ok()?;
-                    let c = char::from_u32(v)?;
-                    // Escape unprintable characters.
-                    res.extend(c.escape_debug());
-                    s = &s[end + 1..];
-                    Some(())
-                })
-                .expect("lexer should have rejected invalid escape sequences");
-        } else {
-            res.push_str(s);
-            return res;
-        }
-    }
-}
-
-#[test]
-fn test_unescape_printable_unicode() {
-    assert!(unescape_printable_unicode(r"\u{2603}\n\u{0}") == r"☃\n\u{0}");
-}
index 1ea18a5cb431e24aa838b652ac305acc5e394d6b..2f86c75a2479cf051b92fc98273daaf7f151e7a1 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 1ea18a5cb431e24aa838b652ac305acc5e394d6b
+Subproject commit 2f86c75a2479cf051b92fc98273daaf7f151e7a1
index 4db5c84df9a63d6f43d170da9fccb52170f8da00..d793a78799a70714ef6d1d832aa1c78eed34f8d6 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![deny(incoherent_fundamental_impls)]
-
 pub trait Trait1<X> {
     type Output;
 }
diff --git a/src/test/compile-fail/issue-50471.rs b/src/test/compile-fail/issue-50471.rs
new file mode 100644 (file)
index 0000000..ce29471
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+fn main() {
+    assert!({false});
+
+    assert!(r"\u{41}" == "A");
+
+    assert!(r"\u{".is_empty());
+}
index 14d5d9caa317f5ed95a9ff6f5dc6144488d89e81..fcf4714ba9695ff3c4a40a67290072ee34d57a16 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// compile-flags: --edition=2018 -Zunstable-options
+
 #![feature(extern_absolute_paths)]
 
 use xcrate::S; //~ ERROR can't find crate for `xcrate`
index defd103f9e457d55d901594a566fdd1cfb4be4ad..c256c5592c2695a1d95975db26f189cee04d9ab7 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// compile-flags: --edition=2018 -Zunstable-options
+
 #![feature(extern_absolute_paths)]
 
 fn main() {
index be1708e2b57489e333a8d68f80c517e0b74a8cb0..837dc617b3ad056cb539711b3659ddb0f6ffd3bf 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// compile-flags: --edition=2018 -Zunstable-options
+
 #![feature(extern_absolute_paths)]
 
 use ycrate; //~ ERROR can't find crate for `ycrate`
index e44465750d1ddc024999c0455e97a8c6d6a93af6..9b7baa0016344221d9de93fc676af7d0e3a727f2 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // aux-build:xcrate.rs
+// compile-flags: --edition=2018 -Zunstable-options
 
 #![feature(crate_in_paths)]
 #![feature(extern_absolute_paths)]
index 0c6c7fc5a0d75bacafd543201c0deaeddbc23694..363ab6220bd6e7fb742c4d9f98a37a013df74579 100644 (file)
@@ -8,8 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![deny(unused_results, unused_must_use)]
 #![allow(dead_code)]
+#![deny(unused_results, unused_must_use)]
+//~^ NOTE: lint level defined here
+//~| NOTE: lint level defined here
 
 #[must_use]
 enum MustUse { Test }
@@ -27,7 +29,8 @@ fn foo<T>() -> T { panic!() }
 fn test() {
     foo::<isize>();
     foo::<MustUse>(); //~ ERROR: unused `MustUse` which must be used
-    foo::<MustUseMsg>(); //~ ERROR: unused `MustUseMsg` which must be used: some message
+    foo::<MustUseMsg>(); //~ ERROR: unused `MustUseMsg` which must be used
+    //~^ NOTE: some message
 }
 
 #[allow(unused_results, unused_must_use)]
@@ -40,7 +43,8 @@ fn test2() {
 fn main() {
     foo::<isize>(); //~ ERROR: unused result
     foo::<MustUse>(); //~ ERROR: unused `MustUse` which must be used
-    foo::<MustUseMsg>(); //~ ERROR: unused `MustUseMsg` which must be used: some message
+    foo::<MustUseMsg>(); //~ ERROR: unused `MustUseMsg` which must be used
+    //~^ NOTE: some message
 
     let _ = foo::<isize>();
     let _ = foo::<MustUse>();
index ec91ddfb9f917d85e2efd26bd22b9adff36ebb1d..a0bc8cf6688bcce2c5f561c58c728ef754c93fb3 100644 (file)
@@ -6,7 +6,7 @@ OUTPUT_FILE := $(TMPDIR)/libtest-json-output.json
 
 all:
        $(RUSTC) --test f.rs
-       $(call RUN,f) -Z unstable-options --test-threads=1 --format=json > $(OUTPUT_FILE) || true
+       RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=json > $(OUTPUT_FILE) || true
 
        cat $(OUTPUT_FILE) | "$(PYTHON)" validate_json.py
 
index a132668ec7c8a43a4e85426fe98f5976e492013e..6a67b5862a815526ed7fb103d30d77333bdfcc0b 100644 (file)
@@ -1,9 +1,9 @@
 -include ../tools.mk
 
 all: extern_absolute_paths.rs extern_in_paths.rs krate2
-       $(RUSTC) extern_absolute_paths.rs -Zsave-analysis
+       $(RUSTC) extern_absolute_paths.rs -Zsave-analysis --edition=2018
        cat $(TMPDIR)/save-analysis/extern_absolute_paths.json | "$(PYTHON)" validate_json.py
-       $(RUSTC) extern_in_paths.rs -Zsave-analysis
+       $(RUSTC) extern_in_paths.rs -Zsave-analysis --edition=2018
        cat $(TMPDIR)/save-analysis/extern_in_paths.json | "$(PYTHON)" validate_json.py
 
 krate2: krate2.rs
diff --git a/src/test/run-make/cross-lang-lto/Makefile b/src/test/run-make/cross-lang-lto/Makefile
new file mode 100644 (file)
index 0000000..98b509c
--- /dev/null
@@ -0,0 +1,53 @@
+
+# min-llvm-version 4.0
+# ignore-mingw
+
+-include ../../run-make-fulldeps/tools.mk
+
+# This test makes sure that the expected .llvmbc sections for use by
+# linker-based LTO are available in object files when compiling with
+# -Z cross-lang-lto
+
+LLVMBC_SECTION_NAME=\\.llvmbc
+
+ifeq ($(UNAME),Darwin)
+       LLVMBC_SECTION_NAME=__bitcode
+endif
+
+
+OBJDUMP=llvm-objdump
+SECTION_HEADERS=$(OBJDUMP) -section-headers
+
+BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Z cross-lang-lto -Ccodegen-units=1
+
+BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Z cross-lang-lto -Ccodegen-units=1 --emit=obj
+
+all: staticlib staticlib-fat-lto staticlib-thin-lto rlib exe cdylib rdylib
+
+staticlib: lib.rs
+       $(BUILD_LIB) --crate-type=staticlib -o $(TMPDIR)/liblib.a
+       [ "$$($(SECTION_HEADERS) $(TMPDIR)/liblib.a | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ]
+
+staticlib-fat-lto: lib.rs
+       $(BUILD_LIB) --crate-type=staticlib -o $(TMPDIR)/liblib-fat-lto.a -Clto=fat
+       [ "$$($(SECTION_HEADERS) $(TMPDIR)/liblib-fat-lto.a | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ]
+
+staticlib-thin-lto: lib.rs
+       $(BUILD_LIB) --crate-type=staticlib -o $(TMPDIR)/liblib-thin-lto.a -Clto=thin
+       [ "$$($(SECTION_HEADERS) $(TMPDIR)/liblib-thin-lto.a | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ]
+
+rlib: lib.rs
+       $(BUILD_LIB) --crate-type=rlib -o $(TMPDIR)/liblib.rlib
+       [ "$$($(SECTION_HEADERS) $(TMPDIR)/liblib.rlib | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ]
+
+cdylib: lib.rs
+       $(BUILD_LIB) --crate-type=cdylib --emit=obj -o $(TMPDIR)/cdylib.o
+       [ "$$($(SECTION_HEADERS) $(TMPDIR)/cdylib.o | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ]
+
+rdylib: lib.rs
+       $(BUILD_LIB) --crate-type=dylib --emit=obj -o $(TMPDIR)/rdylib.o
+       [ "$$($(SECTION_HEADERS) $(TMPDIR)/rdylib.o | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ]
+
+exe: lib.rs
+       $(BUILD_EXE) -o $(TMPDIR)/exe.o
+       [ "$$($(SECTION_HEADERS) $(TMPDIR)/exe.o | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ]
diff --git a/src/test/run-make/cross-lang-lto/lib.rs b/src/test/run-make/cross-lang-lto/lib.rs
new file mode 100644 (file)
index 0000000..b2a5b94
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[no_mangle]
+pub extern "C" fn foo() {
+    println!("abc");
+}
diff --git a/src/test/run-make/cross-lang-lto/main.rs b/src/test/run-make/cross-lang-lto/main.rs
new file mode 100644 (file)
index 0000000..ccd34c9
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    println!("Hello World");
+}
diff --git a/src/test/run-pass/collections-const-new.rs b/src/test/run-pass/collections-const-new.rs
new file mode 100644 (file)
index 0000000..4003c2e
--- /dev/null
@@ -0,0 +1,22 @@
+// 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.
+
+// Test several functions can be used for constants
+// 1. Vec::new()
+// 2. String::new()
+
+#![feature(const_vec_new)]
+#![feature(const_string_new)]
+
+const MY_VEC: Vec<usize> = Vec::new();
+
+const MY_STRING: String = String::new();
+
+pub fn main() {}
diff --git a/src/test/run-pass/issue-43355.rs b/src/test/run-pass/issue-43355.rs
deleted file mode 100644 (file)
index 19431a6..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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 <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.
-
-// Check that the code for issue #43355 can run without an ICE, please remove
-// this test when it becomes an hard error.
-
-pub trait Trait1<X> {
-    type Output;
-}
-pub trait Trait2<X> {}
-
-impl<X, T> Trait1<X> for T where T: Trait2<X> {
-    type Output = ();
-}
-impl<X> Trait1<Box<X>> for A {
-    type Output = i32;
-}
-
-pub struct A;
-
-fn f<X, T: Trait1<Box<X>>>() {
-    println!("k: {}", ::std::mem::size_of::<<T as Trait1<Box<X>>>::Output>());
-}
-
-pub fn g<X, T: Trait2<Box<X>>>() {
-    f::<X, T>();
-}
-
-fn main() {}
index 0fa125a3e503e3d600545c39301b0cdcfb1b7e43..bbe066481a8b15d313c807e0a691b334a2fcdbf7 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // aux-build:xcrate.rs
+// compile-flags: --edition=2018 -Zunstable-options
 
 #![feature(extern_absolute_paths)]
 
index 796f652d6b57ba05aebf395e102307cbb8536842..ead462cf0d2cacc09754c6718616cbaffd30e185 100644 (file)
@@ -12,7 +12,7 @@
 //
 // Regression test for #47075.
 
-// compile-flags: --test
+// compile-flags: --test --edition=2018 -Zunstable-options
 
 #![feature(extern_absolute_paths)]
 
diff --git a/src/test/run-pass/vec-const-new.rs b/src/test/run-pass/vec-const-new.rs
deleted file mode 100644 (file)
index 62e2a36..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// 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.
-
-// Test that Vec::new() can be used for constants
-
-#![feature(const_vec_new)]
-
-const MY_VEC: Vec<usize> = Vec::new();
-
-pub fn main() {}
diff --git a/src/test/rustdoc/auxiliary/mod-stackoverflow.rs b/src/test/rustdoc/auxiliary/mod-stackoverflow.rs
new file mode 100644 (file)
index 0000000..f03593d
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Cmetadata=aux
+
+pub mod tree {
+    pub use tree;
+}
+
+pub mod tree2 {
+    pub mod prelude {
+        pub use tree2;
+    }
+}
diff --git a/src/test/rustdoc/mod-stackoverflow.rs b/src/test/rustdoc/mod-stackoverflow.rs
new file mode 100644 (file)
index 0000000..1e2f6db
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:mod-stackoverflow.rs
+// ignore-cross-compile
+
+extern crate mod_stackoverflow;
+pub use mod_stackoverflow::tree;
+pub use mod_stackoverflow::tree2;
diff --git a/src/test/ui-fulldeps/unnecessary-extern-crate.rs b/src/test/ui-fulldeps/unnecessary-extern-crate.rs
new file mode 100644 (file)
index 0000000..9d678d9
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright 2015 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.
+
+#![deny(unnecessary_extern_crate)]
+#![feature(alloc, test, libc)]
+
+extern crate alloc;
+//~^ ERROR `extern crate` is unnecessary in the new edition
+//~| HELP remove
+extern crate alloc as x;
+//~^ ERROR `extern crate` is unnecessary in the new edition
+//~| HELP use `use`
+
+#[macro_use]
+extern crate test;
+pub extern crate test as y;
+//~^ ERROR `extern crate` is unnecessary in the new edition
+//~| HELP use `pub use`
+pub extern crate libc;
+//~^ ERROR `extern crate` is unnecessary in the new edition
+//~| HELP use `pub use`
+
+
+mod foo {
+    extern crate alloc;
+    //~^ ERROR `extern crate` is unnecessary in the new edition
+    //~| HELP use `use`
+    extern crate alloc as x;
+    //~^ ERROR `extern crate` is unnecessary in the new edition
+    //~| HELP use `use`
+    pub extern crate test;
+    //~^ ERROR `extern crate` is unnecessary in the new edition
+    //~| HELP use `pub use`
+    pub extern crate test as y;
+    //~^ ERROR `extern crate` is unnecessary in the new edition
+    //~| HELP use `pub use`
+    mod bar {
+        extern crate alloc;
+        //~^ ERROR `extern crate` is unnecessary in the new edition
+        //~| HELP use `use`
+        extern crate alloc as x;
+        //~^ ERROR `extern crate` is unnecessary in the new edition
+        //~| HELP use `use`
+    }
+}
+
+
+fn main() {}
diff --git a/src/test/ui-fulldeps/unnecessary-extern-crate.stderr b/src/test/ui-fulldeps/unnecessary-extern-crate.stderr
new file mode 100644 (file)
index 0000000..7718808
--- /dev/null
@@ -0,0 +1,68 @@
+error: `extern crate` is unnecessary in the new edition
+  --> $DIR/unnecessary-extern-crate.rs:14:1
+   |
+LL | extern crate alloc;
+   | ^^^^^^^^^^^^^^^^^^^ help: remove it
+   |
+note: lint level defined here
+  --> $DIR/unnecessary-extern-crate.rs:11:9
+   |
+LL | #![deny(unnecessary_extern_crate)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `extern crate` is unnecessary in the new edition
+  --> $DIR/unnecessary-extern-crate.rs:17:1
+   |
+LL | extern crate alloc as x;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x`
+
+error: `extern crate` is unnecessary in the new edition
+  --> $DIR/unnecessary-extern-crate.rs:23:1
+   |
+LL | pub extern crate test as y;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y`
+
+error: `extern crate` is unnecessary in the new edition
+  --> $DIR/unnecessary-extern-crate.rs:26:1
+   |
+LL | pub extern crate libc;
+   | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use libc`
+
+error: `extern crate` is unnecessary in the new edition
+  --> $DIR/unnecessary-extern-crate.rs:32:5
+   |
+LL |     extern crate alloc;
+   |     ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc`
+
+error: `extern crate` is unnecessary in the new edition
+  --> $DIR/unnecessary-extern-crate.rs:35:5
+   |
+LL |     extern crate alloc as x;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x`
+
+error: `extern crate` is unnecessary in the new edition
+  --> $DIR/unnecessary-extern-crate.rs:38:5
+   |
+LL |     pub extern crate test;
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test`
+
+error: `extern crate` is unnecessary in the new edition
+  --> $DIR/unnecessary-extern-crate.rs:41:5
+   |
+LL |     pub extern crate test as y;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y`
+
+error: `extern crate` is unnecessary in the new edition
+  --> $DIR/unnecessary-extern-crate.rs:45:9
+   |
+LL |         extern crate alloc;
+   |         ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc`
+
+error: `extern crate` is unnecessary in the new edition
+  --> $DIR/unnecessary-extern-crate.rs:48:9
+   |
+LL |         extern crate alloc as x;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x`
+
+error: aborting due to 10 previous errors
+
diff --git a/src/test/ui/const-eval/extern_fat_pointer.rs b/src/test/ui/const-eval/extern_fat_pointer.rs
new file mode 100644 (file)
index 0000000..0713114
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+#![feature(extern_types)]
+
+extern {
+    type Opaque;
+}
+
+const FOO: *const u8 = &42 as *const _ as *const Opaque as *const u8;
+
+fn main() {
+    let _foo = FOO;
+}
index 5026dac0a949e3f0da97c203deb34df5ffa59257..b5bad22f3dc78b2502353b0b56a4a8671a6180b5 100644 (file)
@@ -1,4 +1,4 @@
-warning: unused return value of `need_to_use_this_value` which must be used: it's important
+warning: unused return value of `need_to_use_this_value` which must be used
   --> $DIR/fn_must_use.rs:60:5
    |
 LL |     need_to_use_this_value(); //~ WARN unused return value
@@ -9,6 +9,7 @@ note: lint level defined here
    |
 LL | #![warn(unused_must_use)]
    |         ^^^^^^^^^^^^^^^
+   = note: it's important
 
 warning: unused return value of `MyStruct::need_to_use_this_method_value` which must be used
   --> $DIR/fn_must_use.rs:65:5
@@ -16,11 +17,13 @@ warning: unused return value of `MyStruct::need_to_use_this_method_value` which
 LL |     m.need_to_use_this_method_value(); //~ WARN unused return value
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: unused return value of `EvenNature::is_even` which must be used: no side effects
+warning: unused return value of `EvenNature::is_even` which must be used
   --> $DIR/fn_must_use.rs:66:5
    |
 LL |     m.is_even(); // trait method!
    |     ^^^^^^^^^^^^
+   |
+   = note: no side effects
 
 warning: unused return value of `std::cmp::PartialEq::eq` which must be used
   --> $DIR/fn_must_use.rs:72:5
index 5d8f80e57b0724c5943fe185b71c1cae6fa8f34a..275cd91a4353c3e6e8b80f94736f7c000deae378 100644 (file)
@@ -2,16 +2,17 @@ error[E0277]: `Foo` doesn't implement `std::fmt::Debug`
   --> $DIR/no-debug.rs:20:27
    |
 LL |     println!("{:?} {:?}", Foo, Bar);
-   |                           ^^^ `Foo` cannot be formatted using `:?`; add `#[derive(Debug)]` or manually implement `std::fmt::Debug`
+   |                           ^^^ `Foo` cannot be formatted using `{:?}`
    |
    = help: the trait `std::fmt::Debug` is not implemented for `Foo`
+   = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug`
    = note: required by `std::fmt::Debug::fmt`
 
 error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Debug`
   --> $DIR/no-debug.rs:20:32
    |
 LL |     println!("{:?} {:?}", Foo, Bar);
-   |                                ^^^ `no_debug::Bar` cannot be formatted using `:?` because it doesn't implement `std::fmt::Debug`
+   |                                ^^^ `no_debug::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
    |
    = help: the trait `std::fmt::Debug` is not implemented for `no_debug::Bar`
    = note: required by `std::fmt::Debug::fmt`
@@ -20,18 +21,20 @@ error[E0277]: `Foo` doesn't implement `std::fmt::Display`
   --> $DIR/no-debug.rs:21:23
    |
 LL |     println!("{} {}", Foo, Bar);
-   |                       ^^^ `Foo` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
+   |                       ^^^ `Foo` cannot be formatted with the default formatter
    |
    = help: the trait `std::fmt::Display` is not implemented for `Foo`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
    = note: required by `std::fmt::Display::fmt`
 
 error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Display`
   --> $DIR/no-debug.rs:21:28
    |
 LL |     println!("{} {}", Foo, Bar);
-   |                            ^^^ `no_debug::Bar` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
+   |                            ^^^ `no_debug::Bar` cannot be formatted with the default formatter
    |
    = help: the trait `std::fmt::Display` is not implemented for `no_debug::Bar`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
    = note: required by `std::fmt::Display::fmt`
 
 error: aborting due to 4 previous errors
index af3f1cd29bc872b932a13083e531255aab233a7e..9e53ac6e6525da914cb05a85e5e8eff7b5dca81f 160000 (submodule)
@@ -1 +1 @@
-Subproject commit af3f1cd29bc872b932a13083e531255aab233a7e
+Subproject commit 9e53ac6e6525da914cb05a85e5e8eff7b5dca81f
index 1742229ebb7843a65c05ee495d8de5366fcc5567..e456241f18227c7eb8d78a45daa66c756a9b65e7 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 1742229ebb7843a65c05ee495d8de5366fcc5567
+Subproject commit e456241f18227c7eb8d78a45daa66c756a9b65e7
index 77554f244c8626fdbad754bb0bd9f36226ef532d..45cb147fbbc298d33990e62e3f942a67a55a130e 100644 (file)
@@ -19,5 +19,6 @@ rustfix = "0.2"
 libc = "0.2"
 
 [target.'cfg(windows)'.dependencies]
+lazy_static = "1.0"
 miow = "0.3"
 winapi = { version = "0.3", features = ["winerror"] }
index 7ac3f5b5b25e8e5115f7943c0b0f3594a7906a0d..32980a513f6f94a8946693aa2a7cdae0c3ad45af 100644 (file)
@@ -425,6 +425,15 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut FnMut(&str)) {
     if testfile.is_dir() {
         return;
     }
+
+    let comment = if testfile.to_string_lossy().ends_with(".rs") {
+        "//"
+    } else {
+        "#"
+    };
+
+    let comment_with_brace = comment.to_string() + "[";
+
     let rdr = BufReader::new(File::open(testfile).unwrap());
     for ln in rdr.lines() {
         // Assume that any directives will be found before the first
@@ -434,10 +443,11 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut FnMut(&str)) {
         let ln = ln.trim();
         if ln.starts_with("fn") || ln.starts_with("mod") {
             return;
-        } else if ln.starts_with("//[") {
+        } else if ln.starts_with(&comment_with_brace) {
             // A comment like `//[foo]` is specific to revision `foo`
             if let Some(close_brace) = ln.find(']') {
-                let lncfg = &ln[3..close_brace];
+                let open_brace = ln.find('[').unwrap();
+                let lncfg = &ln[open_brace + 1 .. close_brace];
                 let matches = match cfg {
                     Some(s) => s == &lncfg[..],
                     None => false,
@@ -446,11 +456,11 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut FnMut(&str)) {
                     it(ln[(close_brace + 1) ..].trim_left());
                 }
             } else {
-                panic!("malformed condition directive: expected `//[foo]`, found `{}`",
-                       ln)
+                panic!("malformed condition directive: expected `{}foo]`, found `{}`",
+                        comment_with_brace, ln)
             }
-        } else if ln.starts_with("//") {
-            it(ln[2..].trim_left());
+        } else if ln.starts_with(comment) {
+            it(ln[comment.len() ..].trim_left());
         }
     }
     return;
index a7849d53c3d75cd406feb26fffa4c6a3e315de2b..e8b140978b51b5a621bf38473295bc5fd67a62bb 100644 (file)
@@ -23,6 +23,9 @@
 extern crate log;
 extern crate regex;
 #[macro_use]
+#[cfg(windows)]
+extern crate lazy_static;
+#[macro_use]
 extern crate serde_derive;
 extern crate serde_json;
 extern crate test;
@@ -611,7 +614,12 @@ pub fn is_test(file_name: &OsString) -> bool {
 }
 
 pub fn make_test(config: &Config, testpaths: &TestPaths) -> test::TestDescAndFn {
-    let early_props = EarlyProps::from_file(config, &testpaths.file);
+
+    let early_props = if config.mode == Mode::RunMake {
+        EarlyProps::from_file(config, &testpaths.file.join("Makefile"))
+    } else {
+        EarlyProps::from_file(config, &testpaths.file)
+    };
 
     // The `should-fail` annotation doesn't apply to pretty tests,
     // since we run the pretty printer across all tests by default.
index fae75c352da1f7d21bd3a3060696d67bd18200fc..1bac9ef66bb81354e9b25f6e66ae05d916877ad1 100644 (file)
 
 use extract_gdb_version;
 
+#[cfg(windows)]
+fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R {
+    use std::sync::Mutex;
+    const SEM_NOGPFAULTERRORBOX: u32 = 0x0002;
+    extern "system" {
+        fn SetErrorMode(mode: u32) -> u32;
+    }
+
+    lazy_static! {
+        static ref LOCK: Mutex<()> = {
+            Mutex::new(())
+        };
+    }
+    // Error mode is a global variable, so lock it so only one thread will change it
+    let _lock = LOCK.lock().unwrap();
+
+    // Tell Windows to not show any UI on errors (such as terminating abnormally).
+    // This is important for running tests, since some of them use abnormal
+    // termination by design. This mode is inherited by all child processes.
+    unsafe {
+        let old_mode = SetErrorMode(SEM_NOGPFAULTERRORBOX); // read inherited flags
+        SetErrorMode(old_mode | SEM_NOGPFAULTERRORBOX);
+        let r = f();
+        SetErrorMode(old_mode);
+        r
+    }
+}
+
+#[cfg(not(windows))]
+fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R {
+    f()
+}
+
 /// The name of the environment variable that holds dynamic library locations.
 pub fn dylib_env_var() -> &'static str {
     if cfg!(windows) {
@@ -1578,8 +1611,7 @@ fn compose_and_run(
         let newpath = env::join_paths(&path).unwrap();
         command.env(dylib_env_var(), newpath);
 
-        let mut child = command
-            .spawn()
+        let mut child = disable_error_reporting(|| command.spawn())
             .expect(&format!("failed to exec `{:?}`", &command));
         if let Some(input) = input {
             child
index f48fed70d4447445b586a35c4ae88683542ffc72..e0e1bd7ff778e5913b566c9e03224faecc0eb486 160000 (submodule)
@@ -1 +1 @@
-Subproject commit f48fed70d4447445b586a35c4ae88683542ffc72
+Subproject commit e0e1bd7ff778e5913b566c9e03224faecc0eb486
index 8e23519f57ebca5130913b5ceda69605ff964cfa..1539c2e25781b09d2e5ddabcbe19e63be1a2087a 100755 (executable)
@@ -86,7 +86,7 @@ def update_latest(
                         .format(tool, os, old, new)
                 elif new < old:
                     changed = True
-                    message += '💔 {} on {}: {} â†’ {} (cc {}).\n' \
+                    message += '💔 {} on {}: {} â†’ {} (cc {}, @rust-lang/infra).\n' \
                         .format(tool, os, old, new, MAINTAINERS.get(tool))
 
             if changed:
index d2f44357fef6d61f316abc403e0a5d917f2771c6..d2ade31a52a417257742de72c5936a8a342a34b5 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d2f44357fef6d61f316abc403e0a5d917f2771c6
+Subproject commit d2ade31a52a417257742de72c5936a8a342a34b5
index b6cd17f28ae314f2484ff05d3ce57652d51c5e85..0f8029f251b569a010cb5cfc5a8bff8bf3c949ac 160000 (submodule)
@@ -1 +1 @@
-Subproject commit b6cd17f28ae314f2484ff05d3ce57652d51c5e85
+Subproject commit 0f8029f251b569a010cb5cfc5a8bff8bf3c949ac
index 8caf39fc27b088c25a62730577a522b60af9c284..9a87fcb00d526f4cc683cfbbf98b2bbc9446d0b7 100644 (file)
@@ -73,6 +73,7 @@
     Crate("flate2"),
     Crate("fuchsia-zircon"),
     Crate("fuchsia-zircon-sys"),
+    Crate("getopts"),
     Crate("humantime"),
     Crate("jobserver"),
     Crate("kernel32-sys"),
index fa2274366401445737932941c876e0df8b26232d..022ef57503aaabadaec4d5e7b76525c5ca32599f 100644 (file)
@@ -51,6 +51,7 @@ macro_rules! tidy_error {
 pub mod deps;
 pub mod ui_tests;
 pub mod unstable_book;
+pub mod libcoretest;
 
 fn filter_dirs(path: &Path) -> bool {
     let skip = [
diff --git a/src/tools/tidy/src/libcoretest.rs b/src/tools/tidy/src/libcoretest.rs
new file mode 100644 (file)
index 0000000..ef8b551
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Tidy check to ensure `#[test]` is not used directly inside `libcore`.
+//!
+//! `#![no_core]` libraries cannot be tested directly due to duplicating lang
+//! item. All tests must be written externally in `libcore/tests`.
+
+use std::path::Path;
+use std::fs::read_to_string;
+
+pub fn check(path: &Path, bad: &mut bool) {
+    let libcore_path = path.join("libcore");
+    super::walk(
+        &libcore_path,
+        &mut |subpath| t!(subpath.strip_prefix(&libcore_path)).starts_with("tests"),
+        &mut |subpath| {
+            if t!(read_to_string(subpath)).contains("#[test]") {
+                tidy_error!(
+                    bad,
+                    "{} contains #[test]; libcore tests must be placed inside `src/libcore/tests/`",
+                    subpath.display()
+                );
+            }
+        },
+    );
+}
index 24974192795608aa302b8df9ba4bb7d6cd32e62c..7b86650823a437a1366c2a1a4f0bfc198569790c 100644 (file)
@@ -41,6 +41,7 @@ fn main() {
     features::check(&path, &mut bad, quiet);
     pal::check(&path, &mut bad);
     unstable_book::check(&path, &mut bad);
+    libcoretest::check(&path, &mut bad);
     if !args.iter().any(|s| *s == "--no-vendor") {
         deps::check(&path, &mut bad);
     }