about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-12-26 18:03:00 +0000
committerbors <bors@rust-lang.org>2017-12-26 18:03:00 +0000
commit503153e9506890c31749768474506e0b4e3eb4ef (patch)
tree1bdfae1215771ca33d110a887528425f84f6493a
parent269827ced91bb2b702d4cb62e3e164b225f73157 (diff)
parent44954ab52d82fe5ae5222c3bfd482d38c3db0baa (diff)
downloadrust-503153e9506890c31749768474506e0b4e3eb4ef.tar.gz
rust-503153e9506890c31749768474506e0b4e3eb4ef.zip
Auto merge of #46554 - kennytm:45861-step-4-5-6-7-upload-test-result-and-remove-toolstate-toml, r=alexcrichton
[auto-toolstate] Upload the toolstate result to an external git repository, and removes BuildExpectation

This PR consists of 3 commits.

1. (Steps 4–6) The `toolstate.json` output previously collected is now pushed to the https://github.com/rust-lang-nursery/rust-toolstate repository.
2. (Step 7) Revert commit ab018c7, thus removing all traces of `BuildExpectation` and `toolstate.toml`.
3. (Step 8) Adjust CONTRIBUTION.md for the new procedure.

These are the last steps of #45861. After this PR, the toolstate will be automatically computed and published to https://rust-lang-nursery.github.io/rust-toolstate/. There is no need to manage toolstate.toml again.

Closes #45861.
-rw-r--r--.travis.yml13
-rw-r--r--CONTRIBUTING.md40
-rw-r--r--appveyor.yml6
-rw-r--r--src/Cargo.lock163
-rw-r--r--src/Cargo.toml1
-rw-r--r--src/bootstrap/check.rs44
-rw-r--r--src/bootstrap/config.rs15
-rw-r--r--src/bootstrap/dist.rs10
-rw-r--r--src/bootstrap/lib.rs28
-rw-r--r--src/bootstrap/tool.rs41
-rw-r--r--src/bootstrap/toolstate.rs40
-rw-r--r--src/build_helper/lib.rs80
-rwxr-xr-xsrc/ci/docker/run.sh1
-rw-r--r--src/ci/docker/x86_64-gnu-aux/Dockerfile2
-rw-r--r--src/ci/docker/x86_64-gnu-tools/Dockerfile8
-rwxr-xr-xsrc/ci/docker/x86_64-gnu-tools/checktools.sh23
-rw-r--r--src/ci/docker/x86_64-gnu-tools/repo.sh90
-rw-r--r--src/liballoc_jemalloc/build.rs6
-rw-r--r--src/libstd/build.rs9
m---------src/tools/miri34
-rwxr-xr-xsrc/tools/publish_toolstate.py105
-rw-r--r--src/tools/toolstate.toml36
22 files changed, 444 insertions, 351 deletions
diff --git a/.travis.yml b/.travis.yml
index 090e46b9ea7..6a7725e01cf 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -179,6 +179,17 @@ matrix:
     - env: IMAGE=x86_64-gnu-incremental
       if: branch = auto
 
+    - stage: publish toolstate
+      if: branch = master AND type = push
+      before_install: []
+      install: []
+      cache: false
+      sudo: false
+      script:
+        MESSAGE_FILE=$(mktemp -t msg.XXXXXX);
+        . src/ci/docker/x86_64-gnu-tools/repo.sh;
+        commit_toolstate_change "$MESSAGE_FILE" "$TRAVIS_BUILD_DIR/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "$MESSAGE_FILE"
+
 env:
   global:
     - SCCACHE_BUCKET=rust-lang-ci-sccache2
@@ -186,6 +197,8 @@ env:
     - AWS_ACCESS_KEY_ID=AKIAJAMV3QAMMA6AXHFQ
     # AWS_SECRET_ACCESS_KEY=...
     - secure: "j96XxTVOSUf4s4r4htIxn/fvIa5DWbMgLqWl7r8z2QfgUwscmkMXAwXuFNc7s7bGTpV/+CgDiMFFM6BAFLGKutytIF6oA02s9b+usQYnM0th7YQ2AIgm9GtMTJCJp4AoyfFmh8F2faUICBZlfVLUJ34udHEe35vOklix+0k4WDo="
+    # TOOLSTATE_REPO_ACCESS_TOKEN=...
+    - secure: "cFh8thThqEJLC98XKI5pfqflUzOlxsYPRW20AWRaYOOgYHPTiGWypTXiPbGSKaeAXTZoOA+DpQtEmefc0U6lt9dHc7a/MIaK6isFurjlnKYiLOeTruzyu1z7PWCeZ/jKXsU2RK/88DBtlNwfMdaMIeuKj14IVfpepPPL71ETbuk="
 
 before_install:
   - zcat $HOME/docker/rust-ci.tar.gz | docker load || true
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 919d8329941..54c507304f9 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -369,26 +369,29 @@ Currently building Rust will also build the following external projects:
 
 * [clippy](https://github.com/rust-lang-nursery/rust-clippy)
 * [miri](https://github.com/solson/miri)
+* [rustfmt](https://github.com/rust-lang-nursery/rustfmt)
+* [rls](https://github.com/rust-lang-nursery/rls/)
 
-If your changes break one of these projects, you need to fix them by opening
-a pull request against the broken project asking to put the fix on a branch.
-Then you can disable the tool building via `src/tools/toolstate.toml`.
-Once the branch containing your fix is likely to be merged, you can point
-the affected submodule at this branch.
+We allow breakage of these tools in the nightly channel. Maintainers of these
+projects will be notified of the breakages and should fix them as soon as
+possible.
 
-Don't forget to also add your changes with
+After the external is fixed, one could add the changes with
 
-```
+```sh
 git add path/to/submodule
 ```
 
 outside the submodule.
 
-In order to prepare your PR, you can run the build locally by doing
+In order to prepare your tool-fixing PR, you can run the build locally by doing
 `./x.py build src/tools/TOOL`. If you will be editing the sources
 there, you may wish to set `submodules = false` in the `config.toml`
 to prevent `x.py` from resetting to the original branch.
 
+Breakage is not allowed in the beta and stable channels, and must be addressed
+before the PR is merged.
+
 #### Breaking Tools Built With The Compiler
 [breaking-tools-built-with-the-compiler]: #breaking-tools-built-with-the-compiler
 
@@ -406,12 +409,12 @@ tests.
 That means that, in the default state, you can't update the compiler without first
 fixing rustfmt, rls and the other tools that the compiler builds.
 
-Luckily, a feature was [added to Rust's build](https://github.com/rust-lang/rust/pull/45243)
-to make all of this easy to handle. The idea is that you mark the tools as "broken",
+Luckily, a feature was [added to Rust's build](https://github.com/rust-lang/rust/issues/45861)
+to make all of this easy to handle. The idea is that we allow these tools to be "broken",
 so that the rust-lang/rust build passes without trying to build them, then land the change
 in the compiler, wait for a nightly, and go update the tools that you broke. Once you're done
-and the tools are working again, you go back in the compiler and change the tools back
-from "broken".
+and the tools are working again, you go back in the compiler and update the tools
+so they can be distributed again.
 
 This should avoid a bunch of synchronization dances and is also much easier on contributors as
 there's no need to block on rls/rustfmt/other tools changes going upstream.
@@ -430,15 +433,10 @@ Here are those same steps in detail:
 4. (optional) Maintainers of these submodules will **not** merge the PR. The PR can't be
    merged because CI will be broken. You'll want to write a message on the PR referencing
    your change, and how the PR should be merged once your change makes it into a nightly.
-5. Update `src/tools/toolstate.toml` to indicate that the tool in question is "broken",
-   that will disable building it on CI. See the documentation in that file for the exact
-   configuration values you can use.
-6. Commit the changes to `src/tools/toolstate.toml`, **do not update submodules in your commit**,
-   and then update the PR you have for rust-lang/rust.
-7. Wait for your PR to merge.
-8. Wait for a nightly
-9. (optional) Help land your PR on the upstream repository now that your changes are in nightly.
-10. (optional) Send a PR to rust-lang/rust updating the submodule, reverting `src/tools/toolstate.toml` back to a "building" or "testing" state.
+5. Wait for your PR to merge.
+6. Wait for a nightly
+7. (optional) Help land your PR on the upstream repository now that your changes are in nightly.
+8. (optional) Send a PR to rust-lang/rust updating the submodule.
 
 #### Updating submodules
 [updating-submodules]: #updating-submodules
diff --git a/appveyor.yml b/appveyor.yml
index b8fd479d0f1..da788554049 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -5,6 +5,8 @@ environment:
   AWS_SECRET_ACCESS_KEY:
     secure: 7Y+JiquYedOAgnUU26uL0DPzrxmTtR+qIwG6rNKSuWDffqU3vVZxbGXim9QpTO80
   SCCACHE_DIGEST: f808afabb4a4eb1d7112bcb3fa6be03b61e93412890c88e177c667eb37f46353d7ec294e559b16f9f4b5e894f2185fe7670a0df15fd064889ecbd80f0c34166c
+  TOOLSTATE_REPO_ACCESS_TOKEN:
+    secure: PTZiSxJMVUZ0VnMR5i13E4OagbXfglj7pcskDQiKufVrDm13mLoI0vDJAEM35+bY
 
   # By default schannel checks revocation of certificates unlike some other SSL
   # backends, but we've historically had problems on CI where a revocation
@@ -27,8 +29,8 @@ environment:
 
   # MSVC tools tests
   - MSYS_BITS: 64
-    SCRIPT: src/ci/docker/x86_64-gnu-tools/checktools.sh x.py toolstates.json
-    RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=toolstates.json
+    SCRIPT: src/ci/docker/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstates.json windows
+    RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstates.json --enable-test-miri
 
   # 32/64-bit MinGW builds.
   #
diff --git a/src/Cargo.lock b/src/Cargo.lock
index b329a2b82eb..56a68a7ca54 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -133,8 +133,8 @@ dependencies = [
  "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -152,8 +152,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 name = "build-manifest"
 version = "0.1.0"
 dependencies = [
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -166,7 +166,7 @@ dependencies = [
 
 [[package]]
 name = "byteorder"
-version = "1.1.0"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -205,8 +205,8 @@ dependencies = [
  "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -223,8 +223,8 @@ name = "cargo_metadata"
 version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -235,8 +235,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cargo_metadata"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -272,7 +284,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "clap"
-version = "2.28.0"
+version = "2.29.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -296,8 +308,8 @@ dependencies = [
  "duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -316,8 +328,8 @@ dependencies = [
  "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -392,6 +404,7 @@ dependencies = [
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -426,8 +439,8 @@ version = "0.14.0"
 dependencies = [
  "curl 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -555,8 +568,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -816,7 +829,7 @@ dependencies = [
  "pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -903,7 +916,7 @@ version = "0.1.0"
 name = "installer"
 version = "0.0.0"
 dependencies = [
- "clap 2.28.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -943,8 +956,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -974,8 +987,8 @@ version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1102,7 +1115,7 @@ name = "mdbook"
 version = "0.0.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "clap 2.28.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "handlebars 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1111,8 +1124,8 @@ dependencies = [
  "open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "pulldown-cmark 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1163,6 +1176,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "miri"
+version = "0.1.0"
+dependencies = [
+ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "compiletest_rs 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "multiple_bins"
 version = "0.1.0"
 
@@ -1481,7 +1505,7 @@ name = "racer"
 version = "2.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "clap 2.28.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1609,9 +1633,9 @@ dependencies = [
  "rls-rustc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustfmt-nightly 0.3.2",
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustfmt-nightly 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1636,8 +1660,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1660,8 +1684,8 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1677,7 +1701,7 @@ dependencies = [
 name = "rustbook"
 version = "0.1.0"
 dependencies = [
- "clap 2.28.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "mdbook 0.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -1688,7 +1712,7 @@ dependencies = [
  "arena 0.0.0",
  "backtrace 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
  "fmt_macros 0.0.0",
  "graphviz 0.0.0",
@@ -1937,7 +1961,7 @@ name = "rustc_mir"
 version = "0.0.0"
 dependencies = [
  "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "graphviz 0.0.0",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2133,8 +2157,31 @@ dependencies = [
  "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustfmt-nightly"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cargo_metadata 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive-new 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2195,7 +2242,7 @@ version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -2205,22 +2252,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "serde"
-version = "1.0.24"
+version = "1.0.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "serde_derive"
-version = "1.0.24"
+version = "1.0.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive_internals 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive_internals 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "serde_derive_internals"
-version = "0.18.0"
+version = "0.18.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2232,7 +2279,7 @@ name = "serde_ignored"
 version = "0.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -2243,7 +2290,7 @@ dependencies = [
  "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -2336,7 +2383,7 @@ dependencies = [
  "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -2577,7 +2624,7 @@ name = "toml"
 version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -2659,7 +2706,7 @@ name = "url_serde"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -2781,12 +2828,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
 "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
 "checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32"
-"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d"
+"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
 "checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b"
 "checksum cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f56ec3e469bca7c276f2eea015aa05c5e381356febdbb0683c2580189604537"
+"checksum cargo_metadata 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20d6fb2b5574726329c85cdba0df0347fddfec3cf9c8b588f9931708280f5643"
 "checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719"
 "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
-"checksum clap 2.28.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dc34bf7d5d66268b466b9852bca925ec1d2650654dab4da081e63fd230145c2e"
+"checksum clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "110d43e343eb29f4f51c1db31beb879d546db27998577e5715270a54bcf41d3f"
 "checksum cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb"
 "checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd"
 "checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007"
@@ -2920,6 +2968,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffd34691a510938bb67fe0444fb363103c73ffb31c121d1e16bc92d8945ea8ff"
 "checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e"
 "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
+"checksum rustfmt-nightly 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a1fb3fd656e881c3403c318674d25317034d7ffd30dd36dfcf4b7e09f3bf8ebd"
 "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
 "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d"
 "checksum scopeguard 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "59a076157c1e2dc561d8de585151ee6965d910dd4dcb5dabb7ae3e83981a6c57"
@@ -2928,9 +2977,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
 "checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b"
 "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-"checksum serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "1c57ab4ec5fa85d08aaf8ed9245899d9bbdd66768945b21113b84d5f595cb6a1"
-"checksum serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "02c92ea07b6e49b959c1481804ebc9bfd92d3c459f1274c9a9546829e42a66ce"
-"checksum serde_derive_internals 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75c6aac7b99801a16db5b40b7bf0d7e4ba16e76fbf231e32a4677f271cac0603"
+"checksum serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "386122ba68c214599c44587e0c0b411e8d90894503a95425b4f9508e4317901f"
+"checksum serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "ec0bfa6c5784e7d110514448da0e1dbad41ea5514c3e68be755b23858b83a399"
+"checksum serde_derive_internals 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "730fe9f29fe8db69a601837f416e46cba07792031ed6b27557a43e49d62d89ae"
 "checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142"
 "checksum serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7cf5b0b5b4bd22eeecb7e01ac2e1225c7ef5e4272b79ee28a8392a8c8489c839"
 "checksum shared_child 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "099b38928dbe4a0a01fcd8c233183072f14a7d126a34bed05880869be66e14cc"
diff --git a/src/Cargo.toml b/src/Cargo.toml
index abe1fe5a6de..15594a54ef6 100644
--- a/src/Cargo.toml
+++ b/src/Cargo.toml
@@ -20,6 +20,7 @@ members = [
   "tools/rustdoc",
   "tools/rls",
   "tools/rustfmt",
+  "tools/miri",
   # FIXME(https://github.com/rust-lang/cargo/issues/4089): move these to exclude
   "tools/rls/test_data/bin_lib",
   "tools/rls/test_data/borrow_error",
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index eee403dcbe3..714c01aa504 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -23,7 +23,7 @@ use std::path::{PathBuf, Path};
 use std::process::Command;
 use std::io::Read;
 
-use build_helper::{self, output, BuildExpectation};
+use build_helper::{self, output};
 
 use builder::{Kind, RunConfig, ShouldRun, Builder, Compiler, Step};
 use cache::{INTERNER, Interned};
@@ -65,23 +65,19 @@ impl fmt::Display for TestKind {
     }
 }
 
-fn try_run_expecting(build: &Build, cmd: &mut Command, expect: BuildExpectation) -> bool {
+fn try_run(build: &Build, cmd: &mut Command) -> bool {
     if !build.fail_fast {
-        if !build.try_run(cmd, expect) {
+        if !build.try_run(cmd) {
             let mut failures = build.delayed_failures.borrow_mut();
             failures.push(format!("{:?}", cmd));
             return false;
         }
     } else {
-        build.run_expecting(cmd, expect);
+        build.run(cmd);
     }
     true
 }
 
-fn try_run(build: &Build, cmd: &mut Command) {
-    try_run_expecting(build, cmd, BuildExpectation::None);
-}
-
 fn try_run_quiet(build: &Build, cmd: &mut Command) {
     if !build.fail_fast {
         if !build.try_run_quiet(cmd) {
@@ -259,12 +255,8 @@ impl Step for Rls {
 
         builder.add_rustc_lib_path(compiler, &mut cargo);
 
-        if try_run_expecting(
-            build,
-            &mut cargo,
-            builder.build.config.toolstate.rls.passes(ToolState::Testing),
-        ) {
-            build.save_toolstate("rls", ToolState::Testing);
+        if try_run(build, &mut cargo) {
+            build.save_toolstate("rls", ToolState::TestPass);
         }
     }
 }
@@ -309,12 +301,8 @@ impl Step for Rustfmt {
 
         builder.add_rustc_lib_path(compiler, &mut cargo);
 
-        if try_run_expecting(
-            build,
-            &mut cargo,
-            builder.build.config.toolstate.rustfmt.passes(ToolState::Testing),
-        ) {
-            build.save_toolstate("rustfmt", ToolState::Testing);
+        if try_run(build, &mut cargo) {
+            build.save_toolstate("rustfmt", ToolState::TestPass);
         }
     }
 }
@@ -363,12 +351,8 @@ impl Step for Miri {
 
             builder.add_rustc_lib_path(compiler, &mut cargo);
 
-            if try_run_expecting(
-                build,
-                &mut cargo,
-                builder.build.config.toolstate.miri.passes(ToolState::Testing),
-            ) {
-                build.save_toolstate("miri", ToolState::Testing);
+            if try_run(build, &mut cargo) {
+                build.save_toolstate("miri", ToolState::TestPass);
             }
         } else {
             eprintln!("failed to test miri: could not build");
@@ -422,12 +406,8 @@ impl Step for Clippy {
 
             builder.add_rustc_lib_path(compiler, &mut cargo);
 
-            if try_run_expecting(
-                build,
-                &mut cargo,
-                builder.build.config.toolstate.clippy.passes(ToolState::Testing),
-            ) {
-                build.save_toolstate("clippy-driver", ToolState::Testing);
+            if try_run(build, &mut cargo) {
+                build.save_toolstate("clippy-driver", ToolState::TestPass);
             }
         } else {
             eprintln!("failed to test clippy: could not build");
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 87b1db33a7a..f3ffe9a2761 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -27,7 +27,6 @@ use util::exe;
 use cache::{INTERNER, Interned};
 use flags::Flags;
 pub use flags::Subcommand;
-use toolstate::ToolStates;
 
 /// Global configuration for the entire build and/or bootstrap.
 ///
@@ -134,8 +133,6 @@ pub struct Config {
     // These are either the stage0 downloaded binaries or the locally installed ones.
     pub initial_cargo: PathBuf,
     pub initial_rustc: PathBuf,
-
-    pub toolstate: ToolStates,
 }
 
 /// Per-target configuration stored in the global configuration structure.
@@ -348,18 +345,6 @@ impl Config {
             }
         }).unwrap_or_else(|| TomlConfig::default());
 
-        let toolstate_toml_path = config.src.join("src/tools/toolstate.toml");
-        let parse_toolstate = || -> Result<_, Box<::std::error::Error>> {
-            let mut f = File::open(toolstate_toml_path)?;
-            let mut contents = String::new();
-            f.read_to_string(&mut contents)?;
-            Ok(toml::from_str(&contents)?)
-        };
-        config.toolstate = parse_toolstate().unwrap_or_else(|err| {
-            println!("failed to parse TOML configuration 'toolstate.toml': {}", err);
-            process::exit(2);
-        });
-
         let build = toml.build.clone().unwrap_or(Build::default());
         set(&mut config.build, build.build.clone().map(|x| INTERNER.intern_string(x)));
         set(&mut config.build, flags.build);
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 78de9ec62d9..3d2795f04e2 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -1077,11 +1077,6 @@ impl Step for Rls {
         let target = self.target;
         assert!(build.config.extended);
 
-        if !builder.config.toolstate.rls.testing() {
-            println!("skipping Dist RLS stage{} ({})", stage, target);
-            return None
-        }
-
         println!("Dist RLS stage{} ({})", stage, target);
         let src = build.src.join("src/tools/rls");
         let release_num = build.release_num("rls");
@@ -1164,11 +1159,6 @@ impl Step for Rustfmt {
         let target = self.target;
         assert!(build.config.extended);
 
-        if !builder.config.toolstate.rustfmt.testing() {
-            println!("skipping Dist Rustfmt stage{} ({})", stage, target);
-            return None
-        }
-
         println!("Dist Rustfmt stage{} ({})", stage, target);
         let src = build.src.join("src/tools/rustfmt");
         let release_num = build.release_num("rustfmt");
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 2f00c313a0c..d6dc44034a7 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -143,8 +143,7 @@ use std::path::{PathBuf, Path};
 use std::process::{self, Command};
 use std::slice;
 
-use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppressed, output, mtime,
-                   BuildExpectation};
+use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppressed, output, mtime};
 
 use util::{exe, libdir, OutputFolder, CiEnv};
 
@@ -569,31 +568,24 @@ impl Build {
             .join(libdir(&self.config.build))
     }
 
-    /// Runs a command, printing out nice contextual information if its build
-    /// status is not the expected one
-    fn run_expecting(&self, cmd: &mut Command, expect: BuildExpectation) {
-        self.verbose(&format!("running: {:?}", cmd));
-        run_silent(cmd, expect)
-    }
-
     /// Runs a command, printing out nice contextual information if it fails.
     fn run(&self, cmd: &mut Command) {
-        self.run_expecting(cmd, BuildExpectation::None)
+        self.verbose(&format!("running: {:?}", cmd));
+        run_silent(cmd)
     }
 
     /// Runs a command, printing out nice contextual information if it fails.
     fn run_quiet(&self, cmd: &mut Command) {
         self.verbose(&format!("running: {:?}", cmd));
-        run_suppressed(cmd, BuildExpectation::None)
+        run_suppressed(cmd)
     }
 
-    /// Runs a command, printing out nice contextual information if its build
-    /// status is not the expected one.
-    /// Exits if the command failed to execute at all, otherwise returns whether
-    /// the expectation was met
-    fn try_run(&self, cmd: &mut Command, expect: BuildExpectation) -> bool {
+    /// Runs a command, printing out nice contextual information if it fails.
+    /// Exits if the command failed to execute at all, otherwise returns its
+    /// `status.success()`.
+    fn try_run(&self, cmd: &mut Command) -> bool {
         self.verbose(&format!("running: {:?}", cmd));
-        try_run_silent(cmd, expect)
+        try_run_silent(cmd)
     }
 
     /// Runs a command, printing out nice contextual information if it fails.
@@ -601,7 +593,7 @@ impl Build {
     /// `status.success()`.
     fn try_run_quiet(&self, cmd: &mut Command) -> bool {
         self.verbose(&format!("running: {:?}", cmd));
-        try_run_suppressed(cmd, BuildExpectation::None)
+        try_run_suppressed(cmd)
     }
 
     pub fn is_verbose(&self) -> bool {
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index fa9bdc43c37..ea055cb5d1b 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -22,7 +22,6 @@ use native;
 use channel::GitInfo;
 use cache::Interned;
 use toolstate::ToolState;
-use build_helper::BuildExpectation;
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct CleanTools {
@@ -82,7 +81,7 @@ struct ToolBuild {
     tool: &'static str,
     path: &'static str,
     mode: Mode,
-    expectation: BuildExpectation,
+    is_ext_tool: bool,
 }
 
 impl Step for ToolBuild {
@@ -102,7 +101,7 @@ impl Step for ToolBuild {
         let target = self.target;
         let tool = self.tool;
         let path = self.path;
-        let expectation = self.expectation;
+        let is_ext_tool = self.is_ext_tool;
 
         match self.mode {
             Mode::Libstd => builder.ensure(compile::Std { compiler, target }),
@@ -115,34 +114,25 @@ impl Step for ToolBuild {
         println!("Building stage{} tool {} ({})", compiler.stage, tool, target);
 
         let mut cargo = prepare_tool_cargo(builder, compiler, target, "build", path);
-        let is_expected = build.try_run(&mut cargo, expectation);
-        // If the expectation is "Failing", `try_run` returning true actually
-        // means a build-failure is successfully observed, i.e. the tool is
-        // broken. Thus the XOR here.
-        // Sorry for the complicated logic, but we can remove this expectation
-        // logic after #45861 is fully fixed.
-        build.save_toolstate(tool, if is_expected ^ (expectation == BuildExpectation::Failing) {
-            ToolState::Compiling
+        let is_expected = build.try_run(&mut cargo);
+        build.save_toolstate(tool, if is_expected {
+            ToolState::TestFail
         } else {
-            ToolState::Broken
+            ToolState::BuildFail
         });
 
         if !is_expected {
-            if expectation == BuildExpectation::None {
+            if !is_ext_tool {
                 exit(1);
             } else {
                 return None;
             }
-        }
-
-        if expectation == BuildExpectation::Succeeding || expectation == BuildExpectation::None {
+        } else {
             let cargo_out = build.cargo_out(compiler, Mode::Tool, target)
                 .join(exe(tool, &compiler.host));
             let bin = build.tools_dir(compiler).join(exe(tool, &compiler.host));
             copy(&cargo_out, &bin);
             Some(bin)
-        } else {
-            None
         }
     }
 }
@@ -251,8 +241,8 @@ macro_rules! tool {
                     tool: $tool_name,
                     mode: $mode,
                     path: $path,
-                    expectation: BuildExpectation::None,
-                }).expect("expected to build -- BuildExpectation::None")
+                    is_ext_tool: false,
+                }).expect("expected to build -- essential tool")
             }
         }
         )+
@@ -299,8 +289,8 @@ impl Step for RemoteTestServer {
             tool: "remote-test-server",
             mode: Mode::Libstd,
             path: "src/tools/remote-test-server",
-            expectation: BuildExpectation::None,
-        }).expect("expected to build -- BuildExpectation::None")
+            is_ext_tool: false,
+        }).expect("expected to build -- essential tool")
     }
 }
 
@@ -417,8 +407,8 @@ impl Step for Cargo {
             tool: "cargo",
             mode: Mode::Librustc,
             path: "src/tools/cargo",
-            expectation: BuildExpectation::None,
-        }).expect("BuildExpectation::None - expected to build")
+            is_ext_tool: false,
+        }).expect("expected to build -- essential tool")
     }
 }
 
@@ -455,14 +445,13 @@ macro_rules! tool_extended {
 
             fn run($sel, $builder: &Builder) -> Option<PathBuf> {
                 $extra_deps
-                let toolstate = $builder.build.config.toolstate.$toolstate;
                 $builder.ensure(ToolBuild {
                     compiler: $sel.compiler,
                     target: $sel.target,
                     tool: $tool_name,
                     mode: Mode::Librustc,
                     path: $path,
-                    expectation: toolstate.passes(ToolState::Compiling),
+                    is_ext_tool: true,
                 })
             }
         }
diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs
index 00dbcc86af4..f63c1988906 100644
--- a/src/bootstrap/toolstate.rs
+++ b/src/bootstrap/toolstate.rs
@@ -8,51 +8,21 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use build_helper::BuildExpectation;
-
 #[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
 /// Whether a tool can be compiled, tested or neither
 pub enum ToolState {
     /// The tool compiles successfully, but the test suite fails
-    Compiling = 1,
+    TestFail = 1,
     /// The tool compiles successfully and its test suite passes
-    Testing = 2,
+    TestPass = 2,
     /// The tool can't even be compiled
-    Broken = 0,
-}
-
-impl ToolState {
-    /// If a tool with the current toolstate should be working on
-    /// the given toolstate
-    pub fn passes(self, other: ToolState) -> BuildExpectation {
-        if self as usize >= other as usize {
-            BuildExpectation::Succeeding
-        } else {
-            BuildExpectation::Failing
-        }
-    }
-
-    pub fn testing(&self) -> bool {
-        match *self {
-            ToolState::Testing => true,
-            _ => false,
-        }
-    }
+    BuildFail = 0,
 }
 
 impl Default for ToolState {
     fn default() -> Self {
         // err on the safe side
-        ToolState::Broken
+        ToolState::BuildFail
     }
 }
-
-#[derive(Copy, Clone, Debug, Deserialize, Default)]
-/// Used to express which tools should (not) be compiled or tested.
-/// This is created from `toolstate.toml`.
-pub struct ToolStates {
-    pub miri: ToolState,
-    pub clippy: ToolState,
-    pub rls: ToolState,
-    pub rustfmt: ToolState,
-}
diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs
index 2b6e2828cfb..363bbd79544 100644
--- a/src/build_helper/lib.rs
+++ b/src/build_helper/lib.rs
@@ -35,97 +35,55 @@ macro_rules! t {
     })
 }
 
-#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
-pub enum BuildExpectation {
-    Succeeding,
-    Failing,
-    None,
-}
-
-pub fn run(cmd: &mut Command, expect: BuildExpectation) {
+pub fn run(cmd: &mut Command) {
     println!("running: {:?}", cmd);
-    run_silent(cmd, expect);
+    run_silent(cmd);
 }
 
-pub fn run_silent(cmd: &mut Command, expect: BuildExpectation) {
-    if !try_run_silent(cmd, expect) {
+pub fn run_silent(cmd: &mut Command) {
+    if !try_run_silent(cmd) {
         std::process::exit(1);
     }
 }
 
-pub fn try_run_silent(cmd: &mut Command, expect: BuildExpectation) -> bool {
+pub fn try_run_silent(cmd: &mut Command) -> bool {
     let status = match cmd.status() {
         Ok(status) => status,
         Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
                                 cmd, e)),
     };
-    process_status(
-        cmd,
-        status.success(),
-        expect,
-        || println!("\n\ncommand did not execute successfully: {:?}\n\
-                    expected success, got: {}\n\n",
-                    cmd,
-                    status))
-}
-
-fn process_status<F: FnOnce()>(
-    cmd: &Command,
-    success: bool,
-    expect: BuildExpectation,
-    f: F,
-) -> bool {
-    use BuildExpectation::*;
-    match (expect, success) {
-        (None, false) => { f(); false },
-        // Non-tool build succeeds, everything is good
-        (None, true) => true,
-        // Tool expected to work and is working
-        (Succeeding, true) => true,
-        // Tool expected to fail and is failing
-        (Failing, false) => {
-            println!("This failure is expected (see `src/tools/toolstate.toml`)");
-            true
-        },
-        // Tool expected to work, but is failing
-        (Succeeding, false) => {
-            f();
-            println!("You can disable the tool in `src/tools/toolstate.toml`");
-            false
-        },
-        // Tool expected to fail, but is working
-        (Failing, true) => {
-            println!("Expected `{:?}` to fail, but it succeeded.\n\
-                     Please adjust `src/tools/toolstate.toml` accordingly", cmd);
-            false
-        }
+    if !status.success() {
+        println!("\n\ncommand did not execute successfully: {:?}\n\
+                  expected success, got: {}\n\n",
+                 cmd,
+                 status);
     }
+    status.success()
 }
 
-pub fn run_suppressed(cmd: &mut Command, expect: BuildExpectation) {
-    if !try_run_suppressed(cmd, expect) {
+pub fn run_suppressed(cmd: &mut Command) {
+    if !try_run_suppressed(cmd) {
         std::process::exit(1);
     }
 }
 
-pub fn try_run_suppressed(cmd: &mut Command, expect: BuildExpectation) -> bool {
+pub fn try_run_suppressed(cmd: &mut Command) -> bool {
     let output = match cmd.output() {
         Ok(status) => status,
         Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
                                 cmd, e)),
     };
-    process_status(
-        cmd,
-        output.status.success(),
-        expect,
-        || println!("\n\ncommand did not execute successfully: {:?}\n\
+    if !output.status.success() {
+        println!("\n\ncommand did not execute successfully: {:?}\n\
                   expected success, got: {}\n\n\
                   stdout ----\n{}\n\
                   stderr ----\n{}\n\n",
                  cmd,
                  output.status,
                  String::from_utf8_lossy(&output.stdout),
-                 String::from_utf8_lossy(&output.stderr)))
+                 String::from_utf8_lossy(&output.stderr));
+    }
+    output.status.success()
 }
 
 pub fn gnu_target(target: &str) -> String {
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index a863e1a2d5d..f743c976f91 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -99,6 +99,7 @@ exec docker \
   --env LOCAL_USER_ID=`id -u` \
   --env TRAVIS \
   --env TRAVIS_BRANCH \
+  --env TOOLSTATE_REPO_ACCESS_TOKEN \
   --volume "$HOME/.cargo:/cargo" \
   --volume "$HOME/rustsrc:$HOME/rustsrc" \
   --init \
diff --git a/src/ci/docker/x86_64-gnu-aux/Dockerfile b/src/ci/docker/x86_64-gnu-aux/Dockerfile
index 62c55f48067..44bee199911 100644
--- a/src/ci/docker/x86_64-gnu-aux/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-aux/Dockerfile
@@ -21,5 +21,5 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --enable-test-miri
+ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
 ENV RUST_CHECK_TARGET check-aux
diff --git a/src/ci/docker/x86_64-gnu-tools/Dockerfile b/src/ci/docker/x86_64-gnu-tools/Dockerfile
index fffad1c42df..8975d419d20 100644
--- a/src/ci/docker/x86_64-gnu-tools/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-tools/Dockerfile
@@ -18,6 +18,10 @@ COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
 COPY x86_64-gnu-tools/checktools.sh /tmp/
+COPY x86_64-gnu-tools/repo.sh /tmp/
 
-ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --save-toolstates=/tmp/toolstates.json
-ENV SCRIPT /tmp/checktools.sh ../x.py /tmp/toolstates.json
+ENV RUST_CONFIGURE_ARGS \
+  --build=x86_64-unknown-linux-gnu \
+  --enable-test-miri \
+  --save-toolstates=/tmp/toolstates.json
+ENV SCRIPT /tmp/checktools.sh ../x.py /tmp/toolstates.json linux
diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh
index bf39bc28a67..0d40863c092 100755
--- a/src/ci/docker/x86_64-gnu-tools/checktools.sh
+++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh
@@ -13,7 +13,9 @@
 set -eu
 
 X_PY="$1"
-TOOLSTATE_FILE="$2"
+TOOLSTATE_FILE="$(realpath $2)"
+OS="$3"
+COMMIT="$(git rev-parse HEAD)"
 
 touch "$TOOLSTATE_FILE"
 
@@ -23,17 +25,22 @@ python2.7 "$X_PY" test --no-fail-fast \
     src/tools/rustfmt \
     src/tools/miri \
     src/tools/clippy
-TEST_RESULT=$?
 set -e
 
-# FIXME: Upload this file to the repository.
 cat "$TOOLSTATE_FILE"
 
-# FIXME: After we can properly inform dev-tool maintainers about failure,
-#        comment out the `exit 0` below.
 if [ "$RUST_RELEASE_CHANNEL" = nightly ]; then
-    # exit 0
-    true
+    . "$(dirname $0)/repo.sh"
+    MESSAGE_FILE=$(mktemp -t msg.XXXXXX)
+    echo "($OS CI update)" > "$MESSAGE_FILE"
+    commit_toolstate_change "$MESSAGE_FILE" \
+        sed -i "1 a\\
+$COMMIT\t$(cat "$TOOLSTATE_FILE")
+" "history/$OS.tsv"
+    rm -f "$MESSAGE_FILE"
+    exit 0
 fi
 
-exit $TEST_RESULT
+if grep -q fail "$TOOLSTATE_FILE"; then
+    exit 4
+fi
diff --git a/src/ci/docker/x86_64-gnu-tools/repo.sh b/src/ci/docker/x86_64-gnu-tools/repo.sh
new file mode 100644
index 00000000000..c10afef753e
--- /dev/null
+++ b/src/ci/docker/x86_64-gnu-tools/repo.sh
@@ -0,0 +1,90 @@
+#!/bin/sh
+
+# 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.
+
+# This file provides the function `commit_toolstate_change` for pushing a change
+# to the `rust-toolstate` repository.
+#
+# The function relies on a GitHub bot user, which should have a Personal access
+# token defined in the environment variable $TOOLSTATE_REPO_ACCESS_TOKEN. If for
+# some reason you need to change the token, please update `.travis.yml` and
+# `appveyor.yml`:
+#
+#   1. Generate a new Personal access token:
+#
+#       * Login to the bot account, and go to Settings -> Developer settings ->
+#           Personal access tokens
+#       * Click "Generate new token"
+#       * Enable the "public_repo" permission, then click "Generate token"
+#       * Copy the generated token (should be a 40-digit hexadecimal number).
+#           Save it somewhere secure, as the token would be gone once you leave
+#           the page.
+#
+#   2. Encrypt the token for Travis CI
+#
+#       * Install the `travis` tool locally (`gem install travis`).
+#       * Encrypt the token:
+#           ```
+#           travis -r rust-lang/rust encrypt \
+#                   TOOLSTATE_REPO_ACCESS_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+#           ```
+#       * Copy output to replace the existing one in `.travis.yml`.
+#       * Details of this step can be found in
+#           <https://docs.travis-ci.com/user/encryption-keys/>
+#
+#   3. Encrypt the token for AppVeyor
+#
+#       * Login to AppVeyor using your main account, and login as the rust-lang
+#           organization.
+#       * Open the ["Encrypt data" tool](https://ci.appveyor.com/tools/encrypt)
+#       * Paste the 40-digit token into the "Value to encrypt" box, then click
+#           "Encrypt"
+#       * Copy the output to replace the existing one in `appveyor.yml`.
+#       * Details of this step can be found in
+#           <https://www.appveyor.com/docs/how-to/git-push/>
+#
+#   4. Replace the email address below if the bot account identity is changed
+#
+#       * See <https://help.github.com/articles/about-commit-email-addresses/>
+#           if a private email by GitHub is wanted.
+
+commit_toolstate_change() {
+    OLDFLAGS="$-"
+    set -eu
+
+    git config --global user.email '34210020+rust-toolstate-update@users.noreply.github.com'
+    git config --global user.name 'Rust Toolstate Update'
+    git config --global credential.helper store
+    printf 'https://%s:x-oauth-basic@github.com\n' "$TOOLSTATE_REPO_ACCESS_TOKEN" \
+        > "$HOME/.git-credentials"
+    git clone --depth=1 https://github.com/rust-lang-nursery/rust-toolstate.git
+
+    cd rust-toolstate
+    FAILURE=1
+    MESSAGE_FILE="$1"
+    shift
+    for RETRY_COUNT in 1 2 3 4 5; do
+        "$@"
+        # `git commit` failing means nothing to commit.
+        FAILURE=0
+        git commit -a -F "$MESSAGE_FILE" || break
+        # On failure randomly sleep for 0 to 3 seconds as a crude way to introduce jittering.
+        git push origin master && break || sleep $(LC_ALL=C tr -cd 0-3 < /dev/urandom | head -c 1)
+        FAILURE=1
+        git fetch origin master
+        git reset --hard origin/master
+    done
+    cd ..
+
+    set +eu
+    set "-$OLDFLAGS"
+    return $FAILURE
+}
diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs
index de5006ad396..649cd6e8e85 100644
--- a/src/liballoc_jemalloc/build.rs
+++ b/src/liballoc_jemalloc/build.rs
@@ -16,7 +16,7 @@ extern crate cc;
 use std::env;
 use std::path::PathBuf;
 use std::process::Command;
-use build_helper::{run, native_lib_boilerplate, BuildExpectation};
+use build_helper::{run, native_lib_boilerplate};
 
 fn main() {
     // FIXME: This is a hack to support building targets that don't
@@ -113,7 +113,7 @@ fn main() {
         cmd.arg("--with-lg-quantum=4");
     }
 
-    run(&mut cmd, BuildExpectation::None);
+    run(&mut cmd);
 
     let mut make = Command::new(build_helper::make(&host));
     make.current_dir(&native.out_dir)
@@ -130,7 +130,7 @@ fn main() {
             .arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set"));
     }
 
-    run(&mut make, BuildExpectation::None);
+    run(&mut make);
 
     // The pthread_atfork symbols is used by jemalloc on android but the really
     // old android we're building on doesn't have them defined, so just make
diff --git a/src/libstd/build.rs b/src/libstd/build.rs
index 06f11c8deb4..8a28105ff81 100644
--- a/src/libstd/build.rs
+++ b/src/libstd/build.rs
@@ -14,7 +14,7 @@ extern crate build_helper;
 
 use std::env;
 use std::process::Command;
-use build_helper::{run, native_lib_boilerplate, BuildExpectation};
+use build_helper::{run, native_lib_boilerplate};
 
 fn main() {
     let target = env::var("TARGET").expect("TARGET was not set");
@@ -91,14 +91,11 @@ fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> {
                 .arg("--disable-host-shared")
                 .arg(format!("--host={}", build_helper::gnu_target(target)))
                 .arg(format!("--build={}", build_helper::gnu_target(host)))
-                .env("CFLAGS", env::var("CFLAGS").unwrap_or_default() + " -fvisibility=hidden"),
-        BuildExpectation::None);
+                .env("CFLAGS", env::var("CFLAGS").unwrap_or_default() + " -fvisibility=hidden"));
 
     run(Command::new(build_helper::make(host))
                 .current_dir(&native.out_dir)
                 .arg(format!("INCDIR={}", native.src_dir.display()))
-                .arg("-j").arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set")),
-        BuildExpectation::None);
-
+                .arg("-j").arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set")));
     Ok(())
 }
diff --git a/src/tools/miri b/src/tools/miri
-Subproject 2671cf34a58b11f995add8402e75c1cd94ed051
+Subproject 919604e1ead8294c8ca14f101be4380ea1ea370
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
new file mode 100755
index 00000000000..b90947e5a43
--- /dev/null
+++ b/src/tools/publish_toolstate.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# 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.
+
+import sys
+import re
+import json
+import copy
+import datetime
+import collections
+
+# List of people to ping when the status of a tool changed.
+MAINTAINERS = {
+    'miri': '@oli-obk @RalfJung @eddyb',
+    'clippy-driver': '@Manishearth @llogiq @mcarton @oli-obk',
+    'rls': '@nrc',
+    'rustfmt': '@nrc',
+}
+
+
+def read_current_status(current_commit, path):
+    '''Reads build status of `current_commit` from content of `history/*.tsv`
+    '''
+    with open(path, 'rU') as f:
+        for line in f:
+            (commit, status) = line.split('\t', 1)
+            if commit == current_commit:
+                return json.loads(status)
+    return {}
+
+
+def update_latest(current_commit, relevant_pr_number, current_datetime):
+    '''Updates `_data/latest.json` to match build result of the given commit.
+    '''
+    with open('_data/latest.json', 'rb+') as f:
+        latest = json.load(f, object_pairs_hook=collections.OrderedDict)
+
+        current_status = {
+            os: read_current_status(current_commit, 'history/' + os + '.tsv')
+            for os in ['windows', 'linux']
+        }
+
+        slug = 'rust-lang/rust'
+        message = '📣 Toolstate changed by {}!\n\nTested on commit {}@{}.\n\n' \
+            .format(relevant_pr_number, slug, current_commit)
+        anything_changed = False
+        for status in latest:
+            tool = status['tool']
+            changed = False
+
+            for os, s in current_status.items():
+                old = status[os]
+                new = s.get(tool, old)
+                status[os] = new
+                if new > old:
+                    changed = True
+                    message += '🎉 {} on {}: {} → {}.\n' \
+                        .format(tool, os, old, new)
+                elif new < old:
+                    changed = True
+                    message += '💔 {} on {}: {} → {} (cc {}).\n' \
+                        .format(tool, os, old, new, MAINTAINERS[tool])
+
+            if changed:
+                status['commit'] = current_commit
+                status['datetime'] = current_datetime
+                anything_changed = True
+
+        if not anything_changed:
+            return ''
+
+        f.seek(0)
+        f.truncate(0)
+        json.dump(latest, f, indent=4, separators=(',', ': '))
+        return message
+
+
+if __name__ == '__main__':
+    cur_commit = sys.argv[1]
+    cur_datetime = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
+    cur_commit_msg = sys.argv[2]
+    save_message_to_path = sys.argv[3]
+
+    relevant_pr_match = re.search('#[0-9]+', cur_commit_msg)
+    if relevant_pr_match:
+        relevant_pr_number = 'rust-lang/rust' + relevant_pr_match.group(0)
+    else:
+        relevant_pr_number = '<unknown PR>'
+
+    message = update_latest(cur_commit, relevant_pr_number, cur_datetime)
+    if message:
+        print(message)
+        with open(save_message_to_path, 'w') as f:
+            f.write(message)
+    else:
+        print('<Nothing changed>')
diff --git a/src/tools/toolstate.toml b/src/tools/toolstate.toml
deleted file mode 100644
index 6901343e367..00000000000
--- a/src/tools/toolstate.toml
+++ /dev/null
@@ -1,36 +0,0 @@
-# This file reflects the current status of all tools which are allowed
-# to fail without failing the build.
-#
-# There are three states a tool can be in:
-# 1. Broken: The tool doesn't build
-# 2. Compiling: The tool builds but its tests are failing
-# 3. Testing: The tool builds and its tests are passing
-#
-# In the future there will be further states like "Distributing", which
-# configures whether the tool is included in the Rust distribution.
-#
-# If a tool was working before your PR but is broken now, consider
-# opening a PR against the tool so that it works with your changes.
-# If the tool stops compiling, change its state to `Broken`. If it
-# still builds, change it to `Compiling`.
-# How to do that is described in
-# "CONTRIBUTING.md#External Dependencies". If the effort required is not
-# warranted (e.g. due to the tool abusing some API that you changed, and
-# fixing the tool would mean a significant refactoring) remember to ping
-# the tool authors, so they can fix it, instead of being surprised by the
-# breakage.
-#
-# Each tool has a list of people to ping
-
-# ping @oli-obk @RalfJung @eddyb
-miri = "Broken"
-
-# ping @Manishearth @llogiq @mcarton @oli-obk
-clippy = "Broken"
-
-# ping @nrc
-rls = "Broken"
-
-# ping @nrc
-# when breaking rustfmt, always break rls as well
-rustfmt = "Broken"