]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #47829 - estebank:break-in-for, r=cramertj Suggest removing value...
authorkennytm <kennytm@gmail.com>
Fri, 2 Feb 2018 08:29:16 +0000 (16:29 +0800)
committerkennytm <kennytm@gmail.com>
Fri, 2 Feb 2018 14:48:41 +0000 (22:48 +0800)
254 files changed:
.gitmodules
.travis.yml
appveyor.yml
config.toml.example
src/Cargo.lock
src/Cargo.toml
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/check.rs
src/bootstrap/compile.rs
src/bootstrap/config.rs
src/bootstrap/configure.py
src/bootstrap/dist.rs
src/bootstrap/doc.rs
src/bootstrap/lib.rs
src/bootstrap/native.rs
src/bootstrap/sanity.rs
src/bootstrap/test.rs
src/ci/docker/asmjs/Dockerfile
src/ci/docker/dist-i586-gnu-i586-i686-musl/Dockerfile
src/ci/docker/dist-i686-linux/Dockerfile
src/ci/docker/dist-various-1/Dockerfile
src/ci/docker/dist-x86_64-linux/Dockerfile
src/ci/docker/dist-x86_64-musl/Dockerfile
src/ci/docker/scripts/musl.sh
src/ci/init_repo.sh
src/doc/unstable-book/src/language-features/generators.md
src/etc/wasm32-shim.js
src/liballoc/btree/map.rs
src/libcore/cell.rs
src/libcore/fmt/mod.rs
src/libcore/fmt/num.rs
src/libcore/iter/mod.rs
src/libcore/lib.rs
src/libcore/mem.rs
src/libcore/slice/mod.rs
src/libcore/sync/atomic.rs
src/libcore/tests/iter.rs
src/libcore/time.rs [new file with mode: 0644]
src/liblibc
src/libpanic_abort/lib.rs
src/librustc/Cargo.toml
src/librustc/README.md
src/librustc/dep_graph/dep_node.rs
src/librustc/hir/lowering.rs
src/librustc/infer/error_reporting/mod.rs
src/librustc/lib.rs
src/librustc/middle/liveness.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/region.rs
src/librustc/mir/mod.rs
src/librustc/mir/tcx.rs
src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc/traits/coherence.rs
src/librustc/traits/error_reporting.rs
src/librustc/traits/select.rs
src/librustc/traits/specialize/specialization_graph.rs
src/librustc/ty/adjustment.rs
src/librustc/ty/maps/mod.rs
src/librustc/ty/maps/plumbing.rs
src/librustc/ty/mod.rs
src/librustc/ty/sty.rs
src/librustc_back/target/asmjs_unknown_emscripten.rs
src/librustc_back/target/mips_unknown_linux_musl.rs
src/librustc_back/target/mipsel_unknown_linux_musl.rs
src/librustc_back/target/mod.rs
src/librustc_back/target/msp430_none_elf.rs
src/librustc_back/target/wasm32_unknown_emscripten.rs
src/librustc_back/target/wasm32_unknown_unknown.rs
src/librustc_borrowck/borrowck/README.md
src/librustc_borrowck/borrowck/check_loans.rs
src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
src/librustc_borrowck/borrowck/mod.rs
src/librustc_borrowck/borrowck/move_data.rs
src/librustc_borrowck/borrowck/unused.rs
src/librustc_const_eval/check_match.rs
src/librustc_const_eval/pattern.rs
src/librustc_data_structures/bitvec.rs
src/librustc_driver/Cargo.toml
src/librustc_driver/lib.rs
src/librustc_driver/pretty.rs
src/librustc_errors/diagnostic.rs
src/librustc_errors/diagnostic_builder.rs
src/librustc_errors/emitter.rs
src/librustc_errors/lib.rs
src/librustc_errors/snippet.rs
src/librustc_errors/styled_buffer.rs
src/librustc_llvm/Cargo.toml
src/librustc_llvm/build.rs
src/librustc_metadata/dynamic_lib.rs
src/librustc_mir/borrow_check/flows.rs
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/nll/mod.rs
src/librustc_mir/borrow_check/nll/region_infer/mod.rs
src/librustc_mir/borrow_check/nll/type_check/liveness.rs
src/librustc_mir/borrow_check/nll/type_check/mod.rs
src/librustc_mir/build/block.rs
src/librustc_mir/build/expr/into.rs
src/librustc_mir/build/scope.rs
src/librustc_mir/dataflow/impls/borrows.rs
src/librustc_mir/dataflow/impls/mod.rs
src/librustc_mir/dataflow/mod.rs
src/librustc_mir/dataflow/move_paths/mod.rs
src/librustc_mir/interpret/place.rs
src/librustc_mir/monomorphize/partitioning.rs
src/librustc_mir/transform/elaborate_drops.rs
src/librustc_mir/transform/rustc_peek.rs
src/librustc_mir/util/elaborate_drops.rs
src/librustc_resolve/lib.rs
src/librustc_trans/Cargo.toml
src/librustc_trans/abi.rs
src/librustc_trans/allocator.rs
src/librustc_trans/asm.rs
src/librustc_trans/back/symbol_export.rs
src/librustc_trans/back/write.rs
src/librustc_trans/lib.rs
src/librustc_trans/llvm_util.rs
src/librustc_trans/mir/constant.rs
src/librustc_trans/mir/operand.rs
src/librustc_trans/type_of.rs
src/librustc_trans_utils/trans_crate.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/autoderef.rs
src/librustc_typeck/check/callee.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/method/confirm.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/op.rs
src/librustc_typeck/coherence/inherent_impls_overlap.rs
src/librustc_typeck/diagnostics.rs
src/librustdoc/core.rs
src/librustdoc/html/markdown.rs
src/librustdoc/lib.rs
src/librustdoc/test.rs
src/libstd/Cargo.toml
src/libstd/collections/hash/map.rs
src/libstd/io/error.rs
src/libstd/process.rs
src/libstd/sys/unix/process/process_common.rs
src/libstd/sys/wasm/args.rs
src/libstd/sys/wasm/mod.rs
src/libstd/sys/wasm/os.rs
src/libstd/sys/wasm/stdio.rs
src/libstd/sys/wasm/time.rs
src/libstd/time.rs [new file with mode: 0644]
src/libstd/time/duration.rs [deleted file]
src/libstd/time/mod.rs [deleted file]
src/libsyntax/codemap.rs
src/libsyntax/ext/tt/macro_parser.rs
src/libsyntax/ext/tt/quoted.rs
src/libsyntax/feature_gate.rs
src/libsyntax/json.rs
src/libsyntax/lib.rs
src/libsyntax/parse/lexer/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax/test_snippet.rs
src/libsyntax_ext/deriving/encodable.rs
src/libsyntax_ext/deriving/generic/mod.rs
src/libsyntax_pos/lib.rs
src/libtest/formatters/json.rs [new file with mode: 0644]
src/libtest/formatters/mod.rs [new file with mode: 0644]
src/libtest/formatters/pretty.rs [new file with mode: 0644]
src/libtest/formatters/terse.rs [new file with mode: 0644]
src/libtest/lib.rs
src/libtest/stats.rs
src/libunwind/build.rs
src/libunwind/lib.rs
src/libunwind/libunwind.rs
src/llvm-emscripten [new submodule]
src/rustc/Cargo.toml
src/rustllvm/PassWrapper.cpp
src/test/codegen/function-arguments.rs
src/test/compile-fail/associated-const-type-parameter-arms.rs
src/test/compile-fail/issue-20605.rs
src/test/compile-fail/regions-adjusted-lvalue-op.rs
src/test/incremental/hashes/unary_and_binary_exprs.rs
src/test/parse-fail/closure-return-syntax.rs
src/test/parse-fail/issue-24780.rs
src/test/run-make/hotplug_codegen_backend/the_backend.rs
src/test/run-make/issue-19371/foo.rs
src/test/run-make/libtest-json/Makefile [new file with mode: 0644]
src/test/run-make/libtest-json/f.rs [new file with mode: 0644]
src/test/run-make/libtest-json/output.json [new file with mode: 0644]
src/test/run-make/libtest-json/validate_json.py [new file with mode: 0755]
src/test/run-make/llvm-pass/Makefile
src/test/run-make/llvm-pass/plugin.rs
src/test/run-make/stdin-non-utf8/Makefile [new file with mode: 0644]
src/test/run-make/stdin-non-utf8/non-utf8 [new file with mode: 0644]
src/test/run-pass-fulldeps/create-dir-all-bare.rs
src/test/run-pass-fulldeps/issue-15149.rs
src/test/run-pass-fulldeps/rename-directory.rs
src/test/run-pass-fulldeps/stdio-from.rs
src/test/run-pass-fulldeps/switch-stdout.rs
src/test/run-pass/env-home-dir.rs
src/test/run-pass/issue-18514.rs
src/test/run-pass/issue-18845.rs
src/test/run-pass/issue-47139-1.rs [new file with mode: 0644]
src/test/run-pass/issue-47139-2.rs [new file with mode: 0644]
src/test/run-pass/issue-47638.rs [new file with mode: 0644]
src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs
src/test/run-pass/mir_drop_order.rs
src/test/run-pass/never-type-rvalues.rs [new file with mode: 0644]
src/test/run-pass/sse2.rs
src/test/run-pass/type-ascription.rs
src/test/run-pass/union/union-const-eval-field.rs [new file with mode: 0644]
src/test/run-pass/use-nested-groups.rs
src/test/rustdoc/link-title-escape.rs [new file with mode: 0644]
src/test/ui/blind-item-item-shadow.stderr
src/test/ui/const-fn-error.stderr
src/test/ui/cross-file-errors/main.rs [new file with mode: 0644]
src/test/ui/cross-file-errors/main.stderr [new file with mode: 0644]
src/test/ui/cross-file-errors/underscore.rs [new file with mode: 0644]
src/test/ui/double-import.stderr
src/test/ui/feature-gate-thread_local.stderr
src/test/ui/impl-trait/impl-trait-plus-priority.rs [new file with mode: 0644]
src/test/ui/impl-trait/impl-trait-plus-priority.stderr [new file with mode: 0644]
src/test/ui/imports/duplicate.stderr
src/test/ui/issue-26093.rs
src/test/ui/issue-26093.stderr
src/test/ui/issue-26886.stderr
src/test/ui/issue-33941.stderr
src/test/ui/issue-46471-1.stderr
src/test/ui/issue-46471.stderr
src/test/ui/issue-46472.stderr
src/test/ui/issue-47706-trait.rs [new file with mode: 0644]
src/test/ui/issue-47706-trait.stderr [new file with mode: 0644]
src/test/ui/lint/suggestions.rs
src/test/ui/lint/suggestions.stderr
src/test/ui/macro_backtrace/main.stderr
src/test/ui/nll/capture-ref-in-struct.stderr
src/test/ui/nll/closure-requirements/escape-argument.stderr
src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr
src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr
src/test/ui/nll/drop-no-may-dangle.stderr
src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr
src/test/ui/nll/maybe-initialized-drop-with-fragment.stderr
src/test/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr
src/test/ui/nll/maybe-initialized-drop.stderr
src/test/ui/nll/return-ref-mut-issue-46557.stderr
src/test/ui/resolve-conflict-item-vs-import.stderr
src/test/ui/suggestions/for-c-in-str.rs [new file with mode: 0644]
src/test/ui/suggestions/for-c-in-str.stderr [new file with mode: 0644]
src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr [new file with mode: 0644]
src/test/ui/suggestions/try-on-option.stderr
src/test/ui/suggestions/try-operator-on-main.stderr
src/test/ui/use-mod.stderr
src/test/ui/use-nested-groups-error.rs [new file with mode: 0644]
src/test/ui/use-nested-groups-error.stderr [new file with mode: 0644]
src/tools/cargo
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/tools/tidy/src/lib.rs

index ffa7b321ba6b6eb8e61fe0e6a17f28c4310d6652..65aafeea17bd9f737f0d6a11ef3e9fb815ccccc0 100644 (file)
@@ -51,3 +51,6 @@
 [submodule "src/doc/rust-by-example"]
        path = src/doc/rust-by-example
        url = https://github.com/rust-lang/rust-by-example
+[submodule "src/llvm-emscripten"]
+       path = src/llvm-emscripten
+       url = https://github.com/rust-lang/llvm
index 6e242b74894c5dd66715f904683287ba94338b69..1007aad925d965df1d1625d4388fa9d9de8deeb4 100644 (file)
@@ -81,7 +81,7 @@ matrix:
     # OSX 10.7 and `xcode7` is the latest Xcode able to compile LLVM for 10.7.
     - env: >
         RUST_CHECK_TARGET=dist
-        RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-extended --enable-profiler"
+        RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-extended --enable-profiler --enable-emscripten"
         SRC=.
         DEPLOY=1
         RUSTC_RETRY_LINKER_ON_SEGFAULT=1
@@ -95,7 +95,7 @@ matrix:
 
     - env: >
         RUST_CHECK_TARGET=dist
-        RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended --enable-sanitizers --enable-profiler"
+        RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended --enable-sanitizers --enable-profiler --enable-emscripten"
         SRC=.
         DEPLOY=1
         RUSTC_RETRY_LINKER_ON_SEGFAULT=1
index 1a186c080ce0d7a9aa74ae2090e1a8a46b327e95..7f1c538a32e4640a654607707b863fc8a1e2af97 100644 (file)
@@ -63,6 +63,7 @@ environment:
       --build=x86_64-pc-windows-msvc
       --enable-extended
       --enable-profiler
+      --enable-emscripten
     SCRIPT: python x.py dist
     DEPLOY: 1
   - RUST_CONFIGURE_ARGS: >
@@ -70,10 +71,11 @@ environment:
       --target=i586-pc-windows-msvc
       --enable-extended
       --enable-profiler
+      --enable-emscripten
     SCRIPT: python x.py dist
     DEPLOY: 1
   - MSYS_BITS: 32
-    RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-extended
+    RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-extended --enable-emscripten
     SCRIPT: python x.py dist
     MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
     MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
@@ -81,7 +83,7 @@ environment:
     DEPLOY: 1
   - MSYS_BITS: 64
     SCRIPT: python x.py dist
-    RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-extended
+    RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-extended --enable-emscripten
     MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
     MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z
     MINGW_DIR: mingw64
index 18c1f160c03d28eb1cc1cbea804e89551fef51cd..9ca0f563d0af1472c489b179118d3eb94c5ffa0a 100644 (file)
 # result (broken, compiling, testing) into this JSON file.
 #save-toolstates = "/path/to/toolstates.json"
 
+# This is an array of the codegen backends that will be compiled for the rustc
+# that's being compiled. The default is to only build the LLVM codegen backend,
+# but you can also optionally enable the "emscripten" backend for asm.js or
+# make this an empty array (but that probably won't get too far in the
+# bootstrap)
+#codegen-backends = ["llvm"]
+
+# Flag indicating whether `libstd` calls an imported function to hande basic IO
+# when targetting WebAssembly. Enable this to debug tests for the `wasm32-unknown-unknown`
+# target, as without this option the test output will not be captured.
+#wasm-syscall = false
+
 # =============================================================================
 # Options for specific targets
 #
index e7bf1b6b4e14ddc21f98d968d29cd00a725c1705..d26098903eec5a05931545f94a6a665c149c9290 100644 (file)
@@ -1933,7 +1933,6 @@ dependencies = [
  "rustc_privacy 0.0.0",
  "rustc_resolve 0.0.0",
  "rustc_save_analysis 0.0.0",
- "rustc_trans 0.0.0",
  "rustc_trans_utils 0.0.0",
  "rustc_typeck 0.0.0",
  "serialize 0.0.0",
@@ -1984,6 +1983,7 @@ dependencies = [
  "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "build_helper 0.1.0",
  "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_cratesio_shim 0.0.0",
 ]
 
@@ -2121,6 +2121,7 @@ dependencies = [
  "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "jobserver 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
index ad795b23cf2158983ac99ec52d7369a0d5f13247..c22ba7a37c8b07032f6b768be64101e7a2150c4d 100644 (file)
@@ -4,6 +4,7 @@ members = [
   "rustc",
   "libstd",
   "libtest",
+  "librustc_trans",
   "tools/cargotest",
   "tools/clippy",
   "tools/compiletest",
index ecf9c0a75903e514f0f06b5f322c8c4e7100759c..603a97ddfd412ad23506bc932be645bc5ac65e8b 100644 (file)
@@ -640,14 +640,23 @@ class RustBuild(object):
              os.path.join(self.rust_root, ".gitmodules"),
              "--get-regexp", "path"]
         ).decode(default_encoding).splitlines()]
-        submodules = [module for module in submodules
-                      if not ((module.endswith("llvm") and
-                               self.get_toml('llvm-config')) or
-                              (module.endswith("jemalloc") and
-                               (self.get_toml('use-jemalloc') == "false" or
-                                self.get_toml('jemalloc'))))]
+        filtered_submodules = []
+        for module in submodules:
+            if module.endswith("llvm"):
+                if self.get_toml('llvm-config'):
+                    continue
+            if module.endswith("llvm-emscripten"):
+                backends = self.get_toml('codegen-backends')
+                if backends is None or not 'emscripten' in backends:
+                    continue
+            if module.endswith("jemalloc"):
+                if self.get_toml('use-jemalloc') == 'false':
+                    continue
+                if self.get_toml('jemalloc'):
+                    continue
+            filtered_submodules.append(module)
         run(["git", "submodule", "update",
-             "--init", "--recursive"] + submodules,
+             "--init", "--recursive"] + filtered_submodules,
             cwd=self.rust_root, verbose=self.verbose)
         run(["git", "submodule", "-q", "foreach", "git",
              "reset", "-q", "--hard"],
index 79058984b13523a0dd4795aaa9ca00f6daabd9f4..780513dd943946853c7085980219fd85c5778729 100644 (file)
@@ -377,6 +377,11 @@ fn run(self, builder: &Builder) -> Interned<PathBuf> {
         self.ensure(Libdir { compiler, target })
     }
 
+    pub fn sysroot_codegen_backends(&self, compiler: Compiler) -> PathBuf {
+        self.sysroot_libdir(compiler, compiler.host)
+            .with_file_name("codegen-backends")
+    }
+
     /// Returns the compiler's libdir where it stores the dynamic libraries that
     /// it itself links against.
     ///
@@ -469,6 +474,18 @@ pub fn cargo(&self,
             stage = compiler.stage;
         }
 
+        let mut extra_args = env::var(&format!("RUSTFLAGS_STAGE_{}", stage)).unwrap_or_default();
+        if stage != 0 {
+            let s = env::var("RUSTFLAGS_STAGE_NOT_0").unwrap_or_default();
+            extra_args.push_str(" ");
+            extra_args.push_str(&s);
+        }
+
+        if !extra_args.is_empty() {
+            cargo.env("RUSTFLAGS",
+                format!("{} {}", env::var("RUSTFLAGS").unwrap_or_default(), extra_args));
+        }
+
         // 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.
index 0bc82c4f9f2c2571235083bca558478f6eeaf536..e6871764b2c78ffee2d47dcdab3e9c2c8b156dc7 100644 (file)
@@ -94,7 +94,7 @@ fn run(self, builder: &Builder) {
         build.clear_if_dirty(&stage_out, &libtest_stamp(build, compiler, target));
 
         let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check");
-        rustc_cargo(build, target, &mut cargo);
+        rustc_cargo(build, &mut cargo);
         run_cargo(build,
                   &mut cargo,
                   &librustc_stamp(build, compiler, target),
index 21bbd82dd333a725df98687ff1ad0559ae54fc7b..1d5e11c5d6d41c06f55d088a82b6be93914928e1 100644 (file)
@@ -80,7 +80,7 @@ fn run(self, builder: &Builder) {
 
             // Even if we're not building std this stage, the new sysroot must
             // still contain the musl startup objects.
-            if target.contains("musl") && !target.contains("mips") {
+            if target.contains("musl") {
                 let libdir = builder.sysroot_libdir(compiler, target);
                 copy_musl_third_party_objects(build, target, &libdir);
             }
@@ -97,7 +97,7 @@ fn run(self, builder: &Builder) {
         println!("Building stage{} std artifacts ({} -> {})", compiler.stage,
                 &compiler.host, target);
 
-        if target.contains("musl") && !target.contains("mips") {
+        if target.contains("musl") {
             let libdir = builder.sysroot_libdir(compiler, target);
             copy_musl_third_party_objects(build, target, &libdir);
         }
@@ -300,7 +300,11 @@ fn run(self, builder: &Builder) {
         }
 
         for obj in ["crt2.o", "dllcrt2.o"].iter() {
-            copy(&compiler_file(build.cc(target), obj), &sysroot_dir.join(obj));
+            let src = compiler_file(build,
+                                    build.cc(target),
+                                    target,
+                                    obj);
+            copy(&src, &sysroot_dir.join(obj));
         }
     }
 }
@@ -454,10 +458,6 @@ fn run(self, builder: &Builder) {
 
         builder.ensure(Test { compiler, target });
 
-        // Build LLVM for our target. This will implicitly build the host LLVM
-        // if necessary.
-        builder.ensure(native::Llvm { target });
-
         if build.force_use_stage1(compiler, target) {
             builder.ensure(Rustc {
                 compiler: builder.compiler(1, build.build),
@@ -487,7 +487,7 @@ fn run(self, builder: &Builder) {
         build.clear_if_dirty(&stage_out, &libtest_stamp(build, compiler, target));
 
         let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build");
-        rustc_cargo(build, target, &mut cargo);
+        rustc_cargo(build, &mut cargo);
         run_cargo(build,
                   &mut cargo,
                   &librustc_stamp(build, compiler, target),
@@ -501,14 +501,14 @@ fn run(self, builder: &Builder) {
     }
 }
 
-/// Same as `std_cargo`, but for libtest
-pub fn rustc_cargo(build: &Build,
-                   target: Interned<String>,
-                   cargo: &mut Command) {
+pub fn rustc_cargo(build: &Build, cargo: &mut Command) {
     cargo.arg("--features").arg(build.rustc_features())
          .arg("--manifest-path")
          .arg(build.src.join("src/rustc/Cargo.toml"));
+    rustc_cargo_env(build, cargo);
+}
 
+fn rustc_cargo_env(build: &Build, cargo: &mut Command) {
     // Set some configuration variables picked up by build scripts and
     // the compiler alike
     cargo.env("CFG_RELEASE", build.rust_release())
@@ -536,27 +536,6 @@ pub fn rustc_cargo(build: &Build,
     if !build.unstable_features() {
         cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1");
     }
-    // Flag that rust llvm is in use
-    if build.is_rust_llvm(target) {
-        cargo.env("LLVM_RUSTLLVM", "1");
-    }
-    cargo.env("LLVM_CONFIG", build.llvm_config(target));
-    let target_config = build.config.target_config.get(&target);
-    if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
-        cargo.env("CFG_LLVM_ROOT", s);
-    }
-    // Building with a static libstdc++ is only supported on linux right now,
-    // not for MSVC or macOS
-    if build.config.llvm_static_stdcpp &&
-       !target.contains("freebsd") &&
-       !target.contains("windows") &&
-       !target.contains("apple") {
-        cargo.env("LLVM_STATIC_STDCPP",
-                  compiler_file(build.cxx(target).unwrap(), "libstdc++.a"));
-    }
-    if build.config.llvm_link_shared {
-        cargo.env("LLVM_LINK_SHARED", "1");
-    }
     if let Some(ref s) = build.config.rustc_default_linker {
         cargo.env("CFG_DEFAULT_LINKER", s);
     }
@@ -601,6 +580,172 @@ fn run(self, builder: &Builder) {
     }
 }
 
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct CodegenBackend {
+    pub compiler: Compiler,
+    pub target: Interned<String>,
+    pub backend: Interned<String>,
+}
+
+impl Step for CodegenBackend {
+    type Output = ();
+    const ONLY_HOSTS: bool = true;
+    const DEFAULT: bool = true;
+
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/librustc_trans")
+    }
+
+    fn make_run(run: RunConfig) {
+        let backend = run.builder.config.rust_codegen_backends.get(0);
+        let backend = backend.cloned().unwrap_or_else(|| {
+            INTERNER.intern_str("llvm")
+        });
+        run.builder.ensure(CodegenBackend {
+            compiler: run.builder.compiler(run.builder.top_stage, run.host),
+            target: run.target,
+            backend
+        });
+    }
+
+    fn run(self, builder: &Builder) {
+        let build = builder.build;
+        let compiler = self.compiler;
+        let target = self.target;
+
+        builder.ensure(Rustc { compiler, target });
+
+        if build.force_use_stage1(compiler, target) {
+            builder.ensure(CodegenBackend {
+                compiler: builder.compiler(1, build.build),
+                target,
+                backend: self.backend,
+            });
+            return;
+        }
+
+        let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build");
+        let mut features = build.rustc_features().to_string();
+        cargo.arg("--manifest-path")
+            .arg(build.src.join("src/librustc_trans/Cargo.toml"));
+        rustc_cargo_env(build, &mut cargo);
+
+        match &*self.backend {
+            "llvm" | "emscripten" => {
+                // Build LLVM for our target. This will implicitly build the
+                // host LLVM if necessary.
+                let llvm_config = builder.ensure(native::Llvm {
+                    target,
+                    emscripten: self.backend == "emscripten",
+                });
+
+                if self.backend == "emscripten" {
+                    features.push_str(" emscripten");
+                }
+
+                let _folder = build.fold_output(|| format!("stage{}-rustc_trans", compiler.stage));
+                println!("Building stage{} codegen artifacts ({} -> {}, {})",
+                         compiler.stage, &compiler.host, target, self.backend);
+
+                // Pass down configuration from the LLVM build into the build of
+                // librustc_llvm and librustc_trans.
+                if build.is_rust_llvm(target) {
+                    cargo.env("LLVM_RUSTLLVM", "1");
+                }
+                cargo.env("LLVM_CONFIG", &llvm_config);
+                if self.backend != "emscripten" {
+                    let target_config = build.config.target_config.get(&target);
+                    if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
+                        cargo.env("CFG_LLVM_ROOT", s);
+                    }
+                }
+                // Building with a static libstdc++ is only supported on linux right now,
+                // not for MSVC or macOS
+                if build.config.llvm_static_stdcpp &&
+                   !target.contains("freebsd") &&
+                   !target.contains("windows") &&
+                   !target.contains("apple") {
+                    let file = compiler_file(build,
+                                             build.cxx(target).unwrap(),
+                                             target,
+                                             "libstdc++.a");
+                    cargo.env("LLVM_STATIC_STDCPP", file);
+                }
+                if build.config.llvm_link_shared {
+                    cargo.env("LLVM_LINK_SHARED", "1");
+                }
+            }
+            _ => panic!("unknown backend: {}", self.backend),
+        }
+
+        let tmp_stamp = build.cargo_out(compiler, Mode::Librustc, target)
+            .join(".tmp.stamp");
+        let files = run_cargo(build,
+                              cargo.arg("--features").arg(features),
+                              &tmp_stamp,
+                              false);
+        let mut files = files.into_iter()
+            .filter(|f| {
+                let filename = f.file_name().unwrap().to_str().unwrap();
+                is_dylib(filename) && filename.contains("rustc_trans-")
+            });
+        let codegen_backend = match files.next() {
+            Some(f) => f,
+            None => panic!("no dylibs built for codegen backend?"),
+        };
+        if let Some(f) = files.next() {
+            panic!("codegen backend built two dylibs:\n{}\n{}",
+                   codegen_backend.display(),
+                   f.display());
+        }
+        let stamp = codegen_backend_stamp(build, compiler, target, self.backend);
+        let codegen_backend = codegen_backend.to_str().unwrap();
+        t!(t!(File::create(&stamp)).write_all(codegen_backend.as_bytes()));
+    }
+}
+
+/// Creates the `codegen-backends` folder for a compiler that's about to be
+/// assembled as a complete compiler.
+///
+/// This will take the codegen artifacts produced by `compiler` and link them
+/// into an appropriate location for `target_compiler` to be a functional
+/// compiler.
+fn copy_codegen_backends_to_sysroot(builder: &Builder,
+                                    compiler: Compiler,
+                                    target_compiler: Compiler) {
+    let build = builder.build;
+    let target = target_compiler.host;
+
+    // Note that this step is different than all the other `*Link` steps in
+    // that it's not assembling a bunch of libraries but rather is primarily
+    // moving the codegen backend into place. The codegen backend of rustc is
+    // not linked into the main compiler by default but is rather dynamically
+    // selected at runtime for inclusion.
+    //
+    // Here we're looking for the output dylib of the `CodegenBackend` step and
+    // we're copying that into the `codegen-backends` folder.
+    let dst = builder.sysroot_codegen_backends(target_compiler);
+    t!(fs::create_dir_all(&dst));
+
+    for backend in builder.config.rust_codegen_backends.iter() {
+        let stamp = codegen_backend_stamp(build, compiler, target, *backend);
+        let mut dylib = String::new();
+        t!(t!(File::open(&stamp)).read_to_string(&mut dylib));
+        let file = Path::new(&dylib);
+        let filename = file.file_name().unwrap().to_str().unwrap();
+        // change `librustc_trans-xxxxxx.so` to `librustc_trans-llvm.so`
+        let target_filename = {
+            let dash = filename.find("-").unwrap();
+            let dot = filename.find(".").unwrap();
+            format!("{}-{}{}",
+                    &filename[..dash],
+                    backend,
+                    &filename[dot..])
+        };
+        copy(&file, &dst.join(target_filename));
+    }
+}
+
 /// Cargo's output path for the standard library in a given stage, compiled
 /// by a particular compiler for the specified target.
 pub fn libstd_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
@@ -619,9 +764,22 @@ pub fn librustc_stamp(build: &Build, compiler: Compiler, target: Interned<String
     build.cargo_out(compiler, Mode::Librustc, target).join(".librustc.stamp")
 }
 
-fn compiler_file(compiler: &Path, file: &str) -> PathBuf {
-    let out = output(Command::new(compiler)
-                            .arg(format!("-print-file-name={}", file)));
+fn codegen_backend_stamp(build: &Build,
+                         compiler: Compiler,
+                         target: Interned<String>,
+                         backend: Interned<String>) -> PathBuf {
+    build.cargo_out(compiler, Mode::Librustc, target)
+        .join(format!(".librustc_trans-{}.stamp", backend))
+}
+
+fn compiler_file(build: &Build,
+                 compiler: &Path,
+                 target: Interned<String>,
+                 file: &str) -> PathBuf {
+    let mut cmd = Command::new(compiler);
+    cmd.args(build.cflags(target));
+    cmd.arg(format!("-print-file-name={}", file));
+    let out = output(&mut cmd);
     PathBuf::from(out.trim())
 }
 
@@ -690,20 +848,23 @@ fn run(self, builder: &Builder) -> Compiler {
         }
 
         // Get the compiler that we'll use to bootstrap ourselves.
-        let build_compiler = if target_compiler.host != build.build {
-            // Build a compiler for the host platform. We cannot use the stage0
-            // compiler for the host platform for this because it doesn't have
-            // the libraries we need.  FIXME: Perhaps we should download those
-            // libraries? It would make builds faster...
-            // FIXME: It may be faster if we build just a stage 1
-            // compiler and then use that to bootstrap this compiler
-            // forward.
-            builder.compiler(target_compiler.stage - 1, build.build)
-        } else {
-            // Build the compiler we'll use to build the stage requested. This
-            // may build more than one compiler (going down to stage 0).
-            builder.compiler(target_compiler.stage - 1, target_compiler.host)
-        };
+        //
+        // Note that this is where the recursive nature of the bootstrap
+        // happens, as this will request the previous stage's compiler on
+        // downwards to stage 0.
+        //
+        // Also note that we're building a compiler for the host platform. We
+        // only assume that we can run `build` artifacts, which means that to
+        // produce some other architecture compiler we need to start from
+        // `build` to get there.
+        //
+        // FIXME: Perhaps we should download those libraries?
+        //        It would make builds faster...
+        //
+        // FIXME: It may be faster if we build just a stage 1 compiler and then
+        //        use that to bootstrap this compiler forward.
+        let build_compiler =
+            builder.compiler(target_compiler.stage - 1, build.build);
 
         // Build the libraries for this compiler to link to (i.e., the libraries
         // it uses at runtime). NOTE: Crates the target compiler compiles don't
@@ -721,7 +882,17 @@ fn run(self, builder: &Builder) -> Compiler {
                 builder.ensure(RustcLink { compiler, target_compiler, target });
             }
         } else {
-            builder.ensure(Rustc { compiler: build_compiler, target: target_compiler.host });
+            builder.ensure(Rustc {
+                compiler: build_compiler,
+                target: target_compiler.host,
+            });
+            for &backend in build.config.rust_codegen_backends.iter() {
+                builder.ensure(CodegenBackend {
+                    compiler: build_compiler,
+                    target: target_compiler.host,
+                    backend,
+                });
+            }
         }
 
         let stage = target_compiler.stage;
@@ -740,9 +911,12 @@ fn run(self, builder: &Builder) -> Compiler {
             }
         }
 
-        let out_dir = build.cargo_out(build_compiler, Mode::Librustc, host);
+        copy_codegen_backends_to_sysroot(builder,
+                                         build_compiler,
+                                         target_compiler);
 
         // Link the compiler binary itself into place
+        let out_dir = build.cargo_out(build_compiler, Mode::Librustc, host);
         let rustc = out_dir.join(exe("rustc", &*host));
         let bindir = sysroot.join("bin");
         t!(fs::create_dir_all(&bindir));
@@ -788,7 +962,9 @@ fn stderr_isatty() -> bool {
     }
 }
 
-pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: bool) {
+pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: bool)
+    -> Vec<PathBuf>
+{
     // Instruct Cargo to give us json messages on stdout, critically leaving
     // stderr as piped so we can get those pretty colors.
     cargo.arg("--message-format").arg("json")
@@ -932,8 +1108,8 @@ pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: boo
     let mut new_contents = Vec::new();
     let mut max = None;
     let mut max_path = None;
-    for dep in deps {
-        let mtime = mtime(&dep);
+    for dep in deps.iter() {
+        let mtime = mtime(dep);
         if Some(mtime) > max {
             max = Some(mtime);
             max_path = Some(dep.clone());
@@ -946,7 +1122,7 @@ pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: boo
     if stamp_contents == new_contents && max <= stamp_mtime {
         build.verbose(&format!("not updating {:?}; contents equal and {} <= {}",
                 stamp, max, stamp_mtime));
-        return
+        return deps
     }
     if max > stamp_mtime {
         build.verbose(&format!("updating {:?} as {:?} changed", stamp, max_path));
@@ -954,4 +1130,5 @@ pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: boo
         build.verbose(&format!("updating {:?} as deps changed", stamp));
     }
     t!(t!(File::create(stamp)).write_all(&new_contents));
+    deps
 }
index 72e75fddc1942cbbfcc3bd399d110c5f910845a6..0da04bebac51386995a44ddda9102a78f0671fb9 100644 (file)
@@ -91,6 +91,7 @@ pub struct Config {
     pub rust_optimize_tests: bool,
     pub rust_debuginfo_tests: bool,
     pub rust_dist_src: bool,
+    pub rust_codegen_backends: Vec<Interned<String>>,
 
     pub build: Interned<String>,
     pub hosts: Vec<Interned<String>>,
@@ -106,6 +107,7 @@ pub struct Config {
     pub debug_jemalloc: bool,
     pub use_jemalloc: bool,
     pub backtrace: bool, // support for RUST_BACKTRACE
+    pub wasm_syscall: bool,
 
     // misc
     pub low_priority: bool,
@@ -280,6 +282,8 @@ struct Rust {
     quiet_tests: Option<bool>,
     test_miri: Option<bool>,
     save_toolstates: Option<String>,
+    codegen_backends: Option<Vec<String>>,
+    wasm_syscall: Option<bool>,
 }
 
 /// TOML representation of how each build target is configured.
@@ -318,6 +322,7 @@ pub fn parse(args: &[String]) -> Config {
         config.ignore_git = false;
         config.rust_dist_src = true;
         config.test_miri = false;
+        config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")];
 
         config.on_fail = flags.on_fail;
         config.stage = flags.stage;
@@ -460,11 +465,18 @@ pub fn parse(args: &[String]) -> Config {
             set(&mut config.rust_dist_src, rust.dist_src);
             set(&mut config.quiet_tests, rust.quiet_tests);
             set(&mut config.test_miri, rust.test_miri);
+            set(&mut config.wasm_syscall, rust.wasm_syscall);
             config.rustc_parallel_queries = rust.experimental_parallel_queries.unwrap_or(false);
             config.rustc_default_linker = rust.default_linker.clone();
             config.musl_root = rust.musl_root.clone().map(PathBuf::from);
             config.save_toolstates = rust.save_toolstates.clone().map(PathBuf::from);
 
+            if let Some(ref backends) = rust.codegen_backends {
+                config.rust_codegen_backends = backends.iter()
+                    .map(|s| INTERNER.intern_str(s))
+                    .collect();
+            }
+
             match rust.codegen_units {
                 Some(0) => config.rust_codegen_units = Some(num_cpus::get() as u32),
                 Some(n) => config.rust_codegen_units = Some(n),
index aa9fe459e88c996abd961515514529ac19a1e7ad..bc6f666d0012f5d2aa0930fff2743d5724375abc 100755 (executable)
@@ -65,6 +65,7 @@ o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, m
 o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball")
 o("cargo-openssl-static", "build.openssl-static", "static openssl in cargo")
 o("profiler", "build.profiler", "build the profiler runtime")
+o("emscripten", None, "compile the emscripten backend as well as LLVM")
 
 # Optimization and debugging options. These may be overridden by the release
 # channel, etc.
@@ -120,6 +121,10 @@ v("musl-root-armv7", "target.armv7-unknown-linux-musleabihf.musl-root",
   "armv7-unknown-linux-musleabihf install directory")
 v("musl-root-aarch64", "target.aarch64-unknown-linux-musl.musl-root",
   "aarch64-unknown-linux-musl install directory")
+v("musl-root-mips", "target.mips-unknown-linux-musl.musl-root",
+  "mips-unknown-linux-musl install directory")
+v("musl-root-mipsel", "target.mipsel-unknown-linux-musl.musl-root",
+  "mipsel-unknown-linux-musl install directory")
 v("qemu-armhf-rootfs", "target.arm-unknown-linux-gnueabihf.qemu-rootfs",
   "rootfs in qemu testing, you probably don't want to use this")
 v("qemu-aarch64-rootfs", "target.aarch64-unknown-linux-gnu.qemu-rootfs",
@@ -317,6 +322,8 @@ for key in known_args:
         set('build.host', value.split(','))
     elif option.name == 'target':
         set('build.target', value.split(','))
+    elif option.name == 'emscripten':
+        set('rust.codegen-backends', ['llvm', 'emscripten'])
     elif option.name == 'option-checking':
         # this was handled above
         pass
index 224b31ef26872469d600fc87ff4b99cb006fb0bf..dbb7d19e43285089515cb0c0878214ccc7181b13 100644 (file)
@@ -434,6 +434,13 @@ fn prepare_image(builder: &Builder, compiler: Compiler, image: &Path) {
                 }
             }
 
+            // Copy over the codegen backends
+            let backends_src = builder.sysroot_codegen_backends(compiler);
+            let backends_rel = backends_src.strip_prefix(&src).unwrap();
+            let backends_dst = image.join(&backends_rel);
+            t!(fs::create_dir_all(&backends_dst));
+            cp_r(&backends_src, &backends_dst);
+
             // Man pages
             t!(fs::create_dir_all(image.join("share/man/man1")));
             let man_src = build.src.join("src/doc/man");
@@ -581,7 +588,9 @@ fn run(self, builder: &Builder) -> PathBuf {
         t!(fs::create_dir_all(&dst));
         let mut src = builder.sysroot_libdir(compiler, target).to_path_buf();
         src.pop(); // Remove the trailing /lib folder from the sysroot_libdir
-        cp_r(&src, &dst);
+        cp_filtered(&src, &dst, &|path| {
+            path.file_name().and_then(|s| s.to_str()) != Some("codegen-backends")
+        });
 
         let mut cmd = rust_installer(builder);
         cmd.arg("generate")
index 9bf762a3b4bfda3b41648e0d4628bc64157873bf..6a75fc5112f5c2d07043aaf0063cbc0744d3415e 100644 (file)
@@ -617,7 +617,7 @@ fn run(self, builder: &Builder) {
         t!(symlink_dir_force(&my_out, &out_dir));
 
         let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc");
-        compile::rustc_cargo(build, target, &mut cargo);
+        compile::rustc_cargo(build, &mut cargo);
 
         if build.config.compiler_docs {
             // src/rustc/Cargo.toml contains a bin crate called rustc which
index a6a5ba67723901ea32cd44de9a85449c521be26f..f2a7ce30c8ac77195ef9c0ef23487befd7a7afa1 100644 (file)
@@ -423,6 +423,9 @@ fn std_features(&self) -> String {
         if self.config.profiler {
             features.push_str(" profiler");
         }
+        if self.config.wasm_syscall {
+            features.push_str(" wasm_syscall");
+        }
         features
     }
 
@@ -432,9 +435,6 @@ fn rustc_features(&self) -> String {
         if self.config.use_jemalloc {
             features.push_str(" jemalloc");
         }
-        if self.config.llvm_enabled {
-            features.push_str(" llvm");
-        }
         features
     }
 
@@ -483,6 +483,10 @@ fn llvm_out(&self, target: Interned<String>) -> PathBuf {
         self.out.join(&*target).join("llvm")
     }
 
+    fn emscripten_llvm_out(&self, target: Interned<String>) -> PathBuf {
+        self.out.join(&*target).join("llvm-emscripten")
+    }
+
     /// Output directory for all documentation for a target
     fn doc_out(&self, target: Interned<String>) -> PathBuf {
         self.out.join(&*target).join("doc")
index ba8cf3a8e2eb597844e202e5563937646c758f80..3f30756a568ce0541a8a18497f731931dbb2f5f4 100644 (file)
@@ -22,7 +22,7 @@
 use std::ffi::OsString;
 use std::fs::{self, File};
 use std::io::{Read, Write};
-use std::path::Path;
+use std::path::{Path, PathBuf};
 use std::process::Command;
 
 use build_helper::output;
@@ -30,7 +30,7 @@
 use cc;
 
 use Build;
-use util;
+use util::{self, exe};
 use build_helper::up_to_date;
 use builder::{Builder, RunConfig, ShouldRun, Step};
 use cache::Interned;
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Llvm {
     pub target: Interned<String>,
+    pub emscripten: bool,
 }
 
 impl Step for Llvm {
-    type Output = ();
+    type Output = PathBuf; // path to llvm-config
+
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun) -> ShouldRun {
-        run.path("src/llvm")
+        run.path("src/llvm").path("src/llvm-emscripten")
     }
 
     fn make_run(run: RunConfig) {
-        run.builder.ensure(Llvm { target: run.target })
+        let emscripten = run.path.map(|p| {
+            p.ends_with("llvm-emscripten")
+        }).unwrap_or(false);
+        run.builder.ensure(Llvm {
+            target: run.target,
+            emscripten,
+        });
     }
 
     /// Compile LLVM for `target`.
-    fn run(self, builder: &Builder) {
+    fn run(self, builder: &Builder) -> PathBuf {
         let build = builder.build;
         let target = self.target;
-
-        // If we're not compiling for LLVM bail out here.
-        if !build.config.llvm_enabled {
-            return;
-        }
+        let emscripten = self.emscripten;
 
         // If we're using a custom LLVM bail out here, but we can only use a
         // custom LLVM for the build triple.
-        if let Some(config) = build.config.target_config.get(&target) {
-            if let Some(ref s) = config.llvm_config {
-                return check_llvm_version(build, s);
+        if !self.emscripten {
+            if let Some(config) = build.config.target_config.get(&target) {
+                if let Some(ref s) = config.llvm_config {
+                    check_llvm_version(build, s);
+                    return s.to_path_buf()
+                }
             }
         }
 
@@ -74,8 +81,17 @@ fn run(self, builder: &Builder) {
         let mut rebuild_trigger_contents = String::new();
         t!(t!(File::open(&rebuild_trigger)).read_to_string(&mut rebuild_trigger_contents));
 
-        let out_dir = build.llvm_out(target);
+        let (out_dir, llvm_config_ret_dir) = if emscripten {
+            let dir = build.emscripten_llvm_out(target);
+            let config_dir = dir.join("bin");
+            (dir, config_dir)
+        } else {
+            (build.llvm_out(target),
+                build.llvm_out(build.config.build).join("bin"))
+        };
         let done_stamp = out_dir.join("llvm-finished-building");
+        let build_llvm_config = llvm_config_ret_dir
+            .join(exe("llvm-config", &*build.config.build));
         if done_stamp.exists() {
             let mut done_contents = String::new();
             t!(t!(File::open(&done_stamp)).read_to_string(&mut done_contents));
@@ -83,17 +99,19 @@ fn run(self, builder: &Builder) {
             // If LLVM was already built previously and contents of the rebuild-trigger file
             // didn't change from the previous build, then no action is required.
             if done_contents == rebuild_trigger_contents {
-                return
+                return build_llvm_config
             }
         }
 
         let _folder = build.fold_output(|| "llvm");
-        println!("Building LLVM for {}", target);
+        let descriptor = if emscripten { "Emscripten " } else { "" };
+        println!("Building {}LLVM for {}", descriptor, target);
         let _time = util::timeit();
         t!(fs::create_dir_all(&out_dir));
 
         // http://llvm.org/docs/CMake.html
-        let mut cfg = cmake::Config::new(build.src.join("src/llvm"));
+        let root = if self.emscripten { "src/llvm-emscripten" } else { "src/llvm" };
+        let mut cfg = cmake::Config::new(build.src.join(root));
         if build.config.ninja {
             cfg.generator("Ninja");
         }
@@ -104,13 +122,22 @@ fn run(self, builder: &Builder) {
             (true, true) => "RelWithDebInfo",
         };
 
-        // NOTE: remember to also update `config.toml.example` when changing the defaults!
-        let llvm_targets = match build.config.llvm_targets {
-            Some(ref s) => s,
-            None => "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX;Hexagon",
+        // NOTE: remember to also update `config.toml.example` when changing the
+        // defaults!
+        let llvm_targets = if self.emscripten {
+            "JSBackend"
+        } else {
+            match build.config.llvm_targets {
+                Some(ref s) => s,
+                None => "X86;ARM;AArch64;Mips;PowerPC;SystemZ;MSP430;Sparc;NVPTX;Hexagon",
+            }
         };
 
-        let llvm_exp_targets = &build.config.llvm_experimental_targets;
+        let llvm_exp_targets = if self.emscripten {
+            ""
+        } else {
+            &build.config.llvm_experimental_targets[..]
+        };
 
         let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"};
 
@@ -160,7 +187,10 @@ fn run(self, builder: &Builder) {
 
         // http://llvm.org/docs/HowToCrossCompileLLVM.html
         if target != build.build {
-            builder.ensure(Llvm { target: build.build });
+            builder.ensure(Llvm {
+                target: build.build,
+                emscripten: false,
+            });
             // FIXME: if the llvm root for the build triple is overridden then we
             //        should use llvm-tblgen from there, also should verify that it
             //        actually exists most of the time in normal installs of LLVM.
@@ -246,6 +276,8 @@ fn run(self, builder: &Builder) {
         cfg.build();
 
         t!(t!(File::create(&done_stamp)).write_all(rebuild_trigger_contents.as_bytes()));
+
+        build_llvm_config
     }
 }
 
index a8b43ad3c3080f7e015eb0508a293f599b49ab91..5184cca653c4b156b55dded68955fff8921897f4 100644 (file)
@@ -170,7 +170,7 @@ pub fn check(build: &mut Build) {
         }
 
         // Make sure musl-root is valid
-        if target.contains("musl") && !target.contains("mips") {
+        if target.contains("musl") {
             // If this is a native target (host is also musl) and no musl-root is given,
             // fall back to the system toolchain in /usr before giving up
             if build.musl_root(*target).is_none() && build.config.build == *target {
index 5faec27943847e5a63314d807667baeaa9e80866..5fdc6e009206458a42d7939af533c284e12a0bc8 100644 (file)
@@ -900,6 +900,8 @@ fn run(self, builder: &Builder) {
             cmd.env("PROFILER_SUPPORT", "1");
         }
 
+        cmd.env("RUST_TEST_TMPDIR", build.out.join("tmp"));
+
         cmd.arg("--adb-path").arg("adb");
         cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR);
         if target.contains("android") {
@@ -1209,7 +1211,7 @@ fn run(self, builder: &Builder) {
             }
             Mode::Librustc => {
                 builder.ensure(compile::Rustc { compiler, target });
-                compile::rustc_cargo(build, target, &mut cargo);
+                compile::rustc_cargo(build, &mut cargo);
                 ("librustc", "rustc-main")
             }
             _ => panic!("can only test libraries"),
@@ -1284,6 +1286,14 @@ fn run(self, builder: &Builder) {
             cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
                       build.config.nodejs.as_ref().expect("nodejs not configured"));
         } else if target.starts_with("wasm32") {
+            // Warn about running tests without the `wasm_syscall` feature enabled.
+            // The javascript shim implements the syscall interface so that test
+            // output can be correctly reported.
+            if !build.config.wasm_syscall {
+                println!("Libstd was built without `wasm_syscall` feature enabled: \
+                          test output may not be visible.");
+            }
+
             // On the wasm32-unknown-unknown target we're using LTO which is
             // incompatible with `-C prefer-dynamic`, so disable that here
             cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
index 07849a20d00458d446b1d936d22ddfcd5059a0a3..ff0708459bc898682b8528f66e030fa70e361d0d 100644 (file)
@@ -29,6 +29,6 @@ ENV EM_CONFIG=/emsdk-portable/.emscripten
 
 ENV TARGETS=asmjs-unknown-emscripten
 
-ENV RUST_CONFIGURE_ARGS --target=$TARGETS
+ENV RUST_CONFIGURE_ARGS --target=$TARGETS --enable-emscripten
 
 ENV SCRIPT python2.7 ../x.py test --target $TARGETS
index 4c9d4b3ba78ed673be8a75cab6d5ada6ea0b1d00..035846b4f6437bc2abd2c7d068e97900e207bf27 100644 (file)
@@ -18,10 +18,10 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 
 WORKDIR /build/
 COPY scripts/musl.sh /build/
-RUN CC=gcc CFLAGS="-m32 -fPIC -Wa,-mrelax-relocations=no" \
+RUN CC=gcc CFLAGS="-m32 -Wa,-mrelax-relocations=no" \
     CXX=g++ CXXFLAGS="-m32 -Wa,-mrelax-relocations=no" \
     bash musl.sh i686 --target=i686 && \
-    CC=gcc CFLAGS="-march=pentium -m32 -fPIC -Wa,-mrelax-relocations=no" \
+    CC=gcc CFLAGS="-march=pentium -m32 -Wa,-mrelax-relocations=no" \
     CXX=g++ CXXFLAGS="-march=pentium -m32 -Wa,-mrelax-relocations=no" \
     bash musl.sh i586 --target=i586 && \
     rm -rf /build
index a5d776af19dafce1a5c48d287c209792757c0aca..0fd6af6e10d34317bf0778df3eabc48a4b432e3b 100644 (file)
@@ -85,7 +85,8 @@ ENV RUST_CONFIGURE_ARGS \
       --host=$HOSTS \
       --enable-extended \
       --enable-sanitizers \
-      --enable-profiler
+      --enable-profiler \
+      --enable-emscripten
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
 
 # This is the only builder which will create source tarballs
index 0f08bcddd388fe28c0785ed1f4d01f432d91674e..c83f101d0ac41b15792d02415a4e3093d5c27faa 100644 (file)
@@ -30,6 +30,15 @@ RUN ./build-rumprun.sh
 COPY dist-various-1/install-x86_64-redox.sh /build
 RUN ./install-x86_64-redox.sh
 
+COPY dist-various-1/install-mips-musl.sh /build
+RUN ./install-mips-musl.sh
+
+COPY dist-various-1/install-mipsel-musl.sh /build
+RUN ./install-mipsel-musl.sh
+
+# Suppress some warnings in the openwrt toolchains we downloaded
+ENV STAGING_DIR=/tmp
+
 COPY scripts/musl.sh /build
 RUN env \
     CC=arm-linux-gnueabi-gcc CFLAGS="-march=armv6 -marm" \
@@ -47,14 +56,16 @@ RUN env \
     CC=aarch64-linux-gnu-gcc \
     CXX=aarch64-linux-gnu-g++ \
     bash musl.sh aarch64 && \
+    env \
+    CC=mips-openwrt-linux-gcc \
+    CXX=mips-openwrt-linux-g++ \
+    bash musl.sh mips && \
+    env \
+    CC=mipsel-openwrt-linux-gcc \
+    CXX=mipsel-openwrt-linux-g++ \
+    bash musl.sh mipsel && \
     rm -rf /build/*
 
-COPY dist-various-1/install-mips-musl.sh /build
-RUN ./install-mips-musl.sh
-
-COPY dist-various-1/install-mipsel-musl.sh /build
-RUN ./install-mipsel-musl.sh
-
 ENV TARGETS=asmjs-unknown-emscripten
 ENV TARGETS=$TARGETS,wasm32-unknown-emscripten
 ENV TARGETS=$TARGETS,x86_64-rumprun-netbsd
@@ -77,16 +88,16 @@ ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \
     CC_armv5te_unknown_linux_gnueabi=arm-linux-gnueabi-gcc \
     CFLAGS_armv5te_unknown_linux_gnueabi="-march=armv5te -marm -mfloat-abi=soft"
 
-# Suppress some warnings in the openwrt toolchains we downloaded
-ENV STAGING_DIR=/tmp
-
 ENV RUST_CONFIGURE_ARGS \
-      --enable-extended \
       --target=$TARGETS \
       --musl-root-arm=/musl-arm \
       --musl-root-armhf=/musl-armhf \
       --musl-root-armv7=/musl-armv7 \
-      --musl-root-aarch64=/musl-aarch64
+      --musl-root-aarch64=/musl-aarch64 \
+      --musl-root-mips=/musl-mips \
+      --musl-root-mipsel=/musl-mipsel \
+      --enable-emscripten
+
 ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
 
 # sccache
index a954fd86a2440657b6dc24121f0f5c74acf7ba3e..d368a00b55bd50ce9f7e3853b34b0f93ed355562 100644 (file)
@@ -85,7 +85,8 @@ ENV RUST_CONFIGURE_ARGS \
       --host=$HOSTS \
       --enable-extended \
       --enable-sanitizers \
-      --enable-profiler
+      --enable-profiler \
+      --enable-emscripten
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
 
 # This is the only builder which will create source tarballs
index 77a55b33e41b25963c1af3ba11bc84b7d7dde672..c1061309c30f85a9b5de068dc901e52b0cce4a45 100644 (file)
@@ -21,7 +21,7 @@ WORKDIR /build/
 COPY scripts/musl.sh /build/
 # We need to mitigate rust-lang/rust#34978 when compiling musl itself as well
 RUN CC=gcc \
-    CFLAGS="-fPIC -Wa,-mrelax-relocations=no" \
+    CFLAGS="-Wa,-mrelax-relocations=no" \
     CXX=g++ \
     CXXFLAGS="-Wa,-mrelax-relocations=no" \
     bash musl.sh x86_64 && rm -rf /build
index 7a7233216a35f09568db40ed6ab5e740b1eab7fb..fb0bd06ce309924458212dcee487bb8daddbca6a 100644 (file)
@@ -30,6 +30,8 @@ exit 1
 TAG=$1
 shift
 
+export CFLAGS="-fPIC $CFLAGS"
+
 MUSL=musl-1.1.18
 
 # may have been downloaded in a previous run
@@ -49,42 +51,12 @@ hide_output make clean
 
 cd ..
 
-LLVM=39
+LLVM=60
+
 # may have been downloaded in a previous run
 if [ ! -d libunwind-release_$LLVM ]; then
   curl -L https://github.com/llvm-mirror/llvm/archive/release_$LLVM.tar.gz | tar xzf -
   curl -L https://github.com/llvm-mirror/libunwind/archive/release_$LLVM.tar.gz | tar xzf -
-  # Whoa what's this mysterious patch we're applying to libunwind! Why are we
-  # swapping the values of ESP/EBP in libunwind?!
-  #
-  # Discovered in #35599 it turns out that the vanilla build of libunwind is not
-  # suitable for unwinding i686 musl. After some investigation it ended up
-  # looking like the register values for ESP/EBP were indeed incorrect (swapped)
-  # in the source. Similar commits in libunwind (r280099 and r282589) have noticed
-  # this for other platforms, and we just need to realize it for musl linux as
-  # well.
-  #
-  # More technical info can be found at #35599
-  cd libunwind-release_$LLVM
-  patch -Np1 << EOF
-diff --git a/include/libunwind.h b/include/libunwind.h
-index c5b9633..1360eb2 100644
---- a/include/libunwind.h
-+++ b/include/libunwind.h
-@@ -151,8 +151,8 @@ enum {
-   UNW_X86_ECX = 1,
-   UNW_X86_EDX = 2,
-   UNW_X86_EBX = 3,
--  UNW_X86_EBP = 4,
--  UNW_X86_ESP = 5,
-+  UNW_X86_ESP = 4,
-+  UNW_X86_EBP = 5,
-   UNW_X86_ESI = 6,
-   UNW_X86_EDI = 7
- };
-fi
-EOF
-  cd ..
 fi
 
 mkdir libunwind-build
index 14a1906ff421dd24996e619005ff2cdfeaca90f2..8ab4276fa3b059b38f1a3aba9479c89eba4e4603 100755 (executable)
@@ -48,7 +48,12 @@ travis_time_start
 # Update the cache (a pristine copy of the rust source master)
 retry sh -c "rm -rf $cache_src_dir && mkdir -p $cache_src_dir && \
     git clone --depth 1 https://github.com/rust-lang/rust.git $cache_src_dir"
-(cd $cache_src_dir && git rm src/llvm)
+if [ -d $cache_src_dir/src/llvm ]; then
+  (cd $cache_src_dir && git rm src/llvm)
+fi
+if [ -d $cache_src_dir/src/llvm-emscripten ]; then
+  (cd $cache_src_dir && git rm src/llvm-emscripten)
+fi
 retry sh -c "cd $cache_src_dir && \
     git submodule deinit -f . && git submodule sync && git submodule update --init"
 
@@ -64,14 +69,14 @@ travis_time_start
 # http://stackoverflow.com/questions/12641469/list-submodules-in-a-git-repository
 modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)"
 for module in $modules; do
-    if [ "$module" = src/llvm ]; then
-        commit="$(git ls-tree HEAD src/llvm | awk '{print $3}')"
-        git rm src/llvm
+    if [ "$module" = src/llvm ] || [ "$module" = src/llvm-emscripten ]; then
+        commit="$(git ls-tree HEAD $module | awk '{print $3}')"
+        git rm $module
         retry sh -c "rm -f $commit.tar.gz && \
             curl -sSL -O https://github.com/rust-lang/llvm/archive/$commit.tar.gz"
         tar -C src/ -xf "$commit.tar.gz"
         rm "$commit.tar.gz"
-        mv "src/llvm-$commit" src/llvm
+        mv "src/llvm-$commit" $module
         continue
     fi
     if [ ! -e "$cache_src_dir/$module/.git" ]; then
index 7a559a7bec86662dbdd3aa06850e8ffa24e7b862..e8e2132dca254e01aae972b8f7c86c51abffd808 100644 (file)
@@ -139,11 +139,11 @@ closure-like semantics. Namely:
   types and such.
 
 * Traits like `Send` and `Sync` are automatically implemented for a `Generator`
-  depending on the captured variables of the environment. Unlike closures though
+  depending on the captured variables of the environment. Unlike closures,
   generators also depend on variables live across suspension points. This means
   that although the ambient environment may be `Send` or `Sync`, the generator
   itself may not be due to internal variables live across `yield` points being
-  not-`Send` or not-`Sync`. Note, though, that generators, like closures, do
+  not-`Send` or not-`Sync`. Note that generators, like closures, do
   not implement traits like `Copy` or `Clone` automatically.
 
 * Whenever a generator is dropped it will drop all captured environment
@@ -155,7 +155,7 @@ lifted at a future date, the design is ongoing!
 
 ### Generators as state machines
 
-In the compiler generators are currently compiled as state machines. Each
+In the compiler, generators are currently compiled as state machines. Each
 `yield` expression will correspond to a different state that stores all live
 variables over that suspension point. Resumption of a generator will dispatch on
 the current state and then execute internally until a `yield` is reached, at
index d55083e0f8e03490aa23dea88ea1acfc810fe169..69647f37eecc6a8e98334bb13eb78d6fe06234ba 100644 (file)
@@ -28,14 +28,76 @@ let m = new WebAssembly.Module(buffer);
 
 let memory = null;
 
+function viewstruct(data, fields) {
+  return new Uint32Array(memory.buffer).subarray(data/4, data/4 + fields);
+}
+
 function copystr(a, b) {
-  if (memory === null) {
-    return null
-  }
-  let view = new Uint8Array(memory.buffer).slice(a, a + b);
+  let view = new Uint8Array(memory.buffer).subarray(a, a + b);
   return String.fromCharCode.apply(null, view);
 }
 
+function syscall_write([fd, ptr, len]) {
+  let s = copystr(ptr, len);
+  switch (fd) {
+    case 1: process.stdout.write(s); break;
+    case 2: process.stderr.write(s); break;
+  }
+}
+
+function syscall_exit([code]) {
+  process.exit(code);
+}
+
+function syscall_args(params) {
+  let [ptr, len] = params;
+
+  // Calculate total required buffer size
+  let totalLen = -1;
+  for (let i = 2; i < process.argv.length; ++i) {
+    totalLen += Buffer.byteLength(process.argv[i]) + 1;
+  }
+  if (totalLen < 0) { totalLen = 0; }
+  params[2] = totalLen;
+
+  // If buffer is large enough, copy data
+  if (len >= totalLen) {
+    let view = new Uint8Array(memory.buffer);
+    for (let i = 2; i < process.argv.length; ++i) {
+      let value = process.argv[i];
+      Buffer.from(value).copy(view, ptr);
+      ptr += Buffer.byteLength(process.argv[i]) + 1;
+    }
+  }
+}
+
+function syscall_getenv(params) {
+  let [keyPtr, keyLen, valuePtr, valueLen] = params;
+
+  let key = copystr(keyPtr, keyLen);
+  let value = process.env[key];
+
+  if (value == null) {
+    params[4] = 0xFFFFFFFF;
+  } else {
+    let view = new Uint8Array(memory.buffer);
+    let totalLen = Buffer.byteLength(value);
+    params[4] = totalLen;
+    if (valueLen >= totalLen) {
+      Buffer.from(value).copy(view, valuePtr);
+    }
+  }
+}
+
+function syscall_time(params) {
+  let t = Date.now();
+  let secs = Math.floor(t / 1000);
+  let millis = t % 1000;
+  params[1] = Math.floor(secs / 0x100000000);
+  params[2] = secs % 0x100000000;
+  params[3] = Math.floor(millis * 1000000);
+}
+
 let imports = {};
 imports.env = {
   // These are generated by LLVM itself for various intrinsic calls. Hopefully
@@ -48,68 +110,25 @@ imports.env = {
   log10: Math.log10,
   log10f: Math.log10,
 
-  // These are called in src/libstd/sys/wasm/stdio.rs and are used when
-  // debugging is enabled.
-  rust_wasm_write_stdout: function(a, b) {
-    let s = copystr(a, b);
-    if (s !== null) {
-      process.stdout.write(s);
-    }
-  },
-  rust_wasm_write_stderr: function(a, b) {
-    let s = copystr(a, b);
-    if (s !== null) {
-      process.stderr.write(s);
-    }
-  },
-
-  // These are called in src/libstd/sys/wasm/args.rs and are used when
-  // debugging is enabled.
-  rust_wasm_args_count: function() {
-    if (memory === null)
-      return 0;
-    return process.argv.length - 2;
-  },
-  rust_wasm_args_arg_size: function(i) {
-    return Buffer.byteLength(process.argv[i + 2]);
-  },
-  rust_wasm_args_arg_fill: function(idx, ptr) {
-    let arg = process.argv[idx + 2];
-    let view = new Uint8Array(memory.buffer);
-    Buffer.from(arg).copy(view, ptr);
-  },
-
-  // These are called in src/libstd/sys/wasm/os.rs and are used when
-  // debugging is enabled.
-  rust_wasm_getenv_len: function(a, b) {
-    let key = copystr(a, b);
-    if (key === null) {
-      return -1;
+  rust_wasm_syscall: function(index, data) {
+    switch (index) {
+      case 1: syscall_write(viewstruct(data, 3)); return true;
+      case 2: syscall_exit(viewstruct(data, 1)); return true;
+      case 3: syscall_args(viewstruct(data, 3)); return true;
+      case 4: syscall_getenv(viewstruct(data, 5)); return true;
+      case 6: syscall_time(viewstruct(data, 4)); return true;
+      default:
+        console.log("Unsupported syscall: " + index);
+        return false;
     }
-    if (!(key in process.env)) {
-      return -1;
-    }
-    return Buffer.byteLength(process.env[key]);
-  },
-  rust_wasm_getenv_data: function(a, b, ptr) {
-    let key = copystr(a, b);
-    let value = process.env[key];
-    let view = new Uint8Array(memory.buffer);
-    Buffer.from(value).copy(view, ptr);
-  },
-};
-
-let module_imports = WebAssembly.Module.imports(m);
-
-for (var i = 0; i < module_imports.length; i++) {
-  let imp = module_imports[i];
-  if (imp.module != 'env') {
-    continue
   }
-  if (imp.name == 'memory' && imp.kind == 'memory') {
-    memory = new WebAssembly.Memory({initial: 20});
-    imports.env.memory = memory;
-  }
-}
+};
 
 let instance = new WebAssembly.Instance(m, imports);
+memory = instance.exports.memory;
+try {
+  instance.exports.main();
+} catch (e) {
+  console.error(e);
+  process.exit(101);
+}
index b114dc640fbafb1f97ba4f432b9836592e180fc8..b320bed54320a11da4581742c50f7e51e04a794d 100644 (file)
@@ -1748,6 +1748,11 @@ impl<'a, K: Ord, Q: ?Sized, V> Index<&'a Q> for BTreeMap<K, V>
 {
     type Output = V;
 
+    /// Returns a reference to the value corresponding to the supplied key.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the key is not present in the `BTreeMap`.
     #[inline]
     fn index(&self, key: &Q) -> &V {
         self.get(key).expect("no entry found for key")
index c5375d1e00cb1256c4acef8c3b7a1d1c0dddaa6b..ec0d1b704dcebbfcf7631ccacc20f8808589fede 100644 (file)
@@ -450,7 +450,7 @@ pub fn replace(&self, val: T) -> T {
     /// ```
     #[stable(feature = "move_cell", since = "1.17.0")]
     pub fn into_inner(self) -> T {
-        unsafe { self.value.into_inner() }
+        self.value.into_inner()
     }
 }
 
@@ -569,7 +569,7 @@ pub fn into_inner(self) -> T {
         // compiler statically verifies that it is not currently borrowed.
         // Therefore the following assertion is just a `debug_assert!`.
         debug_assert!(self.borrow.get() == UNUSED);
-        unsafe { self.value.into_inner() }
+        self.value.into_inner()
     }
 
     /// Replaces the wrapped value with a new one, returning the old value,
@@ -1220,11 +1220,6 @@ pub const fn new(value: T) -> UnsafeCell<T> {
 
     /// Unwraps the value.
     ///
-    /// # Safety
-    ///
-    /// This function is unsafe because this thread or another thread may currently be
-    /// inspecting the inner value.
-    ///
     /// # Examples
     ///
     /// ```
@@ -1232,11 +1227,11 @@ pub const fn new(value: T) -> UnsafeCell<T> {
     ///
     /// let uc = UnsafeCell::new(5);
     ///
-    /// let five = unsafe { uc.into_inner() };
+    /// let five = uc.into_inner();
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub unsafe fn into_inner(self) -> T {
+    pub fn into_inner(self) -> T {
         self.value
     }
 }
index 65aacb23bd76813511c1381d85f73b17b1a1a344..6c8a1c3062b00633619ba56a7c7296ce8119d19d 100644 (file)
@@ -1586,6 +1586,7 @@ fn fmt(&self, _: &mut Formatter) -> Result {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Debug for bool {
+    #[inline]
     fn fmt(&self, f: &mut Formatter) -> Result {
         Display::fmt(self, f)
     }
@@ -1748,6 +1749,7 @@ fn fmt(&self, f: &mut Formatter) -> Result {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Debug for () {
+    #[inline]
     fn fmt(&self, f: &mut Formatter) -> Result {
         f.pad("()")
     }
index ee989854a3772e29362d6dc94250bb18b94a7b73..2992e7cf8db341cf0fde7730212752b19ed70096 100644 (file)
@@ -157,6 +157,7 @@ macro_rules! debug {
     ($T:ident) => {
         #[stable(feature = "rust1", since = "1.0.0")]
         impl fmt::Debug for $T {
+            #[inline]
             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 fmt::Display::fmt(self, f)
             }
index 06c29b47bf9217db2fe131db59099d0f807e6fc8..7314fac282b664fe2e92de6ee8fd7a694e955e18 100644 (file)
 use iter_private::TrustedRandomAccess;
 use ops::Try;
 use usize;
+use intrinsics;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::iterator::Iterator;
@@ -694,6 +695,49 @@ fn size_hint(&self) -> (usize, Option<usize>) {
             (f(inner_hint.0), inner_hint.1.map(f))
         }
     }
+
+    #[inline]
+    fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
+        if self.first_take {
+            self.first_take = false;
+            let first = self.iter.next();
+            if n == 0 {
+                return first;
+            }
+            n -= 1;
+        }
+        // n and self.step are indices, we need to add 1 to get the amount of elements
+        // When calling `.nth`, we need to subtract 1 again to convert back to an index
+        // step + 1 can't overflow because `.step_by` sets `self.step` to `step - 1`
+        let mut step = self.step + 1;
+        // n + 1 could overflow
+        // thus, if n is usize::MAX, instead of adding one, we call .nth(step)
+        if n == usize::MAX {
+            self.iter.nth(step - 1);
+        } else {
+            n += 1;
+        }
+
+        // overflow handling
+        loop {
+            let mul = n.checked_mul(step);
+            if unsafe { intrinsics::likely(mul.is_some()) } {
+                return self.iter.nth(mul.unwrap() - 1);
+            }
+            let div_n = usize::MAX / n;
+            let div_step = usize::MAX / step;
+            let nth_n = div_n * n;
+            let nth_step = div_step * step;
+            let nth = if nth_n > nth_step {
+                step -= div_n;
+                nth_n
+            } else {
+                n -= div_step;
+                nth_step
+            };
+            self.iter.nth(nth - 1);
+        }
+    }
 }
 
 // StepBy can only make the iterator shorter, so the len will still fit.
index d5190b65863cb3f0178a377af311600f423eeb10..2e1f925c49a36ba1fa1ca82f1b2e5be911235cfe 100644 (file)
 pub mod str;
 pub mod hash;
 pub mod fmt;
+pub mod time;
 
 // note: does not need to be public
 mod char_private;
index 93f6a0214d77d487b67edf144bce2d8875dc167a..21a0beccbf64d604e32dcfbfd86daa9da116197c 100644 (file)
@@ -189,6 +189,7 @@ pub fn forget<T>(t: T) {
 /// Type | size_of::\<Type>()
 /// ---- | ---------------
 /// () | 0
+/// bool | 1
 /// u8 | 1
 /// u16 | 2
 /// u32 | 4
index 244bf476cafb074a112f562dbdb13087cf407b42..aacbbd5058e05c23ce194e4659be2f6b090d543d 100644 (file)
@@ -1245,7 +1245,8 @@ fn position<P>(&mut self, mut predicate: P) -> Option<usize> where
                 P: FnMut(Self::Item) -> bool,
             {
                 // The addition might panic on overflow
-                let n = self.len();
+                // Use the len of the slice to hint optimizer to remove result index bounds check.
+                let n = make_slice!(self.ptr, self.end).len();
                 self.try_fold(0, move |i, x| {
                     if predicate(x) { Err(i) }
                     else { Ok(i + 1) }
@@ -1263,7 +1264,8 @@ fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
             {
                 // No need for an overflow check here, because `ExactSizeIterator`
                 // implies that the number of elements fits into a `usize`.
-                let n = self.len();
+                // Use the len of the slice to hint optimizer to remove result index bounds check.
+                let n = make_slice!(self.ptr, self.end).len();
                 self.try_rfold(n, move |i, x| {
                     let i = i - 1;
                     if predicate(x) { Err(i) }
index 3da9e9c87dde3330ebad342c33908b3f9c0593b1..8b47143f63caa7a6718154fb60836d8228bfecfc 100644 (file)
@@ -285,7 +285,7 @@ pub fn get_mut(&mut self) -> &mut bool {
     #[inline]
     #[stable(feature = "atomic_access", since = "1.15.0")]
     pub fn into_inner(self) -> bool {
-        unsafe { self.v.into_inner() != 0 }
+        self.v.into_inner() != 0
     }
 
     /// Loads a value from the bool.
@@ -695,7 +695,7 @@ pub fn get_mut(&mut self) -> &mut *mut T {
     #[inline]
     #[stable(feature = "atomic_access", since = "1.15.0")]
     pub fn into_inner(self) -> *mut T {
-        unsafe { self.p.into_inner() }
+        self.p.into_inner()
     }
 
     /// Loads a value from the pointer.
@@ -1051,7 +1051,7 @@ pub fn get_mut(&mut self) -> &mut $int_type {
             #[inline]
             #[$stable_access]
             pub fn into_inner(self) -> $int_type {
-                unsafe { self.v.into_inner() }
+                self.v.into_inner()
             }
 
             /// Loads a value from the atomic integer.
index 8997cf9c6bff9d1e50af8d14e7efeb6582b6012a..e52e119ff59b954389dbd2ec87266f57e22c9b09 100644 (file)
@@ -161,6 +161,68 @@ fn test_iterator_step_by() {
     assert_eq!(it.next(), None);
 }
 
+#[test]
+fn test_iterator_step_by_nth() {
+    let mut it = (0..16).step_by(5);
+    assert_eq!(it.nth(0), Some(0));
+    assert_eq!(it.nth(0), Some(5));
+    assert_eq!(it.nth(0), Some(10));
+    assert_eq!(it.nth(0), Some(15));
+    assert_eq!(it.nth(0), None);
+
+    let it = (0..18).step_by(5);
+    assert_eq!(it.clone().nth(0), Some(0));
+    assert_eq!(it.clone().nth(1), Some(5));
+    assert_eq!(it.clone().nth(2), Some(10));
+    assert_eq!(it.clone().nth(3), Some(15));
+    assert_eq!(it.clone().nth(4), None);
+    assert_eq!(it.clone().nth(42), None);
+}
+
+#[test]
+fn test_iterator_step_by_nth_overflow() {
+    #[cfg(target_pointer_width = "8")]
+    type Bigger = u16;
+    #[cfg(target_pointer_width = "16")]
+    type Bigger = u32;
+    #[cfg(target_pointer_width = "32")]
+    type Bigger = u64;
+    #[cfg(target_pointer_width = "64")]
+    type Bigger = u128;
+
+    #[derive(Clone)]
+    struct Test(Bigger);
+    impl<'a> Iterator for &'a mut Test {
+        type Item = i32;
+        fn next(&mut self) -> Option<Self::Item> { Some(21) }
+        fn nth(&mut self, n: usize) -> Option<Self::Item> {
+            self.0 += n as Bigger + 1;
+            Some(42)
+        }
+    }
+
+    let mut it = Test(0);
+    let root = usize::MAX >> (::std::mem::size_of::<usize>() * 8 / 2);
+    let n = root + 20;
+    (&mut it).step_by(n).nth(n);
+    assert_eq!(it.0, n as Bigger * n as Bigger);
+
+    // large step
+    let mut it = Test(0);
+    (&mut it).step_by(usize::MAX).nth(5);
+    assert_eq!(it.0, (usize::MAX as Bigger) * 5);
+
+    // n + 1 overflows
+    let mut it = Test(0);
+    (&mut it).step_by(2).nth(usize::MAX);
+    assert_eq!(it.0, (usize::MAX as Bigger) * 2);
+
+    // n + 1 overflows
+    let mut it = Test(0);
+    (&mut it).step_by(1).nth(usize::MAX);
+    assert_eq!(it.0, (usize::MAX as Bigger) * 1);
+}
+
 #[test]
 #[should_panic]
 fn test_iterator_step_by_zero() {
diff --git a/src/libcore/time.rs b/src/libcore/time.rs
new file mode 100644 (file)
index 0000000..1a0208d
--- /dev/null
@@ -0,0 +1,603 @@
+// Copyright 2012-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.
+#![stable(feature = "duration_core", since = "1.24.0")]
+
+//! Temporal quantification.
+//!
+//! Example:
+//!
+//! ```
+//! use std::time::Duration;
+//!
+//! let five_seconds = Duration::new(5, 0);
+//! // both declarations are equivalent
+//! assert_eq!(Duration::new(5, 0), Duration::from_secs(5));
+//! ```
+
+use iter::Sum;
+use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign};
+
+const NANOS_PER_SEC: u32 = 1_000_000_000;
+const NANOS_PER_MILLI: u32 = 1_000_000;
+const NANOS_PER_MICRO: u32 = 1_000;
+const MILLIS_PER_SEC: u64 = 1_000;
+const MICROS_PER_SEC: u64 = 1_000_000;
+
+/// A `Duration` type to represent a span of time, typically used for system
+/// timeouts.
+///
+/// Each `Duration` is composed of a whole number of seconds and a fractional part
+/// represented in nanoseconds.  If the underlying system does not support
+/// nanosecond-level precision, APIs binding a system timeout will typically round up
+/// the number of nanoseconds.
+///
+/// `Duration`s implement many common traits, including [`Add`], [`Sub`], and other
+/// [`ops`] traits.
+///
+/// [`Add`]: ../../std/ops/trait.Add.html
+/// [`Sub`]: ../../std/ops/trait.Sub.html
+/// [`ops`]: ../../std/ops/index.html
+///
+/// # Examples
+///
+/// ```
+/// use std::time::Duration;
+///
+/// let five_seconds = Duration::new(5, 0);
+/// let five_seconds_and_five_nanos = five_seconds + Duration::new(0, 5);
+///
+/// assert_eq!(five_seconds_and_five_nanos.as_secs(), 5);
+/// assert_eq!(five_seconds_and_five_nanos.subsec_nanos(), 5);
+///
+/// let ten_millis = Duration::from_millis(10);
+/// ```
+#[stable(feature = "duration_core", since = "1.24.0")]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)]
+pub struct Duration {
+    secs: u64,
+    nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC
+}
+
+impl Duration {
+    /// Creates a new `Duration` from the specified number of whole seconds and
+    /// additional nanoseconds.
+    ///
+    /// If the number of nanoseconds is greater than 1 billion (the number of
+    /// nanoseconds in a second), then it will carry over into the seconds provided.
+    ///
+    /// # Panics
+    ///
+    /// This constructor will panic if the carry from the nanoseconds overflows
+    /// the seconds counter.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::time::Duration;
+    ///
+    /// let five_seconds = Duration::new(5, 0);
+    /// ```
+    #[stable(feature = "duration", since = "1.3.0")]
+    #[inline]
+    pub fn new(secs: u64, nanos: u32) -> Duration {
+        let secs = secs.checked_add((nanos / NANOS_PER_SEC) as u64)
+            .expect("overflow in Duration::new");
+        let nanos = nanos % NANOS_PER_SEC;
+        Duration { secs: secs, nanos: nanos }
+    }
+
+    /// Creates a new `Duration` from the specified number of whole seconds.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::time::Duration;
+    ///
+    /// let duration = Duration::from_secs(5);
+    ///
+    /// assert_eq!(5, duration.as_secs());
+    /// assert_eq!(0, duration.subsec_nanos());
+    /// ```
+    #[stable(feature = "duration", since = "1.3.0")]
+    #[inline]
+    pub const fn from_secs(secs: u64) -> Duration {
+        Duration { secs: secs, nanos: 0 }
+    }
+
+    /// Creates a new `Duration` from the specified number of milliseconds.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::time::Duration;
+    ///
+    /// let duration = Duration::from_millis(2569);
+    ///
+    /// assert_eq!(2, duration.as_secs());
+    /// assert_eq!(569_000_000, duration.subsec_nanos());
+    /// ```
+    #[stable(feature = "duration", since = "1.3.0")]
+    #[inline]
+    pub const fn from_millis(millis: u64) -> Duration {
+        Duration {
+            secs: millis / MILLIS_PER_SEC,
+            nanos: ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI,
+        }
+    }
+
+    /// Creates a new `Duration` from the specified number of microseconds.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(duration_from_micros)]
+    /// use std::time::Duration;
+    ///
+    /// let duration = Duration::from_micros(1_000_002);
+    ///
+    /// assert_eq!(1, duration.as_secs());
+    /// assert_eq!(2000, duration.subsec_nanos());
+    /// ```
+    #[unstable(feature = "duration_from_micros", issue = "44400")]
+    #[inline]
+    pub const fn from_micros(micros: u64) -> Duration {
+        Duration {
+            secs: micros / MICROS_PER_SEC,
+            nanos: ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO,
+        }
+    }
+
+    /// Creates a new `Duration` from the specified number of nanoseconds.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(duration_extras)]
+    /// use std::time::Duration;
+    ///
+    /// let duration = Duration::from_nanos(1_000_000_123);
+    ///
+    /// assert_eq!(1, duration.as_secs());
+    /// assert_eq!(123, duration.subsec_nanos());
+    /// ```
+    #[unstable(feature = "duration_extras", issue = "46507")]
+    #[inline]
+    pub const fn from_nanos(nanos: u64) -> Duration {
+        Duration {
+            secs: nanos / (NANOS_PER_SEC as u64),
+            nanos: (nanos % (NANOS_PER_SEC as u64)) as u32,
+        }
+    }
+
+    /// Returns the number of _whole_ seconds contained by this `Duration`.
+    ///
+    /// The returned value does not include the fractional (nanosecond) part of the
+    /// duration, which can be obtained using [`subsec_nanos`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::time::Duration;
+    ///
+    /// let duration = Duration::new(5, 730023852);
+    /// assert_eq!(duration.as_secs(), 5);
+    /// ```
+    ///
+    /// To determine the total number of seconds represented by the `Duration`,
+    /// use `as_secs` in combination with [`subsec_nanos`]:
+    ///
+    /// ```
+    /// use std::time::Duration;
+    ///
+    /// let duration = Duration::new(5, 730023852);
+    ///
+    /// assert_eq!(5.730023852,
+    ///            duration.as_secs() as f64
+    ///            + duration.subsec_nanos() as f64 * 1e-9);
+    /// ```
+    ///
+    /// [`subsec_nanos`]: #method.subsec_nanos
+    #[stable(feature = "duration", since = "1.3.0")]
+    #[inline]
+    pub fn as_secs(&self) -> u64 { self.secs }
+
+    /// Returns the fractional part of this `Duration`, in milliseconds.
+    ///
+    /// This method does **not** return the length of the duration when
+    /// represented by milliseconds. The returned number always represents a
+    /// fractional portion of a second (i.e. it is less than one thousand).
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(duration_extras)]
+    /// use std::time::Duration;
+    ///
+    /// let duration = Duration::from_millis(5432);
+    /// assert_eq!(duration.as_secs(), 5);
+    /// assert_eq!(duration.subsec_millis(), 432);
+    /// ```
+    #[unstable(feature = "duration_extras", issue = "46507")]
+    #[inline]
+    pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI }
+
+    /// Returns the fractional part of this `Duration`, in microseconds.
+    ///
+    /// This method does **not** return the length of the duration when
+    /// represented by microseconds. The returned number always represents a
+    /// fractional portion of a second (i.e. it is less than one million).
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(duration_extras, duration_from_micros)]
+    /// use std::time::Duration;
+    ///
+    /// let duration = Duration::from_micros(1_234_567);
+    /// assert_eq!(duration.as_secs(), 1);
+    /// assert_eq!(duration.subsec_micros(), 234_567);
+    /// ```
+    #[unstable(feature = "duration_extras", issue = "46507")]
+    #[inline]
+    pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO }
+
+    /// Returns the fractional part of this `Duration`, in nanoseconds.
+    ///
+    /// This method does **not** return the length of the duration when
+    /// represented by nanoseconds. The returned number always represents a
+    /// fractional portion of a second (i.e. it is less than one billion).
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::time::Duration;
+    ///
+    /// let duration = Duration::from_millis(5010);
+    /// assert_eq!(duration.as_secs(), 5);
+    /// assert_eq!(duration.subsec_nanos(), 10_000_000);
+    /// ```
+    #[stable(feature = "duration", since = "1.3.0")]
+    #[inline]
+    pub fn subsec_nanos(&self) -> u32 { self.nanos }
+
+    /// Checked `Duration` addition. Computes `self + other`, returning [`None`]
+    /// if overflow occurred.
+    ///
+    /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::time::Duration;
+    ///
+    /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1)));
+    /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None);
+    /// ```
+    #[stable(feature = "duration_checked_ops", since = "1.16.0")]
+    #[inline]
+    pub fn checked_add(self, rhs: Duration) -> Option<Duration> {
+        if let Some(mut secs) = self.secs.checked_add(rhs.secs) {
+            let mut nanos = self.nanos + rhs.nanos;
+            if nanos >= NANOS_PER_SEC {
+                nanos -= NANOS_PER_SEC;
+                if let Some(new_secs) = secs.checked_add(1) {
+                    secs = new_secs;
+                } else {
+                    return None;
+                }
+            }
+            debug_assert!(nanos < NANOS_PER_SEC);
+            Some(Duration {
+                secs,
+                nanos,
+            })
+        } else {
+            None
+        }
+    }
+
+    /// Checked `Duration` subtraction. Computes `self - other`, returning [`None`]
+    /// if the result would be negative or if overflow occurred.
+    ///
+    /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::time::Duration;
+    ///
+    /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1)));
+    /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None);
+    /// ```
+    #[stable(feature = "duration_checked_ops", since = "1.16.0")]
+    #[inline]
+    pub fn checked_sub(self, rhs: Duration) -> Option<Duration> {
+        if let Some(mut secs) = self.secs.checked_sub(rhs.secs) {
+            let nanos = if self.nanos >= rhs.nanos {
+                self.nanos - rhs.nanos
+            } else {
+                if let Some(sub_secs) = secs.checked_sub(1) {
+                    secs = sub_secs;
+                    self.nanos + NANOS_PER_SEC - rhs.nanos
+                } else {
+                    return None;
+                }
+            };
+            debug_assert!(nanos < NANOS_PER_SEC);
+            Some(Duration { secs: secs, nanos: nanos })
+        } else {
+            None
+        }
+    }
+
+    /// Checked `Duration` multiplication. Computes `self * other`, returning
+    /// [`None`] if overflow occurred.
+    ///
+    /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::time::Duration;
+    ///
+    /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2)));
+    /// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None);
+    /// ```
+    #[stable(feature = "duration_checked_ops", since = "1.16.0")]
+    #[inline]
+    pub fn checked_mul(self, rhs: u32) -> Option<Duration> {
+        // Multiply nanoseconds as u64, because it cannot overflow that way.
+        let total_nanos = self.nanos as u64 * rhs as u64;
+        let extra_secs = total_nanos / (NANOS_PER_SEC as u64);
+        let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32;
+        if let Some(secs) = self.secs
+            .checked_mul(rhs as u64)
+            .and_then(|s| s.checked_add(extra_secs)) {
+            debug_assert!(nanos < NANOS_PER_SEC);
+            Some(Duration {
+                secs,
+                nanos,
+            })
+        } else {
+            None
+        }
+    }
+
+    /// Checked `Duration` division. Computes `self / other`, returning [`None`]
+    /// if `other == 0`.
+    ///
+    /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::time::Duration;
+    ///
+    /// 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);
+    /// ```
+    #[stable(feature = "duration_checked_ops", since = "1.16.0")]
+    #[inline]
+    pub fn checked_div(self, rhs: u32) -> Option<Duration> {
+        if rhs != 0 {
+            let secs = self.secs / (rhs as u64);
+            let carry = self.secs - secs * (rhs as u64);
+            let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64);
+            let nanos = self.nanos / rhs + (extra_nanos as u32);
+            debug_assert!(nanos < NANOS_PER_SEC);
+            Some(Duration { secs: secs, nanos: nanos })
+        } else {
+            None
+        }
+    }
+}
+
+#[stable(feature = "duration", since = "1.3.0")]
+impl Add for Duration {
+    type Output = Duration;
+
+    fn add(self, rhs: Duration) -> Duration {
+        self.checked_add(rhs).expect("overflow when adding durations")
+    }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl AddAssign for Duration {
+    fn add_assign(&mut self, rhs: Duration) {
+        *self = *self + rhs;
+    }
+}
+
+#[stable(feature = "duration", since = "1.3.0")]
+impl Sub for Duration {
+    type Output = Duration;
+
+    fn sub(self, rhs: Duration) -> Duration {
+        self.checked_sub(rhs).expect("overflow when subtracting durations")
+    }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl SubAssign for Duration {
+    fn sub_assign(&mut self, rhs: Duration) {
+        *self = *self - rhs;
+    }
+}
+
+#[stable(feature = "duration", since = "1.3.0")]
+impl Mul<u32> for Duration {
+    type Output = Duration;
+
+    fn mul(self, rhs: u32) -> Duration {
+        self.checked_mul(rhs).expect("overflow when multiplying duration by scalar")
+    }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl MulAssign<u32> for Duration {
+    fn mul_assign(&mut self, rhs: u32) {
+        *self = *self * rhs;
+    }
+}
+
+#[stable(feature = "duration", since = "1.3.0")]
+impl Div<u32> for Duration {
+    type Output = Duration;
+
+    fn div(self, rhs: u32) -> Duration {
+        self.checked_div(rhs).expect("divide by zero error when dividing duration by scalar")
+    }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl DivAssign<u32> for Duration {
+    fn div_assign(&mut self, rhs: u32) {
+        *self = *self / rhs;
+    }
+}
+
+#[stable(feature = "duration_sum", since = "1.16.0")]
+impl Sum for Duration {
+    fn sum<I: Iterator<Item=Duration>>(iter: I) -> Duration {
+        iter.fold(Duration::new(0, 0), |a, b| a + b)
+    }
+}
+
+#[stable(feature = "duration_sum", since = "1.16.0")]
+impl<'a> Sum<&'a Duration> for Duration {
+    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 2b4cd1016bdba92becb4f982a4dcb18fe6653bc4..56444a4545bd71430d64b86b8a71714cfdbe9f5d 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 2b4cd1016bdba92becb4f982a4dcb18fe6653bc4
+Subproject commit 56444a4545bd71430d64b86b8a71714cfdbe9f5d
index c3bd6a2bc187d38cdd176fa19c4df2f369f9c2be..5f768ef4399e88fc12771aab5a6f892c263a66be 100644 (file)
 #![feature(libc)]
 #![feature(panic_runtime)]
 #![feature(staged_api)]
+#![feature(rustc_attrs)]
 
 // Rust's "try" function, but if we're aborting on panics we just call the
 // function as there's nothing else we need to do here.
 #[no_mangle]
+#[rustc_std_internal_symbol]
 pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8),
                                               data: *mut u8,
                                               _data_ptr: *mut usize,
@@ -50,6 +52,7 @@
 // will kill us with an illegal instruction, which will do a good enough job for
 // now hopefully.
 #[no_mangle]
+#[rustc_std_internal_symbol]
 pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 {
     abort();
 
index f95dbcf411cba5eee54b9437a0e3e14e821ff348..2c4898cb2c006dc61f1dfbe69d9910c6d94bd319 100644 (file)
@@ -14,7 +14,7 @@ bitflags = "1.0"
 fmt_macros = { path = "../libfmt_macros" }
 graphviz = { path = "../libgraphviz" }
 jobserver = "0.1"
-log = "0.4"
+log = { version = "0.4", features = ["release_max_level_info", "std"] }
 rustc_apfloat = { path = "../librustc_apfloat" }
 rustc_back = { path = "../librustc_back" }
 rustc_const_math = { path = "../librustc_const_math" }
@@ -26,7 +26,6 @@ syntax_pos = { path = "../libsyntax_pos" }
 backtrace = "0.3.3"
 byteorder = { version = "1.1", features = ["i128"]}
 
-
 # Note that these dependencies are a lie, they're just here to get linkage to
 # work.
 #
index ddf71a06d607c7f7016546b0cc6fdb7da8ee3bef..722456a76ce591a6377853ad958b04e353ee0586 100644 (file)
@@ -176,6 +176,7 @@ pointers for understanding them better.
 - `'gcx` -- the lifetime of the global arena (see `librustc/ty`).
 - generics -- the set of generic type parameters defined on a type or item
 - ICE -- internal compiler error. When the compiler crashes.
+- ICH -- incremental compilation hash.
 - infcx -- the inference context (see `librustc/infer`)
 - MIR -- the **Mid-level IR** that is created after type-checking for use by borrowck and trans.
   Defined in the `src/librustc/mir/` module, but much of the code that manipulates it is
index 1de9091b5df7d34f059aa9418186f7bf1d4ea24f..4034055d041558f2360e5227c9fdbe3a32451aa1 100644 (file)
@@ -639,6 +639,9 @@ pub fn fingerprint_needed_for_crate_hash(self) -> bool {
     [] TargetFeaturesEnabled(DefId),
 
     [] InstanceDefSizeEstimate { instance_def: InstanceDef<'tcx> },
+
+    [] GetSymbolExportLevel(DefId),
+
 );
 
 trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
index f2f420c91dd1a1455375f7f9f5afbca70784de2c..55dcb16c3c95fdbdb939dd62b601f9e6727cab23 100644 (file)
@@ -3033,7 +3033,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
 
                 // `match <sub_expr> { ... }`
                 let arms = hir_vec![pat_arm, break_arm];
-                let match_expr = self.expr(e.span,
+                let match_expr = self.expr(sub_expr.span,
                                            hir::ExprMatch(sub_expr,
                                                           arms,
                                                           hir::MatchSource::WhileLetDesugar),
@@ -3071,24 +3071,25 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
 
                 // expand <head>
                 let head = self.lower_expr(head);
+                let head_sp = head.span;
 
                 let iter = self.str_to_ident("iter");
 
                 let next_ident = self.str_to_ident("__next");
-                let next_pat = self.pat_ident_binding_mode(e.span,
+                let next_pat = self.pat_ident_binding_mode(pat.span,
                                                            next_ident,
                                                            hir::BindingAnnotation::Mutable);
 
                 // `::std::option::Option::Some(val) => next = val`
                 let pat_arm = {
                     let val_ident = self.str_to_ident("val");
-                    let val_pat = self.pat_ident(e.span, val_ident);
-                    let val_expr = P(self.expr_ident(e.span, val_ident, val_pat.id));
-                    let next_expr = P(self.expr_ident(e.span, next_ident, next_pat.id));
-                    let assign = P(self.expr(e.span,
+                    let val_pat = self.pat_ident(pat.span, val_ident);
+                    let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat.id));
+                    let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat.id));
+                    let assign = P(self.expr(pat.span,
                                              hir::ExprAssign(next_expr, val_expr),
                                              ThinVec::new()));
-                    let some_pat = self.pat_some(e.span, val_pat);
+                    let some_pat = self.pat_some(pat.span, val_pat);
                     self.arm(hir_vec![some_pat], assign)
                 };
 
@@ -3101,46 +3102,45 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                 };
 
                 // `mut iter`
-                let iter_pat = self.pat_ident_binding_mode(e.span,
+                let iter_pat = self.pat_ident_binding_mode(head_sp,
                                                            iter,
                                                            hir::BindingAnnotation::Mutable);
 
                 // `match ::std::iter::Iterator::next(&mut iter) { ... }`
                 let match_expr = {
-                    let iter = P(self.expr_ident(e.span, iter, iter_pat.id));
-                    let ref_mut_iter = self.expr_mut_addr_of(e.span, iter);
+                    let iter = P(self.expr_ident(head_sp, iter, iter_pat.id));
+                    let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
                     let next_path = &["iter", "Iterator", "next"];
-                    let next_path = P(self.expr_std_path(e.span, next_path, ThinVec::new()));
-                    let next_expr = P(self.expr_call(e.span, next_path,
+                    let next_path = P(self.expr_std_path(head_sp, next_path, ThinVec::new()));
+                    let next_expr = P(self.expr_call(head_sp, next_path,
                                       hir_vec![ref_mut_iter]));
                     let arms = hir_vec![pat_arm, break_arm];
 
-                    P(self.expr(e.span,
+                    P(self.expr(head_sp,
                                 hir::ExprMatch(next_expr, arms,
                                                hir::MatchSource::ForLoopDesugar),
                                 ThinVec::new()))
                 };
-                let match_stmt = respan(e.span, hir::StmtExpr(match_expr, self.next_id().node_id));
+                let match_stmt = respan(head_sp, hir::StmtExpr(match_expr, self.next_id().node_id));
 
-                let next_expr = P(self.expr_ident(e.span, next_ident, next_pat.id));
+                let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat.id));
 
                 // `let mut __next`
-                let next_let = self.stmt_let_pat(e.span,
+                let next_let = self.stmt_let_pat(head_sp,
                     None,
                     next_pat,
                     hir::LocalSource::ForLoopDesugar);
 
                 // `let <pat> = __next`
                 let pat = self.lower_pat(pat);
-                let pat_let = self.stmt_let_pat(e.span,
+                let pat_let = self.stmt_let_pat(head_sp,
                     Some(next_expr),
                     pat,
                     hir::LocalSource::ForLoopDesugar);
 
-                let body_block = self.with_loop_scope(e.id,
-                                                        |this| this.lower_block(body, false));
+                let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
                 let body_expr = P(self.expr_block(body_block, ThinVec::new()));
-                let body_stmt = respan(e.span, hir::StmtExpr(body_expr, self.next_id().node_id));
+                let body_stmt = respan(body.span, hir::StmtExpr(body_expr, self.next_id().node_id));
 
                 let loop_block = P(self.block_all(e.span,
                                                   hir_vec![next_let,
@@ -3167,12 +3167,12 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                 // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
                 let into_iter_expr = {
                     let into_iter_path = &["iter", "IntoIterator", "into_iter"];
-                    let into_iter = P(self.expr_std_path(e.span, into_iter_path,
+                    let into_iter = P(self.expr_std_path(head_sp, into_iter_path,
                                                          ThinVec::new()));
-                    P(self.expr_call(e.span, into_iter, hir_vec![head]))
+                    P(self.expr_call(head_sp, into_iter, hir_vec![head]))
                 };
 
-                let match_expr = P(self.expr_match(e.span,
+                let match_expr = P(self.expr_match(head_sp,
                                                    into_iter_expr,
                                                    hir_vec![iter_arm],
                                                    hir::MatchSource::ForLoopDesugar));
index 541c1356dd4abbd73ae604adf5c2a22c499b8786..b10e742595720dc595863c124d1404ce9d74f8b8 100644 (file)
@@ -958,7 +958,8 @@ pub fn report_generic_bound_failure(&self,
                             // `sp` only covers `T`, change it so that it covers
                             // `T:` when appropriate
                             let sp = if has_lifetimes {
-                                sp.to(sp.next_point().next_point())
+                                sp.to(self.tcx.sess.codemap().next_point(
+                                        self.tcx.sess.codemap().next_point(sp)))
                             } else {
                                 sp
                             };
index d727dfb0c4b2deef220d33c0f16cefa057ad8e37..db6863d6dadc272a0d01fc86296d6c92d4ec38ea 100644 (file)
@@ -66,6 +66,7 @@
 #![feature(specialization)]
 #![feature(unboxed_closures)]
 #![feature(underscore_lifetimes)]
+#![feature(universal_impl_trait)]
 #![feature(trace_macros)]
 #![feature(catch_expr)]
 #![feature(test)]
index d4fa03b508566aa489f2ed059ca2bf6b883233eb..297586f140e346e91391f075d68a2d56adf11224 100644 (file)
@@ -1034,10 +1034,10 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
           }
 
           hir::ExprAssign(ref l, ref r) => {
-            // see comment on lvalues in
-            // propagate_through_lvalue_components()
-            let succ = self.write_lvalue(&l, succ, ACC_WRITE);
-            let succ = self.propagate_through_lvalue_components(&l, succ);
+            // see comment on places in
+            // propagate_through_place_components()
+            let succ = self.write_place(&l, succ, ACC_WRITE);
+            let succ = self.propagate_through_place_components(&l, succ);
             self.propagate_through_expr(&r, succ)
           }
 
@@ -1047,11 +1047,11 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
                 let succ = self.propagate_through_expr(&l, succ);
                 self.propagate_through_expr(&r, succ)
             } else {
-                // see comment on lvalues in
-                // propagate_through_lvalue_components()
-                let succ = self.write_lvalue(&l, succ, ACC_WRITE|ACC_READ);
+                // see comment on places in
+                // propagate_through_place_components()
+                let succ = self.write_place(&l, succ, ACC_WRITE|ACC_READ);
                 let succ = self.propagate_through_expr(&r, succ);
-                self.propagate_through_lvalue_components(&l, succ)
+                self.propagate_through_place_components(&l, succ)
             }
           }
 
@@ -1121,14 +1121,14 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
 
           hir::ExprInlineAsm(ref ia, ref outputs, ref inputs) => {
             let succ = ia.outputs.iter().zip(outputs).rev().fold(succ, |succ, (o, output)| {
-                // see comment on lvalues
-                // in propagate_through_lvalue_components()
+                // see comment on places
+                // in propagate_through_place_components()
                 if o.is_indirect {
                     self.propagate_through_expr(output, succ)
                 } else {
                     let acc = if o.is_rw { ACC_WRITE|ACC_READ } else { ACC_WRITE };
-                    let succ = self.write_lvalue(output, succ, acc);
-                    self.propagate_through_lvalue_components(output, succ)
+                    let succ = self.write_place(output, succ, acc);
+                    self.propagate_through_place_components(output, succ)
                 }
             });
 
@@ -1146,11 +1146,11 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
         }
     }
 
-    fn propagate_through_lvalue_components(&mut self,
+    fn propagate_through_place_components(&mut self,
                                            expr: &Expr,
                                            succ: LiveNode)
                                            -> LiveNode {
-        // # Lvalues
+        // # Places
         //
         // In general, the full flow graph structure for an
         // assignment/move/etc can be handled in one of two ways,
@@ -1160,7 +1160,7 @@ fn propagate_through_lvalue_components(&mut self,
         //
         // The two kinds of graphs are:
         //
-        //    Tracked lvalue          Untracked lvalue
+        //    Tracked place          Untracked place
         // ----------------------++-----------------------
         //                       ||
         //         |             ||           |
@@ -1168,7 +1168,7 @@ fn propagate_through_lvalue_components(&mut self,
         //     (rvalue)          ||       (rvalue)
         //         |             ||           |
         //         v             ||           v
-        // (write of lvalue)     ||   (lvalue components)
+        // (write of place)     ||   (place components)
         //         |             ||           |
         //         v             ||           v
         //      (succ)           ||        (succ)
@@ -1177,25 +1177,25 @@ fn propagate_through_lvalue_components(&mut self,
         //
         // I will cover the two cases in turn:
         //
-        // # Tracked lvalues
+        // # Tracked places
         //
-        // A tracked lvalue is a local variable/argument `x`.  In
+        // A tracked place is a local variable/argument `x`.  In
         // these cases, the link_node where the write occurs is linked
-        // to node id of `x`.  The `write_lvalue()` routine generates
+        // to node id of `x`.  The `write_place()` routine generates
         // the contents of this node.  There are no subcomponents to
         // consider.
         //
-        // # Non-tracked lvalues
+        // # Non-tracked places
         //
-        // These are lvalues like `x[5]` or `x.f`.  In that case, we
+        // These are places like `x[5]` or `x.f`.  In that case, we
         // basically ignore the value which is written to but generate
         // reads for the components---`x` in these two examples.  The
         // components reads are generated by
-        // `propagate_through_lvalue_components()` (this fn).
+        // `propagate_through_place_components()` (this fn).
         //
-        // # Illegal lvalues
+        // # Illegal places
         //
-        // It is still possible to observe assignments to non-lvalues;
+        // It is still possible to observe assignments to non-places;
         // these errors are detected in the later pass borrowck.  We
         // just ignore such cases and treat them as reads.
 
@@ -1207,17 +1207,17 @@ fn propagate_through_lvalue_components(&mut self,
         }
     }
 
-    // see comment on propagate_through_lvalue()
-    fn write_lvalue(&mut self, expr: &Expr, succ: LiveNode, acc: u32)
+    // see comment on propagate_through_place()
+    fn write_place(&mut self, expr: &Expr, succ: LiveNode, acc: u32)
                     -> LiveNode {
         match expr.node {
           hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
               self.access_path(expr.id, path, succ, acc)
           }
 
-          // We do not track other lvalues, so just propagate through
+          // We do not track other places, so just propagate through
           // to their subcomponents.  Also, it may happen that
-          // non-lvalues occur here, because those are detected in the
+          // non-places occur here, because those are detected in the
           // later pass borrowck.
           _ => succ
         }
@@ -1363,14 +1363,14 @@ fn check_arm<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, arm: &'tcx hir::Arm) {
 fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
     match expr.node {
       hir::ExprAssign(ref l, _) => {
-        this.check_lvalue(&l);
+        this.check_place(&l);
 
         intravisit::walk_expr(this, expr);
       }
 
       hir::ExprAssignOp(_, ref l, _) => {
         if !this.tables.is_method_call(expr) {
-            this.check_lvalue(&l);
+            this.check_place(&l);
         }
 
         intravisit::walk_expr(this, expr);
@@ -1381,10 +1381,10 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
           this.visit_expr(input);
         }
 
-        // Output operands must be lvalues
+        // Output operands must be places
         for (o, output) in ia.outputs.iter().zip(outputs) {
           if !o.is_indirect {
-            this.check_lvalue(output);
+            this.check_place(output);
           }
           this.visit_expr(output);
         }
@@ -1409,7 +1409,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
 }
 
 impl<'a, 'tcx> Liveness<'a, 'tcx> {
-    fn check_lvalue(&mut self, expr: &'tcx Expr) {
+    fn check_place(&mut self, expr: &'tcx Expr) {
         match expr.node {
             hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
                 if let Def::Local(nid) = path.def {
@@ -1423,7 +1423,7 @@ fn check_lvalue(&mut self, expr: &'tcx Expr) {
                 }
             }
             _ => {
-                // For other kinds of lvalues, no checks are required,
+                // For other kinds of places, no checks are required,
                 // and any embedded expressions are actually rvalues
                 intravisit::walk_expr(self, expr);
             }
index a8955723e3ae01da07466a4d5161209ad9992179..45b595adfe7b8a8a5c104ecaf9ef0ffb9ee54cad 100644 (file)
@@ -26,8 +26,8 @@
 //!       | E.comp    // access to an interior component
 //!
 //! Imagine a routine ToAddr(Expr) that evaluates an expression and returns an
-//! address where the result is to be found.  If Expr is an lvalue, then this
-//! is the address of the lvalue.  If Expr is an rvalue, this is the address of
+//! address where the result is to be found.  If Expr is a place, then this
+//! is the address of the place.  If Expr is an rvalue, this is the address of
 //! some temporary spot in memory where the result is stored.
 //!
 //! Now, cat_expr() classifies the expression Expr and the address A=ToAddr(Expr)
@@ -182,7 +182,7 @@ pub struct cmt_<'tcx> {
     pub id: ast::NodeId,           // id of expr/pat producing this value
     pub span: Span,                // span of same expr/pat
     pub cat: Categorization<'tcx>, // categorization of expr
-    pub mutbl: MutabilityCategory, // mutability of expr as lvalue
+    pub mutbl: MutabilityCategory, // mutability of expr as place
     pub ty: Ty<'tcx>,              // type of the expr (*see WARNING above*)
     pub note: Note,                // Note about the provenance of this cmt
 }
@@ -517,7 +517,7 @@ fn pat_ty(&self, pat: &hir::Pat) -> McResult<Ty<'tcx>> {
                     // a bind-by-ref means that the base_ty will be the type of the ident itself,
                     // but what we want here is the type of the underlying value being borrowed.
                     // So peel off one-level, turning the &T into T.
-                    match base_ty.builtin_deref(false, ty::NoPreference) {
+                    match base_ty.builtin_deref(false) {
                         Some(t) => t.ty,
                         None => {
                             debug!("By-ref binding of non-derefable type {:?}", base_ty);
@@ -603,7 +603,7 @@ pub fn cat_expr_unadjusted(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
         match expr.node {
           hir::ExprUnary(hir::UnDeref, ref e_base) => {
             if self.tables.is_method_call(expr) {
-                self.cat_overloaded_lvalue(expr, e_base, false)
+                self.cat_overloaded_place(expr, e_base, false)
             } else {
                 let base_cmt = self.cat_expr(&e_base)?;
                 self.cat_deref(expr, base_cmt, false)
@@ -631,7 +631,7 @@ pub fn cat_expr_unadjusted(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
                 // The call to index() returns a `&T` value, which
                 // is an rvalue. That is what we will be
                 // dereferencing.
-                self.cat_overloaded_lvalue(expr, base, true)
+                self.cat_overloaded_place(expr, base, true)
             } else {
                 let base_cmt = self.cat_expr(&base)?;
                 self.cat_index(expr, base_cmt, expr_ty, InteriorOffsetKind::Index)
@@ -983,27 +983,27 @@ pub fn cat_tup_field<N:ast_node>(&self,
         ret
     }
 
-    fn cat_overloaded_lvalue(&self,
+    fn cat_overloaded_place(&self,
                              expr: &hir::Expr,
                              base: &hir::Expr,
                              implicit: bool)
                              -> McResult<cmt<'tcx>> {
-        debug!("cat_overloaded_lvalue: implicit={}", implicit);
+        debug!("cat_overloaded_place: implicit={}", implicit);
 
         // Reconstruct the output assuming it's a reference with the
         // same region and mutability as the receiver. This holds for
         // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
-        let lvalue_ty = self.expr_ty(expr)?;
+        let place_ty = self.expr_ty(expr)?;
         let base_ty = self.expr_ty_adjusted(base)?;
 
         let (region, mutbl) = match base_ty.sty {
             ty::TyRef(region, mt) => (region, mt.mutbl),
             _ => {
-                span_bug!(expr.span, "cat_overloaded_lvalue: base is not a reference")
+                span_bug!(expr.span, "cat_overloaded_place: base is not a reference")
             }
         };
         let ref_ty = self.tcx.mk_ref(region, ty::TypeAndMut {
-            ty: lvalue_ty,
+            ty: place_ty,
             mutbl,
         });
 
@@ -1019,7 +1019,7 @@ pub fn cat_deref<N:ast_node>(&self,
         debug!("cat_deref: base_cmt={:?}", base_cmt);
 
         let base_cmt_ty = base_cmt.ty;
-        let deref_ty = match base_cmt_ty.builtin_deref(true, ty::NoPreference) {
+        let deref_ty = match base_cmt_ty.builtin_deref(true) {
             Some(mt) => mt.ty,
             None => {
                 debug!("Explicit deref of non-derefable type: {:?}",
@@ -1386,7 +1386,7 @@ pub fn guarantor(&self) -> cmt<'tcx> {
         }
     }
 
-    /// Returns `FreelyAliasable(_)` if this lvalue represents a freely aliasable pointer type.
+    /// Returns `FreelyAliasable(_)` if this place represents a freely aliasable pointer type.
     pub fn freely_aliasable(&self) -> Aliasability {
         // Maybe non-obvious: copied upvars can only be considered
         // non-aliasable in once closures, since any other kind can be
@@ -1453,7 +1453,7 @@ pub fn descriptive_string(&self, tcx: TyCtxt) -> String {
                 "static item".to_string()
             }
             Categorization::Rvalue(..) => {
-                "non-lvalue".to_string()
+                "non-place".to_string()
             }
             Categorization::Local(vid) => {
                 if tcx.hir.is_argument(vid) {
index 66b3adb83c160a8a3f9b2da16c27e49cdce7f366..dad2d7a7c90fb4ffd33668b8b9844de3cd9cefa9 100644 (file)
@@ -1112,7 +1112,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
     //    I mean that creating a binding into a ref-counted or managed value
     //    would still count.)
     //
-    // 3. `ET`, which matches both rvalues like `foo()` as well as lvalues
+    // 3. `ET`, which matches both rvalues like `foo()` as well as places
     //    based on rvalues like `foo().x[2].y`.
     //
     // A subexpression `<rvalue>` that appears in a let initializer
@@ -1283,7 +1283,7 @@ fn record_rvalue_scope_if_borrow_expr<'a, 'tcx>(
     ///        | (ET)
     ///        | <rvalue>
     ///
-    /// Note: ET is intended to match "rvalues or lvalues based on rvalues".
+    /// Note: ET is intended to match "rvalues or places based on rvalues".
     fn record_rvalue_scope<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
                                      expr: &hir::Expr,
                                      blk_scope: Option<Scope>) {
index 3aa94b3469942bea97eedf6ef9e9b42779cf58fe..3b644aa13f321cc8e9183f3490b56432480f885d 100644 (file)
@@ -733,13 +733,13 @@ pub enum TerminatorKind<'tcx> {
     },
 
     /// Drop the Place and assign the new value over it. This ensures
-    /// that the assignment to LV occurs *even if* the destructor for
+    /// that the assignment to `P` occurs *even if* the destructor for
     /// place unwinds. Its semantics are best explained by by the
     /// elaboration:
     ///
     /// ```
     /// BB0 {
-    ///   DropAndReplace(LV <- RV, goto BB1, unwind BB2)
+    ///   DropAndReplace(P <- V, goto BB1, unwind BB2)
     /// }
     /// ```
     ///
@@ -747,15 +747,15 @@ pub enum TerminatorKind<'tcx> {
     ///
     /// ```
     /// BB0 {
-    ///   Drop(LV, goto BB1, unwind BB2)
+    ///   Drop(P, goto BB1, unwind BB2)
     /// }
     /// BB1 {
-    ///   // LV is now unitialized
-    ///   LV <- RV
+    ///   // P is now unitialized
+    ///   P <- V
     /// }
     /// BB2 {
-    ///   // LV is now unitialized -- its dtor panicked
-    ///   LV <- RV
+    ///   // P is now unitialized -- its dtor panicked
+    ///   P <- V
     /// }
     /// ```
     DropAndReplace {
index 23f360d5c3922a6e6a998675df01594e70ac18d7..53607764b3984ec4ddf1c27d1adfb68df640b873 100644 (file)
@@ -52,7 +52,7 @@ pub fn projection_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
         match *elem {
             ProjectionElem::Deref => {
                 let ty = self.to_ty(tcx)
-                             .builtin_deref(true, ty::LvaluePreference::NoPreference)
+                             .builtin_deref(true)
                              .unwrap_or_else(|| {
                                  bug!("deref projection of non-dereferencable ty {:?}", self)
                              })
index b9546143a054b32af67f2b88bf2ddd72cf5edfe5..9543d01597d04b0d6a8769c8de54f9a339711fd8 100644 (file)
@@ -1288,6 +1288,8 @@ fn parse_lto(slot: &mut Lto, v: Option<&str>) -> bool {
     dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
         "in dep-info output, omit targets for tracking dependencies of the dep-info files \
          themselves"),
+    approximate_suggestions: bool = (false, parse_bool, [UNTRACKED],
+        "include machine-applicability of suggestions in JSON output"),
     unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
         "Present the input source, unstable (and less-pretty) variants;
         valid types are any of the types for `--pretty`, as well as:
index 2765239d5e6494cc0c1d84dae5307164ba3b2025..f4a00a43d8d92b5dcb471e5bb1c3e973906bab0b 100644 (file)
@@ -904,22 +904,27 @@ pub fn build_session_with_codemap(sopts: config::Options,
 
     let emitter: Box<Emitter> = match (sopts.error_format, emitter_dest) {
         (config::ErrorOutputType::HumanReadable(color_config), None) => {
-            Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), false))
+            Box::new(EmitterWriter::stderr(color_config,
+                                           Some(codemap.clone()),
+                                           false,
+                                           sopts.debugging_opts.teach))
         }
         (config::ErrorOutputType::HumanReadable(_), Some(dst)) => {
-            Box::new(EmitterWriter::new(dst, Some(codemap.clone()), false))
+            Box::new(EmitterWriter::new(dst, Some(codemap.clone()), false, false))
         }
         (config::ErrorOutputType::Json(pretty), None) => {
-            Box::new(JsonEmitter::stderr(Some(registry), codemap.clone(), pretty))
+            Box::new(JsonEmitter::stderr(Some(registry), codemap.clone(),
+                     pretty, sopts.debugging_opts.approximate_suggestions))
         }
         (config::ErrorOutputType::Json(pretty), Some(dst)) => {
-            Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone(), pretty))
+            Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone(),
+                     pretty, sopts.debugging_opts.approximate_suggestions))
         }
         (config::ErrorOutputType::Short(color_config), None) => {
-            Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), true))
+            Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false))
         }
         (config::ErrorOutputType::Short(_), Some(dst)) => {
-            Box::new(EmitterWriter::new(dst, Some(codemap.clone()), true))
+            Box::new(EmitterWriter::new(dst, Some(codemap.clone()), true, false))
         }
     };
 
@@ -1095,11 +1100,11 @@ pub enum IncrCompSession {
 pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
     let emitter: Box<Emitter> = match output {
         config::ErrorOutputType::HumanReadable(color_config) => {
-            Box::new(EmitterWriter::stderr(color_config, None, false))
+            Box::new(EmitterWriter::stderr(color_config, None, false, false))
         }
         config::ErrorOutputType::Json(pretty) => Box::new(JsonEmitter::basic(pretty)),
         config::ErrorOutputType::Short(color_config) => {
-            Box::new(EmitterWriter::stderr(color_config, None, true))
+            Box::new(EmitterWriter::stderr(color_config, None, true, false))
         }
     };
     let handler = errors::Handler::with_emitter(true, false, emitter);
@@ -1110,11 +1115,11 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
 pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
     let emitter: Box<Emitter> = match output {
         config::ErrorOutputType::HumanReadable(color_config) => {
-            Box::new(EmitterWriter::stderr(color_config, None, false))
+            Box::new(EmitterWriter::stderr(color_config, None, false, false))
         }
         config::ErrorOutputType::Json(pretty) => Box::new(JsonEmitter::basic(pretty)),
         config::ErrorOutputType::Short(color_config) => {
-            Box::new(EmitterWriter::stderr(color_config, None, true))
+            Box::new(EmitterWriter::stderr(color_config, None, true, false))
         }
     };
     let handler = errors::Handler::with_emitter(true, false, emitter);
index ae68e3fe8d01f065c2954ff6465fcccceecca21b..9de18612d816c468db047ff0bab636e344c9f690 100644 (file)
@@ -19,7 +19,7 @@
 use ty::fold::TypeFoldable;
 use ty::subst::Subst;
 
-use infer::{InferCtxt, InferOk};
+use infer::{InferOk};
 
 /// Whether we do the orphan check relative to this crate or
 /// to some remote crate.
@@ -40,13 +40,20 @@ pub struct OverlapResult<'tcx> {
     pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
 }
 
-/// If there are types that satisfy both impls, returns a suitably-freshened
-/// `ImplHeader` with those types substituted
-pub fn overlapping_impls<'cx, 'gcx, 'tcx>(infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
-                                          impl1_def_id: DefId,
-                                          impl2_def_id: DefId,
-                                          intercrate_mode: IntercrateMode)
-                                          -> Option<OverlapResult<'tcx>>
+/// If there are types that satisfy both impls, invokes `on_overlap`
+/// with a suitably-freshened `ImplHeader` with those types
+/// substituted. Otherwise, invokes `no_overlap`.
+pub fn overlapping_impls<'gcx, F1, F2, R>(
+    tcx: TyCtxt<'_, 'gcx, 'gcx>,
+    impl1_def_id: DefId,
+    impl2_def_id: DefId,
+    intercrate_mode: IntercrateMode,
+    on_overlap: F1,
+    no_overlap: F2,
+) -> R
+where
+    F1: FnOnce(OverlapResult<'_>) -> R,
+    F2: FnOnce() -> R,
 {
     debug!("impl_can_satisfy(\
            impl1_def_id={:?}, \
@@ -56,8 +63,23 @@ pub fn overlapping_impls<'cx, 'gcx, 'tcx>(infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
            impl2_def_id,
            intercrate_mode);
 
-    let selcx = &mut SelectionContext::intercrate(infcx, intercrate_mode);
-    overlap(selcx, impl1_def_id, impl2_def_id)
+    let overlaps = tcx.infer_ctxt().enter(|infcx| {
+        let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode);
+        overlap(selcx, impl1_def_id, impl2_def_id).is_some()
+    });
+
+    if !overlaps {
+        return no_overlap();
+    }
+
+    // In the case where we detect an error, run the check again, but
+    // this time tracking intercrate ambuiguity causes for better
+    // diagnostics. (These take time and can lead to false errors.)
+    tcx.infer_ctxt().enter(|infcx| {
+        let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode);
+        selcx.enable_tracking_intercrate_ambiguity_causes();
+        on_overlap(overlap(selcx, impl1_def_id, impl2_def_id).unwrap())
+    })
 }
 
 fn with_fresh_ty_vars<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
@@ -135,10 +157,10 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
         return None
     }
 
-    Some(OverlapResult {
-        impl_header: selcx.infcx().resolve_type_vars_if_possible(&a_impl_header),
-        intercrate_ambiguity_causes: selcx.intercrate_ambiguity_causes().to_vec(),
-    })
+    let impl_header =  selcx.infcx().resolve_type_vars_if_possible(&a_impl_header);
+    let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
+    debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
+    Some(OverlapResult { impl_header, intercrate_ambiguity_causes })
 }
 
 pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
index 42200a3a44728335967a229640ddbb4501e33953..d65becb912a3cc57150e8a44c4014baf03ba6265 100644 (file)
@@ -831,6 +831,11 @@ fn get_fn_like_arguments(&self, node: hir::map::Node) -> (Span, Vec<ArgKind>) {
                 span,
                 node: hir::ImplItemKind::Method(hir::MethodSig { ref decl, .. }, _),
                 ..
+            }) |
+            hir::map::NodeTraitItem(&hir::TraitItem {
+                span,
+                node: hir::TraitItemKind::Method(hir::MethodSig { ref decl, .. }, _),
+                ..
             }) => {
                 (self.tcx.sess.codemap().def_span(span), decl.inputs.iter()
                         .map(|arg| match arg.clone().into_inner().node {
index 55cbc890e1e91de2c39b45c9975ccb686fee9305..4ed25646d436d03671852d1d3a0fcd0f625e9c85 100644 (file)
@@ -92,10 +92,10 @@ pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
 
     inferred_obligations: SnapshotVec<InferredObligationsSnapshotVecDelegate<'tcx>>,
 
-    intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
+    intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,
 }
 
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub enum IntercrateAmbiguityCause {
     DownstreamCrate {
         trait_desc: String,
@@ -423,7 +423,7 @@ pub fn new(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>) -> SelectionContext<'cx, 'gcx
             freshener: infcx.freshener(),
             intercrate: None,
             inferred_obligations: SnapshotVec::new(),
-            intercrate_ambiguity_causes: Vec::new(),
+            intercrate_ambiguity_causes: None,
         }
     }
 
@@ -435,10 +435,30 @@ pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
             freshener: infcx.freshener(),
             intercrate: Some(mode),
             inferred_obligations: SnapshotVec::new(),
-            intercrate_ambiguity_causes: Vec::new(),
+            intercrate_ambiguity_causes: None,
         }
     }
 
+    /// Enables tracking of intercrate ambiguity causes. These are
+    /// used in coherence to give improved diagnostics. We don't do
+    /// this until we detect a coherence error because it can lead to
+    /// false overflow results (#47139) and because it costs
+    /// computation time.
+    pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
+        assert!(self.intercrate.is_some());
+        assert!(self.intercrate_ambiguity_causes.is_none());
+        self.intercrate_ambiguity_causes = Some(vec![]);
+        debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
+    }
+
+    /// Gets the intercrate ambiguity causes collected since tracking
+    /// was enabled and disables tracking at the same time. If
+    /// tracking is not enabled, just returns an empty vector.
+    pub fn take_intercrate_ambiguity_causes(&mut self) -> Vec<IntercrateAmbiguityCause> {
+        assert!(self.intercrate.is_some());
+        self.intercrate_ambiguity_causes.take().unwrap_or(vec![])
+    }
+
     pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'gcx, 'tcx> {
         self.infcx
     }
@@ -451,10 +471,6 @@ pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'gcx, 'tcx> {
         self.infcx
     }
 
-    pub fn intercrate_ambiguity_causes(&self) -> &[IntercrateAmbiguityCause] {
-        &self.intercrate_ambiguity_causes
-    }
-
     /// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection
     /// context's self.
     fn in_snapshot<R, F>(&mut self, f: F) -> R
@@ -828,19 +844,23 @@ fn evaluate_stack<'o>(&mut self,
             debug!("evaluate_stack({:?}) --> unbound argument, intercrate -->  ambiguous",
                    stack.fresh_trait_ref);
             // Heuristics: show the diagnostics when there are no candidates in crate.
-            if let Ok(candidate_set) = self.assemble_candidates(stack) {
-                if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
-                    let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
-                    let self_ty = trait_ref.self_ty();
-                    let cause = IntercrateAmbiguityCause::DownstreamCrate {
-                        trait_desc: trait_ref.to_string(),
-                        self_desc: if self_ty.has_concrete_skeleton() {
-                            Some(self_ty.to_string())
-                        } else {
-                            None
-                        },
-                    };
-                    self.intercrate_ambiguity_causes.push(cause);
+            if self.intercrate_ambiguity_causes.is_some() {
+                debug!("evaluate_stack: intercrate_ambiguity_causes is some");
+                if let Ok(candidate_set) = self.assemble_candidates(stack) {
+                    if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
+                        let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+                        let self_ty = trait_ref.self_ty();
+                        let cause = IntercrateAmbiguityCause::DownstreamCrate {
+                            trait_desc: trait_ref.to_string(),
+                            self_desc: if self_ty.has_concrete_skeleton() {
+                                Some(self_ty.to_string())
+                            } else {
+                                None
+                            },
+                        };
+                        debug!("evaluate_stack: pushing cause = {:?}", cause);
+                        self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+                    }
                 }
             }
             return EvaluatedToAmbig;
@@ -1092,25 +1112,29 @@ fn candidate_from_obligation_no_cache<'o>(&mut self,
             None => {}
             Some(conflict) => {
                 debug!("coherence stage: not knowable");
-                // Heuristics: show the diagnostics when there are no candidates in crate.
-                let candidate_set = self.assemble_candidates(stack)?;
-                if !candidate_set.ambiguous && candidate_set.vec.iter().all(|c| {
-                    !self.evaluate_candidate(stack, &c).may_apply()
-                }) {
-                    let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
-                    let self_ty = trait_ref.self_ty();
-                    let trait_desc = trait_ref.to_string();
-                    let self_desc = if self_ty.has_concrete_skeleton() {
-                        Some(self_ty.to_string())
-                    } else {
-                        None
-                    };
-                    let cause = if let Conflict::Upstream = conflict {
-                        IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
-                    } else {
-                        IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
-                    };
-                    self.intercrate_ambiguity_causes.push(cause);
+                if self.intercrate_ambiguity_causes.is_some() {
+                    debug!("evaluate_stack: intercrate_ambiguity_causes is some");
+                    // Heuristics: show the diagnostics when there are no candidates in crate.
+                    let candidate_set = self.assemble_candidates(stack)?;
+                    if !candidate_set.ambiguous && candidate_set.vec.iter().all(|c| {
+                        !self.evaluate_candidate(stack, &c).may_apply()
+                    }) {
+                        let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+                        let self_ty = trait_ref.self_ty();
+                        let trait_desc = trait_ref.to_string();
+                        let self_desc = if self_ty.has_concrete_skeleton() {
+                            Some(self_ty.to_string())
+                        } else {
+                            None
+                        };
+                        let cause = if let Conflict::Upstream = conflict {
+                            IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
+                        } else {
+                            IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
+                        };
+                        debug!("evaluate_stack: pushing cause = {:?}", cause);
+                        self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+                    }
                 }
                 return Ok(None);
             }
index 834389e5d009c62145d41e7fd88b2d0698e62265..a10169e13e60a705e4bc9e0bc3d6cf75cf5a4a75 100644 (file)
@@ -133,12 +133,12 @@ fn insert(&mut self,
             };
 
             let tcx = tcx.global_tcx();
-            let (le, ge) = tcx.infer_ctxt().enter(|infcx| {
-                let overlap = traits::overlapping_impls(&infcx,
-                                                        possible_sibling,
-                                                        impl_def_id,
-                                                        traits::IntercrateMode::Issue43355);
-                if let Some(overlap) = overlap {
+            let (le, ge) = traits::overlapping_impls(
+                tcx,
+                possible_sibling,
+                impl_def_id,
+                traits::IntercrateMode::Issue43355,
+                |overlap| {
                     if tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
                         return Ok((false, false));
                     }
@@ -151,10 +151,9 @@ fn insert(&mut self,
                     } else {
                         Ok((le, ge))
                     }
-                } else {
-                    Ok((false, false))
-                }
-            })?;
+                },
+                || Ok((false, false)),
+            )?;
 
             if le && !ge {
                 debug!("descending as child of TraitRef {:?}",
@@ -171,16 +170,14 @@ fn insert(&mut self,
                 return Ok(Inserted::Replaced(possible_sibling));
             } else {
                 if !tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
-                    tcx.infer_ctxt().enter(|infcx| {
-                        if let Some(overlap) = traits::overlapping_impls(
-                            &infcx,
-                            possible_sibling,
-                            impl_def_id,
-                            traits::IntercrateMode::Fixed)
-                        {
-                            last_lint = Some(overlap_error(overlap));
-                        }
-                    });
+                    traits::overlapping_impls(
+                        tcx,
+                        possible_sibling,
+                        impl_def_id,
+                        traits::IntercrateMode::Fixed,
+                        |overlap| last_lint = Some(overlap_error(overlap)),
+                        || (),
+                    );
                 }
 
                 // no overlap (error bailed already via ?)
index 6df6bb9df232044512896ae1db652ae9787fb40b..96d69b4fba21a9a0255db52ed91da9714cc2d184 100644 (file)
@@ -77,7 +77,7 @@ pub enum Adjust<'tcx> {
     /// Go from a mut raw pointer to a const raw pointer.
     MutToConstPointer,
 
-    /// Dereference once, producing an lvalue.
+    /// Dereference once, producing a place.
     Deref(Option<OverloadedDeref<'tcx>>),
 
     /// Take the address and produce either a `&` or `*` pointer.
index 6c79f6a62fa0b3779861edcddbe7bf95b300c89d..85fca68187fe661fc82f9084cd94aea5719144cd 100644 (file)
         -> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>),
     [] fn export_name: ExportName(DefId) -> Option<Symbol>,
     [] fn contains_extern_indicator: ContainsExternIndicator(DefId) -> bool,
+    [] fn symbol_export_level: GetSymbolExportLevel(DefId) -> SymbolExportLevel,
     [] fn is_translated_function: IsTranslatedFunction(DefId) -> bool,
     [] fn codegen_unit: CodegenUnit(InternedString) -> Arc<CodegenUnit<'tcx>>,
     [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats,
index c9eebc3d2a0a723e9f486ced5063d4d54699ae9b..0ab6ee1a54a9b1a02ac866b6e6f3839c97c2296a 100644 (file)
@@ -921,6 +921,8 @@ macro_rules! force {
 
         DepKind::TargetFeaturesWhitelist => { force!(target_features_whitelist, LOCAL_CRATE); }
         DepKind::TargetFeaturesEnabled => { force!(target_features_enabled, def_id!()); }
+
+        DepKind::GetSymbolExportLevel => { force!(symbol_export_level, def_id!()); }
     }
 
     true
index 63df1179af22828e7eeb26b1f29f5f8e5a9972b2..f52f2ea0f9fc8258b9d93964c6694a1da0cb9e9a 100644 (file)
@@ -12,7 +12,6 @@
 pub use self::AssociatedItemContainer::*;
 pub use self::BorrowKind::*;
 pub use self::IntVarValue::*;
-pub use self::LvaluePreference::*;
 pub use self::fold::TypeFoldable;
 
 use hir::{map as hir_map, FreevarMap, TraitMap};
@@ -2099,21 +2098,6 @@ pub fn maybe_walk<F>(&'tcx self, mut f: F)
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum LvaluePreference {
-    PreferMutLvalue,
-    NoPreference
-}
-
-impl LvaluePreference {
-    pub fn from_mutbl(m: hir::Mutability) -> Self {
-        match m {
-            hir::MutMutable => PreferMutLvalue,
-            hir::MutImmutable => NoPreference,
-        }
-    }
-}
-
 impl BorrowKind {
     pub fn from_mutbl(m: hir::Mutability) -> BorrowKind {
         match m {
@@ -2193,60 +2177,6 @@ pub fn expr_span(self, id: NodeId) -> Span {
         }
     }
 
-    pub fn expr_is_lval(self, expr: &hir::Expr) -> bool {
-         match expr.node {
-            hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
-                match path.def {
-                    Def::Local(..) | Def::Upvar(..) | Def::Static(..) | Def::Err => true,
-                    _ => false,
-                }
-            }
-
-            hir::ExprType(ref e, _) => {
-                self.expr_is_lval(e)
-            }
-
-            hir::ExprUnary(hir::UnDeref, _) |
-            hir::ExprField(..) |
-            hir::ExprTupField(..) |
-            hir::ExprIndex(..) => {
-                true
-            }
-
-            // Partially qualified paths in expressions can only legally
-            // refer to associated items which are always rvalues.
-            hir::ExprPath(hir::QPath::TypeRelative(..)) |
-
-            hir::ExprCall(..) |
-            hir::ExprMethodCall(..) |
-            hir::ExprStruct(..) |
-            hir::ExprTup(..) |
-            hir::ExprIf(..) |
-            hir::ExprMatch(..) |
-            hir::ExprClosure(..) |
-            hir::ExprBlock(..) |
-            hir::ExprRepeat(..) |
-            hir::ExprArray(..) |
-            hir::ExprBreak(..) |
-            hir::ExprAgain(..) |
-            hir::ExprRet(..) |
-            hir::ExprWhile(..) |
-            hir::ExprLoop(..) |
-            hir::ExprAssign(..) |
-            hir::ExprInlineAsm(..) |
-            hir::ExprAssignOp(..) |
-            hir::ExprLit(_) |
-            hir::ExprUnary(..) |
-            hir::ExprBox(..) |
-            hir::ExprAddrOf(..) |
-            hir::ExprBinary(..) |
-            hir::ExprYield(..) |
-            hir::ExprCast(..) => {
-                false
-            }
-        }
-    }
-
     pub fn provided_trait_methods(self, id: DefId) -> Vec<AssociatedItem> {
         self.associated_items(id)
             .filter(|item| item.kind == AssociatedKind::Method && item.defaultness.has_value())
index db7e4fe45ef769d2e523ed3a4e1d2d26c35d1939..0c1ebd1a2ba2f2f0c754d1ed8067c4bbdefcbfb1 100644 (file)
@@ -1514,18 +1514,12 @@ pub fn has_concrete_skeleton(&self) -> bool {
     ///
     /// The parameter `explicit` indicates if this is an *explicit* dereference.
     /// Some types---notably unsafe ptrs---can only be dereferenced explicitly.
-    pub fn builtin_deref(&self, explicit: bool, pref: ty::LvaluePreference)
-        -> Option<TypeAndMut<'tcx>>
-    {
+    pub fn builtin_deref(&self, explicit: bool) -> Option<TypeAndMut<'tcx>> {
         match self.sty {
             TyAdt(def, _) if def.is_box() => {
                 Some(TypeAndMut {
                     ty: self.boxed_ty(),
-                    mutbl: if pref == ty::PreferMutLvalue {
-                        hir::MutMutable
-                    } else {
-                        hir::MutImmutable
-                    },
+                    mutbl: hir::MutImmutable,
                 })
             },
             TyRef(_, mt) => Some(mt),
index a54627279b02c2a4a7179057e3ceae05dc88324b..5d9f0f6012bf267019070055d907ee983391b5ad 100644 (file)
@@ -31,6 +31,7 @@ pub fn target() -> Result<Target, String> {
         max_atomic_width: Some(32),
         post_link_args: args,
         target_family: Some("unix".to_string()),
+        codegen_backend: "emscripten".to_string(),
         .. Default::default()
     };
     Ok(Target {
index 3f6b984272ed5ec40c620311258c3023e8c8bc85..80168d4af4b1bac77b0b6cdc5b57ce2c46a398b7 100644 (file)
@@ -9,9 +9,16 @@
 // except according to those terms.
 
 use LinkerFlavor;
-use target::{Target, TargetOptions, TargetResult};
+use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
+    let mut base = super::linux_musl_base::opts();
+    base.cpu = "mips32r2".to_string();
+    base.features = "+mips32r2,+soft-float".to_string();
+    base.max_atomic_width = Some(32);
+    // see #36994
+    base.exe_allocation_crate = None;
+    base.crt_static_default = false;
     Ok(Target {
         llvm_target: "mips-unknown-linux-musl".to_string(),
         target_endian: "big".to_string(),
@@ -23,15 +30,6 @@ pub fn target() -> TargetResult {
         target_env: "musl".to_string(),
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
-        options: TargetOptions {
-            cpu: "mips32r2".to_string(),
-            features: "+mips32r2,+soft-float".to_string(),
-            max_atomic_width: Some(32),
-
-            // see #36994
-            exe_allocation_crate: None,
-
-            ..super::linux_base::opts()
-        }
+        options: base,
     })
 }
index 464f0bfe48058d33513be98327afabd0c97c3f32..b09d96eb9cbcbfd264c38adb41feb89f710d2cf3 100644 (file)
@@ -9,9 +9,16 @@
 // except according to those terms.
 
 use LinkerFlavor;
-use target::{Target, TargetOptions, TargetResult};
+use target::{Target, TargetResult};
 
 pub fn target() -> TargetResult {
+    let mut base = super::linux_musl_base::opts();
+    base.cpu = "mips32".to_string();
+    base.features = "+mips32,+soft-float".to_string();
+    base.max_atomic_width = Some(32);
+    // see #36994
+    base.exe_allocation_crate = None;
+    base.crt_static_default = false;
     Ok(Target {
         llvm_target: "mipsel-unknown-linux-musl".to_string(),
         target_endian: "little".to_string(),
@@ -23,15 +30,6 @@ pub fn target() -> TargetResult {
         target_env: "musl".to_string(),
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
-        options: TargetOptions {
-            cpu: "mips32".to_string(),
-            features: "+mips32,+soft-float".to_string(),
-            max_atomic_width: Some(32),
-
-            // see #36994
-            exe_allocation_crate: None,
-
-            ..super::linux_base::opts()
-        }
+        options: base,
     })
 }
index 2e860f940a7a7b7fa1cbf3fa25d11fe717ada873..2872c59157d6be1cf1b5d73aec7f39d8e0aa584b 100644 (file)
@@ -465,6 +465,13 @@ pub struct TargetOptions {
     /// Whether to lower 128-bit operations to compiler_builtins calls.  Use if
     /// your backend only supports 64-bit and smaller math.
     pub i128_lowering: bool,
+
+    /// The codegen backend to use for this target, typically "llvm"
+    pub codegen_backend: String,
+
+    /// The default visibility for symbols in this target should be "hidden"
+    /// rather than "default"
+    pub default_hidden_visibility: bool,
 }
 
 impl Default for TargetOptions {
@@ -534,6 +541,8 @@ fn default() -> TargetOptions {
             singlethread: false,
             no_builtins: false,
             i128_lowering: false,
+            codegen_backend: "llvm".to_string(),
+            default_hidden_visibility: false,
         }
     }
 }
@@ -780,6 +789,8 @@ macro_rules! key {
         key!(requires_lto, bool);
         key!(singlethread, bool);
         key!(no_builtins, bool);
+        key!(codegen_backend);
+        key!(default_hidden_visibility, bool);
 
         if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
             for name in array.iter().filter_map(|abi| abi.as_string()) {
@@ -976,6 +987,8 @@ macro_rules! target_option_val {
         target_option_val!(requires_lto);
         target_option_val!(singlethread);
         target_option_val!(no_builtins);
+        target_option_val!(codegen_backend);
+        target_option_val!(default_hidden_visibility);
 
         if default.abi_blacklist != self.options.abi_blacklist {
             d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter()
index 509a7cf5e03234158d70a61ca70ec53cbb749b74..966df897f01f1e09295b609d7c3530fbb5e4378a 100644 (file)
@@ -53,6 +53,12 @@ pub fn target() -> TargetResult {
             // don't want to invoke that many gcc instances.
             default_codegen_units: Some(1),
 
+            // Since MSP430 doesn't meaningfully support faulting on illegal
+            // instructions, LLVM generates a call to abort() function instead
+            // of a trap instruction. Such calls are 4 bytes long, and that is
+            // too much overhead for such small target.
+            trap_unreachable: false,
+
             .. Default::default( )
         }
     })
index 197c1f7a4da494c2f9f649f69ea57e3aeee5c092..4823541f2262ca89d56e2e2718897cb360bf80ea 100644 (file)
@@ -35,6 +35,7 @@ pub fn target() -> Result<Target, String> {
         max_atomic_width: Some(32),
         post_link_args,
         target_family: Some("unix".to_string()),
+        codegen_backend: "emscripten".to_string(),
         .. Default::default()
     };
     Ok(Target {
index 7e1011ab8af96a2bd47b721b2fbf4f0c3f629498..242860e5c6e9285034cc5946e8a626a40275ec99 100644 (file)
@@ -83,6 +83,9 @@ pub fn target() -> Result<Target, String> {
         // performing LTO with compiler-builtins.
         no_builtins: true,
 
+        // no dynamic linking, no need for default visibility!
+        default_hidden_visibility: true,
+
         .. Default::default()
     };
     Ok(Target {
index b877c5a9cbcbcccbb7ec2d8d2b728f41c0a709da..da2b1ef0b1c02a3aef7b1345945d3858285a1e11 100644 (file)
@@ -43,14 +43,14 @@ it is safe with respect to the in-scope loans.
 # Formal model
 
 Throughout the docs we'll consider a simple subset of Rust in which
-you can only borrow from lvalues, defined like so:
+you can only borrow from places, defined like so:
 
 ```text
-LV = x | LV.f | *LV
+P = x | P.f | *P
 ```
 
-Here `x` represents some variable, `LV.f` is a field reference,
-and `*LV` is a pointer dereference. There is no auto-deref or other
+Here `x` represents some variable, `P.f` is a field reference,
+and `*P` is a pointer dereference. There is no auto-deref or other
 niceties. This means that if you have a type like:
 
 ```rust
@@ -58,7 +58,7 @@ struct S { f: i32 }
 ```
 
 and a variable `a: Box<S>`, then the rust expression `a.f` would correspond
-to an `LV` of `(*a).f`.
+to an `P` of `(*a).f`.
 
 Here is the formal grammar for the types we'll consider:
 
@@ -99,7 +99,7 @@ this sort of thing.
 #### Loans and restrictions
 
 The way the borrow checker works is that it analyzes each borrow
-expression (in our simple model, that's stuff like `&LV`, though in
+expression (in our simple model, that's stuff like `&P`, though in
 real life there are a few other cases to consider). For each borrow
 expression, it computes a `Loan`, which is a data structure that
 records (1) the value being borrowed, (2) the mutability and scope of
@@ -108,29 +108,29 @@ struct defined in `middle::borrowck`. Formally, we define `LOAN` as
 follows:
 
 ```text
-LOAN = (LV, LT, MQ, RESTRICTION*)
-RESTRICTION = (LV, ACTION*)
+LOAN = (P, LT, MQ, RESTRICTION*)
+RESTRICTION = (P, ACTION*)
 ACTION = MUTATE | CLAIM | FREEZE
 ```
 
-Here the `LOAN` tuple defines the lvalue `LV` being borrowed; the
+Here the `LOAN` tuple defines the place `P` being borrowed; the
 lifetime `LT` of that borrow; the mutability `MQ` of the borrow; and a
 list of restrictions. The restrictions indicate actions which, if
 taken, could invalidate the loan and lead to type safety violations.
 
-Each `RESTRICTION` is a pair of a restrictive lvalue `LV` (which will
+Each `RESTRICTION` is a pair of a restrictive place `P` (which will
 either be the path that was borrowed or some prefix of the path that
 was borrowed) and a set of restricted actions.  There are three kinds
-of actions that may be restricted for the path `LV`:
+of actions that may be restricted for the path `P`:
 
-- `MUTATE` means that `LV` cannot be assigned to;
-- `CLAIM` means that the `LV` cannot be borrowed mutably;
-- `FREEZE` means that the `LV` cannot be borrowed immutably;
+- `MUTATE` means that `P` cannot be assigned to;
+- `CLAIM` means that the `P` cannot be borrowed mutably;
+- `FREEZE` means that the `P` cannot be borrowed immutably;
 
-Finally, it is never possible to move from an lvalue that appears in a
-restriction. This implies that the "empty restriction" `(LV, [])`,
+Finally, it is never possible to move from a place that appears in a
+restriction. This implies that the "empty restriction" `(P, [])`,
 which contains an empty set of actions, still has a purpose---it
-prevents moves from `LV`. I chose not to make `MOVE` a fourth kind of
+prevents moves from `P`. I chose not to make `MOVE` a fourth kind of
 action because that would imply that sometimes moves are permitted
 from restricted values, which is not the case.
 
@@ -239,22 +239,22 @@ live. (This is done via restrictions, read on.)
 
 We start with the `gather_loans` pass, which walks the AST looking for
 borrows.  For each borrow, there are three bits of information: the
-lvalue `LV` being borrowed and the mutability `MQ` and lifetime `LT`
+place `P` being borrowed and the mutability `MQ` and lifetime `LT`
 of the resulting pointer. Given those, `gather_loans` applies four
 validity tests:
 
-1. `MUTABILITY(LV, MQ)`: The mutability of the reference is
-compatible with the mutability of `LV` (i.e., not borrowing immutable
+1. `MUTABILITY(P, MQ)`: The mutability of the reference is
+compatible with the mutability of `P` (i.e., not borrowing immutable
 data as mutable).
 
-2. `ALIASABLE(LV, MQ)`: The aliasability of the reference is
-compatible with the aliasability of `LV`. The goal is to prevent
+2. `ALIASABLE(P, MQ)`: The aliasability of the reference is
+compatible with the aliasability of `P`. The goal is to prevent
 `&mut` borrows of aliasability data.
 
-3. `LIFETIME(LV, LT, MQ)`: The lifetime of the borrow does not exceed
+3. `LIFETIME(P, LT, MQ)`: The lifetime of the borrow does not exceed
 the lifetime of the value being borrowed.
 
-4. `RESTRICTIONS(LV, LT, ACTIONS) = RS`: This pass checks and computes the
+4. `RESTRICTIONS(P, LT, ACTIONS) = RS`: This pass checks and computes the
 restrictions to maintain memory safety. These are the restrictions
 that will go into the final loan. We'll discuss in more detail below.
 
@@ -263,7 +263,7 @@ that will go into the final loan. We'll discuss in more detail below.
 Checking mutability is fairly straightforward. We just want to prevent
 immutable data from being borrowed as mutable. Note that it is ok to borrow
 mutable data as immutable, since that is simply a freeze. The judgement
-`MUTABILITY(LV, MQ)` means the mutability of `LV` is compatible with a borrow
+`MUTABILITY(P, MQ)` means the mutability of `P` is compatible with a borrow
 of mutability `MQ`. The Rust code corresponding to this predicate is the
 function `check_mutability` in `middle::borrowck::gather_loans`.
 
@@ -288,15 +288,15 @@ MUTABILITY(X, imm)                  // M-Var-Imm
 
 Fields and boxes inherit their mutability from
 their base expressions, so both of their rules basically
-delegate the check to the base expression `LV`:
+delegate the check to the base expression `P`:
 
 ```text
-MUTABILITY(LV.f, MQ)                // M-Field
-  MUTABILITY(LV, MQ)
+MUTABILITY(P.f, MQ)                // M-Field
+  MUTABILITY(P, MQ)
 
-MUTABILITY(*LV, MQ)                 // M-Deref-Unique
-  TYPE(LV) = Box<Ty>
-  MUTABILITY(LV, MQ)
+MUTABILITY(*P, MQ)                 // M-Deref-Unique
+  TYPE(P) = Box<Ty>
+  MUTABILITY(P, MQ)
 ```
 
 ### Checking mutability of immutable pointer types
@@ -305,8 +305,8 @@ Immutable pointer types like `&T` can only
 be borrowed if MQ is immutable:
 
 ```text
-MUTABILITY(*LV, imm)               // M-Deref-Borrowed-Imm
-  TYPE(LV) = &Ty
+MUTABILITY(*P, imm)               // M-Deref-Borrowed-Imm
+  TYPE(P) = &Ty
 ```
 
 ### Checking mutability of mutable pointer types
@@ -314,15 +314,15 @@ MUTABILITY(*LV, imm)               // M-Deref-Borrowed-Imm
 `&mut T` can be frozen, so it is acceptable to borrow it as either imm or mut:
 
 ```text
-MUTABILITY(*LV, MQ)                 // M-Deref-Borrowed-Mut
-  TYPE(LV) = &mut Ty
+MUTABILITY(*P, MQ)                 // M-Deref-Borrowed-Mut
+  TYPE(P) = &mut Ty
 ```
 
 ## Checking aliasability
 
 The goal of the aliasability check is to ensure that we never permit `&mut`
-borrows of aliasable data. The judgement `ALIASABLE(LV, MQ)` means the
-aliasability of `LV` is compatible with a borrow of mutability `MQ`. The Rust
+borrows of aliasable data. The judgement `ALIASABLE(P, MQ)` means the
+aliasability of `P` is compatible with a borrow of mutability `MQ`. The Rust
 code corresponding to this predicate is the function `check_aliasability()` in
 `middle::borrowck::gather_loans`.
 
@@ -340,11 +340,11 @@ the stack frame.
 Owned content is aliasable if it is found in an aliasable location:
 
 ```text
-ALIASABLE(LV.f, MQ)                // M-Field
-  ALIASABLE(LV, MQ)
+ALIASABLE(P.f, MQ)                // M-Field
+  ALIASABLE(P, MQ)
 
-ALIASABLE(*LV, MQ)                 // M-Deref-Unique
-  ALIASABLE(LV, MQ)
+ALIASABLE(*P, MQ)                 // M-Deref-Unique
+  ALIASABLE(P, MQ)
 ```
 
 ### Checking aliasability of immutable pointer types
@@ -353,8 +353,8 @@ Immutable pointer types like `&T` are aliasable, and hence can only be
 borrowed immutably:
 
 ```text
-ALIASABLE(*LV, imm)                // M-Deref-Borrowed-Imm
-  TYPE(LV) = &Ty
+ALIASABLE(*P, imm)                // M-Deref-Borrowed-Imm
+  TYPE(P) = &Ty
 ```
 
 ### Checking aliasability of mutable pointer types
@@ -362,16 +362,16 @@ ALIASABLE(*LV, imm)                // M-Deref-Borrowed-Imm
 `&mut T` can be frozen, so it is acceptable to borrow it as either imm or mut:
 
 ```text
-ALIASABLE(*LV, MQ)                 // M-Deref-Borrowed-Mut
-  TYPE(LV) = &mut Ty
+ALIASABLE(*P, MQ)                 // M-Deref-Borrowed-Mut
+  TYPE(P) = &mut Ty
 ```
 
 ## Checking lifetime
 
 These rules aim to ensure that no data is borrowed for a scope that exceeds
 its lifetime. These two computations wind up being intimately related.
-Formally, we define a predicate `LIFETIME(LV, LT, MQ)`, which states that
-"the lvalue `LV` can be safely borrowed for the lifetime `LT` with mutability
+Formally, we define a predicate `LIFETIME(P, LT, MQ)`, which states that
+"the place `P` can be safely borrowed for the lifetime `LT` with mutability
 `MQ`". The Rust code corresponding to this predicate is the module
 `middle::borrowck::gather_loans::lifetime`.
 
@@ -391,12 +391,12 @@ The lifetime of a field or box is the same as the lifetime
 of its owner:
 
 ```text
-LIFETIME(LV.f, LT, MQ)              // L-Field
-  LIFETIME(LV, LT, MQ)
+LIFETIME(P.f, LT, MQ)              // L-Field
+  LIFETIME(P, LT, MQ)
 
-LIFETIME(*LV, LT, MQ)               // L-Deref-Send
-  TYPE(LV) = Box<Ty>
-  LIFETIME(LV, LT, MQ)
+LIFETIME(*P, LT, MQ)               // L-Deref-Send
+  TYPE(P) = Box<Ty>
+  LIFETIME(P, LT, MQ)
 ```
 
 ### Checking lifetime for derefs of references
@@ -408,8 +408,8 @@ of the borrow is shorter than the lifetime `LT'` of the pointer
 itself:
 
 ```text
-LIFETIME(*LV, LT, MQ)               // L-Deref-Borrowed
-  TYPE(LV) = &LT' Ty OR &LT' mut Ty
+LIFETIME(*P, LT, MQ)               // L-Deref-Borrowed
+  TYPE(P) = &LT' Ty OR &LT' mut Ty
   LT <= LT'
 ```
 
@@ -417,17 +417,17 @@ LIFETIME(*LV, LT, MQ)               // L-Deref-Borrowed
 
 The final rules govern the computation of *restrictions*, meaning that
 we compute the set of actions that will be illegal for the life of the
-loan. The predicate is written `RESTRICTIONS(LV, LT, ACTIONS) =
+loan. The predicate is written `RESTRICTIONS(P, LT, ACTIONS) =
 RESTRICTION*`, which can be read "in order to prevent `ACTIONS` from
-occurring on `LV`, the restrictions `RESTRICTION*` must be respected
+occurring on `P`, the restrictions `RESTRICTION*` must be respected
 for the lifetime of the loan".
 
 Note that there is an initial set of restrictions: these restrictions
 are computed based on the kind of borrow:
 
 ```text
-&mut LV =>   RESTRICTIONS(LV, LT, MUTATE|CLAIM|FREEZE)
-&LV =>       RESTRICTIONS(LV, LT, MUTATE|CLAIM)
+&mut P =>   RESTRICTIONS(P, LT, MUTATE|CLAIM|FREEZE)
+&P =>       RESTRICTIONS(P, LT, MUTATE|CLAIM)
 ```
 
 The reasoning here is that a mutable borrow must be the only writer,
@@ -451,8 +451,8 @@ Restricting a field is the same as restricting the owner of that
 field:
 
 ```text
-RESTRICTIONS(LV.f, LT, ACTIONS) = RS, (LV.f, ACTIONS)  // R-Field
-  RESTRICTIONS(LV, LT, ACTIONS) = RS
+RESTRICTIONS(P.f, LT, ACTIONS) = RS, (P.f, ACTIONS)  // R-Field
+  RESTRICTIONS(P, LT, ACTIONS) = RS
 ```
 
 The reasoning here is as follows. If the field must not be mutated,
@@ -467,16 +467,16 @@ origin of inherited mutability.
 Because the mutability of owned referents is inherited, restricting an
 owned referent is similar to restricting a field, in that it implies
 restrictions on the pointer. However, boxes have an important
-twist: if the owner `LV` is mutated, that causes the owned referent
-`*LV` to be freed! So whenever an owned referent `*LV` is borrowed, we
-must prevent the box `LV` from being mutated, which means
+twist: if the owner `P` is mutated, that causes the owned referent
+`*P` to be freed! So whenever an owned referent `*P` is borrowed, we
+must prevent the box `P` from being mutated, which means
 that we always add `MUTATE` and `CLAIM` to the restriction set imposed
-on `LV`:
+on `P`:
 
 ```text
-RESTRICTIONS(*LV, LT, ACTIONS) = RS, (*LV, ACTIONS)    // R-Deref-Send-Pointer
-  TYPE(LV) = Box<Ty>
-  RESTRICTIONS(LV, LT, ACTIONS|MUTATE|CLAIM) = RS
+RESTRICTIONS(*P, LT, ACTIONS) = RS, (*P, ACTIONS)    // R-Deref-Send-Pointer
+  TYPE(P) = Box<Ty>
+  RESTRICTIONS(P, LT, ACTIONS|MUTATE|CLAIM) = RS
 ```
 
 ### Restrictions for loans of immutable borrowed referents
@@ -484,15 +484,15 @@ RESTRICTIONS(*LV, LT, ACTIONS) = RS, (*LV, ACTIONS)    // R-Deref-Send-Pointer
 Immutable borrowed referents are freely aliasable, meaning that
 the compiler does not prevent you from copying the pointer.  This
 implies that issuing restrictions is useless. We might prevent the
-user from acting on `*LV` itself, but there could be another path
-`*LV1` that refers to the exact same memory, and we would not be
+user from acting on `*P` itself, but there could be another path
+`*P1` that refers to the exact same memory, and we would not be
 restricting that path. Therefore, the rule for `&Ty` pointers
 always returns an empty set of restrictions, and it only permits
 restricting `MUTATE` and `CLAIM` actions:
 
 ```text
-RESTRICTIONS(*LV, LT, ACTIONS) = []                    // R-Deref-Imm-Borrowed
-  TYPE(LV) = &LT' Ty
+RESTRICTIONS(*P, LT, ACTIONS) = []                    // R-Deref-Imm-Borrowed
+  TYPE(P) = &LT' Ty
   LT <= LT'                                            // (1)
   ACTIONS subset of [MUTATE, CLAIM]
 ```
@@ -546,7 +546,7 @@ This function is legal. The reason for this is that the inner pointer
 (`*point : &'b Point`) is enough to guarantee the memory is immutable
 and valid for the lifetime `'b`.  This is reflected in
 `RESTRICTIONS()` by the fact that we do not recurse (i.e., we impose
-no restrictions on `LV`, which in this particular case is the pointer
+no restrictions on `P`, which in this particular case is the pointer
 `point : &'a &'b Point`).
 
 #### Why both `LIFETIME()` and `RESTRICTIONS()`?
@@ -612,10 +612,10 @@ while the new claimant is live.
 The rule for mutable borrowed pointers is as follows:
 
 ```text
-RESTRICTIONS(*LV, LT, ACTIONS) = RS, (*LV, ACTIONS)    // R-Deref-Mut-Borrowed
-  TYPE(LV) = &LT' mut Ty
+RESTRICTIONS(*P, LT, ACTIONS) = RS, (*P, ACTIONS)    // R-Deref-Mut-Borrowed
+  TYPE(P) = &LT' mut Ty
   LT <= LT'                                            // (1)
-  RESTRICTIONS(LV, LT, ACTIONS) = RS                   // (2)
+  RESTRICTIONS(P, LT, ACTIONS) = RS                   // (2)
 ```
 
 Let's examine the two numbered clauses:
@@ -670,7 +670,7 @@ fn foo(t0: &mut i32) {
 
 Remember that `&mut` pointers are linear, and hence `let t1 = t0` is a
 move of `t0` -- or would be, if it were legal. Instead, we get an
-error, because clause (2) imposes restrictions on `LV` (`t0`, here),
+error, because clause (2) imposes restrictions on `P` (`t0`, here),
 and any restrictions on a path make it impossible to move from that
 path.
 
@@ -906,7 +906,7 @@ results of a dataflow computation.
 
 The `MovePath` tree tracks every path that is moved or assigned to.
 These paths have the same form as the `LoanPath` data structure, which
-in turn is the "real world version of the lvalues `LV` that we
+in turn is the "real world version of the places `P` that we
 introduced earlier. The difference between a `MovePath` and a `LoanPath`
 is that move paths are:
 
@@ -1132,7 +1132,7 @@ is implied by the relevant moves.
 While writing up these docs, I encountered some rules I believe to be
 stricter than necessary:
 
-- I think restricting the `&mut` LV against moves and `ALIAS` is sufficient,
+- I think restricting the `&mut` P against moves and `ALIAS` is sufficient,
   `MUTATE` and `CLAIM` are overkill. `MUTATE` was necessary when swap was
   a built-in operator, but as it is not, it is implied by `CLAIM`,
   and `CLAIM` is implied by `ALIAS`. The only net effect of this is an
index 862ea0c240ab9bd286b47b2780b821822c107ae7..9888b2fffc7792beaa1a8c4590a185966f372621 100644 (file)
@@ -591,8 +591,8 @@ pub fn report_error_if_loan_conflicts_with_restriction(&self,
             // 3. Where does old loan expire.
 
             let previous_end_span =
-                Some(old_loan.kill_scope.span(self.tcx(), &self.bccx.region_scope_tree)
-                     .end_point());
+                Some(self.tcx().sess.codemap().end_point(
+                        old_loan.kill_scope.span(self.tcx(), &self.bccx.region_scope_tree)));
 
             let mut err = match (new_loan.kind, old_loan.kind) {
                 (ty::MutBorrow, ty::MutBorrow) =>
index 66aaafb77f757cc3e54681fc28f76b1f859299b7..97fa94b5e5cf9c159ccba5baaec181549904f300 100644 (file)
@@ -104,7 +104,7 @@ fn check_scope(&self, max_scope: ty::Region<'tcx>) -> R {
 
     fn scope(&self, cmt: &mc::cmt<'tcx>) -> ty::Region<'tcx> {
         //! Returns the maximal region scope for the which the
-        //! lvalue `cmt` is guaranteed to be valid without any
+        //! place `cmt` is guaranteed to be valid without any
         //! rooting etc, and presuming `cmt` is not mutated.
 
         match cmt.cat {
index f755efc89a58ed1925807a912161a4fa40f1ada5..84ca2a9318ab36a226efd894a4dc2ef1ac647ea8 100644 (file)
@@ -170,7 +170,7 @@ fn build_borrowck_dataflow_data<'a, 'c, 'tcx, F>(this: &mut BorrowckCtxt<'a, 'tc
     if !force_analysis && move_data.is_empty() && all_loans.is_empty() {
         // large arrays of data inserted as constants can take a lot of
         // time and memory to borrow-check - see issue #36799. However,
-        // they don't have lvalues, so no borrow-check is actually needed.
+        // they don't have places, so no borrow-check is actually needed.
         // Recognize that case and skip borrow-checking.
         debug!("skipping loan propagation for {:?} because of no loans", body_id);
         return None;
@@ -384,9 +384,9 @@ fn cleaned(self) -> InteriorKind {
 }
 
 // This can be:
-// - a pointer dereference (`*LV` in README.md)
+// - a pointer dereference (`*P` in README.md)
 // - a field reference, with an optional definition of the containing
-//   enum variant (`LV.f` in README.md)
+//   enum variant (`P.f` in README.md)
 // `DefId` is present when the field is part of struct that is in
 // a variant of an enum. For instance in:
 // `enum E { X { foo: u32 }, Y { foo: u32 }}`
@@ -1276,7 +1276,8 @@ fn report_out_of_scope_escaping_closure_capture(&self,
     fn region_end_span(&self, region: ty::Region<'tcx>) -> Option<Span> {
         match *region {
             ty::ReScope(scope) => {
-                Some(scope.span(self.tcx, &self.region_scope_tree).end_point())
+                Some(self.tcx.sess.codemap().end_point(
+                        scope.span(self.tcx, &self.region_scope_tree)))
             }
             _ => None
         }
index 98de394ae3967cbe67a9493989f96747e385c5bb..a90dcd1072f9513d5319650ffebbb4f7074fb815 100644 (file)
@@ -153,7 +153,7 @@ pub struct Assignment {
     /// span of node where assignment occurs
     pub span: Span,
 
-    /// id for l-value expression on lhs of assignment
+    /// id for place expression on lhs of assignment
     pub assignee_id: hir::ItemLocalId,
 }
 
index ddee122d0a6bd1a4d91d7a248892ced94b2a7bff..7bcd8a185453b11004648411493a1bf70febb5dd 100644 (file)
@@ -77,7 +77,7 @@ fn check_unused_mut_pat(&self, pats: &[P<hir::Pat>]) {
                 continue
             }
 
-            let mut_span = tcx.sess.codemap().span_until_char(ids[0].2, ' ');
+            let mut_span = tcx.sess.codemap().span_until_non_whitespace(ids[0].2);
 
             // Ok, every name wasn't used mutably, so issue a warning that this
             // didn't need to be mutable.
index fd171b89924701f7a268edc9c37f0dd46603646c..ae53ed0e1140d1226e4ba29f8ba45041ad13c40e 100644 (file)
@@ -127,13 +127,16 @@ fn visit_body(&mut self, body: &'tcx hir::Body) {
     }
 }
 
+
 impl<'a, 'tcx> PatternContext<'a, 'tcx> {
     fn report_inlining_errors(&self, pat_span: Span) {
         for error in &self.errors {
             match *error {
                 PatternError::StaticInPattern(span) => {
-                    span_err!(self.tcx.sess, span, E0158,
-                              "statics cannot be referenced in patterns");
+                    self.span_e0158(span, "statics cannot be referenced in patterns")
+                }
+                PatternError::AssociatedConstInPattern(span) => {
+                    self.span_e0158(span, "associated consts cannot be referenced in patterns")
                 }
                 PatternError::ConstEval(ref err) => {
                     err.report(self.tcx, pat_span, "pattern");
@@ -141,6 +144,10 @@ fn report_inlining_errors(&self, pat_span: Span) {
             }
         }
     }
+
+    fn span_e0158(&self, span: Span, text: &str) {
+        span_err!(self.tcx.sess, span, E0158, "{}", text)
+    }
 }
 
 impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
index 3577feaf90c1abb2b7a1040f6c61aa8b131f55bc..e0b3929e32a8d9686b3cc0b9cfb0fabf6d622dad 100644 (file)
@@ -27,6 +27,7 @@
 
 #[derive(Clone, Debug)]
 pub enum PatternError<'tcx> {
+    AssociatedConstInPattern(Span),
     StaticInPattern(Span),
     ConstEval(ConstEvalErr<'tcx>),
 }
@@ -635,6 +636,10 @@ fn lower_path(&mut self,
                   -> Pattern<'tcx> {
         let ty = self.tables.node_id_to_type(id);
         let def = self.tables.qpath_def(qpath, id);
+        let is_associated_const = match def {
+            Def::AssociatedConst(_) => true,
+            _ => false,
+        };
         let kind = match def {
             Def::Const(def_id) | Def::AssociatedConst(def_id) => {
                 let substs = self.tables.node_substs(id);
@@ -656,7 +661,11 @@ fn lower_path(&mut self,
                         return pat;
                     }
                     None => {
-                        self.errors.push(PatternError::StaticInPattern(span));
+                        self.errors.push(if is_associated_const {
+                            PatternError::AssociatedConstInPattern(span)
+                        } else {
+                            PatternError::StaticInPattern(span)
+                        });
                         PatternKind::Wild
                     }
                 }
index 94edaa746f915b08a6d2f83f77888288e4affd72..80cdb0e441790fac9971f6668e3135b25af6b9f6 100644 (file)
@@ -51,6 +51,17 @@ pub fn insert(&mut self, bit: usize) -> bool {
         new_value != value
     }
 
+    /// Returns true if the bit has changed.
+    #[inline]
+    pub fn remove(&mut self, bit: usize) -> bool {
+        let (word, mask) = word_mask(bit);
+        let data = &mut self.data[word];
+        let value = *data;
+        let new_value = value & !mask;
+        *data = new_value;
+        new_value != value
+    }
+
     #[inline]
     pub fn insert_all(&mut self, all: &BitVector) -> bool {
         assert!(self.data.len() == all.data.len());
index 4f7bbd7927575ac8b92c69be9b35d2b426a996b7..18493b8bb39406cab6e41d8b9a48c44a6dc93d97 100644 (file)
@@ -11,7 +11,7 @@ crate-type = ["dylib"]
 [dependencies]
 arena = { path = "../libarena" }
 graphviz = { path = "../libgraphviz" }
-log = { version = "0.4", features = ["release_max_level_info"] }
+log = "0.4"
 env_logger = { version = "0.4", default-features = false }
 rustc = { path = "../librustc" }
 rustc_allocator = { path = "../librustc_allocator" }
@@ -29,7 +29,6 @@ rustc_plugin = { path = "../librustc_plugin" }
 rustc_privacy = { path = "../librustc_privacy" }
 rustc_resolve = { path = "../librustc_resolve" }
 rustc_save_analysis = { path = "../librustc_save_analysis" }
-rustc_trans = { path = "../librustc_trans", optional = true }
 rustc_trans_utils = { path = "../librustc_trans_utils" }
 rustc_typeck = { path = "../librustc_typeck" }
 serialize = { path = "../libserialize" }
@@ -38,6 +37,3 @@ syntax_ext = { path = "../libsyntax_ext" }
 syntax_pos = { path = "../libsyntax_pos" }
 
 ar = "0.3.0"
-
-[features]
-llvm = ["rustc_trans"]
index cdb50a0ae48507a90d180fb1b9e32aaaa4f9a4c5..05dcaf731352a36074af2240764ca8c328d324b8 100644 (file)
@@ -47,8 +47,6 @@
 extern crate rustc_mir;
 extern crate rustc_resolve;
 extern crate rustc_save_analysis;
-#[cfg(feature="llvm")]
-pub extern crate rustc_trans;
 extern crate rustc_trans_utils;
 extern crate rustc_typeck;
 extern crate serialize;
 use rustc::session::CompileIncomplete;
 use rustc::session::config::{Input, PrintRequest, ErrorOutputType};
 use rustc::session::config::nightly_options;
+use rustc::session::filesearch;
 use rustc::session::{early_error, early_warn};
 use rustc::lint::Lint;
 use rustc::lint;
 use rustc::middle::cstore::CrateStore;
 use rustc_metadata::locator;
 use rustc_metadata::cstore::CStore;
+use rustc_metadata::dynamic_lib::DynamicLibrary;
 use rustc::util::common::{time, ErrorReported};
 use rustc_trans_utils::trans_crate::TransCrate;
 
 use serialize::json::ToJson;
 
 use std::any::Any;
-use std::cmp::max;
 use std::cmp::Ordering::Equal;
+use std::cmp::max;
 use std::default::Default;
+use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
 use std::env;
 use std::ffi::OsString;
 use std::io::{self, Read, Write};
 use std::iter::repeat;
+use std::mem;
 use std::panic;
-use std::path::PathBuf;
+use std::path::{PathBuf, Path};
 use std::process::{self, Command, Stdio};
 use std::rc::Rc;
 use std::str;
+use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
+use std::sync::{Once, ONCE_INIT};
 use std::thread;
 
 use syntax::ast;
@@ -163,7 +167,8 @@ pub fn run<F>(run_compiler: F) -> isize
                     let emitter =
                         errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto,
                                                                None,
-                                                               true);
+                                                               true,
+                                                               false);
                     let handler = errors::Handler::with_emitter(true, false, Box::new(emitter));
                     handler.emit(&MultiSpan::new(),
                                  "aborting due to previous error(s)",
@@ -176,57 +181,246 @@ pub fn run<F>(run_compiler: F) -> isize
     0
 }
 
-#[cfg(not(feature="llvm"))]
-pub use rustc_trans_utils::trans_crate::MetadataOnlyTransCrate as DefaultTransCrate;
-#[cfg(feature="llvm")]
-pub use rustc_trans::LlvmTransCrate as DefaultTransCrate;
+fn load_backend_from_dylib(path: &Path) -> fn() -> Box<TransCrate> {
+    // Note that we're specifically using `open_global_now` here rather than
+    // `open`, namely we want the behavior on Unix of RTLD_GLOBAL and RTLD_NOW,
+    // where NOW means "bind everything right now" because we don't want
+    // surprises later on and RTLD_GLOBAL allows the symbols to be made
+    // available for future dynamic libraries opened. This is currently used by
+    // loading LLVM and then making its symbols available for other dynamic
+    // libraries.
+    let lib = match DynamicLibrary::open_global_now(path) {
+        Ok(lib) => lib,
+        Err(err) => {
+            let err = format!("couldn't load codegen backend {:?}: {:?}",
+                              path,
+                              err);
+            early_error(ErrorOutputType::default(), &err);
+        }
+    };
+    unsafe {
+        match lib.symbol("__rustc_codegen_backend") {
+            Ok(f) => {
+                mem::forget(lib);
+                mem::transmute::<*mut u8, _>(f)
+            }
+            Err(e) => {
+                let err = format!("couldn't load codegen backend as it \
+                                   doesn't export the `__rustc_codegen_backend` \
+                                   symbol: {:?}", e);
+                early_error(ErrorOutputType::default(), &err);
+            }
+        }
+    }
+}
 
-#[cfg(not(feature="llvm"))]
-pub mod rustc_trans {
-    pub use rustc_trans_utils::trans_crate::MetadataOnlyTransCrate as LlvmTransCrate;
+pub fn get_trans(sess: &Session) -> Box<TransCrate> {
+    static INIT: Once = ONCE_INIT;
+    static mut LOAD: fn() -> Box<TransCrate> = || unreachable!();
+
+    INIT.call_once(|| {
+        let trans_name = sess.opts.debugging_opts.codegen_backend.as_ref()
+            .unwrap_or(&sess.target.target.options.codegen_backend);
+        let backend = match &trans_name[..] {
+            "metadata_only" => {
+                rustc_trans_utils::trans_crate::MetadataOnlyTransCrate::new
+            }
+            filename if filename.contains(".") => {
+                load_backend_from_dylib(filename.as_ref())
+            }
+            trans_name => get_trans_sysroot(trans_name),
+        };
 
-    pub fn print_version() {}
-    pub fn print_passes() {}
+        unsafe {
+            LOAD = backend;
+        }
+    });
+    let backend = unsafe { LOAD() };
+    backend.init(sess);
+    backend
 }
 
-fn load_backend_from_dylib(sess: &Session, backend_name: &str) -> Box<TransCrate> {
-    use std::path::Path;
-    use rustc_metadata::dynamic_lib::DynamicLibrary;
-
-    match DynamicLibrary::open(Some(Path::new(backend_name))) {
-        Ok(lib) => {
-            unsafe {
-                let trans = {
-                    let __rustc_codegen_backend: unsafe fn(&Session) -> Box<TransCrate>;
-                    __rustc_codegen_backend = match lib.symbol("__rustc_codegen_backend") {
-                        Ok(f) => ::std::mem::transmute::<*mut u8, _>(f),
-                        Err(e) => sess.fatal(&format!("Couldnt load codegen backend as it\
-                        doesn't export the __rustc_backend_new symbol: {:?}", e)),
-                    };
-                    __rustc_codegen_backend(sess)
-                };
-                ::std::mem::forget(lib);
-                trans
+fn get_trans_sysroot(backend_name: &str) -> fn() -> Box<TransCrate> {
+    // For now we only allow this function to be called once as it'll dlopen a
+    // few things, which seems to work best if we only do that once. In
+    // general this assertion never trips due to the once guard in `get_trans`,
+    // but there's a few manual calls to this function in this file we protect
+    // against.
+    static LOADED: AtomicBool = ATOMIC_BOOL_INIT;
+    assert!(!LOADED.fetch_or(true, Ordering::SeqCst),
+            "cannot load the default trans backend twice");
+
+    // When we're compiling this library with `--test` it'll run as a binary but
+    // not actually exercise much functionality. As a result most of the logic
+    // here is defunkt (it assumes we're a dynamic library in a sysroot) so
+    // let's just return a dummy creation function which won't be used in
+    // general anyway.
+    if cfg!(test) {
+        return rustc_trans_utils::trans_crate::MetadataOnlyTransCrate::new
+    }
+
+    let target = session::config::host_triple();
+    let mut sysroot_candidates = vec![filesearch::get_or_default_sysroot()];
+    let path = current_dll_path()
+        .and_then(|s| s.canonicalize().ok());
+    if let Some(dll) = path {
+        // use `parent` twice to chop off the file name and then also the
+        // directory containing the dll which should be either `lib` or `bin`.
+        if let Some(path) = dll.parent().and_then(|p| p.parent()) {
+            // The original `path` pointed at the `rustc_driver` crate's dll.
+            // Now that dll should only be in one of two locations. The first is
+            // in the compiler's libdir, for example `$sysroot/lib/*.dll`. The
+            // other is the target's libdir, for example
+            // `$sysroot/lib/rustlib/$target/lib/*.dll`.
+            //
+            // We don't know which, so let's assume that if our `path` above
+            // ends in `$target` we *could* be in the target libdir, and always
+            // assume that we may be in the main libdir.
+            sysroot_candidates.push(path.to_owned());
+
+            if path.ends_with(target) {
+                sysroot_candidates.extend(path.parent() // chop off `$target`
+                    .and_then(|p| p.parent())           // chop off `rustlib`
+                    .and_then(|p| p.parent())           // chop off `lib`
+                    .map(|s| s.to_owned()));
             }
         }
-        Err(err) => {
-            sess.fatal(&format!("Couldnt load codegen backend {:?}: {:?}", backend_name, err));
+    }
+
+    let sysroot = sysroot_candidates.iter()
+        .map(|sysroot| {
+            let libdir = filesearch::relative_target_lib_path(&sysroot, &target);
+            sysroot.join(libdir).with_file_name("codegen-backends")
+        })
+        .filter(|f| {
+            info!("codegen backend candidate: {}", f.display());
+            f.exists()
+        })
+        .next();
+    let sysroot = match sysroot {
+        Some(path) => path,
+        None => {
+            let candidates = sysroot_candidates.iter()
+                .map(|p| p.display().to_string())
+                .collect::<Vec<_>>()
+                .join("\n* ");
+            let err = format!("failed to find a `codegen-backends` folder \
+                               in the sysroot candidates:\n* {}", candidates);
+            early_error(ErrorOutputType::default(), &err);
+        }
+    };
+    info!("probing {} for a codegen backend", sysroot.display());
+
+    let d = match sysroot.read_dir() {
+        Ok(d) => d,
+        Err(e) => {
+            let err = format!("failed to load default codegen backend, couldn't \
+                               read `{}`: {}", sysroot.display(), e);
+            early_error(ErrorOutputType::default(), &err);
+        }
+    };
+
+    let mut file: Option<PathBuf> = None;
+
+    let expected_name = format!("rustc_trans-{}", backend_name);
+    for entry in d.filter_map(|e| e.ok()) {
+        let path = entry.path();
+        let filename = match path.file_name().and_then(|s| s.to_str()) {
+            Some(s) => s,
+            None => continue,
+        };
+        if !(filename.starts_with(DLL_PREFIX) && filename.ends_with(DLL_SUFFIX)) {
+            continue
+        }
+        let name = &filename[DLL_PREFIX.len() .. filename.len() - DLL_SUFFIX.len()];
+        if name != expected_name {
+            continue
         }
+        if let Some(ref prev) = file {
+            let err = format!("duplicate codegen backends found\n\
+                first:  {}\n\
+                second: {}\n\
+            ", prev.display(), path.display());
+            early_error(ErrorOutputType::default(), &err);
+        }
+        file = Some(path.clone());
     }
-}
 
-pub fn get_trans(sess: &Session) -> Box<TransCrate> {
-    let trans_name = sess.opts.debugging_opts.codegen_backend.clone();
-    match trans_name.as_ref().map(|s|&**s) {
-        None => DefaultTransCrate::new(&sess),
-        Some("llvm") => rustc_trans::LlvmTransCrate::new(&sess),
-        Some("metadata_only") => {
-            rustc_trans_utils::trans_crate::MetadataOnlyTransCrate::new(&sess)
+    match file {
+        Some(ref s) => return load_backend_from_dylib(s),
+        None => {
+            let err = format!("failed to load default codegen backend for `{}`, \
+                               no appropriate codegen dylib found in `{}`",
+                               backend_name, sysroot.display());
+            early_error(ErrorOutputType::default(), &err);
+        }
+    }
+
+    #[cfg(unix)]
+    fn current_dll_path() -> Option<PathBuf> {
+        use std::ffi::{OsStr, CStr};
+        use std::os::unix::prelude::*;
+
+        unsafe {
+            let addr = current_dll_path as usize as *mut _;
+            let mut info = mem::zeroed();
+            if libc::dladdr(addr, &mut info) == 0 {
+                info!("dladdr failed");
+                return None
+            }
+            if info.dli_fname.is_null() {
+                info!("dladdr returned null pointer");
+                return None
+            }
+            let bytes = CStr::from_ptr(info.dli_fname).to_bytes();
+            let os = OsStr::from_bytes(bytes);
+            Some(PathBuf::from(os))
         }
-        Some(filename) if filename.contains(".") => {
-            load_backend_from_dylib(&sess, &filename)
+    }
+
+    #[cfg(windows)]
+    fn current_dll_path() -> Option<PathBuf> {
+        use std::ffi::OsString;
+        use std::os::windows::prelude::*;
+
+        extern "system" {
+            fn GetModuleHandleExW(dwFlags: u32,
+                                  lpModuleName: usize,
+                                  phModule: *mut usize) -> i32;
+            fn GetModuleFileNameW(hModule: usize,
+                                  lpFilename: *mut u16,
+                                  nSize: u32) -> u32;
+        }
+
+        const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS: u32 = 0x00000004;
+
+        unsafe {
+            let mut module = 0;
+            let r = GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+                                       current_dll_path as usize,
+                                       &mut module);
+            if r == 0 {
+                info!("GetModuleHandleExW failed: {}", io::Error::last_os_error());
+                return None
+            }
+            let mut space = Vec::with_capacity(1024);
+            let r = GetModuleFileNameW(module,
+                                       space.as_mut_ptr(),
+                                       space.capacity() as u32);
+            if r == 0 {
+                info!("GetModuleFileNameW failed: {}", io::Error::last_os_error());
+                return None
+            }
+            let r = r as usize;
+            if r >= space.capacity() {
+                info!("our buffer was too small? {}",
+                      io::Error::last_os_error());
+                return None
+            }
+            space.set_len(r);
+            let os = OsString::from_wide(&space);
+            Some(PathBuf::from(os))
         }
-        Some(trans_name) => sess.fatal(&format!("Unknown codegen backend {}", trans_name)),
     }
 }
 
@@ -263,10 +457,13 @@ macro_rules! do_or_return {($expr: expr, $sess: expr) => {
                                            None);
 
     let (odir, ofile) = make_output(&matches);
-    let (input, input_file_path) = match make_input(&matches.free) {
-        Some((input, input_file_path)) => callbacks.some_input(input, input_file_path),
+    let (input, input_file_path, input_err) = match make_input(&matches.free) {
+        Some((input, input_file_path, input_err)) => {
+            let (input, input_file_path) = callbacks.some_input(input, input_file_path);
+            (input, input_file_path, input_err)
+        },
         None => match callbacks.no_input(&matches, &sopts, &cfg, &odir, &ofile, &descriptions) {
-            Some((input, input_file_path)) => (input, input_file_path),
+            Some((input, input_file_path)) => (input, input_file_path, None),
             None => return (Ok(()), None),
         },
     };
@@ -277,6 +474,13 @@ macro_rules! do_or_return {($expr: expr, $sess: expr) => {
         sopts, input_file_path.clone(), descriptions, codemap, emitter_dest,
     );
 
+    if let Some(err) = input_err {
+        // Immediately stop compilation if there was an issue reading
+        // the input (for example if the input stream is not UTF-8).
+        sess.err(&format!("{}", err));
+        return (Err(CompileIncomplete::Stopped), Some(sess));
+    }
+
     let trans = get_trans(&sess);
 
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
@@ -319,17 +523,22 @@ fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>)
 }
 
 // Extract input (string or file and optional path) from matches.
-fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>)> {
+fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>, Option<io::Error>)> {
     if free_matches.len() == 1 {
         let ifile = &free_matches[0];
         if ifile == "-" {
             let mut src = String::new();
-            io::stdin().read_to_string(&mut src).unwrap();
+            let err = if io::stdin().read_to_string(&mut src).is_err() {
+                Some(io::Error::new(io::ErrorKind::InvalidData,
+                                    "couldn't read from stdin, as it did not contain valid UTF-8"))
+            } else {
+                None
+            };
             Some((Input::Str { name: FileName::Anon, input: src },
-                  None))
+                  None, err))
         } else {
             Some((Input::File(PathBuf::from(ifile)),
-                  Some(PathBuf::from(ifile))))
+                  Some(PathBuf::from(ifile)), None))
         }
     } else {
         None
@@ -878,7 +1087,7 @@ fn unw(x: Option<&str>) -> &str {
         println!("commit-date: {}", unw(commit_date_str()));
         println!("host: {}", config::host_triple());
         println!("release: {}", unw(release_str()));
-        rustc_trans::print_version();
+        get_trans_sysroot("llvm")().print_version();
     }
 }
 
@@ -1175,7 +1384,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
     }
 
     if cg_flags.contains(&"passes=list".to_string()) {
-        rustc_trans::print_passes();
+        get_trans_sysroot("llvm")().print_passes();
         return None;
     }
 
@@ -1241,6 +1450,7 @@ pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
             let emitter =
                 Box::new(errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto,
                                                                 None,
+                                                                false,
                                                                 false));
             let handler = errors::Handler::with_emitter(true, false, emitter);
 
@@ -1284,8 +1494,8 @@ pub fn diagnostics_registry() -> errors::registry::Registry {
     all_errors.extend_from_slice(&rustc_typeck::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS);
-    #[cfg(feature="llvm")]
-    all_errors.extend_from_slice(&rustc_trans::DIAGNOSTICS);
+    // FIXME: need to figure out a way to get these back in here
+    // all_errors.extend_from_slice(get_trans(sess).diagnostics());
     all_errors.extend_from_slice(&rustc_trans_utils::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS);
index 68f4b17a6a3f24a8f7b99bc46052f3df7f7c912c..4ae6a93d6983a12bd8535c7b19f1fca136ce4401 100644 (file)
@@ -228,7 +228,8 @@ fn call_with_pp_support_hir<'tcx, A, F>(&self,
             }
             PpmTyped => {
                 let control = &driver::CompileController::basic();
-                abort_on_err(driver::phase_3_run_analysis_passes(&*::DefaultTransCrate::new(&sess),
+                let trans = ::get_trans(sess);
+                abort_on_err(driver::phase_3_run_analysis_passes(&*trans,
                                                                  control,
                                                                  sess,
                                                                  cstore,
@@ -1081,7 +1082,8 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
     let mut out = Vec::new();
 
     let control = &driver::CompileController::basic();
-    abort_on_err(driver::phase_3_run_analysis_passes(&*::DefaultTransCrate::new(&sess),
+    let trans = ::get_trans(sess);
+    abort_on_err(driver::phase_3_run_analysis_passes(&*trans,
                                                      control,
                                                      sess,
                                                      cstore,
index 2e654fe9929a6af7801755994f0dcc8147c29043..40e4efb397d305087b223e4cad8d8143f3d771a7 100644 (file)
@@ -222,6 +222,7 @@ pub fn span_suggestion_short(&mut self, sp: Span, msg: &str, suggestion: String)
             }],
             msg: msg.to_owned(),
             show_code_when_inline: false,
+            approximate: false,
         });
         self
     }
@@ -252,6 +253,7 @@ pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &m
             }],
             msg: msg.to_owned(),
             show_code_when_inline: true,
+            approximate: false,
         });
         self
     }
@@ -267,6 +269,41 @@ pub fn span_suggestions(&mut self, sp: Span, msg: &str, suggestions: Vec<String>
             }).collect(),
             msg: msg.to_owned(),
             show_code_when_inline: true,
+            approximate: false,
+        });
+        self
+    }
+
+    /// This is a suggestion that may contain mistakes or fillers and should
+    /// be read and understood by a human.
+    pub fn span_approximate_suggestion(&mut self, sp: Span, msg: &str,
+                                       suggestion: String) -> &mut Self {
+        self.suggestions.push(CodeSuggestion {
+            substitutions: vec![Substitution {
+                parts: vec![SubstitutionPart {
+                    snippet: suggestion,
+                    span: sp,
+                }],
+            }],
+            msg: msg.to_owned(),
+            show_code_when_inline: true,
+            approximate: true,
+        });
+        self
+    }
+
+    pub fn span_approximate_suggestions(&mut self, sp: Span, msg: &str,
+                                        suggestions: Vec<String>) -> &mut Self {
+        self.suggestions.push(CodeSuggestion {
+            substitutions: suggestions.into_iter().map(|snippet| Substitution {
+                parts: vec![SubstitutionPart {
+                    snippet,
+                    span: sp,
+                }],
+            }).collect(),
+            msg: msg.to_owned(),
+            show_code_when_inline: true,
+            approximate: true,
         });
         self
     }
index 61674ada6fa63c1bc37a7ff3e7b09d92a57801e7..2536fc648c70ad693f8356b6dfc8d2bf9345e11f 100644 (file)
@@ -186,6 +186,16 @@ pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self
                                      msg: &str,
                                      suggestions: Vec<String>)
                                      -> &mut Self);
+    forward!(pub fn span_approximate_suggestion(&mut self,
+                                                sp: Span,
+                                                msg: &str,
+                                                suggestion: String)
+                                                -> &mut Self);
+    forward!(pub fn span_approximate_suggestions(&mut self,
+                                                 sp: Span,
+                                                 msg: &str,
+                                                 suggestions: Vec<String>)
+                                                 -> &mut Self);
     forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
     forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
 
index 58f851aea3817e44d81b8a1735ea9d5c6fb4c6b9..a49284eb55a465aae7d0aae87744fc34833530db 100644 (file)
@@ -106,6 +106,7 @@ pub struct EmitterWriter {
     dst: Destination,
     cm: Option<Rc<CodeMapper>>,
     short_message: bool,
+    teach: bool,
 }
 
 struct FileWithAnnotatedLines {
@@ -117,32 +118,37 @@ struct FileWithAnnotatedLines {
 impl EmitterWriter {
     pub fn stderr(color_config: ColorConfig,
                   code_map: Option<Rc<CodeMapper>>,
-                  short_message: bool)
+                  short_message: bool,
+                  teach: bool)
                   -> EmitterWriter {
         if color_config.use_color() {
             let dst = Destination::from_stderr();
             EmitterWriter {
                 dst,
                 cm: code_map,
-                short_message: short_message,
+                short_message,
+                teach,
             }
         } else {
             EmitterWriter {
                 dst: Raw(Box::new(io::stderr())),
                 cm: code_map,
-                short_message: short_message,
+                short_message,
+                teach,
             }
         }
     }
 
     pub fn new(dst: Box<Write + Send>,
                code_map: Option<Rc<CodeMapper>>,
-               short_message: bool)
+               short_message: bool,
+               teach: bool)
                -> EmitterWriter {
         EmitterWriter {
             dst: Raw(dst),
             cm: code_map,
-            short_message: short_message,
+            short_message,
+            teach,
         }
     }
 
@@ -284,6 +290,10 @@ fn render_source_line(&self,
                           line: &Line,
                           width_offset: usize,
                           code_offset: usize) -> Vec<(usize, Style)> {
+        if line.line_index == 0 {
+            return Vec::new();
+        }
+
         let source_string = match file.get_line(line.line_index - 1) {
             Some(s) => s,
             None => return Vec::new(),
@@ -551,7 +561,14 @@ fn render_source_line(&self,
                                code_offset + annotation.start_col,
                                style);
                 }
-                _ => (),
+                _ if self.teach => {
+                    buffer.set_style_range(line_offset,
+                                           code_offset + annotation.start_col,
+                                           code_offset + annotation.end_col,
+                                           style,
+                                           annotation.is_primary);
+                }
+                _ => {}
             }
         }
 
@@ -767,6 +784,7 @@ fn fix_multispan_in_std_macros(&mut self,
                         }
                         // Check to make sure we're not in any <*macros>
                         if !cm.span_to_filename(def_site).is_macros() &&
+                           !trace.macro_decl_name.starts_with("desugaring of ") &&
                            !trace.macro_decl_name.starts_with("#[") ||
                            always_backtrace {
                             new_labels.push((trace.call_site,
@@ -1013,8 +1031,21 @@ fn emit_message_default(&mut self,
 
                 // Then, the secondary file indicator
                 buffer.prepend(buffer_msg_line_offset + 1, "::: ", Style::LineNumber);
+                let loc = if let Some(first_line) = annotated_file.lines.first() {
+                    let col = if let Some(first_annotation) = first_line.annotations.first() {
+                        format!(":{}", first_annotation.start_col + 1)
+                    } else {
+                        "".to_string()
+                    };
+                    format!("{}:{}{}",
+                            annotated_file.file.name,
+                            cm.doctest_offset_line(first_line.line_index),
+                            col)
+                } else {
+                    annotated_file.file.name.to_string()
+                };
                 buffer.append(buffer_msg_line_offset + 1,
-                              &annotated_file.file.name.to_string(),
+                              &loc,
                               Style::LineAndColumn);
                 for _ in 0..max_line_num_len {
                     buffer.prepend(buffer_msg_line_offset + 1, " ", Style::NoStyle);
index 3d50c95d3f4f9857d542155d2518474ca84fcaff..236698ed2d45d77ba5099953daf89ba83b626201 100644 (file)
@@ -83,6 +83,12 @@ pub struct CodeSuggestion {
     pub substitutions: Vec<Substitution>,
     pub msg: String,
     pub show_code_when_inline: bool,
+    /// Whether or not the suggestion is approximate
+    ///
+    /// Sometimes we may show suggestions with placeholders,
+    /// which are useful for users but not useful for
+    /// tools like rustfix
+    pub approximate: bool,
 }
 
 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
@@ -297,7 +303,7 @@ pub fn with_tty_emitter_and_flags(color_config: ColorConfig,
                                       cm: Option<Rc<CodeMapper>>,
                                       flags: HandlerFlags)
                                       -> Handler {
-        let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false));
+        let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false));
         Handler::with_emitter_and_flags(emitter, flags)
     }
 
index c2f4701999ea90aa01928079718b42487fc0ada7..6035f33c822cee1eedf6b87ad412c1b4d9f87fb8 100644 (file)
@@ -27,7 +27,8 @@ pub struct FileInfo {
 
     /// The "primary file", if any, gets a `-->` marker instead of
     /// `>>>`, and has a line-number/column printed and not just a
-    /// filename.  It appears first in the listing. It is known to
+    /// filename (other files are not guaranteed to have line numbers
+    /// or columns). It appears first in the listing. It is known to
     /// contain at least one primary span, though primary spans (which
     /// are designated with `^^^`) may also occur in other files.
     primary_span: Option<Span>,
index 2c33f80520360a83fa741b114d4f7d56c3b4c46d..2c736ec22c3b3fd76b97e47dafe1848b3ebd6fac 100644 (file)
@@ -144,4 +144,25 @@ pub fn append(&mut self, line: usize, string: &str, style: Style) {
     pub fn num_lines(&self) -> usize {
         self.text.len()
     }
+
+    pub fn set_style_range(&mut self,
+                           line: usize,
+                           col_start: usize,
+                           col_end: usize,
+                           style: Style,
+                           overwrite: bool) {
+        for col in col_start..col_end {
+            self.set_style(line, col, style, overwrite);
+        }
+    }
+
+    pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
+        if let Some(ref mut line) = self.styles.get_mut(line) {
+            if let Some(s) = line.get_mut(col) {
+                if *s == Style::NoStyle || *s == Style::Quotation || overwrite {
+                    *s = style;
+                }
+            }
+        }
+    }
 }
index a9566c4bcacd7e791d2ac470632e4c46714b7bdb..0978c2ceb141d785b634e278112dc3414b903843 100644 (file)
@@ -7,13 +7,14 @@ build = "build.rs"
 [lib]
 name = "rustc_llvm"
 path = "lib.rs"
-crate-type = ["dylib"]
 
 [features]
 static-libstdcpp = []
+emscripten = []
 
 [dependencies]
 bitflags = "1.0"
+libc = "0.2"
 rustc_cratesio_shim = { path = "../librustc_cratesio_shim" }
 
 [build-dependencies]
index 91dc3210e11abc025d5671947f3f1eea0eccf149..49b93f3c7d6a248fd37b9020a5b606b582ef6849 100644 (file)
@@ -146,6 +146,7 @@ fn main() {
         cfg.define(&flag, None);
     }
 
+    println!("cargo:rerun-if-changed-env=LLVM_RUSTLLVM");
     if env::var_os("LLVM_RUSTLLVM").is_some() {
         cfg.define("LLVM_RUSTLLVM", None);
     }
index 1b42fa03a4fb621e3957708aac4424e122c4c670..d7da0d00012e15261e1ffd2f4c7df5271bf374a6 100644 (file)
@@ -38,7 +38,17 @@ pub fn open(filename: Option<&Path>) -> Result<DynamicLibrary, String> {
         // run.
         match maybe_library {
             Err(err) => Err(err),
-            Ok(handle) => Ok(DynamicLibrary { handle: handle })
+            Ok(handle) => Ok(DynamicLibrary { handle })
+        }
+    }
+
+    /// Load a dynamic library into the global namespace (RTLD_GLOBAL on Unix)
+    /// and do it now (don't use RTLD_LAZY on Unix).
+    pub fn open_global_now(filename: &Path) -> Result<DynamicLibrary, String> {
+        let maybe_library = dl::open_global_now(filename.as_os_str());
+        match maybe_library {
+            Err(err) => Err(err),
+            Ok(handle) => Ok(DynamicLibrary { handle })
         }
     }
 
@@ -145,15 +155,20 @@ pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
         })
     }
 
-    const LAZY: libc::c_int = 1;
+    pub fn open_global_now(filename: &OsStr) -> Result<*mut u8, String> {
+        check_for_errors_in(|| unsafe {
+            let s = CString::new(filename.as_bytes()).unwrap();
+            libc::dlopen(s.as_ptr(), libc::RTLD_GLOBAL | libc::RTLD_NOW) as *mut u8
+        })
+    }
 
     unsafe fn open_external(filename: &OsStr) -> *mut u8 {
         let s = CString::new(filename.as_bytes()).unwrap();
-        libc::dlopen(s.as_ptr(), LAZY) as *mut u8
+        libc::dlopen(s.as_ptr(), libc::RTLD_LAZY) as *mut u8
     }
 
     unsafe fn open_internal() -> *mut u8 {
-        libc::dlopen(ptr::null(), LAZY) as *mut u8
+        libc::dlopen(ptr::null(), libc::RTLD_LAZY) as *mut u8
     }
 
     pub fn check_for_errors_in<T, F>(f: F) -> Result<T, String> where
@@ -224,6 +239,10 @@ fn GetProcAddress(handle: HMODULE,
         fn FreeLibrary(handle: HMODULE) -> BOOL;
     }
 
+    pub fn open_global_now(filename: &OsStr) -> Result<*mut u8, String> {
+        open(Some(filename))
+    }
+
     pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
         // disable "dll load failed" error dialog.
         let prev_error_mode = unsafe {
index 61d6c14d6273054830834b743a444f9770d0f075..ba966c9d4e3166f1c729e86dc82c5210820dac5c 100644 (file)
@@ -15,8 +15,8 @@
 
 use rustc::mir::{BasicBlock, Location};
 
-use dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
-use dataflow::{EverInitializedLvals, MovingOutStatements};
+use dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
+use dataflow::{EverInitializedPlaces, MovingOutStatements};
 use dataflow::{ActiveBorrows, FlowAtLocation, FlowsAtLocation};
 use dataflow::move_paths::HasMoveData;
 use std::fmt;
 // (forced to be `pub` due to its use as an associated type below.)
 pub(crate) struct Flows<'b, 'gcx: 'tcx, 'tcx: 'b> {
     pub borrows: FlowAtLocation<ActiveBorrows<'b, 'gcx, 'tcx>>,
-    pub inits: FlowAtLocation<MaybeInitializedLvals<'b, 'gcx, 'tcx>>,
-    pub uninits: FlowAtLocation<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>,
+    pub inits: FlowAtLocation<MaybeInitializedPlaces<'b, 'gcx, 'tcx>>,
+    pub uninits: FlowAtLocation<MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
     pub move_outs: FlowAtLocation<MovingOutStatements<'b, 'gcx, 'tcx>>,
-    pub ever_inits: FlowAtLocation<EverInitializedLvals<'b, 'gcx, 'tcx>>,
+    pub ever_inits: FlowAtLocation<EverInitializedPlaces<'b, 'gcx, 'tcx>>,
 }
 
 impl<'b, 'gcx, 'tcx> Flows<'b, 'gcx, 'tcx> {
     pub fn new(
         borrows: FlowAtLocation<ActiveBorrows<'b, 'gcx, 'tcx>>,
-        inits: FlowAtLocation<MaybeInitializedLvals<'b, 'gcx, 'tcx>>,
-        uninits: FlowAtLocation<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>,
+        inits: FlowAtLocation<MaybeInitializedPlaces<'b, 'gcx, 'tcx>>,
+        uninits: FlowAtLocation<MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
         move_outs: FlowAtLocation<MovingOutStatements<'b, 'gcx, 'tcx>>,
-        ever_inits: FlowAtLocation<EverInitializedLvals<'b, 'gcx, 'tcx>>,
+        ever_inits: FlowAtLocation<EverInitializedPlaces<'b, 'gcx, 'tcx>>,
     ) -> Self {
         Flows {
             borrows,
index d6937c405f961d91c95a64834f0edc26d2b950e5..9a6d83b8eb75904c81d2b45a128992cf328c4dde 100644 (file)
@@ -35,8 +35,8 @@
 use dataflow::FlowAtLocation;
 use dataflow::MoveDataParamEnv;
 use dataflow::{DataflowAnalysis, DataflowResultsConsumer};
-use dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
-use dataflow::{EverInitializedLvals, MovingOutStatements};
+use dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
+use dataflow::{EverInitializedPlaces, MovingOutStatements};
 use dataflow::{BorrowData, Borrows, ReserveOrActivateIndex};
 use dataflow::{ActiveBorrows, Reservations};
 use dataflow::indexes::BorrowIndex;
@@ -160,7 +160,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
         id,
         &attributes,
         &dead_unwinds,
-        MaybeInitializedLvals::new(tcx, mir, &mdpe),
+        MaybeInitializedPlaces::new(tcx, mir, &mdpe),
         |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
     ));
     let flow_uninits = FlowAtLocation::new(do_dataflow(
@@ -169,7 +169,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
         id,
         &attributes,
         &dead_unwinds,
-        MaybeUninitializedLvals::new(tcx, mir, &mdpe),
+        MaybeUninitializedPlaces::new(tcx, mir, &mdpe),
         |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
     ));
     let flow_move_outs = FlowAtLocation::new(do_dataflow(
@@ -187,7 +187,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
         id,
         &attributes,
         &dead_unwinds,
-        EverInitializedLvals::new(tcx, mir, &mdpe),
+        EverInitializedPlaces::new(tcx, mir, &mdpe),
         |bd, i| DebugFormatted::new(&bd.move_data().inits[i]),
     ));
 
@@ -607,7 +607,7 @@ enum ArtificialField {
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 enum ShallowOrDeep {
     /// From the RFC: "A *shallow* access means that the immediate
-    /// fields reached at LV are accessed, but references or pointers
+    /// fields reached at P are accessed, but references or pointers
     /// found within are not dereferenced. Right now, the only access
     /// that is shallow is an assignment like `x = ...;`, which would
     /// be a *shallow write* of `x`."
@@ -1112,10 +1112,11 @@ fn check_for_invalidation_at_exit(
             debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
             // FIXME: should be talking about the region lifetime instead
             // of just a span here.
+            let span = self.tcx.sess.codemap().end_point(span);
             self.report_borrowed_value_does_not_live_long_enough(
                 context,
                 borrow,
-                span.end_point(),
+                span,
                 flow_state.borrows.operator(),
             )
         }
index f96e107efa38fa76b374b3195908fec29072609f..66ca74b0139a31a31af1ae94c6272cf0ed8ebf60 100644 (file)
@@ -19,7 +19,7 @@
 use transform::MirSource;
 use util::liveness::{LivenessResults, LocalSet};
 use dataflow::FlowAtLocation;
-use dataflow::MaybeInitializedLvals;
+use dataflow::MaybeInitializedPlaces;
 use dataflow::move_paths::MoveData;
 
 use util as mir_util;
@@ -71,7 +71,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
     universal_regions: UniversalRegions<'tcx>,
     mir: &Mir<'tcx>,
     param_env: ty::ParamEnv<'gcx>,
-    flow_inits: &mut FlowAtLocation<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>,
+    flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'cx, 'gcx, 'tcx>>,
     move_data: &MoveData<'tcx>,
 ) -> (
     RegionInferenceContext<'tcx>,
index 9a2f98d4622f77eb00cfd2d2898e29d049b0af05..9a338947f4772272a21f9dd6f62dd9d2d6401e5f 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::collections::HashMap;
+
 use super::universal_regions::UniversalRegions;
 use rustc::hir::def_id::DefId;
 use rustc::infer::InferCtxt;
@@ -22,6 +24,7 @@
 use rustc::traits::ObligationCause;
 use rustc::ty::{self, RegionVid, Ty, TypeFoldable};
 use rustc::util::common::ErrorReported;
+use rustc_data_structures::bitvec::BitVector;
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc_errors::DiagnosticBuilder;
 use std::fmt;
@@ -452,8 +455,6 @@ pub(super) fn solve<'gcx>(
     /// satisfied. Note that some values may grow **too** large to be
     /// feasible, but we check this later.
     fn propagate_constraints(&mut self, mir: &Mir<'tcx>) {
-        let mut changed = true;
-
         debug!("propagate_constraints()");
         debug!("propagate_constraints: constraints={:#?}", {
             let mut constraints: Vec<_> = self.constraints.iter().collect();
@@ -465,37 +466,65 @@ fn propagate_constraints(&mut self, mir: &Mir<'tcx>) {
         // constraints we have accumulated.
         let mut inferred_values = self.liveness_constraints.clone();
 
-        while changed {
-            changed = false;
-            debug!("propagate_constraints: --------------------");
-            for constraint in &self.constraints {
-                debug!("propagate_constraints: constraint={:?}", constraint);
-
-                // Grow the value as needed to accommodate the
-                // outlives constraint.
-                let Ok(made_changes) = self.dfs(
-                    mir,
-                    CopyFromSourceToTarget {
-                        source_region: constraint.sub,
-                        target_region: constraint.sup,
-                        inferred_values: &mut inferred_values,
-                        constraint_point: constraint.point,
-                        constraint_span: constraint.span,
-                    },
-                );
+        let dependency_map = self.build_dependency_map();
+
+        // Constraints that may need to be repropagated (initially all):
+        let mut dirty_list: Vec<_> = (0..self.constraints.len()).collect();
+
+        // Set to 0 for each constraint that is on the dirty list:
+        let mut clean_bit_vec = BitVector::new(dirty_list.len());
+
+        debug!("propagate_constraints: --------------------");
+        while let Some(constraint_idx) = dirty_list.pop() {
+            clean_bit_vec.insert(constraint_idx);
+
+            let constraint = &self.constraints[constraint_idx];
+            debug!("propagate_constraints: constraint={:?}", constraint);
 
-                if made_changes {
-                    debug!("propagate_constraints:   sub={:?}", constraint.sub);
-                    debug!("propagate_constraints:   sup={:?}", constraint.sup);
-                    changed = true;
+            // Grow the value as needed to accommodate the
+            // outlives constraint.
+            let Ok(made_changes) = self.dfs(
+                mir,
+                CopyFromSourceToTarget {
+                    source_region: constraint.sub,
+                    target_region: constraint.sup,
+                    inferred_values: &mut inferred_values,
+                    constraint_point: constraint.point,
+                    constraint_span: constraint.span,
+                },
+            );
+
+            if made_changes {
+                debug!("propagate_constraints:   sub={:?}", constraint.sub);
+                debug!("propagate_constraints:   sup={:?}", constraint.sup);
+
+                for &dep_idx in dependency_map.get(&constraint.sup).unwrap_or(&vec![]) {
+                    if clean_bit_vec.remove(dep_idx) {
+                        dirty_list.push(dep_idx);
+                    }
                 }
             }
+
             debug!("\n");
         }
 
         self.inferred_values = Some(inferred_values);
     }
 
+    /// Builds up a map from each region variable X to a vector with the
+    /// indices of constraints that need to be re-evaluated when X changes.
+    /// These are constraints like Y: X @ P -- so if X changed, we may
+    /// need to grow Y.
+    fn build_dependency_map(&self) -> HashMap<RegionVid, Vec<usize>> {
+        let mut map = HashMap::new();
+
+        for (idx, constraint) in self.constraints.iter().enumerate() {
+            map.entry(constraint.sub).or_insert(Vec::new()).push(idx);
+        }
+
+        map
+    }
+
     /// Once regions have been propagated, this method is used to see
     /// whether the "type tests" produced by typeck were satisfied;
     /// type tests encode type-outlives relationships like `T:
index 8a0578ae4d45c302f36c5c4a791c63fa99de9a2c..6c2037810d3260d831b5227f6f6b88fcd18428e2 100644 (file)
@@ -10,7 +10,7 @@
 
 use dataflow::{FlowAtLocation, FlowsAtLocation};
 use borrow_check::nll::region_infer::Cause;
-use dataflow::MaybeInitializedLvals;
+use dataflow::MaybeInitializedPlaces;
 use dataflow::move_paths::{HasMoveData, MoveData};
 use rustc::mir::{BasicBlock, Location, Mir};
 use rustc::mir::Local;
@@ -34,7 +34,7 @@ pub(super) fn generate<'gcx, 'tcx>(
     cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
     mir: &Mir<'tcx>,
     liveness: &LivenessResults,
-    flow_inits: &mut FlowAtLocation<MaybeInitializedLvals<'_, 'gcx, 'tcx>>,
+    flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
     move_data: &MoveData<'tcx>,
 ) {
     let tcx = cx.tcx();
@@ -63,7 +63,7 @@ struct TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx>
     tcx: TyCtxt<'typeck, 'gcx, 'tcx>,
     mir: &'gen Mir<'tcx>,
     liveness: &'gen LivenessResults,
-    flow_inits: &'gen mut FlowAtLocation<MaybeInitializedLvals<'flow, 'gcx, 'tcx>>,
+    flow_inits: &'gen mut FlowAtLocation<MaybeInitializedPlaces<'flow, 'gcx, 'tcx>>,
     move_data: &'gen MoveData<'tcx>,
 }
 
index 9dcd4435580ab71723e38699e114411c620ac523..015eb8a3b6643bfddf5ddaed9837fc899cd70433 100644 (file)
@@ -15,7 +15,7 @@
 use borrow_check::nll::region_infer::ClosureRegionRequirementsExt;
 use borrow_check::nll::universal_regions::UniversalRegions;
 use dataflow::FlowAtLocation;
-use dataflow::MaybeInitializedLvals;
+use dataflow::MaybeInitializedPlaces;
 use dataflow::move_paths::MoveData;
 use rustc::hir::def_id::DefId;
 use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
@@ -100,7 +100,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
     mir_def_id: DefId,
     universal_regions: &UniversalRegions<'tcx>,
     liveness: &LivenessResults,
-    flow_inits: &mut FlowAtLocation<MaybeInitializedLvals<'_, 'gcx, 'tcx>>,
+    flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
     move_data: &MoveData<'tcx>,
 ) -> MirTypeckRegionConstraints<'tcx> {
     let body_id = infcx.tcx.hir.as_local_node_id(mir_def_id).unwrap();
@@ -397,7 +397,7 @@ fn sanitize_projection(
         let base_ty = base.to_ty(tcx);
         match *pi {
             ProjectionElem::Deref => {
-                let deref_ty = base_ty.builtin_deref(true, ty::LvaluePreference::NoPreference);
+                let deref_ty = base_ty.builtin_deref(true);
                 PlaceTy::Ty {
                     ty: deref_ty.map(|t| t.ty).unwrap_or_else(|| {
                         span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty)
index b2b615d29a5b8ceb7ed72c83d22724c64e1a2fac..ef30b1e452230df786add31df2af97b9344bda0d 100644 (file)
@@ -143,7 +143,17 @@ fn ast_block_stmts(&mut self,
         if let Some(expr) = expr {
             unpack!(block = this.into(destination, block, expr));
         } else {
-            this.cfg.push_assign_unit(block, source_info, destination);
+            // If a block has no trailing expression, then it is given an implicit return type.
+            // This return type is usually `()`, unless the block is diverging, in which case the
+            // return type is `!`. For the unit type, we need to actually return the unit, but in
+            // the case of `!`, no return value is required, as the block will never return.
+            let tcx = this.hir.tcx();
+            let ty = destination.ty(&this.local_decls, tcx).to_ty(tcx);
+            if ty.is_nil() {
+                // We only want to assign an implicit `()` as the return value of the block if the
+                // block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.)
+                this.cfg.push_assign_unit(block, source_info, destination);
+            }
         }
         // Finally, we pop all the let scopes before exiting out from the scope of block
         // itself.
index 3e0ccc7d072607d8af71fdcf2e7ce0377e5e18a2..68b23d1ae17e85c57f2eb192237c5946c31c7327 100644 (file)
@@ -272,7 +272,7 @@ pub fn into_expr(&mut self,
             ExprKind::Continue { .. } |
             ExprKind::Break { .. } |
             ExprKind::InlineAsm { .. } |
-            ExprKind::Return {.. } => {
+            ExprKind::Return { .. } => {
                 unpack!(block = this.stmt_expr(block, expr));
                 this.cfg.push_assign_unit(block, source_info, destination);
                 block.unit()
index ddb4bf0e36ba758d91675318ac9449873d2d2d1a..a631ab27d1c872bf50800437c988fd103b0c13d1 100644 (file)
@@ -695,10 +695,12 @@ pub fn schedule_drop(&mut self,
                 if let DropKind::Value { .. } = drop_kind {
                     scope.needs_cleanup = true;
                 }
+
                 let region_scope_span = region_scope.span(self.hir.tcx(),
                                                           &self.hir.region_scope_tree);
-                // Attribute scope exit drops to scope's closing brace
-                let scope_end = region_scope_span.with_lo(region_scope_span.hi());
+                // Attribute scope exit drops to scope's closing brace.
+                let scope_end = self.hir.tcx().sess.codemap().end_point(region_scope_span);
+
                 scope.drops.push(DropData {
                     span: scope_end,
                     location: place.clone(),
index f543a33b130b6f9b2f05f402caa84a0ff8e3e9a3..632bb5b34284da8e3eb2fab4607dbbc01437a3fb 100644 (file)
@@ -537,8 +537,8 @@ pub(crate) fn opt_region_end_span(&self, region: &Region) -> Option<Span> {
             Some(_) => None,
             None => {
                 match self.0.region_span_map.get(region) {
-                    Some(span) => Some(span.end_point()),
-                    None => Some(self.0.mir.span.end_point())
+                    Some(span) => Some(self.0.tcx.sess.codemap().end_point(*span)),
+                    None => Some(self.0.tcx.sess.codemap().end_point(self.0.mir.span))
                 }
             }
         }
@@ -575,10 +575,10 @@ fn has_been_reserved(&self, b: &BorrowIndex) -> bool {
     /// has a reservation at the time).
     fn is_potential_use(context: PlaceContext) -> bool {
         match context {
-            // storage effects on an place do not activate it
+            // storage effects on a place do not activate it
             PlaceContext::StorageLive | PlaceContext::StorageDead => false,
 
-            // validation effects do not activate an place
+            // validation effects do not activate a place
             //
             // FIXME: Should they? Is it just another read? Or can we
             // guarantee it won't dereference the stored address? How
@@ -589,11 +589,11 @@ fn is_potential_use(context: PlaceContext) -> bool {
             // AsmOutput existed, but it's not necessarily a pure overwrite.
             // so it's possible this should activate the place.
             PlaceContext::AsmOutput |
-            // pure overwrites of an place do not activate it. (note
+            // pure overwrites of a place do not activate it. (note
             // PlaceContext::Call is solely about dest place)
             PlaceContext::Store | PlaceContext::Call => false,
 
-            // reads of an place *do* activate it
+            // reads of a place *do* activate it
             PlaceContext::Move |
             PlaceContext::Copy |
             PlaceContext::Drop |
index 106a88e703c798179453703b9f9fe65050723076..e7c15625cbe2be9bbf946c81395ef3a0d8cde61c 100644 (file)
@@ -36,7 +36,7 @@
 #[allow(dead_code)]
 pub(super) mod borrows;
 
-/// `MaybeInitializedLvals` tracks all l-values that might be
+/// `MaybeInitializedPlaces` tracks all places that might be
 /// initialized upon reaching a particular point in the control flow
 /// for a function.
 ///
 /// }
 /// ```
 ///
-/// To determine whether an l-value *must* be initialized at a
+/// To determine whether a place *must* be initialized at a
 /// particular control-flow point, one can take the set-difference
-/// between this data and the data from `MaybeUninitializedLvals` at the
+/// between this data and the data from `MaybeUninitializedPlaces` at the
 /// corresponding control-flow point.
 ///
 /// Similarly, at a given `drop` statement, the set-intersection
-/// between this data and `MaybeUninitializedLvals` yields the set of
-/// l-values that would require a dynamic drop-flag at that statement.
-pub struct MaybeInitializedLvals<'a, 'gcx: 'tcx, 'tcx: 'a> {
+/// between this data and `MaybeUninitializedPlaces` yields the set of
+/// places that would require a dynamic drop-flag at that statement.
+pub struct MaybeInitializedPlaces<'a, 'gcx: 'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     mir: &'a Mir<'tcx>,
     mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>,
 }
 
-impl<'a, 'gcx: 'tcx, 'tcx> MaybeInitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx: 'tcx, 'tcx> MaybeInitializedPlaces<'a, 'gcx, 'tcx> {
     pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                mir: &'a Mir<'tcx>,
                mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>)
                -> Self
     {
-        MaybeInitializedLvals { tcx: tcx, mir: mir, mdpe: mdpe }
+        MaybeInitializedPlaces { tcx: tcx, mir: mir, mdpe: mdpe }
     }
 }
 
-impl<'a, 'gcx, 'tcx> HasMoveData<'tcx> for MaybeInitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'gcx, 'tcx> {
     fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
 }
 
-/// `MaybeUninitializedLvals` tracks all l-values that might be
+/// `MaybeUninitializedPlaces` tracks all places that might be
 /// uninitialized upon reaching a particular point in the control flow
 /// for a function.
 ///
@@ -118,42 +118,42 @@ fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
 /// }
 /// ```
 ///
-/// To determine whether an l-value *must* be uninitialized at a
+/// To determine whether a place *must* be uninitialized at a
 /// particular control-flow point, one can take the set-difference
-/// between this data and the data from `MaybeInitializedLvals` at the
+/// between this data and the data from `MaybeInitializedPlaces` at the
 /// corresponding control-flow point.
 ///
 /// Similarly, at a given `drop` statement, the set-intersection
-/// between this data and `MaybeInitializedLvals` yields the set of
-/// l-values that would require a dynamic drop-flag at that statement.
-pub struct MaybeUninitializedLvals<'a, 'gcx: 'tcx, 'tcx: 'a> {
+/// between this data and `MaybeInitializedPlaces` yields the set of
+/// places that would require a dynamic drop-flag at that statement.
+pub struct MaybeUninitializedPlaces<'a, 'gcx: 'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     mir: &'a Mir<'tcx>,
     mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>,
 }
 
-impl<'a, 'gcx, 'tcx> MaybeUninitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> MaybeUninitializedPlaces<'a, 'gcx, 'tcx> {
     pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                mir: &'a Mir<'tcx>,
                mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>)
                -> Self
     {
-        MaybeUninitializedLvals { tcx: tcx, mir: mir, mdpe: mdpe }
+        MaybeUninitializedPlaces { tcx: tcx, mir: mir, mdpe: mdpe }
     }
 }
 
-impl<'a, 'gcx, 'tcx> HasMoveData<'tcx> for MaybeUninitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> {
     fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
 }
 
-/// `DefinitelyInitializedLvals` tracks all l-values that are definitely
+/// `DefinitelyInitializedPlaces` tracks all places that are definitely
 /// initialized upon reaching a particular point in the control flow
 /// for a function.
 ///
 /// FIXME: Note that once flow-analysis is complete, this should be
-/// the set-complement of MaybeUninitializedLvals; thus we can get rid
+/// the set-complement of MaybeUninitializedPlaces; thus we can get rid
 /// of one or the other of these two. I'm inclined to get rid of
-/// MaybeUninitializedLvals, simply because the sets will tend to be
+/// MaybeUninitializedPlaces, simply because the sets will tend to be
 /// smaller in this analysis and thus easier for humans to process
 /// when debugging.
 ///
@@ -180,43 +180,43 @@ fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
 /// }
 /// ```
 ///
-/// To determine whether an l-value *may* be uninitialized at a
+/// To determine whether a place *may* be uninitialized at a
 /// particular control-flow point, one can take the set-complement
 /// of this data.
 ///
 /// Similarly, at a given `drop` statement, the set-difference between
-/// this data and `MaybeInitializedLvals` yields the set of l-values
+/// this data and `MaybeInitializedPlaces` yields the set of places
 /// that would require a dynamic drop-flag at that statement.
-pub struct DefinitelyInitializedLvals<'a, 'gcx: 'tcx, 'tcx: 'a> {
+pub struct DefinitelyInitializedPlaces<'a, 'gcx: 'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     mir: &'a Mir<'tcx>,
     mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>,
 }
 
-impl<'a, 'gcx, 'tcx: 'a> DefinitelyInitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx: 'a> DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> {
     pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                mir: &'a Mir<'tcx>,
                mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>)
                -> Self
     {
-        DefinitelyInitializedLvals { tcx: tcx, mir: mir, mdpe: mdpe }
+        DefinitelyInitializedPlaces { tcx: tcx, mir: mir, mdpe: mdpe }
     }
 }
 
-impl<'a, 'gcx, 'tcx: 'a> HasMoveData<'tcx> for DefinitelyInitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx: 'a> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> {
     fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
 }
 
 /// `MovingOutStatements` tracks the statements that perform moves out
-/// of particular l-values. More precisely, it tracks whether the
+/// of particular places. More precisely, it tracks whether the
 /// *effect* of such moves (namely, the uninitialization of the
-/// l-value in question) can reach some point in the control-flow of
+/// place in question) can reach some point in the control-flow of
 /// the function, or if that effect is "killed" by some intervening
-/// operation reinitializing that l-value.
+/// operation reinitializing that place.
 ///
 /// The resulting dataflow is a more enriched version of
-/// `MaybeUninitializedLvals`. Both structures on their own only tell
-/// you if an l-value *might* be uninitialized at a given point in the
+/// `MaybeUninitializedPlaces`. Both structures on their own only tell
+/// you if a place *might* be uninitialized at a given point in the
 /// control flow. But `MovingOutStatements` also includes the added
 /// data of *which* particular statement causing the deinitialization
 /// that the borrow checker's error message may need to report.
@@ -241,7 +241,7 @@ impl<'a, 'gcx, 'tcx> HasMoveData<'tcx> for MovingOutStatements<'a, 'gcx, 'tcx> {
     fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
 }
 
-/// `EverInitializedLvals` tracks all l-values that might have ever been
+/// `EverInitializedPlaces` tracks all places that might have ever been
 /// initialized upon reaching a particular point in the control flow
 /// for a function, without an intervening `Storage Dead`.
 ///
@@ -270,28 +270,28 @@ fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
 ///     c = S;                                 // {a, b, c, d }
 /// }
 /// ```
-pub struct EverInitializedLvals<'a, 'gcx: 'tcx, 'tcx: 'a> {
+pub struct EverInitializedPlaces<'a, 'gcx: 'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     mir: &'a Mir<'tcx>,
     mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>,
 }
 
-impl<'a, 'gcx: 'tcx, 'tcx: 'a> EverInitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx: 'tcx, 'tcx: 'a> EverInitializedPlaces<'a, 'gcx, 'tcx> {
     pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                mir: &'a Mir<'tcx>,
                mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>)
                -> Self
     {
-        EverInitializedLvals { tcx: tcx, mir: mir, mdpe: mdpe }
+        EverInitializedPlaces { tcx: tcx, mir: mir, mdpe: mdpe }
     }
 }
 
-impl<'a, 'gcx, 'tcx> HasMoveData<'tcx> for EverInitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'a, 'gcx, 'tcx> {
     fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
 }
 
 
-impl<'a, 'gcx, 'tcx> MaybeInitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> MaybeInitializedPlaces<'a, 'gcx, 'tcx> {
     fn update_bits(sets: &mut BlockSets<MovePathIndex>, path: MovePathIndex,
                    state: DropFlagState)
     {
@@ -302,7 +302,7 @@ fn update_bits(sets: &mut BlockSets<MovePathIndex>, path: MovePathIndex,
     }
 }
 
-impl<'a, 'gcx, 'tcx> MaybeUninitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> MaybeUninitializedPlaces<'a, 'gcx, 'tcx> {
     fn update_bits(sets: &mut BlockSets<MovePathIndex>, path: MovePathIndex,
                    state: DropFlagState)
     {
@@ -313,7 +313,7 @@ fn update_bits(sets: &mut BlockSets<MovePathIndex>, path: MovePathIndex,
     }
 }
 
-impl<'a, 'gcx, 'tcx> DefinitelyInitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> {
     fn update_bits(sets: &mut BlockSets<MovePathIndex>, path: MovePathIndex,
                    state: DropFlagState)
     {
@@ -324,7 +324,7 @@ fn update_bits(sets: &mut BlockSets<MovePathIndex>, path: MovePathIndex,
     }
 }
 
-impl<'a, 'gcx, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitDenotation for MaybeInitializedPlaces<'a, 'gcx, 'tcx> {
     type Idx = MovePathIndex;
     fn name() -> &'static str { "maybe_init" }
     fn bits_per_block(&self) -> usize {
@@ -375,7 +375,7 @@ fn propagate_call_return(&self,
     }
 }
 
-impl<'a, 'gcx, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitDenotation for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> {
     type Idx = MovePathIndex;
     fn name() -> &'static str { "maybe_uninit" }
     fn bits_per_block(&self) -> usize {
@@ -430,7 +430,7 @@ fn propagate_call_return(&self,
     }
 }
 
-impl<'a, 'gcx, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitDenotation for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> {
     type Idx = MovePathIndex;
     fn name() -> &'static str { "definite_init" }
     fn bits_per_block(&self) -> usize {
@@ -561,7 +561,7 @@ fn propagate_call_return(&self,
     }
 }
 
-impl<'a, 'gcx, 'tcx> BitDenotation for EverInitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitDenotation for EverInitializedPlaces<'a, 'gcx, 'tcx> {
     type Idx = InitIndex;
     fn name() -> &'static str { "ever_init" }
     fn bits_per_block(&self) -> usize {
@@ -657,21 +657,21 @@ fn propagate_call_return(&self,
     }
 }
 
-impl<'a, 'gcx, 'tcx> BitwiseOperator for MaybeInitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitwiseOperator for MaybeInitializedPlaces<'a, 'gcx, 'tcx> {
     #[inline]
     fn join(&self, pred1: usize, pred2: usize) -> usize {
         pred1 | pred2 // "maybe" means we union effects of both preds
     }
 }
 
-impl<'a, 'gcx, 'tcx> BitwiseOperator for MaybeUninitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitwiseOperator for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> {
     #[inline]
     fn join(&self, pred1: usize, pred2: usize) -> usize {
         pred1 | pred2 // "maybe" means we union effects of both preds
     }
 }
 
-impl<'a, 'gcx, 'tcx> BitwiseOperator for DefinitelyInitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitwiseOperator for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> {
     #[inline]
     fn join(&self, pred1: usize, pred2: usize) -> usize {
         pred1 & pred2 // "definitely" means we intersect effects of both preds
@@ -685,7 +685,7 @@ fn join(&self, pred1: usize, pred2: usize) -> usize {
     }
 }
 
-impl<'a, 'gcx, 'tcx> BitwiseOperator for EverInitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitwiseOperator for EverInitializedPlaces<'a, 'gcx, 'tcx> {
     #[inline]
     fn join(&self, pred1: usize, pred2: usize) -> usize {
         pred1 | pred2 // inits from both preds are in scope
@@ -702,21 +702,21 @@ fn join(&self, pred1: usize, pred2: usize) -> usize {
 // propagating, or you start at all-ones and then use Intersect as
 // your merge when propagating.
 
-impl<'a, 'gcx, 'tcx> InitialFlow for MaybeInitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> InitialFlow for MaybeInitializedPlaces<'a, 'gcx, 'tcx> {
     #[inline]
     fn bottom_value() -> bool {
         false // bottom = uninitialized
     }
 }
 
-impl<'a, 'gcx, 'tcx> InitialFlow for MaybeUninitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> InitialFlow for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> {
     #[inline]
     fn bottom_value() -> bool {
         false // bottom = initialized (start_block_effect counters this at outset)
     }
 }
 
-impl<'a, 'gcx, 'tcx> InitialFlow for DefinitelyInitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> InitialFlow for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> {
     #[inline]
     fn bottom_value() -> bool {
         true // bottom = initialized (start_block_effect counters this at outset)
@@ -730,7 +730,7 @@ fn bottom_value() -> bool {
     }
 }
 
-impl<'a, 'gcx, 'tcx> InitialFlow for EverInitializedLvals<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> InitialFlow for EverInitializedPlaces<'a, 'gcx, 'tcx> {
     #[inline]
     fn bottom_value() -> bool {
         false // bottom = no initialized variables by default
index b18fb7c7b9ccef1e84d9d0816af8cfcaacb675fc..bd63198ecd0d273c127723a49efb48e62b00345d 100644 (file)
@@ -26,9 +26,9 @@
 use std::usize;
 
 pub use self::impls::{MaybeStorageLive};
-pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals};
-pub use self::impls::{DefinitelyInitializedLvals, MovingOutStatements};
-pub use self::impls::EverInitializedLvals;
+pub use self::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
+pub use self::impls::{DefinitelyInitializedPlaces, MovingOutStatements};
+pub use self::impls::EverInitializedPlaces;
 pub use self::impls::borrows::{Borrows, BorrowData};
 pub(crate) use self::impls::borrows::{ActiveBorrows, Reservations, ReserveOrActivateIndex};
 pub use self::at_location::{FlowAtLocation, FlowsAtLocation};
index bcf4662211e8b3f38a15440b959a3c0c7595face..7b6ebc6fba8722e93d834113e02955e292e28c87 100644 (file)
@@ -86,7 +86,7 @@ pub fn move_path_index(&self, move_data: &MoveData) -> MovePathIndex {
 /// It follows a tree structure.
 ///
 /// Given `struct X { m: M, n: N }` and `x: X`, moves like `drop x.m;`
-/// move *out* of the l-value `x.m`.
+/// move *out* of the place `x.m`.
 ///
 /// The MovePaths representing `x.m` and `x.n` are siblings (that is,
 /// one of them will link to the other via the `next_sibling` field,
@@ -222,7 +222,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-/// Tables mapping from an l-value to its MovePathIndex.
+/// Tables mapping from a place to its MovePathIndex.
 #[derive(Debug)]
 pub struct MovePathLookup<'tcx> {
     locals: IndexVec<Local, MovePathIndex>,
@@ -247,7 +247,7 @@ pub enum LookupResult {
 impl<'tcx> MovePathLookup<'tcx> {
     // Unlike the builder `fn move_path_for` below, this lookup
     // alternative will *not* create a MovePath on the fly for an
-    // unknown l-value, but will rather return the nearest available
+    // unknown place, but will rather return the nearest available
     // parent.
     pub fn find(&self, place: &Place<'tcx>) -> LookupResult {
         match *place {
index c2c6b23c083a25eecb90189f67a99ff3a35aa949..701b7a07ac988f131f710cb6e8f0730b021d3344 100644 (file)
@@ -9,9 +9,9 @@
 
 #[derive(Copy, Clone, Debug)]
 pub enum Place {
-    /// An place referring to a value allocated in the `Memory` system.
+    /// A place referring to a value allocated in the `Memory` system.
     Ptr {
-        /// An place may have an invalid (integral or undef) pointer,
+        /// A place may have an invalid (integral or undef) pointer,
         /// since it might be turned back into a reference
         /// before ever being dereferenced.
         ptr: Pointer,
@@ -19,7 +19,7 @@ pub enum Place {
         extra: PlaceExtra,
     },
 
-    /// An place referring to a value on the stack. Represented by a stack frame index paired with
+    /// A place referring to a value on the stack. Represented by a stack frame index paired with
     /// a Mir local index.
     Local { frame: usize, local: mir::Local },
 }
@@ -33,7 +33,7 @@ pub enum PlaceExtra {
 }
 
 impl<'tcx> Place {
-    /// Produces an Place that will error if attempted to be read from
+    /// Produces a Place that will error if attempted to be read from
     pub fn undef() -> Self {
         Self::from_primval_ptr(PrimVal::Undef.into(), Align::from_bytes(1, 1).unwrap())
     }
index 806d787c84522601c69c4a56fde4acbc7f547ba4..e9471cdb4f9497658b91a27108906d88f72e98dc 100644 (file)
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::DefPathData;
 use rustc::mir::mono::{Linkage, Visibility};
+use rustc::middle::exported_symbols::SymbolExportLevel;
 use rustc::ty::{self, TyCtxt, InstanceDef};
 use rustc::ty::item_path::characteristic_def_id_of_type;
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
@@ -322,7 +323,16 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                             .or_insert_with(make_codegen_unit);
 
         let mut can_be_internalized = true;
-        let (linkage, visibility) = match trans_item.explicit_linkage(tcx) {
+        let default_visibility = |id: DefId| {
+            if tcx.sess.target.target.options.default_hidden_visibility &&
+                tcx.symbol_export_level(id) != SymbolExportLevel::C
+            {
+                Visibility::Hidden
+            } else {
+                Visibility::Default
+            }
+        };
+        let (linkage, mut visibility) = match trans_item.explicit_linkage(tcx) {
             Some(explicit_linkage) => (explicit_linkage, Visibility::Default),
             None => {
                 match trans_item {
@@ -352,7 +362,8 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     Visibility::Hidden
                                 } else if def_id.is_local() {
                                     if tcx.is_exported_symbol(def_id) {
-                                        Visibility::Default
+                                        can_be_internalized = false;
+                                        default_visibility(def_id)
                                     } else {
                                         Visibility::Hidden
                                     }
@@ -375,7 +386,8 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     MonoItem::GlobalAsm(node_id) => {
                         let def_id = tcx.hir.local_def_id(node_id);
                         let visibility = if tcx.is_exported_symbol(def_id) {
-                            Visibility::Default
+                            can_be_internalized = false;
+                            default_visibility(def_id)
                         } else {
                             Visibility::Hidden
                         };
index 106bc39d0fc5be64ad2072675674340dac064793..9eca343cb5edceb6fe45d11a0752fdb7d2f13252 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex, LookupResult};
-use dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
+use dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
 use dataflow::{DataflowResults};
 use dataflow::{on_all_children_bits, on_all_drop_children_bits};
 use dataflow::{drop_flag_effects_for_location, on_lookup_result_bits};
@@ -60,11 +60,11 @@ fn run_pass<'a, 'tcx>(&self,
             let dead_unwinds = find_dead_unwinds(tcx, mir, id, &env);
             let flow_inits =
                 do_dataflow(tcx, mir, id, &[], &dead_unwinds,
-                            MaybeInitializedLvals::new(tcx, mir, &env),
+                            MaybeInitializedPlaces::new(tcx, mir, &env),
                             |bd, p| DebugFormatted::new(&bd.move_data().move_paths[p]));
             let flow_uninits =
                 do_dataflow(tcx, mir, id, &[], &dead_unwinds,
-                            MaybeUninitializedLvals::new(tcx, mir, &env),
+                            MaybeUninitializedPlaces::new(tcx, mir, &env),
                             |bd, p| DebugFormatted::new(&bd.move_data().move_paths[p]));
 
             ElaborateDropsCtxt {
@@ -97,7 +97,7 @@ fn find_dead_unwinds<'a, 'tcx>(
     let mut dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
     let flow_inits =
         do_dataflow(tcx, mir, id, &[], &dead_unwinds,
-                    MaybeInitializedLvals::new(tcx, mir, &env),
+                    MaybeInitializedPlaces::new(tcx, mir, &env),
                     |bd, p| DebugFormatted::new(&bd.move_data().move_paths[p]));
     for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
         let location = match bb_data.terminator().kind {
@@ -300,8 +300,8 @@ struct ElaborateDropsCtxt<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     mir: &'a Mir<'tcx>,
     env: &'a MoveDataParamEnv<'tcx, 'tcx>,
-    flow_inits: DataflowResults<MaybeInitializedLvals<'a, 'tcx, 'tcx>>,
-    flow_uninits:  DataflowResults<MaybeUninitializedLvals<'a, 'tcx, 'tcx>>,
+    flow_inits: DataflowResults<MaybeInitializedPlaces<'a, 'tcx, 'tcx>>,
+    flow_uninits:  DataflowResults<MaybeUninitializedPlaces<'a, 'tcx, 'tcx>>,
     drop_flags: FxHashMap<MovePathIndex, Local>,
     patch: MirPatch<'tcx>,
 }
index b6153ea1fdbad175839dae13e6b33fd9256ceaca..76283edac7284d60b711280aa7d341b647c8bafa 100644 (file)
@@ -22,7 +22,7 @@
 use dataflow::MoveDataParamEnv;
 use dataflow::BitDenotation;
 use dataflow::DataflowResults;
-use dataflow::{DefinitelyInitializedLvals, MaybeInitializedLvals, MaybeUninitializedLvals};
+use dataflow::{DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces};
 use dataflow::move_paths::{MovePathIndex, LookupResult};
 use dataflow::move_paths::{HasMoveData, MoveData};
 use dataflow;
@@ -50,15 +50,15 @@ fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
         let flow_inits =
             do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
-                        MaybeInitializedLvals::new(tcx, mir, &mdpe),
+                        MaybeInitializedPlaces::new(tcx, mir, &mdpe),
                         |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]));
         let flow_uninits =
             do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
-                        MaybeUninitializedLvals::new(tcx, mir, &mdpe),
+                        MaybeUninitializedPlaces::new(tcx, mir, &mdpe),
                         |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]));
         let flow_def_inits =
             do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
-                        DefinitelyInitializedLvals::new(tcx, mir, &mdpe),
+                        DefinitelyInitializedPlaces::new(tcx, mir, &mdpe),
                         |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]));
 
         if has_rustc_mir_with(&attributes, "rustc_peek_maybe_init").is_some() {
index 3331bc9e59e0b44078909998f9a18a2ff5ec8aeb..65771068014992d107740b8cc1ab4a3b97540321 100644 (file)
@@ -560,7 +560,7 @@ fn destructor_call_block<'a>(&mut self, (succ, unwind): (BasicBlock, Unwind))
     ///        ptr = cur
     ///        cur = cur.offset(1)
     ///    } else {
-    ///        ptr = &mut LV[cur]
+    ///        ptr = &mut P[cur]
     ///        cur = cur + 1
     ///    }
     ///    drop(ptr)
@@ -731,7 +731,7 @@ fn drop_loop_pair(&mut self, ety: Ty<'tcx>, ptr_based: bool) -> BasicBlock {
         if ptr_based {
             let tmp_ty = tcx.mk_mut_ptr(self.place_ty(self.place));
             let tmp = Place::Local(self.new_temp(tmp_ty));
-            // tmp = &LV;
+            // tmp = &P;
             // cur = tmp as *mut T;
             // end = Offset(cur, len);
             drop_block_stmts.push(self.assign(&tmp, Rvalue::Ref(
index 557ff887a3ef283c205ac6b8a4421b61f435c811..2da4bfedd3a175252a230f2d9a17a01ccfdf8dd1 100644 (file)
@@ -2871,8 +2871,8 @@ fn type_ascription_suggestion(&self,
         if let Some(sp) = self.current_type_ascription.last() {
             let mut sp = *sp;
             loop {  // try to find the `:`, bail on first non-':'/non-whitespace
-                sp = sp.next_point();
-                if let Ok(snippet) = cm.span_to_snippet(sp.to(sp.next_point())) {
+                sp = cm.next_point(sp);
+                if let Ok(snippet) = cm.span_to_snippet(sp.to(cm.next_point(sp))) {
                     debug!("snippet {:?}", snippet);
                     let line_sp = cm.lookup_char_pos(sp.hi()).line;
                     let line_base_sp = cm.lookup_char_pos(base_span.lo()).line;
@@ -3980,14 +3980,14 @@ fn report_conflict<'b>(&mut self,
                           container));
 
         err.span_label(span, format!("`{}` re{} here", name, new_participle));
-        if old_binding.span != syntax_pos::DUMMY_SP {
+        if old_binding.span != DUMMY_SP {
             err.span_label(self.session.codemap().def_span(old_binding.span),
                            format!("previous {} of the {} `{}` here", old_noun, old_kind, name));
         }
 
         // See https://github.com/rust-lang/rust/issues/32354
         if old_binding.is_import() || new_binding.is_import() {
-            let binding = if new_binding.is_import() {
+            let binding = if new_binding.is_import() && new_binding.span != DUMMY_SP {
                 new_binding
             } else {
                 old_binding
@@ -3998,9 +3998,21 @@ fn report_conflict<'b>(&mut self,
 
             if let (Ok(snippet), false) = (cm.span_to_snippet(binding.span),
                                            binding.is_renamed_extern_crate()) {
+                let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() {
+                    format!("Other{}", name)
+                } else {
+                    format!("other_{}", name)
+                };
+
                 err.span_suggestion(binding.span,
                                     rename_msg,
-                                    format!("{} as Other{}", snippet, name));
+                                    if snippet.ends_with(';') {
+                                        format!("{} as {};",
+                                                &snippet[..snippet.len()-1],
+                                                suggested_name)
+                                    } else {
+                                        format!("{} as {}", snippet, suggested_name)
+                                    });
             } else {
                 err.span_label(binding.span, rename_msg);
             }
index 79dd57b37f41fdead93d80145de0f452ab39cf42..500c4fdf4e8dd2c58ac67c609d60b7f7ea17503f 100644 (file)
@@ -13,6 +13,7 @@ test = false
 bitflags = "1.0"
 flate2 = "1.0"
 jobserver = "0.1.5"
+libc = "0.2"
 log = "0.4"
 num_cpus = "1.0"
 rustc = { path = "../librustc" }
@@ -36,3 +37,13 @@ tempdir = "0.3"
 
 [target."cfg(windows)".dependencies]
 cc = "1.0.1"
+
+[features]
+# Used to communicate the feature to `rustc_back` in the same manner that the
+# `rustc` driver script communicate this.
+jemalloc = ["rustc_back/jemalloc"]
+
+# This is used to convince Cargo to separately cache builds of `rustc_trans`
+# when this option is enabled or not. That way we can build two, cache two
+# artifacts, and have nice speedy rebuilds.
+emscripten = ["rustc_llvm/emscripten"]
index 9cabd9356e9bfe17b8c55554a6c664126d774aed..12698964d2e65ec7dc76f9b40c4754323d0e926a 100644 (file)
@@ -545,7 +545,7 @@ pub fn is_ignore(&self) -> bool {
         self.mode == PassMode::Ignore
     }
 
-    /// Get the LLVM type for an place of the original Rust type of
+    /// Get the LLVM type for a place of the original Rust type of
     /// this argument/return, i.e. the result of `type_of::type_of`.
     pub fn memory_ty(&self, cx: &CodegenCx<'a, 'tcx>) -> Type {
         self.layout.llvm_type(cx)
@@ -674,7 +674,7 @@ pub fn new_vtable(cx: &CodegenCx<'a, 'tcx>,
                 _ => bug!("FnType::new_vtable: non-pair self {:?}", self_arg)
             }
 
-            let pointee = self_arg.layout.ty.builtin_deref(true, ty::NoPreference)
+            let pointee = self_arg.layout.ty.builtin_deref(true)
                 .unwrap_or_else(|| {
                     bug!("FnType::new_vtable: non-pointer self {:?}", self_arg)
                 }).ty;
index fd5aa1364d381951bcf3025a77b4f62164064da5..e1c145b122d761044a6057c2f670591150701576 100644 (file)
@@ -86,6 +86,10 @@ pub(crate) unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind)
                                                      name.as_ptr(),
                                                      ty);
 
+        if tcx.sess.target.target.options.default_hidden_visibility {
+            llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
+        }
+
         let callee = CString::new(kind.fn_name(method.name)).unwrap();
         let callee = llvm::LLVMRustGetOrInsertFunction(llmod,
                                                        callee.as_ptr(),
index c7be0c4e67d712a3617e9a16f5884f23314dbedd..751f8148a2a9086fde59c055a8b22d83890e6ef3 100644 (file)
@@ -59,8 +59,9 @@ pub fn trans_inline_asm<'a, 'tcx>(
     // Default per-arch clobbers
     // Basically what clang does
     let arch_clobbers = match &bx.sess().target.target.arch[..] {
-        "x86" | "x86_64" => vec!["~{dirflag}", "~{fpsr}", "~{flags}"],
-        _                => Vec::new()
+        "x86" | "x86_64"  => vec!["~{dirflag}", "~{fpsr}", "~{flags}"],
+        "mips" | "mips64" => vec!["~{$1}"],
+        _                 => Vec::new()
     };
 
     let all_constraints =
index 15ff59c7df998098603d60a101b40dd164864f77..989ef8a953746161a09b433fae785aa639b393a4 100644 (file)
@@ -133,6 +133,8 @@ pub fn provide(providers: &mut Providers) {
 
         Arc::new(local_crate)
     };
+
+    providers.symbol_export_level = export_level;
 }
 
 pub fn provide_extern(providers: &mut Providers) {
@@ -203,6 +205,7 @@ pub fn provide_extern(providers: &mut Providers) {
 
         Arc::new(crate_exports)
     };
+    providers.symbol_export_level = export_level;
 }
 
 fn export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel {
index 8afa63a5e9735e113bceac783870cdca3d54d91f..206c73b017459b077b05dd78a719fc242113d806 100644 (file)
@@ -824,9 +824,7 @@ fn binaryen_assemble(cgcx: &CodegenContext,
     if cgcx.debuginfo != config::NoDebugInfo {
         options.debuginfo(true);
     }
-    if cgcx.crate_types.contains(&config::CrateTypeExecutable) {
-        options.start("main");
-    }
+
     options.stack(1024 * 1024);
     options.import_memory(cgcx.wasm_import_memory);
     let assembled = input.and_then(|input| {
@@ -1452,7 +1450,7 @@ fn start_executing_work(tcx: TyCtxt,
         target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(),
         binaryen_linker: tcx.sess.linker_flavor() == LinkerFlavor::Binaryen,
         debuginfo: tcx.sess.opts.debuginfo,
-        wasm_import_memory: wasm_import_memory,
+        wasm_import_memory,
         assembler_cmd,
     };
 
index b67997081aa67c04e79688cd2760710e109f53b4..908d3790170acd110ba21fe75811844c1ad3c15a 100644 (file)
@@ -69,7 +69,7 @@
 
 use back::bytecode::RLIB_BYTECODE_EXTENSION;
 
-pub use llvm_util::{target_features, print_version, print_passes};
+pub use llvm_util::target_features;
 
 use std::any::Any;
 use std::path::PathBuf;
@@ -149,13 +149,16 @@ impl !Send for LlvmTransCrate {} // Llvm is on a per-thread basis
 impl !Sync for LlvmTransCrate {}
 
 impl LlvmTransCrate {
-    pub fn new(sess: &Session) -> Box<TransCrate> {
-        llvm_util::init(sess); // Make sure llvm is inited
+    pub fn new() -> Box<TransCrate> {
         box LlvmTransCrate(())
     }
 }
 
 impl TransCrate for LlvmTransCrate {
+    fn init(&self, sess: &Session) {
+        llvm_util::init(sess); // Make sure llvm is inited
+    }
+
     fn print(&self, req: PrintRequest, sess: &Session) {
         match req {
             PrintRequest::RelocationModels => {
@@ -183,6 +186,19 @@ fn print(&self, req: PrintRequest, sess: &Session) {
         }
     }
 
+    fn print_passes(&self) {
+        llvm_util::print_passes();
+    }
+
+    fn print_version(&self) {
+        llvm_util::print_version();
+    }
+
+    #[cfg(not(stage0))]
+    fn diagnostics(&self) -> &[(&'static str, &'static str)] {
+        &DIAGNOSTICS
+    }
+
     fn target_features(&self, sess: &Session) -> Vec<Symbol> {
         target_features(sess)
     }
@@ -252,8 +268,8 @@ fn join_trans_and_link(
 
 /// This is the entrypoint for a hot plugged rustc_trans
 #[no_mangle]
-pub fn __rustc_codegen_backend(sess: &Session) -> Box<TransCrate> {
-    LlvmTransCrate::new(sess)
+pub fn __rustc_codegen_backend() -> Box<TransCrate> {
+    LlvmTransCrate::new()
 }
 
 struct ModuleTranslation {
index 15988008de2fc6981a4e3c44d9a7fb69cfcc7fd7..843231d376f6c49a82794b68dd447823597f234a 100644 (file)
@@ -79,16 +79,16 @@ unsafe fn configure_llvm(sess: &Session) {
 // detection code will walk past the end of the feature array,
 // leading to crashes.
 
-const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "vfp2\0", "vfp3\0", "vfp4\0"];
+const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "v7\0", "vfp2\0", "vfp3\0", "vfp4\0"];
 
-const AARCH64_WHITELIST: &'static [&'static str] = &["neon\0"];
+const AARCH64_WHITELIST: &'static [&'static str] = &["neon\0", "v7\0"];
 
 const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0",
                                                  "sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0",
                                                  "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0",
                                                  "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0",
                                                  "xsave\0", "xsaveopt\0", "xsavec\0",
-                                                 "xsaves\0",
+                                                 "xsaves\0", "aes\0",
                                                  "avx512bw\0", "avx512cd\0",
                                                  "avx512dq\0", "avx512er\0",
                                                  "avx512f\0", "avx512ifma\0",
index 71ce0aa3da96b9db230f20a923a1b53d67792a7d..a3e55205dd8759c46f5cca3075e78e990e612311 100644 (file)
@@ -140,7 +140,10 @@ fn get_field(&self, cx: &CodegenCx<'a, 'tcx>, i: usize) -> ValueRef {
                 }
             }
             _ => {
-                const_get_elt(self.llval, layout.llvm_field_index(i))
+                match layout.fields {
+                    layout::FieldPlacement::Union(_) => self.llval,
+                    _ => const_get_elt(self.llval, layout.llvm_field_index(i)),
+                }
             }
         }
     }
@@ -209,7 +212,7 @@ enum Base {
     Static(ValueRef)
 }
 
-/// An place as seen from a constant.
+/// A place as seen from a constant.
 #[derive(Copy, Clone)]
 struct ConstPlace<'tcx> {
     base: Base,
@@ -740,7 +743,7 @@ fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
                         operand.llval
                     }
                     mir::CastKind::Unsize => {
-                        let pointee_ty = operand.ty.builtin_deref(true, ty::NoPreference)
+                        let pointee_ty = operand.ty.builtin_deref(true)
                             .expect("consts: unsizing got non-pointer type").ty;
                         let (base, old_info) = if !self.cx.type_is_sized(pointee_ty) {
                             // Normally, the source is a thin pointer and we are
@@ -755,7 +758,7 @@ fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
                             (operand.llval, None)
                         };
 
-                        let unsized_ty = cast_ty.builtin_deref(true, ty::NoPreference)
+                        let unsized_ty = cast_ty.builtin_deref(true)
                             .expect("consts: unsizing got non-pointer target type").ty;
                         let ptr_ty = self.cx.layout_of(unsized_ty).llvm_type(self.cx).ptr_to();
                         let base = consts::ptrcast(base, ptr_ty);
index 25db9f9b4c8a80c4c07273a06f65e1839dd5a70c..e1b906646aa437a9bfefe155ee459eee6596a31d 100644 (file)
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 use llvm::ValueRef;
-use rustc::ty;
 use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
 use rustc::mir;
 use rustc_data_structures::indexed_vec::Idx;
@@ -100,7 +99,7 @@ pub fn immediate(self) -> ValueRef {
     }
 
     pub fn deref(self, cx: &CodegenCx<'a, 'tcx>) -> PlaceRef<'tcx> {
-        let projected_ty = self.layout.ty.builtin_deref(true, ty::NoPreference)
+        let projected_ty = self.layout.ty.builtin_deref(true)
             .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)).ty;
         let (llptr, llextra) = match self.val {
             OperandValue::Immediate(llptr) => (llptr, ptr::null_mut()),
index b1533cfad19f524fd6e0e8baa5bb237fbbc8f0ff..af957500f700268b33fc3880fe79b5e0da72fa35 100644 (file)
@@ -57,7 +57,9 @@ fn uncached_llvm_type<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
         ty::TyClosure(..) |
         ty::TyGenerator(..) |
         ty::TyAdt(..) |
-        ty::TyDynamic(..) |
+        // FIXME(eddyb) producing readable type names for trait objects can result
+        // in problematically distinct types due to HRTB and subtyping (see #47638).
+        // ty::TyDynamic(..) |
         ty::TyForeign(..) |
         ty::TyStr => {
             let mut name = String::with_capacity(32);
index 49756d754fe55edead0878dda179bb50d59aa575..e14abdff3391830cd130df181c2588ec3aa99803 100644 (file)
 use link::{build_link_meta, out_filename};
 
 pub trait TransCrate {
+    fn init(&self, _sess: &Session) {}
     fn print(&self, _req: PrintRequest, _sess: &Session) {}
     fn target_features(&self, _sess: &Session) -> Vec<Symbol> { vec![] }
+    fn print_passes(&self) {}
+    fn print_version(&self) {}
+    fn diagnostics(&self) -> &[(&'static str, &'static str)] { &[] }
 
     fn metadata_loader(&self) -> Box<MetadataLoader>;
     fn provide(&self, _providers: &mut Providers);
@@ -168,7 +172,13 @@ pub struct OngoingCrateTranslation {
 }
 
 impl MetadataOnlyTransCrate {
-    pub fn new(sess: &Session) -> Box<TransCrate> {
+    pub fn new() -> Box<TransCrate> {
+        box MetadataOnlyTransCrate(())
+    }
+}
+
+impl TransCrate for MetadataOnlyTransCrate {
+    fn init(&self, sess: &Session) {
         for cty in sess.opts.crate_types.iter() {
             match *cty {
                 CrateType::CrateTypeRlib | CrateType::CrateTypeDylib |
@@ -180,12 +190,8 @@ pub fn new(sess: &Session) -> Box<TransCrate> {
                 },
             }
         }
-
-        box MetadataOnlyTransCrate(())
     }
-}
 
-impl TransCrate for MetadataOnlyTransCrate {
     fn metadata_loader(&self) -> Box<MetadataLoader> {
         box NoLlvmMetadataLoader
     }
index d5e4aa69c5b4e54d1bc60d7fea73ccbc761558f4..1a285cd869aecad1a376251aa7e80001b1d80617 100644 (file)
@@ -14,8 +14,8 @@
 use rustc::infer;
 use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::traits::ObligationCauseCode;
-use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference};
-use check::{FnCtxt, Expectation, Diverges};
+use rustc::ty::{self, Ty, TypeFoldable};
+use check::{FnCtxt, Expectation, Diverges, Needs};
 use check::coercion::CoerceMany;
 use util::nodemap::FxHashMap;
 
@@ -500,7 +500,7 @@ pub fn check_pat_walk(
 
     pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool {
         if let PatKind::Binding(..) = inner.node {
-            if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true, ty::NoPreference) {
+            if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) {
                 if let ty::TyDynamic(..) = mt.ty.sty {
                     // This is "x = SomeTrait" being reduced from
                     // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
@@ -584,7 +584,7 @@ pub fn check_match(&self,
                                         });
         let discrim_ty;
         if let Some(m) = contains_ref_bindings {
-            discrim_ty = self.check_expr_with_lvalue_pref(discrim, LvaluePreference::from_mutbl(m));
+            discrim_ty = self.check_expr_with_needs(discrim, Needs::maybe_mut_place(m));
         } else {
             // ...but otherwise we want to use any supertype of the
             // discriminant. This is sort of a workaround, see note (*) in
index 169959d12b5d556dd09c5c688146f60004d1ade5..1d7c533178f075b3d9b5bfd25ae2da5e27a2502e 100644 (file)
@@ -10,7 +10,7 @@
 
 use astconv::AstConv;
 
-use super::{FnCtxt, LvalueOp};
+use super::{FnCtxt, PlaceOp, Needs};
 use super::method::MethodCallee;
 
 use rustc::infer::InferOk;
@@ -18,7 +18,6 @@
 use rustc::traits;
 use rustc::ty::{self, Ty, TraitRef};
 use rustc::ty::{ToPredicate, TypeFoldable};
-use rustc::ty::{LvaluePreference, NoPreference};
 use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
 
 use syntax_pos::Span;
@@ -85,7 +84,7 @@ fn next(&mut self) -> Option<Self::Item> {
 
         // Otherwise, deref if type is derefable:
         let (kind, new_ty) =
-            if let Some(mt) = self.cur_ty.builtin_deref(self.include_raw_pointers, NoPreference) {
+            if let Some(mt) = self.cur_ty.builtin_deref(self.include_raw_pointers) {
                 (AutoderefKind::Builtin, mt.ty)
             } else {
                 let ty = self.overloaded_deref_ty(self.cur_ty)?;
@@ -163,19 +162,19 @@ pub fn step_count(&self) -> usize {
     }
 
     /// Returns the adjustment steps.
-    pub fn adjust_steps(&self, pref: LvaluePreference)
+    pub fn adjust_steps(&self, needs: Needs)
                         -> Vec<Adjustment<'tcx>> {
-        self.fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(pref))
+        self.fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(needs))
     }
 
-    pub fn adjust_steps_as_infer_ok(&self, pref: LvaluePreference)
+    pub fn adjust_steps_as_infer_ok(&self, needs: Needs)
                                     -> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
         let mut obligations = vec![];
         let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty)
             .chain(iter::once(self.cur_ty));
         let steps: Vec<_> = self.steps.iter().map(|&(source, kind)| {
             if let AutoderefKind::Overloaded = kind {
-                self.fcx.try_overloaded_deref(self.span, source, pref)
+                self.fcx.try_overloaded_deref(self.span, source, needs)
                     .and_then(|InferOk { value: method, obligations: o }| {
                         obligations.extend(o);
                         if let ty::TyRef(region, mt) = method.sig.output().sty {
@@ -238,8 +237,8 @@ pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'gcx,
     pub fn try_overloaded_deref(&self,
                                 span: Span,
                                 base_ty: Ty<'tcx>,
-                                pref: LvaluePreference)
+                                needs: Needs)
                                 -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
-        self.try_overloaded_lvalue_op(span, base_ty, &[], pref, LvalueOp::Deref)
+        self.try_overloaded_place_op(span, base_ty, &[], needs, PlaceOp::Deref)
     }
 }
index 5c5e5f2735b712a7f789e61688c79a82e6c6ee64..76df9be48386d0df1678828d144c971003a646c5 100644 (file)
@@ -8,14 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use super::{Expectation, FnCtxt, TupleArgumentsFlag};
+use super::{Expectation, FnCtxt, Needs, TupleArgumentsFlag};
 use super::autoderef::Autoderef;
 use super::method::MethodCallee;
 
 use hir::def::Def;
 use hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::{infer, traits};
-use rustc::ty::{self, TyCtxt, TypeFoldable, LvaluePreference, Ty};
+use rustc::ty::{self, TyCtxt, TypeFoldable, Ty};
 use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
 use syntax::abi;
 use syntax::symbol::Symbol;
@@ -96,7 +96,7 @@ fn try_overloaded_call_step(&self,
         // If the callee is a bare function or a closure, then we're all set.
         match adjusted_ty.sty {
             ty::TyFnDef(..) | ty::TyFnPtr(_) => {
-                let adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference);
+                let adjustments = autoderef.adjust_steps(Needs::None);
                 self.apply_adjustments(callee_expr, adjustments);
                 return Some(CallStep::Builtin(adjusted_ty));
             }
@@ -113,7 +113,7 @@ fn try_overloaded_call_step(&self,
                                                                    infer::FnCall,
                                                                    &closure_ty)
                         .0;
-                    let adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference);
+                    let adjustments = autoderef.adjust_steps(Needs::None);
                     self.record_deferred_call_resolution(def_id, DeferredCallResolution {
                         call_expr,
                         callee_expr,
@@ -143,7 +143,7 @@ fn try_overloaded_call_step(&self,
         }
 
         self.try_overloaded_call_traits(call_expr, adjusted_ty).map(|(autoref, method)| {
-            let mut adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference);
+            let mut adjustments = autoderef.adjust_steps(Needs::None);
             adjustments.extend(autoref);
             self.apply_adjustments(callee_expr, adjustments);
             CallStep::Overloaded(method)
index edda557c98c3784f99bbe1ec57c62c6d6b3fe9e8..d0280bf0b30be058e53b8b47dc68174aae56f804 100644 (file)
@@ -60,7 +60,7 @@
 //! sort of a minor point so I've opted to leave it for later---after all
 //! we may want to adjust precisely when coercions occur.
 
-use check::{Diverges, FnCtxt};
+use check::{Diverges, FnCtxt, Needs};
 
 use rustc::hir;
 use rustc::hir::def_id::DefId;
@@ -69,8 +69,7 @@
 use rustc::lint;
 use rustc::traits::{self, ObligationCause, ObligationCauseCode};
 use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
-use rustc::ty::{self, LvaluePreference, TypeAndMut,
-                Ty, ClosureSubsts};
+use rustc::ty::{self, TypeAndMut, Ty, ClosureSubsts};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::error::TypeError;
 use rustc::ty::relate::RelateResult;
@@ -410,9 +409,9 @@ fn coerce_borrowed_pointer(&self,
             return success(vec![], ty, obligations);
         }
 
-        let pref = LvaluePreference::from_mutbl(mt_b.mutbl);
+        let needs = Needs::maybe_mut_place(mt_b.mutbl);
         let InferOk { value: mut adjustments, obligations: o }
-            = autoderef.adjust_steps_as_infer_ok(pref);
+            = autoderef.adjust_steps_as_infer_ok(needs);
         obligations.extend(o);
         obligations.extend(autoderef.into_obligations());
 
index 3a9c4e1901d277e6b9ba342229698ed58069e596..7f5b353f79ef7994a71c9410a2fd256a9a61dd2e 100644 (file)
 use super::{probe, MethodCallee};
 
 use astconv::AstConv;
-use check::{FnCtxt, LvalueOp, callee};
+use check::{FnCtxt, PlaceOp, callee, Needs};
 use hir::def_id::DefId;
 use rustc::ty::subst::Substs;
 use rustc::traits;
-use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty};
+use rustc::ty::{self, Ty};
 use rustc::ty::subst::Subst;
 use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, OverloadedDeref};
 use rustc::ty::fold::TypeFoldable;
@@ -136,7 +136,7 @@ fn confirm(&mut self,
         };
 
         if let Some(hir::MutMutable) = pick.autoref {
-            self.convert_lvalue_derefs_to_mutable();
+            self.convert_place_derefs_to_mutable();
         }
 
         ConfirmResult { callee, illegal_sized_bound }
@@ -155,7 +155,7 @@ fn adjust_self_ty(&mut self,
         let (_, n) = autoderef.nth(pick.autoderefs).unwrap();
         assert_eq!(n, pick.autoderefs);
 
-        let mut adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference);
+        let mut adjustments = autoderef.adjust_steps(Needs::None);
 
         let mut target = autoderef.unambiguous_final_ty();
 
@@ -416,7 +416,7 @@ fn add_obligations(&mut self,
     /// When we select a method with a mutable autoref, we have to go convert any
     /// auto-derefs, indices, etc from `Deref` and `Index` into `DerefMut` and `IndexMut`
     /// respectively.
-    fn convert_lvalue_derefs_to_mutable(&self) {
+    fn convert_place_derefs_to_mutable(&self) {
         // Gather up expressions we want to munge.
         let mut exprs = Vec::new();
         exprs.push(self.self_expr);
@@ -431,14 +431,14 @@ fn convert_lvalue_derefs_to_mutable(&self) {
             }
         }
 
-        debug!("convert_lvalue_derefs_to_mutable: exprs={:?}", exprs);
+        debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs);
 
         // Fix up autoderefs and derefs.
         for (i, &expr) in exprs.iter().rev().enumerate() {
-            debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?}", i, expr);
+            debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr);
 
             // Fix up the autoderefs. Autorefs can only occur immediately preceding
-            // overloaded lvalue ops, and will be fixed by them in order to get
+            // overloaded place ops, and will be fixed by them in order to get
             // the correct region.
             let mut source = self.node_ty(expr.hir_id);
             // Do not mutate adjustments in place, but rather take them,
@@ -449,10 +449,10 @@ fn convert_lvalue_derefs_to_mutable(&self) {
                                            .adjustments_mut()
                                            .remove(expr.hir_id);
             if let Some(mut adjustments) = previous_adjustments {
-                let pref = LvaluePreference::PreferMutLvalue;
+                let needs = Needs::MutPlace;
                 for adjustment in &mut adjustments {
                     if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind {
-                        if let Some(ok) = self.try_overloaded_deref(expr.span, source, pref) {
+                        if let Some(ok) = self.try_overloaded_deref(expr.span, source, needs) {
                             let method = self.register_infer_ok_obligations(ok);
                             if let ty::TyRef(region, mt) = method.sig.output().sty {
                                 *deref = OverloadedDeref {
@@ -470,28 +470,28 @@ fn convert_lvalue_derefs_to_mutable(&self) {
             match expr.node {
                 hir::ExprIndex(ref base_expr, ref index_expr) => {
                     let index_expr_ty = self.node_ty(index_expr.hir_id);
-                    self.convert_lvalue_op_to_mutable(
-                        LvalueOp::Index, expr, base_expr, &[index_expr_ty]);
+                    self.convert_place_op_to_mutable(
+                        PlaceOp::Index, expr, base_expr, &[index_expr_ty]);
                 }
                 hir::ExprUnary(hir::UnDeref, ref base_expr) => {
-                    self.convert_lvalue_op_to_mutable(
-                        LvalueOp::Deref, expr, base_expr, &[]);
+                    self.convert_place_op_to_mutable(
+                        PlaceOp::Deref, expr, base_expr, &[]);
                 }
                 _ => {}
             }
         }
     }
 
-    fn convert_lvalue_op_to_mutable(&self,
-                                    op: LvalueOp,
+    fn convert_place_op_to_mutable(&self,
+                                    op: PlaceOp,
                                     expr: &hir::Expr,
                                     base_expr: &hir::Expr,
                                     arg_tys: &[Ty<'tcx>])
     {
-        debug!("convert_lvalue_op_to_mutable({:?}, {:?}, {:?}, {:?})",
+        debug!("convert_place_op_to_mutable({:?}, {:?}, {:?}, {:?})",
                op, expr, base_expr, arg_tys);
         if !self.tables.borrow().is_method_call(expr) {
-            debug!("convert_lvalue_op_to_mutable - builtin, nothing to do");
+            debug!("convert_place_op_to_mutable - builtin, nothing to do");
             return
         }
 
@@ -499,24 +499,24 @@ fn convert_lvalue_op_to_mutable(&self,
             .map_or_else(|| self.node_ty(expr.hir_id), |adj| adj.target);
         let base_ty = self.resolve_type_vars_if_possible(&base_ty);
 
-        // Need to deref because overloaded lvalue ops take self by-reference.
-        let base_ty = base_ty.builtin_deref(false, NoPreference)
-            .expect("lvalue op takes something that is not a ref")
+        // Need to deref because overloaded place ops take self by-reference.
+        let base_ty = base_ty.builtin_deref(false)
+            .expect("place op takes something that is not a ref")
             .ty;
 
-        let method = self.try_overloaded_lvalue_op(
-            expr.span, base_ty, arg_tys, PreferMutLvalue, op);
+        let method = self.try_overloaded_place_op(
+            expr.span, base_ty, arg_tys, Needs::MutPlace, op);
         let method = match method {
             Some(ok) => self.register_infer_ok_obligations(ok),
             None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed")
         };
-        debug!("convert_lvalue_op_to_mutable: method={:?}", method);
+        debug!("convert_place_op_to_mutable: method={:?}", method);
         self.write_method_call(expr.hir_id, method);
 
         let (region, mutbl) = if let ty::TyRef(r, mt) = method.sig.inputs()[0].sty {
             (r, mt.mutbl)
         } else {
-            span_bug!(expr.span, "input to lvalue op is not a ref?");
+            span_bug!(expr.span, "input to place op is not a ref?");
         };
 
         // Convert the autoref in the base expr to mutable with the correct
@@ -529,7 +529,7 @@ fn convert_lvalue_op_to_mutable(&self,
             let mut source = base_expr_ty;
             for adjustment in &mut adjustments[..] {
                 if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind {
-                    debug!("convert_lvalue_op_to_mutable: converting autoref {:?}", adjustment);
+                    debug!("convert_place_op_to_mutable: converting autoref {:?}", adjustment);
                     adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl));
                     adjustment.target = self.tcx.mk_ref(region, ty::TypeAndMut {
                         ty: source,
index 6147743437b8e638b5be3ad4814dcb3d27f2a0ea..483dd345286d433601cdd3d2728b73ee6ff5865a 100644 (file)
@@ -95,7 +95,6 @@
 use rustc::middle::region;
 use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode};
-use rustc::ty::{ParamTy, LvaluePreference, NoPreference, PreferMutLvalue};
 use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate};
 use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc::ty::fold::TypeFoldable;
@@ -368,6 +367,21 @@ fn coercion_target_type(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, span: Span) -> Ty<'t
     }
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum Needs {
+    MutPlace,
+    None
+}
+
+impl Needs {
+    fn maybe_mut_place(m: hir::Mutability) -> Self {
+        match m {
+            hir::MutMutable => Needs::MutPlace,
+            hir::MutImmutable => Needs::None,
+        }
+    }
+}
+
 #[derive(Copy, Clone)]
 pub struct UnsafetyState {
     pub def: ast::NodeId,
@@ -410,7 +424,7 @@ pub fn recurse(&mut self, blk: &hir::Block) -> UnsafetyState {
 }
 
 #[derive(Debug, Copy, Clone)]
-pub enum LvalueOp {
+pub enum PlaceOp {
     Deref,
     Index
 }
@@ -543,7 +557,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     ///   foo();}` or `{return; 22}`, where we would warn on the
     ///   `foo()` or `22`.
     ///
-    /// - To permit assignment into a local variable or other lvalue
+    /// - To permit assignment into a local variable or other place
     ///   (including the "return slot") of type `!`.  This is allowed
     ///   if **either** the type of value being assigned is `!`, which
     ///   means the current code is dead, **or** the expression's
@@ -2207,11 +2221,65 @@ fn select_obligations_where_possible(&self) {
         }
     }
 
-    /// For the overloaded lvalue expressions (`*x`, `x[3]`), the trait
+    fn is_place_expr(&self, expr: &hir::Expr) -> bool {
+         match expr.node {
+            hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
+                match path.def {
+                    Def::Local(..) | Def::Upvar(..) | Def::Static(..) | Def::Err => true,
+                    _ => false,
+                }
+            }
+
+            hir::ExprType(ref e, _) => {
+                self.is_place_expr(e)
+            }
+
+            hir::ExprUnary(hir::UnDeref, _) |
+            hir::ExprField(..) |
+            hir::ExprTupField(..) |
+            hir::ExprIndex(..) => {
+                true
+            }
+
+            // Partially qualified paths in expressions can only legally
+            // refer to associated items which are always rvalues.
+            hir::ExprPath(hir::QPath::TypeRelative(..)) |
+
+            hir::ExprCall(..) |
+            hir::ExprMethodCall(..) |
+            hir::ExprStruct(..) |
+            hir::ExprTup(..) |
+            hir::ExprIf(..) |
+            hir::ExprMatch(..) |
+            hir::ExprClosure(..) |
+            hir::ExprBlock(..) |
+            hir::ExprRepeat(..) |
+            hir::ExprArray(..) |
+            hir::ExprBreak(..) |
+            hir::ExprAgain(..) |
+            hir::ExprRet(..) |
+            hir::ExprWhile(..) |
+            hir::ExprLoop(..) |
+            hir::ExprAssign(..) |
+            hir::ExprInlineAsm(..) |
+            hir::ExprAssignOp(..) |
+            hir::ExprLit(_) |
+            hir::ExprUnary(..) |
+            hir::ExprBox(..) |
+            hir::ExprAddrOf(..) |
+            hir::ExprBinary(..) |
+            hir::ExprYield(..) |
+            hir::ExprCast(..) => {
+                false
+            }
+        }
+    }
+
+    /// For the overloaded place expressions (`*x`, `x[3]`), the trait
     /// returns a type of `&T`, but the actual type we assign to the
     /// *expression* is `T`. So this function just peels off the return
     /// type by one layer to yield `T`.
-    fn make_overloaded_lvalue_return_type(&self,
+    fn make_overloaded_place_return_type(&self,
                                           method: MethodCallee<'tcx>)
                                           -> ty::TypeAndMut<'tcx>
     {
@@ -2219,7 +2287,7 @@ fn make_overloaded_lvalue_return_type(&self,
         let ret_ty = method.sig.output();
 
         // method returns &T, but the type as visible to user is T, so deref
-        ret_ty.builtin_deref(true, NoPreference).unwrap()
+        ret_ty.builtin_deref(true).unwrap()
     }
 
     fn lookup_indexing(&self,
@@ -2227,7 +2295,7 @@ fn lookup_indexing(&self,
                        base_expr: &'gcx hir::Expr,
                        base_ty: Ty<'tcx>,
                        idx_ty: Ty<'tcx>,
-                       lvalue_pref: LvaluePreference)
+                       needs: Needs)
                        -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
     {
         // FIXME(#18741) -- this is almost but not quite the same as the
@@ -2237,7 +2305,7 @@ fn lookup_indexing(&self,
         let mut autoderef = self.autoderef(base_expr.span, base_ty);
         let mut result = None;
         while result.is_none() && autoderef.next().is_some() {
-            result = self.try_index_step(expr, base_expr, &autoderef, lvalue_pref, idx_ty);
+            result = self.try_index_step(expr, base_expr, &autoderef, needs, idx_ty);
         }
         autoderef.finalize();
         result
@@ -2252,7 +2320,7 @@ fn try_index_step(&self,
                       expr: &hir::Expr,
                       base_expr: &hir::Expr,
                       autoderef: &Autoderef<'a, 'gcx, 'tcx>,
-                      lvalue_pref: LvaluePreference,
+                      needs: Needs,
                       index_ty: Ty<'tcx>)
                       -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
     {
@@ -2279,14 +2347,14 @@ fn try_index_step(&self,
             // type from the method signature.
             // If some lookup succeeded, install method in table
             let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_expr.span));
-            let method = self.try_overloaded_lvalue_op(
-                expr.span, self_ty, &[input_ty], lvalue_pref, LvalueOp::Index);
+            let method = self.try_overloaded_place_op(
+                expr.span, self_ty, &[input_ty], needs, PlaceOp::Index);
 
             let result = method.map(|ok| {
                 debug!("try_index_step: success, using overloaded indexing");
                 let method = self.register_infer_ok_obligations(ok);
 
-                let mut adjustments = autoderef.adjust_steps(lvalue_pref);
+                let mut adjustments = autoderef.adjust_steps(needs);
                 if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
                     adjustments.push(Adjustment {
                         kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
@@ -2305,7 +2373,7 @@ fn try_index_step(&self,
                 self.apply_adjustments(base_expr, adjustments);
 
                 self.write_method_call(expr.hir_id, method);
-                (input_ty, self.make_overloaded_lvalue_return_type(method).ty)
+                (input_ty, self.make_overloaded_place_return_type(method).ty)
             });
             if result.is_some() {
                 return result;
@@ -2315,45 +2383,45 @@ fn try_index_step(&self,
         None
     }
 
-    fn resolve_lvalue_op(&self, op: LvalueOp, is_mut: bool) -> (Option<DefId>, Symbol) {
+    fn resolve_place_op(&self, op: PlaceOp, is_mut: bool) -> (Option<DefId>, Symbol) {
         let (tr, name) = match (op, is_mut) {
-            (LvalueOp::Deref, false) =>
+            (PlaceOp::Deref, false) =>
                 (self.tcx.lang_items().deref_trait(), "deref"),
-            (LvalueOp::Deref, true) =>
+            (PlaceOp::Deref, true) =>
                 (self.tcx.lang_items().deref_mut_trait(), "deref_mut"),
-            (LvalueOp::Index, false) =>
+            (PlaceOp::Index, false) =>
                 (self.tcx.lang_items().index_trait(), "index"),
-            (LvalueOp::Index, true) =>
+            (PlaceOp::Index, true) =>
                 (self.tcx.lang_items().index_mut_trait(), "index_mut"),
         };
         (tr, Symbol::intern(name))
     }
 
-    fn try_overloaded_lvalue_op(&self,
+    fn try_overloaded_place_op(&self,
                                 span: Span,
                                 base_ty: Ty<'tcx>,
                                 arg_tys: &[Ty<'tcx>],
-                                lvalue_pref: LvaluePreference,
-                                op: LvalueOp)
+                                needs: Needs,
+                                op: PlaceOp)
                                 -> Option<InferOk<'tcx, MethodCallee<'tcx>>>
     {
-        debug!("try_overloaded_lvalue_op({:?},{:?},{:?},{:?})",
+        debug!("try_overloaded_place_op({:?},{:?},{:?},{:?})",
                span,
                base_ty,
-               lvalue_pref,
+               needs,
                op);
 
-        // Try Mut first, if preferred.
-        let (mut_tr, mut_op) = self.resolve_lvalue_op(op, true);
-        let method = match (lvalue_pref, mut_tr) {
-            (PreferMutLvalue, Some(trait_did)) => {
+        // Try Mut first, if needed.
+        let (mut_tr, mut_op) = self.resolve_place_op(op, true);
+        let method = match (needs, mut_tr) {
+            (Needs::MutPlace, Some(trait_did)) => {
                 self.lookup_method_in_trait(span, mut_op, trait_did, base_ty, Some(arg_tys))
             }
             _ => None,
         };
 
         // Otherwise, fall back to the immutable version.
-        let (imm_tr, imm_op) = self.resolve_lvalue_op(op, false);
+        let (imm_tr, imm_op) = self.resolve_place_op(op, false);
         let method = match (method, imm_tr) {
             (None, Some(trait_did)) => {
                 self.lookup_method_in_trait(span, imm_op, trait_did, base_ty, Some(arg_tys))
@@ -2457,7 +2525,7 @@ fn parameter_count_error<'tcx>(sess: &Session,
                 err.span_label(def_s, "defined here");
             }
             if sugg_unit {
-                let sugg_span = expr_sp.end_point();
+                let sugg_span = sess.codemap().end_point(expr_sp);
                 // remove closing `)` from the span
                 let sugg_span = sugg_span.with_hi(sugg_span.lo());
                 err.span_suggestion(
@@ -2738,18 +2806,18 @@ fn check_expr_meets_expectation_or_error(&self,
     fn check_expr_coercable_to_type(&self,
                                     expr: &'gcx hir::Expr,
                                     expected: Ty<'tcx>) -> Ty<'tcx> {
-        self.check_expr_coercable_to_type_with_lvalue_pref(expr, expected, NoPreference)
+        self.check_expr_coercable_to_type_with_needs(expr, expected, Needs::None)
     }
 
-    fn check_expr_coercable_to_type_with_lvalue_pref(&self,
-                                                     expr: &'gcx hir::Expr,
-                                                     expected: Ty<'tcx>,
-                                                     lvalue_pref: LvaluePreference)
-                                                     -> Ty<'tcx> {
-        let ty = self.check_expr_with_expectation_and_lvalue_pref(
+    fn check_expr_coercable_to_type_with_needs(&self,
+                                               expr: &'gcx hir::Expr,
+                                               expected: Ty<'tcx>,
+                                               needs: Needs)
+                                               -> Ty<'tcx> {
+        let ty = self.check_expr_with_expectation_and_needs(
             expr,
             ExpectHasType(expected),
-            lvalue_pref);
+            needs);
         self.demand_coerce(expr, ty, expected)
     }
 
@@ -2761,16 +2829,15 @@ fn check_expr_with_hint(&self, expr: &'gcx hir::Expr,
     fn check_expr_with_expectation(&self,
                                    expr: &'gcx hir::Expr,
                                    expected: Expectation<'tcx>) -> Ty<'tcx> {
-        self.check_expr_with_expectation_and_lvalue_pref(expr, expected, NoPreference)
+        self.check_expr_with_expectation_and_needs(expr, expected, Needs::None)
     }
 
     fn check_expr(&self, expr: &'gcx hir::Expr) -> Ty<'tcx> {
         self.check_expr_with_expectation(expr, NoExpectation)
     }
 
-    fn check_expr_with_lvalue_pref(&self, expr: &'gcx hir::Expr,
-                                   lvalue_pref: LvaluePreference) -> Ty<'tcx> {
-        self.check_expr_with_expectation_and_lvalue_pref(expr, NoExpectation, lvalue_pref)
+    fn check_expr_with_needs(&self, expr: &'gcx hir::Expr, needs: Needs) -> Ty<'tcx> {
+        self.check_expr_with_expectation_and_needs(expr, NoExpectation, needs)
     }
 
     // determine the `self` type, using fresh variables for all variables
@@ -2853,9 +2920,9 @@ fn check_method_call(&self,
                          span: Span,
                          args: &'gcx [hir::Expr],
                          expected: Expectation<'tcx>,
-                         lvalue_pref: LvaluePreference) -> Ty<'tcx> {
+                         needs: Needs) -> Ty<'tcx> {
         let rcvr = &args[0];
-        let rcvr_t = self.check_expr_with_lvalue_pref(&rcvr, lvalue_pref);
+        let rcvr_t = self.check_expr_with_needs(&rcvr, needs);
         // no need to check for bot/err -- callee does that
         let rcvr_t = self.structurally_resolved_type(expr.span, rcvr_t);
 
@@ -2965,10 +3032,10 @@ fn check_then_else(&self,
     // Check field access expressions
     fn check_field(&self,
                    expr: &'gcx hir::Expr,
-                   lvalue_pref: LvaluePreference,
+                   needs: Needs,
                    base: &'gcx hir::Expr,
                    field: &Spanned<ast::Name>) -> Ty<'tcx> {
-        let expr_t = self.check_expr_with_lvalue_pref(base, lvalue_pref);
+        let expr_t = self.check_expr_with_needs(base, needs);
         let expr_t = self.structurally_resolved_type(expr.span,
                                                      expr_t);
         let mut private_candidate = None;
@@ -2983,7 +3050,7 @@ fn check_field(&self,
                     if let Some(field) = fields.iter().find(|f| f.name.to_ident() == ident) {
                         let field_ty = self.field_ty(expr.span, field, substs);
                         if field.vis.is_accessible_from(def_scope, self.tcx) {
-                            let adjustments = autoderef.adjust_steps(lvalue_pref);
+                            let adjustments = autoderef.adjust_steps(needs);
                             self.apply_adjustments(base, adjustments);
                             autoderef.finalize();
 
@@ -3102,10 +3169,10 @@ fn name_series_display(&self, names: Vec<ast::Name>) -> String {
     // Check tuple index expressions
     fn check_tup_field(&self,
                        expr: &'gcx hir::Expr,
-                       lvalue_pref: LvaluePreference,
+                       needs: Needs,
                        base: &'gcx hir::Expr,
                        idx: codemap::Spanned<usize>) -> Ty<'tcx> {
-        let expr_t = self.check_expr_with_lvalue_pref(base, lvalue_pref);
+        let expr_t = self.check_expr_with_needs(base, needs);
         let expr_t = self.structurally_resolved_type(expr.span,
                                                      expr_t);
         let mut private_candidate = None;
@@ -3146,7 +3213,7 @@ fn check_tup_field(&self,
             };
 
             if let Some(field_ty) = field {
-                let adjustments = autoderef.adjust_steps(lvalue_pref);
+                let adjustments = autoderef.adjust_steps(needs);
                 self.apply_adjustments(base, adjustments);
                 autoderef.finalize();
                 return field_ty;
@@ -3476,10 +3543,10 @@ fn check_expr_struct(&self,
     /// Note that inspecting a type's structure *directly* may expose the fact
     /// that there are actually multiple representations for `TyError`, so avoid
     /// that when err needs to be handled differently.
-    fn check_expr_with_expectation_and_lvalue_pref(&self,
+    fn check_expr_with_expectation_and_needs(&self,
                                                    expr: &'gcx hir::Expr,
                                                    expected: Expectation<'tcx>,
-                                                   lvalue_pref: LvaluePreference) -> Ty<'tcx> {
+                                                   needs: Needs) -> Ty<'tcx> {
         debug!(">> typechecking: expr={:?} expected={:?}",
                expr, expected);
 
@@ -3492,7 +3559,7 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
         self.diverges.set(Diverges::Maybe);
         self.has_errors.set(false);
 
-        let ty = self.check_expr_kind(expr, expected, lvalue_pref);
+        let ty = self.check_expr_kind(expr, expected, needs);
 
         // Warn for non-block expressions with diverging children.
         match expr.node {
@@ -3526,7 +3593,7 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
     fn check_expr_kind(&self,
                        expr: &'gcx hir::Expr,
                        expected: Expectation<'tcx>,
-                       lvalue_pref: LvaluePreference) -> Ty<'tcx> {
+                       needs: Needs) -> Ty<'tcx> {
         let tcx = self.tcx;
         let id = expr.id;
         match expr.node {
@@ -3560,22 +3627,22 @@ fn check_expr_kind(&self,
                     NoExpectation
                 }
             };
-            let lvalue_pref = match unop {
-                hir::UnDeref => lvalue_pref,
-                _ => NoPreference
+            let needs = match unop {
+                hir::UnDeref => needs,
+                _ => Needs::None
             };
-            let mut oprnd_t = self.check_expr_with_expectation_and_lvalue_pref(&oprnd,
+            let mut oprnd_t = self.check_expr_with_expectation_and_needs(&oprnd,
                                                                                expected_inner,
-                                                                               lvalue_pref);
+                                                                               needs);
 
             if !oprnd_t.references_error() {
                 oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t);
                 match unop {
                     hir::UnDeref => {
-                        if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) {
+                        if let Some(mt) = oprnd_t.builtin_deref(true) {
                             oprnd_t = mt.ty;
                         } else if let Some(ok) = self.try_overloaded_deref(
-                                expr.span, oprnd_t, lvalue_pref) {
+                                expr.span, oprnd_t, needs) {
                             let method = self.register_infer_ok_obligations(ok);
                             if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
                                 self.apply_adjustments(oprnd, vec![Adjustment {
@@ -3583,7 +3650,7 @@ fn check_expr_kind(&self,
                                     target: method.sig.inputs()[0]
                                 }]);
                             }
-                            oprnd_t = self.make_overloaded_lvalue_return_type(method).ty;
+                            oprnd_t = self.make_overloaded_place_return_type(method).ty;
                             self.write_method_call(expr.hir_id, method);
                         } else {
                             type_error_struct!(tcx.sess, expr.span, oprnd_t, E0614,
@@ -3614,8 +3681,8 @@ fn check_expr_kind(&self,
             let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| {
                 match ty.sty {
                     ty::TyRef(_, ref mt) | ty::TyRawPtr(ref mt) => {
-                        if self.tcx.expr_is_lval(&oprnd) {
-                            // Lvalues may legitimately have unsized types.
+                        if self.is_place_expr(&oprnd) {
+                            // Places may legitimately have unsized types.
                             // For example, dereferences of a fat pointer and
                             // the last field of a struct can be unsized.
                             ExpectHasType(mt.ty)
@@ -3626,8 +3693,8 @@ fn check_expr_kind(&self,
                     _ => NoExpectation
                 }
             });
-            let lvalue_pref = LvaluePreference::from_mutbl(mutbl);
-            let ty = self.check_expr_with_expectation_and_lvalue_pref(&oprnd, hint, lvalue_pref);
+            let needs = Needs::maybe_mut_place(mutbl);
+            let ty = self.check_expr_with_expectation_and_needs(&oprnd, hint, needs);
 
             let tm = ty::TypeAndMut { ty: ty, mutbl: mutbl };
             if tm.ty.references_error() {
@@ -3771,7 +3838,7 @@ fn check_expr_kind(&self,
             tcx.types.never
           }
           hir::ExprAssign(ref lhs, ref rhs) => {
-            let lhs_ty = self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue);
+            let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
 
             let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty);
 
@@ -3783,7 +3850,7 @@ fn check_expr_kind(&self,
                 _ => {
                     // Only check this if not in an `if` condition, as the
                     // mistyped comparison help is more appropriate.
-                    if !self.tcx.expr_is_lval(&lhs) {
+                    if !self.is_place_expr(&lhs) {
                         struct_span_err!(self.tcx.sess, expr.span, E0070,
                                          "invalid left-hand side expression")
                             .span_label(expr.span, "left-hand of expression not valid")
@@ -3872,7 +3939,7 @@ fn check_expr_kind(&self,
               self.check_call(expr, &callee, args, expected)
           }
           hir::ExprMethodCall(ref segment, span, ref args) => {
-              self.check_method_call(expr, segment, span, args, expected, lvalue_pref)
+              self.check_method_call(expr, segment, span, args, expected, needs)
           }
           hir::ExprCast(ref e, ref t) => {
             // Find the type of `e`. Supply hints based on the type we are casting to,
@@ -4015,13 +4082,13 @@ fn check_expr_kind(&self,
             self.check_expr_struct(expr, expected, qpath, fields, base_expr)
           }
           hir::ExprField(ref base, ref field) => {
-            self.check_field(expr, lvalue_pref, &base, field)
+            self.check_field(expr, needs, &base, field)
           }
           hir::ExprTupField(ref base, idx) => {
-            self.check_tup_field(expr, lvalue_pref, &base, idx)
+            self.check_tup_field(expr, needs, &base, idx)
           }
           hir::ExprIndex(ref base, ref idx) => {
-              let base_t = self.check_expr_with_lvalue_pref(&base, lvalue_pref);
+              let base_t = self.check_expr_with_needs(&base, needs);
               let idx_t = self.check_expr(&idx);
 
               if base_t.references_error() {
@@ -4030,7 +4097,7 @@ fn check_expr_kind(&self,
                   idx_t
               } else {
                   let base_t = self.structurally_resolved_type(expr.span, base_t);
-                  match self.lookup_indexing(expr, base, base_t, idx_t, lvalue_pref) {
+                  match self.lookup_indexing(expr, base, base_t, idx_t, needs) {
                       Some((index_ty, element_ty)) => {
                           self.demand_coerce(idx, idx_t, index_ty);
                           element_ty
@@ -4178,9 +4245,9 @@ pub fn check_decl_initializer(&self,
             // ref mut, for soundness (issue #23116). In particular, in
             // the latter case, we need to be clear that the type of the
             // referent for the reference that results is *equal to* the
-            // type of the lvalue it is referencing, and not some
+            // type of the place it is referencing, and not some
             // supertype thereof.
-            let init_ty = self.check_expr_with_lvalue_pref(init, LvaluePreference::from_mutbl(m));
+            let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m));
             self.demand_eqtype(init.span, local_ty, init_ty);
             init_ty
         } else {
@@ -4446,10 +4513,10 @@ pub fn suggest_mismatched_types_on_tail(&self,
     /// statement and the return type has been left as default or has been specified as `()`. If so,
     /// it suggests adding a semicolon.
     fn suggest_missing_semicolon(&self,
-                                     err: &mut DiagnosticBuilder<'tcx>,
-                                     expression: &'gcx hir::Expr,
-                                     expected: Ty<'tcx>,
-                                     cause_span: Span) {
+                                 err: &mut DiagnosticBuilder<'tcx>,
+                                 expression: &'gcx hir::Expr,
+                                 expected: Ty<'tcx>,
+                                 cause_span: Span) {
         if expected.is_nil() {
             // `BlockTailExpression` only relevant if the tail expr would be
             // useful on its own.
@@ -4461,7 +4528,7 @@ fn suggest_missing_semicolon(&self,
                 hir::ExprLoop(..) |
                 hir::ExprMatch(..) |
                 hir::ExprBlock(..) => {
-                    let sp = cause_span.next_point();
+                    let sp = self.tcx.sess.codemap().next_point(cause_span);
                     err.span_suggestion(sp,
                                         "try adding a semicolon",
                                         ";".to_string());
@@ -5023,7 +5090,7 @@ pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let lifetime_count = generics.lifetimes().count();
 
     for leaf_ty in ty.walk() {
-        if let ty::TyParam(ParamTy {idx, ..}) = leaf_ty.sty {
+        if let ty::TyParam(ty::ParamTy {idx, ..}) = leaf_ty.sty {
             debug!("Found use of ty param num {}", idx);
             tps_used[idx as usize - lifetime_count] = true;
         } else if let ty::TyError = leaf_ty.sty {
index e099d1c0c2531a46a7a43c809e3a00d682c23090..0698e3ecb6eddb5000f412a1523beb7f06bca4b9 100644 (file)
@@ -10,9 +10,9 @@
 
 //! Code related to processing overloaded binary and unary operators.
 
-use super::FnCtxt;
+use super::{FnCtxt, Needs};
 use super::method::MethodCallee;
-use rustc::ty::{self, Ty, TypeFoldable, NoPreference, PreferMutLvalue, TypeVariants};
+use rustc::ty::{self, Ty, TypeFoldable, TypeVariants};
 use rustc::ty::TypeVariants::{TyStr, TyRef};
 use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
 use rustc::infer::type_variable::TypeVariableOrigin;
@@ -40,10 +40,9 @@ pub fn check_binop_assign(&self,
             return_ty
         };
 
-        let tcx = self.tcx;
-        if !tcx.expr_is_lval(lhs_expr) {
+        if !self.is_place_expr(lhs_expr) {
             struct_span_err!(
-                tcx.sess, lhs_expr.span,
+                self.tcx.sess, lhs_expr.span,
                 E0067, "invalid left-hand side expression")
             .span_label(
                 lhs_expr.span,
@@ -166,18 +165,18 @@ fn check_overloaded_binop(&self,
                op,
                is_assign);
 
-        let lhs_pref = match is_assign {
-            IsAssign::Yes => PreferMutLvalue,
-            IsAssign::No => NoPreference
+        let lhs_needs = match is_assign {
+            IsAssign::Yes => Needs::MutPlace,
+            IsAssign::No => Needs::None
         };
         // Find a suitable supertype of the LHS expression's type, by coercing to
         // a type variable, to pass as the `Self` to the trait, avoiding invariant
         // trait matching creating lifetime constraints that are too strict.
         // E.g. adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result
         // in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`.
-        let lhs_ty = self.check_expr_coercable_to_type_with_lvalue_pref(lhs_expr,
+        let lhs_ty = self.check_expr_coercable_to_type_with_needs(lhs_expr,
             self.next_ty_var(TypeVariableOrigin::MiscVariable(lhs_expr.span)),
-            lhs_pref);
+            lhs_needs);
         let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty);
 
         // NB: As we have not yet type-checked the RHS, we don't have the
index 07d5f813cbbce76977700c569af80bdd868a8ea3..88a2dc817ae63f139f1ad1a38bee016c777fa732 100644 (file)
@@ -82,29 +82,37 @@ fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
 
         for (i, &impl1_def_id) in impls.iter().enumerate() {
             for &impl2_def_id in &impls[(i + 1)..] {
-                let used_to_be_allowed = self.tcx.infer_ctxt().enter(|infcx| {
-                    if let Some(overlap) =
-                        traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id,
-                                                  IntercrateMode::Issue43355)
-                    {
+                let used_to_be_allowed = traits::overlapping_impls(
+                    self.tcx,
+                    impl1_def_id,
+                    impl2_def_id,
+                    IntercrateMode::Issue43355,
+                    |overlap| {
                         self.check_for_common_items_in_impls(
-                            impl1_def_id, impl2_def_id, overlap, false);
+                            impl1_def_id,
+                            impl2_def_id,
+                            overlap,
+                            false,
+                        );
                         false
-                    } else {
-                        true
-                    }
-                });
+                    },
+                    || true,
+                );
 
                 if used_to_be_allowed {
-                    self.tcx.infer_ctxt().enter(|infcx| {
-                        if let Some(overlap) =
-                            traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id,
-                                                      IntercrateMode::Fixed)
-                        {
-                            self.check_for_common_items_in_impls(
-                                impl1_def_id, impl2_def_id, overlap, true);
-                        }
-                    });
+                    traits::overlapping_impls(
+                        self.tcx,
+                        impl1_def_id,
+                        impl2_def_id,
+                        IntercrateMode::Fixed,
+                        |overlap| self.check_for_common_items_in_impls(
+                            impl1_def_id,
+                            impl2_def_id,
+                            overlap,
+                            true,
+                        ),
+                        || (),
+                    );
                 }
             }
         }
index 18d573bd581ebf93cbdf4453bea133f955d9848e..ac7f54250d32b4a3e337b686605585688cf31784 100644 (file)
@@ -732,8 +732,8 @@ fn main() {
 "##,
 
 E0067: r##"
-The left-hand side of a compound assignment expression must be an lvalue
-expression. An lvalue expression represents a memory location and includes
+The left-hand side of a compound assignment expression must be a place
+expression. A place expression represents a memory location and includes
 item paths (ie, namespaced variables), dereferences, indexing expressions,
 and field references.
 
@@ -742,7 +742,7 @@ fn main() {
 ```compile_fail,E0067
 use std::collections::LinkedList;
 
-// Bad: assignment to non-lvalue expression
+// Bad: assignment to non-place expression
 LinkedList::new() += 1;
 
 // ...
@@ -783,14 +783,14 @@ fn foo() -> u8 {
 "##,
 
 E0070: r##"
-The left-hand side of an assignment operator must be an lvalue expression. An
-lvalue expression represents a memory location and can be a variable (with
+The left-hand side of an assignment operator must be a place expression. An
+place expression represents a memory location and can be a variable (with
 optional namespacing), a dereference, an indexing expression or a field
 reference.
 
 More details can be found in the [Expressions] section of the Reference.
 
-[Expressions]: https://doc.rust-lang.org/reference/expressions.html#lvalues-rvalues-and-temporaries
+[Expressions]: https://doc.rust-lang.org/reference/expressions.html#places-rvalues-and-temporaries
 
 Now, we can go further. Here are some erroneous code examples:
 
@@ -806,7 +806,7 @@ fn some_other_func() {}
 
 fn some_function() {
     SOME_CONST = 14; // error : a constant value cannot be changed!
-    1 = 3; // error : 1 isn't a valid lvalue!
+    1 = 3; // error : 1 isn't a valid place!
     some_other_func() = 4; // error : we can't assign value to a function!
     SomeStruct.x = 12; // error : SomeStruct a structure name but it is used
                        // like a variable!
index 5fe4794389ff5a7cfe59a9d4f44cceb84fdf50d5..0674a0b5a3b1096863cc3d4316a22e4a95de575f 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use rustc_lint;
-use rustc_driver::{driver, target_features, abort_on_err};
+use rustc_driver::{self, driver, target_features, abort_on_err};
 use rustc::session::{self, config};
 use rustc::hir::def_id::DefId;
 use rustc::hir::def::Def;
@@ -18,7 +18,6 @@
 use rustc::hir::map as hir_map;
 use rustc::lint;
 use rustc::util::nodemap::FxHashMap;
-use rustc_trans;
 use rustc_resolve as resolve;
 use rustc_metadata::creader::CrateLoader;
 use rustc_metadata::cstore::CStore;
@@ -151,7 +150,7 @@ pub fn run_core(search_paths: SearchPaths,
     let mut sess = session::build_session_(
         sessopts, cpath, diagnostic_handler, codemap,
     );
-    let trans = rustc_trans::LlvmTransCrate::new(&sess);
+    let trans = rustc_driver::get_trans(&sess);
     let cstore = Rc::new(CStore::new(trans.metadata_loader()));
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
 
index dce0c4b001a0d94b86909027ca54a3fc0bc8b2f4..82ced00644da8ea09418af69b07c3fd81c12c9ab 100644 (file)
@@ -872,7 +872,7 @@ fn escape_href(ob: &mut String, s: &str) {
         let link_out = format!("<a href=\"{link}\"{title}>{content}</a>",
                                link = link_buf,
                                title = title.map_or(String::new(),
-                                                    |t| format!(" title=\"{}\"", t)),
+                                                    |t| format!(" title=\"{}\"", Escape(&t))),
                                content = content.unwrap_or(String::new()));
 
         unsafe { hoedown_buffer_put(ob, link_out.as_ptr(), link_out.len()); }
index ccd79e5b2c5f4e7066cdc8a44af7e885799ab18e..e39fe20310c2851a8288033b32fed37c2376e9a8 100644 (file)
@@ -63,8 +63,6 @@
 use std::process;
 use std::sync::mpsc::channel;
 
-use rustc_driver::rustc_trans;
-
 use externalfiles::ExternalHtml;
 use rustc::session::search_paths::SearchPaths;
 use rustc::session::config::{ErrorOutputType, RustcOptGroup, nightly_options,
index 10850f88f2d624d2944d0aef915f9a4ba2f65638..087d88419bc84dbef204b1dc5085b8a4242c9b5e 100644 (file)
@@ -33,7 +33,6 @@
 use rustc_driver::driver::phase_2_configure_and_expand;
 use rustc_metadata::cstore::CStore;
 use rustc_resolve::MakeGlobMap;
-use rustc_trans;
 use syntax::ast;
 use syntax::codemap::CodeMap;
 use syntax::feature_gate::UnstableFeatures;
@@ -84,7 +83,7 @@ pub fn run(input_path: &Path,
     let mut sess = session::build_session_(
         sessopts, Some(input_path.to_owned()), handler, codemap.clone(),
     );
-    let trans = rustc_trans::LlvmTransCrate::new(&sess);
+    let trans = rustc_driver::get_trans(&sess);
     let cstore = Rc::new(CStore::new(trans.metadata_loader()));
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
     sess.parse_sess.config =
@@ -239,6 +238,7 @@ fn drop(&mut self) {
     ));
     let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
                                                       Some(codemap.clone()),
+                                                      false,
                                                       false);
     let old = io::set_panic(Some(box Sink(data.clone())));
     let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
@@ -249,7 +249,7 @@ fn drop(&mut self) {
     let mut sess = session::build_session_(
         sessopts, None, diagnostic_handler, codemap,
     );
-    let trans = rustc_trans::LlvmTransCrate::new(&sess);
+    let trans = rustc_driver::get_trans(&sess);
     let cstore = Rc::new(CStore::new(trans.metadata_loader()));
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
 
index 3430ecabcbeaea079874ef3406e77c19491ac5aa..c1fe4a89d6ac0f9a750a49727cab3be1c4514321 100644 (file)
@@ -48,3 +48,4 @@ jemalloc = ["alloc_jemalloc"]
 force_alloc_system = []
 panic-unwind = ["panic_unwind"]
 profiler = ["profiler_builtins"]
+wasm_syscall = []
index b01420f36a0c38da6a8a0a63a6d5c8ae55f9edb8..82a687ae5e4930cd9fa73d6113ba287f5873d0cb 100644 (file)
@@ -1384,9 +1384,14 @@ impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap<K, V, S>
 {
     type Output = V;
 
+    /// Returns a reference to the value corresponding to the supplied key.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the key is not present in the `HashMap`.
     #[inline]
-    fn index(&self, index: &Q) -> &V {
-        self.get(index).expect("no entry found for key")
+    fn index(&self, key: &Q) -> &V {
+        self.get(key).expect("no entry found for key")
     }
 }
 
index f0b41f30251e09d10209422ea9cd23eb139588ad..bdd675e6e2b851d8f581190902a913ac140ce26b 100644 (file)
@@ -292,8 +292,8 @@ pub fn last_os_error() -> Error {
     /// # if cfg!(target_os = "linux") {
     /// use std::io;
     ///
-    /// let error = io::Error::from_raw_os_error(98);
-    /// assert_eq!(error.kind(), io::ErrorKind::AddrInUse);
+    /// let error = io::Error::from_raw_os_error(22);
+    /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
     /// # }
     /// ```
     ///
@@ -303,8 +303,8 @@ pub fn last_os_error() -> Error {
     /// # if cfg!(windows) {
     /// use std::io;
     ///
-    /// let error = io::Error::from_raw_os_error(10048);
-    /// assert_eq!(error.kind(), io::ErrorKind::AddrInUse);
+    /// let error = io::Error::from_raw_os_error(10022);
+    /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
     /// # }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
index 5c66ac6ddded8efc2049c03fd12e8a766f8ca745..9b2f815b71383b0e6fdca479ecee7ded45264321 100644 (file)
@@ -1843,4 +1843,10 @@ fn ContinueDebugEvent(dwProcessId: DWORD, dwThreadId: DWORD,
         }
         assert!(events > 0);
     }
+
+    #[test]
+    fn test_command_implements_send() {
+        fn take_send_type<T: Send>(_: T) {}
+        take_send_type(Command::new(""))
+    }
 }
index c53bcdbf8e36f228bf060a0aa5410ca3157093e2..7e057401fab70a2a0d41407677e97c90916e9a2b 100644 (file)
@@ -45,7 +45,7 @@ pub struct Command {
     // other keys.
     program: CString,
     args: Vec<CString>,
-    argv: Vec<*const c_char>,
+    argv: Argv,
     env: CommandEnv<DefaultEnvKey>,
 
     cwd: Option<CString>,
@@ -58,6 +58,12 @@ pub struct Command {
     stderr: Option<Stdio>,
 }
 
+// Create a new type for argv, so that we can make it `Send`
+struct Argv(Vec<*const c_char>);
+
+// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args`
+unsafe impl Send for Argv {}
+
 // passed back to std::process with the pipes connected to the child, if any
 // were requested
 pub struct StdioPipes {
@@ -92,7 +98,7 @@ pub fn new(program: &OsStr) -> Command {
         let mut saw_nul = false;
         let program = os2c(program, &mut saw_nul);
         Command {
-            argv: vec![program.as_ptr(), ptr::null()],
+            argv: Argv(vec![program.as_ptr(), ptr::null()]),
             program,
             args: Vec::new(),
             env: Default::default(),
@@ -111,8 +117,8 @@ pub fn arg(&mut self, arg: &OsStr) {
         // Overwrite the trailing NULL pointer in `argv` and then add a new null
         // pointer.
         let arg = os2c(arg, &mut self.saw_nul);
-        self.argv[self.args.len() + 1] = arg.as_ptr();
-        self.argv.push(ptr::null());
+        self.argv.0[self.args.len() + 1] = arg.as_ptr();
+        self.argv.0.push(ptr::null());
 
         // Also make sure we keep track of the owned value to schedule a
         // destructor for this memory.
@@ -133,7 +139,7 @@ pub fn saw_nul(&self) -> bool {
         self.saw_nul
     }
     pub fn get_argv(&self) -> &Vec<*const c_char> {
-        &self.argv
+        &self.argv.0
     }
 
     #[allow(dead_code)]
index d2a4a7b19d548427711a0068c8ae1214dacf73a3..b3c6b671e809949c9bca2b0d43bdc68999f42a5e 100644 (file)
@@ -10,8 +10,8 @@
 
 use ffi::OsString;
 use marker::PhantomData;
-use mem;
 use vec;
+use sys::ArgsSysCall;
 
 pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
     // On wasm these should always be null, so there's nothing for us to do here
@@ -21,38 +21,10 @@ pub unsafe fn cleanup() {
 }
 
 pub fn args() -> Args {
-    // When the runtime debugging is enabled we'll link to some extra runtime
-    // functions to actually implement this. These are for now just implemented
-    // in a node.js script but they're off by default as they're sort of weird
-    // in a web-wasm world.
-    if !super::DEBUG {
-        return Args {
-            iter: Vec::new().into_iter(),
-            _dont_send_or_sync_me: PhantomData,
-        }
-    }
-
-    // You'll find the definitions of these in `src/etc/wasm32-shim.js`. These
-    // are just meant for debugging and should not be relied on.
-    extern {
-        fn rust_wasm_args_count() -> usize;
-        fn rust_wasm_args_arg_size(a: usize) -> usize;
-        fn rust_wasm_args_arg_fill(a: usize, ptr: *mut u8);
-    }
-
-    unsafe {
-        let cnt = rust_wasm_args_count();
-        let mut v = Vec::with_capacity(cnt);
-        for i in 0..cnt {
-            let n = rust_wasm_args_arg_size(i);
-            let mut data = vec![0; n];
-            rust_wasm_args_arg_fill(i, data.as_mut_ptr());
-            v.push(mem::transmute::<Vec<u8>, OsString>(data));
-        }
-        Args {
-            iter: v.into_iter(),
-            _dont_send_or_sync_me: PhantomData,
-        }
+    let v = ArgsSysCall::perform();
+    Args {
+        iter: v.into_iter(),
+        _dont_send_or_sync_me: PhantomData,
     }
 }
 
index ba3d6a2813a451a28573303ccbd08cfe625584db..c02e5e809c8bb33cb81553eec35607420553fbd4 100644 (file)
 
 use io;
 use os::raw::c_char;
-
-// Right now the wasm backend doesn't even have the ability to print to the
-// console by default. Wasm can't import anything from JS! (you have to
-// explicitly provide it).
-//
-// Sometimes that's a real bummer, though, so this flag can be set to `true` to
-// enable calling various shims defined in `src/etc/wasm32-shim.js` which should
-// help receive debug output and see what's going on. In general this flag
-// currently controls "will we call out to our own defined shims in node.js",
-// and this flag should always be `false` for release builds.
-const DEBUG: bool = false;
+use ptr;
+use sys::os_str::Buf;
+use sys_common::{AsInner, FromInner};
+use ffi::{OsString, OsStr};
+use time::Duration;
 
 pub mod args;
 #[cfg(feature = "backtrace")]
@@ -92,7 +86,7 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize {
 }
 
 pub unsafe fn abort_internal() -> ! {
-    ::intrinsics::abort();
+    ExitSysCall::perform(1)
 }
 
 // We don't have randomness yet, but I totally used a random number generator to
@@ -103,3 +97,218 @@ pub unsafe fn abort_internal() -> ! {
 pub fn hashmap_random_keys() -> (u64, u64) {
     (1, 2)
 }
+
+// Implement a minimal set of system calls to enable basic IO
+pub enum SysCallIndex {
+    Read = 0,
+    Write = 1,
+    Exit = 2,
+    Args = 3,
+    GetEnv = 4,
+    SetEnv = 5,
+    Time = 6,
+}
+
+#[repr(C)]
+pub struct ReadSysCall {
+    fd: usize,
+    ptr: *mut u8,
+    len: usize,
+    result: usize,
+}
+
+impl ReadSysCall {
+    pub fn perform(fd: usize, buffer: &mut [u8]) -> usize {
+        let mut call_record = ReadSysCall {
+            fd,
+            len: buffer.len(),
+            ptr: buffer.as_mut_ptr(),
+            result: 0
+        };
+        if unsafe { syscall(SysCallIndex::Read, &mut call_record) } {
+            call_record.result
+        } else {
+            0
+        }
+    }
+}
+
+#[repr(C)]
+pub struct WriteSysCall {
+    fd: usize,
+    ptr: *const u8,
+    len: usize,
+}
+
+impl WriteSysCall {
+    pub fn perform(fd: usize, buffer: &[u8]) {
+        let mut call_record = WriteSysCall {
+            fd,
+            len: buffer.len(),
+            ptr: buffer.as_ptr()
+        };
+        unsafe { syscall(SysCallIndex::Write, &mut call_record); }
+    }
+}
+
+#[repr(C)]
+pub struct ExitSysCall {
+    code: usize,
+}
+
+impl ExitSysCall {
+    pub fn perform(code: usize) -> ! {
+        let mut call_record = ExitSysCall {
+            code
+        };
+        unsafe {
+            syscall(SysCallIndex::Exit, &mut call_record);
+            ::intrinsics::abort();
+        }
+    }
+}
+
+fn receive_buffer<E, F: FnMut(&mut [u8]) -> Result<usize, E>>(estimate: usize, mut f: F)
+    -> Result<Vec<u8>, E>
+{
+    let mut buffer = vec![0; estimate];
+    loop {
+        let result = f(&mut buffer)?;
+        if result <= buffer.len() {
+            buffer.truncate(result);
+            break;
+        }
+        buffer.resize(result, 0);
+    }
+    Ok(buffer)
+}
+
+#[repr(C)]
+pub struct ArgsSysCall {
+    ptr: *mut u8,
+    len: usize,
+    result: usize
+}
+
+impl ArgsSysCall {
+    pub fn perform() -> Vec<OsString> {
+        receive_buffer(1024, |buffer| -> Result<usize, !> {
+            let mut call_record = ArgsSysCall {
+                len: buffer.len(),
+                ptr: buffer.as_mut_ptr(),
+                result: 0
+            };
+            if unsafe { syscall(SysCallIndex::Args, &mut call_record) } {
+                Ok(call_record.result)
+            } else {
+                Ok(0)
+            }
+        })
+            .unwrap()
+            .split(|b| *b == 0)
+            .map(|s| FromInner::from_inner(Buf { inner: s.to_owned() }))
+            .collect()
+    }
+}
+
+#[repr(C)]
+pub struct GetEnvSysCall {
+    key_ptr: *const u8,
+    key_len: usize,
+    value_ptr: *mut u8,
+    value_len: usize,
+    result: usize
+}
+
+impl GetEnvSysCall {
+    pub fn perform(key: &OsStr) -> Option<OsString> {
+        let key_buf = &AsInner::as_inner(key).inner;
+        receive_buffer(64, |buffer| {
+            let mut call_record = GetEnvSysCall {
+                key_len: key_buf.len(),
+                key_ptr: key_buf.as_ptr(),
+                value_len: buffer.len(),
+                value_ptr: buffer.as_mut_ptr(),
+                result: !0usize
+            };
+            if unsafe { syscall(SysCallIndex::GetEnv, &mut call_record) } {
+                if call_record.result == !0usize {
+                    Err(())
+                } else {
+                    Ok(call_record.result)
+                }
+            } else {
+                Err(())
+            }
+        }).ok().map(|s| {
+            FromInner::from_inner(Buf { inner: s })
+        })
+    }
+}
+
+#[repr(C)]
+pub struct SetEnvSysCall {
+    key_ptr: *const u8,
+    key_len: usize,
+    value_ptr: *const u8,
+    value_len: usize
+}
+
+impl SetEnvSysCall {
+    pub fn perform(key: &OsStr, value: Option<&OsStr>) {
+        let key_buf = &AsInner::as_inner(key).inner;
+        let value_buf = value.map(|v| &AsInner::as_inner(v).inner);
+        let mut call_record = SetEnvSysCall {
+            key_len: key_buf.len(),
+            key_ptr: key_buf.as_ptr(),
+            value_len: value_buf.map(|v| v.len()).unwrap_or(!0usize),
+            value_ptr: value_buf.map(|v| v.as_ptr()).unwrap_or(ptr::null())
+        };
+        unsafe { syscall(SysCallIndex::SetEnv, &mut call_record); }
+    }
+}
+
+pub enum TimeClock {
+    Monotonic = 0,
+    System = 1,
+}
+
+#[repr(C)]
+pub struct TimeSysCall {
+    clock: usize,
+    secs_hi: usize,
+    secs_lo: usize,
+    nanos: usize
+}
+
+impl TimeSysCall {
+    pub fn perform(clock: TimeClock) -> Duration {
+        let mut call_record = TimeSysCall {
+            clock: clock as usize,
+            secs_hi: 0,
+            secs_lo: 0,
+            nanos: 0
+        };
+        if unsafe { syscall(SysCallIndex::Time, &mut call_record) } {
+            Duration::new(
+                ((call_record.secs_hi as u64) << 32) | (call_record.secs_lo as u64),
+                call_record.nanos as u32
+            )
+        } else {
+            panic!("Time system call is not implemented by WebAssembly host");
+        }
+    }
+}
+
+unsafe fn syscall<T>(index: SysCallIndex, data: &mut T) -> bool {
+    #[cfg(feature = "wasm_syscall")]
+    extern {
+        #[no_mangle]
+        fn rust_wasm_syscall(index: usize, data: *mut Void) -> usize;
+    }
+
+    #[cfg(not(feature = "wasm_syscall"))]
+    unsafe fn rust_wasm_syscall(_index: usize, _data: *mut Void) -> usize { 0 }
+
+    rust_wasm_syscall(index as usize, data as *mut T as *mut Void) != 0
+}
index c98030f7ebf532f7bd843f981d6ea48dacfbba90..23ca1754719be9905fcdb27e102710ca83277ccd 100644 (file)
@@ -8,16 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use core::intrinsics;
-
 use error::Error as StdError;
 use ffi::{OsString, OsStr};
 use fmt;
 use io;
-use mem;
 use path::{self, PathBuf};
 use str;
-use sys::{unsupported, Void};
+use sys::{unsupported, Void, ExitSysCall, GetEnvSysCall, SetEnvSysCall};
 
 pub fn errno() -> i32 {
     0
@@ -87,36 +84,15 @@ pub fn env() -> Env {
 }
 
 pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
-    // If we're debugging the runtime then we actually probe node.js to ask for
-    // the value of environment variables to help provide inputs to programs.
-    // The `extern` shims here are defined in `src/etc/wasm32-shim.js` and are
-    // intended for debugging only, you should not rely on them.
-    if !super::DEBUG {
-        return Ok(None)
-    }
-
-    extern {
-        fn rust_wasm_getenv_len(k: *const u8, kl: usize) -> isize;
-        fn rust_wasm_getenv_data(k: *const u8, kl: usize, v: *mut u8);
-    }
-    unsafe {
-        let k: &[u8] = mem::transmute(k);
-        let n = rust_wasm_getenv_len(k.as_ptr(), k.len());
-        if n == -1 {
-            return Ok(None)
-        }
-        let mut data = vec![0; n as usize];
-        rust_wasm_getenv_data(k.as_ptr(), k.len(), data.as_mut_ptr());
-        Ok(Some(mem::transmute(data)))
-    }
+    Ok(GetEnvSysCall::perform(k))
 }
 
-pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> {
-    unsupported()
+pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
+    Ok(SetEnvSysCall::perform(k, Some(v)))
 }
 
-pub fn unsetenv(_n: &OsStr) -> io::Result<()> {
-    unsupported()
+pub fn unsetenv(k: &OsStr) -> io::Result<()> {
+    Ok(SetEnvSysCall::perform(k, None))
 }
 
 pub fn temp_dir() -> PathBuf {
@@ -128,7 +104,7 @@ pub fn home_dir() -> Option<PathBuf> {
 }
 
 pub fn exit(_code: i32) -> ! {
-    unsafe { intrinsics::abort() }
+    ExitSysCall::perform(_code as isize as usize)
 }
 
 pub fn getpid() -> u32 {
index 0f75f240251832e5587aac6334afcf6db590916b..beb19c0ed2c1f62bd17b1611db911eb9a04eb7af 100644 (file)
@@ -9,19 +9,19 @@
 // except according to those terms.
 
 use io;
-use sys::{Void, unsupported};
+use sys::{ReadSysCall, WriteSysCall};
 
-pub struct Stdin(Void);
+pub struct Stdin;
 pub struct Stdout;
 pub struct Stderr;
 
 impl Stdin {
     pub fn new() -> io::Result<Stdin> {
-        unsupported()
+        Ok(Stdin)
     }
 
-    pub fn read(&self, _data: &mut [u8]) -> io::Result<usize> {
-        match self.0 {}
+    pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
+        Ok(ReadSysCall::perform(0, data))
     }
 }
 
@@ -31,19 +31,7 @@ pub fn new() -> io::Result<Stdout> {
     }
 
     pub fn write(&self, data: &[u8]) -> io::Result<usize> {
-        // If runtime debugging is enabled at compile time we'll invoke some
-        // runtime functions that are defined in our src/etc/wasm32-shim.js
-        // debugging script. Note that this ffi function call is intended
-        // *purely* for debugging only and should not be relied upon.
-        if !super::DEBUG {
-            return unsupported()
-        }
-        extern {
-            fn rust_wasm_write_stdout(data: *const u8, len: usize);
-        }
-        unsafe {
-            rust_wasm_write_stdout(data.as_ptr(), data.len())
-        }
+        WriteSysCall::perform(1, data);
         Ok(data.len())
     }
 
@@ -58,16 +46,7 @@ pub fn new() -> io::Result<Stderr> {
     }
 
     pub fn write(&self, data: &[u8]) -> io::Result<usize> {
-        // See comments in stdout for what's going on here.
-        if !super::DEBUG {
-            return unsupported()
-        }
-        extern {
-            fn rust_wasm_write_stderr(data: *const u8, len: usize);
-        }
-        unsafe {
-            rust_wasm_write_stderr(data.as_ptr(), data.len())
-        }
+        WriteSysCall::perform(2, data);
         Ok(data.len())
     }
 
index c269def98f6ffdae4f226414e678871adc3e6df7..e52435e63398f226e6cb735a431012f7eb0b3350 100644 (file)
@@ -8,56 +8,50 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use fmt;
 use time::Duration;
+use sys::{TimeSysCall, TimeClock};
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-pub struct Instant;
+pub struct Instant(Duration);
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct SystemTime;
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct SystemTime(Duration);
 
-pub const UNIX_EPOCH: SystemTime = SystemTime;
+pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
 
 impl Instant {
     pub fn now() -> Instant {
-        panic!("not supported on web assembly");
+        Instant(TimeSysCall::perform(TimeClock::Monotonic))
     }
 
-    pub fn sub_instant(&self, _other: &Instant) -> Duration {
-        panic!("can't sub yet");
+    pub fn sub_instant(&self, other: &Instant) -> Duration {
+        self.0 - other.0
     }
 
-    pub fn add_duration(&self, _other: &Duration) -> Instant {
-        panic!("can't add yet");
+    pub fn add_duration(&self, other: &Duration) -> Instant {
+        Instant(self.0 + *other)
     }
 
-    pub fn sub_duration(&self, _other: &Duration) -> Instant {
-        panic!("can't sub yet");
+    pub fn sub_duration(&self, other: &Duration) -> Instant {
+        Instant(self.0 - *other)
     }
 }
 
 impl SystemTime {
     pub fn now() -> SystemTime {
-        panic!("not supported on web assembly");
+        SystemTime(TimeSysCall::perform(TimeClock::System))
     }
 
-    pub fn sub_time(&self, _other: &SystemTime)
+    pub fn sub_time(&self, other: &SystemTime)
                     -> Result<Duration, Duration> {
-        panic!()
-    }
-
-    pub fn add_duration(&self, _other: &Duration) -> SystemTime {
-        panic!()
+        self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
     }
 
-    pub fn sub_duration(&self, _other: &Duration) -> SystemTime {
-        panic!()
+    pub fn add_duration(&self, other: &Duration) -> SystemTime {
+        SystemTime(self.0 + *other)
     }
-}
 
-impl fmt::Debug for SystemTime {
-    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
-        panic!()
+    pub fn sub_duration(&self, other: &Duration) -> SystemTime {
+        SystemTime(self.0 - *other)
     }
 }
diff --git a/src/libstd/time.rs b/src/libstd/time.rs
new file mode 100644 (file)
index 0000000..12f2a9b
--- /dev/null
@@ -0,0 +1,565 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Temporal quantification.
+//!
+//! Example:
+//!
+//! ```
+//! use std::time::Duration;
+//!
+//! let five_seconds = Duration::new(5, 0);
+//! // both declarations are equivalent
+//! assert_eq!(Duration::new(5, 0), Duration::from_secs(5));
+//! ```
+
+#![stable(feature = "time", since = "1.3.0")]
+
+use error::Error;
+use fmt;
+use ops::{Add, Sub, AddAssign, SubAssign};
+use sys::time;
+use sys_common::FromInner;
+
+#[stable(feature = "time", since = "1.3.0")]
+pub use core::time::Duration;
+
+/// A measurement of a monotonically nondecreasing clock.
+/// Opaque and useful only with `Duration`.
+///
+/// Instants are always guaranteed to be no less than any previously measured
+/// instant when created, and are often useful for tasks such as measuring
+/// benchmarks or timing how long an operation takes.
+///
+/// Note, however, that instants are not guaranteed to be **steady**.  In other
+/// words, each tick of the underlying clock may not be the same length (e.g.
+/// some seconds may be longer than others). An instant may jump forwards or
+/// experience time dilation (slow down or speed up), but it will never go
+/// backwards.
+///
+/// Instants are opaque types that can only be compared to one another. There is
+/// no method to get "the number of seconds" from an instant. Instead, it only
+/// allows measuring the duration between two instants (or comparing two
+/// instants).
+///
+/// Example:
+///
+/// ```no_run
+/// use std::time::{Duration, Instant};
+/// use std::thread::sleep;
+///
+/// fn main() {
+///    let now = Instant::now();
+///
+///    // we sleep for 2 seconds
+///    sleep(Duration::new(2, 0));
+///    // it prints '2'
+///    println!("{}", now.elapsed().as_secs());
+/// }
+/// ```
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[stable(feature = "time2", since = "1.8.0")]
+pub struct Instant(time::Instant);
+
+/// A measurement of the system clock, useful for talking to
+/// external entities like the file system or other processes.
+///
+/// Distinct from the [`Instant`] type, this time measurement **is not
+/// monotonic**. This means that you can save a file to the file system, then
+/// save another file to the file system, **and the second file has a
+/// `SystemTime` measurement earlier than the first**. In other words, an
+/// operation that happens after another operation in real time may have an
+/// earlier `SystemTime`!
+///
+/// Consequently, comparing two `SystemTime` instances to learn about the
+/// duration between them returns a [`Result`] instead of an infallible [`Duration`]
+/// to indicate that this sort of time drift may happen and needs to be handled.
+///
+/// Although a `SystemTime` cannot be directly inspected, the [`UNIX_EPOCH`]
+/// constant is provided in this module as an anchor in time to learn
+/// information about a `SystemTime`. By calculating the duration from this
+/// fixed point in time, a `SystemTime` can be converted to a human-readable time,
+/// or perhaps some other string representation.
+///
+/// [`Instant`]: ../../std/time/struct.Instant.html
+/// [`Result`]: ../../std/result/enum.Result.html
+/// [`Duration`]: ../../std/time/struct.Duration.html
+/// [`UNIX_EPOCH`]: ../../std/time/constant.UNIX_EPOCH.html
+///
+/// Example:
+///
+/// ```no_run
+/// use std::time::{Duration, SystemTime};
+/// use std::thread::sleep;
+///
+/// fn main() {
+///    let now = SystemTime::now();
+///
+///    // we sleep for 2 seconds
+///    sleep(Duration::new(2, 0));
+///    match now.elapsed() {
+///        Ok(elapsed) => {
+///            // it prints '2'
+///            println!("{}", elapsed.as_secs());
+///        }
+///        Err(e) => {
+///            // an error occurred!
+///            println!("Error: {:?}", e);
+///        }
+///    }
+/// }
+/// ```
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[stable(feature = "time2", since = "1.8.0")]
+pub struct SystemTime(time::SystemTime);
+
+/// An error returned from the `duration_since` and `elapsed` methods on
+/// `SystemTime`, used to learn how far in the opposite direction a system time
+/// lies.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread::sleep;
+/// use std::time::{Duration, SystemTime};
+///
+/// let sys_time = SystemTime::now();
+/// sleep(Duration::from_secs(1));
+/// let new_sys_time = SystemTime::now();
+/// match sys_time.duration_since(new_sys_time) {
+///     Ok(_) => {}
+///     Err(e) => println!("SystemTimeError difference: {:?}", e.duration()),
+/// }
+/// ```
+#[derive(Clone, Debug)]
+#[stable(feature = "time2", since = "1.8.0")]
+pub struct SystemTimeError(Duration);
+
+impl Instant {
+    /// Returns an instant corresponding to "now".
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::time::Instant;
+    ///
+    /// let now = Instant::now();
+    /// ```
+    #[stable(feature = "time2", since = "1.8.0")]
+    pub fn now() -> Instant {
+        Instant(time::Instant::now())
+    }
+
+    /// Returns the amount of time elapsed from another instant to this one.
+    ///
+    /// # Panics
+    ///
+    /// This function will panic if `earlier` is later than `self`.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::time::{Duration, Instant};
+    /// use std::thread::sleep;
+    ///
+    /// let now = Instant::now();
+    /// sleep(Duration::new(1, 0));
+    /// let new_now = Instant::now();
+    /// println!("{:?}", new_now.duration_since(now));
+    /// ```
+    #[stable(feature = "time2", since = "1.8.0")]
+    pub fn duration_since(&self, earlier: Instant) -> Duration {
+        self.0.sub_instant(&earlier.0)
+    }
+
+    /// Returns the amount of time elapsed since this instant was created.
+    ///
+    /// # Panics
+    ///
+    /// This function may panic if the current time is earlier than this
+    /// instant, which is something that can happen if an `Instant` is
+    /// produced synthetically.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::thread::sleep;
+    /// use std::time::{Duration, Instant};
+    ///
+    /// let instant = Instant::now();
+    /// let three_secs = Duration::from_secs(3);
+    /// sleep(three_secs);
+    /// assert!(instant.elapsed() >= three_secs);
+    /// ```
+    #[stable(feature = "time2", since = "1.8.0")]
+    pub fn elapsed(&self) -> Duration {
+        Instant::now() - *self
+    }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl Add<Duration> for Instant {
+    type Output = Instant;
+
+    fn add(self, other: Duration) -> Instant {
+        Instant(self.0.add_duration(&other))
+    }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl AddAssign<Duration> for Instant {
+    fn add_assign(&mut self, other: Duration) {
+        *self = *self + other;
+    }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl Sub<Duration> for Instant {
+    type Output = Instant;
+
+    fn sub(self, other: Duration) -> Instant {
+        Instant(self.0.sub_duration(&other))
+    }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl SubAssign<Duration> for Instant {
+    fn sub_assign(&mut self, other: Duration) {
+        *self = *self - other;
+    }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl Sub<Instant> for Instant {
+    type Output = Duration;
+
+    fn sub(self, other: Instant) -> Duration {
+        self.duration_since(other)
+    }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl fmt::Debug for Instant {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl SystemTime {
+    /// Returns the system time corresponding to "now".
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::time::SystemTime;
+    ///
+    /// let sys_time = SystemTime::now();
+    /// ```
+    #[stable(feature = "time2", since = "1.8.0")]
+    pub fn now() -> SystemTime {
+        SystemTime(time::SystemTime::now())
+    }
+
+    /// Returns the amount of time elapsed from an earlier point in time.
+    ///
+    /// This function may fail because measurements taken earlier are not
+    /// guaranteed to always be before later measurements (due to anomalies such
+    /// as the system clock being adjusted either forwards or backwards).
+    ///
+    /// If successful, [`Ok`]`(`[`Duration`]`)` is returned where the duration represents
+    /// the amount of time elapsed from the specified measurement to this one.
+    ///
+    /// Returns an [`Err`] if `earlier` is later than `self`, and the error
+    /// contains how far from `self` the time is.
+    ///
+    /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
+    /// [`Duration`]: ../../std/time/struct.Duration.html
+    /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::time::SystemTime;
+    ///
+    /// let sys_time = SystemTime::now();
+    /// let difference = sys_time.duration_since(sys_time)
+    ///                          .expect("SystemTime::duration_since failed");
+    /// println!("{:?}", difference);
+    /// ```
+    #[stable(feature = "time2", since = "1.8.0")]
+    pub fn duration_since(&self, earlier: SystemTime)
+                          -> Result<Duration, SystemTimeError> {
+        self.0.sub_time(&earlier.0).map_err(SystemTimeError)
+    }
+
+    /// Returns the amount of time elapsed since this system time was created.
+    ///
+    /// This function may fail as the underlying system clock is susceptible to
+    /// drift and updates (e.g. the system clock could go backwards), so this
+    /// function may not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is
+    /// returned where the duration represents the amount of time elapsed from
+    /// this time measurement to the current time.
+    ///
+    /// Returns an [`Err`] if `self` is later than the current system time, and
+    /// the error contains how far from the current system time `self` is.
+    ///
+    /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
+    /// [`Duration`]: ../../std/time/struct.Duration.html
+    /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::thread::sleep;
+    /// use std::time::{Duration, SystemTime};
+    ///
+    /// let sys_time = SystemTime::now();
+    /// let one_sec = Duration::from_secs(1);
+    /// sleep(one_sec);
+    /// assert!(sys_time.elapsed().unwrap() >= one_sec);
+    /// ```
+    #[stable(feature = "time2", since = "1.8.0")]
+    pub fn elapsed(&self) -> Result<Duration, SystemTimeError> {
+        SystemTime::now().duration_since(*self)
+    }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl Add<Duration> for SystemTime {
+    type Output = SystemTime;
+
+    fn add(self, dur: Duration) -> SystemTime {
+        SystemTime(self.0.add_duration(&dur))
+    }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl AddAssign<Duration> for SystemTime {
+    fn add_assign(&mut self, other: Duration) {
+        *self = *self + other;
+    }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl Sub<Duration> for SystemTime {
+    type Output = SystemTime;
+
+    fn sub(self, dur: Duration) -> SystemTime {
+        SystemTime(self.0.sub_duration(&dur))
+    }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl SubAssign<Duration> for SystemTime {
+    fn sub_assign(&mut self, other: Duration) {
+        *self = *self - other;
+    }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl fmt::Debug for SystemTime {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+/// An anchor in time which can be used to create new `SystemTime` instances or
+/// learn about where in time a `SystemTime` lies.
+///
+/// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with
+/// respect to the system clock. Using `duration_since` on an existing
+/// [`SystemTime`] instance can tell how far away from this point in time a
+/// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a
+/// [`SystemTime`] instance to represent another fixed point in time.
+///
+/// [`SystemTime`]: ../../std/time/struct.SystemTime.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::time::{SystemTime, UNIX_EPOCH};
+///
+/// match SystemTime::now().duration_since(UNIX_EPOCH) {
+///     Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()),
+///     Err(_) => panic!("SystemTime before UNIX EPOCH!"),
+/// }
+/// ```
+#[stable(feature = "time2", since = "1.8.0")]
+pub const UNIX_EPOCH: SystemTime = SystemTime(time::UNIX_EPOCH);
+
+impl SystemTimeError {
+    /// Returns the positive duration which represents how far forward the
+    /// second system time was from the first.
+    ///
+    /// A `SystemTimeError` is returned from the [`duration_since`] and [`elapsed`]
+    /// methods of [`SystemTime`] whenever the second system time represents a point later
+    /// in time than the `self` of the method call.
+    ///
+    /// [`duration_since`]: ../../std/time/struct.SystemTime.html#method.duration_since
+    /// [`elapsed`]: ../../std/time/struct.SystemTime.html#method.elapsed
+    /// [`SystemTime`]: ../../std/time/struct.SystemTime.html
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::thread::sleep;
+    /// use std::time::{Duration, SystemTime};
+    ///
+    /// let sys_time = SystemTime::now();
+    /// sleep(Duration::from_secs(1));
+    /// let new_sys_time = SystemTime::now();
+    /// match sys_time.duration_since(new_sys_time) {
+    ///     Ok(_) => {}
+    ///     Err(e) => println!("SystemTimeError difference: {:?}", e.duration()),
+    /// }
+    /// ```
+    #[stable(feature = "time2", since = "1.8.0")]
+    pub fn duration(&self) -> Duration {
+        self.0
+    }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl Error for SystemTimeError {
+    fn description(&self) -> &str { "other time was not earlier than self" }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl fmt::Display for SystemTimeError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "second time provided was later than self")
+    }
+}
+
+impl FromInner<time::SystemTime> for SystemTime {
+    fn from_inner(time: time::SystemTime) -> SystemTime {
+        SystemTime(time)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::{Instant, SystemTime, Duration, UNIX_EPOCH};
+
+    macro_rules! assert_almost_eq {
+        ($a:expr, $b:expr) => ({
+            let (a, b) = ($a, $b);
+            if a != b {
+                let (a, b) = if a > b {(a, b)} else {(b, a)};
+                assert!(a - Duration::new(0, 100) <= b);
+            }
+        })
+    }
+
+    #[test]
+    fn instant_monotonic() {
+        let a = Instant::now();
+        let b = Instant::now();
+        assert!(b >= a);
+    }
+
+    #[test]
+    fn instant_elapsed() {
+        let a = Instant::now();
+        a.elapsed();
+    }
+
+    #[test]
+    fn instant_math() {
+        let a = Instant::now();
+        let b = Instant::now();
+        let dur = b.duration_since(a);
+        assert_almost_eq!(b - dur, a);
+        assert_almost_eq!(a + dur, b);
+
+        let second = Duration::new(1, 0);
+        assert_almost_eq!(a - second + second, a);
+    }
+
+    #[test]
+    #[should_panic]
+    fn instant_duration_panic() {
+        let a = Instant::now();
+        (a - Duration::new(1, 0)).duration_since(a);
+    }
+
+    #[test]
+    fn system_time_math() {
+        let a = SystemTime::now();
+        let b = SystemTime::now();
+        match b.duration_since(a) {
+            Ok(dur) if dur == Duration::new(0, 0) => {
+                assert_almost_eq!(a, b);
+            }
+            Ok(dur) => {
+                assert!(b > a);
+                assert_almost_eq!(b - dur, a);
+                assert_almost_eq!(a + dur, b);
+            }
+            Err(dur) => {
+                let dur = dur.duration();
+                assert!(a > b);
+                assert_almost_eq!(b + dur, a);
+                assert_almost_eq!(a - dur, b);
+            }
+        }
+
+        let second = Duration::new(1, 0);
+        assert_almost_eq!(a.duration_since(a - second).unwrap(), second);
+        assert_almost_eq!(a.duration_since(a + second).unwrap_err()
+                           .duration(), second);
+
+        assert_almost_eq!(a - second + second, a);
+
+        // A difference of 80 and 800 years cannot fit inside a 32-bit time_t
+        if !(cfg!(unix) && ::mem::size_of::<::libc::time_t>() <= 4) {
+            let eighty_years = second * 60 * 60 * 24 * 365 * 80;
+            assert_almost_eq!(a - eighty_years + eighty_years, a);
+            assert_almost_eq!(a - (eighty_years * 10) + (eighty_years * 10), a);
+        }
+
+        let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0);
+        let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000)
+            + Duration::new(0, 500_000_000);
+        assert_eq!(one_second_from_epoch, one_second_from_epoch2);
+    }
+
+    #[test]
+    fn system_time_elapsed() {
+        let a = SystemTime::now();
+        drop(a.elapsed());
+    }
+
+    #[test]
+    fn since_epoch() {
+        let ts = SystemTime::now();
+        let a = ts.duration_since(UNIX_EPOCH).unwrap();
+        let b = ts.duration_since(UNIX_EPOCH - Duration::new(1, 0)).unwrap();
+        assert!(b > a);
+        assert_eq!(b - a, Duration::new(1, 0));
+
+        let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30;
+
+        // Right now for CI this test is run in an emulator, and apparently the
+        // aarch64 emulator's sense of time is that we're still living in the
+        // 70s.
+        //
+        // Otherwise let's assume that we're all running computers later than
+        // 2000.
+        if !cfg!(target_arch = "aarch64") {
+            assert!(a > thirty_years);
+        }
+
+        // let's assume that we're all running computers earlier than 2090.
+        // Should give us ~70 years to fix this!
+        let hundred_twenty_years = thirty_years * 4;
+        assert!(a < hundred_twenty_years);
+    }
+}
diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs
deleted file mode 100644 (file)
index ee44483..0000000
+++ /dev/null
@@ -1,590 +0,0 @@
-// Copyright 2012-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 iter::Sum;
-use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign};
-
-const NANOS_PER_SEC: u32 = 1_000_000_000;
-const NANOS_PER_MILLI: u32 = 1_000_000;
-const NANOS_PER_MICRO: u32 = 1_000;
-const MILLIS_PER_SEC: u64 = 1_000;
-const MICROS_PER_SEC: u64 = 1_000_000;
-
-/// A `Duration` type to represent a span of time, typically used for system
-/// timeouts.
-///
-/// Each `Duration` is composed of a whole number of seconds and a fractional part
-/// represented in nanoseconds.  If the underlying system does not support
-/// nanosecond-level precision, APIs binding a system timeout will typically round up
-/// the number of nanoseconds.
-///
-/// `Duration`s implement many common traits, including [`Add`], [`Sub`], and other
-/// [`ops`] traits.
-///
-/// [`Add`]: ../../std/ops/trait.Add.html
-/// [`Sub`]: ../../std/ops/trait.Sub.html
-/// [`ops`]: ../../std/ops/index.html
-///
-/// # Examples
-///
-/// ```
-/// use std::time::Duration;
-///
-/// let five_seconds = Duration::new(5, 0);
-/// let five_seconds_and_five_nanos = five_seconds + Duration::new(0, 5);
-///
-/// assert_eq!(five_seconds_and_five_nanos.as_secs(), 5);
-/// assert_eq!(five_seconds_and_five_nanos.subsec_nanos(), 5);
-///
-/// let ten_millis = Duration::from_millis(10);
-/// ```
-#[stable(feature = "duration", since = "1.3.0")]
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)]
-pub struct Duration {
-    secs: u64,
-    nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC
-}
-
-impl Duration {
-    /// Creates a new `Duration` from the specified number of whole seconds and
-    /// additional nanoseconds.
-    ///
-    /// If the number of nanoseconds is greater than 1 billion (the number of
-    /// nanoseconds in a second), then it will carry over into the seconds provided.
-    ///
-    /// # Panics
-    ///
-    /// This constructor will panic if the carry from the nanoseconds overflows
-    /// the seconds counter.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::time::Duration;
-    ///
-    /// let five_seconds = Duration::new(5, 0);
-    /// ```
-    #[stable(feature = "duration", since = "1.3.0")]
-    #[inline]
-    pub fn new(secs: u64, nanos: u32) -> Duration {
-        let secs = secs.checked_add((nanos / NANOS_PER_SEC) as u64)
-            .expect("overflow in Duration::new");
-        let nanos = nanos % NANOS_PER_SEC;
-        Duration { secs: secs, nanos: nanos }
-    }
-
-    /// Creates a new `Duration` from the specified number of whole seconds.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::time::Duration;
-    ///
-    /// let duration = Duration::from_secs(5);
-    ///
-    /// assert_eq!(5, duration.as_secs());
-    /// assert_eq!(0, duration.subsec_nanos());
-    /// ```
-    #[stable(feature = "duration", since = "1.3.0")]
-    #[inline]
-    pub const fn from_secs(secs: u64) -> Duration {
-        Duration { secs: secs, nanos: 0 }
-    }
-
-    /// Creates a new `Duration` from the specified number of milliseconds.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::time::Duration;
-    ///
-    /// let duration = Duration::from_millis(2569);
-    ///
-    /// assert_eq!(2, duration.as_secs());
-    /// assert_eq!(569_000_000, duration.subsec_nanos());
-    /// ```
-    #[stable(feature = "duration", since = "1.3.0")]
-    #[inline]
-    pub const fn from_millis(millis: u64) -> Duration {
-        Duration {
-            secs: millis / MILLIS_PER_SEC,
-            nanos: ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI,
-        }
-    }
-
-    /// Creates a new `Duration` from the specified number of microseconds.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(duration_from_micros)]
-    /// use std::time::Duration;
-    ///
-    /// let duration = Duration::from_micros(1_000_002);
-    ///
-    /// assert_eq!(1, duration.as_secs());
-    /// assert_eq!(2000, duration.subsec_nanos());
-    /// ```
-    #[unstable(feature = "duration_from_micros", issue = "44400")]
-    #[inline]
-    pub const fn from_micros(micros: u64) -> Duration {
-        Duration {
-            secs: micros / MICROS_PER_SEC,
-            nanos: ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO,
-        }
-    }
-
-    /// Creates a new `Duration` from the specified number of nanoseconds.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(duration_extras)]
-    /// use std::time::Duration;
-    ///
-    /// let duration = Duration::from_nanos(1_000_000_123);
-    ///
-    /// assert_eq!(1, duration.as_secs());
-    /// assert_eq!(123, duration.subsec_nanos());
-    /// ```
-    #[unstable(feature = "duration_extras", issue = "46507")]
-    #[inline]
-    pub const fn from_nanos(nanos: u64) -> Duration {
-        Duration {
-            secs: nanos / (NANOS_PER_SEC as u64),
-            nanos: (nanos % (NANOS_PER_SEC as u64)) as u32,
-        }
-    }
-
-    /// Returns the number of _whole_ seconds contained by this `Duration`.
-    ///
-    /// The returned value does not include the fractional (nanosecond) part of the
-    /// duration, which can be obtained using [`subsec_nanos`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::time::Duration;
-    ///
-    /// let duration = Duration::new(5, 730023852);
-    /// assert_eq!(duration.as_secs(), 5);
-    /// ```
-    ///
-    /// To determine the total number of seconds represented by the `Duration`,
-    /// use `as_secs` in combination with [`subsec_nanos`]:
-    ///
-    /// ```
-    /// use std::time::Duration;
-    ///
-    /// let duration = Duration::new(5, 730023852);
-    ///
-    /// assert_eq!(5.730023852,
-    ///            duration.as_secs() as f64
-    ///            + duration.subsec_nanos() as f64 * 1e-9);
-    /// ```
-    ///
-    /// [`subsec_nanos`]: #method.subsec_nanos
-    #[stable(feature = "duration", since = "1.3.0")]
-    #[inline]
-    pub fn as_secs(&self) -> u64 { self.secs }
-
-    /// Returns the fractional part of this `Duration`, in milliseconds.
-    ///
-    /// This method does **not** return the length of the duration when
-    /// represented by milliseconds. The returned number always represents a
-    /// fractional portion of a second (i.e. it is less than one thousand).
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(duration_extras)]
-    /// use std::time::Duration;
-    ///
-    /// let duration = Duration::from_millis(5432);
-    /// assert_eq!(duration.as_secs(), 5);
-    /// assert_eq!(duration.subsec_millis(), 432);
-    /// ```
-    #[unstable(feature = "duration_extras", issue = "46507")]
-    #[inline]
-    pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI }
-
-    /// Returns the fractional part of this `Duration`, in microseconds.
-    ///
-    /// This method does **not** return the length of the duration when
-    /// represented by microseconds. The returned number always represents a
-    /// fractional portion of a second (i.e. it is less than one million).
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(duration_extras, duration_from_micros)]
-    /// use std::time::Duration;
-    ///
-    /// let duration = Duration::from_micros(1_234_567);
-    /// assert_eq!(duration.as_secs(), 1);
-    /// assert_eq!(duration.subsec_micros(), 234_567);
-    /// ```
-    #[unstable(feature = "duration_extras", issue = "46507")]
-    #[inline]
-    pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO }
-
-    /// Returns the fractional part of this `Duration`, in nanoseconds.
-    ///
-    /// This method does **not** return the length of the duration when
-    /// represented by nanoseconds. The returned number always represents a
-    /// fractional portion of a second (i.e. it is less than one billion).
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::time::Duration;
-    ///
-    /// let duration = Duration::from_millis(5010);
-    /// assert_eq!(duration.as_secs(), 5);
-    /// assert_eq!(duration.subsec_nanos(), 10_000_000);
-    /// ```
-    #[stable(feature = "duration", since = "1.3.0")]
-    #[inline]
-    pub fn subsec_nanos(&self) -> u32 { self.nanos }
-
-    /// Checked `Duration` addition. Computes `self + other`, returning [`None`]
-    /// if overflow occurred.
-    ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::time::Duration;
-    ///
-    /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1)));
-    /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None);
-    /// ```
-    #[stable(feature = "duration_checked_ops", since = "1.16.0")]
-    #[inline]
-    pub fn checked_add(self, rhs: Duration) -> Option<Duration> {
-        if let Some(mut secs) = self.secs.checked_add(rhs.secs) {
-            let mut nanos = self.nanos + rhs.nanos;
-            if nanos >= NANOS_PER_SEC {
-                nanos -= NANOS_PER_SEC;
-                if let Some(new_secs) = secs.checked_add(1) {
-                    secs = new_secs;
-                } else {
-                    return None;
-                }
-            }
-            debug_assert!(nanos < NANOS_PER_SEC);
-            Some(Duration {
-                secs,
-                nanos,
-            })
-        } else {
-            None
-        }
-    }
-
-    /// Checked `Duration` subtraction. Computes `self - other`, returning [`None`]
-    /// if the result would be negative or if overflow occurred.
-    ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::time::Duration;
-    ///
-    /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1)));
-    /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None);
-    /// ```
-    #[stable(feature = "duration_checked_ops", since = "1.16.0")]
-    #[inline]
-    pub fn checked_sub(self, rhs: Duration) -> Option<Duration> {
-        if let Some(mut secs) = self.secs.checked_sub(rhs.secs) {
-            let nanos = if self.nanos >= rhs.nanos {
-                self.nanos - rhs.nanos
-            } else {
-                if let Some(sub_secs) = secs.checked_sub(1) {
-                    secs = sub_secs;
-                    self.nanos + NANOS_PER_SEC - rhs.nanos
-                } else {
-                    return None;
-                }
-            };
-            debug_assert!(nanos < NANOS_PER_SEC);
-            Some(Duration { secs: secs, nanos: nanos })
-        } else {
-            None
-        }
-    }
-
-    /// Checked `Duration` multiplication. Computes `self * other`, returning
-    /// [`None`] if overflow occurred.
-    ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::time::Duration;
-    ///
-    /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2)));
-    /// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None);
-    /// ```
-    #[stable(feature = "duration_checked_ops", since = "1.16.0")]
-    #[inline]
-    pub fn checked_mul(self, rhs: u32) -> Option<Duration> {
-        // Multiply nanoseconds as u64, because it cannot overflow that way.
-        let total_nanos = self.nanos as u64 * rhs as u64;
-        let extra_secs = total_nanos / (NANOS_PER_SEC as u64);
-        let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32;
-        if let Some(secs) = self.secs
-            .checked_mul(rhs as u64)
-            .and_then(|s| s.checked_add(extra_secs)) {
-            debug_assert!(nanos < NANOS_PER_SEC);
-            Some(Duration {
-                secs,
-                nanos,
-            })
-        } else {
-            None
-        }
-    }
-
-    /// Checked `Duration` division. Computes `self / other`, returning [`None`]
-    /// if `other == 0`.
-    ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::time::Duration;
-    ///
-    /// 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);
-    /// ```
-    #[stable(feature = "duration_checked_ops", since = "1.16.0")]
-    #[inline]
-    pub fn checked_div(self, rhs: u32) -> Option<Duration> {
-        if rhs != 0 {
-            let secs = self.secs / (rhs as u64);
-            let carry = self.secs - secs * (rhs as u64);
-            let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64);
-            let nanos = self.nanos / rhs + (extra_nanos as u32);
-            debug_assert!(nanos < NANOS_PER_SEC);
-            Some(Duration { secs: secs, nanos: nanos })
-        } else {
-            None
-        }
-    }
-}
-
-#[stable(feature = "duration", since = "1.3.0")]
-impl Add for Duration {
-    type Output = Duration;
-
-    fn add(self, rhs: Duration) -> Duration {
-        self.checked_add(rhs).expect("overflow when adding durations")
-    }
-}
-
-#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl AddAssign for Duration {
-    fn add_assign(&mut self, rhs: Duration) {
-        *self = *self + rhs;
-    }
-}
-
-#[stable(feature = "duration", since = "1.3.0")]
-impl Sub for Duration {
-    type Output = Duration;
-
-    fn sub(self, rhs: Duration) -> Duration {
-        self.checked_sub(rhs).expect("overflow when subtracting durations")
-    }
-}
-
-#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl SubAssign for Duration {
-    fn sub_assign(&mut self, rhs: Duration) {
-        *self = *self - rhs;
-    }
-}
-
-#[stable(feature = "duration", since = "1.3.0")]
-impl Mul<u32> for Duration {
-    type Output = Duration;
-
-    fn mul(self, rhs: u32) -> Duration {
-        self.checked_mul(rhs).expect("overflow when multiplying duration by scalar")
-    }
-}
-
-#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl MulAssign<u32> for Duration {
-    fn mul_assign(&mut self, rhs: u32) {
-        *self = *self * rhs;
-    }
-}
-
-#[stable(feature = "duration", since = "1.3.0")]
-impl Div<u32> for Duration {
-    type Output = Duration;
-
-    fn div(self, rhs: u32) -> Duration {
-        self.checked_div(rhs).expect("divide by zero error when dividing duration by scalar")
-    }
-}
-
-#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl DivAssign<u32> for Duration {
-    fn div_assign(&mut self, rhs: u32) {
-        *self = *self / rhs;
-    }
-}
-
-#[stable(feature = "duration_sum", since = "1.16.0")]
-impl Sum for Duration {
-    fn sum<I: Iterator<Item=Duration>>(iter: I) -> Duration {
-        iter.fold(Duration::new(0, 0), |a, b| a + b)
-    }
-}
-
-#[stable(feature = "duration_sum", since = "1.16.0")]
-impl<'a> Sum<&'a Duration> for Duration {
-    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);
-    }
-}
diff --git a/src/libstd/time/mod.rs b/src/libstd/time/mod.rs
deleted file mode 100644 (file)
index 6ce3b3e..0000000
+++ /dev/null
@@ -1,567 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Temporal quantification.
-//!
-//! Example:
-//!
-//! ```
-//! use std::time::Duration;
-//!
-//! let five_seconds = Duration::new(5, 0);
-//! // both declarations are equivalent
-//! assert_eq!(Duration::new(5, 0), Duration::from_secs(5));
-//! ```
-
-#![stable(feature = "time", since = "1.3.0")]
-
-use error::Error;
-use fmt;
-use ops::{Add, Sub, AddAssign, SubAssign};
-use sys::time;
-use sys_common::FromInner;
-
-#[stable(feature = "time", since = "1.3.0")]
-pub use self::duration::Duration;
-
-mod duration;
-
-/// A measurement of a monotonically nondecreasing clock.
-/// Opaque and useful only with `Duration`.
-///
-/// Instants are always guaranteed to be no less than any previously measured
-/// instant when created, and are often useful for tasks such as measuring
-/// benchmarks or timing how long an operation takes.
-///
-/// Note, however, that instants are not guaranteed to be **steady**.  In other
-/// words, each tick of the underlying clock may not be the same length (e.g.
-/// some seconds may be longer than others). An instant may jump forwards or
-/// experience time dilation (slow down or speed up), but it will never go
-/// backwards.
-///
-/// Instants are opaque types that can only be compared to one another. There is
-/// no method to get "the number of seconds" from an instant. Instead, it only
-/// allows measuring the duration between two instants (or comparing two
-/// instants).
-///
-/// Example:
-///
-/// ```no_run
-/// use std::time::{Duration, Instant};
-/// use std::thread::sleep;
-///
-/// fn main() {
-///    let now = Instant::now();
-///
-///    // we sleep for 2 seconds
-///    sleep(Duration::new(2, 0));
-///    // it prints '2'
-///    println!("{}", now.elapsed().as_secs());
-/// }
-/// ```
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[stable(feature = "time2", since = "1.8.0")]
-pub struct Instant(time::Instant);
-
-/// A measurement of the system clock, useful for talking to
-/// external entities like the file system or other processes.
-///
-/// Distinct from the [`Instant`] type, this time measurement **is not
-/// monotonic**. This means that you can save a file to the file system, then
-/// save another file to the file system, **and the second file has a
-/// `SystemTime` measurement earlier than the first**. In other words, an
-/// operation that happens after another operation in real time may have an
-/// earlier `SystemTime`!
-///
-/// Consequently, comparing two `SystemTime` instances to learn about the
-/// duration between them returns a [`Result`] instead of an infallible [`Duration`]
-/// to indicate that this sort of time drift may happen and needs to be handled.
-///
-/// Although a `SystemTime` cannot be directly inspected, the [`UNIX_EPOCH`]
-/// constant is provided in this module as an anchor in time to learn
-/// information about a `SystemTime`. By calculating the duration from this
-/// fixed point in time, a `SystemTime` can be converted to a human-readable time,
-/// or perhaps some other string representation.
-///
-/// [`Instant`]: ../../std/time/struct.Instant.html
-/// [`Result`]: ../../std/result/enum.Result.html
-/// [`Duration`]: ../../std/time/struct.Duration.html
-/// [`UNIX_EPOCH`]: ../../std/time/constant.UNIX_EPOCH.html
-///
-/// Example:
-///
-/// ```no_run
-/// use std::time::{Duration, SystemTime};
-/// use std::thread::sleep;
-///
-/// fn main() {
-///    let now = SystemTime::now();
-///
-///    // we sleep for 2 seconds
-///    sleep(Duration::new(2, 0));
-///    match now.elapsed() {
-///        Ok(elapsed) => {
-///            // it prints '2'
-///            println!("{}", elapsed.as_secs());
-///        }
-///        Err(e) => {
-///            // an error occurred!
-///            println!("Error: {:?}", e);
-///        }
-///    }
-/// }
-/// ```
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[stable(feature = "time2", since = "1.8.0")]
-pub struct SystemTime(time::SystemTime);
-
-/// An error returned from the `duration_since` and `elapsed` methods on
-/// `SystemTime`, used to learn how far in the opposite direction a system time
-/// lies.
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::thread::sleep;
-/// use std::time::{Duration, SystemTime};
-///
-/// let sys_time = SystemTime::now();
-/// sleep(Duration::from_secs(1));
-/// let new_sys_time = SystemTime::now();
-/// match sys_time.duration_since(new_sys_time) {
-///     Ok(_) => {}
-///     Err(e) => println!("SystemTimeError difference: {:?}", e.duration()),
-/// }
-/// ```
-#[derive(Clone, Debug)]
-#[stable(feature = "time2", since = "1.8.0")]
-pub struct SystemTimeError(Duration);
-
-impl Instant {
-    /// Returns an instant corresponding to "now".
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::time::Instant;
-    ///
-    /// let now = Instant::now();
-    /// ```
-    #[stable(feature = "time2", since = "1.8.0")]
-    pub fn now() -> Instant {
-        Instant(time::Instant::now())
-    }
-
-    /// Returns the amount of time elapsed from another instant to this one.
-    ///
-    /// # Panics
-    ///
-    /// This function will panic if `earlier` is later than `self`.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::time::{Duration, Instant};
-    /// use std::thread::sleep;
-    ///
-    /// let now = Instant::now();
-    /// sleep(Duration::new(1, 0));
-    /// let new_now = Instant::now();
-    /// println!("{:?}", new_now.duration_since(now));
-    /// ```
-    #[stable(feature = "time2", since = "1.8.0")]
-    pub fn duration_since(&self, earlier: Instant) -> Duration {
-        self.0.sub_instant(&earlier.0)
-    }
-
-    /// Returns the amount of time elapsed since this instant was created.
-    ///
-    /// # Panics
-    ///
-    /// This function may panic if the current time is earlier than this
-    /// instant, which is something that can happen if an `Instant` is
-    /// produced synthetically.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::thread::sleep;
-    /// use std::time::{Duration, Instant};
-    ///
-    /// let instant = Instant::now();
-    /// let three_secs = Duration::from_secs(3);
-    /// sleep(three_secs);
-    /// assert!(instant.elapsed() >= three_secs);
-    /// ```
-    #[stable(feature = "time2", since = "1.8.0")]
-    pub fn elapsed(&self) -> Duration {
-        Instant::now() - *self
-    }
-}
-
-#[stable(feature = "time2", since = "1.8.0")]
-impl Add<Duration> for Instant {
-    type Output = Instant;
-
-    fn add(self, other: Duration) -> Instant {
-        Instant(self.0.add_duration(&other))
-    }
-}
-
-#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl AddAssign<Duration> for Instant {
-    fn add_assign(&mut self, other: Duration) {
-        *self = *self + other;
-    }
-}
-
-#[stable(feature = "time2", since = "1.8.0")]
-impl Sub<Duration> for Instant {
-    type Output = Instant;
-
-    fn sub(self, other: Duration) -> Instant {
-        Instant(self.0.sub_duration(&other))
-    }
-}
-
-#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl SubAssign<Duration> for Instant {
-    fn sub_assign(&mut self, other: Duration) {
-        *self = *self - other;
-    }
-}
-
-#[stable(feature = "time2", since = "1.8.0")]
-impl Sub<Instant> for Instant {
-    type Output = Duration;
-
-    fn sub(self, other: Instant) -> Duration {
-        self.duration_since(other)
-    }
-}
-
-#[stable(feature = "time2", since = "1.8.0")]
-impl fmt::Debug for Instant {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        self.0.fmt(f)
-    }
-}
-
-impl SystemTime {
-    /// Returns the system time corresponding to "now".
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::time::SystemTime;
-    ///
-    /// let sys_time = SystemTime::now();
-    /// ```
-    #[stable(feature = "time2", since = "1.8.0")]
-    pub fn now() -> SystemTime {
-        SystemTime(time::SystemTime::now())
-    }
-
-    /// Returns the amount of time elapsed from an earlier point in time.
-    ///
-    /// This function may fail because measurements taken earlier are not
-    /// guaranteed to always be before later measurements (due to anomalies such
-    /// as the system clock being adjusted either forwards or backwards).
-    ///
-    /// If successful, [`Ok`]`(`[`Duration`]`)` is returned where the duration represents
-    /// the amount of time elapsed from the specified measurement to this one.
-    ///
-    /// Returns an [`Err`] if `earlier` is later than `self`, and the error
-    /// contains how far from `self` the time is.
-    ///
-    /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
-    /// [`Duration`]: ../../std/time/struct.Duration.html
-    /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::time::SystemTime;
-    ///
-    /// let sys_time = SystemTime::now();
-    /// let difference = sys_time.duration_since(sys_time)
-    ///                          .expect("SystemTime::duration_since failed");
-    /// println!("{:?}", difference);
-    /// ```
-    #[stable(feature = "time2", since = "1.8.0")]
-    pub fn duration_since(&self, earlier: SystemTime)
-                          -> Result<Duration, SystemTimeError> {
-        self.0.sub_time(&earlier.0).map_err(SystemTimeError)
-    }
-
-    /// Returns the amount of time elapsed since this system time was created.
-    ///
-    /// This function may fail as the underlying system clock is susceptible to
-    /// drift and updates (e.g. the system clock could go backwards), so this
-    /// function may not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is
-    /// returned where the duration represents the amount of time elapsed from
-    /// this time measurement to the current time.
-    ///
-    /// Returns an [`Err`] if `self` is later than the current system time, and
-    /// the error contains how far from the current system time `self` is.
-    ///
-    /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
-    /// [`Duration`]: ../../std/time/struct.Duration.html
-    /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::thread::sleep;
-    /// use std::time::{Duration, SystemTime};
-    ///
-    /// let sys_time = SystemTime::now();
-    /// let one_sec = Duration::from_secs(1);
-    /// sleep(one_sec);
-    /// assert!(sys_time.elapsed().unwrap() >= one_sec);
-    /// ```
-    #[stable(feature = "time2", since = "1.8.0")]
-    pub fn elapsed(&self) -> Result<Duration, SystemTimeError> {
-        SystemTime::now().duration_since(*self)
-    }
-}
-
-#[stable(feature = "time2", since = "1.8.0")]
-impl Add<Duration> for SystemTime {
-    type Output = SystemTime;
-
-    fn add(self, dur: Duration) -> SystemTime {
-        SystemTime(self.0.add_duration(&dur))
-    }
-}
-
-#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl AddAssign<Duration> for SystemTime {
-    fn add_assign(&mut self, other: Duration) {
-        *self = *self + other;
-    }
-}
-
-#[stable(feature = "time2", since = "1.8.0")]
-impl Sub<Duration> for SystemTime {
-    type Output = SystemTime;
-
-    fn sub(self, dur: Duration) -> SystemTime {
-        SystemTime(self.0.sub_duration(&dur))
-    }
-}
-
-#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl SubAssign<Duration> for SystemTime {
-    fn sub_assign(&mut self, other: Duration) {
-        *self = *self - other;
-    }
-}
-
-#[stable(feature = "time2", since = "1.8.0")]
-impl fmt::Debug for SystemTime {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        self.0.fmt(f)
-    }
-}
-
-/// An anchor in time which can be used to create new `SystemTime` instances or
-/// learn about where in time a `SystemTime` lies.
-///
-/// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with
-/// respect to the system clock. Using `duration_since` on an existing
-/// [`SystemTime`] instance can tell how far away from this point in time a
-/// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a
-/// [`SystemTime`] instance to represent another fixed point in time.
-///
-/// [`SystemTime`]: ../../std/time/struct.SystemTime.html
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::time::{SystemTime, UNIX_EPOCH};
-///
-/// match SystemTime::now().duration_since(UNIX_EPOCH) {
-///     Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()),
-///     Err(_) => panic!("SystemTime before UNIX EPOCH!"),
-/// }
-/// ```
-#[stable(feature = "time2", since = "1.8.0")]
-pub const UNIX_EPOCH: SystemTime = SystemTime(time::UNIX_EPOCH);
-
-impl SystemTimeError {
-    /// Returns the positive duration which represents how far forward the
-    /// second system time was from the first.
-    ///
-    /// A `SystemTimeError` is returned from the [`duration_since`] and [`elapsed`]
-    /// methods of [`SystemTime`] whenever the second system time represents a point later
-    /// in time than the `self` of the method call.
-    ///
-    /// [`duration_since`]: ../../std/time/struct.SystemTime.html#method.duration_since
-    /// [`elapsed`]: ../../std/time/struct.SystemTime.html#method.elapsed
-    /// [`SystemTime`]: ../../std/time/struct.SystemTime.html
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::thread::sleep;
-    /// use std::time::{Duration, SystemTime};
-    ///
-    /// let sys_time = SystemTime::now();
-    /// sleep(Duration::from_secs(1));
-    /// let new_sys_time = SystemTime::now();
-    /// match sys_time.duration_since(new_sys_time) {
-    ///     Ok(_) => {}
-    ///     Err(e) => println!("SystemTimeError difference: {:?}", e.duration()),
-    /// }
-    /// ```
-    #[stable(feature = "time2", since = "1.8.0")]
-    pub fn duration(&self) -> Duration {
-        self.0
-    }
-}
-
-#[stable(feature = "time2", since = "1.8.0")]
-impl Error for SystemTimeError {
-    fn description(&self) -> &str { "other time was not earlier than self" }
-}
-
-#[stable(feature = "time2", since = "1.8.0")]
-impl fmt::Display for SystemTimeError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "second time provided was later than self")
-    }
-}
-
-impl FromInner<time::SystemTime> for SystemTime {
-    fn from_inner(time: time::SystemTime) -> SystemTime {
-        SystemTime(time)
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::{Instant, SystemTime, Duration, UNIX_EPOCH};
-
-    macro_rules! assert_almost_eq {
-        ($a:expr, $b:expr) => ({
-            let (a, b) = ($a, $b);
-            if a != b {
-                let (a, b) = if a > b {(a, b)} else {(b, a)};
-                assert!(a - Duration::new(0, 100) <= b);
-            }
-        })
-    }
-
-    #[test]
-    fn instant_monotonic() {
-        let a = Instant::now();
-        let b = Instant::now();
-        assert!(b >= a);
-    }
-
-    #[test]
-    fn instant_elapsed() {
-        let a = Instant::now();
-        a.elapsed();
-    }
-
-    #[test]
-    fn instant_math() {
-        let a = Instant::now();
-        let b = Instant::now();
-        let dur = b.duration_since(a);
-        assert_almost_eq!(b - dur, a);
-        assert_almost_eq!(a + dur, b);
-
-        let second = Duration::new(1, 0);
-        assert_almost_eq!(a - second + second, a);
-    }
-
-    #[test]
-    #[should_panic]
-    fn instant_duration_panic() {
-        let a = Instant::now();
-        (a - Duration::new(1, 0)).duration_since(a);
-    }
-
-    #[test]
-    fn system_time_math() {
-        let a = SystemTime::now();
-        let b = SystemTime::now();
-        match b.duration_since(a) {
-            Ok(dur) if dur == Duration::new(0, 0) => {
-                assert_almost_eq!(a, b);
-            }
-            Ok(dur) => {
-                assert!(b > a);
-                assert_almost_eq!(b - dur, a);
-                assert_almost_eq!(a + dur, b);
-            }
-            Err(dur) => {
-                let dur = dur.duration();
-                assert!(a > b);
-                assert_almost_eq!(b + dur, a);
-                assert_almost_eq!(a - dur, b);
-            }
-        }
-
-        let second = Duration::new(1, 0);
-        assert_almost_eq!(a.duration_since(a - second).unwrap(), second);
-        assert_almost_eq!(a.duration_since(a + second).unwrap_err()
-                           .duration(), second);
-
-        assert_almost_eq!(a - second + second, a);
-
-        // A difference of 80 and 800 years cannot fit inside a 32-bit time_t
-        if !(cfg!(unix) && ::mem::size_of::<::libc::time_t>() <= 4) {
-            let eighty_years = second * 60 * 60 * 24 * 365 * 80;
-            assert_almost_eq!(a - eighty_years + eighty_years, a);
-            assert_almost_eq!(a - (eighty_years * 10) + (eighty_years * 10), a);
-        }
-
-        let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0);
-        let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000)
-            + Duration::new(0, 500_000_000);
-        assert_eq!(one_second_from_epoch, one_second_from_epoch2);
-    }
-
-    #[test]
-    fn system_time_elapsed() {
-        let a = SystemTime::now();
-        drop(a.elapsed());
-    }
-
-    #[test]
-    fn since_epoch() {
-        let ts = SystemTime::now();
-        let a = ts.duration_since(UNIX_EPOCH).unwrap();
-        let b = ts.duration_since(UNIX_EPOCH - Duration::new(1, 0)).unwrap();
-        assert!(b > a);
-        assert_eq!(b - a, Duration::new(1, 0));
-
-        let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30;
-
-        // Right now for CI this test is run in an emulator, and apparently the
-        // aarch64 emulator's sense of time is that we're still living in the
-        // 70s.
-        //
-        // Otherwise let's assume that we're all running computers later than
-        // 2000.
-        if !cfg!(target_arch = "aarch64") {
-            assert!(a > thirty_years);
-        }
-
-        // let's assume that we're all running computers earlier than 2090.
-        // Should give us ~70 years to fix this!
-        let hundred_twenty_years = thirty_years * 4;
-        assert!(a < hundred_twenty_years);
-    }
-}
index a58a61c36361b4d82f0dd548a1f08464e1344d04..3601b9ba8a8c1cdbf8b5669f1fd42e5f0b17cf17 100644 (file)
@@ -25,6 +25,7 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::StableHasher;
 use std::cell::{RefCell, Ref};
+use std::cmp;
 use std::hash::Hash;
 use std::path::{Path, PathBuf};
 use std::rc::Rc;
@@ -592,8 +593,30 @@ pub fn span_until_char(&self, sp: Span, c: char) -> Span {
         }
     }
 
-    /// Given a `Span`, try to get a shorter span ending just after the first
-    /// occurrence of `char` `c`.
+    /// Given a `Span`, get a new `Span` covering the first token and all its trailing whitespace or
+    /// the original `Span`.
+    ///
+    /// If `sp` points to `"let mut x"`, then a span pointing at `"let "` will be returned.
+    pub fn span_until_non_whitespace(&self, sp: Span) -> Span {
+        if let Ok(snippet) = self.span_to_snippet(sp) {
+            let mut offset = 0;
+            // get the bytes width of all the non-whitespace characters
+            for c in snippet.chars().take_while(|c| !c.is_whitespace()) {
+                offset += c.len_utf8();
+            }
+            // get the bytes width of all the whitespace characters after that
+            for c in snippet[offset..].chars().take_while(|c| c.is_whitespace()) {
+                offset += c.len_utf8();
+            }
+            if offset > 1 {
+                return sp.with_hi(BytePos(sp.lo().0 + offset as u32));
+            }
+        }
+        sp
+    }
+
+    /// Given a `Span`, try to get a shorter span ending just after the first occurrence of `char`
+    /// `c`.
     pub fn span_through_char(&self, sp: Span, c: char) -> Span {
         if let Ok(snippet) = self.span_to_snippet(sp) {
             if let Some(offset) = snippet.find(c) {
@@ -607,6 +630,101 @@ pub fn def_span(&self, sp: Span) -> Span {
         self.span_until_char(sp, '{')
     }
 
+    /// Returns a new span representing just the end-point of this span
+    pub fn end_point(&self, sp: Span) -> Span {
+        let pos = sp.hi().0;
+
+        let width = self.find_width_of_character_at_span(sp, false);
+        let corrected_end_position = pos.checked_sub(width).unwrap_or(pos);
+
+        let end_point = BytePos(cmp::max(corrected_end_position, sp.lo().0));
+        sp.with_lo(end_point)
+    }
+
+    /// Returns a new span representing the next character after the end-point of this span
+    pub fn next_point(&self, sp: Span) -> Span {
+        let start_of_next_point = sp.hi().0;
+
+        let width = self.find_width_of_character_at_span(sp, true);
+        // If the width is 1, then the next span should point to the same `lo` and `hi`. However,
+        // in the case of a multibyte character, where the width != 1, the next span should
+        // span multiple bytes to include the whole character.
+        let end_of_next_point = start_of_next_point.checked_add(
+            width - 1).unwrap_or(start_of_next_point);
+
+        let end_of_next_point = BytePos(cmp::max(sp.lo().0 + 1, end_of_next_point));
+        Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt())
+    }
+
+    /// Finds the width of a character, either before or after the provided span.
+    fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 {
+        // Disregard malformed spans and assume a one-byte wide character.
+        if sp.lo() >= sp.hi() {
+            debug!("find_width_of_character_at_span: early return malformed span");
+            return 1;
+        }
+
+        let local_begin = self.lookup_byte_offset(sp.lo());
+        let local_end = self.lookup_byte_offset(sp.hi());
+        debug!("find_width_of_character_at_span: local_begin=`{:?}`, local_end=`{:?}`",
+               local_begin, local_end);
+
+        let start_index = local_begin.pos.to_usize();
+        let end_index = local_end.pos.to_usize();
+        debug!("find_width_of_character_at_span: start_index=`{:?}`, end_index=`{:?}`",
+               start_index, end_index);
+
+        // Disregard indexes that are at the start or end of their spans, they can't fit bigger
+        // characters.
+        if (!forwards && end_index == usize::min_value()) ||
+            (forwards && start_index == usize::max_value()) {
+            debug!("find_width_of_character_at_span: start or end of span, cannot be multibyte");
+            return 1;
+        }
+
+        let source_len = (local_begin.fm.end_pos - local_begin.fm.start_pos).to_usize();
+        debug!("find_width_of_character_at_span: source_len=`{:?}`", source_len);
+        // Ensure indexes are also not malformed.
+        if start_index > end_index || end_index > source_len {
+            debug!("find_width_of_character_at_span: source indexes are malformed");
+            return 1;
+        }
+
+        // We need to extend the snippet to the end of the src rather than to end_index so when
+        // searching forwards for boundaries we've got somewhere to search.
+        let snippet = if let Some(ref src) = local_begin.fm.src {
+            let len = src.len();
+            (&src[start_index..len]).to_string()
+        } else if let Some(src) = local_begin.fm.external_src.borrow().get_source() {
+            let len = src.len();
+            (&src[start_index..len]).to_string()
+        } else {
+            return 1;
+        };
+        debug!("find_width_of_character_at_span: snippet=`{:?}`", snippet);
+
+        let file_start_pos = local_begin.fm.start_pos.to_usize();
+        let file_end_pos = local_begin.fm.end_pos.to_usize();
+        debug!("find_width_of_character_at_span: file_start_pos=`{:?}` file_end_pos=`{:?}`",
+               file_start_pos, file_end_pos);
+
+        let mut target = if forwards { end_index + 1 } else { end_index - 1 };
+        debug!("find_width_of_character_at_span: initial target=`{:?}`", target);
+
+        while !snippet.is_char_boundary(target - start_index)
+                && target >= file_start_pos && target <= file_end_pos {
+            target = if forwards { target + 1 } else { target - 1 };
+            debug!("find_width_of_character_at_span: target=`{:?}`", target);
+        }
+        debug!("find_width_of_character_at_span: final target=`{:?}`", target);
+
+        if forwards {
+            (target - end_index) as u32
+        } else {
+            (end_index - target) as u32
+        }
+    }
+
     pub fn get_filemap(&self, filename: &FileName) -> Option<Rc<FileMap>> {
         for fm in self.files.borrow().iter() {
             if *filename == fm.name {
index 3e3c1618fffb2de30119d58246fffb69aad263c3..1a9849ca5307de616f1dd4f662ac94e4457a828f 100644 (file)
@@ -90,8 +90,8 @@
 use errors::FatalError;
 use ext::tt::quoted::{self, TokenTree};
 use parse::{Directory, ParseSess};
-use parse::parser::{PathStyle, Parser};
-use parse::token::{self, DocComment, Token, Nonterminal};
+use parse::parser::{Parser, PathStyle};
+use parse::token::{self, DocComment, Nonterminal, Token};
 use print::pprust;
 use symbol::keywords;
 use tokenstream::TokenStream;
 use std::mem;
 use std::rc::Rc;
 use std::collections::HashMap;
-use std::collections::hash_map::Entry::{Vacant, Occupied};
+use std::collections::hash_map::Entry::{Occupied, Vacant};
 
-// To avoid costly uniqueness checks, we require that `MatchSeq` always has
-// a nonempty body.
+// To avoid costly uniqueness checks, we require that `MatchSeq` always has a nonempty body.
 
+/// Either a sequence of token trees or a single one. This is used as the representation of the
+/// sequence of tokens that make up a matcher.
 #[derive(Clone)]
 enum TokenTreeOrTokenTreeVec {
     Tt(TokenTree),
@@ -112,6 +113,8 @@ enum TokenTreeOrTokenTreeVec {
 }
 
 impl TokenTreeOrTokenTreeVec {
+    /// Returns the number of constituent top-level token trees of `self` (top-level in that it
+    /// will not recursively descend into subtrees).
     fn len(&self) -> usize {
         match *self {
             TtSeq(ref v) => v.len(),
@@ -119,6 +122,7 @@ fn len(&self) -> usize {
         }
     }
 
+    /// The the `index`-th token tree of `self`.
     fn get_tt(&self, index: usize) -> TokenTree {
         match *self {
             TtSeq(ref v) => v[index].clone(),
@@ -127,36 +131,96 @@ fn get_tt(&self, index: usize) -> TokenTree {
     }
 }
 
-/// an unzipping of `TokenTree`s
+/// An unzipping of `TokenTree`s... see the `stack` field of `MatcherPos`.
+///
+/// This is used by `inner_parse_loop` to keep track of delimited submatchers that we have
+/// descended into.
 #[derive(Clone)]
 struct MatcherTtFrame {
+    /// The "parent" matcher that we are descending into.
     elts: TokenTreeOrTokenTreeVec,
+    /// The position of the "dot" in `elts` at the time we descended.
     idx: usize,
 }
 
+/// Represents a single "position" (aka "matcher position", aka "item"), as described in the module
+/// documentation.
 #[derive(Clone)]
 struct MatcherPos {
-    stack: Vec<MatcherTtFrame>,
+    /// The token or sequence of tokens that make up the matcher
     top_elts: TokenTreeOrTokenTreeVec,
-    sep: Option<Token>,
+    /// The position of the "dot" in this matcher
     idx: usize,
-    up: Option<Box<MatcherPos>>,
+    /// The beginning position in the source that the beginning of this matcher corresponds to. In
+    /// other words, the token in the source at `sp_lo` is matched against the first token of the
+    /// matcher.
+    sp_lo: BytePos,
+
+    /// For each named metavar in the matcher, we keep track of token trees matched against the
+    /// metavar by the black box parser. In particular, there may be more than one match per
+    /// metavar if we are in a repetition (each repetition matches each of the variables).
+    /// Moreover, matchers and repetitions can be nested; the `matches` field is shared (hence the
+    /// `Rc`) among all "nested" matchers. `match_lo`, `match_cur`, and `match_hi` keep track of
+    /// the current position of the `self` matcher position in the shared `matches` list.
+    ///
+    /// Also, note that while we are descending into a sequence, matchers are given their own
+    /// `matches` vector. Only once we reach the end of a full repetition of the sequence do we add
+    /// all bound matches from the submatcher into the shared top-level `matches` vector. If `sep`
+    /// and `up` are `Some`, then `matches` is _not_ the shared top-level list. Instead, if one
+    /// wants the shared `matches`, one should use `up.matches`.
     matches: Vec<Rc<Vec<NamedMatch>>>,
+    /// The position in `matches` corresponding to the first metavar in this matcher's sequence of
+    /// token trees. In other words, the first metavar in the first token of `top_elts` corresponds
+    /// to `matches[match_lo]`.
     match_lo: usize,
+    /// The position in `matches` corresponding to the metavar we are currently trying to match
+    /// against the source token stream. `match_lo <= match_cur <= match_hi`.
     match_cur: usize,
+    /// Similar to `match_lo` except `match_hi` is the position in `matches` of the _last_ metavar
+    /// in this matcher.
     match_hi: usize,
-    sp_lo: BytePos,
+
+    // Specifically used if we are matching a repetition. If we aren't both should be `None`.
+    /// The separator if we are in a repetition
+    sep: Option<Token>,
+    /// The "parent" matcher position if we are in a repetition. That is, the matcher position just
+    /// before we enter the sequence.
+    up: Option<Box<MatcherPos>>,
+
+    // Specifically used to "unzip" token trees. By "unzip", we mean to unwrap the delimiters from
+    // a delimited token tree (e.g. something wrapped in `(` `)`) or to get the contents of a doc
+    // comment...
+    /// When matching against matchers with nested delimited submatchers (e.g. `pat ( pat ( .. )
+    /// pat ) pat`), we need to keep track of the matchers we are descending into. This stack does
+    /// that where the bottom of the stack is the outermost matcher.
+    // Also, throughout the comments, this "descent" is often referred to as "unzipping"...
+    stack: Vec<MatcherTtFrame>,
 }
 
 impl MatcherPos {
+    /// Add `m` as a named match for the `idx`-th metavar.
     fn push_match(&mut self, idx: usize, m: NamedMatch) {
         let matches = Rc::make_mut(&mut self.matches[idx]);
         matches.push(m);
     }
 }
 
+/// Represents the possible results of an attempted parse.
+pub enum ParseResult<T> {
+    /// Parsed successfully.
+    Success(T),
+    /// Arm failed to match. If the second parameter is `token::Eof`, it indicates an unexpected
+    /// end of macro invocation. Otherwise, it indicates that no rules expected the given token.
+    Failure(syntax_pos::Span, Token),
+    /// Fatal error (malformed macro?). Abort compilation.
+    Error(syntax_pos::Span, String),
+}
+
+/// A `ParseResult` where the `Success` variant contains a mapping of `Ident`s to `NamedMatch`es.
+/// This represents the mapping of metavars to the token trees they bind to.
 pub type NamedParseResult = ParseResult<HashMap<Ident, Rc<NamedMatch>>>;
 
+/// Count how many metavars are named in the given matcher `ms`.
 pub fn count_names(ms: &[TokenTree]) -> usize {
     ms.iter().fold(0, |count, elt| {
         count + match *elt {
@@ -169,20 +233,38 @@ pub fn count_names(ms: &[TokenTree]) -> usize {
     })
 }
 
+/// Initialize `len` empty shared `Vec`s to be used to store matches of metavars.
+fn create_matches(len: usize) -> Vec<Rc<Vec<NamedMatch>>> {
+    (0..len).into_iter().map(|_| Rc::new(Vec::new())).collect()
+}
+
+/// Generate the top-level matcher position in which the "dot" is before the first token of the
+/// matcher `ms` and we are going to start matching at position `lo` in the source.
 fn initial_matcher_pos(ms: Vec<TokenTree>, lo: BytePos) -> Box<MatcherPos> {
     let match_idx_hi = count_names(&ms[..]);
     let matches = create_matches(match_idx_hi);
     Box::new(MatcherPos {
-        stack: vec![],
-        top_elts: TtSeq(ms),
-        sep: None,
+        // Start with the top level matcher given to us
+        top_elts: TtSeq(ms), // "elts" is an abbr. for "elements"
+        // The "dot" is before the first token of the matcher
         idx: 0,
-        up: None,
+        // We start matching with byte `lo` in the source code
+        sp_lo: lo,
+
+        // Initialize `matches` to a bunch of empty `Vec`s -- one for each metavar in `top_elts`.
+        // `match_lo` for `top_elts` is 0 and `match_hi` is `matches.len()`. `match_cur` is 0 since
+        // we haven't actually matched anything yet.
         matches,
         match_lo: 0,
         match_cur: 0,
         match_hi: match_idx_hi,
-        sp_lo: lo
+
+        // Haven't descended into any delimiters, so empty stack
+        stack: vec![],
+
+        // Haven't descended into any sequences, so both of these are `None`.
+        sep: None,
+        up: None,
     })
 }
 
@@ -202,29 +284,36 @@ fn initial_matcher_pos(ms: Vec<TokenTree>, lo: BytePos) -> Box<MatcherPos> {
 /// token tree. The depth of the `NamedMatch` structure will therefore depend
 /// only on the nesting depth of `ast::TTSeq`s in the originating
 /// token tree it was derived from.
-
 #[derive(Debug, Clone)]
 pub enum NamedMatch {
     MatchedSeq(Rc<Vec<NamedMatch>>, syntax_pos::Span),
-    MatchedNonterminal(Rc<Nonterminal>)
+    MatchedNonterminal(Rc<Nonterminal>),
 }
 
-fn nameize<I: Iterator<Item=NamedMatch>>(sess: &ParseSess, ms: &[TokenTree], mut res: I)
-                                             -> NamedParseResult {
-    fn n_rec<I: Iterator<Item=NamedMatch>>(sess: &ParseSess, m: &TokenTree, res: &mut I,
-             ret_val: &mut HashMap<Ident, Rc<NamedMatch>>)
-             -> Result<(), (syntax_pos::Span, String)> {
+/// Takes a sequence of token trees `ms` representing a matcher which successfully matched input
+/// and an iterator of items that matched input and produces a `NamedParseResult`.
+fn nameize<I: Iterator<Item = NamedMatch>>(
+    sess: &ParseSess,
+    ms: &[TokenTree],
+    mut res: I,
+) -> NamedParseResult {
+    // Recursively descend into each type of matcher (e.g. sequences, delimited, metavars) and make
+    // sure that each metavar has _exactly one_ binding. If a metavar does not have exactly one
+    // binding, then there is an error. If it does, then we insert the binding into the
+    // `NamedParseResult`.
+    fn n_rec<I: Iterator<Item = NamedMatch>>(
+        sess: &ParseSess,
+        m: &TokenTree,
+        res: &mut I,
+        ret_val: &mut HashMap<Ident, Rc<NamedMatch>>,
+    ) -> Result<(), (syntax_pos::Span, String)> {
         match *m {
-            TokenTree::Sequence(_, ref seq) => {
-                for next_m in &seq.tts {
-                    n_rec(sess, next_m, res.by_ref(), ret_val)?
-                }
-            }
-            TokenTree::Delimited(_, ref delim) => {
-                for next_m in &delim.tts {
-                    n_rec(sess, next_m, res.by_ref(), ret_val)?;
-                }
-            }
+            TokenTree::Sequence(_, ref seq) => for next_m in &seq.tts {
+                n_rec(sess, next_m, res.by_ref(), ret_val)?
+            },
+            TokenTree::Delimited(_, ref delim) => for next_m in &delim.tts {
+                n_rec(sess, next_m, res.by_ref(), ret_val)?;
+            },
             TokenTree::MetaVarDecl(span, _, id) if id.name == keywords::Invalid.name() => {
                 if sess.missing_fragment_specifiers.borrow_mut().remove(&span) {
                     return Err((span, "missing fragment specifier".to_string()));
@@ -250,7 +339,7 @@ fn n_rec<I: Iterator<Item=NamedMatch>>(sess: &ParseSess, m: &TokenTree, res: &mu
     let mut ret_val = HashMap::new();
     for m in ms {
         match n_rec(sess, m, res.by_ref(), &mut ret_val) {
-            Ok(_) => {},
+            Ok(_) => {}
             Err((sp, msg)) => return Error(sp, msg),
         }
     }
@@ -258,25 +347,20 @@ fn n_rec<I: Iterator<Item=NamedMatch>>(sess: &ParseSess, m: &TokenTree, res: &mu
     Success(ret_val)
 }
 
-pub enum ParseResult<T> {
-    Success(T),
-    /// Arm failed to match. If the second parameter is `token::Eof`, it
-    /// indicates an unexpected end of macro invocation. Otherwise, it
-    /// indicates that no rules expected the given token.
-    Failure(syntax_pos::Span, Token),
-    /// Fatal error (malformed macro?). Abort compilation.
-    Error(syntax_pos::Span, String)
-}
-
+/// Generate an appropriate parsing failure message. For EOF, this is "unexpected end...". For
+/// other tokens, this is "unexpected token...".
 pub fn parse_failure_msg(tok: Token) -> String {
     match tok {
         token::Eof => "unexpected end of macro invocation".to_string(),
-        _ => format!("no rules expected the token `{}`", pprust::token_to_string(&tok)),
+        _ => format!(
+            "no rules expected the token `{}`",
+            pprust::token_to_string(&tok)
+        ),
     }
 }
 
 /// Perform a token equality check, ignoring syntax context (that is, an unhygienic comparison)
-fn token_name_eq(t1 : &Token, t2 : &Token) -> bool {
+fn token_name_eq(t1: &Token, t2: &Token) -> bool {
     if let (Some(id1), Some(id2)) = (t1.ident(), t2.ident()) {
         id1.name == id2.name
     } else if let (&token::Lifetime(id1), &token::Lifetime(id2)) = (t1, t2) {
@@ -286,77 +370,121 @@ fn token_name_eq(t1 : &Token, t2 : &Token) -> bool {
     }
 }
 
-fn create_matches(len: usize) -> Vec<Rc<Vec<NamedMatch>>> {
-    (0..len).into_iter().map(|_| Rc::new(Vec::new())).collect()
-}
-
-fn inner_parse_loop(sess: &ParseSess,
-                    cur_items: &mut SmallVector<Box<MatcherPos>>,
-                    next_items: &mut Vec<Box<MatcherPos>>,
-                    eof_items: &mut SmallVector<Box<MatcherPos>>,
-                    bb_items: &mut SmallVector<Box<MatcherPos>>,
-                    token: &Token,
-                    span: syntax_pos::Span)
-                    -> ParseResult<()> {
+/// Process the matcher positions of `cur_items` until it is empty. In the process, this will
+/// produce more items in `next_items`, `eof_items`, and `bb_items`.
+///
+/// For more info about the how this happens, see the module-level doc comments and the inline
+/// comments of this function.
+///
+/// # Parameters
+///
+/// - `sess`: the parsing session into which errors are emitted.
+/// - `cur_items`: the set of current items to be processed. This should be empty by the end of a
+///   successful execution of this function.
+/// - `next_items`: the set of newly generated items. These are used to replenish `cur_items` in
+///   the function `parse`.
+/// - `eof_items`: the set of items that would be valid if this was the EOF.
+/// - `bb_items`: the set of items that are waiting for the black-box parser.
+/// - `token`: the current token of the parser.
+/// - `span`: the `Span` in the source code corresponding to the token trees we are trying to match
+///   against the matcher positions in `cur_items`.
+///
+/// # Returns
+///
+/// A `ParseResult`. Note that matches are kept track of through the items generated.
+fn inner_parse_loop(
+    sess: &ParseSess,
+    cur_items: &mut SmallVector<Box<MatcherPos>>,
+    next_items: &mut Vec<Box<MatcherPos>>,
+    eof_items: &mut SmallVector<Box<MatcherPos>>,
+    bb_items: &mut SmallVector<Box<MatcherPos>>,
+    token: &Token,
+    span: syntax_pos::Span,
+) -> ParseResult<()> {
+    // Pop items from `cur_items` until it is empty.
     while let Some(mut item) = cur_items.pop() {
-        // When unzipped trees end, remove them
+        // When unzipped trees end, remove them. This corresponds to backtracking out of a
+        // delimited submatcher into which we already descended. In backtracking out again, we need
+        // to advance the "dot" past the delimiters in the outer matcher.
         while item.idx >= item.top_elts.len() {
             match item.stack.pop() {
                 Some(MatcherTtFrame { elts, idx }) => {
                     item.top_elts = elts;
                     item.idx = idx + 1;
                 }
-                None => break
+                None => break,
             }
         }
 
+        // Get the current position of the "dot" (`idx`) in `item` and the number of token trees in
+        // the matcher (`len`).
         let idx = item.idx;
         let len = item.top_elts.len();
 
-        // at end of sequence
+        // If `idx >= len`, then we are at or past the end of the matcher of `item`.
         if idx >= len {
-            // We are repeating iff there is a parent
+            // We are repeating iff there is a parent. If the matcher is inside of a repetition,
+            // then we could be at the end of a sequence or at the beginning of the next
+            // repetition.
             if item.up.is_some() {
-                // Disregarding the separator, add the "up" case to the tokens that should be
-                // examined.
-                // (remove this condition to make trailing seps ok)
+                // At this point, regardless of whether there is a separator, we should add all
+                // matches from the complete repetition of the sequence to the shared, top-level
+                // `matches` list (actually, `up.matches`, which could itself not be the top-level,
+                // but anyway...). Moreover, we add another item to `cur_items` in which the "dot"
+                // is at the end of the `up` matcher. This ensures that the "dot" in the `up`
+                // matcher is also advanced sufficiently.
+                //
+                // NOTE: removing the condition `idx == len` allows trailing separators.
                 if idx == len {
+                    // Get the `up` matcher
                     let mut new_pos = item.up.clone().unwrap();
 
-                    // update matches (the MBE "parse tree") by appending
-                    // each tree as a subtree.
-
-                    // Only touch the binders we have actually bound
+                    // Add matches from this repetition to the `matches` of `up`
                     for idx in item.match_lo..item.match_hi {
                         let sub = item.matches[idx].clone();
                         let span = span.with_lo(item.sp_lo);
                         new_pos.push_match(idx, MatchedSeq(sub, span));
                     }
 
+                    // Move the "dot" past the repetition in `up`
                     new_pos.match_cur = item.match_hi;
                     new_pos.idx += 1;
                     cur_items.push(new_pos);
                 }
 
-                // Check if we need a separator
+                // Check if we need a separator.
                 if idx == len && item.sep.is_some() {
-                    // We have a separator, and it is the current token.
-                    if item.sep.as_ref().map(|sep| token_name_eq(token, sep)).unwrap_or(false) {
+                    // We have a separator, and it is the current token. We can advance past the
+                    // separator token.
+                    if item.sep
+                        .as_ref()
+                        .map(|sep| token_name_eq(token, sep))
+                        .unwrap_or(false)
+                    {
                         item.idx += 1;
                         next_items.push(item);
                     }
-                } else { // we don't need a separator
+                }
+                // We don't need a separator. Move the "dot" back to the beginning of the matcher
+                // and try to match again.
+                else {
                     item.match_cur = item.match_lo;
                     item.idx = 0;
                     cur_items.push(item);
                 }
-            } else {
-                // We aren't repeating, so we must be potentially at the end of the input.
+            }
+            // If we are not in a repetition, then being at the end of a matcher means that we have
+            // reached the potential end of the input.
+            else {
                 eof_items.push(item);
             }
-        } else {
+        }
+        // We are in the middle of a matcher.
+        else {
+            // Look at what token in the matcher we are trying to match the current token (`token`)
+            // against. Depending on that, we may generate new items.
             match item.top_elts.get_tt(idx) {
-                /* need to descend into sequence */
+                // Need to descend into a sequence
                 TokenTree::Sequence(sp, seq) => {
                     if seq.op == quoted::KleeneOp::ZeroOrMore {
                         // Examine the case where there are 0 matches of this sequence
@@ -384,11 +512,16 @@ fn inner_parse_loop(sess: &ParseSess,
                         top_elts: Tt(TokenTree::Sequence(sp, seq)),
                     }));
                 }
+
+                // We need to match a metavar (but the identifier is invalid)... this is an error
                 TokenTree::MetaVarDecl(span, _, id) if id.name == keywords::Invalid.name() => {
                     if sess.missing_fragment_specifiers.borrow_mut().remove(&span) {
                         return Error(span, "missing fragment specifier".to_string());
                     }
                 }
+
+                // We need to match a metavar with a valid ident... call out to the black-box
+                // parser by adding an item to `bb_items`.
                 TokenTree::MetaVarDecl(_, _, id) => {
                     // Built-in nonterminals never start with these tokens,
                     // so we can eliminate them from consideration.
@@ -396,6 +529,13 @@ fn inner_parse_loop(sess: &ParseSess,
                         bb_items.push(item);
                     }
                 }
+
+                // We need to descend into a delimited submatcher or a doc comment. To do this, we
+                // push the current matcher onto a stack and push a new item containing the
+                // submatcher onto `cur_items`.
+                //
+                // At the beginning of the loop, if we reach the end of the delimited submatcher,
+                // we pop the stack to backtrack out of the descent.
                 seq @ TokenTree::Delimited(..) | seq @ TokenTree::Token(_, DocComment(..)) => {
                     let lower_elts = mem::replace(&mut item.top_elts, Tt(seq));
                     let idx = item.idx;
@@ -406,36 +546,76 @@ fn inner_parse_loop(sess: &ParseSess,
                     item.idx = 0;
                     cur_items.push(item);
                 }
+
+                // We just matched a normal token. We can just advance the parser.
                 TokenTree::Token(_, ref t) if token_name_eq(t, token) => {
                     item.idx += 1;
                     next_items.push(item);
                 }
+
+                // There was another token that was not `token`... This means we can't add any
+                // rules. NOTE that this is not necessarily an error unless _all_ items in
+                // `cur_items` end up doing this. There may still be some other matchers that do
+                // end up working out.
                 TokenTree::Token(..) | TokenTree::MetaVar(..) => {}
             }
         }
     }
 
+    // Yay a successful parse (so far)!
     Success(())
 }
 
-pub fn parse(sess: &ParseSess,
-             tts: TokenStream,
-             ms: &[TokenTree],
-             directory: Option<Directory>,
-             recurse_into_modules: bool)
-             -> NamedParseResult {
+/// Use the given sequence of token trees (`ms`) as a matcher. Match the given token stream `tts`
+/// against it and return the match.
+///
+/// # Parameters
+///
+/// - `sess`: The session into which errors are emitted
+/// - `tts`: The tokenstream we are matching against the pattern `ms`
+/// - `ms`: A sequence of token trees representing a pattern against which we are matching
+/// - `directory`: Information about the file locations (needed for the black-box parser)
+/// - `recurse_into_modules`: Whether or not to recurse into modules (needed for the black-box
+///   parser)
+pub fn parse(
+    sess: &ParseSess,
+    tts: TokenStream,
+    ms: &[TokenTree],
+    directory: Option<Directory>,
+    recurse_into_modules: bool,
+) -> NamedParseResult {
+    // Create a parser that can be used for the "black box" parts.
     let mut parser = Parser::new(sess, tts, directory, recurse_into_modules, true);
+
+    // A queue of possible matcher positions. We initialize it with the matcher position in which
+    // the "dot" is before the first token of the first token tree in `ms`. `inner_parse_loop` then
+    // processes all of these possible matcher positions and produces posible next positions into
+    // `next_items`. After some post-processing, the contents of `next_items` replenish `cur_items`
+    // and we start over again.
     let mut cur_items = SmallVector::one(initial_matcher_pos(ms.to_owned(), parser.span.lo()));
-    let mut next_items = Vec::new(); // or proceed normally
+    let mut next_items = Vec::new();
 
     loop {
-        let mut bb_items = SmallVector::new(); // black-box parsed by parser.rs
+        // Matcher positions black-box parsed by parser.rs (`parser`)
+        let mut bb_items = SmallVector::new();
+
+        // Matcher positions that would be valid if the macro invocation was over now
         let mut eof_items = SmallVector::new();
         assert!(next_items.is_empty());
 
-        match inner_parse_loop(sess, &mut cur_items, &mut next_items, &mut eof_items, &mut bb_items,
-                               &parser.token, parser.span) {
-            Success(_) => {},
+        // Process `cur_items` until either we have finished the input or we need to get some
+        // parsing from the black-box parser done. The result is that `next_items` will contain a
+        // bunch of possible next matcher positions in `next_items`.
+        match inner_parse_loop(
+            sess,
+            &mut cur_items,
+            &mut next_items,
+            &mut eof_items,
+            &mut bb_items,
+            &parser.token,
+            parser.span,
+        ) {
+            Success(_) => {}
             Failure(sp, tok) => return Failure(sp, tok),
             Error(sp, msg) => return Error(sp, msg),
         }
@@ -443,46 +623,75 @@ pub fn parse(sess: &ParseSess,
         // inner parse loop handled all cur_items, so it's empty
         assert!(cur_items.is_empty());
 
-        /* error messages here could be improved with links to orig. rules */
+        // We need to do some post processing after the `inner_parser_loop`.
+        //
+        // Error messages here could be improved with links to original rules.
+
+        // If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise,
+        // either the parse is ambiguous (which should never happen) or their is a syntax error.
         if token_name_eq(&parser.token, &token::Eof) {
             if eof_items.len() == 1 {
-                let matches = eof_items[0].matches.iter_mut().map(|dv| {
-                    Rc::make_mut(dv).pop().unwrap()
-                });
+                let matches = eof_items[0]
+                    .matches
+                    .iter_mut()
+                    .map(|dv| Rc::make_mut(dv).pop().unwrap());
                 return nameize(sess, ms, matches);
             } else if eof_items.len() > 1 {
-                return Error(parser.span, "ambiguity: multiple successful parses".to_string());
+                return Error(
+                    parser.span,
+                    "ambiguity: multiple successful parses".to_string(),
+                );
             } else {
                 return Failure(parser.span, token::Eof);
             }
-        } else if (!bb_items.is_empty() && !next_items.is_empty()) || bb_items.len() > 1 {
-            let nts = bb_items.iter().map(|item| match item.top_elts.get_tt(item.idx) {
-                TokenTree::MetaVarDecl(_, bind, name) => {
-                    format!("{} ('{}')", name, bind)
-                }
-                _ => panic!()
-            }).collect::<Vec<String>>().join(" or ");
-
-            return Error(parser.span, format!(
-                "local ambiguity: multiple parsing options: {}",
-                match next_items.len() {
-                    0 => format!("built-in NTs {}.", nts),
-                    1 => format!("built-in NTs {} or 1 other option.", nts),
-                    n => format!("built-in NTs {} or {} other options.", nts, n),
-                }
-            ));
-        } else if bb_items.is_empty() && next_items.is_empty() {
+        }
+        // Another possibility is that we need to call out to parse some rust nonterminal
+        // (black-box) parser. However, if there is not EXACTLY ONE of these, something is wrong.
+        else if (!bb_items.is_empty() && !next_items.is_empty()) || bb_items.len() > 1 {
+            let nts = bb_items
+                .iter()
+                .map(|item| match item.top_elts.get_tt(item.idx) {
+                    TokenTree::MetaVarDecl(_, bind, name) => format!("{} ('{}')", name, bind),
+                    _ => panic!(),
+                })
+                .collect::<Vec<String>>()
+                .join(" or ");
+
+            return Error(
+                parser.span,
+                format!(
+                    "local ambiguity: multiple parsing options: {}",
+                    match next_items.len() {
+                        0 => format!("built-in NTs {}.", nts),
+                        1 => format!("built-in NTs {} or 1 other option.", nts),
+                        n => format!("built-in NTs {} or {} other options.", nts, n),
+                    }
+                ),
+            );
+        }
+        // If there are no posible next positions AND we aren't waiting for the black-box parser,
+        // then their is a syntax error.
+        else if bb_items.is_empty() && next_items.is_empty() {
             return Failure(parser.span, parser.token);
-        } else if !next_items.is_empty() {
-            /* Now process the next token */
+        }
+        // Dump all possible `next_items` into `cur_items` for the next iteration.
+        else if !next_items.is_empty() {
+            // Now process the next token
             cur_items.extend(next_items.drain(..));
             parser.bump();
-        } else /* bb_items.len() == 1 */ {
+        }
+        // Finally, we have the case where we need to call the black-box parser to get some
+        // nonterminal.
+        else {
+            assert_eq!(bb_items.len(), 1);
+
             let mut item = bb_items.pop().unwrap();
             if let TokenTree::MetaVarDecl(span, _, ident) = item.top_elts.get_tt(item.idx) {
                 let match_cur = item.match_cur;
-                item.push_match(match_cur,
-                    MatchedNonterminal(Rc::new(parse_nt(&mut parser, span, &ident.name.as_str()))));
+                item.push_match(
+                    match_cur,
+                    MatchedNonterminal(Rc::new(parse_nt(&mut parser, span, &ident.name.as_str()))),
+                );
                 item.idx += 1;
                 item.match_cur += 1;
             } else {
@@ -512,20 +721,21 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
         "expr" => token.can_begin_expr(),
         "ty" => token.can_begin_type(),
         "ident" => token.is_ident(),
-        "vis" => match *token { // The follow-set of :vis + "priv" keyword + interpolated
+        "vis" => match *token {
+            // The follow-set of :vis + "priv" keyword + interpolated
             Token::Comma | Token::Ident(_) | Token::Interpolated(_) => true,
             _ => token.can_begin_type(),
         },
         "block" => match *token {
             Token::OpenDelim(token::Brace) => true,
             Token::Interpolated(ref nt) => match nt.0 {
-                token::NtItem(_) |
-                token::NtPat(_) |
-                token::NtTy(_) |
-                token::NtIdent(_) |
-                token::NtMeta(_) |
-                token::NtPath(_) |
-                token::NtVis(_) => false, // none of these may start with '{'.
+                token::NtItem(_)
+                | token::NtPat(_)
+                | token::NtTy(_)
+                | token::NtIdent(_)
+                | token::NtMeta(_)
+                | token::NtPath(_)
+                token::NtVis(_) => false, // none of these may start with '{'.
                 _ => true,
             },
             _ => false,
@@ -562,6 +772,18 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
     }
 }
 
+/// A call to the "black-box" parser to parse some rust nonterminal.
+///
+/// # Parameters
+///
+/// - `p`: the "black-box" parser to use
+/// - `sp`: the `Span` we want to parse
+/// - `name`: the name of the metavar _matcher_ we want to match (e.g. `tt`, `ident`, `block`,
+///   etc...)
+///
+/// # Returns
+///
+/// The parsed nonterminal.
 fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
     if name == "tt" {
         return token::NtTT(p.parse_token_tree());
@@ -591,12 +813,15 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
         "ident" => match p.token {
             token::Ident(sn) => {
                 p.bump();
-                token::NtIdent(Spanned::<Ident>{node: sn, span: p.prev_span})
+                token::NtIdent(Spanned::<Ident> {
+                    node: sn,
+                    span: p.prev_span,
+                })
             }
             _ => {
                 let token_str = pprust::token_to_string(&p.token);
-                p.fatal(&format!("expected ident, found {}",
-                                 &token_str[..])).emit();
+                p.fatal(&format!("expected ident, found {}", &token_str[..]))
+                    .emit();
                 FatalError.raise()
             }
         },
@@ -606,6 +831,6 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
         "lifetime" => token::NtLifetime(p.expect_lifetime()),
         // this is not supposed to happen, since it has been checked
         // when compiling the macro.
-        _ => p.span_bug(sp, "invalid fragment specifier")
+        _ => p.span_bug(sp, "invalid fragment specifier"),
     }
 }
index 0e21e3f6b00109e48863721368f91167262446a1..c55dfaba8f6b26bec457ea005cc78aa0d465d95b 100644 (file)
 
 use ast;
 use ext::tt::macro_parser;
-use parse::{ParseSess, token};
+use parse::{token, ParseSess};
 use print::pprust;
 use symbol::keywords;
-use syntax_pos::{DUMMY_SP, Span, BytePos};
+use syntax_pos::{BytePos, Span, DUMMY_SP};
 use tokenstream;
 
 use std::rc::Rc;
 
+/// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note
+/// that the delimiter itself might be `NoDelim`.
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct Delimited {
     pub delim: token::DelimToken,
@@ -25,14 +27,17 @@ pub struct Delimited {
 }
 
 impl Delimited {
+    /// Return the opening delimiter (possibly `NoDelim`).
     pub fn open_token(&self) -> token::Token {
         token::OpenDelim(self.delim)
     }
 
+    /// Return the closing delimiter (possibly `NoDelim`).
     pub fn close_token(&self) -> token::Token {
         token::CloseDelim(self.delim)
     }
 
+    /// Return a `self::TokenTree` with a `Span` corresponding to the opening delimiter.
     pub fn open_tt(&self, span: Span) -> TokenTree {
         let open_span = if span == DUMMY_SP {
             DUMMY_SP
@@ -42,6 +47,7 @@ pub fn open_tt(&self, span: Span) -> TokenTree {
         TokenTree::Token(open_span, self.open_token())
     }
 
+    /// Return a `self::TokenTree` with a `Span` corresponding to the closing delimiter.
     pub fn close_tt(&self, span: Span) -> TokenTree {
         let close_span = if span == DUMMY_SP {
             DUMMY_SP
@@ -68,12 +74,14 @@ pub struct SequenceRepetition {
 /// for token sequences.
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
 pub enum KleeneOp {
+    /// Kleene star (`*`) for zero or more repetitions
     ZeroOrMore,
+    /// Kleene plus (`+`) for one or more repetitions
     OneOrMore,
 }
 
 /// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)`
-/// are "first-class" token trees.
+/// are "first-class" token trees. Useful for parsing macros.
 #[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
 pub enum TokenTree {
     Token(Span, token::Token),
@@ -83,10 +91,15 @@ pub enum TokenTree {
     /// E.g. `$var`
     MetaVar(Span, ast::Ident),
     /// E.g. `$var:expr`. This is only used in the left hand side of MBE macros.
-    MetaVarDecl(Span, ast::Ident /* name to bind */, ast::Ident /* kind of nonterminal */),
+    MetaVarDecl(
+        Span,
+        ast::Ident, /* name to bind */
+        ast::Ident, /* kind of nonterminal */
+    ),
 }
 
 impl TokenTree {
+    /// Return the number of tokens in the tree.
     pub fn len(&self) -> usize {
         match *self {
             TokenTree::Delimited(_, ref delimed) => match delimed.delim {
@@ -98,6 +111,8 @@ pub fn len(&self) -> usize {
         }
     }
 
+    /// Returns true if the given token tree contains no other tokens. This is vacuously true for
+    /// single tokens or metavar/decls, but may be false for delimited trees or sequences.
     pub fn is_empty(&self) -> bool {
         match *self {
             TokenTree::Delimited(_, ref delimed) => match delimed.delim {
@@ -109,6 +124,7 @@ pub fn is_empty(&self) -> bool {
         }
     }
 
+    /// Get the `index`-th sub-token-tree. This only makes sense for delimited trees and sequences.
     pub fn get_tt(&self, index: usize) -> TokenTree {
         match (self, index) {
             (&TokenTree::Delimited(_, ref delimed), _) if delimed.delim == token::NoDelim => {
@@ -131,21 +147,48 @@ pub fn get_tt(&self, index: usize) -> TokenTree {
     /// Retrieve the `TokenTree`'s span.
     pub fn span(&self) -> Span {
         match *self {
-            TokenTree::Token(sp, _) |
-            TokenTree::MetaVar(sp, _) |
-            TokenTree::MetaVarDecl(sp, _, _) |
-            TokenTree::Delimited(sp, _) |
-            TokenTree::Sequence(sp, _) => sp,
+            TokenTree::Token(sp, _)
+            | TokenTree::MetaVar(sp, _)
+            | TokenTree::MetaVarDecl(sp, _, _)
+            | TokenTree::Delimited(sp, _)
+            TokenTree::Sequence(sp, _) => sp,
         }
     }
 }
 
-pub fn parse(input: tokenstream::TokenStream, expect_matchers: bool, sess: &ParseSess)
-             -> Vec<TokenTree> {
+/// Takes a `tokenstream::TokenStream` and returns a `Vec<self::TokenTree>`. Specifically, this
+/// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a
+/// collection of `TokenTree` for use in parsing a macro.
+///
+/// # Parameters
+///
+/// - `input`: a token stream to read from, the contents of which we are parsing.
+/// - `expect_matchers`: `parse` can be used to parse either the "patterns" or the "body" of a
+///   macro. Both take roughly the same form _except_ that in a pattern, metavars are declared with
+///   their "matcher" type. For example `$var:expr` or `$id:ident`. In this example, `expr` and
+///   `ident` are "matchers". They are not present in the body of a macro rule -- just in the
+///   pattern, so we pass a parameter to indicate whether to expect them or not.
+/// - `sess`: the parsing session. Any errors will be emitted to this session.
+///
+/// # Returns
+///
+/// A collection of `self::TokenTree`. There may also be some errors emitted to `sess`.
+pub fn parse(
+    input: tokenstream::TokenStream,
+    expect_matchers: bool,
+    sess: &ParseSess,
+) -> Vec<TokenTree> {
+    // Will contain the final collection of `self::TokenTree`
     let mut result = Vec::new();
+
+    // For each token tree in `input`, parse the token into a `self::TokenTree`, consuming
+    // additional trees if need be.
     let mut trees = input.trees();
     while let Some(tree) = trees.next() {
         let tree = parse_tree(tree, &mut trees, expect_matchers, sess);
+
+        // Given the parsed tree, if there is a metavar and we are expecting matchers, actually
+        // parse out the matcher (i.e. in `$id:ident` this would parse the `:` and `ident`).
         match tree {
             TokenTree::MetaVar(start_sp, ident) if expect_matchers => {
                 let span = match trees.next() {
@@ -154,78 +197,149 @@ pub fn parse(input: tokenstream::TokenStream, expect_matchers: bool, sess: &Pars
                             Some(kind) => {
                                 let span = end_sp.with_lo(start_sp.lo());
                                 result.push(TokenTree::MetaVarDecl(span, ident, kind));
-                                continue
+                                continue;
                             }
                             _ => end_sp,
                         },
-                        tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span),
+                        tree => tree.as_ref()
+                            .map(tokenstream::TokenTree::span)
+                            .unwrap_or(span),
                     },
-                    tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp),
+                    tree => tree.as_ref()
+                        .map(tokenstream::TokenTree::span)
+                        .unwrap_or(start_sp),
                 };
                 sess.missing_fragment_specifiers.borrow_mut().insert(span);
-                result.push(TokenTree::MetaVarDecl(span, ident, keywords::Invalid.ident()));
+                result.push(TokenTree::MetaVarDecl(
+                    span,
+                    ident,
+                    keywords::Invalid.ident(),
+                ));
             }
+
+            // Not a metavar or no matchers allowed, so just return the tree
             _ => result.push(tree),
         }
     }
     result
 }
 
-fn parse_tree<I>(tree: tokenstream::TokenTree,
-                 trees: &mut I,
-                 expect_matchers: bool,
-                 sess: &ParseSess)
-                 -> TokenTree
-    where I: Iterator<Item = tokenstream::TokenTree>,
+/// Takes a `tokenstream::TokenTree` and returns a `self::TokenTree`. Specifically, this takes a
+/// generic `TokenTree`, such as is used in the rest of the compiler, and returns a `TokenTree`
+/// for use in parsing a macro.
+///
+/// Converting the given tree may involve reading more tokens.
+///
+/// # Parameters
+///
+/// - `tree`: the tree we wish to convert.
+/// - `trees`: an iterator over trees. We may need to read more tokens from it in order to finish
+///   converting `tree`
+/// - `expect_matchers`: same as for `parse` (see above).
+/// - `sess`: the parsing session. Any errors will be emitted to this session.
+fn parse_tree<I>(
+    tree: tokenstream::TokenTree,
+    trees: &mut I,
+    expect_matchers: bool,
+    sess: &ParseSess,
+) -> TokenTree
+where
+    I: Iterator<Item = tokenstream::TokenTree>,
 {
+    // Depending on what `tree` is, we could be parsing different parts of a macro
     match tree {
+        // `tree` is a `$` token. Look at the next token in `trees`
         tokenstream::TokenTree::Token(span, token::Dollar) => match trees.next() {
+            // `tree` is followed by a delimited set of token trees. This indicates the beginning
+            // of a repetition sequence in the macro (e.g. `$(pat)*`).
             Some(tokenstream::TokenTree::Delimited(span, delimited)) => {
+                // Must have `(` not `{` or `[`
                 if delimited.delim != token::Paren {
                     let tok = pprust::token_to_string(&token::OpenDelim(delimited.delim));
                     let msg = format!("expected `(`, found `{}`", tok);
                     sess.span_diagnostic.span_err(span, &msg);
                 }
+                // Parse the contents of the sequence itself
                 let sequence = parse(delimited.tts.into(), expect_matchers, sess);
+                // Get the Kleene operator and optional separator
                 let (separator, op) = parse_sep_and_kleene_op(trees, span, sess);
+                // Count the number of captured "names" (i.e. named metavars)
                 let name_captures = macro_parser::count_names(&sequence);
-                TokenTree::Sequence(span, Rc::new(SequenceRepetition {
-                    tts: sequence,
-                    separator,
-                    op,
-                    num_captures: name_captures,
-                }))
+                TokenTree::Sequence(
+                    span,
+                    Rc::new(SequenceRepetition {
+                        tts: sequence,
+                        separator,
+                        op,
+                        num_captures: name_captures,
+                    }),
+                )
             }
+
+            // `tree` is followed by an `ident`. This could be `$meta_var` or the `$crate` special
+            // metavariable that names the crate of the invokation.
             Some(tokenstream::TokenTree::Token(ident_span, ref token)) if token.is_ident() => {
                 let ident = token.ident().unwrap();
                 let span = ident_span.with_lo(span.lo());
                 if ident.name == keywords::Crate.name() {
-                    let ident = ast::Ident { name: keywords::DollarCrate.name(), ..ident };
+                    let ident = ast::Ident {
+                        name: keywords::DollarCrate.name(),
+                        ..ident
+                    };
                     TokenTree::Token(span, token::Ident(ident))
                 } else {
                     TokenTree::MetaVar(span, ident)
                 }
             }
+
+            // `tree` is followed by a random token. This is an error.
             Some(tokenstream::TokenTree::Token(span, tok)) => {
-                let msg = format!("expected identifier, found `{}`", pprust::token_to_string(&tok));
+                let msg = format!(
+                    "expected identifier, found `{}`",
+                    pprust::token_to_string(&tok)
+                );
                 sess.span_diagnostic.span_err(span, &msg);
                 TokenTree::MetaVar(span, keywords::Invalid.ident())
             }
+
+            // There are no more tokens. Just return the `$` we already have.
             None => TokenTree::Token(span, token::Dollar),
         },
+
+        // `tree` is an arbitrary token. Keep it.
         tokenstream::TokenTree::Token(span, tok) => TokenTree::Token(span, tok),
-        tokenstream::TokenTree::Delimited(span, delimited) => {
-            TokenTree::Delimited(span, Rc::new(Delimited {
+
+        // `tree` is the beginning of a delimited set of tokens (e.g. `(` or `{`). We need to
+        // descend into the delimited set and further parse it.
+        tokenstream::TokenTree::Delimited(span, delimited) => TokenTree::Delimited(
+            span,
+            Rc::new(Delimited {
                 delim: delimited.delim,
                 tts: parse(delimited.tts.into(), expect_matchers, sess),
-            }))
-        }
+            }),
+        ),
     }
 }
 
-fn parse_sep_and_kleene_op<I>(input: &mut I, span: Span, sess: &ParseSess)
-                              -> (Option<token::Token>, KleeneOp)
-    where I: Iterator<Item = tokenstream::TokenTree>,
+/// Attempt to parse a single Kleene star, possibly with a separator.
+///
+/// For example, in a pattern such as `$(a),*`, `a` is the pattern to be repeated, `,` is the
+/// separator, and `*` is the Kleene operator. This function is specifically concerned with parsing
+/// the last two tokens of such a pattern: namely, the optional separator and the Kleene operator
+/// itself. Note that here we are parsing the _macro_ itself, rather than trying to match some
+/// stream of tokens in an invocation of a macro.
+///
+/// This function will take some input iterator `input` corresponding to `span` and a parsing
+/// session `sess`. If the next one (or possibly two) tokens in `input` correspond to a Kleene
+/// operator and separator, then a tuple with `(separator, KleeneOp)` is returned. Otherwise, an
+/// error with the appropriate span is emitted to `sess` and a dummy value is returned.
+fn parse_sep_and_kleene_op<I>(
+    input: &mut I,
+    span: Span,
+    sess: &ParseSess,
+) -> (Option<token::Token>, KleeneOp)
+where
+    I: Iterator<Item = tokenstream::TokenTree>,
 {
     fn kleene_op(token: &token::Token) -> Option<KleeneOp> {
         match *token {
@@ -235,20 +349,40 @@ fn kleene_op(token: &token::Token) -> Option<KleeneOp> {
         }
     }
 
+    // We attempt to look at the next two token trees in `input`. I will call the first #1 and the
+    // second #2. If #1 and #2 don't match a valid KleeneOp with/without separator, that is an
+    // error, and we should emit an error on the most specific span possible.
     let span = match input.next() {
+        // #1 is a token
         Some(tokenstream::TokenTree::Token(span, tok)) => match kleene_op(&tok) {
+            // #1 is a KleeneOp with no separator
             Some(op) => return (None, op),
+
+            // #1 is not a KleeneOp, but may be a separator... need to look at #2
             None => match input.next() {
+                // #2 is a token
                 Some(tokenstream::TokenTree::Token(span, tok2)) => match kleene_op(&tok2) {
+                    // #2 is a KleeneOp, so #1 must be a separator
                     Some(op) => return (Some(tok), op),
+
+                    // #2 is not a KleeneOp... error
                     None => span,
                 },
-                tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span),
-            }
+
+                // #2 is not a token at all... error
+                tree => tree.as_ref()
+                    .map(tokenstream::TokenTree::span)
+                    .unwrap_or(span),
+            },
         },
-        tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span),
+
+        // #1 is not a token at all... error
+        tree => tree.as_ref()
+            .map(tokenstream::TokenTree::span)
+            .unwrap_or(span),
     };
 
+    // Error...
     sess.span_diagnostic.span_err(span, "expected `*` or `+`");
     (None, KleeneOp::ZeroOrMore)
 }
index 8512e215ca7655cad4d5bf4cac965867b1e908a9..3e523fca92a037a969a38270e74caaa20da2a7c7 100644 (file)
@@ -694,9 +694,7 @@ pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
     ("thread_local", Whitelisted, Gated(Stability::Unstable,
                                         "thread_local",
                                         "`#[thread_local]` is an experimental feature, and does \
-                                         not currently handle destructors. There is no \
-                                         corresponding `#[task_local]` mapping to the task \
-                                         model",
+                                         not currently handle destructors.",
                                         cfg_fn!(thread_local))),
 
     ("rustc_on_unimplemented", Normal, Gated(Stability::Unstable,
@@ -790,6 +788,11 @@ pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
                                                        is just used for rustc unit tests \
                                                        and will never be stable",
                                                       cfg_fn!(rustc_attrs))),
+    ("rustc_serialize_exclude_null", Normal, Gated(Stability::Unstable,
+                                             "rustc_attrs",
+                                             "the `#[rustc_serialize_exclude_null]` attribute \
+                                              is an internal-only feature",
+                                             cfg_fn!(rustc_attrs))),
     ("rustc_synthetic", Whitelisted, Gated(Stability::Unstable,
                                                       "rustc_attrs",
                                                       "this attribute \
index 54c726d84621fe36f1bd28adf5cc338b2c8325e8..98d5fa8f797fa7e105838655419bfd607feb29b7 100644 (file)
@@ -38,34 +38,41 @@ pub struct JsonEmitter {
     registry: Option<Registry>,
     cm: Rc<CodeMapper + 'static>,
     pretty: bool,
+    /// Whether "approximate suggestions" are enabled in the config
+    approximate_suggestions: bool,
 }
 
 impl JsonEmitter {
     pub fn stderr(registry: Option<Registry>,
                   code_map: Rc<CodeMap>,
-                  pretty: bool) -> JsonEmitter {
+                  pretty: bool,
+                  approximate_suggestions: bool) -> JsonEmitter {
         JsonEmitter {
             dst: Box::new(io::stderr()),
             registry,
             cm: code_map,
             pretty,
+            approximate_suggestions,
         }
     }
 
     pub fn basic(pretty: bool) -> JsonEmitter {
         let file_path_mapping = FilePathMapping::empty();
-        JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)), pretty)
+        JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)),
+                            pretty, false)
     }
 
     pub fn new(dst: Box<Write + Send>,
                registry: Option<Registry>,
                code_map: Rc<CodeMap>,
-               pretty: bool) -> JsonEmitter {
+               pretty: bool,
+               approximate_suggestions: bool) -> JsonEmitter {
         JsonEmitter {
             dst,
             registry,
             cm: code_map,
             pretty,
+            approximate_suggestions,
         }
     }
 }
@@ -101,6 +108,7 @@ struct Diagnostic {
 }
 
 #[derive(RustcEncodable)]
+#[allow(unused_attributes)]
 struct DiagnosticSpan {
     file_name: String,
     byte_start: u32,
@@ -121,6 +129,9 @@ struct DiagnosticSpan {
     /// If we are suggesting a replacement, this will contain text
     /// that should be sliced in atop this span.
     suggested_replacement: Option<String>,
+    /// If the suggestion is approximate
+    #[rustc_serialize_exclude_null]
+    suggestion_approximate: Option<bool>,
     /// Macro invocations that created the code at this span, if any.
     expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
 }
@@ -188,7 +199,7 @@ fn flush(&mut self) -> io::Result<()> {
         }
         let buf = BufWriter::default();
         let output = buf.clone();
-        EmitterWriter::new(Box::new(buf), Some(je.cm.clone()), false).emit(db);
+        EmitterWriter::new(Box::new(buf), Some(je.cm.clone()), false, false).emit(db);
         let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap();
         let output = String::from_utf8(output).unwrap();
 
@@ -220,7 +231,7 @@ fn from_sub_diagnostic(db: &SubDiagnostic, je: &JsonEmitter) -> Diagnostic {
 
 impl DiagnosticSpan {
     fn from_span_label(span: SpanLabel,
-                       suggestion: Option<&String>,
+                       suggestion: Option<(&String, bool)>,
                        je: &JsonEmitter)
                        -> DiagnosticSpan {
         Self::from_span_etc(span.span,
@@ -233,7 +244,7 @@ fn from_span_label(span: SpanLabel,
     fn from_span_etc(span: Span,
                      is_primary: bool,
                      label: Option<String>,
-                     suggestion: Option<&String>,
+                     suggestion: Option<(&String, bool)>,
                      je: &JsonEmitter)
                      -> DiagnosticSpan {
         // obtain the full backtrace from the `macro_backtrace`
@@ -253,7 +264,7 @@ fn from_span_etc(span: Span,
     fn from_span_full(span: Span,
                       is_primary: bool,
                       label: Option<String>,
-                      suggestion: Option<&String>,
+                      suggestion: Option<(&String, bool)>,
                       mut backtrace: vec::IntoIter<MacroBacktrace>,
                       je: &JsonEmitter)
                       -> DiagnosticSpan {
@@ -281,6 +292,13 @@ fn from_span_full(span: Span,
                 def_site_span,
             })
         });
+
+        let suggestion_approximate = if je.approximate_suggestions {
+             suggestion.map(|x| x.1)
+        } else {
+            None
+        };
+
         DiagnosticSpan {
             file_name: start.file.name.to_string(),
             byte_start: span.lo().0 - start.file.start_pos.0,
@@ -291,7 +309,8 @@ fn from_span_full(span: Span,
             column_end: end.col.0 + 1,
             is_primary,
             text: DiagnosticSpanLine::from_span(span, je),
-            suggested_replacement: suggestion.cloned(),
+            suggested_replacement: suggestion.map(|x| x.0.clone()),
+            suggestion_approximate,
             expansion: backtrace_step,
             label,
         }
@@ -309,14 +328,15 @@ fn from_suggestion(suggestion: &CodeSuggestion, je: &JsonEmitter)
         suggestion.substitutions
                       .iter()
                       .flat_map(|substitution| {
-                          substitution.parts.iter().map(move |suggestion| {
+                          substitution.parts.iter().map(move |suggestion_inner| {
                               let span_label = SpanLabel {
-                                  span: suggestion.span,
+                                  span: suggestion_inner.span,
                                   is_primary: true,
                                   label: None,
                               };
                               DiagnosticSpan::from_span_label(span_label,
-                                                              Some(&suggestion.snippet),
+                                                              Some((&suggestion_inner.snippet,
+                                                                   suggestion.approximate)),
                                                               je)
                           })
                       })
index 3b4c5da10f20b35b5f0014a956419e00b4125d11..9181cca215c848602d3f8bbe1a93a3ac45561588 100644 (file)
@@ -25,6 +25,7 @@
 #![feature(match_default_bindings)]
 #![feature(i128_type)]
 #![feature(const_atomic_usize_new)]
+#![feature(rustc_attrs)]
 
 // See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
 #[allow(unused_extern_crates)]
index b95c91548d00b99954ed70701f9e1cc87eed12ed..0fd069b76aadc6db18963786525c78f71ab94f06 100644 (file)
@@ -1745,6 +1745,7 @@ mod tests {
     fn mk_sess(cm: Rc<CodeMap>) -> ParseSess {
         let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()),
                                                           Some(cm.clone()),
+                                                          false,
                                                           false);
         ParseSess {
             span_diagnostic: errors::Handler::with_emitter(true, false, Box::new(emitter)),
index d393cab471850a5af744a53f39f23ccee8a83bbb..b3c485a85c0632ecce7ba883acc2a6fc2ced86a7 100644 (file)
@@ -704,13 +704,15 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
                     expect.clone()
                 };
                 (format!("expected one of {}, found `{}`", expect, actual),
-                 (self.prev_span.next_point(), format!("expected one of {} here", short_expect)))
+                 (self.sess.codemap().next_point(self.prev_span),
+                  format!("expected one of {} here", short_expect)))
             } else if expected.is_empty() {
                 (format!("unexpected token: `{}`", actual),
                  (self.prev_span, "unexpected token after this".to_string()))
             } else {
                 (format!("expected {}, found `{}`", expect, actual),
-                 (self.prev_span.next_point(), format!("expected {} here", expect)))
+                 (self.sess.codemap().next_point(self.prev_span),
+                  format!("expected {} here", expect)))
             };
             let mut err = self.fatal(&msg_exp);
             let sp = if self.token == token::Token::Eof {
@@ -1362,7 +1364,7 @@ pub fn parse_ty_bare_fn(&mut self, generic_params: Vec<GenericParam>)
 
         self.expect_keyword(keywords::Fn)?;
         let (inputs, variadic) = self.parse_fn_args(false, true)?;
-        let ret_ty = self.parse_ret_ty()?;
+        let ret_ty = self.parse_ret_ty(false)?;
         let decl = P(FnDecl {
             inputs,
             output: ret_ty,
@@ -1501,9 +1503,9 @@ fn parse_trait_item_(&mut self,
     }
 
     /// Parse optional return type [ -> TY ] in function decl
-    pub fn parse_ret_ty(&mut self) -> PResult<'a, FunctionRetTy> {
+    fn parse_ret_ty(&mut self, allow_plus: bool) -> PResult<'a, FunctionRetTy> {
         if self.eat(&token::RArrow) {
-            Ok(FunctionRetTy::Ty(self.parse_ty_no_plus()?))
+            Ok(FunctionRetTy::Ty(self.parse_ty_common(allow_plus, true)?))
         } else {
             Ok(FunctionRetTy::Default(self.span.with_hi(self.span.lo())))
         }
@@ -1528,6 +1530,7 @@ fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool)
         maybe_whole!(self, NtTy, |x| x);
 
         let lo = self.span;
+        let mut impl_dyn_multi = false;
         let node = if self.eat(&token::OpenDelim(token::Paren)) {
             // `(TYPE)` is a parenthesized type.
             // `(TYPE,)` is a tuple with a single field of type TYPE.
@@ -1614,13 +1617,17 @@ fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool)
                 self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)?
             }
         } else if self.eat_keyword(keywords::Impl) {
-            // FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511).
-            TyKind::ImplTrait(self.parse_ty_param_bounds()?)
+            // Always parse bounds greedily for better error recovery.
+            let bounds = self.parse_ty_param_bounds()?;
+            impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
+            TyKind::ImplTrait(bounds)
         } else if self.check_keyword(keywords::Dyn) &&
                   self.look_ahead(1, |t| t.can_begin_bound() && !can_continue_type_after_ident(t)) {
-            // FIXME: figure out priority of `+` in `dyn Trait1 + Trait2` (#34511).
             self.bump(); // `dyn`
-            TyKind::TraitObject(self.parse_ty_param_bounds()?, TraitObjectSyntax::Dyn)
+            // Always parse bounds greedily for better error recovery.
+            let bounds = self.parse_ty_param_bounds()?;
+            impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
+            TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)
         } else if self.check(&token::Question) ||
                   self.check_lifetime() && self.look_ahead(1, |t| t == &token::BinOp(token::Plus)) {
             // Bound list (trait object type)
@@ -1656,6 +1663,7 @@ fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool)
         let ty = Ty { node, span, id: ast::DUMMY_NODE_ID };
 
         // Try to recover from use of `+` with incorrect priority.
+        self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty);
         self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?;
         let ty = self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)?;
 
@@ -1673,6 +1681,15 @@ fn parse_remaining_bounds(&mut self, generic_params: Vec<GenericParam>, path: as
         Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
     }
 
+    fn maybe_report_ambiguous_plus(&mut self, allow_plus: bool, impl_dyn_multi: bool, ty: &Ty) {
+        if !allow_plus && impl_dyn_multi {
+            let sum_with_parens = format!("({})", pprust::ty_to_string(&ty));
+            self.struct_span_err(ty.span, "ambiguous `+` in a type")
+                .span_suggestion(ty.span, "use parentheses to disambiguate", sum_with_parens)
+                .emit();
+        }
+    }
+
     fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> {
         // Do not add `+` to expected tokens.
         if !allow_plus || self.token != token::BinOp(token::Plus) {
@@ -3190,7 +3207,7 @@ pub fn parse_if_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr
         // return. This won't catch blocks with an explicit `return`, but that would be caught by
         // the dead code lint.
         if self.eat_keyword(keywords::Else) || !cond.returns() {
-            let sp = lo.next_point();
+            let sp = self.sess.codemap().next_point(lo);
             let mut err = self.diagnostic()
                 .struct_span_err(sp, "missing condition for `if` statemement");
             err.span_label(sp, "expected if condition here");
@@ -4894,7 +4911,7 @@ fn parse_fn_args(&mut self, named_args: bool, allow_variadic: bool)
     pub fn parse_fn_decl(&mut self, allow_variadic: bool) -> PResult<'a, P<FnDecl>> {
 
         let (args, variadic) = self.parse_fn_args(true, allow_variadic)?;
-        let ret_ty = self.parse_ret_ty()?;
+        let ret_ty = self.parse_ret_ty(true)?;
 
         Ok(P(FnDecl {
             inputs: args,
@@ -5035,7 +5052,7 @@ fn parse_fn_decl_with_self<F>(&mut self, parse_arg_fn: F) -> PResult<'a, P<FnDec
         self.expect(&token::CloseDelim(token::Paren))?;
         Ok(P(FnDecl {
             inputs: fn_inputs,
-            output: self.parse_ret_ty()?,
+            output: self.parse_ret_ty(true)?,
             variadic: false
         }))
     }
@@ -5057,7 +5074,7 @@ fn parse_fn_block_decl(&mut self) -> PResult<'a, P<FnDecl>> {
                 args
             }
         };
-        let output = self.parse_ret_ty()?;
+        let output = self.parse_ret_ty(true)?;
 
         Ok(P(FnDecl {
             inputs: inputs_captures,
@@ -6113,6 +6130,7 @@ fn parse_item_extern_crate(&mut self,
         self.expect(&token::Semi)?;
 
         let prev_span = self.prev_span;
+
         Ok(self.mk_item(lo.to(prev_span),
                         ident,
                         ItemKind::ExternCrate(maybe_path),
index 5072f2e2793f1bea2f5d9033aa3988cea9636579..3b4bba24d779b6d0176fdc8c3e8f5b9461e83aa8 100644 (file)
@@ -62,6 +62,7 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
 
     let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }),
                                      Some(code_map.clone()),
+                                     false,
                                      false);
     let handler = Handler::with_emitter(true, false, Box::new(emitter));
     handler.span_err(msp, "foo");
index 0e6e96438d8176ffc16065ee9fc21d3d5c41ae1c..743f22b6b314075a34d3a76c9cc44de77fb6abab 100644 (file)
@@ -190,7 +190,7 @@ fn encodable_substructure(cx: &mut ExtCtxt,
         Struct(_, ref fields) => {
             let emit_struct_field = cx.ident_of("emit_struct_field");
             let mut stmts = Vec::new();
-            for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() {
+            for (i, &FieldInfo { name, ref self_, span, attrs, .. }) in fields.iter().enumerate() {
                 let name = match name {
                     Some(id) => id.name,
                     None => Symbol::intern(&format!("_field{}", i)),
@@ -212,7 +212,19 @@ fn encodable_substructure(cx: &mut ExtCtxt,
                 } else {
                     cx.expr(span, ExprKind::Ret(Some(call)))
                 };
-                stmts.push(cx.stmt_expr(call));
+
+                // This exists for https://github.com/rust-lang/rust/pull/47540
+                //
+                // If we decide to stabilize that flag this can be removed
+                let expr = if attrs.iter().any(|a| a.check_name("rustc_serialize_exclude_null")) {
+                    let is_some = cx.ident_of("is_some");
+                    let condition = cx.expr_method_call(span, self_.clone(), is_some, vec![]);
+                    cx.expr_if(span, condition, call, None)
+                } else {
+                    call
+                };
+                let stmt = cx.stmt_expr(expr);
+                stmts.push(stmt);
             }
 
             // unit structs have no fields and need to return Ok()
index 3660d2fe46a92b0ff86c22a91627a484495fd6fa..0dfe9cb970efbd8d7e0024059f3e9b871d03cf84 100644 (file)
@@ -1439,7 +1439,7 @@ fn build_enum_match_tuple<'b>(&self,
                                                          &catch_all_substructure);
 
             // Final wrinkle: the self_args are expressions that deref
-            // down to desired l-values, but we cannot actually deref
+            // down to desired places, but we cannot actually deref
             // them when they are fed as r-values into a tuple
             // expression; here add a layer of borrowing, turning
             // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
@@ -1516,7 +1516,7 @@ fn build_enum_match_tuple<'b>(&self,
         } else {
 
             // Final wrinkle: the self_args are expressions that deref
-            // down to desired l-values, but we cannot actually deref
+            // down to desired places, but we cannot actually deref
             // them when they are fed as r-values into a tuple
             // expression; here add a layer of borrowing, turning
             // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
index 85f0925b98210383459cc783e35cc131af6165aa..dd1ec7284f6901320987f68a3bd325bf2ad5201f 100644 (file)
@@ -216,20 +216,6 @@ pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
         self.data().with_ctxt(ctxt)
     }
 
-    /// Returns a new span representing just the end-point of this span
-    pub fn end_point(self) -> Span {
-        let span = self.data();
-        let lo = cmp::max(span.hi.0 - 1, span.lo.0);
-        span.with_lo(BytePos(lo))
-    }
-
-    /// Returns a new span representing the next character after the end-point of this span
-    pub fn next_point(self) -> Span {
-        let span = self.data();
-        let lo = cmp::max(span.hi.0, span.lo.0 + 1);
-        Span::new(BytePos(lo), BytePos(lo), span.ctxt)
-    }
-
     /// Returns `self` if `self` is not the dummy span, and `other` otherwise.
     pub fn substitute_dummy(self, other: Span) -> Span {
         if self.source_equal(&DUMMY_SP) { other } else { self }
diff --git a/src/libtest/formatters/json.rs b/src/libtest/formatters/json.rs
new file mode 100644 (file)
index 0000000..d323d50
--- /dev/null
@@ -0,0 +1,229 @@
+// Copyright 2012-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 super::*;
+
+pub(crate) struct JsonFormatter<T> {
+    out: OutputLocation<T>,
+}
+
+impl<T: Write> JsonFormatter<T> {
+    pub fn new(out: OutputLocation<T>) -> Self {
+        Self { out }
+    }
+
+    fn write_message(&mut self, s: &str) -> io::Result<()> {
+        assert!(!s.contains('\n'));
+
+        self.out.write_all(s.as_ref())?;
+        self.out.write_all(b"\n")
+    }
+
+    fn write_event(
+        &mut self,
+        ty: &str,
+        name: &str,
+        evt: &str,
+        extra: Option<String>,
+    ) -> io::Result<()> {
+        if let Some(extras) = extra {
+            self.write_message(&*format!(
+                r#"{{ "type": "{}", "name": "{}", "event": "{}", {} }}"#,
+                ty,
+                name,
+                evt,
+                extras
+            ))
+        } else {
+            self.write_message(&*format!(
+                r#"{{ "type": "{}", "name": "{}", "event": "{}" }}"#,
+                ty,
+                name,
+                evt
+            ))
+        }
+    }
+}
+
+impl<T: Write> OutputFormatter for JsonFormatter<T> {
+    fn write_run_start(&mut self, test_count: usize) -> io::Result<()> {
+        self.write_message(&*format!(
+            r#"{{ "type": "suite", "event": "started", "test_count": "{}" }}"#,
+            test_count
+        ))
+    }
+
+    fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
+        self.write_message(&*format!(
+            r#"{{ "type": "test", "event": "started", "name": "{}" }}"#,
+            desc.name
+        ))
+    }
+
+    fn write_result(
+        &mut self,
+        desc: &TestDesc,
+        result: &TestResult,
+        stdout: &[u8],
+    ) -> io::Result<()> {
+        match *result {
+            TrOk => self.write_event("test", desc.name.as_slice(), "ok", None),
+
+            TrFailed => {
+                let extra_data = if stdout.len() > 0 {
+                    Some(format!(
+                        r#""stdout": "{}""#,
+                        EscapedString(String::from_utf8_lossy(stdout))
+                    ))
+                } else {
+                    None
+                };
+
+                self.write_event("test", desc.name.as_slice(), "failed", extra_data)
+            }
+
+            TrFailedMsg(ref m) => {
+                self.write_event(
+                    "test",
+                    desc.name.as_slice(),
+                    "failed",
+                    Some(format!(r#""message": "{}""#, EscapedString(m))),
+                )
+            }
+
+            TrIgnored => self.write_event("test", desc.name.as_slice(), "ignored", None),
+
+            TrAllowedFail => {
+                self.write_event("test", desc.name.as_slice(), "allowed_failure", None)
+            }
+
+            TrBench(ref bs) => {
+                let median = bs.ns_iter_summ.median as usize;
+                let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
+
+                let mbps = if bs.mb_s == 0 {
+                    "".into()
+                } else {
+                    format!(r#", "mib_per_second": {}"#, bs.mb_s)
+                };
+
+                let line = format!(
+                    "{{ \"type\": \"bench\", \
+                                \"name\": \"{}\", \
+                                \"median\": {}, \
+                                \"deviation\": {}{} }}",
+                    desc.name,
+                    median,
+                    deviation,
+                    mbps
+                );
+
+                self.write_message(&*line)
+            }
+        }
+    }
+
+    fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
+        self.write_message(&*format!(
+            r#"{{ "type": "test", "event": "timeout", "name": "{}" }}"#,
+            desc.name
+        ))
+    }
+
+    fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
+
+        self.write_message(&*format!(
+            "{{ \"type\": \"suite\", \
+            \"event\": \"{}\", \
+            \"passed\": {}, \
+            \"failed\": {}, \
+            \"allowed_fail\": {}, \
+            \"ignored\": {}, \
+            \"measured\": {}, \
+            \"filtered_out\": \"{}\" }}",
+            if state.failed == 0 { "ok" } else { "failed" },
+            state.passed,
+            state.failed + state.allowed_fail,
+            state.allowed_fail,
+            state.ignored,
+            state.measured,
+            state.filtered_out
+        ))?;
+
+        Ok(state.failed == 0)
+    }
+}
+
+/// A formatting utility used to print strings with characters in need of escaping.
+/// Base code taken form `libserialize::json::escape_str`
+struct EscapedString<S: AsRef<str>>(S);
+
+impl<S: AsRef<str>> ::std::fmt::Display for EscapedString<S> {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        let mut start = 0;
+
+        for (i, byte) in self.0.as_ref().bytes().enumerate() {
+            let escaped = match byte {
+                b'"' => "\\\"",
+                b'\\' => "\\\\",
+                b'\x00' => "\\u0000",
+                b'\x01' => "\\u0001",
+                b'\x02' => "\\u0002",
+                b'\x03' => "\\u0003",
+                b'\x04' => "\\u0004",
+                b'\x05' => "\\u0005",
+                b'\x06' => "\\u0006",
+                b'\x07' => "\\u0007",
+                b'\x08' => "\\b",
+                b'\t' => "\\t",
+                b'\n' => "\\n",
+                b'\x0b' => "\\u000b",
+                b'\x0c' => "\\f",
+                b'\r' => "\\r",
+                b'\x0e' => "\\u000e",
+                b'\x0f' => "\\u000f",
+                b'\x10' => "\\u0010",
+                b'\x11' => "\\u0011",
+                b'\x12' => "\\u0012",
+                b'\x13' => "\\u0013",
+                b'\x14' => "\\u0014",
+                b'\x15' => "\\u0015",
+                b'\x16' => "\\u0016",
+                b'\x17' => "\\u0017",
+                b'\x18' => "\\u0018",
+                b'\x19' => "\\u0019",
+                b'\x1a' => "\\u001a",
+                b'\x1b' => "\\u001b",
+                b'\x1c' => "\\u001c",
+                b'\x1d' => "\\u001d",
+                b'\x1e' => "\\u001e",
+                b'\x1f' => "\\u001f",
+                b'\x7f' => "\\u007f",
+                _ => {
+                    continue;
+                }
+            };
+
+            if start < i {
+                f.write_str(&self.0.as_ref()[start..i])?;
+            }
+
+            f.write_str(escaped)?;
+
+            start = i + 1;
+        }
+
+        if start != self.0.as_ref().len() {
+            f.write_str(&self.0.as_ref()[start..])?;
+        }
+
+        Ok(())
+    }
+}
diff --git a/src/libtest/formatters/mod.rs b/src/libtest/formatters/mod.rs
new file mode 100644 (file)
index 0000000..24c7929
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2012-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 super::*;
+
+mod pretty;
+mod json;
+mod terse;
+
+pub(crate) use self::pretty::PrettyFormatter;
+pub(crate) use self::json::JsonFormatter;
+pub(crate) use self::terse::TerseFormatter;
+
+pub(crate) trait OutputFormatter {
+    fn write_run_start(&mut self, test_count: usize) -> io::Result<()>;
+    fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()>;
+    fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()>;
+    fn write_result(
+        &mut self,
+        desc: &TestDesc,
+        result: &TestResult,
+        stdout: &[u8],
+    ) -> io::Result<()>;
+    fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool>;
+}
diff --git a/src/libtest/formatters/pretty.rs b/src/libtest/formatters/pretty.rs
new file mode 100644 (file)
index 0000000..f2064de
--- /dev/null
@@ -0,0 +1,247 @@
+// Copyright 2012-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 super::*;
+
+pub(crate) struct PrettyFormatter<T> {
+    out: OutputLocation<T>,
+    use_color: bool,
+
+    /// Number of columns to fill when aligning names
+    max_name_len: usize,
+
+    is_multithreaded: bool,
+}
+
+impl<T: Write> PrettyFormatter<T> {
+    pub fn new(
+        out: OutputLocation<T>,
+        use_color: bool,
+        max_name_len: usize,
+        is_multithreaded: bool,
+    ) -> Self {
+        PrettyFormatter {
+            out,
+            use_color,
+            max_name_len,
+            is_multithreaded,
+        }
+    }
+
+    #[cfg(test)]
+    pub fn output_location(&self) -> &OutputLocation<T> {
+        &self.out
+    }
+
+    pub fn write_ok(&mut self) -> io::Result<()> {
+        self.write_short_result("ok", term::color::GREEN)
+    }
+
+    pub fn write_failed(&mut self) -> io::Result<()> {
+        self.write_short_result("FAILED", term::color::RED)
+    }
+
+    pub fn write_ignored(&mut self) -> io::Result<()> {
+        self.write_short_result("ignored", term::color::YELLOW)
+    }
+
+    pub fn write_allowed_fail(&mut self) -> io::Result<()> {
+        self.write_short_result("FAILED (allowed)", term::color::YELLOW)
+    }
+
+    pub fn write_bench(&mut self) -> io::Result<()> {
+        self.write_pretty("bench", term::color::CYAN)
+    }
+
+    pub fn write_short_result(
+        &mut self,
+        result: &str,
+        color: term::color::Color,
+    ) -> io::Result<()> {
+        self.write_pretty(result, color)?;
+        self.write_plain("\n")
+    }
+
+    pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
+        match self.out {
+            Pretty(ref mut term) => {
+                if self.use_color {
+                    term.fg(color)?;
+                }
+                term.write_all(word.as_bytes())?;
+                if self.use_color {
+                    term.reset()?;
+                }
+                term.flush()
+            }
+            Raw(ref mut stdout) => {
+                stdout.write_all(word.as_bytes())?;
+                stdout.flush()
+            }
+        }
+    }
+
+    pub fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
+        let s = s.as_ref();
+        self.out.write_all(s.as_bytes())?;
+        self.out.flush()
+    }
+
+    pub fn write_successes(&mut self, state: &ConsoleTestState) -> io::Result<()> {
+        self.write_plain("\nsuccesses:\n")?;
+        let mut successes = Vec::new();
+        let mut stdouts = String::new();
+        for &(ref f, ref stdout) in &state.not_failures {
+            successes.push(f.name.to_string());
+            if !stdout.is_empty() {
+                stdouts.push_str(&format!("---- {} stdout ----\n\t", f.name));
+                let output = String::from_utf8_lossy(stdout);
+                stdouts.push_str(&output);
+                stdouts.push_str("\n");
+            }
+        }
+        if !stdouts.is_empty() {
+            self.write_plain("\n")?;
+            self.write_plain(&stdouts)?;
+        }
+
+        self.write_plain("\nsuccesses:\n")?;
+        successes.sort();
+        for name in &successes {
+            self.write_plain(&format!("    {}\n", name))?;
+        }
+        Ok(())
+    }
+
+    pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
+        self.write_plain("\nfailures:\n")?;
+        let mut failures = Vec::new();
+        let mut fail_out = String::new();
+        for &(ref f, ref stdout) in &state.failures {
+            failures.push(f.name.to_string());
+            if !stdout.is_empty() {
+                fail_out.push_str(&format!("---- {} stdout ----\n\t", f.name));
+                let output = String::from_utf8_lossy(stdout);
+                fail_out.push_str(&output);
+                fail_out.push_str("\n");
+            }
+        }
+        if !fail_out.is_empty() {
+            self.write_plain("\n")?;
+            self.write_plain(&fail_out)?;
+        }
+
+        self.write_plain("\nfailures:\n")?;
+        failures.sort();
+        for name in &failures {
+            self.write_plain(&format!("    {}\n", name))?;
+        }
+        Ok(())
+    }
+
+    fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
+        let name = desc.padded_name(self.max_name_len, desc.name.padding());
+        self.write_plain(&format!("test {} ... ", name))?;
+
+        Ok(())
+    }
+}
+
+impl<T: Write> OutputFormatter for PrettyFormatter<T> {
+    fn write_run_start(&mut self, test_count: usize) -> io::Result<()> {
+        let noun = if test_count != 1 { "tests" } else { "test" };
+        self.write_plain(&format!("\nrunning {} {}\n", test_count, noun))
+    }
+
+    fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
+        // When running tests concurrently, we should not print
+        // the test's name as the result will be mis-aligned.
+        // When running the tests serially, we print the name here so
+        // that the user can see which test hangs.
+        if !self.is_multithreaded {
+            self.write_test_name(desc)?;
+        }
+
+        Ok(())
+    }
+
+    fn write_result(&mut self, desc: &TestDesc, result: &TestResult, _: &[u8]) -> io::Result<()> {
+        if self.is_multithreaded {
+            self.write_test_name(desc)?;
+        }
+
+        match *result {
+            TrOk => self.write_ok(),
+            TrFailed | TrFailedMsg(_) => self.write_failed(),
+            TrIgnored => self.write_ignored(),
+            TrAllowedFail => self.write_allowed_fail(),
+            TrBench(ref bs) => {
+                self.write_bench()?;
+                self.write_plain(&format!(": {}\n", fmt_bench_samples(bs)))
+            }
+        }
+    }
+
+    fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
+        if self.is_multithreaded {
+            self.write_test_name(desc)?;
+        }
+
+        self.write_plain(&format!(
+            "test {} has been running for over {} seconds\n",
+            desc.name,
+            TEST_WARN_TIMEOUT_S
+        ))
+    }
+
+    fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
+        if state.options.display_output {
+            self.write_successes(state)?;
+        }
+        let success = state.failed == 0;
+        if !success {
+            self.write_failures(state)?;
+        }
+
+        self.write_plain("\ntest result: ")?;
+
+        if success {
+            // There's no parallelism at this point so it's safe to use color
+            self.write_pretty("ok", term::color::GREEN)?;
+        } else {
+            self.write_pretty("FAILED", term::color::RED)?;
+        }
+
+        let s = if state.allowed_fail > 0 {
+            format!(
+                ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out\n\n",
+                state.passed,
+                state.failed + state.allowed_fail,
+                state.allowed_fail,
+                state.ignored,
+                state.measured,
+                state.filtered_out
+            )
+        } else {
+            format!(
+                ". {} passed; {} failed; {} ignored; {} measured; {} filtered out\n\n",
+                state.passed,
+                state.failed,
+                state.ignored,
+                state.measured,
+                state.filtered_out
+            )
+        };
+
+        self.write_plain(&s)?;
+
+        Ok(success)
+    }
+}
diff --git a/src/libtest/formatters/terse.rs b/src/libtest/formatters/terse.rs
new file mode 100644 (file)
index 0000000..8868948
--- /dev/null
@@ -0,0 +1,246 @@
+// Copyright 2012-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 super::*;
+
+pub(crate) struct TerseFormatter<T> {
+    out: OutputLocation<T>,
+    use_color: bool,
+    is_multithreaded: bool,
+    /// Number of columns to fill when aligning names
+    max_name_len: usize,
+
+    test_count: usize,
+}
+
+impl<T: Write> TerseFormatter<T> {
+    pub fn new(
+        out: OutputLocation<T>,
+        use_color: bool,
+        max_name_len: usize,
+        is_multithreaded: bool,
+    ) -> Self {
+        TerseFormatter {
+            out,
+            use_color,
+            max_name_len,
+            is_multithreaded,
+            test_count: 0,
+        }
+    }
+
+    pub fn write_ok(&mut self) -> io::Result<()> {
+        self.write_short_result(".", term::color::GREEN)
+    }
+
+    pub fn write_failed(&mut self) -> io::Result<()> {
+        self.write_short_result("F", term::color::RED)
+    }
+
+    pub fn write_ignored(&mut self) -> io::Result<()> {
+        self.write_short_result("i", term::color::YELLOW)
+    }
+
+    pub fn write_allowed_fail(&mut self) -> io::Result<()> {
+        self.write_short_result("a", term::color::YELLOW)
+    }
+
+    pub fn write_bench(&mut self) -> io::Result<()> {
+        self.write_pretty("bench", term::color::CYAN)
+    }
+
+    pub fn write_short_result(
+        &mut self,
+        result: &str,
+        color: term::color::Color,
+    ) -> io::Result<()> {
+        self.write_pretty(result, color)?;
+        if self.test_count % QUIET_MODE_MAX_COLUMN == QUIET_MODE_MAX_COLUMN - 1 {
+            // we insert a new line every 100 dots in order to flush the
+            // screen when dealing with line-buffered output (e.g. piping to
+            // `stamp` in the rust CI).
+            self.write_plain("\n")?;
+        }
+
+        self.test_count += 1;
+        Ok(())
+    }
+
+    pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
+        match self.out {
+            Pretty(ref mut term) => {
+                if self.use_color {
+                    term.fg(color)?;
+                }
+                term.write_all(word.as_bytes())?;
+                if self.use_color {
+                    term.reset()?;
+                }
+                term.flush()
+            }
+            Raw(ref mut stdout) => {
+                stdout.write_all(word.as_bytes())?;
+                stdout.flush()
+            }
+        }
+    }
+
+    pub fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
+        let s = s.as_ref();
+        self.out.write_all(s.as_bytes())?;
+        self.out.flush()
+    }
+
+    pub fn write_outputs(&mut self, state: &ConsoleTestState) -> io::Result<()> {
+        self.write_plain("\nsuccesses:\n")?;
+        let mut successes = Vec::new();
+        let mut stdouts = String::new();
+        for &(ref f, ref stdout) in &state.not_failures {
+            successes.push(f.name.to_string());
+            if !stdout.is_empty() {
+                stdouts.push_str(&format!("---- {} stdout ----\n\t", f.name));
+                let output = String::from_utf8_lossy(stdout);
+                stdouts.push_str(&output);
+                stdouts.push_str("\n");
+            }
+        }
+        if !stdouts.is_empty() {
+            self.write_plain("\n")?;
+            self.write_plain(&stdouts)?;
+        }
+
+        self.write_plain("\nsuccesses:\n")?;
+        successes.sort();
+        for name in &successes {
+            self.write_plain(&format!("    {}\n", name))?;
+        }
+        Ok(())
+    }
+
+    pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
+        self.write_plain("\nfailures:\n")?;
+        let mut failures = Vec::new();
+        let mut fail_out = String::new();
+        for &(ref f, ref stdout) in &state.failures {
+            failures.push(f.name.to_string());
+            if !stdout.is_empty() {
+                fail_out.push_str(&format!("---- {} stdout ----\n\t", f.name));
+                let output = String::from_utf8_lossy(stdout);
+                fail_out.push_str(&output);
+                fail_out.push_str("\n");
+            }
+        }
+        if !fail_out.is_empty() {
+            self.write_plain("\n")?;
+            self.write_plain(&fail_out)?;
+        }
+
+        self.write_plain("\nfailures:\n")?;
+        failures.sort();
+        for name in &failures {
+            self.write_plain(&format!("    {}\n", name))?;
+        }
+        Ok(())
+    }
+
+    fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
+        let name = desc.padded_name(self.max_name_len, desc.name.padding());
+        self.write_plain(&format!("test {} ... ", name))?;
+
+        Ok(())
+    }
+}
+
+impl<T: Write> OutputFormatter for TerseFormatter<T> {
+    fn write_run_start(&mut self, test_count: usize) -> io::Result<()> {
+        let noun = if test_count != 1 { "tests" } else { "test" };
+        self.write_plain(&format!("\nrunning {} {}\n", test_count, noun))
+    }
+
+    fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
+        // Remnants from old libtest code that used the padding value
+        // in order to indicate benchmarks.
+        // When running benchmarks, terse-mode should still print their name as if
+        // it is the Pretty formatter.
+        if !self.is_multithreaded && desc.name.padding() == PadOnRight {
+            self.write_test_name(desc)?;
+        }
+
+        Ok(())
+    }
+
+    fn write_result(&mut self, desc: &TestDesc, result: &TestResult, _: &[u8]) -> io::Result<()> {
+        match *result {
+            TrOk => self.write_ok(),
+            TrFailed | TrFailedMsg(_) => self.write_failed(),
+            TrIgnored => self.write_ignored(),
+            TrAllowedFail => self.write_allowed_fail(),
+            TrBench(ref bs) => {
+                if self.is_multithreaded {
+                    self.write_test_name(desc)?;
+                }
+                self.write_bench()?;
+                self.write_plain(&format!(": {}\n", fmt_bench_samples(bs)))
+            }
+        }
+    }
+
+    fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
+        self.write_plain(&format!(
+            "test {} has been running for over {} seconds\n",
+            desc.name,
+            TEST_WARN_TIMEOUT_S
+        ))
+    }
+
+    fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
+        if state.options.display_output {
+            self.write_outputs(state)?;
+        }
+        let success = state.failed == 0;
+        if !success {
+            self.write_failures(state)?;
+        }
+
+        self.write_plain("\ntest result: ")?;
+
+        if success {
+            // There's no parallelism at this point so it's safe to use color
+            self.write_pretty("ok", term::color::GREEN)?;
+        } else {
+            self.write_pretty("FAILED", term::color::RED)?;
+        }
+
+        let s = if state.allowed_fail > 0 {
+            format!(
+                ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out\n\n",
+                state.passed,
+                state.failed + state.allowed_fail,
+                state.allowed_fail,
+                state.ignored,
+                state.measured,
+                state.filtered_out
+            )
+        } else {
+            format!(
+                ". {} passed; {} failed; {} ignored; {} measured; {} filtered out\n\n",
+                state.passed,
+                state.failed,
+                state.ignored,
+                state.measured,
+                state.filtered_out
+            )
+        };
+
+        self.write_plain(&s)?;
+
+        Ok(success)
+    }
+}
index f7880d3c4d854f7afaa8018a9b949e32003cbae6..ffa27688cf1a70d4ac71face0478209e5736bb82 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -71,6 +71,7 @@
 use std::sync::{Arc, Mutex};
 use std::thread;
 use std::time::{Instant, Duration};
+use std::borrow::Cow;
 
 const TEST_WARN_TIMEOUT_S: u64 = 60;
 const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in quiet mode
@@ -84,6 +85,9 @@ pub mod test {
 }
 
 pub mod stats;
+mod formatters;
+
+use formatters::{OutputFormatter, PrettyFormatter, TerseFormatter, JsonFormatter};
 
 // The name of a test. By convention this follows the rules for rust
 // paths; i.e. it should be a series of identifiers separated by double
@@ -94,14 +98,33 @@ pub mod test {
 pub enum TestName {
     StaticTestName(&'static str),
     DynTestName(String),
+    AlignedTestName(Cow<'static, str>, NamePadding),
 }
 impl TestName {
     fn as_slice(&self) -> &str {
         match *self {
             StaticTestName(s) => s,
             DynTestName(ref s) => s,
+            AlignedTestName(ref s, _) => &*s,
         }
     }
+
+    fn padding(&self) -> NamePadding {
+        match self {
+            &AlignedTestName(_, p) => p,
+            _ => PadNone,
+        }
+    }
+
+    fn with_padding(&self, padding: NamePadding) -> TestName {
+        let name = match self {
+            &TestName::StaticTestName(name) => Cow::Borrowed(name),
+            &TestName::DynTestName(ref name) => Cow::Owned(name.clone()),
+            &TestName::AlignedTestName(ref name, _) => name.clone(),
+        };
+
+        TestName::AlignedTestName(name, padding)
+    }
 }
 impl fmt::Display for TestName {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -109,7 +132,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 pub enum NamePadding {
     PadNone,
     PadOnRight,
@@ -217,10 +240,7 @@ pub struct Metric {
 
 impl Metric {
     pub fn new(value: f64, noise: f64) -> Metric {
-        Metric {
-            value,
-            noise,
-        }
+        Metric { value, noise }
     }
 }
 
@@ -232,9 +252,7 @@ pub struct Options {
 
 impl Options {
     pub fn new() -> Options {
-        Options {
-            display_output: false,
-        }
+        Options { display_output: false }
     }
 
     pub fn display_output(mut self, display_output: bool) -> Options {
@@ -274,25 +292,24 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Options) {
 // rather than a &[].
 pub fn test_main_static(tests: &[TestDescAndFn]) {
     let args = env::args().collect::<Vec<_>>();
-    let owned_tests = tests.iter()
-                           .map(|t| {
-                               match t.testfn {
-                                   StaticTestFn(f) => {
-                                       TestDescAndFn {
-                                           testfn: StaticTestFn(f),
-                                           desc: t.desc.clone(),
-                                       }
-                                   }
-                                   StaticBenchFn(f) => {
-                                       TestDescAndFn {
-                                           testfn: StaticBenchFn(f),
-                                           desc: t.desc.clone(),
-                                       }
-                                   }
-                                   _ => panic!("non-static tests passed to test::test_main_static"),
-                               }
-                           })
-                           .collect();
+    let owned_tests = tests
+        .iter()
+        .map(|t| match t.testfn {
+            StaticTestFn(f) => {
+                TestDescAndFn {
+                    testfn: StaticTestFn(f),
+                    desc: t.desc.clone(),
+                }
+            }
+            StaticBenchFn(f) => {
+                TestDescAndFn {
+                    testfn: StaticBenchFn(f),
+                    desc: t.desc.clone(),
+                }
+            }
+            _ => panic!("non-static tests passed to test::test_main_static"),
+        })
+        .collect();
     test_main(&args, owned_tests, Options::new())
 }
 
@@ -303,6 +320,13 @@ pub enum ColorConfig {
     NeverColor,
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum OutputFormat {
+    Pretty,
+    Terse,
+    Json,
+}
+
 #[derive(Debug)]
 pub struct TestOpts {
     pub list: bool,
@@ -314,7 +338,7 @@ pub struct TestOpts {
     pub logfile: Option<PathBuf>,
     pub nocapture: bool,
     pub color: ColorConfig,
-    pub quiet: bool,
+    pub format: OutputFormat,
     pub test_threads: Option<usize>,
     pub skip: Vec<String>,
     pub options: Options,
@@ -333,7 +357,7 @@ fn new() -> TestOpts {
             logfile: None,
             nocapture: false,
             color: AutoColor,
-            quiet: false,
+            format: OutputFormat::Pretty,
             test_threads: None,
             skip: vec![],
             options: Options::new(),
@@ -351,26 +375,76 @@ fn optgroups() -> getopts::Options {
         .optflag("", "bench", "Run benchmarks instead of tests")
         .optflag("", "list", "List all tests and benchmarks")
         .optflag("h", "help", "Display this message (longer with --help)")
-        .optopt("", "logfile", "Write logs to the specified file instead \
-                                of stdout", "PATH")
-        .optflag("", "nocapture", "don't capture stdout/stderr of each \
-                                   task, allow printing directly")
-        .optopt("", "test-threads", "Number of threads used for running tests \
-                                     in parallel", "n_threads")
-        .optmulti("", "skip", "Skip tests whose names contain FILTER (this flag can \
-                               be used multiple times)","FILTER")
-        .optflag("q", "quiet", "Display one character per test instead of one line")
-        .optflag("", "exact", "Exactly match filters rather than by substring")
-        .optopt("", "color", "Configure coloring of output:
+        .optopt(
+            "",
+            "logfile",
+            "Write logs to the specified file instead \
+                                of stdout",
+            "PATH",
+        )
+        .optflag(
+            "",
+            "nocapture",
+            "don't capture stdout/stderr of each \
+                                   task, allow printing directly",
+        )
+        .optopt(
+            "",
+            "test-threads",
+            "Number of threads used for running tests \
+                                     in parallel",
+            "n_threads",
+        )
+        .optmulti(
+            "",
+            "skip",
+            "Skip tests whose names contain FILTER (this flag can \
+                               be used multiple times)",
+            "FILTER",
+        )
+        .optflag(
+            "q",
+            "quiet",
+            "Display one character per test instead of one line. \
+                                Alias to --format=terse",
+        )
+        .optflag(
+            "",
+            "exact",
+            "Exactly match filters rather than by substring",
+        )
+        .optopt(
+            "",
+            "color",
+            "Configure coloring of output:
             auto   = colorize if stdout is a tty and tests are run on serially (default);
             always = always colorize output;
-            never  = never colorize output;", "auto|always|never");
-    return opts
+            never  = never colorize output;",
+            "auto|always|never",
+        )
+        .optopt(
+            "",
+            "format",
+            "Configure formatting of output:
+            pretty = Print verbose output;
+            terse  = Display one character per test;
+            json   = Output a json document",
+            "pretty|terse|json",
+        )
+        .optopt(
+            "Z",
+            "",
+            "Enable nightly-only flags:
+            unstable-options = Allow use of experimental features",
+            "unstable-options",
+        );
+    return opts;
 }
 
 fn usage(binary: &str, options: &getopts::Options) {
     let message = format!("Usage: {} [OPTIONS] [FILTER]", binary);
-    println!(r#"{usage}
+    println!(
+        r#"{usage}
 
 The FILTER string is tested against the name of all tests, and only those
 tests whose names contain the filter are run.
@@ -397,11 +471,23 @@ fn usage(binary: &str, options: &getopts::Options) {
                      test, then the test runner will ignore these tests during
                      normal test runs. Running with --ignored will run these
                      tests."#,
-             usage = options.usage(&message));
+        usage = options.usage(&message)
+    );
+}
+
+// FIXME: Copied from libsyntax until linkage errors are resolved. Issue #47566
+fn is_nightly() -> bool {
+    // Whether this is a feature-staged build, i.e. on the beta or stable channel
+    let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
+    // Whether we should enable unstable features for bootstrapping
+    let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
+
+    bootstrap || !disable_unstable_features
 }
 
 // Parses command line arguments into test options
 pub fn parse_opts(args: &[String]) -> Option<OptRes> {
+    let mut allow_unstable = false;
     let opts = optgroups();
     let args = args.get(1..).unwrap_or(args);
     let matches = match opts.parse(args) {
@@ -409,6 +495,24 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
         Err(f) => return Some(Err(f.to_string())),
     };
 
+    if let Some(opt) = matches.opt_str("Z") {
+        if !is_nightly() {
+            return Some(Err(
+                "the option `Z` is only accepted on the nightly compiler"
+                    .into(),
+            ));
+        }
+
+        match &*opt {
+            "unstable-options" => {
+                allow_unstable = true;
+            }
+            _ => {
+                return Some(Err("Unrecognized option to `Z`".into()));
+            }
+        }
+    };
+
     if matches.opt_present("h") {
         usage(&args[0], &opts);
         return None;
@@ -435,22 +539,25 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
     if !nocapture {
         nocapture = match env::var("RUST_TEST_NOCAPTURE") {
             Ok(val) => &val != "0",
-            Err(_) => false
+            Err(_) => false,
         };
     }
 
     let test_threads = match matches.opt_str("test-threads") {
-        Some(n_str) =>
+        Some(n_str) => {
             match n_str.parse::<usize>() {
-                Ok(0) =>
-                    return Some(Err(format!("argument for --test-threads must not be 0"))),
+                Ok(0) => return Some(Err(format!("argument for --test-threads must not be 0"))),
                 Ok(n) => Some(n),
-                Err(e) =>
-                    return Some(Err(format!("argument for --test-threads must be a number > 0 \
-                                             (error: {})", e)))
-            },
-        None =>
-            None,
+                Err(e) => {
+                    return Some(Err(format!(
+                        "argument for --test-threads must be a number > 0 \
+                                             (error: {})",
+                        e
+                    )))
+                }
+            }
+        }
+        None => None,
     };
 
     let color = match matches.opt_str("color").as_ref().map(|s| &**s) {
@@ -459,9 +566,34 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
         Some("never") => NeverColor,
 
         Some(v) => {
-            return Some(Err(format!("argument for --color must be auto, always, or never (was \
+            return Some(Err(format!(
+                "argument for --color must be auto, always, or never (was \
+                                     {})",
+                v
+            )))
+        }
+    };
+
+    let format = match matches.opt_str("format").as_ref().map(|s| &**s) {
+        None if quiet => OutputFormat::Terse,
+        Some("pretty") | None => OutputFormat::Pretty,
+        Some("terse") => OutputFormat::Terse,
+        Some("json") => {
+            if !allow_unstable {
+                return Some(Err(
+                    "The \"json\" format is only accepted on the nightly compiler"
+                        .into(),
+                ));
+            }
+            OutputFormat::Json
+        }
+
+        Some(v) => {
+            return Some(Err(format!(
+                "argument for --format must be pretty, terse, or json (was \
                                      {})",
-                                    v)))
+                v
+            )))
         }
     };
 
@@ -475,7 +607,7 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
         logfile,
         nocapture,
         color,
-        quiet,
+        format,
         test_threads,
         skip: matches.opt_strs("skip"),
         options: Options::new(),
@@ -507,11 +639,24 @@ enum OutputLocation<T> {
     Raw(T),
 }
 
-struct ConsoleTestState<T> {
+impl<T: Write> Write for OutputLocation<T> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        match *self {
+            Pretty(ref mut term) => term.write(buf),
+            Raw(ref mut stdout) => stdout.write(buf),
+        }
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        match *self {
+            Pretty(ref mut term) => term.flush(),
+            Raw(ref mut stdout) => stdout.flush(),
+        }
+    }
+}
+
+struct ConsoleTestState {
     log_out: Option<File>,
-    out: OutputLocation<T>,
-    use_color: bool,
-    quiet: bool,
     total: usize,
     passed: usize,
     failed: usize,
@@ -522,26 +667,18 @@ struct ConsoleTestState<T> {
     metrics: MetricMap,
     failures: Vec<(TestDesc, Vec<u8>)>,
     not_failures: Vec<(TestDesc, Vec<u8>)>,
-    max_name_len: usize, // number of columns to fill when aligning names
     options: Options,
 }
 
-impl<T: Write> ConsoleTestState<T> {
-    pub fn new(opts: &TestOpts, _: Option<T>) -> io::Result<ConsoleTestState<io::Stdout>> {
+impl ConsoleTestState {
+    pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestState> {
         let log_out = match opts.logfile {
             Some(ref path) => Some(File::create(path)?),
             None => None,
         };
-        let out = match term::stdout() {
-            None => Raw(io::stdout()),
-            Some(t) => Pretty(t),
-        };
 
         Ok(ConsoleTestState {
-            out,
             log_out,
-            use_color: use_color(opts),
-            quiet: opts.quiet,
             total: 0,
             passed: 0,
             failed: 0,
@@ -552,119 +689,10 @@ pub fn new(opts: &TestOpts, _: Option<T>) -> io::Result<ConsoleTestState<io::Std
             metrics: MetricMap::new(),
             failures: Vec::new(),
             not_failures: Vec::new(),
-            max_name_len: 0,
             options: opts.options,
         })
     }
 
-    pub fn write_ok(&mut self) -> io::Result<()> {
-        self.write_short_result("ok", ".", term::color::GREEN)
-    }
-
-    pub fn write_failed(&mut self) -> io::Result<()> {
-        self.write_short_result("FAILED", "F", term::color::RED)
-    }
-
-    pub fn write_ignored(&mut self) -> io::Result<()> {
-        self.write_short_result("ignored", "i", term::color::YELLOW)
-    }
-
-    pub fn write_allowed_fail(&mut self) -> io::Result<()> {
-        self.write_short_result("FAILED (allowed)", "a", term::color::YELLOW)
-    }
-
-    pub fn write_bench(&mut self) -> io::Result<()> {
-        self.write_pretty("bench", term::color::CYAN)
-    }
-
-    pub fn write_short_result(&mut self, verbose: &str, quiet: &str, color: term::color::Color)
-                              -> io::Result<()> {
-        if self.quiet {
-            self.write_pretty(quiet, color)?;
-            if self.current_test_count() % QUIET_MODE_MAX_COLUMN == QUIET_MODE_MAX_COLUMN - 1 {
-                // we insert a new line every 100 dots in order to flush the
-                // screen when dealing with line-buffered output (e.g. piping to
-                // `stamp` in the rust CI).
-                self.write_plain("\n")?;
-            }
-            Ok(())
-        } else {
-            self.write_pretty(verbose, color)?;
-            self.write_plain("\n")
-        }
-    }
-
-    pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
-        match self.out {
-            Pretty(ref mut term) => {
-                if self.use_color {
-                    term.fg(color)?;
-                }
-                term.write_all(word.as_bytes())?;
-                if self.use_color {
-                    term.reset()?;
-                }
-                term.flush()
-            }
-            Raw(ref mut stdout) => {
-                stdout.write_all(word.as_bytes())?;
-                stdout.flush()
-            }
-        }
-    }
-
-    pub fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
-        let s = s.as_ref();
-        match self.out {
-            Pretty(ref mut term) => {
-                term.write_all(s.as_bytes())?;
-                term.flush()
-            }
-            Raw(ref mut stdout) => {
-                stdout.write_all(s.as_bytes())?;
-                stdout.flush()
-            }
-        }
-    }
-
-    pub fn write_run_start(&mut self, len: usize) -> io::Result<()> {
-        self.total = len;
-        let noun = if len != 1 {
-            "tests"
-        } else {
-            "test"
-        };
-        self.write_plain(&format!("\nrunning {} {}\n", len, noun))
-    }
-
-    pub fn write_test_start(&mut self, test: &TestDesc, align: NamePadding) -> io::Result<()> {
-        if self.quiet && align != PadOnRight {
-            Ok(())
-        } else {
-            let name = test.padded_name(self.max_name_len, align);
-            self.write_plain(&format!("test {} ... ", name))
-        }
-    }
-
-    pub fn write_result(&mut self, result: &TestResult) -> io::Result<()> {
-        match *result {
-            TrOk => self.write_ok(),
-            TrFailed | TrFailedMsg(_) => self.write_failed(),
-            TrIgnored => self.write_ignored(),
-            TrAllowedFail => self.write_allowed_fail(),
-            TrBench(ref bs) => {
-                self.write_bench()?;
-                self.write_plain(&format!(": {}\n", fmt_bench_samples(bs)))
-            }
-        }
-    }
-
-    pub fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
-        self.write_plain(&format!("test {} has been running for over {} seconds\n",
-                                  desc.name,
-                                  TEST_WARN_TIMEOUT_S))
-    }
-
     pub fn write_log<S: AsRef<str>>(&mut self, msg: S) -> io::Result<()> {
         let msg = msg.as_ref();
         match self.log_out {
@@ -674,114 +702,23 @@ pub fn write_log<S: AsRef<str>>(&mut self, msg: S) -> io::Result<()> {
     }
 
     pub fn write_log_result(&mut self, test: &TestDesc, result: &TestResult) -> io::Result<()> {
-        self.write_log(
-            format!("{} {}\n",
-                    match *result {
-                        TrOk => "ok".to_owned(),
-                        TrFailed => "failed".to_owned(),
-                        TrFailedMsg(ref msg) => format!("failed: {}", msg),
-                        TrIgnored => "ignored".to_owned(),
-                        TrAllowedFail => "failed (allowed)".to_owned(),
-                        TrBench(ref bs) => fmt_bench_samples(bs),
-                    },
-                    test.name))
-    }
-
-    pub fn write_failures(&mut self) -> io::Result<()> {
-        self.write_plain("\nfailures:\n")?;
-        let mut failures = Vec::new();
-        let mut fail_out = String::new();
-        for &(ref f, ref stdout) in &self.failures {
-            failures.push(f.name.to_string());
-            if !stdout.is_empty() {
-                fail_out.push_str(&format!("---- {} stdout ----\n\t", f.name));
-                let output = String::from_utf8_lossy(stdout);
-                fail_out.push_str(&output);
-                fail_out.push_str("\n");
-            }
-        }
-        if !fail_out.is_empty() {
-            self.write_plain("\n")?;
-            self.write_plain(&fail_out)?;
-        }
-
-        self.write_plain("\nfailures:\n")?;
-        failures.sort();
-        for name in &failures {
-            self.write_plain(&format!("    {}\n", name))?;
-        }
-        Ok(())
-    }
-
-    pub fn write_outputs(&mut self) -> io::Result<()> {
-        self.write_plain("\nsuccesses:\n")?;
-        let mut successes = Vec::new();
-        let mut stdouts = String::new();
-        for &(ref f, ref stdout) in &self.not_failures {
-            successes.push(f.name.to_string());
-            if !stdout.is_empty() {
-                stdouts.push_str(&format!("---- {} stdout ----\n\t", f.name));
-                let output = String::from_utf8_lossy(stdout);
-                stdouts.push_str(&output);
-                stdouts.push_str("\n");
-            }
-        }
-        if !stdouts.is_empty() {
-            self.write_plain("\n")?;
-            self.write_plain(&stdouts)?;
-        }
-
-        self.write_plain("\nsuccesses:\n")?;
-        successes.sort();
-        for name in &successes {
-            self.write_plain(&format!("    {}\n", name))?;
-        }
-        Ok(())
+        self.write_log(format!(
+            "{} {}\n",
+            match *result {
+                TrOk => "ok".to_owned(),
+                TrFailed => "failed".to_owned(),
+                TrFailedMsg(ref msg) => format!("failed: {}", msg),
+                TrIgnored => "ignored".to_owned(),
+                TrAllowedFail => "failed (allowed)".to_owned(),
+                TrBench(ref bs) => fmt_bench_samples(bs),
+            },
+            test.name
+        ))
     }
 
     fn current_test_count(&self) -> usize {
         self.passed + self.failed + self.ignored + self.measured + self.allowed_fail
     }
-
-    pub fn write_run_finish(&mut self) -> io::Result<bool> {
-        assert!(self.current_test_count() == self.total);
-
-        if self.options.display_output {
-            self.write_outputs()?;
-        }
-        let success = self.failed == 0;
-        if !success {
-            self.write_failures()?;
-        }
-
-        self.write_plain("\ntest result: ")?;
-        if success {
-            // There's no parallelism at this point so it's safe to use color
-            self.write_pretty("ok", term::color::GREEN)?;
-        } else {
-            self.write_pretty("FAILED", term::color::RED)?;
-        }
-        let s = if self.allowed_fail > 0 {
-            format!(
-                ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out\n\n",
-                self.passed,
-                self.failed + self.allowed_fail,
-                self.allowed_fail,
-                self.ignored,
-                self.measured,
-                self.filtered_out)
-        } else {
-            format!(
-                ". {} passed; {} failed; {} ignored; {} measured; {} filtered out\n\n",
-                self.passed,
-                self.failed,
-                self.ignored,
-                self.measured,
-                self.filtered_out)
-        };
-        self.write_plain(&s)?;
-        return Ok(success);
-    }
 }
 
 // Format a number with thousands separators
@@ -815,19 +752,30 @@ pub fn fmt_bench_samples(bs: &BenchSamples) -> String {
     let median = bs.ns_iter_summ.median as usize;
     let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
 
-    output.write_fmt(format_args!("{:>11} ns/iter (+/- {})",
-                                  fmt_thousands_sep(median, ','),
-                                  fmt_thousands_sep(deviation, ',')))
-          .unwrap();
+    output
+        .write_fmt(format_args!(
+            "{:>11} ns/iter (+/- {})",
+            fmt_thousands_sep(median, ','),
+            fmt_thousands_sep(deviation, ',')
+        ))
+        .unwrap();
     if bs.mb_s != 0 {
-        output.write_fmt(format_args!(" = {} MB/s", bs.mb_s)).unwrap();
+        output
+            .write_fmt(format_args!(" = {} MB/s", bs.mb_s))
+            .unwrap();
     }
     output
 }
 
 // List the tests to console, and optionally to logfile. Filters are honored.
 pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> {
-    let mut st = ConsoleTestState::new(opts, None::<io::Stdout>)?;
+    let mut output = match term::stdout() {
+        None => Raw(io::stdout()),
+        Some(t) => Pretty(t),
+    };
+
+    let quiet = opts.format == OutputFormat::Terse;
+    let mut st = ConsoleTestState::new(opts)?;
 
     let mut ntest = 0;
     let mut nbench = 0;
@@ -835,14 +783,24 @@ pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Res
     for test in filter_tests(&opts, tests) {
         use TestFn::*;
 
-        let TestDescAndFn { desc: TestDesc { name, .. }, testfn } = test;
+        let TestDescAndFn {
+            desc: TestDesc { name, .. },
+            testfn,
+        } = test;
 
         let fntype = match testfn {
-            StaticTestFn(..) | DynTestFn(..) => { ntest += 1; "test" },
-            StaticBenchFn(..) | DynBenchFn(..) => { nbench += 1; "benchmark" },
+            StaticTestFn(..) | DynTestFn(..) => {
+                ntest += 1;
+                "test"
+            }
+            StaticBenchFn(..) |
+            DynBenchFn(..) => {
+                nbench += 1;
+                "benchmark"
+            }
         };
 
-        st.write_plain(format!("{}: {}\n", name, fntype))?;
+        writeln!(output, "{}: {}", name, fntype)?;
         st.write_log(format!("{} {}\n", fntype, name))?;
     }
 
@@ -853,13 +811,16 @@ fn plural(count: u32, s: &str) -> String {
         }
     }
 
-    if !opts.quiet {
+    if !quiet {
         if ntest != 0 || nbench != 0 {
-            st.write_plain("\n")?;
+            writeln!(output, "")?;
         }
-        st.write_plain(format!("{}, {}\n",
+
+        writeln!(output,
+            "{}, {}",
             plural(ntest, "test"),
-            plural(nbench, "benchmark")))?;
+            plural(nbench, "benchmark")
+        )?;
     }
 
     Ok(())
@@ -867,16 +828,23 @@ fn plural(count: u32, s: &str) -> String {
 
 // A simple console test runner
 pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<bool> {
+    fn callback(
+        event: &TestEvent,
+        st: &mut ConsoleTestState,
+        out: &mut OutputFormatter,
+    ) -> io::Result<()> {
 
-    fn callback<T: Write>(event: &TestEvent, st: &mut ConsoleTestState<T>) -> io::Result<()> {
         match (*event).clone() {
-            TeFiltered(ref filtered_tests) => st.write_run_start(filtered_tests.len()),
+            TeFiltered(ref filtered_tests) => {
+                st.total = filtered_tests.len();
+                out.write_run_start(filtered_tests.len())
+            }
             TeFilteredOut(filtered_out) => Ok(st.filtered_out = filtered_out),
-            TeWait(ref test, padding) => st.write_test_start(test, padding),
-            TeTimeout(ref test) => st.write_timeout(test),
+            TeWait(ref test) => out.write_test_start(test),
+            TeTimeout(ref test) => out.write_timeout(test),
             TeResult(test, result, stdout) => {
                 st.write_log_result(&test, &result)?;
-                st.write_result(&result)?;
+                out.write_result(&test, &result, &*stdout)?;
                 match result {
                     TrOk => {
                         st.passed += 1;
@@ -885,9 +853,11 @@ fn callback<T: Write>(event: &TestEvent, st: &mut ConsoleTestState<T>) -> io::Re
                     TrIgnored => st.ignored += 1,
                     TrAllowedFail => st.allowed_fail += 1,
                     TrBench(bs) => {
-                        st.metrics.insert_metric(test.name.as_slice(),
-                                                 bs.ns_iter_summ.median,
-                                                 bs.ns_iter_summ.max - bs.ns_iter_summ.min);
+                        st.metrics.insert_metric(
+                            test.name.as_slice(),
+                            bs.ns_iter_summ.median,
+                            bs.ns_iter_summ.max - bs.ns_iter_summ.min,
+                        );
                         st.measured += 1
                     }
                     TrFailed => {
@@ -897,9 +867,7 @@ fn callback<T: Write>(event: &TestEvent, st: &mut ConsoleTestState<T>) -> io::Re
                     TrFailedMsg(msg) => {
                         st.failed += 1;
                         let mut stdout = stdout;
-                        stdout.extend_from_slice(
-                            format!("note: {}", msg).as_bytes()
-                        );
+                        stdout.extend_from_slice(format!("note: {}", msg).as_bytes());
                         st.failures.push((test, stdout));
                     }
                 }
@@ -908,19 +876,47 @@ fn callback<T: Write>(event: &TestEvent, st: &mut ConsoleTestState<T>) -> io::Re
         }
     }
 
-    let mut st = ConsoleTestState::new(opts, None::<io::Stdout>)?;
+    let output = match term::stdout() {
+        None => Raw(io::stdout()),
+        Some(t) => Pretty(t),
+    };
+
+    let max_name_len = tests
+        .iter()
+        .max_by_key(|t| len_if_padded(*t))
+        .map(|t| t.desc.name.as_slice().len())
+        .unwrap_or(0);
+
+    let is_multithreaded = opts.test_threads.unwrap_or_else(get_concurrency) > 1;
+
+    let mut out: Box<OutputFormatter> = match opts.format {
+        OutputFormat::Pretty => Box::new(PrettyFormatter::new(
+            output,
+            use_color(opts),
+            max_name_len,
+            is_multithreaded,
+        )),
+        OutputFormat::Terse => Box::new(TerseFormatter::new(
+            output,
+            use_color(opts),
+            max_name_len,
+            is_multithreaded,
+        )),
+        OutputFormat::Json => Box::new(JsonFormatter::new(output)),
+    };
+    let mut st = ConsoleTestState::new(opts)?;
     fn len_if_padded(t: &TestDescAndFn) -> usize {
         match t.testfn.padding() {
             PadNone => 0,
             PadOnRight => t.desc.name.as_slice().len(),
         }
     }
-    if let Some(t) = tests.iter().max_by_key(|t| len_if_padded(*t)) {
-        let n = t.desc.name.as_slice();
-        st.max_name_len = n.len();
-    }
-    run_tests(opts, tests, |x| callback(&x, &mut st))?;
-    return st.write_run_finish();
+
+    run_tests(opts, tests, |x| callback(&x, &mut st, &mut *out))?;
+
+    assert!(st.current_test_count() == st.total);
+
+    return out.write_run_finish(&st);
 }
 
 #[test]
@@ -939,11 +935,10 @@ fn should_sort_failures_before_printing_them() {
         allow_fail: false,
     };
 
-    let mut st = ConsoleTestState {
+    let mut out = PrettyFormatter::new(Raw(Vec::new()), false, 10, false);
+
+    let st = ConsoleTestState {
         log_out: None,
-        out: Raw(Vec::new()),
-        use_color: false,
-        quiet: false,
         total: 0,
         passed: 0,
         failed: 0,
@@ -951,17 +946,16 @@ fn should_sort_failures_before_printing_them() {
         allowed_fail: 0,
         filtered_out: 0,
         measured: 0,
-        max_name_len: 10,
         metrics: MetricMap::new(),
         failures: vec![(test_b, Vec::new()), (test_a, Vec::new())],
         options: Options::new(),
         not_failures: Vec::new(),
     };
 
-    st.write_failures().unwrap();
-    let s = match st.out {
-        Raw(ref m) => String::from_utf8_lossy(&m[..]),
-        Pretty(_) => unreachable!(),
+    out.write_failures(&st).unwrap();
+    let s = match out.output_location() {
+        &Raw(ref m) => String::from_utf8_lossy(&m[..]),
+        &Pretty(_) => unreachable!(),
     };
 
     let apos = s.find("a").unwrap();
@@ -1009,7 +1003,7 @@ fn stdout_isatty() -> bool {
 #[derive(Clone)]
 pub enum TestEvent {
     TeFiltered(Vec<TestDesc>),
-    TeWait(TestDesc, NamePadding),
+    TeWait(TestDesc),
     TeResult(TestDesc, TestResult, Vec<u8>),
     TeTimeout(TestDesc),
     TeFilteredOut(usize),
@@ -1017,9 +1011,19 @@ pub enum TestEvent {
 
 pub type MonitorMsg = (TestDesc, TestResult, Vec<u8>);
 
+struct Sink(Arc<Mutex<Vec<u8>>>);
+impl Write for Sink {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+        Write::write(&mut *self.0.lock().unwrap(), data)
+    }
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
 
 pub fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) -> io::Result<()>
-    where F: FnMut(TestEvent) -> io::Result<()>
+where
+    F: FnMut(TestEvent) -> io::Result<()>,
 {
     use std::collections::HashMap;
     use std::sync::mpsc::RecvTimeoutError;
@@ -1031,27 +1035,29 @@ pub fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F)
         filtered_tests = convert_benchmarks_to_tests(filtered_tests);
     }
 
+    let filtered_tests = {
+        let mut filtered_tests = filtered_tests;
+        for test in filtered_tests.iter_mut() {
+            test.desc.name = test.desc.name.with_padding(test.testfn.padding());
+        }
+
+        filtered_tests
+    };
+
     let filtered_out = tests_len - filtered_tests.len();
     callback(TeFilteredOut(filtered_out))?;
 
-    let filtered_descs = filtered_tests.iter()
-                                       .map(|t| t.desc.clone())
-                                       .collect();
+    let filtered_descs = filtered_tests.iter().map(|t| t.desc.clone()).collect();
 
     callback(TeFiltered(filtered_descs))?;
 
     let (filtered_tests, filtered_benchs): (Vec<_>, _) =
-        filtered_tests.into_iter().partition(|e| {
-            match e.testfn {
-                StaticTestFn(_) | DynTestFn(_) => true,
-                _ => false,
-            }
+        filtered_tests.into_iter().partition(|e| match e.testfn {
+            StaticTestFn(_) | DynTestFn(_) => true,
+            _ => false,
         });
 
-    let concurrency = match opts.test_threads {
-        Some(n) => n,
-        None => get_concurrency(),
-    };
+    let concurrency = opts.test_threads.unwrap_or_else(get_concurrency);
 
     let mut remaining = filtered_tests;
     remaining.reverse();
@@ -1063,8 +1069,13 @@ pub fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F)
 
     fn get_timed_out_tests(running_tests: &mut HashMap<TestDesc, Instant>) -> Vec<TestDesc> {
         let now = Instant::now();
-        let timed_out = running_tests.iter()
-            .filter_map(|(desc, timeout)| if &now >= timeout { Some(desc.clone())} else { None })
+        let timed_out = running_tests
+            .iter()
+            .filter_map(|(desc, timeout)| if &now >= timeout {
+                Some(desc.clone())
+            } else {
+                None
+            })
             .collect();
         for test in &timed_out {
             running_tests.remove(test);
@@ -1079,13 +1090,14 @@ fn calc_timeout(running_tests: &HashMap<TestDesc, Instant>) -> Option<Duration>
                 *next_timeout - now
             } else {
                 Duration::new(0, 0)
-            }})
+            }
+        })
     };
 
     if concurrency == 1 {
         while !remaining.is_empty() {
             let test = remaining.pop().unwrap();
-            callback(TeWait(test.desc.clone(), test.testfn.padding()))?;
+            callback(TeWait(test.desc.clone()))?;
             run_test(opts, !opts.run_tests, test, tx.clone());
             let (test, result, stdout) = rx.recv().unwrap();
             callback(TeResult(test, result, stdout))?;
@@ -1096,6 +1108,7 @@ fn calc_timeout(running_tests: &HashMap<TestDesc, Instant>) -> Option<Duration>
                 let test = remaining.pop().unwrap();
                 let timeout = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S);
                 running_tests.insert(test.desc.clone(), timeout);
+                callback(TeWait(test.desc.clone()))?; //here no pad
                 run_test(opts, !opts.run_tests, test, tx.clone());
                 pending += 1;
             }
@@ -1119,7 +1132,6 @@ fn calc_timeout(running_tests: &HashMap<TestDesc, Instant>) -> Option<Duration>
             let (desc, result, stdout) = res.unwrap();
             running_tests.remove(&desc);
 
-            callback(TeWait(desc.clone(), PadNone))?;
             callback(TeResult(desc, result, stdout))?;
             pending -= 1;
         }
@@ -1128,7 +1140,7 @@ fn calc_timeout(running_tests: &HashMap<TestDesc, Instant>) -> Option<Duration>
     if opts.bench_benchmarks {
         // All benchmarks run at the end, in serial.
         for b in filtered_benchs {
-            callback(TeWait(b.desc.clone(), b.testfn.padding()))?;
+            callback(TeWait(b.desc.clone()))?;
             run_test(opts, false, b, tx.clone());
             let (test, result, stdout) = rx.recv().unwrap();
             callback(TeResult(test, result, stdout))?;
@@ -1145,8 +1157,10 @@ fn get_concurrency() -> usize {
             match opt_n {
                 Some(n) if n > 0 => n,
                 _ => {
-                    panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.",
-                           s)
+                    panic!(
+                        "RUST_TEST_THREADS is `{}`, should be a positive integer.",
+                        s
+                    )
                 }
             }
         }
@@ -1203,10 +1217,8 @@ fn num_cpus() -> usize {
         unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize }
     }
 
-    #[cfg(any(target_os = "freebsd",
-              target_os = "dragonfly",
-              target_os = "bitrig",
-              target_os = "netbsd"))]
+    #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig",
+                target_os = "netbsd"))]
     fn num_cpus() -> usize {
         use std::ptr;
 
@@ -1219,12 +1231,14 @@ fn num_cpus() -> usize {
         if cpus < 1 {
             let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
             unsafe {
-                libc::sysctl(mib.as_mut_ptr(),
-                             2,
-                             &mut cpus as *mut _ as *mut _,
-                             &mut cpus_size as *mut _ as *mut _,
-                             ptr::null_mut(),
-                             0);
+                libc::sysctl(
+                    mib.as_mut_ptr(),
+                    2,
+                    &mut cpus as *mut _ as *mut _,
+                    &mut cpus_size as *mut _ as *mut _,
+                    ptr::null_mut(),
+                    0,
+                );
             }
             if cpus < 1 {
                 cpus = 1;
@@ -1242,12 +1256,14 @@ fn num_cpus() -> usize {
         let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
 
         unsafe {
-            libc::sysctl(mib.as_mut_ptr(),
-                         2,
-                         &mut cpus as *mut _ as *mut _,
-                         &mut cpus_size as *mut _ as *mut _,
-                         ptr::null_mut(),
-                         0);
+            libc::sysctl(
+                mib.as_mut_ptr(),
+                2,
+                &mut cpus as *mut _ as *mut _,
+                &mut cpus_size as *mut _ as *mut _,
+                ptr::null_mut(),
+                0,
+            );
         }
         if cpus < 1 {
             cpus = 1;
@@ -1269,27 +1285,27 @@ pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescA
     filtered = match opts.filter {
         None => filtered,
         Some(ref filter) => {
-            filtered.into_iter()
-                    .filter(|test| {
-                        if opts.filter_exact {
-                            test.desc.name.as_slice() == &filter[..]
-                        } else {
-                            test.desc.name.as_slice().contains(&filter[..])
-                        }
-                    })
-                    .collect()
+            filtered
+                .into_iter()
+                .filter(|test| if opts.filter_exact {
+                    test.desc.name.as_slice() == &filter[..]
+                } else {
+                    test.desc.name.as_slice().contains(&filter[..])
+                })
+                .collect()
         }
     };
 
     // Skip tests that match any of the skip filters
-    filtered = filtered.into_iter()
-        .filter(|t| !opts.skip.iter().any(|sf| {
-                if opts.filter_exact {
-                    t.desc.name.as_slice() == &sf[..]
-                } else {
-                    t.desc.name.as_slice().contains(&sf[..])
-                }
-            }))
+    filtered = filtered
+        .into_iter()
+        .filter(|t| {
+            !opts.skip.iter().any(|sf| if opts.filter_exact {
+                t.desc.name.as_slice() == &sf[..]
+            } else {
+                t.desc.name.as_slice().contains(&sf[..])
+            })
+        })
         .collect();
 
     // Maybe pull out the ignored test and unignore them
@@ -1298,9 +1314,12 @@ pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescA
     } else {
         fn filter(test: TestDescAndFn) -> Option<TestDescAndFn> {
             if test.desc.ignore {
-                let TestDescAndFn {desc, testfn} = test;
+                let TestDescAndFn { desc, testfn } = test;
                 Some(TestDescAndFn {
-                    desc: TestDesc { ignore: false, ..desc },
+                    desc: TestDesc {
+                        ignore: false,
+                        ..desc
+                    },
                     testfn,
                 })
             } else {
@@ -1311,7 +1330,9 @@ fn filter(test: TestDescAndFn) -> Option<TestDescAndFn> {
     };
 
     // Sort the tests alphabetically
-    filtered.sort_by(|t1, t2| t1.desc.name.as_slice().cmp(t2.desc.name.as_slice()));
+    filtered.sort_by(|t1, t2| {
+        t1.desc.name.as_slice().cmp(t2.desc.name.as_slice())
+    });
 
     filtered
 }
@@ -1334,24 +1355,26 @@ pub fn convert_benchmarks_to_tests(tests: Vec<TestDescAndFn>) -> Vec<TestDescAnd
                     })
                 }))
             }
-            f => f,
-        };
-        TestDescAndFn {
-            desc: x.desc,
-            testfn,
-        }
-    }).collect()
+                f => f,
+            };
+            TestDescAndFn {
+                desc: x.desc,
+                testfn,
+            }
+        })
+        .collect()
 }
 
-pub fn run_test(opts: &TestOpts,
-                force_ignore: bool,
-                test: TestDescAndFn,
-                monitor_ch: Sender<MonitorMsg>) {
+pub fn run_test(
+    opts: &TestOpts,
+    force_ignore: bool,
+    test: TestDescAndFn,
+    monitor_ch: Sender<MonitorMsg>,
+) {
 
-    let TestDescAndFn {desc, testfn} = test;
+    let TestDescAndFn { desc, testfn } = test;
 
-    let ignore_because_panic_abort =
-        cfg!(target_arch = "wasm32") &&
+    let ignore_because_panic_abort = cfg!(target_arch = "wasm32") &&
         !cfg!(target_os = "emscripten") &&
         desc.should_panic != ShouldPanic::No;
 
@@ -1364,16 +1387,6 @@ fn run_test_inner(desc: TestDesc,
                       monitor_ch: Sender<MonitorMsg>,
                       nocapture: bool,
                       testfn: Box<FnBox() + Send>) {
-        struct Sink(Arc<Mutex<Vec<u8>>>);
-        impl Write for Sink {
-            fn write(&mut self, data: &[u8]) -> io::Result<usize> {
-                Write::write(&mut *self.0.lock().unwrap(), data)
-            }
-            fn flush(&mut self) -> io::Result<()> {
-                Ok(())
-            }
-        }
-
         // Buffer for capturing standard I/O
         let data = Arc::new(Mutex::new(Vec::new()));
         let data2 = data.clone();
@@ -1383,7 +1396,7 @@ fn flush(&mut self) -> io::Result<()> {
             let oldio = if !nocapture {
                 Some((
                     io::set_print(Some(Box::new(Sink(data2.clone())))),
-                    io::set_panic(Some(Box::new(Sink(data2))))
+                    io::set_panic(Some(Box::new(Sink(data2)))),
                 ))
             } else {
                 None
@@ -1398,21 +1411,18 @@ fn flush(&mut self) -> io::Result<()> {
 
             let test_result = calc_result(&desc, result);
             let stdout = data.lock().unwrap().to_vec();
-            monitor_ch.send((desc.clone(), test_result, stdout)).unwrap();
+            monitor_ch
+                .send((desc.clone(), test_result, stdout))
+                .unwrap();
         };
 
 
         // If the platform is single-threaded we're just going to run
         // the test synchronously, regardless of the concurrency
         // level.
-        let supports_threads =
-            !cfg!(target_os = "emscripten") &&
-            !cfg!(target_arch = "wasm32");
+        let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_arch = "wasm32");
         if supports_threads {
-            let cfg = thread::Builder::new().name(match name {
-                DynTestName(ref name) => name.clone(),
-                StaticTestName(name) => name.to_owned(),
-            });
+            let cfg = thread::Builder::new().name(name.as_slice().to_owned());
             cfg.spawn(runtest).unwrap();
         } else {
             runtest();
@@ -1421,14 +1431,16 @@ fn flush(&mut self) -> io::Result<()> {
 
     match testfn {
         DynBenchFn(bencher) => {
-            let bs = ::bench::benchmark(|harness| bencher.run(harness));
-            monitor_ch.send((desc, TrBench(bs), Vec::new())).unwrap();
-            return;
+            ::bench::benchmark(desc,
+                                monitor_ch,
+                                opts.nocapture,
+                                |harness| bencher.run(harness));
         }
         StaticBenchFn(benchfn) => {
-            let bs = ::bench::benchmark(|harness| (benchfn.clone())(harness));
-            monitor_ch.send((desc, TrBench(bs), Vec::new())).unwrap();
-            return;
+            ::bench::benchmark(desc,
+                                monitor_ch,
+                                opts.nocapture,
+                                |harness| (benchfn.clone())(harness));
         }
         DynTestFn(f) => {
             let cb = move || {
@@ -1436,9 +1448,10 @@ fn flush(&mut self) -> io::Result<()> {
             };
             run_test_inner(desc, monitor_ch, opts.nocapture, Box::new(cb))
         }
-        StaticTestFn(f) =>
+        StaticTestFn(f) => {
             run_test_inner(desc, monitor_ch, opts.nocapture,
-                           Box::new(move || __rust_begin_short_backtrace(f))),
+                           Box::new(move || __rust_begin_short_backtrace(f)))
+        }
     }
 }
 
@@ -1452,12 +1465,13 @@ fn calc_result(desc: &TestDesc, task_result: Result<(), Box<Any + Send>>) -> Tes
     match (&desc.should_panic, task_result) {
         (&ShouldPanic::No, Ok(())) |
         (&ShouldPanic::Yes, Err(_)) => TrOk,
-        (&ShouldPanic::YesWithMessage(msg), Err(ref err)) =>
+        (&ShouldPanic::YesWithMessage(msg), Err(ref err)) => {
             if err.downcast_ref::<String>()
-                  .map(|e| &**e)
-                  .or_else(|| err.downcast_ref::<&'static str>().map(|e| *e))
-                  .map(|e| e.contains(msg))
-                  .unwrap_or(false) {
+                .map(|e| &**e)
+                .or_else(|| err.downcast_ref::<&'static str>().map(|e| *e))
+                .map(|e| e.contains(msg))
+                .unwrap_or(false)
+            {
                 TrOk
             } else {
                 if desc.allow_fail {
@@ -1465,7 +1479,8 @@ fn calc_result(desc: &TestDesc, task_result: Result<(), Box<Any + Send>>) -> Tes
                 } else {
                     TrFailedMsg(format!("Panic did not include expected string '{}'", msg))
                 }
-            },
+            }
+        }
         _ if desc.allow_fail => TrAllowedFail,
         _ => TrFailed,
     }
@@ -1493,18 +1508,15 @@ pub fn new() -> MetricMap {
     /// you want to see grow larger, so a change larger than `noise` in the
     /// negative direction represents a regression.
     pub fn insert_metric(&mut self, name: &str, value: f64, noise: f64) {
-        let m = Metric {
-            value,
-            noise,
-        };
+        let m = Metric { value, noise };
         self.0.insert(name.to_owned(), m);
     }
 
     pub fn fmt_metrics(&self) -> String {
         let v = self.0
-                   .iter()
-                   .map(|(k, v)| format!("{}: {} (+/- {})", *k, v.value, v.noise))
-                   .collect::<Vec<_>>();
+            .iter()
+            .map(|(k, v)| format!("{}: {} (+/- {})", *k, v.value, v.noise))
+            .collect::<Vec<_>>();
         v.join(", ")
     }
 }
@@ -1534,7 +1546,8 @@ pub fn black_box<T>(dummy: T) -> T {
 impl Bencher {
     /// Callback for benchmark functions to run in their body.
     pub fn iter<T, F>(&mut self, mut inner: F)
-        where F: FnMut() -> T
+    where
+        F: FnMut() -> T,
     {
         if self.mode == BenchMode::Single {
             ns_iter_inner(&mut inner, 1);
@@ -1545,7 +1558,8 @@ pub fn iter<T, F>(&mut self, mut inner: F)
     }
 
     pub fn bench<F>(&mut self, mut f: F) -> Option<stats::Summary>
-        where F: FnMut(&mut Bencher)
+    where
+        F: FnMut(&mut Bencher),
     {
         f(self);
         return self.summary;
@@ -1557,7 +1571,8 @@ fn ns_from_dur(dur: Duration) -> u64 {
 }
 
 fn ns_iter_inner<T, F>(inner: &mut F, k: u64) -> u64
-    where F: FnMut() -> T
+where
+    F: FnMut() -> T,
 {
     let start = Instant::now();
     for _ in 0..k {
@@ -1568,7 +1583,8 @@ fn ns_iter_inner<T, F>(inner: &mut F, k: u64) -> u64
 
 
 pub fn iter<T, F>(inner: &mut F) -> stats::Summary
-    where F: FnMut() -> T
+where
+    F: FnMut() -> T,
 {
     // Initial bench run to get ballpark figure.
     let ns_single = ns_iter_inner(inner, 1);
@@ -1610,7 +1626,8 @@ pub fn iter<T, F>(inner: &mut F) -> stats::Summary
         // If we've run for 100ms and seem to have converged to a
         // stable median.
         if loop_run > Duration::from_millis(100) && summ.median_abs_dev_pct < 1.0 &&
-           summ.median - summ5.median < summ5.median_abs_dev {
+            summ.median - summ5.median < summ5.median_abs_dev
+        {
             return summ5;
         }
 
@@ -1634,12 +1651,16 @@ pub fn iter<T, F>(inner: &mut F) -> stats::Summary
 }
 
 pub mod bench {
+    use std::panic::{catch_unwind, AssertUnwindSafe};
     use std::cmp;
+    use std::io;
+    use std::sync::{Arc, Mutex};
     use stats;
-    use super::{Bencher, BenchSamples, BenchMode};
+    use super::{Bencher, BenchSamples, BenchMode, Sink, MonitorMsg, TestDesc, Sender, TestResult};
 
-    pub fn benchmark<F>(f: F) -> BenchSamples
-        where F: FnMut(&mut Bencher)
+    pub fn benchmark<F>(desc: TestDesc, monitor_ch: Sender<MonitorMsg>, nocapture: bool, f: F)
+    where
+        F: FnMut(&mut Bencher),
     {
         let mut bs = Bencher {
             mode: BenchMode::Auto,
@@ -1647,30 +1668,58 @@ pub fn benchmark<F>(f: F) -> BenchSamples
             bytes: 0,
         };
 
-        return match bs.bench(f) {
-            Some(ns_iter_summ) => {
+        let data = Arc::new(Mutex::new(Vec::new()));
+        let data2 = data.clone();
+
+        let oldio = if !nocapture {
+            Some((
+                io::set_print(Some(Box::new(Sink(data2.clone())))),
+                io::set_panic(Some(Box::new(Sink(data2)))),
+            ))
+        } else {
+            None
+        };
+
+        let result = catch_unwind(AssertUnwindSafe(|| bs.bench(f)));
+
+        if let Some((printio, panicio)) = oldio {
+            io::set_print(printio);
+            io::set_panic(panicio);
+        };
+
+        let test_result = match result { //bs.bench(f) {
+            Ok(Some(ns_iter_summ)) => {
                 let ns_iter = cmp::max(ns_iter_summ.median as u64, 1);
                 let mb_s = bs.bytes * 1000 / ns_iter;
 
-                BenchSamples {
+                let bs = BenchSamples {
                     ns_iter_summ,
                     mb_s: mb_s as usize,
-                }
+                };
+                TestResult::TrBench(bs)
             }
-            None => {
+            Ok(None) => {
                 // iter not called, so no data.
                 // FIXME: error in this case?
                 let samples: &mut [f64] = &mut [0.0_f64; 1];
-                BenchSamples {
+                let bs = BenchSamples {
                     ns_iter_summ: stats::Summary::new(samples),
                     mb_s: 0,
-                }
+                };
+                TestResult::TrBench(bs)
+            }
+            Err(_) => {
+                TestResult::TrFailed
             }
         };
+
+        let stdout = data.lock().unwrap().to_vec();
+        monitor_ch.send((desc, test_result, stdout)).unwrap();
     }
 
     pub fn run_once<F>(f: F)
-        where F: FnMut(&mut Bencher)
+    where
+        F: FnMut(&mut Bencher),
     {
         let mut bs = Bencher {
             mode: BenchMode::Single,
@@ -1810,7 +1859,11 @@ fn f() {}
 
     #[test]
     fn parse_ignored_flag() {
-        let args = vec!["progname".to_string(), "filter".to_string(), "--ignored".to_string()];
+        let args = vec![
+            "progname".to_string(),
+            "filter".to_string(),
+            "--ignored".to_string(),
+        ];
         let opts = match parse_opts(&args) {
             Some(Ok(o)) => o,
             _ => panic!("Malformed arg in parse_ignored_flag"),
@@ -1827,7 +1880,8 @@ pub fn filter_for_ignored_option() {
         opts.run_tests = true;
         opts.run_ignored = true;
 
-        let tests = vec![TestDescAndFn {
+        let tests =
+            vec![TestDescAndFn {
                              desc: TestDesc {
                                  name: StaticTestName("1"),
                                  ignore: true,
@@ -1855,72 +1909,95 @@ pub fn filter_for_ignored_option() {
     #[test]
     pub fn exact_filter_match() {
         fn tests() -> Vec<TestDescAndFn> {
-            vec!["base",
-                 "base::test",
-                 "base::test1",
-                 "base::test2",
-            ].into_iter()
-            .map(|name| TestDescAndFn {
-                desc: TestDesc {
-                    name: StaticTestName(name),
-                    ignore: false,
-                    should_panic: ShouldPanic::No,
-                    allow_fail: false,
-                },
-                testfn: DynTestFn(Box::new(move || {}))
-            })
-            .collect()
+            vec!["base", "base::test", "base::test1", "base::test2"]
+                .into_iter()
+                .map(|name| {
+                    TestDescAndFn {
+                        desc: TestDesc {
+                            name: StaticTestName(name),
+                            ignore: false,
+                            should_panic: ShouldPanic::No,
+                            allow_fail: false,
+                        },
+                        testfn: DynTestFn(Box::new(move || {}))
+                    }
+                }).collect()
         }
 
-        let substr = filter_tests(&TestOpts {
+        let substr = filter_tests(
+            &TestOpts {
                 filter: Some("base".into()),
                 ..TestOpts::new()
-            }, tests());
+            },
+            tests(),
+        );
         assert_eq!(substr.len(), 4);
 
-        let substr = filter_tests(&TestOpts {
+        let substr = filter_tests(
+            &TestOpts {
                 filter: Some("bas".into()),
                 ..TestOpts::new()
-            }, tests());
+            },
+            tests(),
+        );
         assert_eq!(substr.len(), 4);
 
-        let substr = filter_tests(&TestOpts {
+        let substr = filter_tests(
+            &TestOpts {
                 filter: Some("::test".into()),
                 ..TestOpts::new()
-            }, tests());
+            },
+            tests(),
+        );
         assert_eq!(substr.len(), 3);
 
-        let substr = filter_tests(&TestOpts {
+        let substr = filter_tests(
+            &TestOpts {
                 filter: Some("base::test".into()),
                 ..TestOpts::new()
-            }, tests());
+            },
+            tests(),
+        );
         assert_eq!(substr.len(), 3);
 
-        let exact = filter_tests(&TestOpts {
+        let exact = filter_tests(
+            &TestOpts {
                 filter: Some("base".into()),
-                filter_exact: true, ..TestOpts::new()
-            }, tests());
+                filter_exact: true,
+                ..TestOpts::new()
+            },
+            tests(),
+        );
         assert_eq!(exact.len(), 1);
 
-        let exact = filter_tests(&TestOpts {
+        let exact = filter_tests(
+            &TestOpts {
                 filter: Some("bas".into()),
                 filter_exact: true,
                 ..TestOpts::new()
-            }, tests());
+            },
+            tests(),
+        );
         assert_eq!(exact.len(), 0);
 
-        let exact = filter_tests(&TestOpts {
+        let exact = filter_tests(
+            &TestOpts {
                 filter: Some("::test".into()),
                 filter_exact: true,
                 ..TestOpts::new()
-            }, tests());
+            },
+            tests(),
+        );
         assert_eq!(exact.len(), 0);
 
-        let exact = filter_tests(&TestOpts {
+        let exact = filter_tests(
+            &TestOpts {
                 filter: Some("base::test".into()),
                 filter_exact: true,
                 ..TestOpts::new()
-            }, tests());
+            },
+            tests(),
+        );
         assert_eq!(exact.len(), 1);
     }
 
@@ -1929,15 +2006,17 @@ pub fn sort_tests() {
         let mut opts = TestOpts::new();
         opts.run_tests = true;
 
-        let names = vec!["sha1::test".to_string(),
-                         "isize::test_to_str".to_string(),
-                         "isize::test_pow".to_string(),
-                         "test::do_not_run_ignored_tests".to_string(),
-                         "test::ignored_tests_result_in_ignored".to_string(),
-                         "test::first_free_arg_should_be_a_filter".to_string(),
-                         "test::parse_ignored_flag".to_string(),
-                         "test::filter_for_ignored_option".to_string(),
-                         "test::sort_tests".to_string()];
+        let names = vec![
+            "sha1::test".to_string(),
+            "isize::test_to_str".to_string(),
+            "isize::test_pow".to_string(),
+            "test::do_not_run_ignored_tests".to_string(),
+            "test::ignored_tests_result_in_ignored".to_string(),
+            "test::first_free_arg_should_be_a_filter".to_string(),
+            "test::parse_ignored_flag".to_string(),
+            "test::filter_for_ignored_option".to_string(),
+            "test::sort_tests".to_string(),
+        ];
         let tests = {
             fn testfn() {}
             let mut tests = Vec::new();
@@ -1957,15 +2036,17 @@ fn testfn() {}
         };
         let filtered = filter_tests(&opts, tests);
 
-        let expected = vec!["isize::test_pow".to_string(),
-                            "isize::test_to_str".to_string(),
-                            "sha1::test".to_string(),
-                            "test::do_not_run_ignored_tests".to_string(),
-                            "test::filter_for_ignored_option".to_string(),
-                            "test::first_free_arg_should_be_a_filter".to_string(),
-                            "test::ignored_tests_result_in_ignored".to_string(),
-                            "test::parse_ignored_flag".to_string(),
-                            "test::sort_tests".to_string()];
+        let expected = vec![
+            "isize::test_pow".to_string(),
+            "isize::test_to_str".to_string(),
+            "sha1::test".to_string(),
+            "test::do_not_run_ignored_tests".to_string(),
+            "test::filter_for_ignored_option".to_string(),
+            "test::first_free_arg_should_be_a_filter".to_string(),
+            "test::ignored_tests_result_in_ignored".to_string(),
+            "test::parse_ignored_flag".to_string(),
+            "test::sort_tests".to_string(),
+        ];
 
         for (a, b) in expected.iter().zip(filtered) {
             assert!(*a == b.desc.name.to_string());
@@ -2004,8 +2085,7 @@ fn f(_: &mut Bencher) {}
     #[test]
     pub fn test_bench_once_iter() {
         fn f(b: &mut Bencher) {
-            b.iter(|| {
-            })
+            b.iter(|| {})
         }
         bench::run_once(f);
     }
@@ -2013,15 +2093,42 @@ fn f(b: &mut Bencher) {
     #[test]
     pub fn test_bench_no_iter() {
         fn f(_: &mut Bencher) {}
-        bench::benchmark(f);
+
+        let (tx, rx) = channel();
+
+        let desc = TestDesc {
+            name: StaticTestName("f"),
+            ignore: false,
+            should_panic: ShouldPanic::No,
+            allow_fail: false,
+        };
+
+        ::bench::benchmark(desc,
+                            tx,
+                            true,
+                            f);
+        rx.recv().unwrap();
     }
 
     #[test]
     pub fn test_bench_iter() {
         fn f(b: &mut Bencher) {
-            b.iter(|| {
-            })
+            b.iter(|| {})
         }
-        bench::benchmark(f);
+
+        let (tx, rx) = channel();
+
+        let desc = TestDesc {
+            name: StaticTestName("f"),
+            ignore: false,
+            should_panic: ShouldPanic::No,
+            allow_fail: false,
+        };
+
+        ::bench::benchmark(desc,
+                            tx,
+                            true,
+                            f);
+        rx.recv().unwrap();
     }
 }
index 9f8b4a73d0cc0c6369a6cb7236d2e154d94cc270..e22fdf77fc171e4ad06596947dc1493c8bcae063 100644 (file)
@@ -400,16 +400,18 @@ fn test_norm2() {
     }
     #[test]
     fn test_norm10narrow() {
-        let val = &[966.0000000000,
-                    985.0000000000,
-                    1110.0000000000,
-                    848.0000000000,
-                    821.0000000000,
-                    975.0000000000,
-                    962.0000000000,
-                    1157.0000000000,
-                    1217.0000000000,
-                    955.0000000000];
+        let val = &[
+            966.0000000000,
+            985.0000000000,
+            1110.0000000000,
+            848.0000000000,
+            821.0000000000,
+            975.0000000000,
+            962.0000000000,
+            1157.0000000000,
+            1217.0000000000,
+            955.0000000000,
+        ];
         let summ = &Summary {
             sum: 9996.0000000000,
             min: 821.0000000000,
@@ -428,16 +430,18 @@ fn test_norm10narrow() {
     }
     #[test]
     fn test_norm10medium() {
-        let val = &[954.0000000000,
-                    1064.0000000000,
-                    855.0000000000,
-                    1000.0000000000,
-                    743.0000000000,
-                    1084.0000000000,
-                    704.0000000000,
-                    1023.0000000000,
-                    357.0000000000,
-                    869.0000000000];
+        let val = &[
+            954.0000000000,
+            1064.0000000000,
+            855.0000000000,
+            1000.0000000000,
+            743.0000000000,
+            1084.0000000000,
+            704.0000000000,
+            1023.0000000000,
+            357.0000000000,
+            869.0000000000,
+        ];
         let summ = &Summary {
             sum: 8653.0000000000,
             min: 357.0000000000,
@@ -456,16 +460,18 @@ fn test_norm10medium() {
     }
     #[test]
     fn test_norm10wide() {
-        let val = &[505.0000000000,
-                    497.0000000000,
-                    1591.0000000000,
-                    887.0000000000,
-                    1026.0000000000,
-                    136.0000000000,
-                    1580.0000000000,
-                    940.0000000000,
-                    754.0000000000,
-                    1433.0000000000];
+        let val = &[
+            505.0000000000,
+            497.0000000000,
+            1591.0000000000,
+            887.0000000000,
+            1026.0000000000,
+            136.0000000000,
+            1580.0000000000,
+            940.0000000000,
+            754.0000000000,
+            1433.0000000000,
+        ];
         let summ = &Summary {
             sum: 9349.0000000000,
             min: 136.0000000000,
@@ -484,31 +490,33 @@ fn test_norm10wide() {
     }
     #[test]
     fn test_norm25verynarrow() {
-        let val = &[991.0000000000,
-                    1018.0000000000,
-                    998.0000000000,
-                    1013.0000000000,
-                    974.0000000000,
-                    1007.0000000000,
-                    1014.0000000000,
-                    999.0000000000,
-                    1011.0000000000,
-                    978.0000000000,
-                    985.0000000000,
-                    999.0000000000,
-                    983.0000000000,
-                    982.0000000000,
-                    1015.0000000000,
-                    1002.0000000000,
-                    977.0000000000,
-                    948.0000000000,
-                    1040.0000000000,
-                    974.0000000000,
-                    996.0000000000,
-                    989.0000000000,
-                    1015.0000000000,
-                    994.0000000000,
-                    1024.0000000000];
+        let val = &[
+            991.0000000000,
+            1018.0000000000,
+            998.0000000000,
+            1013.0000000000,
+            974.0000000000,
+            1007.0000000000,
+            1014.0000000000,
+            999.0000000000,
+            1011.0000000000,
+            978.0000000000,
+            985.0000000000,
+            999.0000000000,
+            983.0000000000,
+            982.0000000000,
+            1015.0000000000,
+            1002.0000000000,
+            977.0000000000,
+            948.0000000000,
+            1040.0000000000,
+            974.0000000000,
+            996.0000000000,
+            989.0000000000,
+            1015.0000000000,
+            994.0000000000,
+            1024.0000000000,
+        ];
         let summ = &Summary {
             sum: 24926.0000000000,
             min: 948.0000000000,
@@ -527,16 +535,18 @@ fn test_norm25verynarrow() {
     }
     #[test]
     fn test_exp10a() {
-        let val = &[23.0000000000,
-                    11.0000000000,
-                    2.0000000000,
-                    57.0000000000,
-                    4.0000000000,
-                    12.0000000000,
-                    5.0000000000,
-                    29.0000000000,
-                    3.0000000000,
-                    21.0000000000];
+        let val = &[
+            23.0000000000,
+            11.0000000000,
+            2.0000000000,
+            57.0000000000,
+            4.0000000000,
+            12.0000000000,
+            5.0000000000,
+            29.0000000000,
+            3.0000000000,
+            21.0000000000,
+        ];
         let summ = &Summary {
             sum: 167.0000000000,
             min: 2.0000000000,
@@ -555,16 +565,18 @@ fn test_exp10a() {
     }
     #[test]
     fn test_exp10b() {
-        let val = &[24.0000000000,
-                    17.0000000000,
-                    6.0000000000,
-                    38.0000000000,
-                    25.0000000000,
-                    7.0000000000,
-                    51.0000000000,
-                    2.0000000000,
-                    61.0000000000,
-                    32.0000000000];
+        let val = &[
+            24.0000000000,
+            17.0000000000,
+            6.0000000000,
+            38.0000000000,
+            25.0000000000,
+            7.0000000000,
+            51.0000000000,
+            2.0000000000,
+            61.0000000000,
+            32.0000000000,
+        ];
         let summ = &Summary {
             sum: 263.0000000000,
             min: 2.0000000000,
@@ -583,16 +595,18 @@ fn test_exp10b() {
     }
     #[test]
     fn test_exp10c() {
-        let val = &[71.0000000000,
-                    2.0000000000,
-                    32.0000000000,
-                    1.0000000000,
-                    6.0000000000,
-                    28.0000000000,
-                    13.0000000000,
-                    37.0000000000,
-                    16.0000000000,
-                    36.0000000000];
+        let val = &[
+            71.0000000000,
+            2.0000000000,
+            32.0000000000,
+            1.0000000000,
+            6.0000000000,
+            28.0000000000,
+            13.0000000000,
+            37.0000000000,
+            16.0000000000,
+            36.0000000000,
+        ];
         let summ = &Summary {
             sum: 242.0000000000,
             min: 1.0000000000,
@@ -611,31 +625,33 @@ fn test_exp10c() {
     }
     #[test]
     fn test_exp25() {
-        let val = &[3.0000000000,
-                    24.0000000000,
-                    1.0000000000,
-                    19.0000000000,
-                    7.0000000000,
-                    5.0000000000,
-                    30.0000000000,
-                    39.0000000000,
-                    31.0000000000,
-                    13.0000000000,
-                    25.0000000000,
-                    48.0000000000,
-                    1.0000000000,
-                    6.0000000000,
-                    42.0000000000,
-                    63.0000000000,
-                    2.0000000000,
-                    12.0000000000,
-                    108.0000000000,
-                    26.0000000000,
-                    1.0000000000,
-                    7.0000000000,
-                    44.0000000000,
-                    25.0000000000,
-                    11.0000000000];
+        let val = &[
+            3.0000000000,
+            24.0000000000,
+            1.0000000000,
+            19.0000000000,
+            7.0000000000,
+            5.0000000000,
+            30.0000000000,
+            39.0000000000,
+            31.0000000000,
+            13.0000000000,
+            25.0000000000,
+            48.0000000000,
+            1.0000000000,
+            6.0000000000,
+            42.0000000000,
+            63.0000000000,
+            2.0000000000,
+            12.0000000000,
+            108.0000000000,
+            26.0000000000,
+            1.0000000000,
+            7.0000000000,
+            44.0000000000,
+            25.0000000000,
+            11.0000000000,
+        ];
         let summ = &Summary {
             sum: 593.0000000000,
             min: 1.0000000000,
@@ -654,31 +670,33 @@ fn test_exp25() {
     }
     #[test]
     fn test_binom25() {
-        let val = &[18.0000000000,
-                    17.0000000000,
-                    27.0000000000,
-                    15.0000000000,
-                    21.0000000000,
-                    25.0000000000,
-                    17.0000000000,
-                    24.0000000000,
-                    25.0000000000,
-                    24.0000000000,
-                    26.0000000000,
-                    26.0000000000,
-                    23.0000000000,
-                    15.0000000000,
-                    23.0000000000,
-                    17.0000000000,
-                    18.0000000000,
-                    18.0000000000,
-                    21.0000000000,
-                    16.0000000000,
-                    15.0000000000,
-                    31.0000000000,
-                    20.0000000000,
-                    17.0000000000,
-                    15.0000000000];
+        let val = &[
+            18.0000000000,
+            17.0000000000,
+            27.0000000000,
+            15.0000000000,
+            21.0000000000,
+            25.0000000000,
+            17.0000000000,
+            24.0000000000,
+            25.0000000000,
+            24.0000000000,
+            26.0000000000,
+            26.0000000000,
+            23.0000000000,
+            15.0000000000,
+            23.0000000000,
+            17.0000000000,
+            18.0000000000,
+            18.0000000000,
+            21.0000000000,
+            16.0000000000,
+            15.0000000000,
+            31.0000000000,
+            20.0000000000,
+            17.0000000000,
+            15.0000000000,
+        ];
         let summ = &Summary {
             sum: 514.0000000000,
             min: 15.0000000000,
@@ -697,31 +715,33 @@ fn test_binom25() {
     }
     #[test]
     fn test_pois25lambda30() {
-        let val = &[27.0000000000,
-                    33.0000000000,
-                    34.0000000000,
-                    34.0000000000,
-                    24.0000000000,
-                    39.0000000000,
-                    28.0000000000,
-                    27.0000000000,
-                    31.0000000000,
-                    28.0000000000,
-                    38.0000000000,
-                    21.0000000000,
-                    33.0000000000,
-                    36.0000000000,
-                    29.0000000000,
-                    37.0000000000,
-                    32.0000000000,
-                    34.0000000000,
-                    31.0000000000,
-                    39.0000000000,
-                    25.0000000000,
-                    31.0000000000,
-                    32.0000000000,
-                    40.0000000000,
-                    24.0000000000];
+        let val = &[
+            27.0000000000,
+            33.0000000000,
+            34.0000000000,
+            34.0000000000,
+            24.0000000000,
+            39.0000000000,
+            28.0000000000,
+            27.0000000000,
+            31.0000000000,
+            28.0000000000,
+            38.0000000000,
+            21.0000000000,
+            33.0000000000,
+            36.0000000000,
+            29.0000000000,
+            37.0000000000,
+            32.0000000000,
+            34.0000000000,
+            31.0000000000,
+            39.0000000000,
+            25.0000000000,
+            31.0000000000,
+            32.0000000000,
+            40.0000000000,
+            24.0000000000,
+        ];
         let summ = &Summary {
             sum: 787.0000000000,
             min: 21.0000000000,
@@ -740,31 +760,33 @@ fn test_pois25lambda30() {
     }
     #[test]
     fn test_pois25lambda40() {
-        let val = &[42.0000000000,
-                    50.0000000000,
-                    42.0000000000,
-                    46.0000000000,
-                    34.0000000000,
-                    45.0000000000,
-                    34.0000000000,
-                    49.0000000000,
-                    39.0000000000,
-                    28.0000000000,
-                    40.0000000000,
-                    35.0000000000,
-                    37.0000000000,
-                    39.0000000000,
-                    46.0000000000,
-                    44.0000000000,
-                    32.0000000000,
-                    45.0000000000,
-                    42.0000000000,
-                    37.0000000000,
-                    48.0000000000,
-                    42.0000000000,
-                    33.0000000000,
-                    42.0000000000,
-                    48.0000000000];
+        let val = &[
+            42.0000000000,
+            50.0000000000,
+            42.0000000000,
+            46.0000000000,
+            34.0000000000,
+            45.0000000000,
+            34.0000000000,
+            49.0000000000,
+            39.0000000000,
+            28.0000000000,
+            40.0000000000,
+            35.0000000000,
+            37.0000000000,
+            39.0000000000,
+            46.0000000000,
+            44.0000000000,
+            32.0000000000,
+            45.0000000000,
+            42.0000000000,
+            37.0000000000,
+            48.0000000000,
+            42.0000000000,
+            33.0000000000,
+            42.0000000000,
+            48.0000000000,
+        ];
         let summ = &Summary {
             sum: 1019.0000000000,
             min: 28.0000000000,
@@ -783,31 +805,33 @@ fn test_pois25lambda40() {
     }
     #[test]
     fn test_pois25lambda50() {
-        let val = &[45.0000000000,
-                    43.0000000000,
-                    44.0000000000,
-                    61.0000000000,
-                    51.0000000000,
-                    53.0000000000,
-                    59.0000000000,
-                    52.0000000000,
-                    49.0000000000,
-                    51.0000000000,
-                    51.0000000000,
-                    50.0000000000,
-                    49.0000000000,
-                    56.0000000000,
-                    42.0000000000,
-                    52.0000000000,
-                    51.0000000000,
-                    43.0000000000,
-                    48.0000000000,
-                    48.0000000000,
-                    50.0000000000,
-                    42.0000000000,
-                    43.0000000000,
-                    42.0000000000,
-                    60.0000000000];
+        let val = &[
+            45.0000000000,
+            43.0000000000,
+            44.0000000000,
+            61.0000000000,
+            51.0000000000,
+            53.0000000000,
+            59.0000000000,
+            52.0000000000,
+            49.0000000000,
+            51.0000000000,
+            51.0000000000,
+            50.0000000000,
+            49.0000000000,
+            56.0000000000,
+            42.0000000000,
+            52.0000000000,
+            51.0000000000,
+            43.0000000000,
+            48.0000000000,
+            48.0000000000,
+            50.0000000000,
+            42.0000000000,
+            43.0000000000,
+            42.0000000000,
+            60.0000000000,
+        ];
         let summ = &Summary {
             sum: 1235.0000000000,
             min: 42.0000000000,
@@ -826,31 +850,33 @@ fn test_pois25lambda50() {
     }
     #[test]
     fn test_unif25() {
-        let val = &[99.0000000000,
-                    55.0000000000,
-                    92.0000000000,
-                    79.0000000000,
-                    14.0000000000,
-                    2.0000000000,
-                    33.0000000000,
-                    49.0000000000,
-                    3.0000000000,
-                    32.0000000000,
-                    84.0000000000,
-                    59.0000000000,
-                    22.0000000000,
-                    86.0000000000,
-                    76.0000000000,
-                    31.0000000000,
-                    29.0000000000,
-                    11.0000000000,
-                    41.0000000000,
-                    53.0000000000,
-                    45.0000000000,
-                    44.0000000000,
-                    98.0000000000,
-                    98.0000000000,
-                    7.0000000000];
+        let val = &[
+            99.0000000000,
+            55.0000000000,
+            92.0000000000,
+            79.0000000000,
+            14.0000000000,
+            2.0000000000,
+            33.0000000000,
+            49.0000000000,
+            3.0000000000,
+            32.0000000000,
+            84.0000000000,
+            59.0000000000,
+            22.0000000000,
+            86.0000000000,
+            76.0000000000,
+            31.0000000000,
+            29.0000000000,
+            11.0000000000,
+            41.0000000000,
+            53.0000000000,
+            45.0000000000,
+            44.0000000000,
+            98.0000000000,
+            98.0000000000,
+            7.0000000000,
+        ];
         let summ = &Summary {
             sum: 1242.0000000000,
             min: 2.0000000000,
@@ -885,18 +911,14 @@ mod bench {
 
     #[bench]
     pub fn sum_three_items(b: &mut Bencher) {
-        b.iter(|| {
-            [1e20f64, 1.5f64, -1e20f64].sum();
-        })
+        b.iter(|| { [1e20f64, 1.5f64, -1e20f64].sum(); })
     }
     #[bench]
     pub fn sum_many_f64(b: &mut Bencher) {
         let nums = [-1e30f64, 1e60, 1e30, 1.0, -1e60];
         let v = (0..500).map(|i| nums[i % 5]).collect::<Vec<_>>();
 
-        b.iter(|| {
-            v.sum();
-        })
+        b.iter(|| { v.sum(); })
     }
 
     #[bench]
index afd1e5e1c5ecf7da08e7cdac21bf80aa8e54339e..11c4c2faf134278e0650a1163b3b54c28c6bfad5 100644 (file)
@@ -15,7 +15,7 @@ fn main() {
     let target = env::var("TARGET").expect("TARGET was not set");
 
     if target.contains("linux") {
-        if target.contains("musl") && !target.contains("mips") {
+        if target.contains("musl") {
             // musl is handled in lib.rs
         } else if !target.contains("android") {
             println!("cargo:rustc-link-lib=gcc_s");
index 5bb1eb96dcfad2504e19189426cca773eef03dfe..5347c781218ce4b947f10a3d2e11529a686abf04 100644 (file)
@@ -35,7 +35,7 @@
     }
 }
 
-#[cfg(all(target_env = "musl", not(target_arch = "mips")))]
+#[cfg(target_env = "musl")]
 #[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
 #[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
 extern {}
index e22f6702672986091766db4b5f7aadd6ddce784e..e6fff7963f79c31e24a0357f66ad078f38f9f868 100644 (file)
@@ -93,8 +93,7 @@ pub enum _Unwind_Context {}
 }
 
 cfg_if! {
-if #[cfg(not(any(all(target_os = "android", target_arch = "arm"),
-                 all(target_os = "linux", target_arch = "arm"))))] {
+if #[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))] {
     // Not ARM EHABI
     #[repr(C)]
     #[derive(Copy, Clone, PartialEq)]
diff --git a/src/llvm-emscripten b/src/llvm-emscripten
new file mode 160000 (submodule)
index 0000000..2717444
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 2717444753318e461e0c3b30dacd03ffbac96903
index d185c061d5bd9fb6656b7240de820824447d2137..bbc4c2ee43e079dd9cb0f2900aaf68e586c6d5bd 100644 (file)
@@ -7,12 +7,9 @@ version = "0.0.0"
 name = "rustc"
 path = "rustc.rs"
 
-# All optional dependencies so the features passed to this Cargo.toml select
-# what should actually be built.
 [dependencies]
 rustc_back = { path = "../librustc_back" }
 rustc_driver = { path = "../librustc_driver" }
 
 [features]
 jemalloc = ["rustc_back/jemalloc"]
-llvm = ["rustc_driver/llvm"]
index b2f1229891d261dd4758130671f1a87ec46f0de3..06d1301d70003bafb0da71f268a04999a655d220 100644 (file)
@@ -836,6 +836,10 @@ struct LLVMRustThinLTOData {
   StringMap<FunctionImporter::ImportMapTy> ImportLists;
   StringMap<FunctionImporter::ExportSetTy> ExportLists;
   StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries;
+
+#if LLVM_VERSION_GE(7, 0)
+  LLVMRustThinLTOData() : Index(/* isPerformingAnalysis = */ false) {}
+#endif
 };
 
 // Just an argument to the `LLVMRustCreateThinLTOData` function below.
@@ -918,7 +922,14 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
   //
   // This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp`
 #if LLVM_VERSION_GE(5, 0)
+#if LLVM_VERSION_GE(7, 0)
+  auto deadIsPrevailing = [&](GlobalValue::GUID G) {
+    return PrevailingType::Unknown;
+  };
+  computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols, deadIsPrevailing);
+#else
   computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols);
+#endif
   ComputeCrossModuleImport(
     Ret->Index,
     Ret->ModuleToDefinedGVSummaries,
index f8945a6ee8d93aeb0eba51b16923d601f02b0f59..0e98d3f9050a8194573bdf8a23ef43955bc97869 100644 (file)
@@ -122,13 +122,13 @@ pub fn unsafe_slice(_: &[UnsafeInner]) {
 pub fn str(_: &[u8]) {
 }
 
-// CHECK: @trait_borrow(%"core::ops::drop::Drop"* nonnull %arg0.0, {}* noalias nonnull readonly %arg0.1)
+// CHECK: @trait_borrow({}* nonnull %arg0.0, {}* noalias nonnull readonly %arg0.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn trait_borrow(_: &Drop) {
 }
 
-// CHECK: @trait_box(%"core::ops::drop::Drop"* noalias nonnull, {}* noalias nonnull readonly)
+// CHECK: @trait_box({}* noalias nonnull, {}* noalias nonnull readonly)
 #[no_mangle]
 pub fn trait_box(_: Box<Drop>) {
 }
index 52bb4a1b463b4b7f75709c567bdb0481aef7d439..630a234fa66410e2cf886b0bc15244759c1a99e4 100644 (file)
@@ -16,6 +16,7 @@ pub trait Foo {
 }
 
 struct Abc;
+
 impl Foo for Abc {
     const X: EFoo = EFoo::B;
 }
@@ -27,8 +28,10 @@ impl Foo for Def {
 
 pub fn test<A: Foo, B: Foo>(arg: EFoo) {
     match arg {
-        A::X => println!("A::X"), //~ error: statics cannot be referenced in patterns [E0158]
-        B::X => println!("B::X"), //~ error: statics cannot be referenced in patterns [E0158]
+        A::X => println!("A::X"),
+        //~^ error: associated consts cannot be referenced in patterns [E0158]
+        B::X => println!("B::X"),
+        //~^ error: associated consts cannot be referenced in patterns [E0158]
         _ => (),
     }
 }
index b7c544c78483aa7b6cd245d1251a7f63a948c9d6..5eb0e4360fc93beeb208a294674ca837dded48d3 100644 (file)
@@ -10,7 +10,7 @@
 
 fn changer<'a>(mut things: Box<Iterator<Item=&'a mut u8>>) {
     for item in *things { *item = 0 }
-//~^ ERROR `std::iter::Iterator<Item=&mut u8>: std::marker::Sized` is not satisfied
+//~^ ERROR the trait bound `std::iter::Iterator<Item=&mut u8>: std::marker::Sized` is not satisfied
 }
 
 fn main() {}
index 167c8630707528d1ca5c5d0dbe922a3a615648e8..bb02d6d8bba8a2f7ee3ce51d731cbecac0da8811 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// check that we link regions in mutable lvalue ops correctly - issue #41774
+// check that we link regions in mutable place ops correctly - issue #41774
 
 struct Data(i32);
 
index 85f6ef60c5dc0c5d1a891b6dcf53b7e8d193d412..466690e7ca12bea49d1cfcd979e0469eeffa0fd4 100644 (file)
@@ -404,9 +404,9 @@ pub fn value_cast(a: u32) -> i32 {
 
 
 
-// Change l-value in assignment ------------------------------------------------
+// Change place in assignment --------------------------------------------------
 #[cfg(cfail1)]
-pub fn lvalue() -> i32 {
+pub fn place() -> i32 {
     let mut x = 10;
     let mut y = 11;
     x = 9;
@@ -416,7 +416,7 @@ pub fn lvalue() -> i32 {
 #[cfg(not(cfail1))]
 #[rustc_clean(except="HirBody,MirOptimized,MirValidated", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-pub fn lvalue() -> i32 {
+pub fn place() -> i32 {
     let mut x = 10;
     let mut y = 11;
     y = 9;
index 1da6735918012f11be58ef6b620cbaec9b8ca17e..4c77edec56f136e647f93086f350d1d7ed7d1398 100644 (file)
@@ -13,5 +13,5 @@
 
 fn main() {
     let x = || -> i32 22;
-    //~^ ERROR expected one of `!`, `(`, `::`, `<`, or `{`, found `22`
+    //~^ ERROR expected one of `!`, `(`, `+`, `::`, `<`, or `{`, found `22`
 }
index 56b91699478ef92277ccfce9601d1b6a706f30c9..6fd4ee38a4d7a6e8ca3fc980f037c886a4d53ae5 100644 (file)
@@ -15,6 +15,6 @@
 // compile-flags: -Z parse-only
 
 fn foo() -> Vec<usize>> {
-    //~^ ERROR expected one of `!`, `::`, `where`, or `{`, found `>`
+    //~^ ERROR expected one of `!`, `+`, `::`, `where`, or `{`, found `>`
     Vec::new()
 }
index 0de404ed249d5eec54acb15d7ef2ab178180bbba..5972149590c23cfaf25903f161d3d0aab84bcb6e 100644 (file)
@@ -77,6 +77,6 @@ fn join_trans_and_link(
 
 /// This is the entrypoint for a hot plugged rustc_trans
 #[no_mangle]
-pub fn __rustc_codegen_backend(sess: &Session) -> Box<TransCrate> {
-    Box::new(TheBackend(MetadataOnlyTransCrate::new(sess)))
+pub fn __rustc_codegen_backend() -> Box<TransCrate> {
+    Box::new(TheBackend(MetadataOnlyTransCrate::new()))
 }
index c360dde618ef54f2f2a7167c0081f4643a505716..b4b29e15ce174c4c08a14c07459d3d833df34c03 100644 (file)
@@ -15,7 +15,6 @@
 extern crate rustc_lint;
 extern crate rustc_metadata;
 extern crate rustc_errors;
-extern crate rustc_trans;
 extern crate rustc_trans_utils;
 extern crate syntax;
 
@@ -63,7 +62,7 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc<CStore>, Box<TransCrate>) {
 
     let descriptions = Registry::new(&rustc::DIAGNOSTICS);
     let sess = build_session(opts, None, descriptions);
-    let trans = rustc_trans::LlvmTransCrate::new(&sess);
+    let trans = rustc_driver::get_trans(&sess);
     let cstore = Rc::new(CStore::new(trans.metadata_loader()));
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
     (sess, cstore, trans)
diff --git a/src/test/run-make/libtest-json/Makefile b/src/test/run-make/libtest-json/Makefile
new file mode 100644 (file)
index 0000000..ec91ddf
--- /dev/null
@@ -0,0 +1,14 @@
+-include ../tools.mk
+
+# Test expected libtest's JSON output
+
+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
+
+       cat $(OUTPUT_FILE) | "$(PYTHON)" validate_json.py
+
+       # Compare to output file
+       diff output.json $(OUTPUT_FILE)
diff --git a/src/test/run-make/libtest-json/f.rs b/src/test/run-make/libtest-json/f.rs
new file mode 100644 (file)
index 0000000..5cff1f1
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[test]
+fn a() {
+    // Should pass
+}
+
+#[test]
+fn b() {
+    assert!(false)
+}
+
+#[test]
+#[should_panic]
+fn c() {
+    assert!(false);
+}
+
+#[test]
+#[ignore]
+fn d() {
+    assert!(false);
+}
+
diff --git a/src/test/run-make/libtest-json/output.json b/src/test/run-make/libtest-json/output.json
new file mode 100644 (file)
index 0000000..235f8cd
--- /dev/null
@@ -0,0 +1,10 @@
+{ "type": "suite", "event": "started", "test_count": "4" }
+{ "type": "test", "event": "started", "name": "a" }
+{ "type": "test", "name": "a", "event": "ok" }
+{ "type": "test", "event": "started", "name": "b" }
+{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'b' panicked at 'assertion failed: false', f.rs:18:5\nnote: Run with `RUST_BACKTRACE=1` for a backtrace.\n" }
+{ "type": "test", "event": "started", "name": "c" }
+{ "type": "test", "name": "c", "event": "ok" }
+{ "type": "test", "event": "started", "name": "d" }
+{ "type": "test", "name": "d", "event": "ignored" }
+{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "allowed_fail": 0, "ignored": 1, "measured": 0, "filtered_out": "0" }
diff --git a/src/test/run-make/libtest-json/validate_json.py b/src/test/run-make/libtest-json/validate_json.py
new file mode 100755 (executable)
index 0000000..1e97639
--- /dev/null
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+
+# Copyright 2016 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.
+
+import sys
+import json
+
+# Try to decode line in order to ensure it is a valid JSON document
+for line in sys.stdin:
+    json.loads(line)
index 0d31d2c823500ab64d6d9412b77de4300d71db1d..8a18aadf36a8bb635684927b165c09f869f0c862 100644 (file)
@@ -1,5 +1,9 @@
 -include ../tools.mk
 
+ifeq ($(UNAME),Darwin)
+PLUGIN_FLAGS := -C link-args=-Wl,-undefined,dynamic_lookup
+endif
+
 ifeq ($(findstring stage1,$(RUST_BUILD_STAGE)),stage1)
 # ignore stage1
 all:
@@ -11,7 +15,7 @@ ifdef IS_WINDOWS
 all:
 else
 all: $(call NATIVE_STATICLIB,llvm-function-pass) $(call NATIVE_STATICLIB,llvm-module-pass)
-       $(RUSTC) plugin.rs -C prefer-dynamic
+       $(RUSTC) plugin.rs -C prefer-dynamic $(PLUGIN_FLAGS)
        $(RUSTC) main.rs
 
 $(TMPDIR)/libllvm-function-pass.o:
index 37aab2bbd059aa61579de5e914b41bdb71381abc..f77b2fca857a613e3759bb50b4fec40995186fc6 100644 (file)
@@ -14,7 +14,6 @@
 
 extern crate rustc;
 extern crate rustc_plugin;
-extern crate rustc_trans;
 
 #[link(name = "llvm-function-pass", kind = "static")]
 #[link(name = "llvm-module-pass", kind = "static")]
diff --git a/src/test/run-make/stdin-non-utf8/Makefile b/src/test/run-make/stdin-non-utf8/Makefile
new file mode 100644 (file)
index 0000000..7948c44
--- /dev/null
@@ -0,0 +1,6 @@
+-include ../tools.mk
+
+all:
+       cp non-utf8 $(TMPDIR)/non-utf.rs
+       cat $(TMPDIR)/non-utf.rs | $(RUSTC) - 2>&1 \
+               | $(CGREP) "error: couldn't read from stdin, as it did not contain valid UTF-8"
diff --git a/src/test/run-make/stdin-non-utf8/non-utf8 b/src/test/run-make/stdin-non-utf8/non-utf8
new file mode 100644 (file)
index 0000000..bc87051
--- /dev/null
@@ -0,0 +1 @@
+Ã’
index ba42cb870c97edf124f38b8192c76314cfb0074f..a35eed1f72d7913814a43ef64c2c8b62cf48802a 100644 (file)
@@ -8,18 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-cross-compile
-
-#![feature(rustc_private)]
-
-extern crate tempdir;
-
 use std::env;
 use std::fs;
-use tempdir::TempDir;
+use std::path::PathBuf;
 
 fn main() {
-    let td = TempDir::new("create-dir-all-bare").unwrap();
-    env::set_current_dir(td.path()).unwrap();
+    let path = PathBuf::from(env::var_os("RUST_TEST_TMPDIR").unwrap());
+    env::set_current_dir(&path).unwrap();
     fs::create_dir_all("create-dir-all-bare").unwrap();
 }
index 121fd4a9825df0d3770b66ed3db7a1da5a468bf8..15ac1d55cc8c41a2164112f0f917eac8dff55bda 100644 (file)
 // no-prefer-dynamic
 // ignore-cross-compile
 
-#![feature(rustc_private)]
-
-extern crate tempdir;
-
 use std::env;
 use std::fs;
 use std::process;
 use std::str;
-use tempdir::TempDir;
+use std::path::PathBuf;
 
 fn main() {
     // If we're the child, make sure we were invoked correctly
@@ -41,8 +37,9 @@ fn test() {
     let my_path = env::current_exe().unwrap();
     let my_dir  = my_path.parent().unwrap();
 
-    let child_dir = TempDir::new_in(&my_dir, "issue-15140-child").unwrap();
-    let child_dir = child_dir.path();
+    let child_dir = PathBuf::from(env::var_os("RUST_TEST_TMPDIR").unwrap());
+    let child_dir = child_dir.join("issue-15140-child");
+    fs::create_dir_all(&child_dir).unwrap();
 
     let child_path = child_dir.join(&format!("mytest{}",
                                              env::consts::EXE_SUFFIX));
@@ -63,11 +60,4 @@ fn test() {
             format!("child assertion failed\n child stdout:\n {}\n child stderr:\n {}",
                     str::from_utf8(&child_output.stdout).unwrap(),
                     str::from_utf8(&child_output.stderr).unwrap()));
-
-    let res = fs::remove_dir_all(&child_dir);
-    if res.is_err() {
-        // On Windows deleting just executed mytest.exe can fail because it's still locked
-        std::thread::sleep_ms(1000);
-        fs::remove_dir_all(&child_dir).unwrap();
-    }
 }
index 7a2a4343522bb05e4ce8b062c246a3441f527793..417707e89322c27611f685ec7a724d73c87a7a3c 100644 (file)
 
 // ignore-cross-compile
 
-#![feature(rustc_private)]
-
-extern crate tempdir;
-
+use std::env;
 use std::ffi::CString;
 use std::fs::{self, File};
-use tempdir::TempDir;
+use std::path::PathBuf;
 
 fn rename_directory() {
-    let tmpdir = TempDir::new("rename_directory").ok().expect("rename_directory failed");
-    let tmpdir = tmpdir.path();
+    let tmpdir = PathBuf::from(env::var_os("RUST_TEST_TMPDIR").unwrap());
     let old_path = tmpdir.join("foo/bar/baz");
     fs::create_dir_all(&old_path).unwrap();
     let test_file = &old_path.join("temp.txt");
index 535ab711f5bcf62ee8803cd4c229a5809ec6775d..5b28ce0f0c68da7ae13d20e28387493e5201f3d4 100644 (file)
 
 // ignore-cross-compile
 
-#![feature(rustc_private)]
-
-extern crate tempdir;
-
 use std::env;
 use std::fs::File;
 use std::io;
 use std::io::{Read, Write};
 use std::process::{Command, Stdio};
-
-use tempdir::TempDir;
+use std::path::PathBuf;
 
 fn main() {
     if env::args().len() > 1 {
@@ -31,9 +26,9 @@ fn main() {
 }
 
 fn parent() -> io::Result<()> {
-    let td = TempDir::new("foo").unwrap();
-    let input = td.path().join("input");
-    let output = td.path().join("output");
+    let td = PathBuf::from(env::var_os("RUST_TEST_TMPDIR").unwrap());
+    let input = td.join("stdio-from-input");
+    let output = td.join("stdio-from-output");
 
     File::create(&input)?.write_all(b"foo\n")?;
 
index 16f7e2832853663452934ebbd86f0be7dc52783c..316b97f17ef94eeb44f0bcecfa24ddbec6ac6f05 100644 (file)
@@ -8,14 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_private)]
-
-extern crate tempdir;
-
+use std::env;
 use std::fs::File;
 use std::io::{Read, Write};
-
-use tempdir::TempDir;
+use std::path::PathBuf;
 
 #[cfg(unix)]
 fn switch_stdout_to(file: File) {
@@ -48,8 +44,8 @@ fn switch_stdout_to(file: File) {
 }
 
 fn main() {
-    let td = TempDir::new("foo").unwrap();
-    let path = td.path().join("bar");
+    let path = PathBuf::from(env::var_os("RUST_TEST_TMPDIR").unwrap());
+    let path = path.join("switch-stdout-output");
     let f = File::create(&path).unwrap();
 
     println!("foo");
index 22e440c6ffa51e08df652819779fada80ef54e96..9bbff1eeb81f3870004c02c6fe90cfce2577661b 100644 (file)
@@ -27,7 +27,10 @@ fn main() {
     if cfg!(target_os = "android") {
         assert!(home_dir().is_none());
     } else {
-        assert!(home_dir().is_some());
+        // When HOME is not set, some platforms return `None`,
+        // but others return `Some` with a default.
+        // Just check that it is not "/home/MountainView".
+        assert_ne!(home_dir(), Some(PathBuf::from("/home/MountainView")));
     }
 }
 
index 88bf95f036b86275729e3d4d246792d7b72d3851..2a1e55d867f72a67edf933231274d10fba38308d 100644 (file)
@@ -10,7 +10,7 @@
 
 // Test that we don't ICE when translating a generic impl method from
 // an extern crate that contains a match expression on a local
-// variable lvalue where one of the match case bodies contains an
+// variable place where one of the match case bodies contains an
 // expression that autoderefs through an overloaded generic deref
 // impl.
 
index 3d8e0556a560e1851ee8885e8734685ed385249a..241408ddef13596d68a6969571a9ccb430f05995 100644 (file)
@@ -11,7 +11,7 @@
 // This used to generate invalid IR in that even if we took the
 // `false` branch we'd still try to free the Box from the other
 // arm. This was due to treating `*Box::new(9)` as an rvalue datum
-// instead of as an lvalue.
+// instead of as a place.
 
 fn test(foo: bool) -> u8 {
     match foo {
diff --git a/src/test/run-pass/issue-47139-1.rs b/src/test/run-pass/issue-47139-1.rs
new file mode 100644 (file)
index 0000000..cb87991
--- /dev/null
@@ -0,0 +1,87 @@
+// Copyright 2016 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.
+
+// Regression test for issue #47139:
+//
+// Coherence was encountering an (unnecessary) overflow trying to
+// decide if the two impls of dummy overlap.
+//
+// The overflow went something like:
+//
+// - `&'a ?T: Insertable` ?
+// - let ?T = Option<?U> ?
+// - `Option<?U>: Insertable` ?
+// - `Option<&'a ?U>: Insertable` ?
+// - `&'a ?U: Insertable` ?
+//
+// While somewhere in the middle, a projection would occur, which
+// broke cycle detection.
+//
+// It turned out that this cycle was being kicked off due to some
+// extended diagnostic attempts in coherence, so removing those
+// sidestepped the issue for now.
+
+#![allow(dead_code)]
+
+pub trait Insertable {
+    type Values;
+
+    fn values(self) -> Self::Values;
+}
+
+impl<T> Insertable for Option<T>
+    where
+    T: Insertable,
+    T::Values: Default,
+{
+    type Values = T::Values;
+
+    fn values(self) -> Self::Values {
+        self.map(Insertable::values).unwrap_or_default()
+    }
+}
+
+impl<'a, T> Insertable for &'a Option<T>
+    where
+    Option<&'a T>: Insertable,
+{
+    type Values = <Option<&'a T> as Insertable>::Values;
+
+    fn values(self) -> Self::Values {
+        self.as_ref().values()
+    }
+}
+
+impl<'a, T> Insertable for &'a [T]
+{
+    type Values = Self;
+
+    fn values(self) -> Self::Values {
+        self
+    }
+}
+
+trait Unimplemented { }
+
+trait Dummy { }
+
+struct Foo<T> { t: T }
+
+impl<'a, U> Dummy for Foo<&'a U>
+    where &'a U: Insertable
+{
+}
+
+impl<T> Dummy for T
+    where T: Unimplemented
+{ }
+
+fn main() {
+}
diff --git a/src/test/run-pass/issue-47139-2.rs b/src/test/run-pass/issue-47139-2.rs
new file mode 100644 (file)
index 0000000..08eaee5
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright 2016 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.
+
+// Regression test for issue #47139:
+//
+// Same as issue-47139-1.rs, but the impls of dummy are in the
+// opposite order. This influenced the way that coherence ran and in
+// some cases caused the overflow to occur when it wouldn't otherwise.
+// In an effort to make the regr test more robust, I am including both
+// orderings.
+
+#![allow(dead_code)]
+
+pub trait Insertable {
+    type Values;
+
+    fn values(self) -> Self::Values;
+}
+
+impl<T> Insertable for Option<T>
+    where
+    T: Insertable,
+    T::Values: Default,
+{
+    type Values = T::Values;
+
+    fn values(self) -> Self::Values {
+        self.map(Insertable::values).unwrap_or_default()
+    }
+}
+
+impl<'a, T> Insertable for &'a Option<T>
+    where
+    Option<&'a T>: Insertable,
+{
+    type Values = <Option<&'a T> as Insertable>::Values;
+
+    fn values(self) -> Self::Values {
+        self.as_ref().values()
+    }
+}
+
+impl<'a, T> Insertable for &'a [T]
+{
+    type Values = Self;
+
+    fn values(self) -> Self::Values {
+        self
+    }
+}
+
+trait Unimplemented { }
+
+trait Dummy { }
+
+struct Foo<T> { t: T }
+
+impl<T> Dummy for T
+    where T: Unimplemented
+{ }
+
+impl<'a, U> Dummy for Foo<&'a U>
+    where &'a U: Insertable
+{
+}
+
+fn main() {
+}
diff --git a/src/test/run-pass/issue-47638.rs b/src/test/run-pass/issue-47638.rs
new file mode 100644 (file)
index 0000000..6f627b2
--- /dev/null
@@ -0,0 +1,18 @@
+// 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 id<'c, 'b>(f: &'c &'b Fn(&i32)) -> &'c &'b Fn(&'static i32) {
+    f
+}
+
+fn main() {
+    let f: &Fn(&i32) = &|x| {};
+    id(&f);
+}
index c729f736115a9a2a81bcabc412ba817cd1c2233b..4de8f6a7194159dafd8c68d0a0308cd69982a3dc 100644 (file)
@@ -8,8 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Test that an `&mut self` method, when invoked on an lvalue whose
-// type is `&mut [u8]`, passes in a pointer to the lvalue and not a
+// Test that an `&mut self` method, when invoked on a place whose
+// type is `&mut [u8]`, passes in a pointer to the place and not a
 // temporary. Issue #19147.
 
 use std::slice;
index 41cb458c0b8b486c3a7ac664ca70538075d643d2..7ab133bbab4e1b44fd1820e2fb3e6cdccc3d6b09 100644 (file)
@@ -41,7 +41,7 @@ fn main() {
         // all borrows are extended - nothing has been dropped yet
         assert_eq!(get(), vec![]);
     }
-    // in a let-statement, extended lvalues are dropped
+    // in a let-statement, extended places are dropped
     // *after* the let result (tho they have the same scope
     // as far as scope-based borrowck goes).
     assert_eq!(get(), vec![0, 2, 3, 1]);
diff --git a/src/test/run-pass/never-type-rvalues.rs b/src/test/run-pass/never-type-rvalues.rs
new file mode 100644 (file)
index 0000000..bda288f
--- /dev/null
@@ -0,0 +1,46 @@
+// 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.
+
+#![feature(never_type)]
+#![allow(dead_code)]
+#![allow(path_statements)]
+#![allow(unreachable_patterns)]
+
+fn never_direct(x: !) {
+    x;
+}
+
+fn never_ref_pat(ref x: !) {
+    *x;
+}
+
+fn never_ref(x: &!) {
+    let &y = x;
+    y;
+}
+
+fn never_pointer(x: *const !) {
+    unsafe {
+        *x;
+    }
+}
+
+fn never_slice(x: &[!]) {
+    x[0];
+}
+
+fn never_match(x: Result<(), !>) {
+    match x {
+        Ok(_) => {},
+        Err(_) => {},
+    }
+}
+
+pub fn main() { }
index c2414e5ff5d96c98cebb88c54fef144dfa36bcda..22469b2fde058180210fd9e58efd4c6b87809b6b 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// min-llvm-version 4.0
+// no-system-llvm -- needs MCSubtargetInfo::getFeatureTable()
 // ignore-cloudabi no std::env
 
 #![feature(cfg_target_feature)]
index bca384c64712f299dbed42df9e04ee766748fec0..18fb8e2e408f196f5d599b2954a170a251dbd1d9 100644 (file)
@@ -40,6 +40,6 @@ fn main() {
     assert_eq!(b, 1: u16);
 
     let mut v = Vec::new();
-    v: Vec<u8> = vec![1, 2, 3]; // Lvalue type ascription
+    v: Vec<u8> = vec![1, 2, 3]; // Place expression type ascription
     assert_eq!(v, [1u8, 2, 3]);
 }
diff --git a/src/test/run-pass/union/union-const-eval-field.rs b/src/test/run-pass/union/union-const-eval-field.rs
new file mode 100644 (file)
index 0000000..f83f49f
--- /dev/null
@@ -0,0 +1,45 @@
+// 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.
+
+#![feature(const_fn)]
+
+type Field1 = i32;
+type Field2 = f32;
+type Field3 = i64;
+
+union DummyUnion {
+    field1: Field1,
+    field2: Field2,
+    field3: Field3,
+}
+
+const FLOAT1_AS_I32: i32 = 1065353216;
+const UNION: DummyUnion = DummyUnion { field1: FLOAT1_AS_I32 };
+
+const fn read_field1() -> Field1 {
+    const FIELD1: Field1 = unsafe { UNION.field1 };
+    FIELD1
+}
+
+const fn read_field2() -> Field2 {
+    const FIELD2: Field2 = unsafe { UNION.field2 };
+    FIELD2
+}
+
+const fn read_field3() -> Field3 {
+    const FIELD3: Field3 = unsafe { UNION.field3 };
+    FIELD3
+}
+
+fn main() {
+    assert_eq!(read_field1(), FLOAT1_AS_I32);
+    assert_eq!(read_field2(), 1.0);
+    assert_eq!(read_field3(), unsafe { UNION.field3 });
+}
index 74a82afd462b869f1f793429ba3226957fdbdd10..a28f8da9ff882f31167faa7d0aebbcc4f6e9da60 100644 (file)
@@ -24,12 +24,19 @@ pub enum I {}
     }
 }
 
+// Test every possible part of the syntax
 use a::{B, d::{self, *, g::H}};
 
+// Test a more common use case
+use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
+
 fn main() {
     let _: B;
     let _: E;
     let _: F;
     let _: H;
     let _: d::g::I;
+
+    let _: Arc<AtomicBool>;
+    let _: Ordering;
 }
diff --git a/src/test/rustdoc/link-title-escape.rs b/src/test/rustdoc/link-title-escape.rs
new file mode 100644 (file)
index 0000000..eb53c3c
--- /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-flags: -Z unstable-options --disable-commonmark
+
+#![crate_name = "foo"]
+
+//! hello [foo]
+//!
+//! [foo]: url 'title & <stuff> & "things"'
+
+// @has 'foo/index.html' 'title &amp; &lt;stuff&gt; &amp; &quot;things&quot;'
index 855b3799eb5db106dc305b2d74a821a9cb091c3d..d3588be26697583a60f8ebc43170c2eeeb1d32fa 100644 (file)
@@ -10,8 +10,8 @@ error[E0255]: the name `foo` is defined multiple times
    = note: `foo` must be defined only once in the type namespace of this module
 help: You can use `as` to change the binding name of the import
    |
-13 | use foo::foo as Otherfoo;
-   |     ^^^^^^^^^^^^^^^^^^^^
+13 | use foo::foo as other_foo;
+   |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index 0e275e78fc68c83cd9dcc8f3a60d0c597f88949d..4f4f8b5ad00930d0e229d4f0af61b3cf68f46ba6 100644 (file)
@@ -13,22 +13,16 @@ error[E0016]: blocks in constant functions are limited to items and tail express
    |                   ^
 
 error[E0015]: calls in constant functions are limited to constant functions, struct and enum constructors
-  --> $DIR/const-fn-error.rs:17:5
+  --> $DIR/const-fn-error.rs:17:14
    |
-17 | /     for i in 0..x { //~ ERROR calls in constant functions
-18 | |     //~| ERROR constant function contains unimplemented
-19 | |         sum += i;
-20 | |     }
-   | |_____^
+17 |     for i in 0..x { //~ ERROR calls in constant functions
+   |              ^^^^
 
 error[E0019]: constant function contains unimplemented expression type
-  --> $DIR/const-fn-error.rs:17:5
+  --> $DIR/const-fn-error.rs:17:14
    |
-17 | /     for i in 0..x { //~ ERROR calls in constant functions
-18 | |     //~| ERROR constant function contains unimplemented
-19 | |         sum += i;
-20 | |     }
-   | |_____^
+17 |     for i in 0..x { //~ ERROR calls in constant functions
+   |              ^^^^
 
 error[E0080]: constant evaluation error
   --> $DIR/const-fn-error.rs:21:5
diff --git a/src/test/ui/cross-file-errors/main.rs b/src/test/ui/cross-file-errors/main.rs
new file mode 100644 (file)
index 0000000..8eae79a
--- /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.
+
+#[macro_use]
+mod underscore;
+
+fn main() {
+    underscore!();
+}
diff --git a/src/test/ui/cross-file-errors/main.stderr b/src/test/ui/cross-file-errors/main.stderr
new file mode 100644 (file)
index 0000000..a1cdae1
--- /dev/null
@@ -0,0 +1,11 @@
+error: expected expression, found `_`
+  --> $DIR/underscore.rs:18:9
+   |
+18 |         _
+   |         ^
+   | 
+  ::: $DIR/main.rs:15:5
+   |
+15 |     underscore!();
+   |     -------------- in this macro invocation
+
diff --git a/src/test/ui/cross-file-errors/underscore.rs b/src/test/ui/cross-file-errors/underscore.rs
new file mode 100644 (file)
index 0000000..312b3b8
--- /dev/null
@@ -0,0 +1,20 @@
+// 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.
+
+// We want this file only so we can test cross-file error
+// messages, but we don't want it in an external crate.
+// ignore-test
+#![crate_type = "lib"]
+
+macro_rules! underscore {
+    () => (
+        _
+    )
+}
index fcd3f2696f200122d19bd51677572e20aecd1190..2a0f9ee34f2befdbb71013c6c901effa4e6bb9ee 100644 (file)
@@ -9,8 +9,8 @@ error[E0252]: the name `foo` is defined multiple times
    = note: `foo` must be defined only once in the value namespace of this module
 help: You can use `as` to change the binding name of the import
    |
-23 | use sub2::foo as Otherfoo; //~ ERROR the name `foo` is defined multiple times
-   |     ^^^^^^^^^^^^^^^^^^^^^
+23 | use sub2::foo as other_foo; //~ ERROR the name `foo` is defined multiple times
+   |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index 0f932abe4ee31b725533964d8ddf17eec73ad04c..f7b05d5cf25611acb86adac0bc279a56f4555d27 100644 (file)
@@ -1,4 +1,4 @@
-error[E0658]: `#[thread_local]` is an experimental feature, and does not currently handle destructors. There is no corresponding `#[task_local]` mapping to the task model (see issue #29594)
+error[E0658]: `#[thread_local]` is an experimental feature, and does not currently handle destructors. (see issue #29594)
   --> $DIR/feature-gate-thread_local.rs:18:1
    |
 18 | #[thread_local] //~ ERROR `#[thread_local]` is an experimental feature
diff --git a/src/test/ui/impl-trait/impl-trait-plus-priority.rs b/src/test/ui/impl-trait/impl-trait-plus-priority.rs
new file mode 100644 (file)
index 0000000..f451123
--- /dev/null
@@ -0,0 +1,59 @@
+// 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.
+
+// compile-flags: -Z parse-only -Z continue-parse-after-error
+
+fn f() -> impl A + {} // OK
+fn f() -> impl A + B {} // OK
+fn f() -> dyn A + B {} // OK
+fn f() -> A + B {} // OK
+
+impl S {
+    fn f(self) -> impl A + { // OK
+        let _ = |a, b| -> impl A + {}; // OK
+    }
+    fn f(self) -> impl A + B { // OK
+        let _ = |a, b| -> impl A + B {}; // OK
+    }
+    fn f(self) -> dyn A + B { // OK
+        let _ = |a, b| -> dyn A + B {}; // OK
+    }
+    fn f(self) -> A + B { // OK
+        let _ = |a, b| -> A + B {}; // OK
+    }
+}
+
+type A = fn() -> impl A +;
+//~^ ERROR ambiguous `+` in a type
+type A = fn() -> impl A + B;
+//~^ ERROR ambiguous `+` in a type
+type A = fn() -> dyn A + B;
+//~^ ERROR ambiguous `+` in a type
+type A = fn() -> A + B;
+//~^ ERROR expected a path on the left-hand side of `+`, not `fn() -> A`
+
+type A = Fn() -> impl A +;
+//~^ ERROR ambiguous `+` in a type
+type A = Fn() -> impl A + B;
+//~^ ERROR ambiguous `+` in a type
+type A = Fn() -> dyn A + B;
+//~^ ERROR ambiguous `+` in a type
+type A = Fn() -> A + B; // OK, interpreted as `(Fn() -> A) + B` for compatibility
+
+type A = &impl A +;
+//~^ ERROR ambiguous `+` in a type
+type A = &impl A + B;
+//~^ ERROR ambiguous `+` in a type
+type A = &dyn A + B;
+//~^ ERROR ambiguous `+` in a type
+type A = &A + B;
+//~^ ERROR expected a path on the left-hand side of `+`, not `&A`
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/impl-trait-plus-priority.stderr b/src/test/ui/impl-trait/impl-trait-plus-priority.stderr
new file mode 100644 (file)
index 0000000..885c394
--- /dev/null
@@ -0,0 +1,68 @@
+error: ambiguous `+` in a type
+  --> $DIR/impl-trait-plus-priority.rs:33:18
+   |
+33 | type A = fn() -> impl A +;
+   |                  ^^^^^^^^ help: use parentheses to disambiguate: `(impl A)`
+
+error: ambiguous `+` in a type
+  --> $DIR/impl-trait-plus-priority.rs:35:18
+   |
+35 | type A = fn() -> impl A + B;
+   |                  ^^^^^^^^^^ help: use parentheses to disambiguate: `(impl A + B)`
+
+error: ambiguous `+` in a type
+  --> $DIR/impl-trait-plus-priority.rs:37:18
+   |
+37 | type A = fn() -> dyn A + B;
+   |                  ^^^^^^^^^ help: use parentheses to disambiguate: `(dyn A + B)`
+
+error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> A`
+  --> $DIR/impl-trait-plus-priority.rs:39:10
+   |
+39 | type A = fn() -> A + B;
+   |          ^^^^^^^^^^^^^ perhaps you forgot parentheses?
+
+error: ambiguous `+` in a type
+  --> $DIR/impl-trait-plus-priority.rs:42:18
+   |
+42 | type A = Fn() -> impl A +;
+   |                  ^^^^^^^^ help: use parentheses to disambiguate: `(impl A)`
+
+error: ambiguous `+` in a type
+  --> $DIR/impl-trait-plus-priority.rs:44:18
+   |
+44 | type A = Fn() -> impl A + B;
+   |                  ^^^^^^^^^^ help: use parentheses to disambiguate: `(impl A + B)`
+
+error: ambiguous `+` in a type
+  --> $DIR/impl-trait-plus-priority.rs:46:18
+   |
+46 | type A = Fn() -> dyn A + B;
+   |                  ^^^^^^^^^ help: use parentheses to disambiguate: `(dyn A + B)`
+
+error: ambiguous `+` in a type
+  --> $DIR/impl-trait-plus-priority.rs:50:11
+   |
+50 | type A = &impl A +;
+   |           ^^^^^^^^ help: use parentheses to disambiguate: `(impl A)`
+
+error: ambiguous `+` in a type
+  --> $DIR/impl-trait-plus-priority.rs:52:11
+   |
+52 | type A = &impl A + B;
+   |           ^^^^^^^^^^ help: use parentheses to disambiguate: `(impl A + B)`
+
+error: ambiguous `+` in a type
+  --> $DIR/impl-trait-plus-priority.rs:54:11
+   |
+54 | type A = &dyn A + B;
+   |           ^^^^^^^^^ help: use parentheses to disambiguate: `(dyn A + B)`
+
+error[E0178]: expected a path on the left-hand side of `+`, not `&A`
+  --> $DIR/impl-trait-plus-priority.rs:56:10
+   |
+56 | type A = &A + B;
+   |          ^^^^^^ help: try adding parentheses: `&(A + B)`
+
+error: aborting due to 11 previous errors
+
index a74401314a18cb3698e6ac419087d5872bcbd23e..6e5b91a11c900e43f054f7eda9a062696a176053 100644 (file)
@@ -9,8 +9,8 @@ error[E0252]: the name `foo` is defined multiple times
    = note: `foo` must be defined only once in the value namespace of this module
 help: You can use `as` to change the binding name of the import
    |
-25 |     use a::foo as Otherfoo; //~ ERROR the name `foo` is defined multiple times
-   |         ^^^^^^^^^^^^^^^^^^
+25 |     use a::foo as other_foo; //~ ERROR the name `foo` is defined multiple times
+   |         ^^^^^^^^^^^^^^^^^^^
 
 error[E0659]: `foo` is ambiguous
   --> $DIR/duplicate.rs:56:9
index 3489a2ca9be1517f920ee2a2c008512acc4d87d5..22751c4a37cdd0b97308047e4e0701a483fb63d1 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-macro_rules! not_an_lvalue {
+macro_rules! not_a_place {
     ($thing:expr) => {
         $thing = 42;
         //~^ ERROR invalid left-hand side expression
@@ -16,5 +16,5 @@ macro_rules! not_an_lvalue {
 }
 
 fn main() {
-    not_an_lvalue!(99);
+    not_a_place!(99);
 }
index c2b81b2ce43fdd70a568ae4a4c398ac66d1344eb..b850852623fd8ddd449c07b7a1cec039a67915d7 100644 (file)
@@ -4,8 +4,8 @@ error[E0070]: invalid left-hand side expression
 13 |         $thing = 42;
    |         ^^^^^^^^^^^ left-hand of expression not valid
 ...
-19 |     not_an_lvalue!(99);
-   |     ------------------- in this macro invocation
+19 |     not_a_place!(99);
+   |     ----------------- in this macro invocation
 
 error: aborting due to previous error
 
index cb2eca87068f813e555a954509c5965d6a28b027..e6424e535ee329e36577f216a937efc8c2c3fff8 100644 (file)
@@ -24,8 +24,8 @@ error[E0252]: the name `sync` is defined multiple times
    = note: `sync` must be defined only once in the type namespace of this module
 help: You can use `as` to change the binding name of the import
    |
-14 | use std::sync as Othersync; //~ ERROR the name `sync` is defined multiple times
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+14 | use std::sync as other_sync; //~ ERROR the name `sync` is defined multiple times
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
index 953e6fe77d716c26e97575a31fe318c1af7d7091..78c9ce9a1b12a0967a288c49adedf814eaa50687 100644 (file)
@@ -8,10 +8,10 @@ error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _,
               found type `&_`
 
 error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as std::iter::Iterator>::Item == &_`
-  --> $DIR/issue-33941.rs:14:5
+  --> $DIR/issue-33941.rs:14:14
    |
 14 |     for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference
    |
    = note: expected type `(&_, &_)`
               found type `&_`
index 9f12092f99cc04bef8a999a43ca2bf24d42bbdb5..97dfb458d2dfb24451a58353adf86bb508e39e05 100644 (file)
@@ -15,7 +15,7 @@ error[E0597]: `z` does not live long enough (Mir)
 16 |         &mut z
    |         ^^^^^^ borrowed value does not live long enough
 17 |     };
-   |      - `z` dropped here while still borrowed
+   |     - `z` dropped here while still borrowed
 ...
 21 | }
    | - borrowed value needs to live until here
index 19fc579d198ff6d3be172c1c3b47d50c5eaa3ece..4c196bba5a1f10d1c02660bed9dfba2f5fc38e06 100644 (file)
@@ -16,7 +16,7 @@ error[E0597]: `x` does not live long enough (Mir)
    |     ^^ borrowed value does not live long enough
 ...
 18 | }
-   |  - borrowed value only lives until here
+   | - borrowed value only lives until here
    |
    = note: borrowed value must be valid for the static lifetime...
 
index 50df72fc2a0201326b2b674109c1563c2a39ba8e..2f332a7a55850dc5f74789d067fe88958306f979 100644 (file)
@@ -24,7 +24,7 @@ error[E0597]: borrowed value does not live long enough (Mir)
    |          ^ temporary value does not live long enough
 ...
 17 | }
-   |  - temporary value only lives until here
+   | - temporary value only lives until here
    |
 note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:1...
   --> $DIR/issue-46472.rs:13:1
diff --git a/src/test/ui/issue-47706-trait.rs b/src/test/ui/issue-47706-trait.rs
new file mode 100644 (file)
index 0000000..86a9da4
--- /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.
+
+trait T {
+    fn f(&self, _: ()) {
+        None::<()>.map(Self::f);
+    }
+    //~^^ ERROR function is expected to take a single 0-tuple as argument
+}
diff --git a/src/test/ui/issue-47706-trait.stderr b/src/test/ui/issue-47706-trait.stderr
new file mode 100644 (file)
index 0000000..320e98d
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0601]: main function not found
+
+error[E0593]: function is expected to take a single 0-tuple as argument, but it takes 2 distinct arguments
+  --> $DIR/issue-47706-trait.rs:13:20
+   |
+12 |     fn f(&self, _: ()) {
+   |     ------------------ takes 2 distinct arguments
+13 |         None::<()>.map(Self::f);
+   |                    ^^^ expected function that takes a single 0-tuple as argument
+
+error: aborting due to 2 previous errors
+
index dfcaede1402da372ac99f6bc1bcd12964503189c..e35675eacd835cc88f1d7f7e7e25165ec751f7c0 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-tidy-tab
+
 #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
 #![feature(no_debug)]
 
@@ -46,11 +48,15 @@ fn main() {
         let mut a = (1); // should suggest no `mut`, no parens
         //~^ WARN does not need to be mutable
         //~| WARN unnecessary parentheses
+        // the line after `mut` has a `\t` at the beginning, this is on purpose
+        let mut
+               b = 1;
+        //~^^ WARN does not need to be mutable
         let d = Equinox { warp_factor: 9.975 };
         match d {
             Equinox { warp_factor: warp_factor } => {} // should suggest shorthand
             //~^ WARN this pattern is redundant
         }
-        println!("{}", a);
+        println!("{} {}", a, b);
     }
 }
index 8b30f552d377140a0d49f171ab67e46685819a8b..90d6bd312e419505974bf7d8db881e1f323c87f4 100644 (file)
@@ -1,41 +1,53 @@
 warning: unnecessary parentheses around assigned value
-  --> $DIR/suggestions.rs:46:21
+  --> $DIR/suggestions.rs:48:21
    |
-46 |         let mut a = (1); // should suggest no `mut`, no parens
+48 |         let mut a = (1); // should suggest no `mut`, no parens
    |                     ^^^ help: remove these parentheses
    |
 note: lint level defined here
-  --> $DIR/suggestions.rs:11:21
+  --> $DIR/suggestions.rs:13:21
    |
-11 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
+13 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
    |                     ^^^^^^^^^^^^^
 
 warning: use of deprecated attribute `no_debug`: the `#[no_debug]` attribute was an experimental feature that has been deprecated due to lack of demand. See https://github.com/rust-lang/rust/issues/29721
-  --> $DIR/suggestions.rs:41:1
+  --> $DIR/suggestions.rs:43:1
    |
-41 | #[no_debug] // should suggest removal of deprecated attribute
+43 | #[no_debug] // should suggest removal of deprecated attribute
    | ^^^^^^^^^^^ help: remove this attribute
    |
    = note: #[warn(deprecated)] on by default
 
 warning: variable does not need to be mutable
-  --> $DIR/suggestions.rs:46:13
+  --> $DIR/suggestions.rs:48:13
    |
-46 |         let mut a = (1); // should suggest no `mut`, no parens
-   |             ---^^
+48 |         let mut a = (1); // should suggest no `mut`, no parens
+   |             ----^
    |             |
    |             help: remove this `mut`
    |
 note: lint level defined here
-  --> $DIR/suggestions.rs:11:9
+  --> $DIR/suggestions.rs:13:9
    |
-11 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
+13 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
    |         ^^^^^^^^^^
 
+warning: variable does not need to be mutable
+  --> $DIR/suggestions.rs:52:13
+   |
+52 |            let mut
+   |   _____________^
+   |  |_____________|
+   | ||
+53 | ||             b = 1;
+   | ||____________-^
+   |  |____________|
+   |               help: remove this `mut`
+
 warning: static is marked #[no_mangle], but not exported
-  --> $DIR/suggestions.rs:14:14
+  --> $DIR/suggestions.rs:16:14
    |
-14 | #[no_mangle] static SHENZHOU: usize = 1; // should suggest `pub`
+16 | #[no_mangle] static SHENZHOU: usize = 1; // should suggest `pub`
    |              -^^^^^^^^^^^^^^^^^^^^^^^^^^
    |              |
    |              help: try making it public: `pub`
@@ -43,9 +55,9 @@ warning: static is marked #[no_mangle], but not exported
    = note: #[warn(private_no_mangle_statics)] on by default
 
 error: const items should never be #[no_mangle]
-  --> $DIR/suggestions.rs:16:14
+  --> $DIR/suggestions.rs:18:14
    |
-16 | #[no_mangle] const DISCOVERY: usize = 1; // should suggest `pub static` rather than `const`
+18 | #[no_mangle] const DISCOVERY: usize = 1; // should suggest `pub static` rather than `const`
    |              -----^^^^^^^^^^^^^^^^^^^^^^
    |              |
    |              help: try a static value: `pub static`
@@ -53,19 +65,19 @@ error: const items should never be #[no_mangle]
    = note: #[deny(no_mangle_const_items)] on by default
 
 warning: functions generic over types must be mangled
-  --> $DIR/suggestions.rs:20:1
+  --> $DIR/suggestions.rs:22:1
    |
-19 | #[no_mangle] // should suggest removal (generics can't be no-mangle)
+21 | #[no_mangle] // should suggest removal (generics can't be no-mangle)
    | ------------ help: remove this attribute
-20 | pub fn defiant<T>(_t: T) {}
+22 | pub fn defiant<T>(_t: T) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: #[warn(no_mangle_generic_items)] on by default
 
 warning: function is marked #[no_mangle], but not exported
-  --> $DIR/suggestions.rs:24:1
+  --> $DIR/suggestions.rs:26:1
    |
-24 | fn rio_grande() {} // should suggest `pub`
+26 | fn rio_grande() {} // should suggest `pub`
    | -^^^^^^^^^^^^^^^^^
    | |
    | help: try making it public: `pub`
@@ -73,29 +85,29 @@ warning: function is marked #[no_mangle], but not exported
    = note: #[warn(private_no_mangle_fns)] on by default
 
 warning: static is marked #[no_mangle], but not exported
-  --> $DIR/suggestions.rs:31:18
+  --> $DIR/suggestions.rs:33:18
    |
-31 |     #[no_mangle] pub static DAUNTLESS: bool = true;
+33 |     #[no_mangle] pub static DAUNTLESS: bool = true;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: function is marked #[no_mangle], but not exported
-  --> $DIR/suggestions.rs:33:18
+  --> $DIR/suggestions.rs:35:18
    |
-33 |     #[no_mangle] pub fn val_jean() {}
+35 |     #[no_mangle] pub fn val_jean() {}
    |                  ^^^^^^^^^^^^^^^^^^^^
 
 warning: denote infinite loops with `loop { ... }`
-  --> $DIR/suggestions.rs:44:5
+  --> $DIR/suggestions.rs:46:5
    |
-44 |     while true { // should suggest `loop`
+46 |     while true { // should suggest `loop`
    |     ^^^^^^^^^^ help: use `loop`
    |
    = note: #[warn(while_true)] on by default
 
 warning: the `warp_factor:` in this pattern is redundant
-  --> $DIR/suggestions.rs:51:23
+  --> $DIR/suggestions.rs:57:23
    |
-51 |             Equinox { warp_factor: warp_factor } => {} // should suggest shorthand
+57 |             Equinox { warp_factor: warp_factor } => {} // should suggest shorthand
    |                       ------------^^^^^^^^^^^^
    |                       |
    |                       help: remove this
index 5990f71b3ca0ad1f7b74d980855f0d201f254187..48138ee711b3fbb01d0a4854e0b2544ffbcdfbd8 100644 (file)
@@ -22,7 +22,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found
 27 |       ping!();
    |       -------- in this macro invocation
    | 
-  ::: <ping macros>
+  ::: <ping macros>:1:1
    |
 1  |   (  ) => { pong ! (  ) ; }
    |   -------------------------
@@ -42,7 +42,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found
 28 |       deep!();
    |       -------- in this macro invocation (#1)
    | 
-  ::: <deep macros>
+  ::: <deep macros>:1:1
    |
 1  |   (  ) => { foo ! (  ) ; }
    |   ------------------------
@@ -50,7 +50,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found
    |   |         in this macro invocation (#2)
    |   in this expansion of `deep!` (#1)
    | 
-  ::: <foo macros>
+  ::: <foo macros>:1:1
    |
 1  |   (  ) => { bar ! (  ) ; }
    |   ------------------------
@@ -58,7 +58,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found
    |   |         in this macro invocation (#3)
    |   in this expansion of `foo!` (#2)
    | 
-  ::: <bar macros>
+  ::: <bar macros>:1:1
    |
 1  |   (  ) => { ping ! (  ) ; }
    |   -------------------------
@@ -66,7 +66,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found
    |   |         in this macro invocation (#4)
    |   in this expansion of `bar!` (#3)
    | 
-  ::: <ping macros>
+  ::: <ping macros>:1:1
    |
 1  |   (  ) => { pong ! (  ) ; }
    |   -------------------------
index 7e7487daa67a377d3647c22b32aab4d50f378e2b..d05ec91be3026cc4fe515d364f5a505f4cd28e60 100644 (file)
@@ -5,7 +5,7 @@ error[E0597]: `y` does not live long enough
    |                ^^ borrowed value does not live long enough
 ...
 38 |     }
-   |      - borrowed value only lives until here
+   |     - borrowed value only lives until here
 39 | 
 40 |     deref(p);
    |           - borrow later used here
index 09d5617b08ef564f20b134e4f44dd553862d7878..ee29f2f9c5c59b7264e1b5b26fb869fe0e3a1041 100644 (file)
@@ -30,7 +30,7 @@ error[E0597]: `y` does not live long enough
    |                         ^^ borrowed value does not live long enough
 38 |         //~^ ERROR `y` does not live long enough [E0597]
 39 |     }
-   |      - borrowed value only lives until here
+   |     - borrowed value only lives until here
 40 | 
 41 |     deref(p);
    |           - borrow later used here
index 430fb711c635d8c7911e00757f67925ab87c14ea..501d2991547377efc0f5d99acbed21014c196f53 100644 (file)
@@ -57,7 +57,7 @@ error[E0597]: `y` does not live long enough
    | |_________^ borrowed value does not live long enough
 ...
 36 |       }
-   |        - borrowed value only lives until here
+   |       - borrowed value only lives until here
 37 | 
 38 |       deref(p);
    |             - borrow later used here
index 090bacbc17d076a047baad94e434580ff575cba5..556cd020f7ff5aaac4ff79788d4b4f3eaeaf207e 100644 (file)
@@ -34,7 +34,7 @@ error[E0597]: `y` does not live long enough
    |                           ^^^^^^^^^ borrowed value does not live long enough
 ...
 36 |     }
-   |      - borrowed value only lives until here
+   |     - borrowed value only lives until here
 37 | 
 38 |     deref(p);
    |           - borrow later used here
index ef850f3a568c0b84f3a5ddcc9b7090e1d423165e..dee5873ba3be1c9511164325b4d82f33899cb4b1 100644 (file)
@@ -8,7 +8,7 @@ error[E0506]: cannot assign to `v[..]` because it is borrowed
    |         ^^^^^^^^^ assignment to borrowed `v[..]` occurs here
 ...
 35 | }
-   |  - borrow later used here, when `p` is dropped
+   | - borrow later used here, when `p` is dropped
 
 error[E0506]: cannot assign to `v[..]` because it is borrowed
   --> $DIR/drop-no-may-dangle.rs:34:5
@@ -19,7 +19,7 @@ error[E0506]: cannot assign to `v[..]` because it is borrowed
 34 |     v[0] += 1; //~ ERROR cannot assign to `v[..]` because it is borrowed
    |     ^^^^^^^^^ assignment to borrowed `v[..]` occurs here
 35 | }
-   |  - borrow later used here, when `p` is dropped
+   | - borrow later used here, when `p` is dropped
 
 error: aborting due to 2 previous errors
 
index 3c685ce111a972e13ae12952995d6fc30b045767..fbaaf5511ccd506b086f2bf94bc5059947cfb3dc 100644 (file)
@@ -8,7 +8,7 @@ error[E0506]: cannot assign to `x` because it is borrowed
    |     ^^^^^ assignment to borrowed `x` occurs here
 33 |     // FIXME ^ Should not error in the future with implicit dtors, only manually implemented ones
 34 | }
-   |  - borrow later used here, when `foo` is dropped
+   | - borrow later used here, when `foo` is dropped
 
 error: aborting due to previous error
 
index 072818c7ce17bc3fa146a59398c344894b0b2781..5d526cda042e91b8ae9bf9c1b8ccaef6e1e2a4f4 100644 (file)
@@ -7,7 +7,7 @@ error[E0506]: cannot assign to `x` because it is borrowed
 31 |     x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
    |     ^^^^^ assignment to borrowed `x` occurs here
 32 | }
-   |  - borrow later used here, when `foo` is dropped
+   | - borrow later used here, when `foo` is dropped
 
 error: aborting due to previous error
 
index 89117c2bfeafead7730d16421c366822a7c3b001..ecd60821194f831fbf3eb3cb32cd97328bc72593 100644 (file)
@@ -8,7 +8,7 @@ error[E0506]: cannot assign to `x` because it is borrowed
    |     ^^^^^ assignment to borrowed `x` occurs here
 33 |     // FIXME ^ This currently errors and it should not.
 34 | }
-   |  - borrow later used here, when `foo` is dropped
+   | - borrow later used here, when `foo` is dropped
 
 error: aborting due to previous error
 
index 626307a80ed5783d74c9be1f5f0256a1445db6da..874d63a0441b61971ecb636102d3d3d6d040ef51 100644 (file)
@@ -6,7 +6,7 @@ error[E0506]: cannot assign to `x` because it is borrowed
 26 |     x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
    |     ^^^^^ assignment to borrowed `x` occurs here
 27 | }
-   |  - borrow later used here, when `wrap` is dropped
+   | - borrow later used here, when `wrap` is dropped
 
 error: aborting due to previous error
 
index 763e2bfd8929447f270a2d7bc6b9d9a74d9ad6d0..cd77569dae0bffd86c140e9dd8dc750e25bdecd6 100644 (file)
@@ -5,7 +5,7 @@ error[E0597]: borrowed value does not live long enough
    |                     ^^^^^^^ temporary value does not live long enough
 18 |     x
 19 | }
-   |  - temporary value only lives until here
+   | - temporary value only lives until here
    |
    = note: borrowed value must be valid for lifetime '_#2r...
 
index 03ef66681e4404f35980d00429d34fccc3f241a5..e2245b8a8b10a7b39bdb0827fc04123f9f055441 100644 (file)
@@ -10,8 +10,8 @@ error[E0255]: the name `transmute` is defined multiple times
    = note: `transmute` must be defined only once in the value namespace of this module
 help: You can use `as` to change the binding name of the import
    |
-11 | use std::mem::transmute as Othertransmute;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+11 | use std::mem::transmute as other_transmute;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/for-c-in-str.rs b/src/test/ui/suggestions/for-c-in-str.rs
new file mode 100644 (file)
index 0000000..011886e
--- /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.
+
+// E0277 should point exclusively at line 14, not the entire for loop span
+
+fn main() {
+    for c in "asdf" {
+    //~^ ERROR the trait bound `&str: std::iter::Iterator` is not satisfied
+    //~| NOTE `&str` is not an iterator
+    //~| HELP the trait `std::iter::Iterator` is not implemented for `&str`
+    //~| NOTE required by `std::iter::IntoIterator::into_iter`
+        println!("");
+    }
+}
diff --git a/src/test/ui/suggestions/for-c-in-str.stderr b/src/test/ui/suggestions/for-c-in-str.stderr
new file mode 100644 (file)
index 0000000..7a6dc9a
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0277]: the trait bound `&str: std::iter::Iterator` is not satisfied
+  --> $DIR/for-c-in-str.rs:14:14
+   |
+14 |     for c in "asdf" {
+   |              ^^^^^^ `&str` is not an iterator; maybe try calling `.iter()` or a similar method
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `&str`
+   = note: required by `std::iter::IntoIterator::into_iter`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs b/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs
new file mode 100644 (file)
index 0000000..4d75127
--- /dev/null
@@ -0,0 +1,13 @@
+// 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.
+
+extern crate std;
+fn main() {}
+//~^^ ERROR the name `std` is defined multiple times [E0259]
diff --git a/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr b/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr
new file mode 100644 (file)
index 0000000..01dba62
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0259]: the name `std` is defined multiple times
+  --> $DIR/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs:11:1
+   |
+11 | extern crate std;
+   | ^^^^^^^^^^^^^^^^^ `std` reimported here
+   |
+   = note: `std` must be defined only once in the type namespace of this module
+help: You can use `as` to change the binding name of the import
+   |
+11 | extern crate std as other_std;
+   |
+
+error: aborting due to previous error
+
index b1be9ad3cf697bea9776dc30a5c94c75b4fd122a..dfe950818e7e6ec181d0f6ed17d15dff843fe069 100644 (file)
@@ -10,10 +10,7 @@ error[E0277]: the `?` operator can only be used in a function that returns `Resu
   --> $DIR/try-on-option.rs:23:5
    |
 23 |     x?; //~ the `?` operator
-   |     --
-   |     |
-   |     cannot use the `?` operator in a function that returns `u32`
-   |     in this macro invocation
+   |     ^^ cannot use the `?` operator in a function that returns `u32`
    |
    = help: the trait `std::ops::Try` is not implemented for `u32`
    = note: required by `std::ops::Try::from_error`
index 3b32b4a9eb7ba44f016784de1a326775530c10f2..e97823a3d5d5b96496e5acd2e0695da4c56e7555 100644 (file)
@@ -2,10 +2,7 @@ error[E0277]: the `?` operator can only be used in a function that returns `Resu
   --> $DIR/try-operator-on-main.rs:19:5
    |
 19 |     std::fs::File::open("foo")?; //~ ERROR the `?` operator can only
-   |     ---------------------------
-   |     |
-   |     cannot use the `?` operator in a function that returns `()`
-   |     in this macro invocation
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
    |
    = help: the trait `std::ops::Try` is not implemented for `()`
    = note: required by `std::ops::Try::from_error`
@@ -14,10 +11,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `std
   --> $DIR/try-operator-on-main.rs:22:5
    |
 22 |     ()?; //~ ERROR the `?` operator can only
-   |     ---
-   |     |
-   |     the `?` operator cannot be applied to type `()`
-   |     in this macro invocation
+   |     ^^^ the `?` operator cannot be applied to type `()`
    |
    = help: the trait `std::ops::Try` is not implemented for `()`
    = note: required by `std::ops::Try::into_result`
@@ -38,10 +32,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `std
   --> $DIR/try-operator-on-main.rs:32:5
    |
 32 |     ()?; //~ ERROR the `?` operator can only
-   |     ---
-   |     |
-   |     the `?` operator cannot be applied to type `()`
-   |     in this macro invocation
+   |     ^^^ the `?` operator cannot be applied to type `()`
    |
    = help: the trait `std::ops::Try` is not implemented for `()`
    = note: required by `std::ops::Try::into_result`
index bb64909e64a0c5b67b780c2f9dbfee59205b5be5..1c9f306f493db9b5c357b3e84abcc583041668a5 100644 (file)
@@ -25,7 +25,7 @@ error[E0252]: the name `bar` is defined multiple times
    = note: `bar` must be defined only once in the type namespace of this module
 help: You can use `as` to change the binding name of the import
    |
-15 |     self as Otherbar
+15 |     self as other_bar
    |
 
 error: aborting due to 3 previous errors
diff --git a/src/test/ui/use-nested-groups-error.rs b/src/test/ui/use-nested-groups-error.rs
new file mode 100644 (file)
index 0000000..a9b6b3e
--- /dev/null
@@ -0,0 +1,27 @@
+// 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.
+
+#![feature(use_nested_groups)]
+
+mod a {
+    pub mod b1 {
+        pub enum C2 {}
+    }
+
+    pub enum B2 {}
+}
+
+use a::{b1::{C1, C2}, B2};
+//~^ ERROR unresolved import `a::b1::C1`
+
+fn main() {
+    let _: C2;
+    let _: B2;
+}
diff --git a/src/test/ui/use-nested-groups-error.stderr b/src/test/ui/use-nested-groups-error.stderr
new file mode 100644 (file)
index 0000000..cae3468
--- /dev/null
@@ -0,0 +1,8 @@
+error[E0432]: unresolved import `a::b1::C1`
+  --> $DIR/use-nested-groups-error.rs:21:14
+   |
+21 | use a::{b1::{C1, C2}, B2};
+   |              ^^ no `C1` in `a::b1`. Did you mean to use `C2`?
+
+error: aborting due to previous error
+
index 91e36aa86c7037de50642f2fec1cf47c3d18af02..1d6dfea44f97199d5d5c177c7dadcde393eaff9a 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 91e36aa86c7037de50642f2fec1cf47c3d18af02
+Subproject commit 1d6dfea44f97199d5d5c177c7dadcde393eaff9a
index 533aaf9cd27353bf9e0b78eab246f8df8728da72..e3d453a991d802d3e23dbc5717ee4cc6cedbeba0 100644 (file)
@@ -485,7 +485,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
         filter: config.filter.clone(),
         filter_exact: config.filter_exact,
         run_ignored: config.run_ignored,
-        quiet: config.quiet,
+        format: if config.quiet { test::OutputFormat::Terse } else { test::OutputFormat::Pretty },
         logfile: config.logfile.clone(),
         run_tests: true,
         bench_benchmarks: true,
@@ -667,9 +667,16 @@ fn up_to_date(config: &Config, testpaths: &TestPaths, props: &EarlyProps) -> boo
     for pretty_printer_file in &pretty_printer_files {
         inputs.push(mtime(&rust_src_dir.join(pretty_printer_file)));
     }
-    for lib in config.run_lib_path.read_dir().unwrap() {
-        let lib = lib.unwrap();
-        inputs.push(mtime(&lib.path()));
+    let mut entries = config.run_lib_path.read_dir().unwrap()
+        .collect::<Vec<_>>();
+    while let Some(entry) = entries.pop() {
+        let entry = entry.unwrap();
+        let path = entry.path();
+        if entry.metadata().unwrap().is_file() {
+            inputs.push(mtime(&path));
+        } else {
+            entries.extend(path.read_dir().unwrap());
+        }
     }
     if let Some(ref rustdoc_path) = config.rustdoc_path {
         inputs.push(mtime(&rustdoc_path));
index bf5fc00428df2cad5558c4527ba9c08f8887d1c3..abf62a060b83b388f77c00a8c6f3d355891ebb27 100644 (file)
@@ -1402,7 +1402,7 @@ fn exec_compiled_test(&self) -> ProcRes {
     }
 
     /// For each `aux-build: foo/bar` annotation, we check to find the
-    /// file in a `aux` directory relative to the test itself.
+    /// file in a `auxiliary` directory relative to the test itself.
     fn compute_aux_test_paths(&self, rel_ab: &str) -> TestPaths {
         let test_ab = self.testpaths
             .file
index eee2902bfb6f736ccdd1a94af68293af1a1544b5..4d89008d5ca54bb59b8df75c67ae00d785a646bd 100644 (file)
@@ -54,6 +54,7 @@ fn filter_dirs(path: &Path) -> bool {
         "src/dlmalloc",
         "src/jemalloc",
         "src/llvm",
+        "src/llvm-emscripten",
         "src/libbacktrace",
         "src/libcompiler_builtins",
         "src/librustc_data_structures/owning_ref",