about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMark <MarkMcCaskey@users.noreply.github.com>2017-08-31 12:49:48 -0400
committerGitHub <noreply@github.com>2017-08-31 12:49:48 -0400
commite572d85e00befa25b5912c0076ef8831a4f9a9f0 (patch)
tree9dc00bb5150d55b456da8ac57251e8354f3d740e
parent1d69c985be6a196e4a30f6deb0d8347aaad62662 (diff)
parent97b01abf3d222523d0db4f79c13ed45e7fef27e3 (diff)
downloadrust-e572d85e00befa25b5912c0076ef8831a4f9a9f0.tar.gz
rust-e572d85e00befa25b5912c0076ef8831a4f9a9f0.zip
Merge branch 'master' into master
-rw-r--r--src/Cargo.lock306
-rw-r--r--src/doc/unstable-book/src/language-features/generators.md2
-rw-r--r--src/doc/unstable-book/src/library-features/splice.md3
-rw-r--r--src/liballoc/macros.rs29
-rw-r--r--src/liballoc/string.rs109
-rw-r--r--src/liballoc/tests/string.rs22
-rw-r--r--src/libcore/macros.rs47
m---------src/liblibc0
-rw-r--r--src/libproc_macro/Cargo.toml1
-rw-r--r--src/libproc_macro/diagnostic.rs134
-rw-r--r--src/libproc_macro/lib.rs22
-rw-r--r--src/librustc/dep_graph/dep_node.rs4
-rw-r--r--src/librustc/ich/hcx.rs6
-rw-r--r--src/librustc/middle/region.rs76
-rw-r--r--src/librustc/traits/mod.rs4
-rw-r--r--src/librustc/traits/select.rs3
-rw-r--r--src/librustc/traits/specialize/mod.rs18
-rw-r--r--src/librustc/traits/specialize/specialization_graph.rs6
-rw-r--r--src/librustc/ty/context.rs36
-rw-r--r--src/librustc/ty/maps.rs39
-rw-r--r--src/librustc/ty/mod.rs1
-rw-r--r--src/librustc_errors/diagnostic.rs2
-rw-r--r--src/librustc_errors/diagnostic_builder.rs13
-rw-r--r--src/librustc_metadata/encoder.rs5
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs71
-rw-r--r--src/librustc_passes/consts.rs37
-rw-r--r--src/librustc_privacy/lib.rs5
-rw-r--r--src/librustc_resolve/macros.rs3
-rw-r--r--src/librustc_typeck/check/method/probe.rs8
-rw-r--r--src/librustdoc/Cargo.toml1
-rw-r--r--src/librustdoc/html/render.rs33
-rw-r--r--src/librustdoc/lib.rs1
-rw-r--r--src/librustdoc/visit_ast.rs5
-rw-r--r--src/libstd/io/mod.rs2
-rw-r--r--src/libstd/macros.rs122
-rw-r--r--src/libstd/os/raw.rs6
-rw-r--r--src/libstd/sys/unix/fd.rs28
-rw-r--r--src/libstd/sys/unix/fs.rs2
-rw-r--r--src/libstd/sys/unix/process/process_unix.rs5
-rw-r--r--src/test/compile-fail/check-static-values-constraints.rs3
-rw-r--r--src/test/compile-fail/static-drop-scope.rs26
-rw-r--r--src/test/run-make/sysroot-crates-are-unstable/Makefile37
-rw-r--r--src/test/run-make/sysroot-crates-are-unstable/test.py71
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs28
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-on-trait.rs25
-rw-r--r--src/test/run-pass/rvalue-static-promotion.rs18
-rw-r--r--src/test/rustdoc/issue-29449.rs6
-rw-r--r--src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs56
-rw-r--r--src/test/ui-fulldeps/proc-macro/three-equals.rs38
-rw-r--r--src/test/ui-fulldeps/proc-macro/three-equals.stderr48
-rw-r--r--src/tools/tidy/src/deps.rs6
51 files changed, 1266 insertions, 313 deletions
diff --git a/src/Cargo.lock b/src/Cargo.lock
index cb55fb602e3..d21bb62b742 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -176,7 +176,7 @@ dependencies = [
 [[package]]
 name = "cargo"
 version = "0.22.0"
-source = "git+https://github.com/rust-lang/cargo#bcf3997b1fa177afc5b6c632a6fbbf6cc75df427"
+source = "git+https://github.com/rust-lang/cargo#3d3f2c05d742e5f907e951aa8849b03f0bc1a895"
 replace = "cargo 0.22.0"
 
 [[package]]
@@ -313,6 +313,14 @@ name = "completion"
 version = "0.1.0"
 
 [[package]]
+name = "conv"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "core"
 version = "0.0.0"
 dependencies = [
@@ -354,6 +362,30 @@ version = "0.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "cssparser"
+version = "0.13.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "procedural-masquerade 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cssparser-macros"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "procedural-masquerade 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "curl"
 version = "0.4.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -381,6 +413,11 @@ dependencies = [
 ]
 
 [[package]]
+name = "custom_derive"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "dbghelp-sys"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -390,6 +427,14 @@ dependencies = [
 ]
 
 [[package]]
+name = "debug_unreachable"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "derive-new"
 version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -417,7 +462,7 @@ dependencies = [
 
 [[package]]
 name = "dtoa"
-version = "0.4.1"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -523,8 +568,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "futf"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "futures"
-version = "0.1.14"
+version = "0.1.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -635,6 +689,26 @@ name = "hover"
 version = "0.1.0"
 
 [[package]]
+name = "html-diff"
+version = "0.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "kuchiki 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "html5ever"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "markup5ever 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "idna"
 version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -688,7 +762,7 @@ dependencies = [
 
 [[package]]
 name = "itoa"
-version = "0.3.1"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -697,7 +771,7 @@ version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -705,7 +779,7 @@ name = "jsonrpc-core"
 version = "7.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.15 (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.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -722,6 +796,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "kuchiki"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "html5ever 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "languageserver-types"
 version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -809,6 +894,41 @@ dependencies = [
 ]
 
 [[package]]
+name = "mac"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "magenta"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "magenta-sys"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "markup5ever"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "string_cache 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tendril 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "matches"
 version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -902,7 +1022,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -1030,19 +1150,64 @@ version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "phf"
+version = "0.7.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "phf_codegen"
+version = "0.7.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "phf_generator"
+version = "0.7.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.7.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "pkg-config"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "precomputed-hash"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "proc_macro"
 version = "0.0.0"
 dependencies = [
+ "rustc_errors 0.0.0",
  "syntax 0.0.0",
  "syntax_pos 0.0.0",
 ]
 
 [[package]]
+name = "procedural-masquerade"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "profiler_builtins"
 version = "0.0.0"
 dependencies = [
@@ -1106,10 +1271,11 @@ dependencies = [
 
 [[package]]
 name = "rand"
-version = "0.3.15"
+version = "0.3.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1634,6 +1800,7 @@ dependencies = [
  "build_helper 0.1.0",
  "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "html-diff 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1687,6 +1854,21 @@ version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "selectors"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "precomputed-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "semver"
 version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1737,8 +1919,8 @@ name = "serde_json"
 version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1753,6 +1935,16 @@ version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "siphasher"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "smallvec"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "socket2"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1802,6 +1994,36 @@ dependencies = [
 ]
 
 [[package]]
+name = "string_cache"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 0.2.8 (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.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.11 (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)",
+]
+
+[[package]]
+name = "string_cache_codegen"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "string_cache_shared"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "strings"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1923,7 +2145,17 @@ name = "tempdir"
 version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tendril"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "futf 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "utf-8 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -2060,6 +2292,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "unreachable"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unreachable"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -2102,6 +2342,14 @@ dependencies = [
 ]
 
 [[package]]
+name = "utf-8"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "utf8-ranges"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2202,16 +2450,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
 "checksum clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2267a8fdd4dce6956ba6649e130f62fb279026e5e84b92aa939ac8f85ce3f9f0"
 "checksum cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ebbb35d3dc9cd09497168f33de1acb79b265d350ab0ac34133b98f8509af1f"
+"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299"
 "checksum core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5909502e547762013619f4c4e01cc7393c20fe2d52d7fa471c1210adb2320dc7"
 "checksum core-foundation-sys 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bc9fb3d6cb663e6fd7cf1c63f9b144ee2b1e4a78595a0451dd34bff85b9a3387"
 "checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"
+"checksum cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef6124306e5ebc5ab11891d063aeafdd0cdc308079b708c8b566125f3680292b"
+"checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df"
 "checksum curl 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7034c534a1d7d22f7971d6088aa9d281d219ef724026c3428092500f41ae9c2c"
 "checksum curl-sys 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d5481162dc4f424d088581db2f979fa7d4c238fe9794595de61d8d7522e277de"
+"checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9"
 "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
+"checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3"
 "checksum derive-new 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41be6ca3b99e0c0483fb2389685448f650459c3ecbe4e18d7705d8010ec4ab8e"
 "checksum diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0a515461b6c8c08419850ced27bc29e86166dcdcde8fbe76f8b1f0589bb49472"
 "checksum docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b5b93718f8b3e5544fcc914c43de828ca6c6ace23e0332c6080a2977b49787a"
-"checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90"
+"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
 "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
 "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
 "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
@@ -2222,7 +2475,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
 "checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d"
 "checksum fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ab76cfd2aaa59b7bf6688ad9ba15bbae64bff97f04ea02144cfd3443e5c2866"
-"checksum futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4b63a4792d4f8f686defe3b39b92127fea6344de5d38202b2ee5a11bbbf29d6a"
+"checksum futf 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "51f93f3de6ba1794dcd5810b3546d004600a59a98266487c8407bc4b24e398f3"
+"checksum futures 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a82bdc62350ca9d7974c760e9665102fc9d740992a528c2254aa930e53b783c4"
 "checksum gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)" = "120d07f202dcc3f72859422563522b66fe6463a4c513df062874daad05f85f0a"
 "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
 "checksum git2 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aa01936ac96555c083c0e8553f672616274408d9d3fc5b8696603fbf63ff43ee"
@@ -2233,12 +2487,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum handlebars 0.26.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fbba80e74e9591a5f6a4ffff6b7f9d645759a896e431cfbdc853e9184370294a"
 "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa"
 "checksum home 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f25ae61099d8f3fee8b483df0bd4ecccf4b2731897aad40d50eca1b641fe6db"
+"checksum html-diff 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "17dbc64943cae56925cf9ff22e8c76ccdb8010f6675a1a56660ec7e597ffa7c7"
+"checksum html5ever 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a49d5001dd1bddf042ea41ed4e0a671d50b1bf187e66b349d7ec613bdce4ad90"
 "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
 "checksum ignore 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b3fcaf2365eb14b28ec7603c98c06cc531f19de9eb283d89a3dff8417c8c99f5"
-"checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c"
+"checksum itoa 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f74cf6ca1bdbc28496a2b9798ab7fccc2ca5a42cace95bb2b219577216a5fb90"
 "checksum jobserver 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "443ae8bc0af6c106e6e8b77e04684faecc1a5ce94e058f4c2b0a037b0ea1b133"
 "checksum jsonrpc-core 7.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "903e5eee845f3d83c1436d12848d97b1247cf850ff06a8e1db2f1ce3543af2cf"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
+"checksum kuchiki 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ef2ea4f2f7883cd7c6772b06c14abca01a2cc1f75c426cebffcf6b3b925ef9fc"
 "checksum languageserver-types 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d52e477b23bf52cd3ca0f9fc6c5d14be954eec97e3b9cdfbd962d911bd533caf"
 "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf"
 "checksum libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "8a014d9226c2cc402676fbe9ea2e15dd5222cd1dd57f576b5b283178c944a264"
@@ -2247,6 +2504,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "3fdd64ef8ee652185674455c1d450b83cbc8ad895625d543b5324d923f82e4d8"
 "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b"
 "checksum lzma-sys 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "66b2e318eb97ab84f05725471f90c52a09c964053a5899a13fd0165acc26d00b"
+"checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
+"checksum magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf0336886480e671965f794bc9b6fce88503563013d1bfb7a502c81fe3ac527"
+"checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699"
+"checksum markup5ever 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff834ac7123c6a37826747e5ca09db41fd7a83126792021c2e636ad174bb77d3"
 "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
 "checksum mdbook 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "22911d86cde6f80fa9f0fb2a68bbbde85d97af4fe0ce267141c83a4187d28700"
 "checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
@@ -2269,14 +2530,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
 "checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356"
 "checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8"
+"checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc"
+"checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f"
+"checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03"
+"checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2"
 "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
+"checksum precomputed-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf1fc3616b3ef726a847f2cd2388c646ef6a1f1ba4835c2629004da48184150"
+"checksum procedural-masquerade 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c93cdc1fb30af9ddf3debc4afbdb0f35126cbd99daa229dd76cdd5349b41d989"
 "checksum psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "abcd5d1a07d360e29727f757a9decb3ce8bc6e0efa8969cfaad669a8317a2478"
 "checksum pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ab1e588ef8efd702c7ed9d2bd774db5e6f4d878bb5a1a9f371828fbdff6973"
 "checksum quick-error 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c36987d4978eb1be2e422b1e0423a557923a5c3e7e6f31d5699e9aafaefa469"
 "checksum quote 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5cf478fe1006dbcc72567121d23dbdae5f1632386068c5c86ff4f645628504"
 "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
 "checksum racer 2.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "f120c7510ef7aff254aeb06067fb6fac573ec96a1660e194787cf9dced412bf0"
-"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
+"checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf"
 "checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
 "checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b"
 "checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
@@ -2291,6 +2558,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "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"
+"checksum selectors 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3c89b1c6a3c029c82263f7dd2d44d0005ee7374eb09e254ab59dede4353a8c0"
 "checksum semver 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fdd61b85a0fa777f7fb7c454b9189b2941b110d1385ce84d7f76efdf1606a85"
 "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
 "checksum serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f7726f29ddf9731b17ff113c461e362c381d9d69433f79de4f3dd572488823e9"
@@ -2299,8 +2567,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum serde_ignored 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c10e798e4405d7dcec3658989e35ee6706f730a9ed7c1184d5ebd84317e82f46"
 "checksum serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "48b04779552e92037212c3615370f6bd57a40ebba7f20e554ff9f55e41a69a7b"
 "checksum shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5cc96481d54583947bfe88bf30c23d53f883c6cd0145368b69989d97b84ef8"
+"checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
+"checksum smallvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f8266519bc1d17d0b5b16f6c21295625d562841c708f6376f49028a43e9c11e"
 "checksum socket2 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4daf80fcf54186fac4fe049e0b39d36a5cfde69a11a06413e61e77f553cccf9a"
 "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
+"checksum string_cache 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "413fc7852aeeb5472f1986ef755f561ddf0c789d3d796e65f0b6fe293ecd4ef8"
+"checksum string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "479cde50c3539481f33906a387f2bd17c8e87cb848c35b6021d41fb81ff9b4d7"
+"checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
 "checksum strings 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da75d8bf2c4d210d63dd09581a041b036001f9f6e03d9b151dbff810fb7ba26a"
 "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
 "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
@@ -2311,6 +2584,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76a302e717e348aa372ff577791c3832395650073b8d8432f8b3cb170b34afde"
 "checksum tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "281285b717926caa919ad905ef89c63d75805c7d89437fb873100925a53f2b1b"
 "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
+"checksum tendril 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1b72f8e2f5b73b65c315b1a70c730f24b9d7a25f39e98de8acbe2bb795caea"
 "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
 "checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
 "checksum termcolor 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9a5193a56b8d82014662c4b933dea6bec851daf018a2b01722e007daaf5f9dca"
@@ -2327,10 +2601,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
 "checksum unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "36dff09cafb4ec7c8cf0023eb0b686cb6ce65499116a12201c9e11840ca01beb"
 "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
+"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"
 "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
 "checksum url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb819346883532a271eb626deb43c4a1bb4c4dd47c519bd78137c3e72a4fe27"
 "checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea"
 "checksum userenv-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d28ea36bbd9192d75bd9fa9b39f96ddb986eaee824adae5d53b6e51919b2f3"
+"checksum utf-8 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b6f923c601c7ac48ef1d66f7d5b5b2d9a7ba9c51333ab75a3ddf8d0309185a56"
 "checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
 "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
 "checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b"
diff --git a/src/doc/unstable-book/src/language-features/generators.md b/src/doc/unstable-book/src/language-features/generators.md
index 3b7b77e2c3e..7a559a7bec8 100644
--- a/src/doc/unstable-book/src/language-features/generators.md
+++ b/src/doc/unstable-book/src/language-features/generators.md
@@ -2,7 +2,7 @@
 
 The tracking issue for this feature is: [#43122]
 
-[#34511]: https://github.com/rust-lang/rust/issues/43122
+[#43122]: https://github.com/rust-lang/rust/issues/43122
 
 ------------------------
 
diff --git a/src/doc/unstable-book/src/library-features/splice.md b/src/doc/unstable-book/src/library-features/splice.md
index ca7f78a8f79..dae4475257a 100644
--- a/src/doc/unstable-book/src/library-features/splice.md
+++ b/src/doc/unstable-book/src/library-features/splice.md
@@ -18,7 +18,6 @@ let mut s = String::from("α is alpha, β is beta");
 let beta_offset = s.find('β').unwrap_or(s.len());
 
 // Replace the range up until the β from the string
-let t: String = s.splice(..beta_offset, "Α is capital alpha; ").collect();
-assert_eq!(t, "α is alpha, ");
+s.splice(..beta_offset, "Α is capital alpha; ");
 assert_eq!(s, "Α is capital alpha; β is beta");
 ```
\ No newline at end of file
diff --git a/src/liballoc/macros.rs b/src/liballoc/macros.rs
index 763f04fcd0d..43ebaa4fbdb 100644
--- a/src/liballoc/macros.rs
+++ b/src/liballoc/macros.rs
@@ -8,12 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-/// Creates a `Vec` containing the arguments.
+/// Creates a [`Vec`] containing the arguments.
 ///
 /// `vec!` allows `Vec`s to be defined with the same syntax as array expressions.
 /// There are two forms of this macro:
 ///
-/// - Create a `Vec` containing a given list of elements:
+/// - Create a [`Vec`] containing a given list of elements:
 ///
 /// ```
 /// let v = vec![1, 2, 3];
@@ -22,7 +22,7 @@
 /// assert_eq!(v[2], 3);
 /// ```
 ///
-/// - Create a `Vec` from a given element and size:
+/// - Create a [`Vec`] from a given element and size:
 ///
 /// ```
 /// let v = vec![1; 3];
@@ -30,14 +30,17 @@
 /// ```
 ///
 /// Note that unlike array expressions this syntax supports all elements
-/// which implement `Clone` and the number of elements doesn't have to be
+/// which implement [`Clone`] and the number of elements doesn't have to be
 /// a constant.
 ///
-/// This will use `clone()` to duplicate an expression, so one should be careful
+/// This will use `clone` to duplicate an expression, so one should be careful
 /// using this with types having a nonstandard `Clone` implementation. For
 /// example, `vec![Rc::new(1); 5]` will create a vector of five references
 /// to the same boxed integer value, not five references pointing to independently
 /// boxed integers.
+///
+/// [`Vec`]: ../std/vec/struct.Vec.html
+/// [`Clone`]: ../std/clone/trait.Clone.html
 #[cfg(not(test))]
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -67,10 +70,22 @@ macro_rules! vec {
     ($($x:expr,)*) => (vec![$($x),*])
 }
 
-/// Use the syntax described in `std::fmt` to create a value of type `String`.
-/// See [`std::fmt`][fmt] for more information.
+/// Creates a `String` using interpolation of runtime expressions.
+///
+/// The first argument `format!` recieves is a format string.  This must be a string
+/// literal.  The power of the formatting string is in the `{}`s contained.
+///
+/// Additional parameters passed to `format!` replace the `{}`s within the
+/// formatting string in the order given unless named or positional parameters
+/// are used, see [`std::fmt`][fmt] for more information.
+///
+/// A common use for `format!` is concatenation and interpolation of strings.
+/// The same convention is used with [`print!`] and [`write!`] macros,
+/// depending on the intended destination of the string.
 ///
 /// [fmt]: ../std/fmt/index.html
+/// [`print!`]: ../std/macro.print.html
+/// [`write!`]: ../std/macro.write.html
 ///
 /// # Panics
 ///
diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs
index b1919c7c968..ddb23b2ef37 100644
--- a/src/liballoc/string.rs
+++ b/src/liballoc/string.rs
@@ -1392,11 +1392,11 @@ impl String {
     }
 
     /// Creates a splicing iterator that removes the specified range in the string,
-    /// replaces with the given string, and yields the removed chars.
-    /// The given string doesn’t need to be the same length as the range.
+    /// and replaces it with the given string.
+    /// The given string doesn't need to be the same length as the range.
     ///
-    /// Note: The element range is removed when the [`Splice`] is dropped,
-    /// even if the iterator is not consumed until the end.
+    /// Note: Unlike [`Vec::splice`], the replacement happens eagerly, and this
+    /// method does not return the removed chars.
     ///
     /// # Panics
     ///
@@ -1404,7 +1404,7 @@ impl String {
     /// boundary, or if they're out of bounds.
     ///
     /// [`char`]: ../../std/primitive.char.html
-    /// [`Splice`]: ../../std/string/struct.Splice.html
+    /// [`Vec::splice`]: ../../std/vec/struct.Vec.html#method.splice
     ///
     /// # Examples
     ///
@@ -1416,45 +1416,32 @@ impl String {
     /// let beta_offset = s.find('β').unwrap_or(s.len());
     ///
     /// // Replace the range up until the β from the string
-    /// let t: String = s.splice(..beta_offset, "Α is capital alpha; ").collect();
-    /// assert_eq!(t, "α is alpha, ");
+    /// s.splice(..beta_offset, "Α is capital alpha; ");
     /// assert_eq!(s, "Α is capital alpha; β is beta");
     /// ```
     #[unstable(feature = "splice", reason = "recently added", issue = "32310")]
-    pub fn splice<'a, 'b, R>(&'a mut self, range: R, replace_with: &'b str) -> Splice<'a, 'b>
+    pub fn splice<R>(&mut self, range: R, replace_with: &str)
         where R: RangeArgument<usize>
     {
         // Memory safety
         //
         // The String version of Splice does not have the memory safety issues
         // of the vector version. The data is just plain bytes.
-        // Because the range removal happens in Drop, if the Splice iterator is leaked,
-        // the removal will not happen.
-        let len = self.len();
-        let start = match range.start() {
-             Included(&n) => n,
-             Excluded(&n) => n + 1,
-             Unbounded => 0,
+
+        match range.start() {
+             Included(&n) => assert!(self.is_char_boundary(n)),
+             Excluded(&n) => assert!(self.is_char_boundary(n + 1)),
+             Unbounded => {},
         };
-        let end = match range.end() {
-             Included(&n) => n + 1,
-             Excluded(&n) => n,
-             Unbounded => len,
+        match range.end() {
+             Included(&n) => assert!(self.is_char_boundary(n + 1)),
+             Excluded(&n) => assert!(self.is_char_boundary(n)),
+             Unbounded => {},
         };
 
-        // Take out two simultaneous borrows. The &mut String won't be accessed
-        // until iteration is over, in Drop.
-        let self_ptr = self as *mut _;
-        // slicing does the appropriate bounds checks
-        let chars_iter = self[start..end].chars();
-
-        Splice {
-            start,
-            end,
-            iter: chars_iter,
-            string: self_ptr,
-            replace_with,
-        }
+        unsafe {
+            self.as_mut_vec()
+        }.splice(range, replace_with.bytes());
     }
 
     /// Converts this `String` into a [`Box`]`<`[`str`]`>`.
@@ -2241,61 +2228,3 @@ impl<'a> DoubleEndedIterator for Drain<'a> {
 
 #[unstable(feature = "fused", issue = "35602")]
 impl<'a> FusedIterator for Drain<'a> {}
-
-/// A splicing iterator for `String`.
-///
-/// This struct is created by the [`splice()`] method on [`String`]. See its
-/// documentation for more.
-///
-/// [`splice()`]: struct.String.html#method.splice
-/// [`String`]: struct.String.html
-#[derive(Debug)]
-#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
-pub struct Splice<'a, 'b> {
-    /// Will be used as &'a mut String in the destructor
-    string: *mut String,
-    /// Start of part to remove
-    start: usize,
-    /// End of part to remove
-    end: usize,
-    /// Current remaining range to remove
-    iter: Chars<'a>,
-    replace_with: &'b str,
-}
-
-#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
-unsafe impl<'a, 'b> Sync for Splice<'a, 'b> {}
-#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
-unsafe impl<'a, 'b> Send for Splice<'a, 'b> {}
-
-#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
-impl<'a, 'b> Drop for Splice<'a, 'b> {
-    fn drop(&mut self) {
-        unsafe {
-            let vec = (*self.string).as_mut_vec();
-            vec.splice(self.start..self.end, self.replace_with.bytes());
-        }
-    }
-}
-
-#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
-impl<'a, 'b> Iterator for Splice<'a, 'b> {
-    type Item = char;
-
-    #[inline]
-    fn next(&mut self) -> Option<char> {
-        self.iter.next()
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-}
-
-#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
-impl<'a, 'b> DoubleEndedIterator for Splice<'a, 'b> {
-    #[inline]
-    fn next_back(&mut self) -> Option<char> {
-        self.iter.next_back()
-    }
-}
diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs
index f5c124c6b44..6aba18ddf49 100644
--- a/src/liballoc/tests/string.rs
+++ b/src/liballoc/tests/string.rs
@@ -442,9 +442,8 @@ fn test_drain() {
 #[test]
 fn test_splice() {
     let mut s = "Hello, world!".to_owned();
-    let t: String = s.splice(7..12, "世界").collect();
+    s.splice(7..12, "世界");
     assert_eq!(s, "Hello, 世界!");
-    assert_eq!(t, "world");
 }
 
 #[test]
@@ -457,12 +456,10 @@ fn test_splice_char_boundary() {
 #[test]
 fn test_splice_inclusive_range() {
     let mut v = String::from("12345");
-    let t: String = v.splice(2...3, "789").collect();
+    v.splice(2...3, "789");
     assert_eq!(v, "127895");
-    assert_eq!(t, "34");
-    let t2: String = v.splice(1...2, "A").collect();
+    v.splice(1...2, "A");
     assert_eq!(v, "1A895");
-    assert_eq!(t2, "27");
 }
 
 #[test]
@@ -482,24 +479,15 @@ fn test_splice_inclusive_out_of_bounds() {
 #[test]
 fn test_splice_empty() {
     let mut s = String::from("12345");
-    let t: String = s.splice(1..2, "").collect();
+    s.splice(1..2, "");
     assert_eq!(s, "1345");
-    assert_eq!(t, "2");
 }
 
 #[test]
 fn test_splice_unbounded() {
     let mut s = String::from("12345");
-    let t: String = s.splice(.., "").collect();
+    s.splice(.., "");
     assert_eq!(s, "");
-    assert_eq!(t, "12345");
-}
-
-#[test]
-fn test_splice_forget() {
-    let mut s = String::from("12345");
-    ::std::mem::forget(s.splice(2..4, "789"));
-    assert_eq!(s, "12345");
 }
 
 #[test]
diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs
index 375c1f10db2..2cd049ac153 100644
--- a/src/libcore/macros.rs
+++ b/src/libcore/macros.rs
@@ -62,11 +62,13 @@ macro_rules! panic {
 /// # Custom Messages
 ///
 /// This macro has a second form, where a custom panic message can
-/// be provided with or without arguments for formatting.
+/// be provided with or without arguments for formatting.  See [`std::fmt`]
+/// for syntax for this form.
 ///
 /// [`panic!`]: macro.panic.html
 /// [`debug_assert!`]: macro.debug_assert.html
-/// [testing]: ../book/first-edition/testing.html
+/// [testing]: ../book/second-edition/ch11-01-writing-tests.html#checking-results-with-the-assert-macro
+/// [`std::fmt`]: ../std/fmt/index.html
 ///
 /// # Examples
 ///
@@ -252,13 +254,15 @@ macro_rules! debug_assert {
 /// On panic, this macro will print the values of the expressions with their
 /// debug representations.
 ///
-/// Unlike `assert_eq!`, `debug_assert_eq!` statements are only enabled in non
+/// Unlike [`assert_eq!`], `debug_assert_eq!` statements are only enabled in non
 /// optimized builds by default. An optimized build will omit all
 /// `debug_assert_eq!` statements unless `-C debug-assertions` is passed to the
 /// compiler. This makes `debug_assert_eq!` useful for checks that are too
 /// expensive to be present in a release build but may be helpful during
 /// development.
 ///
+/// [`assert_eq!`]: ../std/macro.assert_eq.html
+///
 /// # Examples
 ///
 /// ```
@@ -277,13 +281,15 @@ macro_rules! debug_assert_eq {
 /// On panic, this macro will print the values of the expressions with their
 /// debug representations.
 ///
-/// Unlike `assert_ne!`, `debug_assert_ne!` statements are only enabled in non
+/// Unlike [`assert_ne!`], `debug_assert_ne!` statements are only enabled in non
 /// optimized builds by default. An optimized build will omit all
 /// `debug_assert_ne!` statements unless `-C debug-assertions` is passed to the
 /// compiler. This makes `debug_assert_ne!` useful for checks that are too
 /// expensive to be present in a release build but may be helpful during
 /// development.
 ///
+/// [`assert_ne!`]: ../std/macro.assert_ne.html
+///
 /// # Examples
 ///
 /// ```
@@ -300,10 +306,9 @@ macro_rules! debug_assert_ne {
 /// Helper macro for reducing boilerplate code for matching `Result` together
 /// with converting downstream errors.
 ///
-/// Prefer using `?` syntax to `try!`. `?` is built in to the language and is
-/// more succinct than `try!`. It is the standard method for error propagation.
+/// The `?` operator was added to replace `try!` and should be used instead.
 ///
-/// `try!` matches the given `Result`. In case of the `Ok` variant, the
+/// `try!` matches the given [`Result`]. In case of the `Ok` variant, the
 /// expression has the value of the wrapped value.
 ///
 /// In case of the `Err` variant, it retrieves the inner error. `try!` then
@@ -312,7 +317,9 @@ macro_rules! debug_assert_ne {
 /// error is then immediately returned.
 ///
 /// Because of the early return, `try!` can only be used in functions that
-/// return `Result`.
+/// return [`Result`].
+///
+/// [`Result`]: ../std/result/enum.Result.html
 ///
 /// # Examples
 ///
@@ -331,12 +338,19 @@ macro_rules! debug_assert_ne {
 ///     }
 /// }
 ///
+/// // The prefered method of quick returning Errors
+/// fn write_to_file_question() -> Result<(), MyError> {
+///     let mut file = File::create("my_best_friends.txt")?;
+///     Ok(())
+/// }
+///
+/// // The previous method of quick returning Errors
 /// fn write_to_file_using_try() -> Result<(), MyError> {
 ///     let mut file = try!(File::create("my_best_friends.txt"));
 ///     try!(file.write_all(b"This is a list of my best friends."));
-///     println!("I wrote to the file");
 ///     Ok(())
 /// }
+///
 /// // This is equivalent to:
 /// fn write_to_file_using_match() -> Result<(), MyError> {
 ///     let mut file = try!(File::create("my_best_friends.txt"));
@@ -344,7 +358,6 @@ macro_rules! debug_assert_ne {
 ///         Ok(v) => v,
 ///         Err(e) => return Err(From::from(e)),
 ///     }
-///     println!("I wrote to the file");
 ///     Ok(())
 /// }
 /// ```
@@ -365,7 +378,7 @@ macro_rules! try {
 /// formatted according to the specified format string and the result will be passed to the writer.
 /// The writer may be any value with a `write_fmt` method; generally this comes from an
 /// implementation of either the [`std::fmt::Write`] or the [`std::io::Write`] trait. The macro
-/// returns whatever the 'write_fmt' method returns; commonly a [`std::fmt::Result`], or an
+/// returns whatever the `write_fmt` method returns; commonly a [`std::fmt::Result`], or an
 /// [`io::Result`].
 ///
 /// See [`std::fmt`] for more information on the format string syntax.
@@ -470,10 +483,20 @@ macro_rules! writeln {
 /// * Loops that dynamically terminate.
 /// * Iterators that dynamically terminate.
 ///
+/// If the determination that the code is unreachable proves incorrect, the
+/// program immediately terminates with a [`panic!`].  The function [`unreachable`],
+/// which belongs to the [`std::intrinsics`] module, informs the compilier to
+/// optimize the code out of the release version entirely.
+///
+/// [`panic!`]:  ../std/macro.panic.html
+/// [`unreachable`]: ../std/intrinsics/fn.unreachable.html
+/// [`std::intrinsics`]: ../std/intrinsics/index.html
+///
 /// # Panics
 ///
-/// This will always [panic!](macro.panic.html)
+/// This will always [`panic!`]
 ///
+/// [`panic!`]: ../std/macro.panic.html
 /// # Examples
 ///
 /// Match arms:
diff --git a/src/liblibc b/src/liblibc
-Subproject 2a5b50b7f7f539a0fd201331d6c1e0534aa332f
+Subproject 04a5e75c99dc92afab490c38fcbbeac9b4bc810
diff --git a/src/libproc_macro/Cargo.toml b/src/libproc_macro/Cargo.toml
index 1b5141773a9..cfd83e348a8 100644
--- a/src/libproc_macro/Cargo.toml
+++ b/src/libproc_macro/Cargo.toml
@@ -10,3 +10,4 @@ crate-type = ["dylib"]
 [dependencies]
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
+rustc_errors = { path = "../librustc_errors" }
diff --git a/src/libproc_macro/diagnostic.rs b/src/libproc_macro/diagnostic.rs
new file mode 100644
index 00000000000..c39aec896e6
--- /dev/null
+++ b/src/libproc_macro/diagnostic.rs
@@ -0,0 +1,134 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use Span;
+
+use rustc_errors as rustc;
+
+/// An enum representing a diagnostic level.
+#[unstable(feature = "proc_macro", issue = "38356")]
+#[derive(Copy, Clone, Debug)]
+pub enum Level {
+    /// An error.
+    Error,
+    /// A warning.
+    Warning,
+    /// A note.
+    Note,
+    /// A help message.
+    Help,
+    #[doc(hidden)]
+    __Nonexhaustive,
+}
+
+/// A structure representing a diagnostic message and associated children
+/// messages.
+#[unstable(feature = "proc_macro", issue = "38356")]
+#[derive(Clone, Debug)]
+pub struct Diagnostic {
+    level: Level,
+    message: String,
+    span: Option<Span>,
+    children: Vec<Diagnostic>
+}
+
+macro_rules! diagnostic_child_methods {
+    ($spanned:ident, $regular:ident, $level:expr) => (
+        /// Add a new child diagnostic message to `self` with the level
+        /// identified by this methods name with the given `span` and `message`.
+        #[unstable(feature = "proc_macro", issue = "38356")]
+        pub fn $spanned<T: Into<String>>(mut self, span: Span, message: T) -> Diagnostic {
+            self.children.push(Diagnostic::spanned(span, $level, message));
+            self
+        }
+
+        /// Add a new child diagnostic message to `self` with the level
+        /// identified by this method's name with the given `message`.
+        #[unstable(feature = "proc_macro", issue = "38356")]
+        pub fn $regular<T: Into<String>>(mut self, message: T) -> Diagnostic {
+            self.children.push(Diagnostic::new($level, message));
+            self
+        }
+    )
+}
+
+impl Diagnostic {
+    /// Create a new diagnostic with the given `level` and `message`.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn new<T: Into<String>>(level: Level, message: T) -> Diagnostic {
+        Diagnostic {
+            level: level,
+            message: message.into(),
+            span: None,
+            children: vec![]
+        }
+    }
+
+    /// Create a new diagnostic with the given `level` and `message` pointing to
+    /// the given `span`.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn spanned<T: Into<String>>(span: Span, level: Level, message: T) -> Diagnostic {
+        Diagnostic {
+            level: level,
+            message: message.into(),
+            span: Some(span),
+            children: vec![]
+        }
+    }
+
+    diagnostic_child_methods!(span_error, error, Level::Error);
+    diagnostic_child_methods!(span_warning, warning, Level::Warning);
+    diagnostic_child_methods!(span_note, note, Level::Note);
+    diagnostic_child_methods!(span_help, help, Level::Help);
+
+    /// Returns the diagnostic `level` for `self`.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn level(&self) -> Level {
+        self.level
+    }
+
+    /// Emit the diagnostic.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn emit(self) {
+        ::__internal::with_sess(move |(sess, _)| {
+            let handler = &sess.span_diagnostic;
+            let level = __internal::level_to_internal_level(self.level);
+            let mut diag = rustc::DiagnosticBuilder::new(handler, level, &*self.message);
+
+            if let Some(span) = self.span {
+                diag.set_span(span.0);
+            }
+
+            for child in self.children {
+                let span = child.span.map(|s| s.0);
+                let level = __internal::level_to_internal_level(child.level);
+                diag.sub(level, &*child.message, span);
+            }
+
+            diag.emit();
+        });
+    }
+}
+
+#[unstable(feature = "proc_macro_internals", issue = "27812")]
+#[doc(hidden)]
+pub mod __internal {
+    use super::{Level, rustc};
+
+    pub fn level_to_internal_level(level: Level) -> rustc::Level {
+        match level {
+            Level::Error => rustc::Level::Error,
+            Level::Warning => rustc::Level::Warning,
+            Level::Note => rustc::Level::Note,
+            Level::Help => rustc::Level::Help,
+            Level::__Nonexhaustive => unreachable!("Level::__Nonexhaustive")
+        }
+    }
+}
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index a86854cdbc7..e403e2a00c9 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -42,6 +42,12 @@
 #[macro_use]
 extern crate syntax;
 extern crate syntax_pos;
+extern crate rustc_errors;
+
+mod diagnostic;
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+pub use diagnostic::{Diagnostic, Level};
 
 use std::{ascii, fmt, iter};
 use std::str::FromStr;
@@ -188,12 +194,28 @@ pub fn quote_span(span: Span) -> TokenStream {
     TokenStream(quote::Quote::quote(&span.0))
 }
 
+macro_rules! diagnostic_method {
+    ($name:ident, $level:expr) => (
+        /// Create a new `Diagnostic` with the given `message` at the span
+        /// `self`.
+        #[unstable(feature = "proc_macro", issue = "38356")]
+        pub fn $name<T: Into<String>>(self, message: T) -> Diagnostic {
+            Diagnostic::spanned(self, $level, message)
+        }
+    )
+}
+
 impl Span {
     /// The span of the invocation of the current procedural macro.
     #[unstable(feature = "proc_macro", issue = "38356")]
     pub fn call_site() -> Span {
         ::__internal::with_sess(|(_, mark)| Span(mark.expn_info().unwrap().call_site))
     }
+
+    diagnostic_method!(error, Level::Error);
+    diagnostic_method!(warning, Level::Warning);
+    diagnostic_method!(note, Level::Note);
+    diagnostic_method!(help, Level::Help);
 }
 
 /// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`).
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 9a80db472db..ea827fb3139 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -62,6 +62,7 @@
 
 use hir::def_id::{CrateNum, DefId};
 use hir::map::DefPathHash;
+use hir::HirId;
 
 use ich::Fingerprint;
 use ty::{TyCtxt, Instance, InstanceDef};
@@ -527,6 +528,9 @@ define_dep_nodes!( <'tcx>
     [] HasGlobalAllocator(DefId),
     [] ExternCrate(DefId),
     [] LintLevels,
+    [] Specializes { impl1: DefId, impl2: DefId },
+    [] InScopeTraits(HirId),
+    [] ModuleExports(HirId),
 );
 
 trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs
index 544c824f83c..9c841022fcb 100644
--- a/src/librustc/ich/hcx.rs
+++ b/src/librustc/ich/hcx.rs
@@ -205,13 +205,15 @@ impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ast::N
                 // corresponding entry in the `trait_map` we need to hash that.
                 // Make sure we don't ignore too much by checking that there is
                 // no entry in a debug_assert!().
-                debug_assert!(hcx.tcx.trait_map.get(self).is_none());
+                let hir_id = hcx.tcx.hir.node_to_hir_id(*self);
+                debug_assert!(hcx.tcx.in_scope_traits(hir_id).is_none());
             }
             NodeIdHashingMode::HashDefPath => {
                 hcx.tcx.hir.definitions().node_to_hir_id(*self).hash_stable(hcx, hasher);
             }
             NodeIdHashingMode::HashTraitsInScope => {
-                if let Some(traits) = hcx.tcx.trait_map.get(self) {
+                let hir_id = hcx.tcx.hir.node_to_hir_id(*self);
+                if let Some(traits) = hcx.tcx.in_scope_traits(hir_id) {
                     // The ordering of the candidates is not fixed. So we hash
                     // the def-ids and then sort them and hash the collection.
                     let mut candidates: AccumulateVec<[_; 8]> =
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index a611b3b937b..8b01d5045c6 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -223,7 +223,9 @@ pub struct RegionMaps {
     /// table, the appropriate cleanup scope is the innermost
     /// enclosing statement, conditional expression, or repeating
     /// block (see `terminating_scopes`).
-    rvalue_scopes: NodeMap<CodeExtent>,
+    /// In constants, None is used to indicate that certain expressions
+    /// escape into 'static and should have no local cleanup scope.
+    rvalue_scopes: NodeMap<Option<CodeExtent>>,
 
     /// Encodes the hierarchy of fn bodies. Every fn body (including
     /// closures) forms its own distinct region hierarchy, rooted in
@@ -358,9 +360,11 @@ impl<'tcx> RegionMaps {
         self.var_map.insert(var, lifetime);
     }
 
-    fn record_rvalue_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent) {
+    fn record_rvalue_scope(&mut self, var: ast::NodeId, lifetime: Option<CodeExtent>) {
         debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime);
-        assert!(var != lifetime.node_id());
+        if let Some(lifetime) = lifetime {
+            assert!(var != lifetime.node_id());
+        }
         self.rvalue_scopes.insert(var, lifetime);
     }
 
@@ -389,7 +393,7 @@ impl<'tcx> RegionMaps {
         // check for a designated rvalue scope
         if let Some(&s) = self.rvalue_scopes.get(&expr_id) {
             debug!("temporary_scope({:?}) = {:?} [custom]", expr_id, s);
-            return Some(s);
+            return s;
         }
 
         // else, locate the innermost terminating scope
@@ -803,16 +807,11 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
 }
 
 fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
-                           local: &'tcx hir::Local) {
-    debug!("resolve_local(local.id={:?},local.init={:?})",
-           local.id,local.init.is_some());
+                           pat: Option<&'tcx hir::Pat>,
+                           init: Option<&'tcx hir::Expr>) {
+    debug!("resolve_local(pat={:?}, init={:?})", pat, init);
 
-    // For convenience in trans, associate with the local-id the var
-    // scope that will be used for any bindings declared in this
-    // pattern.
     let blk_scope = visitor.cx.var_parent;
-    let blk_scope = blk_scope.expect("locals must be within a block");
-    visitor.region_maps.record_var_scope(local.id, blk_scope);
 
     // As an exception to the normal rules governing temporary
     // lifetimes, initializers in a let have a temporary lifetime
@@ -872,15 +871,22 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
     //
     // FIXME(#6308) -- Note that `[]` patterns work more smoothly post-DST.
 
-    if let Some(ref expr) = local.init {
+    if let Some(expr) = init {
         record_rvalue_scope_if_borrow_expr(visitor, &expr, blk_scope);
 
-        if is_binding_pat(&local.pat) {
-            record_rvalue_scope(visitor, &expr, blk_scope);
+        if let Some(pat) = pat {
+            if is_binding_pat(pat) {
+                record_rvalue_scope(visitor, &expr, blk_scope);
+            }
         }
     }
 
-    intravisit::walk_local(visitor, local);
+    if let Some(pat) = pat {
+        visitor.visit_pat(pat);
+    }
+    if let Some(expr) = init {
+        visitor.visit_expr(expr);
+    }
 
     /// True if `pat` match the `P&` nonterminal:
     ///
@@ -954,7 +960,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
     fn record_rvalue_scope_if_borrow_expr<'a, 'tcx>(
         visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
         expr: &hir::Expr,
-        blk_id: CodeExtent)
+        blk_id: Option<CodeExtent>)
     {
         match expr.node {
             hir::ExprAddrOf(_, ref subexpr) => {
@@ -1004,7 +1010,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
     /// Note: ET is intended to match "rvalues or lvalues based on rvalues".
     fn record_rvalue_scope<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
                                      expr: &hir::Expr,
-                                     blk_scope: CodeExtent) {
+                                     blk_scope: Option<CodeExtent>) {
         let mut expr = expr;
         loop {
             // Note: give all the expressions matching `ET` with the
@@ -1077,12 +1083,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
 
         let outer_cx = self.cx;
         let outer_ts = mem::replace(&mut self.terminating_scopes, NodeSet());
-
-        // Only functions have an outer terminating (drop) scope,
-        // while temporaries in constant initializers are 'static.
-        if let MirSource::Fn(_) = MirSource::from_node(self.tcx, owner_id) {
-            self.terminating_scopes.insert(body_id.node_id);
-        }
+        self.terminating_scopes.insert(body_id.node_id);
 
         if let Some(root_id) = self.cx.root_id {
             self.region_maps.record_fn_parent(body_id.node_id, root_id);
@@ -1100,7 +1101,30 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
 
         // The body of the every fn is a root scope.
         self.cx.parent = self.cx.var_parent;
-        self.visit_expr(&body.value);
+        if let MirSource::Fn(_) = MirSource::from_node(self.tcx, owner_id) {
+            self.visit_expr(&body.value);
+        } else {
+            // Only functions have an outer terminating (drop) scope, while
+            // temporaries in constant initializers may be 'static, but only
+            // according to rvalue lifetime semantics, using the same
+            // syntactical rules used for let initializers.
+            //
+            // E.g. in `let x = &f();`, the temporary holding the result from
+            // the `f()` call lives for the entirety of the surrounding block.
+            //
+            // Similarly, `const X: ... = &f();` would have the result of `f()`
+            // live for `'static`, implying (if Drop restrictions on constants
+            // ever get lifted) that the value *could* have a destructor, but
+            // it'd get leaked instead of the destructor running during the
+            // evaluation of `X` (if at all allowed by CTFE).
+            //
+            // However, `const Y: ... = g(&f());`, like `let y = g(&f());`,
+            // would *not* let the `f()` temporary escape into an outer scope
+            // (i.e. `'static`), which means that after `g` returns, it drops,
+            // and all the associated destruction scope rules apply.
+            self.cx.var_parent = None;
+            resolve_local(self, None, Some(&body.value));
+        }
 
         // Restore context we had at the start.
         self.cx = outer_cx;
@@ -1120,7 +1144,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
         resolve_expr(self, ex);
     }
     fn visit_local(&mut self, l: &'tcx Local) {
-        resolve_local(self, l);
+        resolve_local(self, Some(&l.pat), l.init.as_ref().map(|e| &**e));
     }
 }
 
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 228c9761756..019f0a70911 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -38,7 +38,7 @@ pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal};
 pub use self::object_safety::ObjectSafetyViolation;
 pub use self::object_safety::MethodViolationCode;
 pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
-pub use self::specialize::{OverlapError, specialization_graph, specializes, translate_substs};
+pub use self::specialize::{OverlapError, specialization_graph, translate_substs};
 pub use self::specialize::{SpecializesCache, find_associated_item};
 pub use self::util::elaborate_predicates;
 pub use self::util::supertraits;
@@ -831,6 +831,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
     *providers = ty::maps::Providers {
         is_object_safe: object_safety::is_object_safe_provider,
         specialization_graph_of: specialize::specialization_graph_provider,
+        specializes: specialize::specializes,
         ..*providers
     };
 }
@@ -839,6 +840,7 @@ pub fn provide_extern(providers: &mut ty::maps::Providers) {
     *providers = ty::maps::Providers {
         is_object_safe: object_safety::is_object_safe_provider,
         specialization_graph_of: specialize::specialization_graph_provider,
+        specializes: specialize::specializes,
         ..*providers
     };
 }
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 4e9398e5058..726e5d83428 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -36,7 +36,6 @@ use infer;
 use infer::{InferCtxt, InferOk, TypeFreshener};
 use ty::subst::{Kind, Subst, Substs};
 use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
-use traits;
 use ty::fast_reject;
 use ty::relate::TypeRelation;
 use middle::lang_items;
@@ -1865,7 +1864,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 if other.evaluation == EvaluatedToOk {
                     if let ImplCandidate(victim_def) = victim.candidate {
                         let tcx = self.tcx().global_tcx();
-                        return traits::specializes(tcx, other_def, victim_def) ||
+                        return tcx.specializes((other_def, victim_def)) ||
                             tcx.impls_are_allowed_to_overlap(other_def, victim_def);
                     }
                 }
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 7c916e162a4..2dd6ca4b5a9 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -150,15 +150,12 @@ pub fn find_associated_item<'a, 'tcx>(
 /// Specialization is determined by the sets of types to which the impls apply;
 /// impl1 specializes impl2 if it applies to a subset of the types impl2 applies
 /// to.
-pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                             impl1_def_id: DefId,
-                             impl2_def_id: DefId) -> bool {
+pub(super) fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                    (impl1_def_id, impl2_def_id): (DefId, DefId))
+    -> bool
+{
     debug!("specializes({:?}, {:?})", impl1_def_id, impl2_def_id);
 
-    if let Some(r) = tcx.specializes_cache.borrow().check(impl1_def_id, impl2_def_id) {
-        return r;
-    }
-
     // The feature gate should prevent introducing new specializations, but not
     // taking advantage of upstream ones.
     if !tcx.sess.features.borrow().specialization &&
@@ -188,7 +185,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
 
     // Create a infcx, taking the predicates of impl1 as assumptions:
-    let result = tcx.infer_ctxt().enter(|infcx| {
+    tcx.infer_ctxt().enter(|infcx| {
         // Normalize the trait reference. The WF rules ought to ensure
         // that this always succeeds.
         let impl1_trait_ref =
@@ -204,10 +201,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
         // Attempt to prove that impl2 applies, given all of the above.
         fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
-    });
-
-    tcx.specializes_cache.borrow_mut().insert(impl1_def_id, impl2_def_id, result);
-    result
+    })
 }
 
 /// Attempt to fulfill all obligations of `target_impl` after unification with
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs
index 8b31cb599e4..5242accceab 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc/traits/specialize/specialization_graph.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use super::{OverlapError, specializes};
+use super::OverlapError;
 
 use hir::def_id::DefId;
 use traits;
@@ -118,8 +118,8 @@ impl<'a, 'gcx, 'tcx> Children {
                         return Ok((false, false));
                     }
 
-                    let le = specializes(tcx, impl_def_id, possible_sibling);
-                    let ge = specializes(tcx, possible_sibling, impl_def_id);
+                    let le = tcx.specializes((impl_def_id, possible_sibling));
+                    let ge = tcx.specializes((possible_sibling, impl_def_id));
 
                     if le == ge {
                         // overlap, but no specialization; error out
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 1fe53882c70..14d47d5d195 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -14,8 +14,8 @@ use dep_graph::DepGraph;
 use errors::DiagnosticBuilder;
 use session::Session;
 use middle;
-use hir::{TraitMap};
-use hir::def::{Def, ExportMap};
+use hir::{TraitCandidate, HirId};
+use hir::def::{Def, Export};
 use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use hir::map as hir_map;
 use hir::map::DefPathHash;
@@ -808,8 +808,6 @@ pub struct GlobalCtxt<'tcx> {
 
     pub sess: &'tcx Session,
 
-    pub specializes_cache: RefCell<traits::SpecializesCache>,
-
     pub trans_trait_caches: traits::trans::TransTraitCaches<'tcx>,
 
     pub dep_graph: DepGraph,
@@ -819,10 +817,10 @@ pub struct GlobalCtxt<'tcx> {
 
     /// Map indicating what traits are in scope for places where this
     /// is relevant; generated by resolve.
-    pub trait_map: TraitMap,
+    trait_map: FxHashMap<HirId, Rc<Vec<TraitCandidate>>>,
 
     /// Export map produced by name resolution.
-    pub export_map: ExportMap,
+    export_map: FxHashMap<HirId, Rc<Vec<Export>>>,
 
     pub named_region_map: resolve_lifetime::NamedRegionMap,
 
@@ -1072,14 +1070,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         tls::enter_global(GlobalCtxt {
             sess: s,
             trans_trait_caches: traits::trans::TransTraitCaches::new(dep_graph.clone()),
-            specializes_cache: RefCell::new(traits::SpecializesCache::new()),
             global_arenas: arenas,
             global_interners: interners,
             dep_graph: dep_graph.clone(),
             types: common_types,
             named_region_map,
-            trait_map: resolutions.trait_map,
-            export_map: resolutions.export_map,
+            trait_map: resolutions.trait_map.into_iter().map(|(k, v)| {
+                (hir.node_to_hir_id(k), Rc::new(v))
+            }).collect(),
+            export_map: resolutions.export_map.into_iter().map(|(k, v)| {
+                (hir.node_to_hir_id(k), Rc::new(v))
+            }).collect(),
             hir,
             def_path_hash_to_def_id,
             maps: maps::Maps::new(providers),
@@ -1997,3 +1998,20 @@ impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> {
         Ok(f(&iter.collect::<Result<AccumulateVec<[_; 8]>, _>>()?))
     }
 }
+
+fn in_scope_traits<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: HirId)
+    -> Option<Rc<Vec<TraitCandidate>>>
+{
+    tcx.gcx.trait_map.get(&id).cloned()
+}
+
+fn module_exports<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: HirId)
+    -> Option<Rc<Vec<Export>>>
+{
+    tcx.gcx.export_map.get(&id).cloned()
+}
+
+pub fn provide(providers: &mut ty::maps::Providers) {
+    providers.in_scope_traits = in_scope_traits;
+    providers.module_exports = module_exports;
+}
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 03e093c5a50..da81bfbb0dc 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -11,8 +11,8 @@
 use dep_graph::{DepConstructor, DepNode, DepNodeIndex};
 use errors::{Diagnostic, DiagnosticBuilder};
 use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
-use hir::def::Def;
-use hir;
+use hir::def::{Def, Export};
+use hir::{self, TraitCandidate, HirId};
 use lint;
 use middle::const_val;
 use middle::cstore::{ExternCrate, LinkagePreference};
@@ -80,6 +80,15 @@ impl Key for CrateNum {
     }
 }
 
+impl Key for HirId {
+    fn map_crate(&self) -> CrateNum {
+        LOCAL_CRATE
+    }
+    fn default_span(&self, _tcx: TyCtxt) -> Span {
+        DUMMY_SP
+    }
+}
+
 impl Key for DefId {
     fn map_crate(&self) -> CrateNum {
         self.krate
@@ -540,6 +549,24 @@ impl<'tcx> QueryDescription for queries::lint_levels<'tcx> {
     }
 }
 
+impl<'tcx> QueryDescription for queries::specializes<'tcx> {
+    fn describe(_tcx: TyCtxt, _: (DefId, DefId)) -> String {
+        format!("computing whether impls specialize one another")
+    }
+}
+
+impl<'tcx> QueryDescription for queries::in_scope_traits<'tcx> {
+    fn describe(_tcx: TyCtxt, _: HirId) -> String {
+        format!("fetching the traits in scope at a particular ast node")
+    }
+}
+
+impl<'tcx> QueryDescription for queries::module_exports<'tcx> {
+    fn describe(_tcx: TyCtxt, _: HirId) -> String {
+        format!("fetching the exported items for a module")
+    }
+}
+
 // If enabled, send a message to the profile-queries thread
 macro_rules! profq_msg {
     ($tcx:expr, $msg:expr) => {
@@ -1108,6 +1135,10 @@ define_maps! { <'tcx>
     [] extern_crate: ExternCrate(DefId) -> Rc<Option<ExternCrate>>,
 
     [] lint_levels: lint_levels(CrateNum) -> Rc<lint::LintLevelMap>,
+
+    [] specializes: specializes_node((DefId, DefId)) -> bool,
+    [] in_scope_traits: InScopeTraits(HirId) -> Option<Rc<Vec<TraitCandidate>>>,
+    [] module_exports: ModuleExports(HirId) -> Option<Rc<Vec<Export>>>,
 }
 
 fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
@@ -1183,3 +1214,7 @@ fn layout_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'
 fn lint_levels<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
     DepConstructor::LintLevels
 }
+
+fn specializes_node<'tcx>((a, b): (DefId, DefId)) -> DepConstructor<'tcx> {
+    DepConstructor::Specializes { impl1: a, impl2: b }
+}
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 8cabb88ee98..ca735599a0d 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -2517,6 +2517,7 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
 pub fn provide(providers: &mut ty::maps::Providers) {
     util::provide(providers);
+    context::provide(providers);
     *providers = ty::maps::Providers {
         associated_item,
         associated_item_def_ids,
diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs
index 0f063542383..9aae188f9ec 100644
--- a/src/librustc_errors/diagnostic.rs
+++ b/src/librustc_errors/diagnostic.rs
@@ -288,7 +288,7 @@ impl Diagnostic {
 
     /// Convenience function for internal use, clients should use one of the
     /// public methods above.
-    fn sub(&mut self,
+    pub(crate) fn sub(&mut self,
            level: Level,
            message: &str,
            span: MultiSpan,
diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs
index 2c8d8b4691f..2cd433bfe3a 100644
--- a/src/librustc_errors/diagnostic_builder.rs
+++ b/src/librustc_errors/diagnostic_builder.rs
@@ -110,6 +110,19 @@ impl<'a> DiagnosticBuilder<'a> {
         // }
     }
 
+    /// Convenience function for internal use, clients should use one of the
+    /// span_* methods instead.
+    pub fn sub<S: Into<MultiSpan>>(
+        &mut self,
+        level: Level,
+        message: &str,
+        span: Option<S>,
+    ) -> &mut Self {
+        let span = span.map(|s| s.into()).unwrap_or(MultiSpan::new());
+        self.diagnostic.sub(level, message, span, None);
+        self
+    }
+
     /// Delay emission of this diagnostic as a bug.
     ///
     /// This can be useful in contexts where an error indicates a bug but
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index be3ac51ccb3..62aa86995d0 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -548,12 +548,13 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
                                                                  &hir::Visibility)>)
                            -> Entry<'tcx> {
         let tcx = self.tcx;
+        let hir_id = tcx.hir.node_to_hir_id(id);
         let def_id = tcx.hir.local_def_id(id);
         debug!("IsolatedEncoder::encode_info_for_mod({:?})", def_id);
 
         let data = ModData {
-            reexports: match tcx.export_map.get(&id) {
-                Some(exports) if *vis == hir::Public => {
+            reexports: match tcx.module_exports(hir_id) {
+                Some(ref exports) if *vis == hir::Public => {
                     self.lazy_seq_from_slice(exports.as_slice())
                 }
                 _ => LazySeq::empty(),
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 9126949156c..2198b533ea0 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -120,6 +120,7 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     return_qualif: Option<Qualif>,
     qualif: Qualif,
     const_fn_arg_vars: BitVector,
+    local_needs_drop: IndexVec<Local, Option<Span>>,
     temp_promotion_state: IndexVec<Local, TempState>,
     promotion_candidates: Vec<Candidate>
 }
@@ -146,6 +147,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
             return_qualif: None,
             qualif: Qualif::empty(),
             const_fn_arg_vars: BitVector::new(mir.local_decls.len()),
+            local_needs_drop: IndexVec::from_elem(None, &mir.local_decls),
             temp_promotion_state: temps,
             promotion_candidates: vec![]
         }
@@ -194,15 +196,25 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
     }
 
     /// Check for NEEDS_DROP (from an ADT or const fn call) and
+    /// error, unless we're in a function.
+    fn always_deny_drop(&self) {
+        self.deny_drop_with_feature_gate_override(false);
+    }
+
+    /// Check for NEEDS_DROP (from an ADT or const fn call) and
     /// error, unless we're in a function, or the feature-gate
     /// for globals with destructors is enabled.
     fn deny_drop(&self) {
+        self.deny_drop_with_feature_gate_override(true);
+    }
+
+    fn deny_drop_with_feature_gate_override(&self, allow_gate: bool) {
         if self.mode == Mode::Fn || !self.qualif.intersects(Qualif::NEEDS_DROP) {
             return;
         }
 
         // Static and const fn's allow destructors, but they're feature-gated.
-        let msg = if self.mode != Mode::Const {
+        let msg = if allow_gate && self.mode != Mode::Const {
             // Feature-gate for globals with destructors is enabled.
             if self.tcx.sess.features.borrow().drop_types_in_const {
                 return;
@@ -223,7 +235,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
         let mut err =
             struct_span_err!(self.tcx.sess, self.span, E0493, "{}", msg);
 
-        if self.mode != Mode::Const {
+        if allow_gate && self.mode != Mode::Const {
             help!(&mut err,
                   "in Nightly builds, add `#![feature(drop_types_in_const)]` \
                    to the crate attributes to enable");
@@ -231,7 +243,8 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
             self.find_drop_implementation_method_span()
                 .map(|span| err.span_label(span, "destructor defined here"));
 
-            err.span_label(self.span, "constants cannot have destructors");
+            err.span_label(self.span,
+                format!("{}s cannot have destructors", self.mode));
         }
 
         err.emit();
@@ -314,6 +327,15 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
             return;
         }
 
+        // When initializing a local, record whether the *value* being
+        // stored in it needs dropping, which it may not, even if its
+        // type does, e.g. `None::<String>`.
+        if let Lvalue::Local(local) = *dest {
+            if qualif.intersects(Qualif::NEEDS_DROP) {
+                self.local_needs_drop[local] = Some(self.span);
+            }
+        }
+
         match *dest {
             Lvalue::Local(index) if self.mir.local_kind(index) == LocalKind::Temp => {
                 debug!("store to temp {:?}", index);
@@ -360,7 +382,6 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
 
             let target = match mir[bb].terminator().kind {
                 TerminatorKind::Goto { target } |
-                // Drops are considered noops.
                 TerminatorKind::Drop { target, .. } |
                 TerminatorKind::Assert { target, .. } |
                 TerminatorKind::Call { destination: Some((_, target)), .. } => {
@@ -560,22 +581,32 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
 
     fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
         match *operand {
-            Operand::Consume(_) => {
+            Operand::Consume(ref lvalue) => {
                 self.nest(|this| {
                     this.super_operand(operand, location);
                     this.try_consume();
                 });
+
+                // Mark the consumed locals to indicate later drops are noops.
+                if let Lvalue::Local(local) = *lvalue {
+                    self.local_needs_drop[local] = None;
+                }
             }
             Operand::Constant(ref constant) => {
-                if let Literal::Item { def_id, substs } = constant.literal {
-                    // Don't peek inside generic (associated) constants.
-                    if substs.types().next().is_some() {
+                if let Literal::Item { def_id, substs: _ } = constant.literal {
+                    // Don't peek inside trait associated constants.
+                    if self.tcx.trait_of_item(def_id).is_some() {
                         self.add_type(constant.ty);
                     } else {
                         let bits = self.tcx.at(constant.span).mir_const_qualif(def_id);
 
                         let qualif = Qualif::from_bits(bits).expect("invalid mir_const_qualif");
                         self.add(qualif);
+
+                        // Just in case the type is more specific than
+                        // the definition, e.g. impl associated const
+                        // with type parameters, take it into account.
+                        self.qualif.restrict(constant.ty, self.tcx, self.param_env);
                     }
 
                     // Let `const fn` transitively have destructors,
@@ -866,6 +897,30 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                 }
                 self.assign(dest, location);
             }
+        } else if let TerminatorKind::Drop { location: ref lvalue, .. } = *kind {
+            self.super_terminator_kind(bb, kind, location);
+
+            // Deny *any* live drops anywhere other than functions.
+            if self.mode != Mode::Fn {
+                // HACK(eddyb) Emulate a bit of dataflow analysis,
+                // conservatively, that drop elaboration will do.
+                let needs_drop = if let Lvalue::Local(local) = *lvalue {
+                    self.local_needs_drop[local]
+                } else {
+                    None
+                };
+
+                if let Some(span) = needs_drop {
+                    let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx);
+                    self.add_type(ty);
+
+                    // Use the original assignment span to be more precise.
+                    let old_span = self.span;
+                    self.span = span;
+                    self.always_deny_drop();
+                    self.span = old_span;
+                }
+            }
         } else {
             // Qualify any operands inside other terminators.
             self.super_terminator_kind(bb, kind, location);
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 918be14ce9d..41ba7d678e8 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -87,19 +87,14 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
         }
     }
 
-    // Adds the worst effect out of all the values of one type.
-    fn add_type(&mut self, ty: Ty<'gcx>) {
-        if !ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) {
-            self.promotable = false;
-        }
-
-        if ty.needs_drop(self.tcx, self.param_env) {
-            self.promotable = false;
-        }
+    // Returns true iff all the values of the type are promotable.
+    fn type_has_only_promotable_values(&mut self, ty: Ty<'gcx>) -> bool {
+        ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) &&
+        !ty.needs_drop(self.tcx, self.param_env)
     }
 
     fn handle_const_fn_call(&mut self, def_id: DefId, ret_ty: Ty<'gcx>) {
-        self.add_type(ret_ty);
+        self.promotable &= self.type_has_only_promotable_values(ret_ty);
 
         self.promotable &= if let Some(fn_id) = self.tcx.hir.as_local_node_id(def_id) {
             FnLikeNode::from_node(self.tcx.hir.get(fn_id)).map_or(false, |fn_like| {
@@ -333,20 +328,30 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
             match def {
                 Def::VariantCtor(..) | Def::StructCtor(..) |
                 Def::Fn(..) | Def::Method(..) => {}
-                Def::AssociatedConst(_) => v.add_type(node_ty),
-                Def::Const(did) => {
-                    v.promotable &= if let Some(node_id) = v.tcx.hir.as_local_node_id(did) {
-                        match v.tcx.hir.expect_item(node_id).node {
-                            hir::ItemConst(_, body) => {
+
+                Def::Const(did) |
+                Def::AssociatedConst(did) => {
+                    let promotable = if v.tcx.trait_of_item(did).is_some() {
+                        // Don't peek inside trait associated constants.
+                        false
+                    } else if let Some(node_id) = v.tcx.hir.as_local_node_id(did) {
+                        match v.tcx.hir.maybe_body_owned_by(node_id) {
+                            Some(body) => {
                                 v.visit_nested_body(body);
                                 v.tcx.rvalue_promotable_to_static.borrow()[&body.node_id]
                             }
-                            _ => false
+                            None => false
                         }
                     } else {
                         v.tcx.const_is_rvalue_promotable_to_static(did)
                     };
+
+                    // Just in case the type is more specific than the definition,
+                    // e.g. impl associated const with type parameters, check it.
+                    // Also, trait associated consts are relaxed by this.
+                    v.promotable &= promotable || v.type_has_only_promotable_values(node_ty);
                 }
+
                 _ => {
                     v.promotable = false;
                 }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index e34b0927f67..8dc07898419 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -325,8 +325,9 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
         // This code is here instead of in visit_item so that the
         // crate module gets processed as well.
         if self.prev_level.is_some() {
-            if let Some(exports) = self.tcx.export_map.get(&id) {
-                for export in exports {
+            let hir_id = self.tcx.hir.node_to_hir_id(id);
+            if let Some(exports) = self.tcx.module_exports(hir_id) {
+                for export in exports.iter() {
                     if let Some(node_id) = self.tcx.hir.as_local_node_id(export.def.def_id()) {
                         self.update(node_id, Some(AccessLevel::Exported));
                     }
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index f8dc341653e..9531c8baa0b 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -402,7 +402,8 @@ impl<'a> Resolver<'a> {
         let ast::Path { ref segments, span } = *path;
         let path: Vec<_> = segments.iter().map(|seg| respan(seg.span, seg.identifier)).collect();
         let invocation = self.invocations[&scope];
-        self.current_module = invocation.module.get();
+        let module = invocation.module.get();
+        self.current_module = if module.is_trait() { module.parent.unwrap() } else { module };
 
         if path.len() > 1 {
             if !self.use_extern_macros && self.gated_errors.insert(span) {
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 228b6c88f24..ba74c902f55 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -639,10 +639,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     fn assemble_extension_candidates_for_traits_in_scope(&mut self,
                                                          expr_id: ast::NodeId)
                                                          -> Result<(), MethodError<'tcx>> {
+        if expr_id == ast::DUMMY_NODE_ID {
+            return Ok(())
+        }
         let mut duplicates = FxHashSet();
-        let opt_applicable_traits = self.tcx.trait_map.get(&expr_id);
+        let expr_hir_id = self.tcx.hir.node_to_hir_id(expr_id);
+        let opt_applicable_traits = self.tcx.in_scope_traits(expr_hir_id);
         if let Some(applicable_traits) = opt_applicable_traits {
-            for trait_candidate in applicable_traits {
+            for trait_candidate in applicable_traits.iter() {
                 let trait_did = trait_candidate.def_id;
                 if duplicates.insert(trait_did) {
                     let import_id = trait_candidate.import_id;
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index f9400e68a16..08359bc3f19 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -12,6 +12,7 @@ path = "lib.rs"
 env_logger = { version = "0.4", default-features = false }
 log = "0.3"
 pulldown-cmark = { version = "0.0.14", default-features = false }
+html-diff = "0.0.3"
 
 [build-dependencies]
 build_helper = { path = "../build_helper" }
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 5b8c7503a79..dec0fe599e7 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -75,6 +75,8 @@ use html::item_type::ItemType;
 use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, RenderType};
 use html::{highlight, layout};
 
+use html_diff;
+
 /// A pair of name and its optional document.
 pub type NameDoc = (String, Option<String>);
 
@@ -1643,6 +1645,33 @@ fn document(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Re
     Ok(())
 }
 
+fn get_html_diff(w: &mut fmt::Formatter, md_text: &str, render_type: RenderType,
+                 prefix: &str) -> fmt::Result {
+    let output = format!("{}", Markdown(md_text, render_type));
+    let old = format!("{}", Markdown(md_text, match render_type {
+                                                  RenderType::Hoedown => RenderType::Pulldown,
+                                                  RenderType::Pulldown => RenderType::Hoedown,
+                                              }));
+    let differences = html_diff::get_differences(&output, &old);
+    if !differences.is_empty() {
+        println!("Differences spotted in {:?}:\n{}",
+                 md_text,
+                 differences.iter()
+                            .filter_map(|s| {
+                                match *s {
+                                    html_diff::Difference::NodeText { ref elem_text,
+                                                                      ref opposite_elem_text,
+                                                                      .. }
+                                        if elem_text.trim() == opposite_elem_text.trim() => None,
+                                    _ => Some(format!("=> {}", s.to_string())),
+                                }
+                            })
+                            .collect::<Vec<String>>()
+                            .join("\n"));
+    }
+    write!(w, "<div class='docblock'>{}{}</div>", prefix, output)
+}
+
 fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLink,
                   render_type: RenderType, prefix: &str) -> fmt::Result {
     if let Some(s) = item.doc_value() {
@@ -1652,7 +1681,7 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin
         } else {
             format!("{}", &plain_summary_line(Some(s)))
         };
-        write!(w, "<div class='docblock'>{}{}</div>", prefix, Markdown(&markdown, render_type))?;
+        get_html_diff(w, &markdown, render_type, prefix)?;
     } else if !prefix.is_empty() {
         write!(w, "<div class='docblock'>{}</div>", prefix)?;
     }
@@ -1676,7 +1705,7 @@ fn render_assoc_const_value(item: &clean::Item) -> String {
 fn document_full(w: &mut fmt::Formatter, item: &clean::Item,
                  render_type: RenderType, prefix: &str) -> fmt::Result {
     if let Some(s) = item.doc_value() {
-        write!(w, "<div class='docblock'>{}{}</div>", prefix, Markdown(s, render_type))?;
+        get_html_diff(w, s, render_type, prefix)?;
     } else if !prefix.is_empty() {
         write!(w, "<div class='docblock'>{}</div>", prefix)?;
     }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 61a8165d26a..d04b6d3417a 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -28,6 +28,7 @@
 extern crate arena;
 extern crate getopts;
 extern crate env_logger;
+extern crate html_diff;
 extern crate libc;
 extern crate rustc;
 extern crate rustc_data_structures;
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index e3426fba1bc..1f33cd77651 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -199,8 +199,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             self.visit_item(item, None, &mut om);
         }
         self.inside_public_path = orig_inside_public_path;
-        if let Some(exports) = self.cx.tcx.export_map.get(&id) {
-            for export in exports {
+        let hir_id = self.cx.tcx.hir.node_to_hir_id(id);
+        if let Some(exports) = self.cx.tcx.module_exports(hir_id) {
+            for export in exports.iter() {
                 if let Def::Macro(def_id, ..) = export.def {
                     if def_id.krate == LOCAL_CRATE || self.reexported_macros.contains(&def_id) {
                         continue // These are `krate.exported_macros`, handled in `self.visit()`.
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 074ab3ebd8f..181b8726e48 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -212,7 +212,7 @@
 //! # }
 //! ```
 //!
-//! [functions-list]: #functions-1
+//! [functions-list]: #functions-2
 //!
 //! ## io::Result
 //!
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index c426bf8086e..0330ff5950b 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -26,13 +26,33 @@ macro_rules! __rust_unstable_column {
 
 /// The entry point for panic of Rust threads.
 ///
+/// This allows a program to to terminate immediately and provide feedback
+/// to the caller of the program. `panic!` should be used when a program reaches
+/// an unrecoverable problem.
+///
+/// This macro is the perfect way to assert conditions in example code and in
+/// tests.  `panic!` is closely tied with the `unwrap` method of both [`Option`]
+/// and [`Result`][runwrap] enums.  Both implementations call `panic!` when they are set
+/// to None or Err variants.
+///
 /// This macro is used to inject panic into a Rust thread, causing the thread to
 /// panic entirely. Each thread's panic can be reaped as the `Box<Any>` type,
 /// and the single-argument form of the `panic!` macro will be the value which
 /// is transmitted.
 ///
+/// [`Result`] enum is often a better solution for recovering from errors than
+/// using the `panic!` macro.  This macro should be used to avoid proceeding using
+/// incorrect values, such as from external sources.  Detailed information about
+/// error handling is found in the [book].
+///
 /// The multi-argument form of this macro panics with a string and has the
-/// `format!` syntax for building a string.
+/// [`format!`] syntax for building a string.
+///
+/// [runwrap]: ../std/result/enum.Result.html#method.unwrap
+/// [`Option`]: ../std/option/enum.Option.html#method.unwrap
+/// [`Result`]: ../std/result/enum.Result.html
+/// [`format!`]: ../std/macro.format.html
+/// [book]: ../book/second-edition/ch09-01-unrecoverable-errors-with-panic.html
 ///
 /// # Current implementation
 ///
@@ -78,15 +98,19 @@ macro_rules! panic {
 
 /// Macro for printing to the standard output.
 ///
-/// Equivalent to the `println!` macro except that a newline is not printed at
+/// Equivalent to the [`println!`] macro except that a newline is not printed at
 /// the end of the message.
 ///
 /// Note that stdout is frequently line-buffered by default so it may be
-/// necessary to use `io::stdout().flush()` to ensure the output is emitted
+/// necessary to use [`io::stdout().flush()`][flush] to ensure the output is emitted
 /// immediately.
 ///
 /// Use `print!` only for the primary output of your program.  Use
-/// `eprint!` instead to print error and progress messages.
+/// [`eprint!`] instead to print error and progress messages.
+///
+/// [`println!`]: ../std/macro.println.html
+/// [flush]: ../std/io/trait.Write.html#tymethod.flush
+/// [`eprint!`]: ../std/macro.eprint.html
 ///
 /// # Panics
 ///
@@ -118,16 +142,20 @@ macro_rules! print {
     ($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*)));
 }
 
-/// Macro for printing to the standard output, with a newline. On all
-/// platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone
+/// Macro for printing to the standard output, with a newline.
+///
+/// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone
 /// (no additional CARRIAGE RETURN (`\r`/`U+000D`).
 ///
-/// Use the `format!` syntax to write data to the standard output.
-/// See `std::fmt` for more information.
+/// Use the [`format!`] syntax to write data to the standard output.
+/// See [`std::fmt`] for more information.
 ///
 /// Use `println!` only for the primary output of your program.  Use
-/// `eprintln!` instead to print error and progress messages.
+/// [`eprintln!`] instead to print error and progress messages.
 ///
+/// [`format!`]: ../std/macro.format.html
+/// [`std::fmt`]: ../std/fmt/index.html
+/// [`eprintln!`]: ../std/macro.eprint.html
 /// # Panics
 ///
 /// Panics if writing to `io::stdout` fails.
@@ -149,16 +177,25 @@ macro_rules! println {
 
 /// Macro for printing to the standard error.
 ///
-/// Equivalent to the `print!` macro, except that output goes to
-/// `io::stderr` instead of `io::stdout`.  See `print!` for
+/// Equivalent to the [`print!`] macro, except that output goes to
+/// [`io::stderr`] instead of `io::stdout`.  See [`print!`] for
 /// example usage.
 ///
 /// Use `eprint!` only for error and progress messages.  Use `print!`
 /// instead for the primary output of your program.
 ///
+/// [`io::stderr`]: ../std/io/struct.Stderr.html
+/// [`print!`]: ../std/macro.print.html
+///
 /// # Panics
 ///
 /// Panics if writing to `io::stderr` fails.
+///
+/// # Examples
+///
+/// ```
+/// eprint!("Error: Could not complete task");
+/// ```
 #[macro_export]
 #[stable(feature = "eprint", since = "1.19.0")]
 #[allow_internal_unstable]
@@ -168,16 +205,25 @@ macro_rules! eprint {
 
 /// Macro for printing to the standard error, with a newline.
 ///
-/// Equivalent to the `println!` macro, except that output goes to
-/// `io::stderr` instead of `io::stdout`.  See `println!` for
+/// Equivalent to the [`println!`] macro, except that output goes to
+/// [`io::stderr`] instead of `io::stdout`.  See [`println!`] for
 /// example usage.
 ///
 /// Use `eprintln!` only for error and progress messages.  Use `println!`
 /// instead for the primary output of your program.
 ///
+/// [`io::stderr`]: ../std/io/struct.Stderr.html
+/// [`println!`]: ../std/macro.println.html
+///
 /// # Panics
 ///
 /// Panics if writing to `io::stderr` fails.
+///
+/// # Examples
+///
+/// ```
+/// eprintln!("Error: Could not complete task");
+/// ```
 #[macro_export]
 #[stable(feature = "eprint", since = "1.19.0")]
 macro_rules! eprintln {
@@ -267,13 +313,23 @@ pub mod builtin {
 
     /// The core macro for formatted string creation & output.
     ///
+    /// This macro functions by taking a formatting string literal containing
+    /// `{}` for each additional argument passed.  `format_args!` prepares the
+    /// additional parameters to ensure the output can be interpreted as a string
+    /// and canonicalizes the arguments into a single type.  Any value that implements
+    /// the [`Display`] trait can be passed to `format_args!`, as can any
+    /// [`Debug`] implementation be passed to a `{:?}` within the formatting string.
+    ///
     /// This macro produces a value of type [`fmt::Arguments`]. This value can be
-    /// passed to the functions in [`std::fmt`] for performing useful functions.
+    /// passed to the macros within [`std::fmt`] for performing useful redirection.
     /// All other formatting macros ([`format!`], [`write!`], [`println!`], etc) are
-    /// proxied through this one.
+    /// proxied through this one.  `format_args!`, unlike its derived macros, avoids
+    /// heap allocations.
     ///
     /// For more information, see the documentation in [`std::fmt`].
     ///
+    /// [`Display`]: ../std/fmt/trait.Display.html
+    /// [`Debug`]: ../std/fmt/trait.Debug.html
     /// [`fmt::Arguments`]: ../std/fmt/struct.Arguments.html
     /// [`std::fmt`]: ../std/fmt/index.html
     /// [`format!`]: ../std/macro.format.html
@@ -301,9 +357,11 @@ pub mod builtin {
     /// compile time, yielding an expression of type `&'static str`.
     ///
     /// If the environment variable is not defined, then a compilation error
-    /// will be emitted.  To not emit a compile error, use the `option_env!`
+    /// will be emitted.  To not emit a compile error, use the [`option_env!`]
     /// macro instead.
     ///
+    /// [`option_env!`]: ../std/macro.option_env.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -319,11 +377,14 @@ pub mod builtin {
     /// If the named environment variable is present at compile time, this will
     /// expand into an expression of type `Option<&'static str>` whose value is
     /// `Some` of the value of the environment variable. If the environment
-    /// variable is not present, then this will expand to `None`.
+    /// variable is not present, then this will expand to `None`.  See
+    /// [`Option<T>`][option] for more information on this type.
     ///
     /// A compile time error is never emitted when using this macro regardless
     /// of whether the environment variable is present or not.
     ///
+    /// [option]: ../std/option/enum.Option.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -385,10 +446,16 @@ pub mod builtin {
 
     /// A macro which expands to the line number on which it was invoked.
     ///
+    /// With [`column!`] and [`file!`], these macros provide debugging information for
+    /// developers about the location within the source.
+    ///
     /// The expanded expression has type `u32`, and the returned line is not
     /// the invocation of the `line!()` macro itself, but rather the first macro
     /// invocation leading up to the invocation of the `line!()` macro.
     ///
+    /// [`column!`]: macro.column.html
+    /// [`file!`]: macro.file.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -401,9 +468,15 @@ pub mod builtin {
 
     /// A macro which expands to the column number on which it was invoked.
     ///
+    /// With [`line!`] and [`file!`], these macros provide debugging information for
+    /// developers about the location within the source.
+    ///
     /// The expanded expression has type `u32`, and the returned column is not
-    /// the invocation of the `column!()` macro itself, but rather the first macro
-    /// invocation leading up to the invocation of the `column!()` macro.
+    /// the invocation of the `column!` macro itself, but rather the first macro
+    /// invocation leading up to the invocation of the `column!` macro.
+    ///
+    /// [`line!`]: macro.line.html
+    /// [`file!`]: macro.file.html
     ///
     /// # Examples
     ///
@@ -417,11 +490,18 @@ pub mod builtin {
 
     /// A macro which expands to the file name from which it was invoked.
     ///
+    /// With [`line!`] and [`column!`], these macros provide debugging information for
+    /// developers about the location within the source.
+    ///
+    ///
     /// The expanded expression has type `&'static str`, and the returned file
-    /// is not the invocation of the `file!()` macro itself, but rather the
-    /// first macro invocation leading up to the invocation of the `file!()`
+    /// is not the invocation of the `file!` macro itself, but rather the
+    /// first macro invocation leading up to the invocation of the `file!`
     /// macro.
     ///
+    /// [`line!`]: macro.line.html
+    /// [`column!`]: macro.column.html
+    ///
     /// # Examples
     ///
     /// ```
diff --git a/src/libstd/os/raw.rs b/src/libstd/os/raw.rs
index c34491941d6..fe0427d4e5f 100644
--- a/src/libstd/os/raw.rs
+++ b/src/libstd/os/raw.rs
@@ -14,8 +14,7 @@
 
 use fmt;
 
-#[cfg(any(target_os = "emscripten",
-          all(target_os = "linux", any(target_arch = "aarch64",
+#[cfg(any(all(target_os = "linux", any(target_arch = "aarch64",
                                        target_arch = "arm",
                                        target_arch = "powerpc",
                                        target_arch = "powerpc64",
@@ -24,8 +23,7 @@ use fmt;
                                          target_arch = "arm")),
           all(target_os = "fuchsia", target_arch = "aarch64")))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
-#[cfg(not(any(target_os = "emscripten",
-              all(target_os = "linux", any(target_arch = "aarch64",
+#[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64",
                                            target_arch = "arm",
                                            target_arch = "powerpc",
                                            target_arch = "powerpc64",
diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs
index 138087f1651..f50b093acc8 100644
--- a/src/libstd/sys/unix/fd.rs
+++ b/src/libstd/sys/unix/fd.rs
@@ -71,13 +71,21 @@ impl FileDesc {
         #[cfg(target_os = "android")]
         use super::android::cvt_pread64;
 
-        #[cfg(not(target_os = "android"))]
+        #[cfg(target_os = "emscripten")]
         unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
             -> io::Result<isize>
         {
-            #[cfg(any(target_os = "linux", target_os = "emscripten"))]
             use libc::pread64;
-            #[cfg(not(any(target_os = "linux", target_os = "emscripten")))]
+            cvt(pread64(fd, buf, count, offset as i32))
+        }
+
+        #[cfg(not(any(target_os = "android", target_os = "emscripten")))]
+        unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
+            -> io::Result<isize>
+        {
+            #[cfg(target_os = "linux")]
+            use libc::pread64;
+            #[cfg(not(target_os = "linux"))]
             use libc::pread as pread64;
             cvt(pread64(fd, buf, count, offset))
         }
@@ -104,13 +112,21 @@ impl FileDesc {
         #[cfg(target_os = "android")]
         use super::android::cvt_pwrite64;
 
-        #[cfg(not(target_os = "android"))]
+        #[cfg(target_os = "emscripten")]
+        unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
+            -> io::Result<isize>
+        {
+            use libc::pwrite64;
+            cvt(pwrite64(fd, buf, count, offset as i32))
+        }
+
+        #[cfg(not(any(target_os = "android", target_os = "emscripten")))]
         unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
             -> io::Result<isize>
         {
-            #[cfg(any(target_os = "linux", target_os = "emscripten"))]
+            #[cfg(target_os = "linux")]
             use libc::pwrite64;
-            #[cfg(not(any(target_os = "linux", target_os = "emscripten")))]
+            #[cfg(not(target_os = "linux"))]
             use libc::pwrite as pwrite64;
             cvt(pwrite64(fd, buf, count, offset))
         }
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
index cb0f687e072..f94af491332 100644
--- a/src/libstd/sys/unix/fs.rs
+++ b/src/libstd/sys/unix/fs.rs
@@ -514,6 +514,8 @@ impl File {
             SeekFrom::End(off) => (libc::SEEK_END, off),
             SeekFrom::Current(off) => (libc::SEEK_CUR, off),
         };
+        #[cfg(target_os = "emscripten")]
+        let pos = pos as i32;
         let n = cvt(unsafe { lseek64(self.0.raw(), pos, whence) })?;
         Ok(n as u64)
     }
diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs
index edd322ca6fa..ae24021fb6c 100644
--- a/src/libstd/sys/unix/process/process_unix.rs
+++ b/src/libstd/sys/unix/process/process_unix.rs
@@ -10,7 +10,6 @@
 
 use io::{self, Error, ErrorKind};
 use libc::{self, c_int, gid_t, pid_t, uid_t};
-use mem;
 use ptr;
 
 use sys::cvt;
@@ -184,7 +183,9 @@ impl Command {
         }
 
         // NaCl has no signal support.
-        if cfg!(not(any(target_os = "nacl", target_os = "emscripten"))) {
+        #[cfg(not(any(target_os = "nacl", target_os = "emscripten")))]
+        {
+            use mem;
             // Reset signal handling so the child process starts in a
             // standardized state. libstd ignores SIGPIPE, and signal-handling
             // libraries often set a mask. Child processes inherit ignored
diff --git a/src/test/compile-fail/check-static-values-constraints.rs b/src/test/compile-fail/check-static-values-constraints.rs
index 3642add3259..c349aababd6 100644
--- a/src/test/compile-fail/check-static-values-constraints.rs
+++ b/src/test/compile-fail/check-static-values-constraints.rs
@@ -86,8 +86,9 @@ static STATIC8: SafeStruct = SafeStruct{field1: SafeEnum::Variant1,
 // This example should fail because field1 in the base struct is not safe
 static STATIC9: SafeStruct = SafeStruct{field1: SafeEnum::Variant1,
                                         ..SafeStruct{field1: SafeEnum::Variant3(WithDtor),
+//~^ ERROR destructors in statics are an unstable feature
+//~| ERROR statics are not allowed to have destructors
                                                      field2: SafeEnum::Variant1}};
-//~^^ ERROR destructors in statics are an unstable feature
 
 struct UnsafeStruct;
 
diff --git a/src/test/compile-fail/static-drop-scope.rs b/src/test/compile-fail/static-drop-scope.rs
new file mode 100644
index 00000000000..e5f10b65cee
--- /dev/null
+++ b/src/test/compile-fail/static-drop-scope.rs
@@ -0,0 +1,26 @@
+// 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.
+
+#![feature(drop_types_in_const)]
+
+struct WithDtor;
+
+impl Drop for WithDtor {
+    fn drop(&mut self) {}
+}
+
+static FOO: Option<&'static WithDtor> = Some(&WithDtor);
+//~^ ERROR statics are not allowed to have destructors
+//~| ERROR borrowed value does not live long enoug
+
+static BAR: i32 = (WithDtor, 0).1;
+//~^ ERROR statics are not allowed to have destructors
+
+fn main () {}
diff --git a/src/test/run-make/sysroot-crates-are-unstable/Makefile b/src/test/run-make/sysroot-crates-are-unstable/Makefile
index 4b7052f9b94..a35174b3c2a 100644
--- a/src/test/run-make/sysroot-crates-are-unstable/Makefile
+++ b/src/test/run-make/sysroot-crates-are-unstable/Makefile
@@ -1,35 +1,2 @@
--include ../tools.mk
-
-# This is a whitelist of files which are stable crates or simply are not crates,
-# we don't check for the instability of these crates as they're all stable!
-STABLE_CRATES := \
-	std \
-	core \
-	proc_macro \
-	rsbegin.o \
-	rsend.o \
-	dllcrt2.o \
-	crt2.o \
-	clang_rt.%_dynamic.dylib
-
-# Generate a list of all crates in the sysroot. To do this we list all files in
-# rustc's sysroot, look at the filename, strip everything after the `-`, and
-# strip the leading `lib` (if present)
-SYSROOT := $(shell $(RUSTC) --print sysroot)
-LIBS := $(wildcard $(SYSROOT)/lib/rustlib/$(TARGET)/lib/*)
-LIBS := $(foreach lib,$(LIBS),$(notdir $(lib)))
-LIBS := $(foreach lib,$(LIBS),$(word 1,$(subst -, ,$(lib))))
-LIBS := $(foreach lib,$(LIBS),$(patsubst lib%,%,$(lib)))
-LIBS := $(filter-out $(STABLE_CRATES),$(LIBS))
-
-all: $(foreach lib,$(LIBS),check-crate-$(lib)-is-unstable)
-
-check-crate-%-is-unstable:
-	@echo verifying $* is an unstable crate
-	@echo 'extern crate $*;' | \
-		$(RUSTC) - --crate-type rlib 2>&1 | cat > $(TMPDIR)/$*; \
-		true
-	@grep -q 'use of unstable library feature' $(TMPDIR)/$* || \
-		(echo crate $* is not unstable && \
-		cat $(TMPDIR)/$* && \
-		false)
+all:
+	python2.7 test.py
diff --git a/src/test/run-make/sysroot-crates-are-unstable/test.py b/src/test/run-make/sysroot-crates-are-unstable/test.py
new file mode 100644
index 00000000000..210059e1010
--- /dev/null
+++ b/src/test/run-make/sysroot-crates-are-unstable/test.py
@@ -0,0 +1,71 @@
+# Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+import sys
+import os
+from os import listdir
+from os.path import isfile, join
+from subprocess import PIPE, Popen
+
+
+# This is a whitelist of files which are stable crates or simply are not crates,
+# we don't check for the instability of these crates as they're all stable!
+STABLE_CRATES = ['std', 'core', 'proc_macro', 'rsbegin.o', 'rsend.o', 'dllcrt2.o', 'crt2.o',
+                 'clang_rt']
+
+
+def convert_to_string(s):
+    if s.__class__.__name__ == 'bytes':
+        return s.decode('utf-8')
+    return s
+
+
+def exec_command(command, to_input=None):
+    child = None
+    if to_input is None:
+        child = Popen(command, stdout=PIPE, stderr=PIPE)
+    else:
+        child = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE)
+    stdout, stderr = child.communicate(input=to_input)
+    return (convert_to_string(stdout), convert_to_string(stderr))
+
+
+def check_lib(lib):
+    if lib['name'] in STABLE_CRATES:
+        return True
+    print('verifying if {} is an unstable crate'.format(lib['name']))
+    stdout, stderr = exec_command([os.environ['RUSTC'], '-', '--crate-type', 'rlib',
+                                   '--extern', '{}={}'.format(lib['name'], lib['path'])],
+                                  to_input='extern crate {};'.format(lib['name']))
+    if not 'use of unstable library feature' in '{}{}'.format(stdout, stderr):
+        print('crate {} "{}" is not unstable'.format(lib['name'], lib['path']))
+        print('{}{}'.format(stdout, stderr))
+        print('')
+        return False
+    return True
+
+# Generate a list of all crates in the sysroot. To do this we list all files in
+# rustc's sysroot, look at the filename, strip everything after the `-`, and
+# strip the leading `lib` (if present)
+def get_all_libs(dir_path):
+    return [{ 'path': join(dir_path, f), 'name': f[3:].split('-')[0] }
+            for f in listdir(dir_path)
+            if isfile(join(dir_path, f)) and f.endswith('.rlib') and f not in STABLE_CRATES]
+
+
+sysroot = exec_command([os.environ['RUSTC'], '--print', 'sysroot'])[0].replace('\n', '')
+libs = get_all_libs(join(sysroot, 'lib/rustlib/{}/lib'.format(os.environ['TARGET'])))
+
+ret = 0
+for lib in libs:
+    if not check_lib(lib):
+        # We continue so users can see all the not unstable crates.
+        ret = 1
+sys.exit(ret)
diff --git a/src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs b/src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs
new file mode 100644
index 00000000000..8ba38875eff
--- /dev/null
+++ b/src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs
@@ -0,0 +1,28 @@
+// 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.
+
+// aux-build:attr-on-trait.rs
+
+#![feature(proc_macro)]
+
+extern crate attr_on_trait;
+
+trait Foo {
+    #[attr_on_trait::foo]
+    fn foo() {}
+}
+
+impl Foo for i32 {
+    fn foo(&self) {}
+}
+
+fn main() {
+    3i32.foo();
+}
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-on-trait.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-on-trait.rs
new file mode 100644
index 00000000000..8e977034027
--- /dev/null
+++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-on-trait.rs
@@ -0,0 +1,25 @@
+// 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.
+
+// no-prefer-dynamic
+
+#![feature(proc_macro)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn foo(attr: TokenStream, item: TokenStream) -> TokenStream {
+    drop(attr);
+    assert_eq!(item.to_string(), "fn foo() { }");
+    "fn foo(&self);".parse().unwrap()
+}
diff --git a/src/test/run-pass/rvalue-static-promotion.rs b/src/test/run-pass/rvalue-static-promotion.rs
index e57491930a4..acf96b566df 100644
--- a/src/test/run-pass/rvalue-static-promotion.rs
+++ b/src/test/run-pass/rvalue-static-promotion.rs
@@ -8,8 +8,20 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#[allow(unused_variables)]
+use std::cell::Cell;
+
+const NONE_CELL_STRING: Option<Cell<String>> = None;
+
+struct Foo<T>(T);
+impl<T> Foo<T> {
+    const FOO: Option<Box<T>> = None;
+}
+
 fn main() {
-    let x: &'static u32 = &42;
-    let y: &'static Option<u32> = &None;
+    let _: &'static u32 = &42;
+    let _: &'static Option<u32> = &None;
+
+    // We should be able to peek at consts and see they're None.
+    let _: &'static Option<Cell<String>> = &NONE_CELL_STRING;
+    let _: &'static Option<Box<()>> = &Foo::FOO;
 }
diff --git a/src/test/rustdoc/issue-29449.rs b/src/test/rustdoc/issue-29449.rs
index f296048e30b..29b89d68970 100644
--- a/src/test/rustdoc/issue-29449.rs
+++ b/src/test/rustdoc/issue-29449.rs
@@ -18,12 +18,12 @@ impl Foo {
     /// # Panics
     pub fn bar() {}
 
-    // @has - '//*[@id="examples-1"]//a' 'Examples'
+    // @has - '//*[@id="examples-2"]//a' 'Examples'
     /// # Examples
     pub fn bar_1() {}
 
-    // @has - '//*[@id="examples-2"]//a' 'Examples'
-    // @has - '//*[@id="panics-1"]//a' 'Panics'
+    // @has - '//*[@id="examples-4"]//a' 'Examples'
+    // @has - '//*[@id="panics-2"]//a' 'Panics'
     /// # Examples
     /// # Panics
     pub fn bar_2() {}
diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs
new file mode 100644
index 00000000000..6fca32fece1
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs
@@ -0,0 +1,56 @@
+// 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.
+
+// no-prefer-dynamic
+#![feature(proc_macro)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenNode, Span, Diagnostic};
+
+fn parse(input: TokenStream) -> Result<(), Diagnostic> {
+    let mut count = 0;
+    let mut last_span = Span::default();
+    for tree in input {
+        let span = tree.span;
+        if count >= 3 {
+            return Err(span.error(format!("expected EOF, found `{}`.", tree))
+                           .span_note(last_span, "last good input was here")
+                           .help("input must be: `===`"))
+        }
+
+        if let TokenNode::Op('=', _) = tree.kind {
+            count += 1;
+        } else {
+            return Err(span.error(format!("expected `=`, found `{}`.", tree)));
+        }
+
+        last_span = span;
+    }
+
+    if count < 3 {
+        return Err(Span::default()
+                       .error(format!("found {} equal signs, need exactly 3", count))
+                       .help("input must be: `===`"))
+    }
+
+    Ok(())
+}
+
+#[proc_macro]
+pub fn three_equals(input: TokenStream) -> TokenStream {
+    if let Err(diag) = parse(input) {
+        diag.emit();
+        return TokenStream::empty();
+    }
+
+    "3".parse().unwrap()
+}
diff --git a/src/test/ui-fulldeps/proc-macro/three-equals.rs b/src/test/ui-fulldeps/proc-macro/three-equals.rs
new file mode 100644
index 00000000000..016e05c51f5
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/three-equals.rs
@@ -0,0 +1,38 @@
+// 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.
+
+// aux-build:three-equals.rs
+// ignore-stage1
+
+#![feature(proc_macro)]
+
+extern crate three_equals;
+
+use three_equals::three_equals;
+
+fn main() {
+    // This one is okay.
+    three_equals!(===);
+
+    // Need exactly three equals.
+    three_equals!(==);
+
+    // Need exactly three equals.
+    three_equals!(=====);
+
+    // Only equals accepted.
+    three_equals!(abc);
+
+    // Only equals accepted.
+    three_equals!(!!);
+
+    // Only three characters expected.
+    three_equals!(===a);
+}
diff --git a/src/test/ui-fulldeps/proc-macro/three-equals.stderr b/src/test/ui-fulldeps/proc-macro/three-equals.stderr
new file mode 100644
index 00000000000..1afe0be2800
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/three-equals.stderr
@@ -0,0 +1,48 @@
+error: found 2 equal signs, need exactly 3
+  --> $DIR/three-equals.rs:25:5
+   |
+25 |     three_equals!(==);
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = help: input must be: `===`
+
+error: expected EOF, found `=`.
+  --> $DIR/three-equals.rs:28:21
+   |
+28 |     three_equals!(=====);
+   |                     ^^
+   |
+note: last good input was here
+  --> $DIR/three-equals.rs:28:21
+   |
+28 |     three_equals!(=====);
+   |                     ^^
+   = help: input must be: `===`
+
+error: expected `=`, found `abc`.
+  --> $DIR/three-equals.rs:31:19
+   |
+31 |     three_equals!(abc);
+   |                   ^^^
+
+error: expected `=`, found `!`.
+  --> $DIR/three-equals.rs:34:19
+   |
+34 |     three_equals!(!!);
+   |                   ^
+
+error: expected EOF, found `a`.
+  --> $DIR/three-equals.rs:37:22
+   |
+37 |     three_equals!(===a);
+   |                      ^
+   |
+note: last good input was here
+  --> $DIR/three-equals.rs:37:21
+   |
+37 |     three_equals!(===a);
+   |                     ^
+   = help: input must be: `===`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index f572ad9cd02..e9e4b55402c 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -33,6 +33,12 @@ static EXCEPTIONS: &'static [&'static str] = &[
     "openssl", // BSD+advertising clause, cargo, mdbook
     "pest", // MPL2, mdbook via handlebars
     "thread-id", // Apache-2.0, mdbook
+    "cssparser", // MPL-2.0, rustdoc
+    "smallvec", // MPL-2.0, rustdoc
+    "magenta-sys", // BSD-3-Clause, rustdoc
+    "magenta", // BSD-3-Clause, rustdoc
+    "cssparser-macros", // MPL-2.0, rustdoc
+    "selectors", // MPL-2.0, rustdoc
 ];
 
 pub fn check(path: &Path, bad: &mut bool) {