about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/Cargo.lock18
-rw-r--r--src/ci/docker/disabled/dist-armebv7r-none-eabihf/Dockerfile36
-rw-r--r--src/ci/docker/dist-various-1/Dockerfile9
-rw-r--r--src/liballoc/boxed.rs211
-rw-r--r--src/liballoc/lib.rs2
-rw-r--r--src/liballoc/pin.rs302
-rw-r--r--src/liballoc_jemalloc/lib.rs9
-rw-r--r--src/liballoc_system/lib.rs1
-rw-r--r--src/libarena/lib.rs1
-rw-r--r--src/libcore/future/future.rs2
-rw-r--r--src/libcore/future/future_obj.rs2
-rw-r--r--src/libcore/lib.rs2
-rw-r--r--src/libcore/marker.rs9
-rw-r--r--src/libcore/mem.rs149
-rw-r--r--src/libcore/option.rs2
-rw-r--r--src/libcore/pin.rs160
-rw-r--r--src/libfmt_macros/lib.rs1
-rw-r--r--src/libgraphviz/lib.rs1
-rw-r--r--src/libpanic_abort/lib.rs5
-rw-r--r--src/libpanic_unwind/lib.rs1
-rw-r--r--src/libproc_macro/lib.rs1
-rw-r--r--src/libprofiler_builtins/lib.rs1
-rw-r--r--src/librustc/hir/map/blocks.rs26
-rw-r--r--src/librustc/hir/map/collector.rs95
-rw-r--r--src/librustc/hir/map/mod.rs576
-rw-r--r--src/librustc/hir/mod.rs64
-rw-r--r--src/librustc/hir/print.rs40
-rw-r--r--src/librustc/ich/hcx.rs8
-rw-r--r--src/librustc/ich/impls_hir.rs1
-rw-r--r--src/librustc/ich/impls_syntax.rs4
-rw-r--r--src/librustc/ich/impls_ty.rs7
-rw-r--r--src/librustc/infer/anon_types/mod.rs5
-rw-r--r--src/librustc/infer/canonical/query_result.rs19
-rw-r--r--src/librustc/infer/error_reporting/mod.rs24
-rw-r--r--src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs8
-rw-r--r--src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs4
-rw-r--r--src/librustc/infer/error_reporting/nice_region_error/util.rs7
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/lint/mod.rs2
-rw-r--r--src/librustc/middle/dead.rs22
-rw-r--r--src/librustc/middle/liveness.rs4
-rw-r--r--src/librustc/middle/mem_categorization.rs4
-rw-r--r--src/librustc/middle/reachable.rs41
-rw-r--r--src/librustc/middle/region.rs7
-rw-r--r--src/librustc/middle/resolve_lifetime.rs24
-rw-r--r--src/librustc/mir/interpret/error.rs6
-rw-r--r--src/librustc/mir/interpret/mod.rs16
-rw-r--r--src/librustc/mir/interpret/value.rs97
-rw-r--r--src/librustc/mir/mod.rs12
-rw-r--r--src/librustc/session/mod.rs7
-rw-r--r--src/librustc/traits/error_reporting.rs17
-rw-r--r--src/librustc/traits/query/type_op/custom.rs10
-rw-r--r--src/librustc/traits/query/type_op/implied_outlives_bounds.rs80
-rw-r--r--src/librustc/traits/query/type_op/mod.rs1
-rw-r--r--src/librustc/traits/structural_impls.rs6
-rw-r--r--src/librustc/ty/context.rs12
-rw-r--r--src/librustc/ty/mod.rs7
-rw-r--r--src/librustc/ty/structural_impls.rs14
-rw-r--r--src/librustc/ty/subst.rs20
-rw-r--r--src/librustc/ty/util.rs8
-rw-r--r--src/librustc_allocator/expand.rs8
-rw-r--r--src/librustc_allocator/lib.rs1
-rw-r--r--src/librustc_apfloat/lib.rs1
-rw-r--r--src/librustc_asan/lib.rs1
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs4
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs6
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs16
-rw-r--r--src/librustc_borrowck/dataflow.rs12
-rw-r--r--src/librustc_borrowck/lib.rs1
-rw-r--r--src/librustc_codegen_llvm/attributes.rs3
-rw-r--r--src/librustc_codegen_llvm/back/linker.rs3
-rw-r--r--src/librustc_codegen_llvm/back/symbol_export.rs9
-rw-r--r--src/librustc_codegen_llvm/back/write.rs3
-rw-r--r--src/librustc_codegen_llvm/consts.rs6
-rw-r--r--src/librustc_codegen_llvm/lib.rs1
-rw-r--r--src/librustc_codegen_llvm/llvm/ffi.rs1
-rw-r--r--src/librustc_codegen_llvm/llvm_util.rs18
-rw-r--r--src/librustc_codegen_llvm/mir/constant.rs4
-rw-r--r--src/librustc_codegen_llvm/mir/operand.rs2
-rw-r--r--src/librustc_codegen_llvm/mir/place.rs2
-rw-r--r--src/librustc_codegen_utils/lib.rs1
-rw-r--r--src/librustc_codegen_utils/symbol_names.rs19
-rw-r--r--src/librustc_cratesio_shim/src/lib.rs1
-rw-r--r--src/librustc_data_structures/accumulate_vec.rs242
-rw-r--r--src/librustc_data_structures/graph/dominators/mod.rs4
-rw-r--r--src/librustc_data_structures/indexed_set.rs174
-rw-r--r--src/librustc_data_structures/lib.rs5
-rw-r--r--src/librustc_data_structures/small_vec.rs7
-rw-r--r--src/librustc_data_structures/vec_linked_list.rs83
-rw-r--r--src/librustc_driver/lib.rs57
-rw-r--r--src/librustc_driver/pretty.rs38
-rw-r--r--src/librustc_errors/lib.rs1
-rw-r--r--src/librustc_incremental/lib.rs1
-rw-r--r--src/librustc_incremental/persist/dirty_clean.rs15
-rw-r--r--src/librustc_lint/builtin.rs34
-rw-r--r--src/librustc_lint/lib.rs3
-rw-r--r--src/librustc_lint/types.rs4
-rw-r--r--src/librustc_llvm/lib.rs1
-rw-r--r--src/librustc_lsan/lib.rs1
-rw-r--r--src/librustc_metadata/lib.rs1
-rw-r--r--src/librustc_mir/borrow_check/flows.rs4
-rw-r--r--src/librustc_mir/borrow_check/mod.rs3
-rw-r--r--src/librustc_mir/borrow_check/mutability_errors.rs3
-rw-r--r--src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs32
-rw-r--r--src/librustc_mir/borrow_check/nll/mod.rs91
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/values.rs126
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs29
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs23
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs159
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs249
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs553
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs16
-rw-r--r--src/librustc_mir/build/mod.rs7
-rw-r--r--src/librustc_mir/const_eval.rs (renamed from src/librustc_mir/interpret/const_eval.rs)349
-rw-r--r--src/librustc_mir/dataflow/at_location.rs23
-rw-r--r--src/librustc_mir/dataflow/mod.rs24
-rw-r--r--src/librustc_mir/hair/cx/expr.rs28
-rw-r--r--src/librustc_mir/hair/cx/mod.rs3
-rw-r--r--src/librustc_mir/interpret/cast.rs2
-rw-r--r--src/librustc_mir/interpret/eval_context.rs223
-rw-r--r--src/librustc_mir/interpret/intrinsics.rs175
-rw-r--r--src/librustc_mir/interpret/machine.rs101
-rw-r--r--src/librustc_mir/interpret/memory.rs381
-rw-r--r--src/librustc_mir/interpret/mod.rs17
-rw-r--r--src/librustc_mir/interpret/operand.rs185
-rw-r--r--src/librustc_mir/interpret/operator.rs277
-rw-r--r--src/librustc_mir/interpret/place.rs341
-rw-r--r--src/librustc_mir/interpret/step.rs38
-rw-r--r--src/librustc_mir/interpret/terminator.rs (renamed from src/librustc_mir/interpret/terminator/mod.rs)330
-rw-r--r--src/librustc_mir/interpret/terminator/drop.rs66
-rw-r--r--src/librustc_mir/interpret/traits.rs13
-rw-r--r--src/librustc_mir/interpret/validity.rs193
-rw-r--r--src/librustc_mir/lib.rs4
-rw-r--r--src/librustc_mir/monomorphize/collector.rs7
-rw-r--r--src/librustc_mir/monomorphize/partitioning.rs6
-rw-r--r--src/librustc_mir/transform/add_validation.rs6
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs3
-rw-r--r--src/librustc_mir/transform/const_prop.rs23
-rw-r--r--src/librustc_mir/transform/generator.rs6
-rw-r--r--src/librustc_mir/transform/rustc_peek.rs4
-rw-r--r--src/librustc_mir/util/liveness.rs193
-rw-r--r--src/librustc_msan/lib.rs1
-rw-r--r--src/librustc_passes/lib.rs1
-rw-r--r--src/librustc_passes/loops.rs6
-rw-r--r--src/librustc_platform_intrinsics/lib.rs1
-rw-r--r--src/librustc_plugin/lib.rs1
-rw-r--r--src/librustc_privacy/lib.rs22
-rw-r--r--src/librustc_resolve/lib.rs89
-rw-r--r--src/librustc_save_analysis/lib.rs31
-rw-r--r--src/librustc_target/lib.rs1
-rw-r--r--src/librustc_target/spec/armebv7r_none_eabi.rs40
-rw-r--r--src/librustc_target/spec/armebv7r_none_eabihf.rs9
-rw-r--r--src/librustc_target/spec/armv7r_none_eabi.rs40
-rw-r--r--src/librustc_target/spec/armv7r_none_eabihf.rs41
-rw-r--r--src/librustc_target/spec/mod.rs3
-rw-r--r--src/librustc_target/spec/thumb_base.rs5
-rw-r--r--src/librustc_target/spec/thumbv6m_none_eabi.rs4
-rw-r--r--src/librustc_target/spec/thumbv7em_none_eabi.rs4
-rw-r--r--src/librustc_target/spec/thumbv7em_none_eabihf.rs4
-rw-r--r--src/librustc_target/spec/thumbv7m_none_eabi.rs4
-rw-r--r--src/librustc_traits/lib.rs1
-rw-r--r--src/librustc_tsan/lib.rs1
-rw-r--r--src/librustc_typeck/Cargo.toml7
-rw-r--r--src/librustc_typeck/astconv.rs28
-rw-r--r--src/librustc_typeck/check/demand.rs8
-rw-r--r--src/librustc_typeck/check/method/suggest.rs3
-rw-r--r--src/librustc_typeck/check/mod.rs22
-rw-r--r--src/librustc_typeck/check_unused.rs7
-rw-r--r--src/librustc_typeck/coherence/builtin.rs4
-rw-r--r--src/librustc_typeck/collect.rs133
-rw-r--r--src/librustc_typeck/lib.rs8
-rw-r--r--src/librustc_typeck/outlives/implicit_infer.rs41
-rw-r--r--src/librustc_typeck/outlives/mod.rs13
-rw-r--r--src/librustc_typeck/variance/mod.rs11
-rw-r--r--src/librustdoc/html/static/main.js52
-rw-r--r--src/librustdoc/html/static/rustdoc.css18
-rw-r--r--src/librustdoc/lib.rs1
-rw-r--r--src/librustdoc/visit_ast.rs8
-rw-r--r--src/libserialize/lib.rs1
-rw-r--r--src/libstd/alloc.rs8
-rw-r--r--src/libstd/future.rs2
-rw-r--r--src/libstd/keyword_docs.rs21
-rw-r--r--src/libstd/lib.rs3
-rw-r--r--src/libstd/macros.rs2
-rw-r--r--src/libstd/panic.rs2
-rw-r--r--src/libstd/process.rs10
-rw-r--r--src/libstd/sys/windows/backtrace/mod.rs9
-rw-r--r--src/libsyntax/lib.rs1
-rw-r--r--src/libsyntax/print/pprust.rs44
-rw-r--r--src/libsyntax_ext/lib.rs1
-rw-r--r--src/libsyntax_pos/lib.rs1
-rw-r--r--src/libterm/lib.rs1
-rw-r--r--src/libtest/formatters/terse.rs6
-rw-r--r--src/libtest/lib.rs1
-rw-r--r--src/libunwind/lib.rs1
-rw-r--r--src/rustllvm/PassWrapper.cpp13
-rw-r--r--src/test/mir-opt/nll/named-lifetimes-basic.rs18
-rw-r--r--src/test/run-make-fulldeps/target-cpu-native/Makefile19
-rw-r--r--src/test/run-make-fulldeps/use-suggestions-rust-2018/Makefile7
-rw-r--r--src/test/run-make-fulldeps/use-suggestions-rust-2018/ep-nested-lib.rs17
-rw-r--r--src/test/run-make-fulldeps/use-suggestions-rust-2018/use-suggestions.rs13
-rw-r--r--src/test/run-make/wasm-symbols-not-imported/Makefile16
-rw-r--r--src/test/run-make/wasm-symbols-not-imported/foo.rs26
-rw-r--r--src/test/run-make/wasm-symbols-not-imported/verify-no-imports.js20
-rw-r--r--src/test/run-pass-fulldeps/compiler-calls.rs4
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/auxiliary/issue-40001-plugin.rs3
-rw-r--r--src/test/run-pass/async-await.rs4
-rw-r--r--src/test/run-pass/ctfe/promotion.rs8
-rw-r--r--src/test/run-pass/futures-api.rs4
-rw-r--r--src/test/rustdoc-js/pinbox-new.js4
-rw-r--r--src/test/rustdoc-js/vec-new.js2
-rw-r--r--src/test/ui/anon-params-deprecated.stderr6
-rw-r--r--src/test/ui/chalkify/lower_trait.rs6
-rw-r--r--src/test/ui/chalkify/lower_trait_higher_rank.rs2
-rw-r--r--src/test/ui/chalkify/lower_trait_where_clause.rs6
-rw-r--r--src/test/ui/consts/const-eval/double_check2.stderr2
-rw-r--r--src/test/ui/consts/const-eval/ub-enum.stderr4
-rw-r--r--src/test/ui/crate-in-paths.rs22
-rw-r--r--src/test/ui/crate-in-paths.stderr13
-rw-r--r--src/test/ui/future-incompatible-lint-group.stderr2
-rw-r--r--src/test/ui/impl-trait/where-allowed.rs2
-rw-r--r--src/test/ui/issue-52992.rs37
-rw-r--r--src/test/ui/issue-53419.rs21
-rw-r--r--src/test/ui/issue-53568.rs61
-rw-r--r--src/test/ui/issues/issue-17718-const-bad-values.rs1
-rw-r--r--src/test/ui/issues/issue-17718-const-bad-values.stderr8
-rw-r--r--src/test/ui/issues/issue-46471-1.stderr17
-rw-r--r--src/test/ui/match/match-ref-mut-invariance.nll.stderr17
-rw-r--r--src/test/ui/match/match-ref-mut-let-invariance.nll.stderr19
-rw-r--r--src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs4
-rw-r--r--src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr2
-rw-r--r--src/test/ui/nll/mir_check_cast_unsize.rs4
-rw-r--r--src/test/ui/nll/mir_check_cast_unsize.stderr17
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr21
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr17
-rw-r--r--src/test/ui/panic-handler/panic-handler-std.stderr8
-rw-r--r--src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr48
-rw-r--r--src/test/ui/regions/regions-close-object-into-object-2.nll.stderr13
-rw-r--r--src/test/ui/regions/regions-close-object-into-object-4.nll.stderr19
-rw-r--r--src/test/ui/regions/regions-proc-bound-capture.nll.stderr15
-rw-r--r--src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.nll.stderr16
-rw-r--r--src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.nll.stderr16
-rw-r--r--src/test/ui/regions/regions-trait-object-subtyping.nll.stderr19
-rw-r--r--src/test/ui/rust-2018/auxiliary/remove-extern-crate.rs19
-rw-r--r--src/test/ui/rust-2018/remove-extern-crate.fixed39
-rw-r--r--src/test/ui/rust-2018/remove-extern-crate.rs39
-rw-r--r--src/test/ui/rust-2018/remove-extern-crate.stderr25
-rw-r--r--src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr17
-rw-r--r--src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr15
-rw-r--r--src/test/ui/union-ub-fat-ptr.rs33
-rw-r--r--src/test/ui/union-ub-fat-ptr.stderr72
-rw-r--r--src/tools/build-manifest/src/main.rs115
m---------src/tools/clippy28
253 files changed, 5136 insertions, 4037 deletions
diff --git a/src/Cargo.lock b/src/Cargo.lock
index 7d495a8041d..37a6f9130f5 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -224,18 +224,6 @@ dependencies = [
 
 [[package]]
 name = "cargo_metadata"
-version = "0.5.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "cargo_metadata"
 version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -307,7 +295,7 @@ name = "clippy"
 version = "0.0.212"
 dependencies = [
  "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "clippy-mini-macro-test 0.2.0",
  "clippy_lints 0.0.212",
  "compiletest_rs 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -329,7 +317,7 @@ version = "0.2.0"
 name = "clippy_lints"
 version = "0.0.212"
 dependencies = [
- "cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2366,6 +2354,7 @@ dependencies = [
  "rustc_errors 0.0.0",
  "rustc_platform_intrinsics 0.0.0",
  "rustc_target 0.0.0",
+ "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "syntax 0.0.0",
  "syntax_pos 0.0.0",
 ]
@@ -3071,7 +3060,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
 "checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32"
 "checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9"
-"checksum cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1efca0b863ca03ed4c109fb1c55e0bc4bbeb221d3e103d86251046b06a526bd0"
 "checksum cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6809b327f87369e6f3651efd2c5a96c49847a3ed2559477ecba79014751ee1"
 "checksum cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "4a6007c146fdd28d4512a794b07ffe9d8e89e6bf86e2e0c4ddff2e1fb54a0007"
 "checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
diff --git a/src/ci/docker/disabled/dist-armebv7r-none-eabihf/Dockerfile b/src/ci/docker/disabled/dist-armebv7r-none-eabihf/Dockerfile
deleted file mode 100644
index 34c6e640abb..00000000000
--- a/src/ci/docker/disabled/dist-armebv7r-none-eabihf/Dockerfile
+++ /dev/null
@@ -1,36 +0,0 @@
-FROM ubuntu:16.04
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
-  g++ \
-  make \
-  file \
-  curl \
-  ca-certificates \
-  python2.7 \
-  git \
-  cmake \
-  sudo \
-  xz-utils \
-  bzip2 \
-  libssl-dev \
-  pkg-config
-
-
-COPY scripts/sccache.sh /scripts/
-RUN sh /scripts/sccache.sh
-
-ENV BASE_URL=https://releases.linaro.org/components/toolchain/binaries/latest/armeb-eabi/
-ENV GCC_LINARO=gcc-linaro-7.2.1-2017.11-x86_64_armeb-eabi
-
-RUN curl -sL $BASE_URL/$GCC_LINARO.tar.xz | tar -xJ
-
-ENV PATH=$PATH:/$GCC_LINARO/bin
-
-ENV TARGET=armebv7r-none-eabihf
-
-ENV CC_armebv7r_none_eabihf=armeb-eabi-gcc \
-    CFLAGS_armebv7r_none_eabihf="-march=armv7-r"
-
-ENV RUST_CONFIGURE_ARGS --disable-docs
-
-ENV SCRIPT python2.7 ../x.py dist --target $TARGET
diff --git a/src/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile
index bfc5e712f76..e072959baa9 100644
--- a/src/ci/docker/dist-various-1/Dockerfile
+++ b/src/ci/docker/dist-various-1/Dockerfile
@@ -103,11 +103,16 @@ ENV TARGETS=$TARGETS,thumbv7m-none-eabi
 ENV TARGETS=$TARGETS,thumbv7em-none-eabi
 ENV TARGETS=$TARGETS,thumbv7em-none-eabihf
 ENV TARGETS=$TARGETS,riscv32imac-unknown-none-elf
+ENV TARGETS=$TARGETS,armebv7r-none-eabi
+ENV TARGETS=$TARGETS,armebv7r-none-eabihf
+ENV TARGETS=$TARGETS,armv7r-none-eabi
+ENV TARGETS=$TARGETS,armv7r-none-eabihf
 
 ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \
     CC_mips_unknown_linux_musl=mips-openwrt-linux-gcc \
     CC_sparc64_unknown_linux_gnu=sparc64-linux-gnu-gcc \
-    CC_x86_64_unknown_redox=x86_64-unknown-redox-gcc
+    CC_x86_64_unknown_redox=x86_64-unknown-redox-gcc \
+    CC_armebv7r_none_eabi=arm-none-eabi-gcc
 
 ENV RUST_CONFIGURE_ARGS \
       --musl-root-armv5te=/musl-armv5te \
@@ -120,7 +125,7 @@ ENV RUST_CONFIGURE_ARGS \
       --enable-emscripten \
       --disable-docs
 
-ENV SCRIPT \ 
+ENV SCRIPT \
       python2.7 ../x.py test --target $RUN_MAKE_TARGETS src/test/run-make && \
       python2.7 ../x.py dist --target $TARGETS
 
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index 32292e61f94..c25f3eb8f17 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -64,12 +64,14 @@ use core::future::{Future, FutureObj, LocalFutureObj, UnsafeFutureObj};
 use core::hash::{Hash, Hasher};
 use core::iter::FusedIterator;
 use core::marker::{Unpin, Unsize};
-use core::mem::{self, PinMut};
+use core::mem;
+use core::pin::PinMut;
 use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState};
 use core::ptr::{self, NonNull, Unique};
 use core::task::{Context, Poll, Spawn, SpawnErrorKind, SpawnObjError};
 
 use raw_vec::RawVec;
+use pin::PinBox;
 use str::from_boxed_utf8_unchecked;
 
 /// A pointer type for heap allocation.
@@ -758,166 +760,6 @@ impl<T> Generator for Box<T>
     }
 }
 
-/// A pinned, heap allocated reference.
-#[unstable(feature = "pin", issue = "49150")]
-#[fundamental]
-#[repr(transparent)]
-pub struct PinBox<T: ?Sized> {
-    inner: Box<T>,
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T> PinBox<T> {
-    /// Allocate memory on the heap, move the data into it and pin it.
-    #[unstable(feature = "pin", issue = "49150")]
-    pub fn new(data: T) -> PinBox<T> {
-        PinBox { inner: Box::new(data) }
-    }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: ?Sized> PinBox<T> {
-    /// Get a pinned reference to the data in this PinBox.
-    #[inline]
-    pub fn as_pin_mut<'a>(&'a mut self) -> PinMut<'a, T> {
-        unsafe { PinMut::new_unchecked(&mut *self.inner) }
-    }
-
-    /// Constructs a `PinBox` from a raw pointer.
-    ///
-    /// After calling this function, the raw pointer is owned by the
-    /// resulting `PinBox`. Specifically, the `PinBox` destructor will call
-    /// the destructor of `T` and free the allocated memory. Since the
-    /// way `PinBox` allocates and releases memory is unspecified, the
-    /// only valid pointer to pass to this function is the one taken
-    /// from another `PinBox` via the [`PinBox::into_raw`] function.
-    ///
-    /// This function is unsafe because improper use may lead to
-    /// memory problems. For example, a double-free may occur if the
-    /// function is called twice on the same raw pointer.
-    ///
-    /// [`PinBox::into_raw`]: struct.PinBox.html#method.into_raw
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(pin)]
-    /// use std::boxed::PinBox;
-    /// let x = PinBox::new(5);
-    /// let ptr = PinBox::into_raw(x);
-    /// let x = unsafe { PinBox::from_raw(ptr) };
-    /// ```
-    #[inline]
-    pub unsafe fn from_raw(raw: *mut T) -> Self {
-        PinBox { inner: Box::from_raw(raw) }
-    }
-
-    /// Consumes the `PinBox`, returning the wrapped raw pointer.
-    ///
-    /// After calling this function, the caller is responsible for the
-    /// memory previously managed by the `PinBox`. In particular, the
-    /// caller should properly destroy `T` and release the memory. The
-    /// proper way to do so is to convert the raw pointer back into a
-    /// `PinBox` with the [`PinBox::from_raw`] function.
-    ///
-    /// Note: this is an associated function, which means that you have
-    /// to call it as `PinBox::into_raw(b)` instead of `b.into_raw()`. This
-    /// is so that there is no conflict with a method on the inner type.
-    ///
-    /// [`PinBox::from_raw`]: struct.PinBox.html#method.from_raw
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(pin)]
-    /// use std::boxed::PinBox;
-    /// let x = PinBox::new(5);
-    /// let ptr = PinBox::into_raw(x);
-    /// ```
-    #[inline]
-    pub fn into_raw(b: PinBox<T>) -> *mut T {
-        Box::into_raw(b.inner)
-    }
-
-    /// Get a mutable reference to the data inside this PinBox.
-    ///
-    /// This function is unsafe. Users must guarantee that the data is never
-    /// moved out of this reference.
-    #[inline]
-    pub unsafe fn get_mut<'a>(this: &'a mut PinBox<T>) -> &'a mut T {
-        &mut *this.inner
-    }
-
-    /// Convert this PinBox into an unpinned Box.
-    ///
-    /// This function is unsafe. Users must guarantee that the data is never
-    /// moved out of the box.
-    #[inline]
-    pub unsafe fn unpin(this: PinBox<T>) -> Box<T> {
-        this.inner
-    }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: ?Sized> From<Box<T>> for PinBox<T> {
-    fn from(boxed: Box<T>) -> PinBox<T> {
-        PinBox { inner: boxed }
-    }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: Unpin + ?Sized> From<PinBox<T>> for Box<T> {
-    fn from(pinned: PinBox<T>) -> Box<T> {
-        pinned.inner
-    }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: ?Sized> Deref for PinBox<T> {
-    type Target = T;
-
-    fn deref(&self) -> &T {
-        &*self.inner
-    }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: Unpin + ?Sized> DerefMut for PinBox<T> {
-    fn deref_mut(&mut self) -> &mut T {
-        &mut *self.inner
-    }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: fmt::Display + ?Sized> fmt::Display for PinBox<T> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Display::fmt(&*self.inner, f)
-    }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: fmt::Debug + ?Sized> fmt::Debug for PinBox<T> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Debug::fmt(&*self.inner, f)
-    }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: ?Sized> fmt::Pointer for PinBox<T> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        // It's not possible to extract the inner Uniq directly from the Box,
-        // instead we cast it to a *const which aliases the Unique
-        let ptr: *const T = &*self.inner;
-        fmt::Pointer::fmt(&ptr, f)
-    }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<PinBox<U>> for PinBox<T> {}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: ?Sized> Unpin for PinBox<T> {}
-
 #[unstable(feature = "futures_api", issue = "50547")]
 impl<F: ?Sized + Future + Unpin> Future for Box<F> {
     type Output = F::Output;
@@ -928,15 +770,6 @@ impl<F: ?Sized + Future + Unpin> Future for Box<F> {
 }
 
 #[unstable(feature = "futures_api", issue = "50547")]
-impl<F: ?Sized + Future> Future for PinBox<F> {
-    type Output = F::Output;
-
-    fn poll(mut self: PinMut<Self>, cx: &mut Context) -> Poll<Self::Output> {
-        self.as_pin_mut().poll(cx)
-    }
-}
-
-#[unstable(feature = "futures_api", issue = "50547")]
 unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for Box<F>
     where F: Future<Output = T> + 'a
 {
@@ -956,25 +789,6 @@ unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for Box<F>
 }
 
 #[unstable(feature = "futures_api", issue = "50547")]
-unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for PinBox<F>
-    where F: Future<Output = T> + 'a
-{
-    fn into_raw(self) -> *mut () {
-        PinBox::into_raw(self) as *mut ()
-    }
-
-    unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T> {
-        let ptr = ptr as *mut F;
-        let pin: PinMut<F> = PinMut::new_unchecked(&mut *ptr);
-        pin.poll(cx)
-    }
-
-    unsafe fn drop(ptr: *mut ()) {
-        drop(PinBox::from_raw(ptr as *mut F))
-    }
-}
-
-#[unstable(feature = "futures_api", issue = "50547")]
 impl<Sp> Spawn for Box<Sp>
     where Sp: Spawn + ?Sized
 {
@@ -991,13 +805,6 @@ impl<Sp> Spawn for Box<Sp>
 }
 
 #[unstable(feature = "futures_api", issue = "50547")]
-impl<'a, F: Future<Output = ()> + Send + 'a> From<PinBox<F>> for FutureObj<'a, ()> {
-    fn from(boxed: PinBox<F>) -> Self {
-        FutureObj::new(boxed)
-    }
-}
-
-#[unstable(feature = "futures_api", issue = "50547")]
 impl<'a, F: Future<Output = ()> + Send + 'a> From<Box<F>> for FutureObj<'a, ()> {
     fn from(boxed: Box<F>) -> Self {
         FutureObj::new(boxed)
@@ -1005,15 +812,15 @@ impl<'a, F: Future<Output = ()> + Send + 'a> From<Box<F>> for FutureObj<'a, ()>
 }
 
 #[unstable(feature = "futures_api", issue = "50547")]
-impl<'a, F: Future<Output = ()> + 'a> From<PinBox<F>> for LocalFutureObj<'a, ()> {
-    fn from(boxed: PinBox<F>) -> Self {
+impl<'a, F: Future<Output = ()> + 'a> From<Box<F>> for LocalFutureObj<'a, ()> {
+    fn from(boxed: Box<F>) -> Self {
         LocalFutureObj::new(boxed)
     }
 }
 
-#[unstable(feature = "futures_api", issue = "50547")]
-impl<'a, F: Future<Output = ()> + 'a> From<Box<F>> for LocalFutureObj<'a, ()> {
-    fn from(boxed: Box<F>) -> Self {
-        LocalFutureObj::new(boxed)
+#[unstable(feature = "pin", issue = "49150")]
+impl<T: Unpin + ?Sized> From<PinBox<T>> for Box<T> {
+    fn from(pinned: PinBox<T>) -> Box<T> {
+        unsafe { PinBox::unpin(pinned) }
     }
 }
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index bcdfd8c9aa5..676c977514f 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -77,6 +77,7 @@
 #![cfg_attr(not(test), feature(fn_traits))]
 #![cfg_attr(not(test), feature(generator_trait))]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![cfg_attr(test, feature(test))]
 
 #![feature(allocator_api)]
@@ -159,6 +160,7 @@ pub mod collections;
 pub mod sync;
 pub mod rc;
 pub mod raw_vec;
+pub mod pin;
 pub mod prelude;
 pub mod borrow;
 pub mod fmt;
diff --git a/src/liballoc/pin.rs b/src/liballoc/pin.rs
new file mode 100644
index 00000000000..17bbc9882d9
--- /dev/null
+++ b/src/liballoc/pin.rs
@@ -0,0 +1,302 @@
+//! Types which pin data to its location in memory
+//!
+//! It is sometimes useful to have objects that are guaranteed to not move,
+//! in the sense that their placement in memory does not change, and can thus be relied upon.
+//!
+//! A prime example of such a scenario would be building self-referencial structs,
+//! since moving an object with pointers to itself will invalidate them,
+//! which could cause undefined behavior.
+//!
+//! In order to prevent objects from moving, they must be *pinned*,
+//! by wrapping the data in pinning pointer types, such as [`PinMut`] and [`PinBox`],
+//! which are otherwise equivalent to `& mut` and [`Box`], respectively.
+//!
+//! First of all, these are pointer types because pinned data mustn't be passed around by value
+//! (that would change its location in memory).
+//! Secondly, since data can be moved out of `&mut` and [`Box`] with functions such as [`swap`],
+//! which causes their contents to swap places in memory,
+//! we need dedicated types that prohibit such operations.
+//!
+//! However, these restrictions are usually not necessary,
+//! so most types implement the [`Unpin`] auto-trait,
+//! which indicates that the type can be moved out safely.
+//! Doing so removes the limitations of pinning types,
+//! making them the same as their non-pinning counterparts.
+//!
+//! [`PinMut`]: struct.PinMut.html
+//! [`PinBox`]: struct.PinBox.html
+//! [`Unpin`]: trait.Unpin.html
+//! [`swap`]: ../../std/mem/fn.swap.html
+//! [`Box`]: ../boxed/struct.Box.html
+//!
+//! # Examples
+//!
+//! ```rust
+//! #![feature(pin)]
+//!
+//! use std::pin::PinBox;
+//! use std::marker::Pinned;
+//! use std::ptr::NonNull;
+//!
+//! // This is a self referencial struct since the slice field points to the data field.
+//! // We cannot inform the compiler about that with a normal reference,
+//! // since this pattern cannot be described with the usual borrowing rules.
+//! // Instead we use a raw pointer, though one which is known to not be null,
+//! // since we know it's pointing at the string.
+//! struct Unmovable {
+//!     data: String,
+//!     slice: NonNull<String>,
+//!     _pin: Pinned,
+//! }
+//!
+//! impl Unmovable {
+//!     // To ensure the data doesn't move when the function returns,
+//!     // we place it in the heap where it will stay for the lifetime of the object,
+//!     // and the only way to access it would be through a pointer to it.
+//!     fn new(data: String) -> PinBox<Self> {
+//!         let res = Unmovable {
+//!             data,
+//!             // we only create the pointer once the data is in place
+//!             // otherwise it will have already moved before we even started
+//!             slice: NonNull::dangling(),
+//!             _pin: Pinned,
+//!         };
+//!         let mut boxed = PinBox::new(res);
+//!
+//!         let slice = NonNull::from(&boxed.data);
+//!         // we know this is safe because modifying a field doesn't move the whole struct
+//!         unsafe { PinBox::get_mut(&mut boxed).slice = slice };
+//!         boxed
+//!     }
+//! }
+//!
+//! let unmoved = Unmovable::new("hello".to_string());
+//! // The pointer should point to the correct location,
+//! // so long as the struct hasn't moved.
+//! // Meanwhile, we are free to move the pointer around.
+//! # #[allow(unused_mut)]
+//! let mut still_unmoved = unmoved;
+//! assert_eq!(still_unmoved.slice, NonNull::from(&still_unmoved.data));
+//!
+//! // Since our type doesn't implement Unpin, this will fail to compile:
+//! // let new_unmoved = Unmovable::new("world".to_string());
+//! // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved);
+//! ```
+
+#![unstable(feature = "pin", issue = "49150")]
+
+pub use core::pin::*;
+pub use core::marker::Unpin;
+
+use core::convert::From;
+use core::fmt;
+use core::future::{Future, FutureObj, LocalFutureObj, UnsafeFutureObj};
+use core::marker::Unsize;
+use core::ops::{CoerceUnsized, Deref, DerefMut};
+use core::task::{Context, Poll};
+
+use boxed::Box;
+
+/// A pinned, heap allocated reference.
+///
+/// This type is similar to [`Box`], except that it pins its value,
+/// which prevents it from moving out of the reference, unless it implements [`Unpin`].
+///
+/// See the [module documentation] for furthur explaination on pinning.
+///
+/// [`Box`]: ../boxed/struct.Box.html
+/// [`Unpin`]: ../../std/marker/trait.Unpin.html
+/// [module documentation]: index.html
+#[unstable(feature = "pin", issue = "49150")]
+#[fundamental]
+#[repr(transparent)]
+pub struct PinBox<T: ?Sized> {
+    inner: Box<T>,
+}
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<T> PinBox<T> {
+    /// Allocate memory on the heap, move the data into it and pin it.
+    #[unstable(feature = "pin", issue = "49150")]
+    pub fn new(data: T) -> PinBox<T> {
+        PinBox { inner: Box::new(data) }
+    }
+}
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<T: ?Sized> PinBox<T> {
+    /// Get a pinned reference to the data in this PinBox.
+    #[inline]
+    pub fn as_pin_mut<'a>(&'a mut self) -> PinMut<'a, T> {
+        unsafe { PinMut::new_unchecked(&mut *self.inner) }
+    }
+
+    /// Constructs a `PinBox` from a raw pointer.
+    ///
+    /// After calling this function, the raw pointer is owned by the
+    /// resulting `PinBox`. Specifically, the `PinBox` destructor will call
+    /// the destructor of `T` and free the allocated memory. Since the
+    /// way `PinBox` allocates and releases memory is unspecified, the
+    /// only valid pointer to pass to this function is the one taken
+    /// from another `PinBox` via the [`PinBox::into_raw`] function.
+    ///
+    /// This function is unsafe because improper use may lead to
+    /// memory problems. For example, a double-free may occur if the
+    /// function is called twice on the same raw pointer.
+    ///
+    /// [`PinBox::into_raw`]: struct.PinBox.html#method.into_raw
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(pin)]
+    /// use std::pin::PinBox;
+    /// let x = PinBox::new(5);
+    /// let ptr = PinBox::into_raw(x);
+    /// let x = unsafe { PinBox::from_raw(ptr) };
+    /// ```
+    #[inline]
+    pub unsafe fn from_raw(raw: *mut T) -> Self {
+        PinBox { inner: Box::from_raw(raw) }
+    }
+
+    /// Consumes the `PinBox`, returning the wrapped raw pointer.
+    ///
+    /// After calling this function, the caller is responsible for the
+    /// memory previously managed by the `PinBox`. In particular, the
+    /// caller should properly destroy `T` and release the memory. The
+    /// proper way to do so is to convert the raw pointer back into a
+    /// `PinBox` with the [`PinBox::from_raw`] function.
+    ///
+    /// Note: this is an associated function, which means that you have
+    /// to call it as `PinBox::into_raw(b)` instead of `b.into_raw()`. This
+    /// is so that there is no conflict with a method on the inner type.
+    ///
+    /// [`PinBox::from_raw`]: struct.PinBox.html#method.from_raw
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(pin)]
+    /// use std::pin::PinBox;
+    /// let x = PinBox::new(5);
+    /// let ptr = PinBox::into_raw(x);
+    /// ```
+    #[inline]
+    pub fn into_raw(b: PinBox<T>) -> *mut T {
+        Box::into_raw(b.inner)
+    }
+
+    /// Get a mutable reference to the data inside this PinBox.
+    ///
+    /// This function is unsafe. Users must guarantee that the data is never
+    /// moved out of this reference.
+    #[inline]
+    pub unsafe fn get_mut<'a>(this: &'a mut PinBox<T>) -> &'a mut T {
+        &mut *this.inner
+    }
+
+    /// Convert this PinBox into an unpinned Box.
+    ///
+    /// This function is unsafe. Users must guarantee that the data is never
+    /// moved out of the box.
+    #[inline]
+    pub unsafe fn unpin(this: PinBox<T>) -> Box<T> {
+        this.inner
+    }
+}
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<T: ?Sized> From<Box<T>> for PinBox<T> {
+    fn from(boxed: Box<T>) -> PinBox<T> {
+        PinBox { inner: boxed }
+    }
+}
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<T: ?Sized> Deref for PinBox<T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        &*self.inner
+    }
+}
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<T: Unpin + ?Sized> DerefMut for PinBox<T> {
+    fn deref_mut(&mut self) -> &mut T {
+        &mut *self.inner
+    }
+}
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<T: fmt::Display + ?Sized> fmt::Display for PinBox<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&*self.inner, f)
+    }
+}
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<T: fmt::Debug + ?Sized> fmt::Debug for PinBox<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&*self.inner, f)
+    }
+}
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<T: ?Sized> fmt::Pointer for PinBox<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        // It's not possible to extract the inner Uniq directly from the Box,
+        // instead we cast it to a *const which aliases the Unique
+        let ptr: *const T = &*self.inner;
+        fmt::Pointer::fmt(&ptr, f)
+    }
+}
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<PinBox<U>> for PinBox<T> {}
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<T: ?Sized> Unpin for PinBox<T> {}
+
+#[unstable(feature = "futures_api", issue = "50547")]
+impl<F: ?Sized + Future> Future for PinBox<F> {
+    type Output = F::Output;
+
+    fn poll(mut self: PinMut<Self>, cx: &mut Context) -> Poll<Self::Output> {
+        self.as_pin_mut().poll(cx)
+    }
+}
+
+#[unstable(feature = "futures_api", issue = "50547")]
+unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for PinBox<F>
+    where F: Future<Output = T> + 'a
+{
+    fn into_raw(self) -> *mut () {
+        PinBox::into_raw(self) as *mut ()
+    }
+
+    unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T> {
+        let ptr = ptr as *mut F;
+        let pin: PinMut<F> = PinMut::new_unchecked(&mut *ptr);
+        pin.poll(cx)
+    }
+
+    unsafe fn drop(ptr: *mut ()) {
+        drop(PinBox::from_raw(ptr as *mut F))
+    }
+}
+
+#[unstable(feature = "futures_api", issue = "50547")]
+impl<'a, F: Future<Output = ()> + Send + 'a> From<PinBox<F>> for FutureObj<'a, ()> {
+    fn from(boxed: PinBox<F>) -> Self {
+        FutureObj::new(boxed)
+    }
+}
+
+#[unstable(feature = "futures_api", issue = "50547")]
+impl<'a, F: Future<Output = ()> + 'a> From<PinBox<F>> for LocalFutureObj<'a, ()> {
+    fn from(boxed: PinBox<F>) -> Self {
+        LocalFutureObj::new(boxed)
+    }
+}
diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs
index 480a24b9bd1..3d2348f3e45 100644
--- a/src/liballoc_jemalloc/lib.rs
+++ b/src/liballoc_jemalloc/lib.rs
@@ -17,6 +17,7 @@
 #![feature(libc)]
 #![feature(linkage)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(staged_api)]
 #![feature(rustc_attrs)]
 #![cfg_attr(dummy_jemalloc, allow(dead_code, unused_extern_crates))]
@@ -89,16 +90,16 @@ mod contents {
     // linkage directives are provided as part of the current compiler allocator
     // ABI
 
-    #[no_mangle]
     #[rustc_std_internal_symbol]
+    #[cfg_attr(stage0, no_mangle)]
     pub unsafe extern fn __rde_alloc(size: usize, align: usize) -> *mut u8 {
         let flags = align_to_flags(align, size);
         let ptr = mallocx(size as size_t, flags) as *mut u8;
         ptr
     }
 
-    #[no_mangle]
     #[rustc_std_internal_symbol]
+    #[cfg_attr(stage0, no_mangle)]
     pub unsafe extern fn __rde_dealloc(ptr: *mut u8,
                                        size: usize,
                                        align: usize) {
@@ -106,8 +107,8 @@ mod contents {
         sdallocx(ptr as *mut c_void, size, flags);
     }
 
-    #[no_mangle]
     #[rustc_std_internal_symbol]
+    #[cfg_attr(stage0, no_mangle)]
     pub unsafe extern fn __rde_realloc(ptr: *mut u8,
                                        _old_size: usize,
                                        align: usize,
@@ -117,8 +118,8 @@ mod contents {
         ptr
     }
 
-    #[no_mangle]
     #[rustc_std_internal_symbol]
+    #[cfg_attr(stage0, no_mangle)]
     pub unsafe extern fn __rde_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
         let ptr = if align <= MIN_ALIGN && align <= size {
             calloc(size as size_t, 1) as *mut u8
diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs
index 753b6a5e292..ffab9e8e4af 100644
--- a/src/liballoc_system/lib.rs
+++ b/src/liballoc_system/lib.rs
@@ -18,6 +18,7 @@
 #![feature(allocator_api)]
 #![feature(core_intrinsics)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(staged_api)]
 #![feature(rustc_attrs)]
 #![cfg_attr(any(unix, target_os = "cloudabi", target_os = "redox"), feature(libc))]
diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs
index 6ad703180c2..5cb8975e9ce 100644
--- a/src/libarena/lib.rs
+++ b/src/libarena/lib.rs
@@ -27,6 +27,7 @@
 #![feature(core_intrinsics)]
 #![feature(dropck_eyepatch)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(raw_vec_internals)]
 #![cfg_attr(test, feature(test))]
 
diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs
index 10b4ca9b0b2..520b6ebbbaa 100644
--- a/src/libcore/future/future.rs
+++ b/src/libcore/future/future.rs
@@ -12,7 +12,7 @@
             reason = "futures in libcore are unstable",
             issue = "50547")]
 
-use mem::PinMut;
+use pin::PinMut;
 use marker::Unpin;
 use task::{self, Poll};
 
diff --git a/src/libcore/future/future_obj.rs b/src/libcore/future/future_obj.rs
index 2df870a011d..68fe461aeae 100644
--- a/src/libcore/future/future_obj.rs
+++ b/src/libcore/future/future_obj.rs
@@ -15,7 +15,7 @@
 use fmt;
 use future::Future;
 use marker::{PhantomData, Unpin};
-use mem::PinMut;
+use pin::PinMut;
 use task::{Context, Poll};
 
 /// A custom trait object for polling futures, roughly akin to
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index b2ffc9d77d7..2aa3226af89 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -92,6 +92,7 @@
 #![feature(link_llvm_intrinsics)]
 #![feature(never_type)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(exhaustive_patterns)]
 #![feature(macro_at_most_once_rep)]
 #![feature(no_core)]
@@ -190,6 +191,7 @@ pub mod cell;
 pub mod char;
 pub mod panic;
 pub mod panicking;
+pub mod pin;
 pub mod iter;
 pub mod option;
 pub mod raw;
diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs
index b1dc84bb84c..dd57d2dd009 100644
--- a/src/libcore/marker.rs
+++ b/src/libcore/marker.rs
@@ -611,6 +611,7 @@ unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {}
 /// Instead it can be used to prevent moves through the type system,
 /// by controlling the behavior of special pointer types like [`PinMut`],
 /// which "pin" the type in place by not allowing it to be moved out of them.
+/// See the [`pin module`] documentation for more information on pinning.
 ///
 /// Implementing this trait lifts the restrictions of pinning off a type,
 /// which then allows it to move out with functions such as [`replace`].
@@ -619,7 +620,8 @@ unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {}
 ///
 /// ```rust
 /// #![feature(pin)]
-/// use std::mem::{PinMut, replace};
+/// use std::mem::replace;
+/// use std::pin::PinMut;
 ///
 /// let mut string = "this".to_string();
 /// let mut pinned_string = PinMut::new(&mut string);
@@ -630,8 +632,9 @@ unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {}
 ///
 /// This trait is automatically implemented for almost every type.
 ///
-/// [`PinMut`]: ../mem/struct.PinMut.html
-/// [`replace`]: ../mem/fn.replace.html
+/// [`replace`]: ../../std/mem/fn.replace.html
+/// [`PinMut`]: ../pin/struct.PinMut.html
+/// [`pin module`]: ../../std/pin/index.html
 #[unstable(feature = "pin", issue = "49150")]
 pub auto trait Unpin {}
 
diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs
index 67cceb9d536..f2852d98282 100644
--- a/src/libcore/mem.rs
+++ b/src/libcore/mem.rs
@@ -18,13 +18,11 @@
 use clone;
 use cmp;
 use fmt;
-use future::{Future, UnsafeFutureObj};
 use hash;
 use intrinsics;
-use marker::{Copy, PhantomData, Sized, Unpin, Unsize};
+use marker::{Copy, PhantomData, Sized};
 use ptr;
-use task::{Context, Poll};
-use ops::{Deref, DerefMut, CoerceUnsized};
+use ops::{Deref, DerefMut};
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use intrinsics::transmute;
@@ -992,146 +990,3 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
         &mut self.value
     }
 }
-
-/// A pinned reference.
-///
-/// A pinned reference is a lot like a mutable reference, except that it is not
-/// safe to move a value out of a pinned reference unless the type of that
-/// value implements the `Unpin` trait.
-#[unstable(feature = "pin", issue = "49150")]
-#[fundamental]
-pub struct PinMut<'a, T: ?Sized + 'a> {
-    inner: &'a mut T,
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized + Unpin> PinMut<'a, T> {
-    /// Construct a new `PinMut` around a reference to some data of a type that
-    /// implements `Unpin`.
-    #[unstable(feature = "pin", issue = "49150")]
-    pub fn new(reference: &'a mut T) -> PinMut<'a, T> {
-        PinMut { inner: reference }
-    }
-
-    /// Get a mutable reference to the data inside of this `PinMut`.
-    #[unstable(feature = "pin", issue = "49150")]
-    pub fn get_mut(this: PinMut<'a, T>) -> &'a mut T {
-        this.inner
-    }
-}
-
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized> PinMut<'a, T> {
-    /// Construct a new `PinMut` around a reference to some data of a type that
-    /// may or may not implement `Unpin`.
-    ///
-    /// This constructor is unsafe because we do not know what will happen with
-    /// that data after the reference ends. If you cannot guarantee that the
-    /// data will never move again, calling this constructor is invalid.
-    #[unstable(feature = "pin", issue = "49150")]
-    pub unsafe fn new_unchecked(reference: &'a mut T) -> PinMut<'a, T> {
-        PinMut { inner: reference }
-    }
-
-    /// Reborrow a `PinMut` for a shorter lifetime.
-    ///
-    /// For example, `PinMut::get_mut(x.reborrow())` (unsafely) returns a
-    /// short-lived mutable reference reborrowing from `x`.
-    #[unstable(feature = "pin", issue = "49150")]
-    pub fn reborrow<'b>(&'b mut self) -> PinMut<'b, T> {
-        PinMut { inner: self.inner }
-    }
-
-    /// Get a mutable reference to the data inside of this `PinMut`.
-    ///
-    /// This function is unsafe. You must guarantee that you will never move
-    /// the data out of the mutable reference you receive when you call this
-    /// function.
-    #[unstable(feature = "pin", issue = "49150")]
-    pub unsafe fn get_mut_unchecked(this: PinMut<'a, T>) -> &'a mut T {
-        this.inner
-    }
-
-    /// Construct a new pin by mapping the interior value.
-    ///
-    /// For example, if you  wanted to get a `PinMut` of a field of something,
-    /// you could use this to get access to that field in one line of code.
-    ///
-    /// This function is unsafe. You must guarantee that the data you return
-    /// will not move so long as the argument value does not move (for example,
-    /// because it is one of the fields of that value), and also that you do
-    /// not move out of the argument you receive to the interior function.
-    #[unstable(feature = "pin", issue = "49150")]
-    pub unsafe fn map_unchecked<U, F>(this: PinMut<'a, T>, f: F) -> PinMut<'a, U> where
-        F: FnOnce(&mut T) -> &mut U
-    {
-        PinMut { inner: f(this.inner) }
-    }
-
-    /// Assign a new value to the memory behind the pinned reference.
-    #[unstable(feature = "pin", issue = "49150")]
-    pub fn set(this: PinMut<'a, T>, value: T)
-        where T: Sized,
-    {
-        *this.inner = value;
-    }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized> Deref for PinMut<'a, T> {
-    type Target = T;
-
-    fn deref(&self) -> &T {
-        &*self.inner
-    }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized + Unpin> DerefMut for PinMut<'a, T> {
-    fn deref_mut(&mut self) -> &mut T {
-        self.inner
-    }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: fmt::Debug + ?Sized> fmt::Debug for PinMut<'a, T> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Debug::fmt(&**self, f)
-    }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: fmt::Display + ?Sized> fmt::Display for PinMut<'a, T> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Display::fmt(&**self, f)
-    }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized> fmt::Pointer for PinMut<'a, T> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Pointer::fmt(&(&*self.inner as *const T), f)
-    }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<PinMut<'a, U>> for PinMut<'a, T> {}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized> Unpin for PinMut<'a, T> {}
-
-#[unstable(feature = "futures_api", issue = "50547")]
-unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for PinMut<'a, F>
-    where F: Future<Output = T> + 'a
-{
-    fn into_raw(self) -> *mut () {
-        unsafe { PinMut::get_mut_unchecked(self) as *mut F as *mut () }
-    }
-
-    unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T> {
-        PinMut::new_unchecked(&mut *(ptr as *mut F)).poll(cx)
-    }
-
-    unsafe fn drop(_ptr: *mut ()) {}
-}
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index f743fbfd075..3879abb0af9 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -147,7 +147,7 @@
 
 use iter::{FromIterator, FusedIterator, TrustedLen};
 use {hint, mem, ops::{self, Deref}};
-use mem::PinMut;
+use pin::PinMut;
 
 // Note that this is not a lang item per se, but it has a hidden dependency on
 // `Iterator`, which is one. The compiler assumes that the `next` method of
diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs
new file mode 100644
index 00000000000..e9001f86b35
--- /dev/null
+++ b/src/libcore/pin.rs
@@ -0,0 +1,160 @@
+//! Types which pin data to its location in memory
+//!
+//! See the [standard library module] for more information.
+//!
+//! [standard library module]: ../../std/pin/index.html
+
+#![unstable(feature = "pin", issue = "49150")]
+
+use fmt;
+use future::{Future, UnsafeFutureObj};
+use marker::{Sized, Unpin, Unsize};
+use task::{Context, Poll};
+use ops::{Deref, DerefMut, CoerceUnsized};
+
+/// A pinned reference.
+///
+/// This type is similar to a mutable reference, except that it pins its value,
+/// which prevents it from moving out of the reference, unless it implements [`Unpin`].
+///
+/// See the [`pin` module] documentation for furthur explanation on pinning.
+///
+/// [`Unpin`]: ../../std/marker/trait.Unpin.html
+/// [`pin` module]: ../../std/pin/index.html
+#[unstable(feature = "pin", issue = "49150")]
+#[fundamental]
+pub struct PinMut<'a, T: ?Sized + 'a> {
+    inner: &'a mut T,
+}
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<'a, T: ?Sized + Unpin> PinMut<'a, T> {
+    /// Construct a new `PinMut` around a reference to some data of a type that
+    /// implements `Unpin`.
+    #[unstable(feature = "pin", issue = "49150")]
+    pub fn new(reference: &'a mut T) -> PinMut<'a, T> {
+        PinMut { inner: reference }
+    }
+
+    /// Get a mutable reference to the data inside of this `PinMut`.
+    #[unstable(feature = "pin", issue = "49150")]
+    pub fn get_mut(this: PinMut<'a, T>) -> &'a mut T {
+        this.inner
+    }
+}
+
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<'a, T: ?Sized> PinMut<'a, T> {
+    /// Construct a new `PinMut` around a reference to some data of a type that
+    /// may or may not implement `Unpin`.
+    ///
+    /// This constructor is unsafe because we do not know what will happen with
+    /// that data after the lifetime of the reference ends. If you cannot guarantee that the
+    /// data will never move again, calling this constructor is invalid.
+    #[unstable(feature = "pin", issue = "49150")]
+    pub unsafe fn new_unchecked(reference: &'a mut T) -> PinMut<'a, T> {
+        PinMut { inner: reference }
+    }
+
+    /// Reborrow a `PinMut` for a shorter lifetime.
+    ///
+    /// For example, `PinMut::get_mut(x.reborrow())` (unsafely) returns a
+    /// short-lived mutable reference reborrowing from `x`.
+    #[unstable(feature = "pin", issue = "49150")]
+    pub fn reborrow<'b>(&'b mut self) -> PinMut<'b, T> {
+        PinMut { inner: self.inner }
+    }
+
+    /// Get a mutable reference to the data inside of this `PinMut`.
+    ///
+    /// This function is unsafe. You must guarantee that you will never move
+    /// the data out of the mutable reference you receive when you call this
+    /// function.
+    #[unstable(feature = "pin", issue = "49150")]
+    pub unsafe fn get_mut_unchecked(this: PinMut<'a, T>) -> &'a mut T {
+        this.inner
+    }
+
+    /// Construct a new pin by mapping the interior value.
+    ///
+    /// For example, if you  wanted to get a `PinMut` of a field of something,
+    /// you could use this to get access to that field in one line of code.
+    ///
+    /// This function is unsafe. You must guarantee that the data you return
+    /// will not move so long as the argument value does not move (for example,
+    /// because it is one of the fields of that value), and also that you do
+    /// not move out of the argument you receive to the interior function.
+    #[unstable(feature = "pin", issue = "49150")]
+    pub unsafe fn map_unchecked<U, F>(this: PinMut<'a, T>, f: F) -> PinMut<'a, U> where
+        F: FnOnce(&mut T) -> &mut U
+    {
+        PinMut { inner: f(this.inner) }
+    }
+
+    /// Assign a new value to the memory behind the pinned reference.
+    #[unstable(feature = "pin", issue = "49150")]
+    pub fn set(this: PinMut<'a, T>, value: T)
+        where T: Sized,
+    {
+        *this.inner = value;
+    }
+}
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<'a, T: ?Sized> Deref for PinMut<'a, T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        &*self.inner
+    }
+}
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<'a, T: ?Sized + Unpin> DerefMut for PinMut<'a, T> {
+    fn deref_mut(&mut self) -> &mut T {
+        self.inner
+    }
+}
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<'a, T: fmt::Debug + ?Sized> fmt::Debug for PinMut<'a, T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&**self, f)
+    }
+}
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<'a, T: fmt::Display + ?Sized> fmt::Display for PinMut<'a, T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&**self, f)
+    }
+}
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<'a, T: ?Sized> fmt::Pointer for PinMut<'a, T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Pointer::fmt(&(&*self.inner as *const T), f)
+    }
+}
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<PinMut<'a, U>> for PinMut<'a, T> {}
+
+#[unstable(feature = "pin", issue = "49150")]
+impl<'a, T: ?Sized> Unpin for PinMut<'a, T> {}
+
+#[unstable(feature = "futures_api", issue = "50547")]
+unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for PinMut<'a, F>
+    where F: Future<Output = T> + 'a
+{
+    fn into_raw(self) -> *mut () {
+        unsafe { PinMut::get_mut_unchecked(self) as *mut F as *mut () }
+    }
+
+    unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T> {
+        PinMut::new_unchecked(&mut *(ptr as *mut F)).poll(cx)
+    }
+
+    unsafe fn drop(_ptr: *mut ()) {}
+}
diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs
index 1bac6d22d37..3720100700c 100644
--- a/src/libfmt_macros/lib.rs
+++ b/src/libfmt_macros/lib.rs
@@ -21,6 +21,7 @@
        test(attr(deny(warnings))))]
 
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 
 pub use self::Piece::*;
 pub use self::Position::*;
diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs
index 9fa48adebdf..5a0c983b521 100644
--- a/src/libgraphviz/lib.rs
+++ b/src/libgraphviz/lib.rs
@@ -289,6 +289,7 @@
        test(attr(allow(unused_variables), deny(warnings))))]
 
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(str_escape)]
 
 use self::LabelText::*;
diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs
index da568fae70e..4da88d85221 100644
--- a/src/libpanic_abort/lib.rs
+++ b/src/libpanic_abort/lib.rs
@@ -25,13 +25,14 @@
 #![feature(core_intrinsics)]
 #![feature(libc)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(panic_runtime)]
 #![feature(staged_api)]
 #![feature(rustc_attrs)]
 
 // Rust's "try" function, but if we're aborting on panics we just call the
 // function as there's nothing else we need to do here.
-#[no_mangle]
+#[cfg_attr(stage0, no_mangle)]
 #[rustc_std_internal_symbol]
 pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8),
                                               data: *mut u8,
@@ -51,7 +52,7 @@ pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8),
 // which would break compat with XP. For now just use `intrinsics::abort` which
 // will kill us with an illegal instruction, which will do a good enough job for
 // now hopefully.
-#[no_mangle]
+#[cfg_attr(stage0, no_mangle)]
 #[rustc_std_internal_symbol]
 pub unsafe extern fn __rust_start_panic(_payload: usize) -> u32 {
     abort();
diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs
index 9c3fc76c307..3368790b3f7 100644
--- a/src/libpanic_unwind/lib.rs
+++ b/src/libpanic_unwind/lib.rs
@@ -35,6 +35,7 @@
 #![feature(lang_items)]
 #![feature(libc)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(panic_unwind)]
 #![feature(raw)]
 #![feature(staged_api)]
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index 656819880b1..8c667d2f871 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -32,6 +32,7 @@
        test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))]
 
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(rustc_private)]
 #![feature(staged_api)]
 #![feature(lang_items)]
diff --git a/src/libprofiler_builtins/lib.rs b/src/libprofiler_builtins/lib.rs
index a85593253b1..00dd87022c2 100644
--- a/src/libprofiler_builtins/lib.rs
+++ b/src/libprofiler_builtins/lib.rs
@@ -16,4 +16,5 @@
             issue = "0")]
 #![allow(unused_features)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(staged_api)]
diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs
index f2f7f95426a..eeb41682601 100644
--- a/src/librustc/hir/map/blocks.rs
+++ b/src/librustc/hir/map/blocks.rs
@@ -22,8 +22,8 @@
 //! for the `Code` associated with a particular NodeId.
 
 use hir as ast;
-use hir::map::{self, Node};
-use hir::{Expr, FnDecl};
+use hir::map;
+use hir::{Expr, FnDecl, Node};
 use hir::intravisit::FnKind;
 use syntax::ast::{Attribute, Ident, Name, NodeId};
 use syntax_pos::Span;
@@ -39,7 +39,7 @@ use syntax_pos::Span;
 ///
 /// To construct one, use the `Code::from_node` function.
 #[derive(Copy, Clone, Debug)]
-pub struct FnLikeNode<'a> { node: map::Node<'a> }
+pub struct FnLikeNode<'a> { node: Node<'a> }
 
 /// MaybeFnLike wraps a method that indicates if an object
 /// corresponds to some FnLikeNode.
@@ -95,11 +95,11 @@ impl<'a> Code<'a> {
     /// Attempts to construct a Code from presumed FnLike or Expr node input.
     pub fn from_node(map: &map::Map<'a>, id: NodeId) -> Option<Code<'a>> {
         match map.get(id) {
-            map::NodeBlock(_) => {
+            map::Node::Block(_) => {
                 //  Use the parent, hopefully an expression node.
                 Code::from_node(map, map.get_parent_node(id))
             }
-            map::NodeExpr(expr) => Some(Code::Expr(expr)),
+            map::Node::Expr(expr) => Some(Code::Expr(expr)),
             node => FnLikeNode::from_node(node).map(Code::FnLike)
         }
     }
@@ -145,10 +145,10 @@ impl<'a> FnLikeNode<'a> {
     /// Attempts to construct a FnLikeNode from presumed FnLike node input.
     pub fn from_node(node: Node) -> Option<FnLikeNode> {
         let fn_like = match node {
-            map::NodeItem(item) => item.is_fn_like(),
-            map::NodeTraitItem(tm) => tm.is_fn_like(),
-            map::NodeImplItem(it) => it.is_fn_like(),
-            map::NodeExpr(e) => e.is_fn_like(),
+            map::Node::Item(item) => item.is_fn_like(),
+            map::Node::TraitItem(tm) => tm.is_fn_like(),
+            map::Node::ImplItem(it) => it.is_fn_like(),
+            map::Node::Expr(e) => e.is_fn_like(),
             _ => false
         };
         if fn_like {
@@ -234,7 +234,7 @@ impl<'a> FnLikeNode<'a> {
         C: FnOnce(ClosureParts<'a>) -> A,
     {
         match self.node {
-            map::NodeItem(i) => match i.node {
+            map::Node::Item(i) => match i.node {
                 ast::ItemKind::Fn(ref decl, header, ref generics, block) =>
                     item_fn(ItemFnParts {
                         id: i.id,
@@ -249,13 +249,13 @@ impl<'a> FnLikeNode<'a> {
                     }),
                 _ => bug!("item FnLikeNode that is not fn-like"),
             },
-            map::NodeTraitItem(ti) => match ti.node {
+            map::Node::TraitItem(ti) => match ti.node {
                 ast::TraitItemKind::Method(ref sig, ast::TraitMethod::Provided(body)) => {
                     method(ti.id, ti.ident, sig, None, body, ti.span, &ti.attrs)
                 }
                 _ => bug!("trait method FnLikeNode that is not fn-like"),
             },
-            map::NodeImplItem(ii) => {
+            map::Node::ImplItem(ii) => {
                 match ii.node {
                     ast::ImplItemKind::Method(ref sig, body) => {
                         method(ii.id, ii.ident, sig, Some(&ii.vis), body, ii.span, &ii.attrs)
@@ -265,7 +265,7 @@ impl<'a> FnLikeNode<'a> {
                     }
                 }
             },
-            map::NodeExpr(e) => match e.node {
+            map::Node::Expr(e) => match e.node {
                 ast::ExprKind::Closure(_, ref decl, block, _fn_decl_span, _gen) =>
                     closure(ClosureParts::new(&decl, block, e.id, e.span, &e.attrs)),
                 _ => bug!("expr FnLikeNode that is not fn-like"),
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index a14745a1381..30441c331e4 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -29,7 +29,7 @@ pub(super) struct NodeCollector<'a, 'hir> {
     /// The crate
     krate: &'hir Crate,
     /// The node map
-    map: Vec<MapEntry<'hir>>,
+    map: Vec<Option<Entry<'hir>>>,
     /// The parent of this node
     parent_node: NodeId,
 
@@ -114,7 +114,11 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
             hcx,
             hir_body_nodes,
         };
-        collector.insert_entry(CRATE_NODE_ID, RootCrate(root_mod_sig_dep_index));
+        collector.insert_entry(CRATE_NODE_ID, Entry {
+            parent: CRATE_NODE_ID,
+            dep_node: root_mod_sig_dep_index,
+            node: Node::Crate,
+        });
 
         collector
     }
@@ -124,9 +128,8 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
                                                   cstore: &dyn CrateStore,
                                                   source_map: &SourceMap,
                                                   commandline_args_hash: u64)
-                                                  -> (Vec<MapEntry<'hir>>, Svh) {
-        self
-            .hir_body_nodes
+                                                  -> (Vec<Option<Entry<'hir>>>, Svh) {
+        self.hir_body_nodes
             .sort_unstable_by(|&(ref d1, _), &(ref d2, _)| d1.cmp(d2));
 
         let node_hashes = self
@@ -178,44 +181,24 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
         (self.map, svh)
     }
 
-    fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'hir>) {
+    fn insert_entry(&mut self, id: NodeId, entry: Entry<'hir>) {
         debug!("hir_map: {:?} => {:?}", id, entry);
         let len = self.map.len();
         if id.as_usize() >= len {
-            self.map.extend(repeat(NotPresent).take(id.as_usize() - len + 1));
+            self.map.extend(repeat(None).take(id.as_usize() - len + 1));
         }
-        self.map[id.as_usize()] = entry;
+        self.map[id.as_usize()] = Some(entry);
     }
 
     fn insert(&mut self, id: NodeId, node: Node<'hir>) {
-        let parent = self.parent_node;
-        let dep_node_index = if self.currently_in_body {
-            self.current_full_dep_index
-        } else {
-            self.current_signature_dep_index
-        };
-
-        let entry = match node {
-            NodeItem(n) => EntryItem(parent, dep_node_index, n),
-            NodeForeignItem(n) => EntryForeignItem(parent, dep_node_index, n),
-            NodeTraitItem(n) => EntryTraitItem(parent, dep_node_index, n),
-            NodeImplItem(n) => EntryImplItem(parent, dep_node_index, n),
-            NodeVariant(n) => EntryVariant(parent, dep_node_index, n),
-            NodeField(n) => EntryField(parent, dep_node_index, n),
-            NodeAnonConst(n) => EntryAnonConst(parent, dep_node_index, n),
-            NodeExpr(n) => EntryExpr(parent, dep_node_index, n),
-            NodeStmt(n) => EntryStmt(parent, dep_node_index, n),
-            NodeTy(n) => EntryTy(parent, dep_node_index, n),
-            NodeTraitRef(n) => EntryTraitRef(parent, dep_node_index, n),
-            NodeBinding(n) => EntryBinding(parent, dep_node_index, n),
-            NodePat(n) => EntryPat(parent, dep_node_index, n),
-            NodeBlock(n) => EntryBlock(parent, dep_node_index, n),
-            NodeStructCtor(n) => EntryStructCtor(parent, dep_node_index, n),
-            NodeLifetime(n) => EntryLifetime(parent, dep_node_index, n),
-            NodeGenericParam(n) => EntryGenericParam(parent, dep_node_index, n),
-            NodeVisibility(n) => EntryVisibility(parent, dep_node_index, n),
-            NodeLocal(n) => EntryLocal(parent, dep_node_index, n),
-            NodeMacroDef(n) => EntryMacroDef(dep_node_index, n),
+        let entry = Entry {
+            parent: self.parent_node,
+            dep_node: if self.currently_in_body {
+                self.current_full_dep_index
+            } else {
+                self.current_signature_dep_index
+            },
+            node,
         };
 
         // Make sure that the DepNode of some node coincides with the HirId
@@ -326,13 +309,13 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
         debug_assert_eq!(i.hir_id.owner,
                          self.definitions.opt_def_index(i.id).unwrap());
         self.with_dep_node_owner(i.hir_id.owner, i, |this| {
-            this.insert(i.id, NodeItem(i));
+            this.insert(i.id, Node::Item(i));
             this.with_parent(i.id, |this| {
                 match i.node {
                     ItemKind::Struct(ref struct_def, _) => {
                         // If this is a tuple-like struct, register the constructor.
                         if !struct_def.is_struct() {
-                            this.insert(struct_def.id(), NodeStructCtor(struct_def));
+                            this.insert(struct_def.id(), Node::StructCtor(struct_def));
                         }
                     }
                     _ => {}
@@ -343,7 +326,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     }
 
     fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem) {
-        self.insert(foreign_item.id, NodeForeignItem(foreign_item));
+        self.insert(foreign_item.id, Node::ForeignItem(foreign_item));
 
         self.with_parent(foreign_item.id, |this| {
             intravisit::walk_foreign_item(this, foreign_item);
@@ -351,7 +334,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     }
 
     fn visit_generic_param(&mut self, param: &'hir GenericParam) {
-        self.insert(param.id, NodeGenericParam(param));
+        self.insert(param.id, Node::GenericParam(param));
         intravisit::walk_generic_param(self, param);
     }
 
@@ -359,7 +342,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
         debug_assert_eq!(ti.hir_id.owner,
                          self.definitions.opt_def_index(ti.id).unwrap());
         self.with_dep_node_owner(ti.hir_id.owner, ti, |this| {
-            this.insert(ti.id, NodeTraitItem(ti));
+            this.insert(ti.id, Node::TraitItem(ti));
 
             this.with_parent(ti.id, |this| {
                 intravisit::walk_trait_item(this, ti);
@@ -371,7 +354,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
         debug_assert_eq!(ii.hir_id.owner,
                          self.definitions.opt_def_index(ii.id).unwrap());
         self.with_dep_node_owner(ii.hir_id.owner, ii, |this| {
-            this.insert(ii.id, NodeImplItem(ii));
+            this.insert(ii.id, Node::ImplItem(ii));
 
             this.with_parent(ii.id, |this| {
                 intravisit::walk_impl_item(this, ii);
@@ -381,9 +364,9 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
 
     fn visit_pat(&mut self, pat: &'hir Pat) {
         let node = if let PatKind::Binding(..) = pat.node {
-            NodeBinding(pat)
+            Node::Binding(pat)
         } else {
-            NodePat(pat)
+            Node::Pat(pat)
         };
         self.insert(pat.id, node);
 
@@ -393,7 +376,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     }
 
     fn visit_anon_const(&mut self, constant: &'hir AnonConst) {
-        self.insert(constant.id, NodeAnonConst(constant));
+        self.insert(constant.id, Node::AnonConst(constant));
 
         self.with_parent(constant.id, |this| {
             intravisit::walk_anon_const(this, constant);
@@ -401,7 +384,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     }
 
     fn visit_expr(&mut self, expr: &'hir Expr) {
-        self.insert(expr.id, NodeExpr(expr));
+        self.insert(expr.id, Node::Expr(expr));
 
         self.with_parent(expr.id, |this| {
             intravisit::walk_expr(this, expr);
@@ -410,7 +393,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
 
     fn visit_stmt(&mut self, stmt: &'hir Stmt) {
         let id = stmt.node.id();
-        self.insert(id, NodeStmt(stmt));
+        self.insert(id, Node::Stmt(stmt));
 
         self.with_parent(id, |this| {
             intravisit::walk_stmt(this, stmt);
@@ -418,7 +401,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     }
 
     fn visit_ty(&mut self, ty: &'hir Ty) {
-        self.insert(ty.id, NodeTy(ty));
+        self.insert(ty.id, Node::Ty(ty));
 
         self.with_parent(ty.id, |this| {
             intravisit::walk_ty(this, ty);
@@ -426,7 +409,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     }
 
     fn visit_trait_ref(&mut self, tr: &'hir TraitRef) {
-        self.insert(tr.ref_id, NodeTraitRef(tr));
+        self.insert(tr.ref_id, Node::TraitRef(tr));
 
         self.with_parent(tr.ref_id, |this| {
             intravisit::walk_trait_ref(this, tr);
@@ -440,21 +423,21 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     }
 
     fn visit_block(&mut self, block: &'hir Block) {
-        self.insert(block.id, NodeBlock(block));
+        self.insert(block.id, Node::Block(block));
         self.with_parent(block.id, |this| {
             intravisit::walk_block(this, block);
         });
     }
 
     fn visit_local(&mut self, l: &'hir Local) {
-        self.insert(l.id, NodeLocal(l));
+        self.insert(l.id, Node::Local(l));
         self.with_parent(l.id, |this| {
             intravisit::walk_local(this, l)
         })
     }
 
     fn visit_lifetime(&mut self, lifetime: &'hir Lifetime) {
-        self.insert(lifetime.id, NodeLifetime(lifetime));
+        self.insert(lifetime.id, Node::Lifetime(lifetime));
     }
 
     fn visit_vis(&mut self, visibility: &'hir Visibility) {
@@ -463,7 +446,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
             VisibilityKind::Crate(_) |
             VisibilityKind::Inherited => {}
             VisibilityKind::Restricted { id, .. } => {
-                self.insert(id, NodeVisibility(visibility));
+                self.insert(id, Node::Visibility(visibility));
                 self.with_parent(id, |this| {
                     intravisit::walk_vis(this, visibility);
                 });
@@ -475,20 +458,20 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
         let def_index = self.definitions.opt_def_index(macro_def.id).unwrap();
 
         self.with_dep_node_owner(def_index, macro_def, |this| {
-            this.insert(macro_def.id, NodeMacroDef(macro_def));
+            this.insert(macro_def.id, Node::MacroDef(macro_def));
         });
     }
 
     fn visit_variant(&mut self, v: &'hir Variant, g: &'hir Generics, item_id: NodeId) {
         let id = v.node.data.id();
-        self.insert(id, NodeVariant(v));
+        self.insert(id, Node::Variant(v));
         self.with_parent(id, |this| {
             intravisit::walk_variant(this, v, g, item_id);
         });
     }
 
     fn visit_struct_field(&mut self, field: &'hir StructField) {
-        self.insert(field.id, NodeField(field));
+        self.insert(field.id, Node::Field(field));
         self.with_parent(field.id, |this| {
             intravisit::walk_struct_field(this, field);
         });
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index c3112da4f8c..6fffde7cab5 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub use self::Node::*;
-use self::MapEntry::*;
 use self::collector::NodeCollector;
 pub use self::def_collector::{DefCollector, MacroInvocationData};
 pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
@@ -42,172 +40,62 @@ mod def_collector;
 pub mod definitions;
 mod hir_id_validator;
 
-
 pub const ITEM_LIKE_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::Low;
 pub const REGULAR_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::High;
 
+/// Represents an entry and its parent NodeId.
 #[derive(Copy, Clone, Debug)]
-pub enum Node<'hir> {
-    NodeItem(&'hir Item),
-    NodeForeignItem(&'hir ForeignItem),
-    NodeTraitItem(&'hir TraitItem),
-    NodeImplItem(&'hir ImplItem),
-    NodeVariant(&'hir Variant),
-    NodeField(&'hir StructField),
-    NodeAnonConst(&'hir AnonConst),
-    NodeExpr(&'hir Expr),
-    NodeStmt(&'hir Stmt),
-    NodeTy(&'hir Ty),
-    NodeTraitRef(&'hir TraitRef),
-    NodeBinding(&'hir Pat),
-    NodePat(&'hir Pat),
-    NodeBlock(&'hir Block),
-    NodeLocal(&'hir Local),
-    NodeMacroDef(&'hir MacroDef),
-
-    /// NodeStructCtor represents a tuple struct.
-    NodeStructCtor(&'hir VariantData),
-
-    NodeLifetime(&'hir Lifetime),
-    NodeGenericParam(&'hir GenericParam),
-    NodeVisibility(&'hir Visibility),
-}
-
-/// Represents an entry and its parent NodeID.
-/// The odd layout is to bring down the total size.
-#[derive(Copy, Debug)]
-enum MapEntry<'hir> {
-    /// Placeholder for holes in the map.
-    NotPresent,
-
-    /// All the node types, with a parent ID.
-    EntryItem(NodeId, DepNodeIndex, &'hir Item),
-    EntryForeignItem(NodeId, DepNodeIndex, &'hir ForeignItem),
-    EntryTraitItem(NodeId, DepNodeIndex, &'hir TraitItem),
-    EntryImplItem(NodeId, DepNodeIndex, &'hir ImplItem),
-    EntryVariant(NodeId, DepNodeIndex, &'hir Variant),
-    EntryField(NodeId, DepNodeIndex, &'hir StructField),
-    EntryAnonConst(NodeId, DepNodeIndex, &'hir AnonConst),
-    EntryExpr(NodeId, DepNodeIndex, &'hir Expr),
-    EntryStmt(NodeId, DepNodeIndex, &'hir Stmt),
-    EntryTy(NodeId, DepNodeIndex, &'hir Ty),
-    EntryTraitRef(NodeId, DepNodeIndex, &'hir TraitRef),
-    EntryBinding(NodeId, DepNodeIndex, &'hir Pat),
-    EntryPat(NodeId, DepNodeIndex, &'hir Pat),
-    EntryBlock(NodeId, DepNodeIndex, &'hir Block),
-    EntryStructCtor(NodeId, DepNodeIndex, &'hir VariantData),
-    EntryLifetime(NodeId, DepNodeIndex, &'hir Lifetime),
-    EntryGenericParam(NodeId, DepNodeIndex, &'hir GenericParam),
-    EntryVisibility(NodeId, DepNodeIndex, &'hir Visibility),
-    EntryLocal(NodeId, DepNodeIndex, &'hir Local),
-
-    EntryMacroDef(DepNodeIndex, &'hir MacroDef),
-
-    /// Roots for node trees. The DepNodeIndex is the dependency node of the
-    /// crate's root module.
-    RootCrate(DepNodeIndex),
-}
-
-impl<'hir> Clone for MapEntry<'hir> {
-    fn clone(&self) -> MapEntry<'hir> {
-        *self
-    }
+pub struct Entry<'hir> {
+    parent: NodeId,
+    dep_node: DepNodeIndex,
+    node: Node<'hir>,
 }
 
-impl<'hir> MapEntry<'hir> {
+impl<'hir> Entry<'hir> {
     fn parent_node(self) -> Option<NodeId> {
-        Some(match self {
-            EntryItem(id, _, _) => id,
-            EntryForeignItem(id, _, _) => id,
-            EntryTraitItem(id, _, _) => id,
-            EntryImplItem(id, _, _) => id,
-            EntryVariant(id, _, _) => id,
-            EntryField(id, _, _) => id,
-            EntryAnonConst(id, _, _) => id,
-            EntryExpr(id, _, _) => id,
-            EntryStmt(id, _, _) => id,
-            EntryTy(id, _, _) => id,
-            EntryTraitRef(id, _, _) => id,
-            EntryBinding(id, _, _) => id,
-            EntryPat(id, _, _) => id,
-            EntryBlock(id, _, _) => id,
-            EntryStructCtor(id, _, _) => id,
-            EntryLifetime(id, _, _) => id,
-            EntryGenericParam(id, _, _) => id,
-            EntryVisibility(id, _, _) => id,
-            EntryLocal(id, _, _) => id,
-
-            NotPresent |
-            EntryMacroDef(..) |
-            RootCrate(_) => return None,
-        })
-    }
-
-    fn to_node(self) -> Option<Node<'hir>> {
-        Some(match self {
-            EntryItem(_, _, n) => NodeItem(n),
-            EntryForeignItem(_, _, n) => NodeForeignItem(n),
-            EntryTraitItem(_, _, n) => NodeTraitItem(n),
-            EntryImplItem(_, _, n) => NodeImplItem(n),
-            EntryVariant(_, _, n) => NodeVariant(n),
-            EntryField(_, _, n) => NodeField(n),
-            EntryAnonConst(_, _, n) => NodeAnonConst(n),
-            EntryExpr(_, _, n) => NodeExpr(n),
-            EntryStmt(_, _, n) => NodeStmt(n),
-            EntryTy(_, _, n) => NodeTy(n),
-            EntryTraitRef(_, _, n) => NodeTraitRef(n),
-            EntryBinding(_, _, n) => NodeBinding(n),
-            EntryPat(_, _, n) => NodePat(n),
-            EntryBlock(_, _, n) => NodeBlock(n),
-            EntryStructCtor(_, _, n) => NodeStructCtor(n),
-            EntryLifetime(_, _, n) => NodeLifetime(n),
-            EntryGenericParam(_, _, n) => NodeGenericParam(n),
-            EntryVisibility(_, _, n) => NodeVisibility(n),
-            EntryLocal(_, _, n) => NodeLocal(n),
-            EntryMacroDef(_, n) => NodeMacroDef(n),
-
-            NotPresent |
-            RootCrate(_) => return None
-        })
+        match self.node {
+            Node::Crate | Node::MacroDef(_) => None,
+            _ => Some(self.parent),
+        }
     }
 
     fn fn_decl(&self) -> Option<&FnDecl> {
-        match self {
-            EntryItem(_, _, ref item) => {
+        match self.node {
+            Node::Item(ref item) => {
                 match item.node {
                     ItemKind::Fn(ref fn_decl, _, _, _) => Some(&fn_decl),
                     _ => None,
                 }
             }
 
-            EntryTraitItem(_, _, ref item) => {
+            Node::TraitItem(ref item) => {
                 match item.node {
                     TraitItemKind::Method(ref method_sig, _) => Some(&method_sig.decl),
                     _ => None
                 }
             }
 
-            EntryImplItem(_, _, ref item) => {
+            Node::ImplItem(ref item) => {
                 match item.node {
                     ImplItemKind::Method(ref method_sig, _) => Some(&method_sig.decl),
                     _ => None,
                 }
             }
 
-            EntryExpr(_, _, ref expr) => {
+            Node::Expr(ref expr) => {
                 match expr.node {
                     ExprKind::Closure(_, ref fn_decl, ..) => Some(&fn_decl),
                     _ => None,
                 }
             }
 
-            _ => None
+            _ => None,
         }
     }
 
     fn associated_body(self) -> Option<BodyId> {
-        match self {
-            EntryItem(_, _, item) => {
+        match self.node {
+            Node::Item(item) => {
                 match item.node {
                     ItemKind::Const(_, body) |
                     ItemKind::Static(.., body) |
@@ -216,7 +104,7 @@ impl<'hir> MapEntry<'hir> {
                 }
             }
 
-            EntryTraitItem(_, _, item) => {
+            Node::TraitItem(item) => {
                 match item.node {
                     TraitItemKind::Const(_, Some(body)) |
                     TraitItemKind::Method(_, TraitMethod::Provided(body)) => Some(body),
@@ -224,7 +112,7 @@ impl<'hir> MapEntry<'hir> {
                 }
             }
 
-            EntryImplItem(_, _, item) => {
+            Node::ImplItem(item) => {
                 match item.node {
                     ImplItemKind::Const(_, body) |
                     ImplItemKind::Method(_, body) => Some(body),
@@ -232,9 +120,9 @@ impl<'hir> MapEntry<'hir> {
                 }
             }
 
-            EntryAnonConst(_, _, constant) => Some(constant.body),
+            Node::AnonConst(constant) => Some(constant.body),
 
-            EntryExpr(_, _, expr) => {
+            Node::Expr(expr) => {
                 match expr.node {
                     ExprKind::Closure(.., body, _, _) => Some(body),
                     _ => None,
@@ -287,16 +175,16 @@ pub struct Map<'hir> {
     /// The SVH of the local crate.
     pub crate_hash: Svh,
 
-    /// NodeIds are sequential integers from 0, so we can be
+    /// `NodeId`s are sequential integers from 0, so we can be
     /// super-compact by storing them in a vector. Not everything with
-    /// a NodeId is in the map, but empirically the occupancy is about
+    /// a `NodeId` is in the map, but empirically the occupancy is about
     /// 75-80%, so there's not too much overhead (certainly less than
     /// a hashmap, since they (at the time of writing) have a maximum
     /// of 75% occupancy).
     ///
     /// Also, indexing is pretty quick when you've got a vector and
     /// plain old integers.
-    map: Vec<MapEntry<'hir>>,
+    map: Vec<Option<Entry<'hir>>>,
 
     definitions: &'hir Definitions,
 
@@ -313,34 +201,10 @@ impl<'hir> Map<'hir> {
     /// read recorded). If the function just returns a DefId or
     /// NodeId, no actual content was returned, so no read is needed.
     pub fn read(&self, id: NodeId) {
-        let entry = self.map[id.as_usize()];
-        match entry {
-            EntryItem(_, dep_node_index, _) |
-            EntryTraitItem(_, dep_node_index, _) |
-            EntryImplItem(_, dep_node_index, _) |
-            EntryVariant(_, dep_node_index, _) |
-            EntryForeignItem(_, dep_node_index, _) |
-            EntryField(_, dep_node_index, _) |
-            EntryStmt(_, dep_node_index, _) |
-            EntryTy(_, dep_node_index, _) |
-            EntryTraitRef(_, dep_node_index, _) |
-            EntryBinding(_, dep_node_index, _) |
-            EntryPat(_, dep_node_index, _) |
-            EntryBlock(_, dep_node_index, _) |
-            EntryStructCtor(_, dep_node_index, _) |
-            EntryLifetime(_, dep_node_index, _) |
-            EntryGenericParam(_, dep_node_index, _) |
-            EntryVisibility(_, dep_node_index, _) |
-            EntryAnonConst(_, dep_node_index, _) |
-            EntryExpr(_, dep_node_index, _) |
-            EntryLocal(_, dep_node_index, _) |
-            EntryMacroDef(dep_node_index, _) |
-            RootCrate(dep_node_index) => {
-                self.dep_graph.read_index(dep_node_index);
-            }
-            NotPresent => {
-                bug!("called HirMap::read() with invalid NodeId")
-            }
+        if let Some(entry) = self.map[id.as_usize()] {
+            self.dep_graph.read_index(entry.dep_node);
+        } else {
+            bug!("called `HirMap::read()` with invalid `NodeId`")
         }
     }
 
@@ -421,7 +285,7 @@ impl<'hir> Map<'hir> {
         };
 
         match node {
-            NodeItem(item) => {
+            Node::Item(item) => {
                 let def_id = || {
                     self.local_def_id(item.id)
                 };
@@ -448,7 +312,7 @@ impl<'hir> Map<'hir> {
                     ItemKind::Impl(..) => None,
                 }
             }
-            NodeForeignItem(item) => {
+            Node::ForeignItem(item) => {
                 let def_id = self.local_def_id(item.id);
                 match item.node {
                     ForeignItemKind::Fn(..) => Some(Def::Fn(def_id)),
@@ -456,7 +320,7 @@ impl<'hir> Map<'hir> {
                     ForeignItemKind::Type => Some(Def::ForeignTy(def_id)),
                 }
             }
-            NodeTraitItem(item) => {
+            Node::TraitItem(item) => {
                 let def_id = self.local_def_id(item.id);
                 match item.node {
                     TraitItemKind::Const(..) => Some(Def::AssociatedConst(def_id)),
@@ -464,7 +328,7 @@ impl<'hir> Map<'hir> {
                     TraitItemKind::Type(..) => Some(Def::AssociatedTy(def_id)),
                 }
             }
-            NodeImplItem(item) => {
+            Node::ImplItem(item) => {
                 let def_id = self.local_def_id(item.id);
                 match item.node {
                     ImplItemKind::Const(..) => Some(Def::AssociatedConst(def_id)),
@@ -473,30 +337,31 @@ impl<'hir> Map<'hir> {
                     ImplItemKind::Existential(..) => Some(Def::AssociatedExistential(def_id)),
                 }
             }
-            NodeVariant(variant) => {
+            Node::Variant(variant) => {
                 let def_id = self.local_def_id(variant.node.data.id());
                 Some(Def::Variant(def_id))
             }
-            NodeField(_) |
-            NodeAnonConst(_) |
-            NodeExpr(_) |
-            NodeStmt(_) |
-            NodeTy(_) |
-            NodeTraitRef(_) |
-            NodePat(_) |
-            NodeBinding(_) |
-            NodeStructCtor(_) |
-            NodeLifetime(_) |
-            NodeVisibility(_) |
-            NodeBlock(_) => None,
-            NodeLocal(local) => {
+            Node::Field(_) |
+            Node::AnonConst(_) |
+            Node::Expr(_) |
+            Node::Stmt(_) |
+            Node::Ty(_) |
+            Node::TraitRef(_) |
+            Node::Pat(_) |
+            Node::Binding(_) |
+            Node::StructCtor(_) |
+            Node::Lifetime(_) |
+            Node::Visibility(_) |
+            Node::Block(_) |
+            Node::Crate => None,
+            Node::Local(local) => {
                 Some(Def::Local(local.id))
             }
-            NodeMacroDef(macro_def) => {
+            Node::MacroDef(macro_def) => {
                 Some(Def::Macro(self.local_def_id(macro_def.id),
                                 MacroKind::Bang))
             }
-            NodeGenericParam(param) => {
+            Node::GenericParam(param) => {
                 Some(match param.kind {
                     GenericParamKind::Lifetime { .. } => Def::Local(param.id),
                     GenericParamKind::Type { .. } => Def::TyParam(self.local_def_id(param.id)),
@@ -509,8 +374,8 @@ impl<'hir> Map<'hir> {
         self.map.len()
     }
 
-    fn find_entry(&self, id: NodeId) -> Option<MapEntry<'hir>> {
-        self.map.get(id.as_usize()).cloned()
+    fn find_entry(&self, id: NodeId) -> Option<Entry<'hir>> {
+        self.map.get(id.as_usize()).cloned().unwrap_or(None)
     }
 
     pub fn krate(&self) -> &'hir Crate {
@@ -554,7 +419,7 @@ impl<'hir> Map<'hir> {
     /// item (possibly associated), a closure, or a `hir::AnonConst`.
     pub fn body_owner(&self, BodyId { node_id }: BodyId) -> NodeId {
         let parent = self.get_parent_node(node_id);
-        assert!(self.map[parent.as_usize()].is_body_owner(node_id));
+        assert!(self.map[parent.as_usize()].map_or(false, |e| e.is_body_owner(node_id)));
         parent
     }
 
@@ -588,13 +453,13 @@ impl<'hir> Map<'hir> {
 
     pub fn body_owner_kind(&self, id: NodeId) -> BodyOwnerKind {
         match self.get(id) {
-            NodeItem(&Item { node: ItemKind::Const(..), .. }) |
-            NodeTraitItem(&TraitItem { node: TraitItemKind::Const(..), .. }) |
-            NodeImplItem(&ImplItem { node: ImplItemKind::Const(..), .. }) |
-            NodeAnonConst(_) => {
+            Node::Item(&Item { node: ItemKind::Const(..), .. }) |
+            Node::TraitItem(&TraitItem { node: TraitItemKind::Const(..), .. }) |
+            Node::ImplItem(&ImplItem { node: ImplItemKind::Const(..), .. }) |
+            Node::AnonConst(_) => {
                 BodyOwnerKind::Const
             }
-            NodeItem(&Item { node: ItemKind::Static(_, m, _), .. }) => {
+            Node::Item(&Item { node: ItemKind::Static(_, m, _), .. }) => {
                 BodyOwnerKind::Static(m)
             }
             // Default to function if it's not a constant or static.
@@ -604,8 +469,8 @@ impl<'hir> Map<'hir> {
 
     pub fn ty_param_owner(&self, id: NodeId) -> NodeId {
         match self.get(id) {
-            NodeItem(&Item { node: ItemKind::Trait(..), .. }) => id,
-            NodeGenericParam(_) => self.get_parent_node(id),
+            Node::Item(&Item { node: ItemKind::Trait(..), .. }) => id,
+            Node::GenericParam(_) => self.get_parent_node(id),
             _ => {
                 bug!("ty_param_owner: {} not a type parameter",
                     self.node_to_string(id))
@@ -615,10 +480,10 @@ impl<'hir> Map<'hir> {
 
     pub fn ty_param_name(&self, id: NodeId) -> Name {
         match self.get(id) {
-            NodeItem(&Item { node: ItemKind::Trait(..), .. }) => {
+            Node::Item(&Item { node: ItemKind::Trait(..), .. }) => {
                 keywords::SelfType.name()
             }
-            NodeGenericParam(param) => param.name.ident().name,
+            Node::GenericParam(param) => param.name.ident().name,
             _ => bug!("ty_param_name: {} not a type parameter", self.node_to_string(id)),
         }
     }
@@ -669,9 +534,9 @@ impl<'hir> Map<'hir> {
     pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics> {
         self.get_if_local(id).and_then(|node| {
             match node {
-                NodeImplItem(ref impl_item) => Some(&impl_item.generics),
-                NodeTraitItem(ref trait_item) => Some(&trait_item.generics),
-                NodeItem(ref item) => {
+                Node::ImplItem(ref impl_item) => Some(&impl_item.generics),
+                Node::TraitItem(ref trait_item) => Some(&trait_item.generics),
+                Node::Item(ref item) => {
                     match item.node {
                         ItemKind::Fn(_, _, ref generics, _) |
                         ItemKind::Ty(_, ref generics) |
@@ -696,7 +561,13 @@ impl<'hir> Map<'hir> {
     /// Retrieve the Node corresponding to `id`, returning None if
     /// cannot be found.
     pub fn find(&self, id: NodeId) -> Option<Node<'hir>> {
-        let result = self.find_entry(id).and_then(|x| x.to_node());
+        let result = self.find_entry(id).and_then(|entry| {
+            if let Node::Crate = entry.node {
+                None
+            } else {
+                Some(entry.node)
+            }
+        });
         if result.is_some() {
             self.read(id);
         }
@@ -727,14 +598,14 @@ impl<'hir> Map<'hir> {
     /// immediate parent is an item or a closure.
     pub fn is_argument(&self, id: NodeId) -> bool {
         match self.find(id) {
-            Some(NodeBinding(_)) => (),
+            Some(Node::Binding(_)) => (),
             _ => return false,
         }
         match self.find(self.get_parent_node(id)) {
-            Some(NodeItem(_)) |
-            Some(NodeTraitItem(_)) |
-            Some(NodeImplItem(_)) => true,
-            Some(NodeExpr(e)) => {
+            Some(Node::Item(_)) |
+            Some(Node::TraitItem(_)) |
+            Some(Node::ImplItem(_)) => true,
+            Some(Node::Expr(e)) => {
                 match e.node {
                     ExprKind::Closure(..) => true,
                     _ => false,
@@ -766,24 +637,19 @@ impl<'hir> Map<'hir> {
                 return Err(id);
             }
 
-            let node = self.find_entry(parent_node);
-            if node.is_none() {
-                return Err(id);
-            }
-            let node = node.unwrap().to_node();
-            match node {
-                Some(ref node) => {
-                    if found(node) {
-                        return Ok(parent_node);
-                    } else if bail_early(node) {
-                        return Err(parent_node);
-                    }
+            if let Some(entry) = self.find_entry(parent_node) {
+                if let Node::Crate = entry.node {
+                    return Err(id);
                 }
-                None => {
+                if found(&entry.node) {
+                    return Ok(parent_node);
+                } else if bail_early(&entry.node) {
                     return Err(parent_node);
                 }
+                id = parent_node;
+            } else {
+                return Err(id);
             }
-            id = parent_node;
         }
     }
 
@@ -812,16 +678,16 @@ impl<'hir> Map<'hir> {
     pub fn get_return_block(&self, id: NodeId) -> Option<NodeId> {
         let match_fn = |node: &Node| {
             match *node {
-                NodeItem(_) |
-                NodeForeignItem(_) |
-                NodeTraitItem(_) |
-                NodeImplItem(_) => true,
+                Node::Item(_) |
+                Node::ForeignItem(_) |
+                Node::TraitItem(_) |
+                Node::ImplItem(_) => true,
                 _ => false,
             }
         };
         let match_non_returning_block = |node: &Node| {
             match *node {
-                NodeExpr(ref expr) => {
+                Node::Expr(ref expr) => {
                     match expr.node {
                         ExprKind::While(..) | ExprKind::Loop(..) => true,
                         _ => false,
@@ -843,10 +709,10 @@ impl<'hir> Map<'hir> {
     /// in a module, trait, or impl.
     pub fn get_parent(&self, id: NodeId) -> NodeId {
         match self.walk_parent_nodes(id, |node| match *node {
-            NodeItem(_) |
-            NodeForeignItem(_) |
-            NodeTraitItem(_) |
-            NodeImplItem(_) => true,
+            Node::Item(_) |
+            Node::ForeignItem(_) |
+            Node::TraitItem(_) |
+            Node::ImplItem(_) => true,
             _ => false,
         }, |_| false) {
             Ok(id) => id,
@@ -858,7 +724,7 @@ impl<'hir> Map<'hir> {
     /// module parent is in this map.
     pub fn get_module_parent(&self, id: NodeId) -> DefId {
         let id = match self.walk_parent_nodes(id, |node| match *node {
-            NodeItem(&Item { node: ItemKind::Mod(_), .. }) => true,
+            Node::Item(&Item { node: ItemKind::Mod(_), .. }) => true,
             _ => false,
         }, |_| false) {
             Ok(id) => id,
@@ -873,11 +739,11 @@ impl<'hir> Map<'hir> {
     /// regard should be expected to be highly unstable.
     pub fn get_enclosing_scope(&self, id: NodeId) -> Option<NodeId> {
         match self.walk_parent_nodes(id, |node| match *node {
-            NodeItem(_) |
-            NodeForeignItem(_) |
-            NodeTraitItem(_) |
-            NodeImplItem(_) |
-            NodeBlock(_) => true,
+            Node::Item(_) |
+            Node::ForeignItem(_) |
+            Node::TraitItem(_) |
+            Node::ImplItem(_) |
+            Node::Block(_) => true,
             _ => false,
         }, |_| false) {
             Ok(id) => Some(id),
@@ -891,49 +757,43 @@ impl<'hir> Map<'hir> {
 
     pub fn get_foreign_abi(&self, id: NodeId) -> Abi {
         let parent = self.get_parent(id);
-        let abi = match self.find_entry(parent) {
-            Some(EntryItem(_, _, i)) => {
-                match i.node {
-                    ItemKind::ForeignMod(ref nm) => Some(nm.abi),
-                    _ => None
+        if let Some(entry) = self.find_entry(parent) {
+            match entry {
+                Entry { node: Node::Item(Item { node: ItemKind::ForeignMod(ref nm), .. }), .. }
+                    => {
+                    self.read(id); // reveals some of the content of a node
+                    return nm.abi;
                 }
+                _ => {}
             }
-            _ => None
-        };
-        match abi {
-            Some(abi) => {
-                self.read(id); // reveals some of the content of a node
-                abi
-            }
-            None => bug!("expected foreign mod or inlined parent, found {}",
-                          self.node_to_string(parent))
         }
+        bug!("expected foreign mod or inlined parent, found {}", self.node_to_string(parent))
     }
 
     pub fn expect_item(&self, id: NodeId) -> &'hir Item {
         match self.find(id) { // read recorded by `find`
-            Some(NodeItem(item)) => item,
+            Some(Node::Item(item)) => item,
             _ => bug!("expected item, found {}", self.node_to_string(id))
         }
     }
 
     pub fn expect_impl_item(&self, id: NodeId) -> &'hir ImplItem {
         match self.find(id) {
-            Some(NodeImplItem(item)) => item,
+            Some(Node::ImplItem(item)) => item,
             _ => bug!("expected impl item, found {}", self.node_to_string(id))
         }
     }
 
     pub fn expect_trait_item(&self, id: NodeId) -> &'hir TraitItem {
         match self.find(id) {
-            Some(NodeTraitItem(item)) => item,
+            Some(Node::TraitItem(item)) => item,
             _ => bug!("expected trait item, found {}", self.node_to_string(id))
         }
     }
 
     pub fn expect_variant_data(&self, id: NodeId) -> &'hir VariantData {
         match self.find(id) {
-            Some(NodeItem(i)) => {
+            Some(Node::Item(i)) => {
                 match i.node {
                     ItemKind::Struct(ref struct_def, _) |
                     ItemKind::Union(ref struct_def, _) => struct_def,
@@ -943,8 +803,8 @@ impl<'hir> Map<'hir> {
                     }
                 }
             }
-            Some(NodeStructCtor(data)) => data,
-            Some(NodeVariant(variant)) => &variant.node.data,
+            Some(Node::StructCtor(data)) => data,
+            Some(Node::Variant(variant)) => &variant.node.data,
             _ => {
                 bug!("expected struct or variant, found {}",
                      self.node_to_string(id));
@@ -954,21 +814,21 @@ impl<'hir> Map<'hir> {
 
     pub fn expect_variant(&self, id: NodeId) -> &'hir Variant {
         match self.find(id) {
-            Some(NodeVariant(variant)) => variant,
+            Some(Node::Variant(variant)) => variant,
             _ => bug!("expected variant, found {}", self.node_to_string(id)),
         }
     }
 
     pub fn expect_foreign_item(&self, id: NodeId) -> &'hir ForeignItem {
         match self.find(id) {
-            Some(NodeForeignItem(item)) => item,
+            Some(Node::ForeignItem(item)) => item,
             _ => bug!("expected foreign item, found {}", self.node_to_string(id))
         }
     }
 
     pub fn expect_expr(&self, id: NodeId) -> &'hir Expr {
         match self.find(id) { // read recorded by find
-            Some(NodeExpr(expr)) => expr,
+            Some(Node::Expr(expr)) => expr,
             _ => bug!("expected expr, found {}", self.node_to_string(id))
         }
     }
@@ -976,16 +836,16 @@ impl<'hir> Map<'hir> {
     /// Returns the name associated with the given NodeId's AST.
     pub fn name(&self, id: NodeId) -> Name {
         match self.get(id) {
-            NodeItem(i) => i.name,
-            NodeForeignItem(i) => i.name,
-            NodeImplItem(ii) => ii.ident.name,
-            NodeTraitItem(ti) => ti.ident.name,
-            NodeVariant(v) => v.node.name,
-            NodeField(f) => f.ident.name,
-            NodeLifetime(lt) => lt.name.ident().name,
-            NodeGenericParam(param) => param.name.ident().name,
-            NodeBinding(&Pat { node: PatKind::Binding(_,_,l,_), .. }) => l.name,
-            NodeStructCtor(_) => self.name(self.get_parent(id)),
+            Node::Item(i) => i.name,
+            Node::ForeignItem(i) => i.name,
+            Node::ImplItem(ii) => ii.ident.name,
+            Node::TraitItem(ti) => ti.ident.name,
+            Node::Variant(v) => v.node.name,
+            Node::Field(f) => f.ident.name,
+            Node::Lifetime(lt) => lt.name.ident().name,
+            Node::GenericParam(param) => param.name.ident().name,
+            Node::Binding(&Pat { node: PatKind::Binding(_,_,l,_), .. }) => l.name,
+            Node::StructCtor(_) => self.name(self.get_parent(id)),
             _ => bug!("no name for {}", self.node_to_string(id))
         }
     }
@@ -995,18 +855,18 @@ impl<'hir> Map<'hir> {
     pub fn attrs(&self, id: NodeId) -> &'hir [ast::Attribute] {
         self.read(id); // reveals attributes on the node
         let attrs = match self.find(id) {
-            Some(NodeItem(i)) => Some(&i.attrs[..]),
-            Some(NodeForeignItem(fi)) => Some(&fi.attrs[..]),
-            Some(NodeTraitItem(ref ti)) => Some(&ti.attrs[..]),
-            Some(NodeImplItem(ref ii)) => Some(&ii.attrs[..]),
-            Some(NodeVariant(ref v)) => Some(&v.node.attrs[..]),
-            Some(NodeField(ref f)) => Some(&f.attrs[..]),
-            Some(NodeExpr(ref e)) => Some(&*e.attrs),
-            Some(NodeStmt(ref s)) => Some(s.node.attrs()),
-            Some(NodeGenericParam(param)) => Some(&param.attrs[..]),
+            Some(Node::Item(i)) => Some(&i.attrs[..]),
+            Some(Node::ForeignItem(fi)) => Some(&fi.attrs[..]),
+            Some(Node::TraitItem(ref ti)) => Some(&ti.attrs[..]),
+            Some(Node::ImplItem(ref ii)) => Some(&ii.attrs[..]),
+            Some(Node::Variant(ref v)) => Some(&v.node.attrs[..]),
+            Some(Node::Field(ref f)) => Some(&f.attrs[..]),
+            Some(Node::Expr(ref e)) => Some(&*e.attrs),
+            Some(Node::Stmt(ref s)) => Some(s.node.attrs()),
+            Some(Node::GenericParam(param)) => Some(&param.attrs[..]),
             // unit/tuple structs take the attributes straight from
             // the struct definition.
-            Some(NodeStructCtor(_)) => {
+            Some(Node::StructCtor(_)) => {
                 return self.attrs(self.get_parent(id));
             }
             _ => None
@@ -1033,35 +893,33 @@ impl<'hir> Map<'hir> {
 
     pub fn span(&self, id: NodeId) -> Span {
         self.read(id); // reveals span from node
-        match self.find_entry(id) {
-            Some(EntryItem(_, _, item)) => item.span,
-            Some(EntryForeignItem(_, _, foreign_item)) => foreign_item.span,
-            Some(EntryTraitItem(_, _, trait_method)) => trait_method.span,
-            Some(EntryImplItem(_, _, impl_item)) => impl_item.span,
-            Some(EntryVariant(_, _, variant)) => variant.span,
-            Some(EntryField(_, _, field)) => field.span,
-            Some(EntryAnonConst(_, _, constant)) => self.body(constant.body).value.span,
-            Some(EntryExpr(_, _, expr)) => expr.span,
-            Some(EntryStmt(_, _, stmt)) => stmt.span,
-            Some(EntryTy(_, _, ty)) => ty.span,
-            Some(EntryTraitRef(_, _, tr)) => tr.path.span,
-            Some(EntryBinding(_, _, pat)) => pat.span,
-            Some(EntryPat(_, _, pat)) => pat.span,
-            Some(EntryBlock(_, _, block)) => block.span,
-            Some(EntryStructCtor(_, _, _)) => self.expect_item(self.get_parent(id)).span,
-            Some(EntryLifetime(_, _, lifetime)) => lifetime.span,
-            Some(EntryGenericParam(_, _, param)) => param.span,
-            Some(EntryVisibility(_, _, &Spanned {
+        match self.find_entry(id).map(|entry| entry.node) {
+            Some(Node::Item(item)) => item.span,
+            Some(Node::ForeignItem(foreign_item)) => foreign_item.span,
+            Some(Node::TraitItem(trait_method)) => trait_method.span,
+            Some(Node::ImplItem(impl_item)) => impl_item.span,
+            Some(Node::Variant(variant)) => variant.span,
+            Some(Node::Field(field)) => field.span,
+            Some(Node::AnonConst(constant)) => self.body(constant.body).value.span,
+            Some(Node::Expr(expr)) => expr.span,
+            Some(Node::Stmt(stmt)) => stmt.span,
+            Some(Node::Ty(ty)) => ty.span,
+            Some(Node::TraitRef(tr)) => tr.path.span,
+            Some(Node::Binding(pat)) => pat.span,
+            Some(Node::Pat(pat)) => pat.span,
+            Some(Node::Block(block)) => block.span,
+            Some(Node::StructCtor(_)) => self.expect_item(self.get_parent(id)).span,
+            Some(Node::Lifetime(lifetime)) => lifetime.span,
+            Some(Node::GenericParam(param)) => param.span,
+            Some(Node::Visibility(&Spanned {
                 node: VisibilityKind::Restricted { ref path, .. }, ..
             })) => path.span,
-            Some(EntryVisibility(_, _, v)) => bug!("unexpected Visibility {:?}", v),
-            Some(EntryLocal(_, _, local)) => local.span,
-            Some(EntryMacroDef(_, macro_def)) => macro_def.span,
+            Some(Node::Visibility(v)) => bug!("unexpected Visibility {:?}", v),
+            Some(Node::Local(local)) => local.span,
+            Some(Node::MacroDef(macro_def)) => macro_def.span,
 
-            Some(RootCrate(_)) => self.forest.krate.span,
-            Some(NotPresent) | None => {
-                bug!("hir::map::Map::span: id not in map: {:?}", id)
-            }
+            Some(Node::Crate) => self.forest.krate.span,
+            None => bug!("hir::map::Map::span: id not in map: {:?}", id),
         }
     }
 
@@ -1119,7 +977,7 @@ impl<'a, 'hir> NodesMatchingSuffix<'a, 'hir> {
         fn find_first_mod_parent<'a>(map: &'a Map, mut id: NodeId) -> Option<(NodeId, Name)> {
             loop {
                 match map.find(id)? {
-                    NodeItem(item) if item_is_mod(&item) =>
+                    Node::Item(item) if item_is_mod(&item) =>
                         return Some((id, item.name)),
                     _ => {}
                 }
@@ -1154,13 +1012,13 @@ impl<'a, 'hir> Iterator for NodesMatchingSuffix<'a, 'hir> {
                 return None;
             }
             self.idx = NodeId::from_u32(self.idx.as_u32() + 1);
-            let name = match self.map.find_entry(idx) {
-                Some(EntryItem(_, _, n))       => n.name(),
-                Some(EntryForeignItem(_, _, n))=> n.name(),
-                Some(EntryTraitItem(_, _, n))  => n.name(),
-                Some(EntryImplItem(_, _, n))   => n.name(),
-                Some(EntryVariant(_, _, n))    => n.name(),
-                Some(EntryField(_, _, n))      => n.name(),
+            let name = match self.map.find_entry(idx).map(|entry| entry.node) {
+                Some(Node::Item(n)) => n.name(),
+                Some(Node::ForeignItem(n)) => n.name(),
+                Some(Node::TraitItem(n)) => n.name(),
+                Some(Node::ImplItem(n)) => n.name(),
+                Some(Node::Variant(n)) => n.name(),
+                Some(Node::Field(n)) => n.name(),
                 _ => continue,
             };
             if self.matches_names(self.map.get_parent(idx), name) {
@@ -1209,12 +1067,8 @@ pub fn map_crate<'hir>(sess: &::session::Session,
     if log_enabled!(::log::Level::Debug) {
         // This only makes sense for ordered stores; note the
         // enumerate to count the number of entries.
-        let (entries_less_1, _) = map.iter().filter(|&x| {
-            match *x {
-                NotPresent => false,
-                _ => true
-            }
-        }).enumerate().last().expect("AST map was empty after folding?");
+        let (entries_less_1, _) = map.iter().filter_map(|x| *x).enumerate().last()
+            .expect("AST map was empty after folding?");
 
         let entries = entries_less_1 + 1;
         let vector_length = map.len();
@@ -1257,19 +1111,19 @@ impl<'hir> print::PpAnn for Map<'hir> {
 impl<'a> print::State<'a> {
     pub fn print_node(&mut self, node: Node) -> io::Result<()> {
         match node {
-            NodeItem(a)         => self.print_item(&a),
-            NodeForeignItem(a)  => self.print_foreign_item(&a),
-            NodeTraitItem(a)    => self.print_trait_item(a),
-            NodeImplItem(a)     => self.print_impl_item(a),
-            NodeVariant(a)      => self.print_variant(&a),
-            NodeAnonConst(a)    => self.print_anon_const(&a),
-            NodeExpr(a)         => self.print_expr(&a),
-            NodeStmt(a)         => self.print_stmt(&a),
-            NodeTy(a)           => self.print_type(&a),
-            NodeTraitRef(a)     => self.print_trait_ref(&a),
-            NodeBinding(a)       |
-            NodePat(a)          => self.print_pat(&a),
-            NodeBlock(a)        => {
+            Node::Item(a)         => self.print_item(&a),
+            Node::ForeignItem(a)  => self.print_foreign_item(&a),
+            Node::TraitItem(a)    => self.print_trait_item(a),
+            Node::ImplItem(a)     => self.print_impl_item(a),
+            Node::Variant(a)      => self.print_variant(&a),
+            Node::AnonConst(a)    => self.print_anon_const(&a),
+            Node::Expr(a)         => self.print_expr(&a),
+            Node::Stmt(a)         => self.print_stmt(&a),
+            Node::Ty(a)           => self.print_type(&a),
+            Node::TraitRef(a)     => self.print_trait_ref(&a),
+            Node::Binding(a)      |
+            Node::Pat(a)          => self.print_pat(&a),
+            Node::Block(a)        => {
                 use syntax::print::pprust::PrintState;
 
                 // containing cbox, will be closed by print-block at }
@@ -1278,16 +1132,17 @@ impl<'a> print::State<'a> {
                 self.ibox(0)?;
                 self.print_block(&a)
             }
-            NodeLifetime(a)     => self.print_lifetime(&a),
-            NodeVisibility(a)   => self.print_visibility(&a),
-            NodeGenericParam(_) => bug!("cannot print NodeGenericParam"),
-            NodeField(_)        => bug!("cannot print StructField"),
+            Node::Lifetime(a)     => self.print_lifetime(&a),
+            Node::Visibility(a)   => self.print_visibility(&a),
+            Node::GenericParam(_) => bug!("cannot print Node::GenericParam"),
+            Node::Field(_)        => bug!("cannot print StructField"),
             // these cases do not carry enough information in the
             // hir_map to reconstruct their full structure for pretty
             // printing.
-            NodeStructCtor(_)   => bug!("cannot print isolated StructCtor"),
-            NodeLocal(a)        => self.print_local_decl(&a),
-            NodeMacroDef(_)     => bug!("cannot print MacroDef"),
+            Node::StructCtor(_)   => bug!("cannot print isolated StructCtor"),
+            Node::Local(a)        => self.print_local_decl(&a),
+            Node::MacroDef(_)     => bug!("cannot print MacroDef"),
+            Node::Crate     => bug!("cannot print Crate"),
         }
     }
 }
@@ -1313,7 +1168,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
     };
 
     match map.find(id) {
-        Some(NodeItem(item)) => {
+        Some(Node::Item(item)) => {
             let item_str = match item.node {
                 ItemKind::ExternCrate(..) => "extern crate",
                 ItemKind::Use(..) => "use",
@@ -1334,10 +1189,10 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
             };
             format!("{} {}{}", item_str, path_str(), id_str)
         }
-        Some(NodeForeignItem(_)) => {
+        Some(Node::ForeignItem(_)) => {
             format!("foreign item {}{}", path_str(), id_str)
         }
-        Some(NodeImplItem(ii)) => {
+        Some(Node::ImplItem(ii)) => {
             match ii.node {
                 ImplItemKind::Const(..) => {
                     format!("assoc const {} in {}{}", ii.ident, path_str(), id_str)
@@ -1353,7 +1208,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
                 }
             }
         }
-        Some(NodeTraitItem(ti)) => {
+        Some(Node::TraitItem(ti)) => {
             let kind = match ti.node {
                 TraitItemKind::Const(..) => "assoc constant",
                 TraitItemKind::Method(..) => "trait method",
@@ -1362,61 +1217,60 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
 
             format!("{} {} in {}{}", kind, ti.ident, path_str(), id_str)
         }
-        Some(NodeVariant(ref variant)) => {
+        Some(Node::Variant(ref variant)) => {
             format!("variant {} in {}{}",
                     variant.node.name,
                     path_str(), id_str)
         }
-        Some(NodeField(ref field)) => {
+        Some(Node::Field(ref field)) => {
             format!("field {} in {}{}",
                     field.ident,
                     path_str(), id_str)
         }
-        Some(NodeAnonConst(_)) => {
+        Some(Node::AnonConst(_)) => {
             format!("const {}{}", map.node_to_pretty_string(id), id_str)
         }
-        Some(NodeExpr(_)) => {
+        Some(Node::Expr(_)) => {
             format!("expr {}{}", map.node_to_pretty_string(id), id_str)
         }
-        Some(NodeStmt(_)) => {
+        Some(Node::Stmt(_)) => {
             format!("stmt {}{}", map.node_to_pretty_string(id), id_str)
         }
-        Some(NodeTy(_)) => {
+        Some(Node::Ty(_)) => {
             format!("type {}{}", map.node_to_pretty_string(id), id_str)
         }
-        Some(NodeTraitRef(_)) => {
+        Some(Node::TraitRef(_)) => {
             format!("trait_ref {}{}", map.node_to_pretty_string(id), id_str)
         }
-        Some(NodeBinding(_)) => {
+        Some(Node::Binding(_)) => {
             format!("local {}{}", map.node_to_pretty_string(id), id_str)
         }
-        Some(NodePat(_)) => {
+        Some(Node::Pat(_)) => {
             format!("pat {}{}", map.node_to_pretty_string(id), id_str)
         }
-        Some(NodeBlock(_)) => {
+        Some(Node::Block(_)) => {
             format!("block {}{}", map.node_to_pretty_string(id), id_str)
         }
-        Some(NodeLocal(_)) => {
+        Some(Node::Local(_)) => {
             format!("local {}{}", map.node_to_pretty_string(id), id_str)
         }
-        Some(NodeStructCtor(_)) => {
+        Some(Node::StructCtor(_)) => {
             format!("struct_ctor {}{}", path_str(), id_str)
         }
-        Some(NodeLifetime(_)) => {
+        Some(Node::Lifetime(_)) => {
             format!("lifetime {}{}", map.node_to_pretty_string(id), id_str)
         }
-        Some(NodeGenericParam(ref param)) => {
+        Some(Node::GenericParam(ref param)) => {
             format!("generic_param {:?}{}", param, id_str)
         }
-        Some(NodeVisibility(ref vis)) => {
+        Some(Node::Visibility(ref vis)) => {
             format!("visibility {:?}{}", vis, id_str)
         }
-        Some(NodeMacroDef(_)) => {
+        Some(Node::MacroDef(_)) => {
             format!("macro {}{}",  path_str(), id_str)
         }
-        None => {
-            format!("unknown node{}", id_str)
-        }
+        Some(Node::Crate) => format!("root_crate"),
+        None => format!("unknown node{}", id_str),
     }
 }
 
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 6bdfbd40e8d..7ac334d84a9 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -2287,25 +2287,59 @@ pub fn provide(providers: &mut Providers) {
 #[derive(Clone, RustcEncodable, RustcDecodable)]
 pub struct CodegenFnAttrs {
     pub flags: CodegenFnAttrFlags,
+    /// Parsed representation of the `#[inline]` attribute
     pub inline: InlineAttr,
+    /// The `#[export_name = "..."]` attribute, indicating a custom symbol a
+    /// function should be exported under
     pub export_name: Option<Symbol>,
+    /// The `#[link_name = "..."]` attribute, indicating a custom symbol an
+    /// imported function should be imported as. Note that `export_name`
+    /// probably isn't set when this is set, this is for foreign items while
+    /// `#[export_name]` is for Rust-defined functions.
+    pub link_name: Option<Symbol>,
+    /// The `#[target_feature(enable = "...")]` attribute and the enabled
+    /// features (only enabled features are supported right now).
     pub target_features: Vec<Symbol>,
+    /// The `#[linkage = "..."]` attribute and the value we found.
     pub linkage: Option<Linkage>,
+    /// The `#[link_section = "..."]` attribute, or what executable section this
+    /// should be placed in.
     pub link_section: Option<Symbol>,
 }
 
 bitflags! {
     #[derive(RustcEncodable, RustcDecodable)]
     pub struct CodegenFnAttrFlags: u32 {
+        /// #[cold], a hint to LLVM that this function, when called, is never on
+        /// the hot path
         const COLD                      = 1 << 0;
+        /// #[allocator], a hint to LLVM that the pointer returned from this
+        /// function is never null
         const ALLOCATOR                 = 1 << 1;
+        /// #[unwind], an indicator that this function may unwind despite what
+        /// its ABI signature may otherwise imply
         const UNWIND                    = 1 << 2;
+        /// #[rust_allocator_nounwind], an indicator that an imported FFI
+        /// function will never unwind. Probably obsolete by recent changes with
+        /// #[unwind], but hasn't been removed/migrated yet
         const RUSTC_ALLOCATOR_NOUNWIND  = 1 << 3;
+        /// #[naked], indicates to LLVM that no function prologue/epilogue
+        /// should be generated
         const NAKED                     = 1 << 4;
+        /// #[no_mangle], the function's name should be the same as its symbol
         const NO_MANGLE                 = 1 << 5;
+        /// #[rustc_std_internal_symbol], and indicator that this symbol is a
+        /// "weird symbol" for the standard library in that it has slightly
+        /// different linkage, visibility, and reachability rules.
         const RUSTC_STD_INTERNAL_SYMBOL = 1 << 6;
+        /// #[no_debug], indicates that no debugging information should be
+        /// generated for this function by LLVM
         const NO_DEBUG                  = 1 << 7;
+        /// #[thread_local], indicates a static is actually a thread local
+        /// piece of memory
         const THREAD_LOCAL              = 1 << 8;
+        /// #[used], indicates that LLVM can't eliminate this function (but the
+        /// linker can!)
         const USED                      = 1 << 9;
     }
 }
@@ -2316,6 +2350,7 @@ impl CodegenFnAttrs {
             flags: CodegenFnAttrFlags::empty(),
             inline: InlineAttr::None,
             export_name: None,
+            link_name: None,
             target_features: vec![],
             linkage: None,
             link_section: None,
@@ -2335,3 +2370,32 @@ impl CodegenFnAttrs {
         self.flags.contains(CodegenFnAttrFlags::NO_MANGLE) || self.export_name.is_some()
     }
 }
+
+#[derive(Copy, Clone, Debug)]
+pub enum Node<'hir> {
+    Item(&'hir Item),
+    ForeignItem(&'hir ForeignItem),
+    TraitItem(&'hir TraitItem),
+    ImplItem(&'hir ImplItem),
+    Variant(&'hir Variant),
+    Field(&'hir StructField),
+    AnonConst(&'hir AnonConst),
+    Expr(&'hir Expr),
+    Stmt(&'hir Stmt),
+    Ty(&'hir Ty),
+    TraitRef(&'hir TraitRef),
+    Binding(&'hir Pat),
+    Pat(&'hir Pat),
+    Block(&'hir Block),
+    Local(&'hir Local),
+    MacroDef(&'hir MacroDef),
+
+    /// StructCtor represents a tuple struct.
+    StructCtor(&'hir VariantData),
+
+    Lifetime(&'hir Lifetime),
+    GenericParam(&'hir GenericParam),
+    Visibility(&'hir Visibility),
+
+    Crate,
+}
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 9fe462e65a2..8b221f3463e 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub use self::AnnNode::*;
-
 use rustc_target::spec::abi::Abi;
 use syntax::ast;
 use syntax::source_map::{SourceMap, Spanned};
@@ -33,12 +31,12 @@ use std::iter::Peekable;
 use std::vec;
 
 pub enum AnnNode<'a> {
-    NodeName(&'a ast::Name),
-    NodeBlock(&'a hir::Block),
-    NodeItem(&'a hir::Item),
-    NodeSubItem(ast::NodeId),
-    NodeExpr(&'a hir::Expr),
-    NodePat(&'a hir::Pat),
+    Name(&'a ast::Name),
+    Block(&'a hir::Block),
+    Item(&'a hir::Item),
+    SubItem(ast::NodeId),
+    Expr(&'a hir::Expr),
+    Pat(&'a hir::Pat),
 }
 
 pub enum Nested {
@@ -529,7 +527,7 @@ impl<'a> State<'a> {
         self.hardbreak_if_not_bol()?;
         self.maybe_print_comment(item.span.lo())?;
         self.print_outer_attributes(&item.attrs)?;
-        self.ann.pre(self, NodeItem(item))?;
+        self.ann.pre(self, AnnNode::Item(item))?;
         match item.node {
             hir::ItemKind::ExternCrate(orig_name) => {
                 self.head(&visibility_qualified(&item.vis, "extern crate"))?;
@@ -768,7 +766,7 @@ impl<'a> State<'a> {
                 self.s.word(";")?;
             }
         }
-        self.ann.post(self, NodeItem(item))
+        self.ann.post(self, AnnNode::Item(item))
     }
 
     pub fn print_trait_ref(&mut self, t: &hir::TraitRef) -> io::Result<()> {
@@ -933,7 +931,7 @@ impl<'a> State<'a> {
     }
 
     pub fn print_trait_item(&mut self, ti: &hir::TraitItem) -> io::Result<()> {
-        self.ann.pre(self, NodeSubItem(ti.id))?;
+        self.ann.pre(self, AnnNode::SubItem(ti.id))?;
         self.hardbreak_if_not_bol()?;
         self.maybe_print_comment(ti.span.lo())?;
         self.print_outer_attributes(&ti.attrs)?;
@@ -965,11 +963,11 @@ impl<'a> State<'a> {
                                            default.as_ref().map(|ty| &**ty))?;
             }
         }
-        self.ann.post(self, NodeSubItem(ti.id))
+        self.ann.post(self, AnnNode::SubItem(ti.id))
     }
 
     pub fn print_impl_item(&mut self, ii: &hir::ImplItem) -> io::Result<()> {
-        self.ann.pre(self, NodeSubItem(ii.id))?;
+        self.ann.pre(self, AnnNode::SubItem(ii.id))?;
         self.hardbreak_if_not_bol()?;
         self.maybe_print_comment(ii.span.lo())?;
         self.print_outer_attributes(&ii.attrs)?;
@@ -995,7 +993,7 @@ impl<'a> State<'a> {
                 self.print_associated_type(ii.ident, Some(bounds), None)?;
             }
         }
-        self.ann.post(self, NodeSubItem(ii.id))
+        self.ann.post(self, AnnNode::SubItem(ii.id))
     }
 
     pub fn print_stmt(&mut self, st: &hir::Stmt) -> io::Result<()> {
@@ -1055,7 +1053,7 @@ impl<'a> State<'a> {
             hir::DefaultBlock => (),
         }
         self.maybe_print_comment(blk.span.lo())?;
-        self.ann.pre(self, NodeBlock(blk))?;
+        self.ann.pre(self, AnnNode::Block(blk))?;
         self.bopen()?;
 
         self.print_inner_attributes(attrs)?;
@@ -1072,7 +1070,7 @@ impl<'a> State<'a> {
             _ => (),
         }
         self.bclose_maybe_open(blk.span, indented, close_box)?;
-        self.ann.post(self, NodeBlock(blk))
+        self.ann.post(self, AnnNode::Block(blk))
     }
 
     fn print_else(&mut self, els: Option<&hir::Expr>) -> io::Result<()> {
@@ -1321,7 +1319,7 @@ impl<'a> State<'a> {
         self.maybe_print_comment(expr.span.lo())?;
         self.print_outer_attributes(&expr.attrs)?;
         self.ibox(indent_unit)?;
-        self.ann.pre(self, NodeExpr(expr))?;
+        self.ann.pre(self, AnnNode::Expr(expr))?;
         match expr.node {
             hir::ExprKind::Box(ref expr) => {
                 self.word_space("box")?;
@@ -1559,7 +1557,7 @@ impl<'a> State<'a> {
                 self.print_expr_maybe_paren(&expr, parser::PREC_JUMP)?;
             }
         }
-        self.ann.post(self, NodeExpr(expr))?;
+        self.ann.post(self, AnnNode::Expr(expr))?;
         self.end()
     }
 
@@ -1606,7 +1604,7 @@ impl<'a> State<'a> {
         } else {
             self.s.word(&ident.as_str())?;
         }
-        self.ann.post(self, NodeName(&ident.name))
+        self.ann.post(self, AnnNode::Name(&ident.name))
     }
 
     pub fn print_name(&mut self, name: ast::Name) -> io::Result<()> {
@@ -1774,7 +1772,7 @@ impl<'a> State<'a> {
 
     pub fn print_pat(&mut self, pat: &hir::Pat) -> io::Result<()> {
         self.maybe_print_comment(pat.span.lo())?;
-        self.ann.pre(self, NodePat(pat))?;
+        self.ann.pre(self, AnnNode::Pat(pat))?;
         // Pat isn't normalized, but the beauty of it
         // is that it doesn't matter
         match pat.node {
@@ -1928,7 +1926,7 @@ impl<'a> State<'a> {
                 self.s.word("]")?;
             }
         }
-        self.ann.post(self, NodePat(pat))
+        self.ann.post(self, AnnNode::Pat(pat))
     }
 
     fn print_arm(&mut self, arm: &hir::Arm) -> io::Result<()> {
diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs
index f03ad98c7de..371f631737c 100644
--- a/src/librustc/ich/hcx.rs
+++ b/src/librustc/ich/hcx.rs
@@ -34,8 +34,8 @@ use syntax_pos::hygiene;
 use rustc_data_structures::stable_hasher::{HashStable,
                                            StableHasher, StableHasherResult,
                                            ToStableHashKey};
-use rustc_data_structures::accumulate_vec::AccumulateVec;
 use rustc_data_structures::fx::{FxHashSet, FxHashMap};
+use smallvec::SmallVec;
 
 fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
     debug_assert!(ich::IGNORED_ATTRIBUTES.len() > 0);
@@ -405,7 +405,7 @@ pub fn hash_stable_trait_impls<'a, 'gcx, W, R>(
           R: std_hash::BuildHasher,
 {
     {
-        let mut blanket_impls: AccumulateVec<[_; 8]> = blanket_impls
+        let mut blanket_impls: SmallVec<[_; 8]> = blanket_impls
             .iter()
             .map(|&def_id| hcx.def_path_hash(def_id))
             .collect();
@@ -418,7 +418,7 @@ pub fn hash_stable_trait_impls<'a, 'gcx, W, R>(
     }
 
     {
-        let mut keys: AccumulateVec<[_; 8]> =
+        let mut keys: SmallVec<[_; 8]> =
             non_blanket_impls.keys()
                              .map(|k| (k, k.map_def(|d| hcx.def_path_hash(d))))
                              .collect();
@@ -426,7 +426,7 @@ pub fn hash_stable_trait_impls<'a, 'gcx, W, R>(
         keys.len().hash_stable(hcx, hasher);
         for (key, ref stable_key) in keys {
             stable_key.hash_stable(hcx, hasher);
-            let mut impls : AccumulateVec<[_; 8]> = non_blanket_impls[key]
+            let mut impls : SmallVec<[_; 8]> = non_blanket_impls[key]
                 .iter()
                 .map(|&impl_id| hcx.def_path_hash(impl_id))
                 .collect();
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index e82ef8bbdae..2ac195dca82 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -1136,6 +1136,7 @@ impl_stable_hash_for!(struct hir::CodegenFnAttrs {
     flags,
     inline,
     export_name,
+    link_name,
     target_features,
     linkage,
     link_section,
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
index 4811f84635c..ac5fdb2fe27 100644
--- a/src/librustc/ich/impls_syntax.rs
+++ b/src/librustc/ich/impls_syntax.rs
@@ -25,9 +25,9 @@ use syntax_pos::SourceFile;
 
 use hir::def_id::{DefId, CrateNum, CRATE_DEF_INDEX};
 
+use smallvec::SmallVec;
 use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey,
                                            StableHasher, StableHasherResult};
-use rustc_data_structures::accumulate_vec::AccumulateVec;
 
 impl<'a> HashStable<StableHashingContext<'a>> for InternedString {
     #[inline]
@@ -207,7 +207,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] {
         }
 
         // Some attributes are always ignored during hashing.
-        let filtered: AccumulateVec<[&ast::Attribute; 8]> = self
+        let filtered: SmallVec<[&ast::Attribute; 8]> = self
             .iter()
             .filter(|attr| {
                 !attr.is_sugared_doc && !hcx.is_ignored_attr(attr.name())
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index f4c46b6ce09..c598f99a2b5 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -384,7 +384,8 @@ for ::mir::interpret::ConstValue<'gcx> {
                 a.hash_stable(hcx, hasher);
                 b.hash_stable(hcx, hasher);
             }
-            ByRef(alloc, offset) => {
+            ByRef(id, alloc, offset) => {
+                id.hash_stable(hcx, hasher);
                 alloc.hash_stable(hcx, hasher);
                 offset.hash_stable(hcx, hasher);
             }
@@ -446,7 +447,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::Allocation {
         }
         self.undef_mask.hash_stable(hcx, hasher);
         self.align.hash_stable(hcx, hasher);
-        self.runtime_mutability.hash_stable(hcx, hasher);
+        self.mutability.hash_stable(hcx, hasher);
     }
 }
 
@@ -516,7 +517,6 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
             InvalidMemoryAccess |
             InvalidFunctionPointer |
             InvalidBool |
-            InvalidDiscriminant |
             InvalidNullPointerUsage |
             ReadPointerAsBytes |
             ReadBytesAsPointer |
@@ -549,6 +549,7 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
             GeneratorResumedAfterReturn |
             GeneratorResumedAfterPanic |
             InfiniteLoop => {}
+            InvalidDiscriminant(val) => val.hash_stable(hcx, hasher),
             Panic { ref msg, ref file, line, col } => {
                 msg.hash_stable(hcx, hasher);
                 file.hash_stable(hcx, hasher);
diff --git a/src/librustc/infer/anon_types/mod.rs b/src/librustc/infer/anon_types/mod.rs
index 96c64c05ccf..8eab07ece05 100644
--- a/src/librustc/infer/anon_types/mod.rs
+++ b/src/librustc/infer/anon_types/mod.rs
@@ -10,6 +10,7 @@
 
 use hir::def_id::DefId;
 use hir;
+use hir::Node;
 use infer::{self, InferCtxt, InferOk, TypeVariableOrigin};
 use infer::outlives::free_region_map::FreeRegionRelations;
 use rustc_data_structures::fx::FxHashMap;
@@ -697,7 +698,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
                             parent_def_id == tcx.hir.local_def_id(anon_parent_node_id)
                         };
                         let in_definition_scope = match tcx.hir.find(anon_node_id) {
-                            Some(hir::map::NodeItem(item)) => match item.node {
+                            Some(Node::Item(item)) => match item.node {
                                 // impl trait
                                 hir::ItemKind::Existential(hir::ExistTy {
                                     impl_trait_fn: Some(parent),
@@ -714,7 +715,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
                                 ),
                                 _ => def_scope_default(),
                             },
-                            Some(hir::map::NodeImplItem(item)) => match item.node {
+                            Some(Node::ImplItem(item)) => match item.node {
                                 hir::ImplItemKind::Existential(_) => may_define_existential_type(
                                     tcx,
                                     self.parent_def_id,
diff --git a/src/librustc/infer/canonical/query_result.rs b/src/librustc/infer/canonical/query_result.rs
index 341089d8a81..65d42c0888d 100644
--- a/src/librustc/infer/canonical/query_result.rs
+++ b/src/librustc/infer/canonical/query_result.rs
@@ -24,19 +24,18 @@ use infer::canonical::{
 };
 use infer::region_constraints::{Constraint, RegionConstraintData};
 use infer::InferCtxtBuilder;
-use infer::{InferCtxt, InferOk, InferResult, RegionObligation};
+use infer::{InferCtxt, InferOk, InferResult};
 use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc_data_structures::sync::Lrc;
 use std::fmt::Debug;
-use syntax::ast;
 use syntax_pos::DUMMY_SP;
 use traits::query::{Fallible, NoSolution};
 use traits::{FulfillmentContext, TraitEngine};
 use traits::{Obligation, ObligationCause, PredicateObligation};
 use ty::fold::TypeFoldable;
 use ty::subst::{Kind, UnpackedKind};
-use ty::{self, CanonicalVar, Lift, TyCtxt};
+use ty::{self, CanonicalVar, Lift, Ty, TyCtxt};
 
 impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> {
     /// The "main method" for a canonicalized trait query. Given the
@@ -157,7 +156,12 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
 
         let region_obligations = self.take_registered_region_obligations();
         let region_constraints = self.with_region_constraints(|region_constraints| {
-            make_query_outlives(tcx, region_obligations, region_constraints)
+            make_query_outlives(
+                tcx,
+                region_obligations
+                    .iter()
+                    .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region)),
+                region_constraints)
         });
 
         let certainty = if ambig_errors.is_empty() {
@@ -567,7 +571,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
 /// creates query region constraints.
 pub fn make_query_outlives<'tcx>(
     tcx: TyCtxt<'_, '_, 'tcx>,
-    region_obligations: Vec<(ast::NodeId, RegionObligation<'tcx>)>,
+    outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>)>,
     region_constraints: &RegionConstraintData<'tcx>,
 ) -> Vec<QueryRegionConstraint<'tcx>> {
     let RegionConstraintData {
@@ -600,9 +604,8 @@ pub fn make_query_outlives<'tcx>(
             .collect();
 
     outlives.extend(
-        region_obligations
-            .into_iter()
-            .map(|(_, r_o)| ty::OutlivesPredicate(r_o.sup_type.into(), r_o.sub_region))
+        outlives_obligations
+            .map(|(ty, r)| ty::OutlivesPredicate(ty.into(), r))
             .map(ty::Binder::dummy), // no bound regions in the code above
     );
 
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index b05ea9a5ed4..cf0d0ceadca 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -62,7 +62,7 @@ use super::lexical_region_resolve::RegionResolutionError;
 
 use std::{cmp, fmt};
 use hir;
-use hir::map as hir_map;
+use hir::Node;
 use hir::def_id::DefId;
 use middle::region;
 use traits::{ObligationCause, ObligationCauseCode};
@@ -100,8 +100,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 };
                 let span = scope.span(self, region_scope_tree);
                 let tag = match self.hir.find(scope.node_id(self, region_scope_tree)) {
-                    Some(hir_map::NodeBlock(_)) => "block",
-                    Some(hir_map::NodeExpr(expr)) => match expr.node {
+                    Some(Node::Block(_)) => "block",
+                    Some(Node::Expr(expr)) => match expr.node {
                         hir::ExprKind::Call(..) => "call",
                         hir::ExprKind::MethodCall(..) => "method call",
                         hir::ExprKind::Match(.., hir::MatchSource::IfLetDesugar { .. }) => "if let",
@@ -110,10 +110,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                         hir::ExprKind::Match(..) => "match",
                         _ => "expression",
                     },
-                    Some(hir_map::NodeStmt(_)) => "statement",
-                    Some(hir_map::NodeItem(it)) => Self::item_scope_tag(&it),
-                    Some(hir_map::NodeTraitItem(it)) => Self::trait_item_scope_tag(&it),
-                    Some(hir_map::NodeImplItem(it)) => Self::impl_item_scope_tag(&it),
+                    Some(Node::Stmt(_)) => "statement",
+                    Some(Node::Item(it)) => Self::item_scope_tag(&it),
+                    Some(Node::TraitItem(it)) => Self::trait_item_scope_tag(&it),
+                    Some(Node::ImplItem(it)) => Self::impl_item_scope_tag(&it),
                     Some(_) | None => {
                         err.span_note(span, &unknown_scope());
                         return;
@@ -194,10 +194,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         let scope = region.free_region_binding_scope(self);
         let node = self.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID);
         let tag = match self.hir.find(node) {
-            Some(hir_map::NodeBlock(_)) | Some(hir_map::NodeExpr(_)) => "body",
-            Some(hir_map::NodeItem(it)) => Self::item_scope_tag(&it),
-            Some(hir_map::NodeTraitItem(it)) => Self::trait_item_scope_tag(&it),
-            Some(hir_map::NodeImplItem(it)) => Self::impl_item_scope_tag(&it),
+            Some(Node::Block(_)) | Some(Node::Expr(_)) => "body",
+            Some(Node::Item(it)) => Self::item_scope_tag(&it),
+            Some(Node::TraitItem(it)) => Self::trait_item_scope_tag(&it),
+            Some(Node::ImplItem(it)) => Self::impl_item_scope_tag(&it),
             _ => unreachable!()
         };
         let (prefix, span) = match *region {
@@ -1127,7 +1127,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                             // We do this to avoid suggesting code that ends up as `T: 'a'b`,
                             // instead we suggest `T: 'a + 'b` in that case.
                             let mut has_bounds = false;
-                            if let hir_map::NodeGenericParam(ref param) = hir.get(id) {
+                            if let Node::GenericParam(ref param) = hir.get(id) {
                                 has_bounds = !param.bounds.is_empty();
                             }
                             let sp = hir.span(id);
diff --git a/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs b/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs
index 21be09b0ba1..e3faf755672 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs
+++ b/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs
@@ -10,7 +10,7 @@
 
 use hir;
 use ty::{self, Region, TyCtxt};
-use hir::map as hir_map;
+use hir::Node;
 use middle::resolve_lifetime as rl;
 use hir::intravisit::{self, NestedVisitorMap, Visitor};
 use infer::error_reporting::nice_region_error::NiceRegionError;
@@ -40,15 +40,15 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
             let def_id = anon_reg.def_id;
             if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
                 let fndecl = match self.tcx.hir.get(node_id) {
-                    hir_map::NodeItem(&hir::Item {
+                    Node::Item(&hir::Item {
                         node: hir::ItemKind::Fn(ref fndecl, ..),
                         ..
                     }) => &fndecl,
-                    hir_map::NodeTraitItem(&hir::TraitItem {
+                    Node::TraitItem(&hir::TraitItem {
                         node: hir::TraitItemKind::Method(ref m, ..),
                         ..
                     })
-                    | hir_map::NodeImplItem(&hir::ImplItem {
+                    | Node::ImplItem(&hir::ImplItem {
                         node: hir::ImplItemKind::Method(ref m, ..),
                         ..
                     }) => &m.decl,
diff --git a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs b/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs
index f4ef197e5b4..5c27cdb6fb5 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs
+++ b/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs
@@ -15,7 +15,7 @@ use infer::error_reporting::nice_region_error::NiceRegionError;
 use infer::SubregionOrigin;
 use ty::RegionKind;
 use hir::{Expr, ExprKind::Closure};
-use hir::map::NodeExpr;
+use hir::Node;
 use util::common::ErrorReported;
 use infer::lexical_region_resolve::RegionResolutionError::SubSupConflict;
 
@@ -59,7 +59,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
                 let hir = &self.tcx.hir;
                 if let Some(node_id) = hir.as_local_node_id(free_region.scope) {
                     match hir.get(node_id) {
-                        NodeExpr(Expr {
+                        Node::Expr(Expr {
                             node: Closure(_, _, _, closure_span, None),
                             ..
                         }) => {
diff --git a/src/librustc/infer/error_reporting/nice_region_error/util.rs b/src/librustc/infer/error_reporting/nice_region_error/util.rs
index 8cb0df18bc8..30406f1fec5 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/util.rs
+++ b/src/librustc/infer/error_reporting/nice_region_error/util.rs
@@ -10,11 +10,12 @@
 
 //! Helper functions corresponding to lifetime errors due to
 //! anonymous regions.
+
 use hir;
 use infer::error_reporting::nice_region_error::NiceRegionError;
 use ty::{self, Region, Ty};
 use hir::def_id::DefId;
-use hir::map as hir_map;
+use hir::Node;
 use syntax_pos::Span;
 
 // The struct contains the information about the anonymous region
@@ -137,8 +138,8 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
             .as_local_node_id(suitable_region_binding_scope)
             .unwrap();
         let is_impl_item = match self.tcx.hir.find(node_id) {
-            Some(hir_map::NodeItem(..)) | Some(hir_map::NodeTraitItem(..)) => false,
-            Some(hir_map::NodeImplItem(..)) => {
+            Some(Node::Item(..)) | Some(Node::TraitItem(..)) => false,
+            Some(Node::ImplItem(..)) => {
                 self.is_bound_region_in_impl_item(suitable_region_binding_scope)
             }
             _ => return None,
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index db37f1883f1..d014f319564 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -51,6 +51,7 @@
 #![feature(exhaustive_patterns)]
 #![feature(extern_types)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(non_exhaustive)]
 #![feature(proc_macro_internals)]
 #![feature(quote)]
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index 5872440c362..cc0548c0dff 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -266,7 +266,7 @@ macro_rules! late_lint_methods {
 
 macro_rules! expand_lint_pass_methods {
     ($context:ty, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
-        $(#[inline(always)] fn $name(&mut self, $context, $(_: $arg),*) {})*
+        $(#[inline(always)] fn $name(&mut self, _: $context, $(_: $arg),*) {})*
     )
 }
 
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 30701654f29..d320173f9f4 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -12,7 +12,7 @@
 // closely. The idea is that all reachable symbols are live, codes called
 // from live codes are live, and everything else is dead.
 
-use hir::map as hir_map;
+use hir::Node;
 use hir::{self, PatKind};
 use hir::intravisit::{self, Visitor, NestedVisitorMap};
 use hir::itemlikevisit::ItemLikeVisitor;
@@ -29,16 +29,16 @@ use syntax::attr;
 use syntax_pos;
 
 // Any local node that may call something in its body block should be
-// explored. For example, if it's a live NodeItem that is a
+// explored. For example, if it's a live Node::Item that is a
 // function, then we should explore its block to check for codes that
 // may need to be marked as live.
 fn should_explore<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             node_id: ast::NodeId) -> bool {
     match tcx.hir.find(node_id) {
-        Some(hir_map::NodeItem(..)) |
-        Some(hir_map::NodeImplItem(..)) |
-        Some(hir_map::NodeForeignItem(..)) |
-        Some(hir_map::NodeTraitItem(..)) =>
+        Some(Node::Item(..)) |
+        Some(Node::ImplItem(..)) |
+        Some(Node::ForeignItem(..)) |
+        Some(Node::TraitItem(..)) =>
             true,
         _ =>
             false
@@ -145,13 +145,13 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
         }
     }
 
-    fn visit_node(&mut self, node: &hir_map::Node<'tcx>) {
+    fn visit_node(&mut self, node: &Node<'tcx>) {
         let had_repr_c = self.repr_has_repr_c;
         self.repr_has_repr_c = false;
         let had_inherited_pub_visibility = self.inherited_pub_visibility;
         self.inherited_pub_visibility = false;
         match *node {
-            hir_map::NodeItem(item) => {
+            Node::Item(item) => {
                 match item.node {
                     hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
                         let def_id = self.tcx.hir.local_def_id(item.id);
@@ -173,13 +173,13 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
                     _ => ()
                 }
             }
-            hir_map::NodeTraitItem(trait_item) => {
+            Node::TraitItem(trait_item) => {
                 intravisit::walk_trait_item(self, trait_item);
             }
-            hir_map::NodeImplItem(impl_item) => {
+            Node::ImplItem(impl_item) => {
                 intravisit::walk_impl_item(self, impl_item);
             }
-            hir_map::NodeForeignItem(foreign_item) => {
+            Node::ForeignItem(foreign_item) => {
                 intravisit::walk_foreign_item(self, &foreign_item);
             }
             _ => ()
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 7d9590ee578..2697d62cf46 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -102,11 +102,13 @@
 //!   only dead if the end of the function's block can never be reached.
 //!   It is the responsibility of typeck to ensure that there are no
 //!   `return` expressions in a function declared as diverging.
+
 use self::LoopKind::*;
 use self::LiveNodeKind::*;
 use self::VarKind::*;
 
 use hir::def::*;
+use hir::Node;
 use ty::{self, TyCtxt};
 use lint;
 use errors::Applicability;
@@ -362,7 +364,7 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
     // Don't run unused pass for #[derive()]
     if let FnKind::Method(..) = fk {
         let parent = ir.tcx.hir.get_parent(id);
-        if let Some(hir::map::Node::NodeItem(i)) = ir.tcx.hir.find(parent) {
+        if let Some(Node::Item(i)) = ir.tcx.hir.find(parent) {
             if i.attrs.iter().any(|a| a.check_name("automatically_derived")) {
                 return;
             }
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index e0ed0f1da50..b63cde0f205 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -70,7 +70,7 @@ use self::Aliasability::*;
 
 use middle::region;
 use hir::def_id::{DefId, LocalDefId};
-use hir::map as hir_map;
+use hir::Node;
 use infer::InferCtxt;
 use hir::def::{Def, CtorKind};
 use ty::adjustment;
@@ -343,7 +343,7 @@ impl MutabilityCategory {
 
     fn from_local(tcx: TyCtxt, tables: &ty::TypeckTables, id: ast::NodeId) -> MutabilityCategory {
         let ret = match tcx.hir.get(id) {
-            hir_map::NodeBinding(p) => match p.node {
+            Node::Binding(p) => match p.node {
                 PatKind::Binding(..) => {
                     let bm = *tables.pat_binding_modes()
                                     .get(p.hir_id)
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 0328b5f1fd5..55ee8987e8a 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -16,7 +16,7 @@
 // reachable as well.
 
 use hir::{CodegenFnAttrs, CodegenFnAttrFlags};
-use hir::map as hir_map;
+use hir::Node;
 use hir::def::Def;
 use hir::def_id::{DefId, CrateNum};
 use rustc_data_structures::sync::Lrc;
@@ -64,7 +64,7 @@ fn method_might_be_inlined<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
     if let Some(impl_node_id) = tcx.hir.as_local_node_id(impl_src) {
         match tcx.hir.find(impl_node_id) {
-            Some(hir_map::NodeItem(item)) =>
+            Some(Node::Item(item)) =>
                 item_might_be_inlined(tcx, &item, codegen_fn_attrs),
             Some(..) | None =>
                 span_bug!(impl_item.span, "impl did is not an item")
@@ -156,14 +156,14 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
         };
 
         match self.tcx.hir.find(node_id) {
-            Some(hir_map::NodeItem(item)) => {
+            Some(Node::Item(item)) => {
                 match item.node {
                     hir::ItemKind::Fn(..) =>
                         item_might_be_inlined(self.tcx, &item, self.tcx.codegen_fn_attrs(def_id)),
                     _ => false,
                 }
             }
-            Some(hir_map::NodeTraitItem(trait_method)) => {
+            Some(Node::TraitItem(trait_method)) => {
                 match trait_method.node {
                     hir::TraitItemKind::Const(_, ref default) => default.is_some(),
                     hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => true,
@@ -171,7 +171,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                     hir::TraitItemKind::Type(..) => false,
                 }
             }
-            Some(hir_map::NodeImplItem(impl_item)) => {
+            Some(Node::ImplItem(impl_item)) => {
                 match impl_item.node {
                     hir::ImplItemKind::Const(..) => true,
                     hir::ImplItemKind::Method(..) => {
@@ -219,20 +219,23 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
         }
     }
 
-    fn propagate_node(&mut self, node: &hir_map::Node<'tcx>,
+    fn propagate_node(&mut self, node: &Node<'tcx>,
                       search_item: ast::NodeId) {
         if !self.any_library {
             // If we are building an executable, only explicitly extern
             // types need to be exported.
-            if let hir_map::NodeItem(item) = *node {
+            if let Node::Item(item) = *node {
                 let reachable = if let hir::ItemKind::Fn(_, header, ..) = item.node {
                     header.abi != Abi::Rust
                 } else {
                     false
                 };
                 let def_id = self.tcx.hir.local_def_id(item.id);
-                let is_extern = self.tcx.codegen_fn_attrs(def_id).contains_extern_indicator();
-                if reachable || is_extern {
+                let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
+                let is_extern = codegen_attrs.contains_extern_indicator();
+                let std_internal = codegen_attrs.flags.contains(
+                    CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
+                if reachable || is_extern || std_internal {
                     self.reachable_symbols.insert(search_item);
                 }
             }
@@ -245,7 +248,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
         }
 
         match *node {
-            hir_map::NodeItem(item) => {
+            Node::Item(item) => {
                 match item.node {
                     hir::ItemKind::Fn(.., body) => {
                         let def_id = self.tcx.hir.local_def_id(item.id);
@@ -282,7 +285,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                     hir::ItemKind::GlobalAsm(..) => {}
                 }
             }
-            hir_map::NodeTraitItem(trait_method) => {
+            Node::TraitItem(trait_method) => {
                 match trait_method.node {
                     hir::TraitItemKind::Const(_, None) |
                     hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) => {
@@ -295,7 +298,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                     hir::TraitItemKind::Type(..) => {}
                 }
             }
-            hir_map::NodeImplItem(impl_item) => {
+            Node::ImplItem(impl_item) => {
                 match impl_item.node {
                     hir::ImplItemKind::Const(_, body) => {
                         self.visit_nested_body(body);
@@ -310,16 +313,16 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                     hir::ImplItemKind::Type(_) => {}
                 }
             }
-            hir_map::NodeExpr(&hir::Expr { node: hir::ExprKind::Closure(.., body, _, _), .. }) => {
+            Node::Expr(&hir::Expr { node: hir::ExprKind::Closure(.., body, _, _), .. }) => {
                 self.visit_nested_body(body);
             }
             // Nothing to recurse on for these
-            hir_map::NodeForeignItem(_) |
-            hir_map::NodeVariant(_) |
-            hir_map::NodeStructCtor(_) |
-            hir_map::NodeField(_) |
-            hir_map::NodeTy(_) |
-            hir_map::NodeMacroDef(_) => {}
+            Node::ForeignItem(_) |
+            Node::Variant(_) |
+            Node::StructCtor(_) |
+            Node::Field(_) |
+            Node::Ty(_) |
+            Node::MacroDef(_) => {}
             _ => {
                 bug!("found unexpected thingy in worklist: {}",
                      self.tcx.hir.node_to_string(search_item))
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index be1d93dbad1..20ee5f0b046 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -30,6 +30,7 @@ use ty::TyCtxt;
 use ty::query::Providers;
 
 use hir;
+use hir::Node;
 use hir::def_id::DefId;
 use hir::intravisit::{self, Visitor, NestedVisitorMap};
 use hir::{Block, Arm, Pat, PatKind, Stmt, Expr, Local};
@@ -257,7 +258,7 @@ impl Scope {
         }
         let span = tcx.hir.span(node_id);
         if let ScopeData::Remainder(r) = self.data() {
-            if let hir::map::NodeBlock(ref blk) = tcx.hir.get(node_id) {
+            if let Node::Block(ref blk) = tcx.hir.get(node_id) {
                 // Want span for scope starting after the
                 // indexed statement and ending at end of
                 // `blk`; reuse span of `blk` and shift `lo`
@@ -1420,8 +1421,8 @@ fn region_scope_tree<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
         // record its impl/trait parent, as it can also have
         // lifetime parameters free in this body.
         match tcx.hir.get(id) {
-            hir::map::NodeImplItem(_) |
-            hir::map::NodeTraitItem(_) => {
+            Node::ImplItem(_) |
+            Node::TraitItem(_) => {
                 visitor.scope_tree.root_parent = Some(tcx.hir.get_parent(id));
             }
             _ => {}
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 379f4df11fa..d0f801e661b 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -18,7 +18,7 @@
 use hir::def::Def;
 use hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use hir::map::Map;
-use hir::{GenericArg, GenericParam, ItemLocalId, LifetimeName, ParamName};
+use hir::{GenericArg, GenericParam, ItemLocalId, LifetimeName, ParamName, Node};
 use ty::{self, TyCtxt, GenericParamDefKind};
 
 use errors::DiagnosticBuilder;
@@ -1440,10 +1440,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
                     debug!("node id first={:?}", node_id);
                     if let Some((id, span, name)) = match self.tcx.hir.get(node_id) {
-                        hir::map::NodeLifetime(hir_lifetime) => {
+                        Node::Lifetime(hir_lifetime) => {
                             Some((hir_lifetime.id, hir_lifetime.span, hir_lifetime.name.ident()))
                         }
-                        hir::map::NodeGenericParam(param) => {
+                        Node::GenericParam(param) => {
                             Some((param.id, param.span, param.name.ident()))
                         }
                         _ => None,
@@ -1466,10 +1466,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 None => {
                     let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
                     if let Some((id, span, name)) = match self.tcx.hir.get(node_id) {
-                        hir::map::NodeLifetime(hir_lifetime) => {
+                        Node::Lifetime(hir_lifetime) => {
                             Some((hir_lifetime.id, hir_lifetime.span, hir_lifetime.name.ident()))
                         }
-                        hir::map::NodeGenericParam(param) => {
+                        Node::GenericParam(param) => {
                             Some((param.id, param.span, param.name.ident()))
                         }
                         _ => None,
@@ -1643,15 +1643,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             } else if let Some(body_id) = outermost_body {
                 let fn_id = self.tcx.hir.body_owner(body_id);
                 match self.tcx.hir.get(fn_id) {
-                    hir::map::NodeItem(&hir::Item {
+                    Node::Item(&hir::Item {
                         node: hir::ItemKind::Fn(..),
                         ..
                     })
-                    | hir::map::NodeTraitItem(&hir::TraitItem {
+                    | Node::TraitItem(&hir::TraitItem {
                         node: hir::TraitItemKind::Method(..),
                         ..
                     })
-                    | hir::map::NodeImplItem(&hir::ImplItem {
+                    | Node::ImplItem(&hir::ImplItem {
                         node: hir::ImplItemKind::Method(..),
                         ..
                     }) => {
@@ -1868,12 +1868,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         let parent = self.tcx.hir.get_parent_node(output.id);
         let body = match self.tcx.hir.get(parent) {
             // `fn` definitions and methods.
-            hir::map::NodeItem(&hir::Item {
+            Node::Item(&hir::Item {
                 node: hir::ItemKind::Fn(.., body),
                 ..
             }) => Some(body),
 
-            hir::map::NodeTraitItem(&hir::TraitItem {
+            Node::TraitItem(&hir::TraitItem {
                 node: hir::TraitItemKind::Method(_, ref m),
                 ..
             }) => {
@@ -1896,7 +1896,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 }
             }
 
-            hir::map::NodeImplItem(&hir::ImplItem {
+            Node::ImplItem(&hir::ImplItem {
                 node: hir::ImplItemKind::Method(_, body),
                 ..
             }) => {
@@ -1918,7 +1918,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             }
 
             // Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
-            hir::map::NodeForeignItem(_) | hir::map::NodeTy(_) | hir::map::NodeTraitRef(_) => None,
+            Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => None,
             // Everything else (only closures?) doesn't
             // actually enjoy elision in return types.
             _ => {
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index dc6d17d3453..ab38f8fa721 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -190,7 +190,7 @@ pub enum EvalErrorKind<'tcx, O> {
     InvalidMemoryAccess,
     InvalidFunctionPointer,
     InvalidBool,
-    InvalidDiscriminant,
+    InvalidDiscriminant(u128),
     PointerOutOfBounds {
         ptr: Pointer,
         access: bool,
@@ -302,7 +302,7 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> {
                 "tried to use a function pointer after offsetting it",
             InvalidBool =>
                 "invalid boolean value read",
-            InvalidDiscriminant =>
+            InvalidDiscriminant(..) =>
                 "invalid enum discriminant value read",
             PointerOutOfBounds { .. } =>
                 "pointer offset outside bounds of allocation",
@@ -488,6 +488,8 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
                        align {}", size.bytes(), align.abi(), size2.bytes(), align2.abi()),
             Panic { ref msg, line, col, ref file } =>
                 write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
+            InvalidDiscriminant(val) =>
+                write!(f, "encountered invalid enum discriminant {}", val),
             _ => write!(f, "{}", self.description()),
         }
     }
diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs
index 6458c211ab5..147f9ccad7c 100644
--- a/src/librustc/mir/interpret/mod.rs
+++ b/src/librustc/mir/interpret/mod.rs
@@ -393,7 +393,8 @@ impl fmt::Display for AllocId {
 pub enum AllocType<'tcx, M> {
     /// The alloc id is used as a function pointer
     Function(Instance<'tcx>),
-    /// The alloc id points to a static variable
+    /// The alloc id points to a "lazy" static variable that did not get computed (yet).
+    /// This is also used to break the cycle in recursive statics.
     Static(DefId),
     /// The alloc id points to memory
     Memory(M)
@@ -496,13 +497,14 @@ pub struct Allocation {
     pub undef_mask: UndefMask,
     /// The alignment of the allocation to detect unaligned reads.
     pub align: Align,
-    /// Whether the allocation (of a static) should be put into mutable memory when codegenning
-    ///
-    /// Only happens for `static mut` or `static` with interior mutability
-    pub runtime_mutability: Mutability,
+    /// Whether the allocation is mutable.
+    /// Also used by codegen to determine if a static should be put into mutable memory,
+    /// which happens for `static mut` and `static` with interior mutability.
+    pub mutability: Mutability,
 }
 
 impl Allocation {
+    /// Creates a read-only allocation initialized by the given bytes
     pub fn from_bytes(slice: &[u8], align: Align) -> Self {
         let mut undef_mask = UndefMask::new(Size::ZERO);
         undef_mask.grow(Size::from_bytes(slice.len() as u64), true);
@@ -511,7 +513,7 @@ impl Allocation {
             relocations: Relocations::new(),
             undef_mask,
             align,
-            runtime_mutability: Mutability::Immutable,
+            mutability: Mutability::Immutable,
         }
     }
 
@@ -526,7 +528,7 @@ impl Allocation {
             relocations: Relocations::new(),
             undef_mask: UndefMask::new(size),
             align,
-            runtime_mutability: Mutability::Immutable,
+            mutability: Mutability::Mutable,
         }
     }
 }
diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs
index 6b34e3f47cc..d793bb1cc63 100644
--- a/src/librustc/mir/interpret/value.rs
+++ b/src/librustc/mir/interpret/value.rs
@@ -14,7 +14,7 @@ use ty::layout::{HasDataLayout, Size};
 use ty::subst::Substs;
 use hir::def_id::DefId;
 
-use super::{EvalResult, Pointer, PointerArithmetic, Allocation};
+use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend};
 
 /// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which
 /// matches the LocalValue optimizations for easy conversions between Value and ConstValue.
@@ -32,8 +32,9 @@ pub enum ConstValue<'tcx> {
     ///
     /// The second field may be undef in case of `Option<usize>::None`
     ScalarPair(Scalar, ScalarMaybeUndef),
-    /// Used only for the remaining cases. An allocation + offset into the allocation
-    ByRef(&'tcx Allocation, Size),
+    /// Used only for the remaining cases. An allocation + offset into the allocation.
+    /// Invariant: The AllocId matches the allocation.
+    ByRef(AllocId, &'tcx Allocation, Size),
 }
 
 impl<'tcx> ConstValue<'tcx> {
@@ -185,6 +186,57 @@ impl<'tcx> Scalar {
             _ => err!(InvalidBool),
         }
     }
+
+    pub fn to_char(self) -> EvalResult<'tcx, char> {
+        let val = self.to_u32()?;
+        match ::std::char::from_u32(val) {
+            Some(c) => Ok(c),
+            None => err!(InvalidChar(val as u128)),
+        }
+    }
+
+    pub fn to_u8(self) -> EvalResult<'static, u8> {
+        let sz = Size::from_bits(8);
+        let b = self.to_bits(sz)?;
+        assert_eq!(b as u8 as u128, b);
+        Ok(b as u8)
+    }
+
+    pub fn to_u32(self) -> EvalResult<'static, u32> {
+        let sz = Size::from_bits(32);
+        let b = self.to_bits(sz)?;
+        assert_eq!(b as u32 as u128, b);
+        Ok(b as u32)
+    }
+
+    pub fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> {
+        let b = self.to_bits(cx.data_layout().pointer_size)?;
+        assert_eq!(b as u64 as u128, b);
+        Ok(b as u64)
+    }
+
+    pub fn to_i8(self) -> EvalResult<'static, i8> {
+        let sz = Size::from_bits(8);
+        let b = self.to_bits(sz)?;
+        let b = sign_extend(b, sz) as i128;
+        assert_eq!(b as i8 as i128, b);
+        Ok(b as i8)
+    }
+
+    pub fn to_i32(self) -> EvalResult<'static, i32> {
+        let sz = Size::from_bits(32);
+        let b = self.to_bits(sz)?;
+        let b = sign_extend(b, sz) as i128;
+        assert_eq!(b as i32 as i128, b);
+        Ok(b as i32)
+    }
+
+    pub fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> {
+        let b = self.to_bits(cx.data_layout().pointer_size)?;
+        let b = sign_extend(b, cx.data_layout().pointer_size) as i128;
+        assert_eq!(b as i64 as i128, b);
+        Ok(b as i64)
+    }
 }
 
 impl From<Pointer> for Scalar {
@@ -228,6 +280,7 @@ impl From<Scalar> for ScalarMaybeUndef {
 }
 
 impl<'tcx> ScalarMaybeUndef {
+    #[inline]
     pub fn not_undef(self) -> EvalResult<'static, Scalar> {
         match self {
             ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
@@ -235,15 +288,53 @@ impl<'tcx> ScalarMaybeUndef {
         }
     }
 
+    #[inline(always)]
     pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
         self.not_undef()?.to_ptr()
     }
 
+    #[inline(always)]
     pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
         self.not_undef()?.to_bits(target_size)
     }
 
+    #[inline(always)]
     pub fn to_bool(self) -> EvalResult<'tcx, bool> {
         self.not_undef()?.to_bool()
     }
+
+    #[inline(always)]
+    pub fn to_char(self) -> EvalResult<'tcx, char> {
+        self.not_undef()?.to_char()
+    }
+
+    #[inline(always)]
+    pub fn to_u8(self) -> EvalResult<'tcx, u8> {
+        self.not_undef()?.to_u8()
+    }
+
+    #[inline(always)]
+    pub fn to_u32(self) -> EvalResult<'tcx, u32> {
+        self.not_undef()?.to_u32()
+    }
+
+    #[inline(always)]
+    pub fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'tcx, u64> {
+        self.not_undef()?.to_usize(cx)
+    }
+
+    #[inline(always)]
+    pub fn to_i8(self) -> EvalResult<'tcx, i8> {
+        self.not_undef()?.to_i8()
+    }
+
+    #[inline(always)]
+    pub fn to_i32(self) -> EvalResult<'tcx, i32> {
+        self.not_undef()?.to_i32()
+    }
+
+    #[inline(always)]
+    pub fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'tcx, i64> {
+        self.not_undef()?.to_isize(cx)
+    }
 }
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 86e521727c5..0840f333c87 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -194,12 +194,12 @@ impl<'tcx> Mir<'tcx> {
     }
 
     #[inline]
-    pub fn predecessors(&self) -> ReadGuard<IndexVec<BasicBlock, Vec<BasicBlock>>> {
+    pub fn predecessors(&self) -> ReadGuard<'_, IndexVec<BasicBlock, Vec<BasicBlock>>> {
         self.cache.predecessors(self)
     }
 
     #[inline]
-    pub fn predecessors_for(&self, bb: BasicBlock) -> ReadGuard<Vec<BasicBlock>> {
+    pub fn predecessors_for(&self, bb: BasicBlock) -> ReadGuard<'_, Vec<BasicBlock>> {
         ReadGuard::map(self.predecessors(), |p| &p[bb])
     }
 
@@ -328,6 +328,14 @@ impl<'tcx> Mir<'tcx> {
     pub fn return_ty(&self) -> Ty<'tcx> {
         self.local_decls[RETURN_PLACE].ty
     }
+
+    /// Get the location of the terminator for the given block
+    pub fn terminator_loc(&self, bb: BasicBlock) -> Location {
+        Location {
+            block: bb,
+            statement_index: self[bb].statements.len(),
+        }
+    }
 }
 
 #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index ef81cd3a457..c8c0d4c38a2 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -649,13 +649,6 @@ impl Session {
         }
     }
 
-    pub fn target_cpu(&self) -> &str {
-        match self.opts.cg.target_cpu {
-            Some(ref s) => &**s,
-            None => &*self.target.target.options.cpu
-        }
-    }
-
     pub fn must_not_eliminate_frame_pointers(&self) -> bool {
         if let Some(x) = self.opts.cg.force_frame_pointers {
             x
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 405b320f3fe..b34378151cc 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -29,6 +29,7 @@ use super::{
 
 use errors::{Applicability, DiagnosticBuilder};
 use hir;
+use hir::Node;
 use hir::def_id::DefId;
 use infer::{self, InferCtxt};
 use infer::type_variable::TypeVariableOrigin;
@@ -864,7 +865,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                        err: &mut DiagnosticBuilder<'tcx>) {
         if let &ObligationCauseCode::VariableType(node_id) = code {
             let parent_node = self.tcx.hir.get_parent_node(node_id);
-            if let Some(hir::map::NodeLocal(ref local)) = self.tcx.hir.find(parent_node) {
+            if let Some(Node::Local(ref local)) = self.tcx.hir.find(parent_node) {
                 if let Some(ref expr) = local.init {
                     if let hir::ExprKind::Index(_, _) = expr.node {
                         if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
@@ -932,9 +933,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// returns a span and `ArgKind` information that describes the
     /// arguments it expects. This can be supplied to
     /// `report_arg_count_mismatch`.
-    pub fn get_fn_like_arguments(&self, node: hir::map::Node) -> (Span, Vec<ArgKind>) {
+    pub fn get_fn_like_arguments(&self, node: Node) -> (Span, Vec<ArgKind>) {
         match node {
-            hir::map::NodeExpr(&hir::Expr {
+            Node::Expr(&hir::Expr {
                 node: hir::ExprKind::Closure(_, ref _decl, id, span, _),
                 ..
             }) => {
@@ -961,17 +962,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     })
                     .collect::<Vec<ArgKind>>())
             }
-            hir::map::NodeItem(&hir::Item {
+            Node::Item(&hir::Item {
                 span,
                 node: hir::ItemKind::Fn(ref decl, ..),
                 ..
             }) |
-            hir::map::NodeImplItem(&hir::ImplItem {
+            Node::ImplItem(&hir::ImplItem {
                 span,
                 node: hir::ImplItemKind::Method(hir::MethodSig { ref decl, .. }, _),
                 ..
             }) |
-            hir::map::NodeTraitItem(&hir::TraitItem {
+            Node::TraitItem(&hir::TraitItem {
                 span,
                 node: hir::TraitItemKind::Method(hir::MethodSig { ref decl, .. }, _),
                 ..
@@ -987,7 +988,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     _ => ArgKind::Arg("_".to_owned(), "_".to_owned())
                 }).collect::<Vec<ArgKind>>())
             }
-            hir::map::NodeVariant(&hir::Variant {
+            Node::Variant(&hir::Variant {
                 span,
                 node: hir::VariantKind {
                     data: hir::VariantData::Tuple(ref fields, _),
@@ -1000,7 +1001,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                      ArgKind::Arg(field.ident.to_string(), "_".to_string())
                  }).collect::<Vec<_>>())
             }
-            hir::map::NodeStructCtor(ref variant_data) => {
+            Node::StructCtor(ref variant_data) => {
                 (self.tcx.sess.source_map().def_span(self.tcx.hir.span(variant_data.id())),
                  variant_data.fields()
                     .iter().map(|_| ArgKind::Arg("_".to_owned(), "_".to_owned()))
diff --git a/src/librustc/traits/query/type_op/custom.rs b/src/librustc/traits/query/type_op/custom.rs
index 737388ad411..6a5ef75a660 100644
--- a/src/librustc/traits/query/type_op/custom.rs
+++ b/src/librustc/traits/query/type_op/custom.rs
@@ -102,8 +102,14 @@ fn scrape_region_constraints<'gcx, 'tcx, R>(
 
     let region_constraint_data = infcx.take_and_reset_region_constraints();
 
-    let outlives =
-        query_result::make_query_outlives(infcx.tcx, region_obligations, &region_constraint_data);
+    let outlives = query_result::make_query_outlives(
+        infcx.tcx,
+        region_obligations
+            .iter()
+            .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region))
+            .map(|(ty, r)| (infcx.resolve_type_vars_if_possible(&ty), r)),
+        &region_constraint_data,
+    );
 
     if outlives.is_empty() {
         Ok((value, None))
diff --git a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
new file mode 100644
index 00000000000..27534bc8c3c
--- /dev/null
+++ b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
@@ -0,0 +1,80 @@
+// 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.
+
+use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult};
+use traits::query::outlives_bounds::OutlivesBound;
+use traits::query::Fallible;
+use ty::{ParamEnvAnd, Ty, TyCtxt};
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct ImpliedOutlivesBounds<'tcx> {
+    pub ty: Ty<'tcx>,
+}
+
+impl<'tcx> ImpliedOutlivesBounds<'tcx> {
+    pub fn new(ty: Ty<'tcx>) -> Self {
+        ImpliedOutlivesBounds { ty }
+    }
+}
+
+impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for ImpliedOutlivesBounds<'tcx> {
+    type QueryResult = Vec<OutlivesBound<'tcx>>;
+
+    fn try_fast_path(
+        _tcx: TyCtxt<'_, 'gcx, 'tcx>,
+        _key: &ParamEnvAnd<'tcx, Self>,
+    ) -> Option<Self::QueryResult> {
+        None
+    }
+
+    fn perform_query(
+        tcx: TyCtxt<'_, 'gcx, 'tcx>,
+        canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>,
+    ) -> Fallible<CanonicalizedQueryResult<'gcx, Self::QueryResult>> {
+        // FIXME the query should take a `ImpliedOutlivesBounds`
+        let Canonical {
+            variables,
+            value:
+                ParamEnvAnd {
+                    param_env,
+                    value: ImpliedOutlivesBounds { ty },
+                },
+        } = canonicalized;
+        let canonicalized = Canonical {
+            variables,
+            value: param_env.and(ty),
+        };
+
+        tcx.implied_outlives_bounds(canonicalized)
+    }
+
+    fn shrink_to_tcx_lifetime(
+        v: &'a CanonicalizedQueryResult<'gcx, Self::QueryResult>,
+    ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self::QueryResult>> {
+        v
+    }
+}
+
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for ImpliedOutlivesBounds<'tcx> {
+        ty,
+    }
+}
+
+BraceStructLiftImpl! {
+    impl<'a, 'tcx> Lift<'tcx> for ImpliedOutlivesBounds<'a> {
+        type Lifted = ImpliedOutlivesBounds<'tcx>;
+        ty,
+    }
+}
+
+impl_stable_hash_for! {
+    struct ImpliedOutlivesBounds<'tcx> { ty }
+}
diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc/traits/query/type_op/mod.rs
index 3b16dab22f2..8e4236d1754 100644
--- a/src/librustc/traits/query/type_op/mod.rs
+++ b/src/librustc/traits/query/type_op/mod.rs
@@ -21,6 +21,7 @@ use ty::{Lift, ParamEnvAnd, TyCtxt};
 
 pub mod custom;
 pub mod eq;
+pub mod implied_outlives_bounds;
 pub mod normalize;
 pub mod outlives;
 pub mod prove_predicate;
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index 87535a6ae8d..10e930d1c92 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use chalk_engine;
-use rustc_data_structures::accumulate_vec::AccumulateVec;
+use smallvec::SmallVec;
 use traits;
 use traits::project::Normalized;
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
@@ -624,7 +624,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<traits::Goal<'tcx>> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         let v = self.iter()
             .map(|t| t.fold_with(folder))
-            .collect::<AccumulateVec<[_; 8]>>();
+            .collect::<SmallVec<[_; 8]>>();
         folder.tcx().intern_goals(&v)
     }
 
@@ -662,7 +662,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<traits::Clause<'tcx>> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         let v = self.iter()
             .map(|t| t.fold_with(folder))
-            .collect::<AccumulateVec<[_; 8]>>();
+            .collect::<SmallVec<[_; 8]>>();
         folder.tcx().intern_clauses(&v)
     }
 
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 424139e7527..de50598c42c 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -52,7 +52,7 @@ use ty::BindingMode;
 use ty::CanonicalTy;
 use util::nodemap::{DefIdSet, ItemLocalMap};
 use util::nodemap::{FxHashMap, FxHashSet};
-use rustc_data_structures::accumulate_vec::AccumulateVec;
+use smallvec::SmallVec;
 use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
                                            StableHasher, StableHasherResult,
                                            StableVec};
@@ -1043,13 +1043,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
 
         let interned = self.global_arenas.const_allocs.alloc(alloc);
-        if let Some(prev) = allocs.replace(interned) {
+        if let Some(prev) = allocs.replace(interned) { // insert into interner
             bug!("Tried to overwrite interned Allocation: {:#?}", prev)
         }
         interned
     }
 
-    /// Allocates a byte or string literal for `mir::interpret`
+    /// Allocates a byte or string literal for `mir::interpret`, read-only
     pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId {
         // create an allocation that just contains these bytes
         let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes);
@@ -2840,7 +2840,7 @@ pub trait InternIteratorElement<T, R>: Sized {
 impl<T, R> InternIteratorElement<T, R> for T {
     type Output = R;
     fn intern_with<I: Iterator<Item=Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output {
-        f(&iter.collect::<AccumulateVec<[_; 8]>>())
+        f(&iter.collect::<SmallVec<[_; 8]>>())
     }
 }
 
@@ -2849,14 +2849,14 @@ impl<'a, T, R> InternIteratorElement<T, R> for &'a T
 {
     type Output = R;
     fn intern_with<I: Iterator<Item=Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output {
-        f(&iter.cloned().collect::<AccumulateVec<[_; 8]>>())
+        f(&iter.cloned().collect::<SmallVec<[_; 8]>>())
     }
 }
 
 impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> {
     type Output = Result<R, E>;
     fn intern_with<I: Iterator<Item=Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output {
-        Ok(f(&iter.collect::<Result<AccumulateVec<[_; 8]>, _>>()?))
+        Ok(f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?))
     }
 }
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 77b4d32c397..63308ac46d1 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -15,6 +15,7 @@ pub use self::IntVarValue::*;
 pub use self::fold::TypeFoldable;
 
 use hir::{map as hir_map, FreevarMap, TraitMap};
+use hir::Node;
 use hir::def::{Def, CtorKind, ExportMap};
 use hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use hir::map::DefPathData;
@@ -2478,7 +2479,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     pub fn expr_span(self, id: NodeId) -> Span {
         match self.hir.find(id) {
-            Some(hir_map::NodeExpr(e)) => {
+            Some(Node::Expr(e)) => {
                 e.span
             }
             Some(f) => {
@@ -2505,7 +2506,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn opt_associated_item(self, def_id: DefId) -> Option<AssociatedItem> {
         let is_associated_item = if let Some(node_id) = self.hir.as_local_node_id(def_id) {
             match self.hir.get(node_id) {
-                hir_map::NodeTraitItem(_) | hir_map::NodeImplItem(_) => true,
+                Node::TraitItem(_) | Node::ImplItem(_) => true,
                 _ => false,
             }
         } else {
@@ -2895,7 +2896,7 @@ fn trait_of_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option
 /// Yields the parent function's `DefId` if `def_id` is an `impl Trait` definition
 pub fn is_impl_trait_defn(tcx: TyCtxt, def_id: DefId) -> Option<DefId> {
     if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
-        if let hir::map::NodeItem(item) = tcx.hir.get(node_id) {
+        if let Node::Item(item) = tcx.hir.get(node_id) {
             if let hir::ItemKind::Existential(ref exist_ty) = item.node {
                 return exist_ty.impl_trait_fn;
             }
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index e6c10358279..e3ef74f44db 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -16,8 +16,8 @@
 use mir::interpret::{ConstValue, ConstEvalErr};
 use ty::{self, Lift, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
-use rustc_data_structures::accumulate_vec::AccumulateVec;
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use smallvec::SmallVec;
 use mir::interpret;
 
 use std::rc::Rc;
@@ -498,7 +498,7 @@ impl<'a, 'tcx, O: Lift<'tcx>> Lift<'tcx> for interpret::EvalErrorKind<'a, O> {
             InvalidMemoryAccess => InvalidMemoryAccess,
             InvalidFunctionPointer => InvalidFunctionPointer,
             InvalidBool => InvalidBool,
-            InvalidDiscriminant => InvalidDiscriminant,
+            InvalidDiscriminant(val) => InvalidDiscriminant(val),
             PointerOutOfBounds {
                 ptr,
                 access,
@@ -741,7 +741,7 @@ BraceStructTypeFoldableImpl! {
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        let v = self.iter().map(|p| p.fold_with(folder)).collect::<AccumulateVec<[_; 8]>>();
+        let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
         folder.tcx().intern_existential_predicates(&v)
     }
 
@@ -760,7 +760,7 @@ EnumTypeFoldableImpl! {
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        let v = self.iter().map(|t| t.fold_with(folder)).collect::<AccumulateVec<[_; 8]>>();
+        let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
         folder.tcx().intern_type_list(&v)
     }
 
@@ -1016,7 +1016,7 @@ BraceStructTypeFoldableImpl! {
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        let v = self.iter().map(|p| p.fold_with(folder)).collect::<AccumulateVec<[_; 8]>>();
+        let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
         folder.tcx().intern_predicates(&v)
     }
 
@@ -1139,7 +1139,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
         match *self {
             ConstValue::Scalar(v) => ConstValue::Scalar(v),
             ConstValue::ScalarPair(a, b) => ConstValue::ScalarPair(a, b),
-            ConstValue::ByRef(alloc, offset) => ConstValue::ByRef(alloc, offset),
+            ConstValue::ByRef(id, alloc, offset) => ConstValue::ByRef(id, alloc, offset),
             ConstValue::Unevaluated(def_id, substs) => {
                 ConstValue::Unevaluated(def_id, substs.fold_with(folder))
             }
@@ -1150,7 +1150,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
         match *self {
             ConstValue::Scalar(_) |
             ConstValue::ScalarPair(_, _) |
-            ConstValue::ByRef(_, _) => false,
+            ConstValue::ByRef(_, _, _) => false,
             ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor),
         }
     }
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index 6dadc507036..b6ffcd55d91 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -17,9 +17,8 @@ use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 
 use serialize::{self, Encodable, Encoder, Decodable, Decoder};
 use syntax_pos::{Span, DUMMY_SP};
-use rustc_data_structures::accumulate_vec::AccumulateVec;
-use rustc_data_structures::array_vec::ArrayVec;
 use rustc_data_structures::indexed_vec::Idx;
+use smallvec::SmallVec;
 
 use core::intrinsics;
 use std::cmp::Ordering;
@@ -203,11 +202,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
     {
         let defs = tcx.generics_of(def_id);
         let count = defs.count();
-        let mut substs = if count <= 8 {
-            AccumulateVec::Array(ArrayVec::new())
-        } else {
-            AccumulateVec::Heap(Vec::with_capacity(count))
-        };
+        let mut substs = SmallVec::with_capacity(count);
         Substs::fill_item(&mut substs, tcx, defs, &mut mk_kind);
         tcx.intern_substs(&substs)
     }
@@ -227,7 +222,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
         })
     }
 
-    fn fill_item<F>(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>,
+    fn fill_item<F>(substs: &mut SmallVec<[Kind<'tcx>; 8]>,
                     tcx: TyCtxt<'a, 'gcx, 'tcx>,
                     defs: &ty::Generics,
                     mk_kind: &mut F)
@@ -240,7 +235,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
         Substs::fill_single(substs, defs, mk_kind)
     }
 
-    fn fill_single<F>(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>,
+    fn fill_single<F>(substs: &mut SmallVec<[Kind<'tcx>; 8]>,
                       defs: &ty::Generics,
                       mk_kind: &mut F)
     where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx>
@@ -248,10 +243,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
         for param in &defs.params {
             let kind = mk_kind(param, substs);
             assert_eq!(param.index as usize, substs.len());
-            match *substs {
-                AccumulateVec::Array(ref mut arr) => arr.push(kind),
-                AccumulateVec::Heap(ref mut vec) => vec.push(kind),
-            }
+            substs.push(kind);
         }
     }
 
@@ -325,7 +317,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        let params: AccumulateVec<[_; 8]> = self.iter().map(|k| k.fold_with(folder)).collect();
+        let params: SmallVec<[_; 8]> = self.iter().map(|k| k.fold_with(folder)).collect();
 
         // If folding doesn't change the substs, it's faster to avoid
         // calling `mk_substs` and instead reuse the existing substs.
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 938cdf3048b..f7679dc8ce0 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -12,8 +12,8 @@
 
 use hir::def::Def;
 use hir::def_id::DefId;
-use hir::map::{DefPathData, Node};
-use hir;
+use hir::map::DefPathData;
+use hir::{self, Node};
 use ich::NodeIdHashingMode;
 use traits::{self, ObligationCause};
 use ty::{self, Ty, TyCtxt, GenericParamDefKind, TypeFoldable};
@@ -604,10 +604,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn is_static(&self, def_id: DefId) -> Option<hir::Mutability> {
         if let Some(node) = self.hir.get_if_local(def_id) {
             match node {
-                Node::NodeItem(&hir::Item {
+                Node::Item(&hir::Item {
                     node: hir::ItemKind::Static(_, mutbl, _), ..
                 }) => Some(mutbl),
-                Node::NodeForeignItem(&hir::ForeignItem {
+                Node::ForeignItem(&hir::ForeignItem {
                     node: hir::ForeignItemKind::Static(_, is_mutbl), ..
                 }) =>
                     Some(if is_mutbl {
diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs
index 5999416cecf..11e8c30760b 100644
--- a/src/librustc_allocator/expand.rs
+++ b/src/librustc_allocator/expand.rs
@@ -236,15 +236,9 @@ impl<'a> AllocFnFactory<'a> {
     }
 
     fn attrs(&self) -> Vec<Attribute> {
-        let no_mangle = Symbol::intern("no_mangle");
-        let no_mangle = self.cx.meta_word(self.span, no_mangle);
-
         let special = Symbol::intern("rustc_std_internal_symbol");
         let special = self.cx.meta_word(self.span, special);
-        vec![
-            self.cx.attribute(self.span, no_mangle),
-            self.cx.attribute(self.span, special),
-        ]
+        vec![self.cx.attribute(self.span, special)]
     }
 
     fn arg_ty(
diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs
index 2a3404ee830..44fbcade6bc 100644
--- a/src/librustc_allocator/lib.rs
+++ b/src/librustc_allocator/lib.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(rustc_private)]
 
 #[macro_use] extern crate log;
diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs
index d6e821d427d..c3c32ba7d5b 100644
--- a/src/librustc_apfloat/lib.rs
+++ b/src/librustc_apfloat/lib.rs
@@ -46,6 +46,7 @@
 #![forbid(unsafe_code)]
 
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(try_from)]
 // See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
 #[allow(unused_extern_crates)]
diff --git a/src/librustc_asan/lib.rs b/src/librustc_asan/lib.rs
index b3ba86ad8a4..ed8fd305977 100644
--- a/src/librustc_asan/lib.rs
+++ b/src/librustc_asan/lib.rs
@@ -11,6 +11,7 @@
 #![sanitizer_runtime]
 #![feature(alloc_system)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(sanitizer_runtime)]
 #![feature(staged_api)]
 #![no_std]
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index 847d37be899..1af117c97f5 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -16,6 +16,7 @@
 // 2. loans made in overlapping scopes do not conflict
 // 3. assignments do not affect things loaned out as immutable
 // 4. moves do not affect things loaned out in any way
+
 use self::UseError::*;
 
 use borrowck::*;
@@ -29,6 +30,7 @@ use rustc::ty::{self, TyCtxt, RegionKind};
 use syntax::ast;
 use syntax_pos::Span;
 use rustc::hir;
+use rustc::hir::Node;
 use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
 
 use std::rc::Rc;
@@ -201,7 +203,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
 
     let node_id = bccx.tcx.hir.as_local_node_id(def_id).unwrap();
     let movable_generator = !match bccx.tcx.hir.get(node_id) {
-        hir::map::Node::NodeExpr(&hir::Expr {
+        Node::Expr(&hir::Expr {
             node: hir::ExprKind::Closure(.., Some(hir::GeneratorMovability::Static)),
             ..
         }) => true,
diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
index 5c165fbad69..ffc4fbfb4c9 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
@@ -24,7 +24,7 @@ use std::rc::Rc;
 use syntax::ast;
 use syntax_pos::Span;
 use rustc::hir::*;
-use rustc::hir::map::Node::*;
+use rustc::hir::Node;
 
 struct GatherMoveInfo<'c, 'tcx: 'c> {
     id: hir::ItemLocalId,
@@ -60,7 +60,7 @@ fn get_pattern_source<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &Pat) -> Patte
     let parent = tcx.hir.get_parent_node(pat.id);
 
     match tcx.hir.get(parent) {
-        NodeExpr(ref e) => {
+        Node::Expr(ref e) => {
             // the enclosing expression must be a `match` or something else
             assert!(match e.node {
                         ExprKind::Match(..) => true,
@@ -68,7 +68,7 @@ fn get_pattern_source<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &Pat) -> Patte
                     });
             PatternSource::MatchExpr(e)
         }
-        NodeLocal(local) => PatternSource::LetDecl(local),
+        Node::Local(local) => PatternSource::LetDecl(local),
         _ => return PatternSource::Other,
 
     }
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index a3ca329b92d..ad45c5429a5 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -21,7 +21,7 @@ pub use self::MovedValueUseKind::*;
 use self::InteriorKind::*;
 
 use rustc::hir::HirId;
-use rustc::hir::map as hir_map;
+use rustc::hir::Node;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::cfg;
 use rustc::middle::borrowck::{BorrowCheckResult, SignalledError};
@@ -95,8 +95,8 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId)
     let owner_id = tcx.hir.as_local_node_id(owner_def_id).unwrap();
 
     match tcx.hir.get(owner_id) {
-        hir_map::NodeStructCtor(_) |
-        hir_map::NodeVariant(_) => {
+        Node::StructCtor(_) |
+        Node::Variant(_) => {
             // We get invoked with anything that has MIR, but some of
             // those things (notably the synthesized constructors from
             // tuple structs/variants) do not have an associated body
@@ -419,7 +419,7 @@ fn closure_to_block(closure_id: LocalDefId,
                     tcx: TyCtxt) -> ast::NodeId {
     let closure_id = tcx.hir.local_def_id_to_node_id(closure_id);
     match tcx.hir.get(closure_id) {
-        hir_map::NodeExpr(expr) => match expr.node {
+        Node::Expr(expr) => match expr.node {
             hir::ExprKind::Closure(.., body_id, _, _) => {
                 body_id.node_id
             }
@@ -908,7 +908,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                     let node =  self.tcx.hir.get(node_id);
 
                     // This pattern probably always matches.
-                    if let hir_map::NodeExpr(
+                    if let Node::Expr(
                         hir::Expr { node: hir::ExprKind::Index(lhs, _), ..}
                     ) = node {
                         let ty = self.tables.expr_ty(lhs);
@@ -1032,7 +1032,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                 if let ty::ReScope(scope) = *super_scope {
                     let node_id = scope.node_id(self.tcx, &self.region_scope_tree);
                     match self.tcx.hir.find(node_id) {
-                        Some(hir_map::NodeStmt(_)) => {
+                        Some(Node::Stmt(_)) => {
                             if *sub_scope != ty::ReStatic {
                                 db.note("consider using a `let` binding to increase its lifetime");
                             }
@@ -1183,7 +1183,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
 
     fn local_binding_mode(&self, node_id: ast::NodeId) -> ty::BindingMode {
         let pat = match self.tcx.hir.get(node_id) {
-            hir_map::Node::NodeBinding(pat) => pat,
+            Node::Binding(pat) => pat,
             node => bug!("bad node for local: {:?}", node)
         };
 
@@ -1259,7 +1259,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                     None => return
                 };
 
-                if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(node_id) {
+                if let Node::Field(ref field) = self.tcx.hir.get(node_id) {
                     if let Some(msg) = self.suggest_mut_for_immutable(&field.ty, false) {
                         db.span_label(field.ty.span, msg);
                     }
diff --git a/src/librustc_borrowck/dataflow.rs b/src/librustc_borrowck/dataflow.rs
index 640c23ebf9d..832b69cb2ac 100644
--- a/src/librustc_borrowck/dataflow.rs
+++ b/src/librustc_borrowck/dataflow.rs
@@ -117,12 +117,12 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O
            ps: &mut pprust::State,
            node: pprust::AnnNode) -> io::Result<()> {
         let id = match node {
-            pprust::NodeName(_) => return Ok(()),
-            pprust::NodeExpr(expr) => expr.hir_id.local_id,
-            pprust::NodeBlock(blk) => blk.hir_id.local_id,
-            pprust::NodeItem(_) |
-            pprust::NodeSubItem(_) => return Ok(()),
-            pprust::NodePat(pat) => pat.hir_id.local_id
+            pprust::AnnNode::Name(_) => return Ok(()),
+            pprust::AnnNode::Expr(expr) => expr.hir_id.local_id,
+            pprust::AnnNode::Block(blk) => blk.hir_id.local_id,
+            pprust::AnnNode::Item(_) |
+            pprust::AnnNode::SubItem(_) => return Ok(()),
+            pprust::AnnNode::Pat(pat) => pat.hir_id.local_id
         };
 
         if !self.has_bitset_for_local_id(id) {
diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs
index 16da8c8a3b8..edd837e9401 100644
--- a/src/librustc_borrowck/lib.rs
+++ b/src/librustc_borrowck/lib.rs
@@ -15,6 +15,7 @@
 #![allow(non_camel_case_types)]
 
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(quote)]
 
 #![recursion_limit="256"]
diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs
index 2b64642b766..c8a2b47e98d 100644
--- a/src/librustc_codegen_llvm/attributes.rs
+++ b/src/librustc_codegen_llvm/attributes.rs
@@ -124,7 +124,8 @@ pub fn llvm_target_features(sess: &Session) -> impl Iterator<Item = &str> {
 }
 
 pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
-    let target_cpu = CString::new(cx.tcx.sess.target_cpu().to_string()).unwrap();
+    let cpu = llvm_util::target_cpu(cx.tcx.sess);
+    let target_cpu = CString::new(cpu).unwrap();
     llvm::AddFunctionAttrStringValue(
             llfn,
             llvm::AttributePlace::Function,
diff --git a/src/librustc_codegen_llvm/back/linker.rs b/src/librustc_codegen_llvm/back/linker.rs
index a429e8f2d81..eee60b262a1 100644
--- a/src/librustc_codegen_llvm/back/linker.rs
+++ b/src/librustc_codegen_llvm/back/linker.rs
@@ -26,6 +26,7 @@ use rustc::session::config::{self, CrateType, OptLevel, DebugInfo,
 use rustc::ty::TyCtxt;
 use rustc_target::spec::{LinkerFlavor, LldFlavor};
 use serialize::{json, Encoder};
+use llvm_util;
 
 /// For all the linkers we support, and information they might
 /// need out of the shared crate context before we get rid of it.
@@ -202,7 +203,7 @@ impl<'a> GccLinker<'a> {
         };
 
         self.linker_arg(&format!("-plugin-opt={}", opt_level));
-        self.linker_arg(&format!("-plugin-opt=mcpu={}", self.sess.target_cpu()));
+        self.linker_arg(&format!("-plugin-opt=mcpu={}", llvm_util::target_cpu(self.sess)));
 
         match self.sess.opts.cg.lto {
             config::Lto::Thin |
diff --git a/src/librustc_codegen_llvm/back/symbol_export.rs b/src/librustc_codegen_llvm/back/symbol_export.rs
index edb1da0b558..6b1b0b94fd9 100644
--- a/src/librustc_codegen_llvm/back/symbol_export.rs
+++ b/src/librustc_codegen_llvm/back/symbol_export.rs
@@ -13,6 +13,7 @@ use std::sync::Arc;
 
 use monomorphize::Instance;
 use rustc::hir;
+use rustc::hir::Node;
 use rustc::hir::CodegenFnAttrFlags;
 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX};
 use rustc_data_structures::fingerprint::Fingerprint;
@@ -94,7 +95,7 @@ fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             // As a result, if this id is an FFI item (foreign item) then we only
             // let it through if it's included statically.
             match tcx.hir.get(node_id) {
-                hir::map::NodeForeignItem(..) => {
+                Node::ForeignItem(..) => {
                     let def_id = tcx.hir.local_def_id(node_id);
                     if tcx.is_statically_included_foreign_item(def_id) {
                         Some(def_id)
@@ -104,14 +105,14 @@ fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 }
 
                 // Only consider nodes that actually have exported symbols.
-                hir::map::NodeItem(&hir::Item {
+                Node::Item(&hir::Item {
                     node: hir::ItemKind::Static(..),
                     ..
                 }) |
-                hir::map::NodeItem(&hir::Item {
+                Node::Item(&hir::Item {
                     node: hir::ItemKind::Fn(..), ..
                 }) |
-                hir::map::NodeImplItem(&hir::ImplItem {
+                Node::ImplItem(&hir::ImplItem {
                     node: hir::ImplItemKind::Method(..),
                     ..
                 }) => {
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index 80e9965e39c..2373428d68c 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -25,6 +25,7 @@ use rustc::session::Session;
 use rustc::util::nodemap::FxHashMap;
 use time_graph::{self, TimeGraph, Timeline};
 use llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic};
+use llvm_util;
 use {CodegenResults, ModuleSource, ModuleCodegen, CompiledModule, ModuleKind};
 use CrateInfo;
 use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
@@ -173,7 +174,7 @@ pub fn target_machine_factory(sess: &Session, find_features: bool)
     let singlethread = sess.target.target.options.singlethread;
 
     let triple = SmallCStr::new(&sess.target.target.llvm_target);
-    let cpu = SmallCStr::new(sess.target_cpu());
+    let cpu = SmallCStr::new(llvm_util::target_cpu(sess));
     let features = attributes::llvm_target_features(sess)
         .collect::<Vec<_>>()
         .join(",");
diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs
index 6f09ebb3826..522de2f15e0 100644
--- a/src/librustc_codegen_llvm/consts.rs
+++ b/src/librustc_codegen_llvm/consts.rs
@@ -11,7 +11,7 @@
 use libc::c_uint;
 use llvm::{self, SetUnnamedAddr, True};
 use rustc::hir::def_id::DefId;
-use rustc::hir::map as hir_map;
+use rustc::hir::Node;
 use debuginfo;
 use base;
 use monomorphize::MonoItem;
@@ -135,7 +135,7 @@ pub fn get_static(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll Value {
 
         let llty = cx.layout_of(ty).llvm_type(cx);
         let (g, attrs) = match cx.tcx.hir.get(id) {
-            hir_map::NodeItem(&hir::Item {
+            Node::Item(&hir::Item {
                 ref attrs, span, node: hir::ItemKind::Static(..), ..
             }) => {
                 if declare::get_declared_value(cx, &sym[..]).is_some() {
@@ -153,7 +153,7 @@ pub fn get_static(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll Value {
                 (g, attrs)
             }
 
-            hir_map::NodeForeignItem(&hir::ForeignItem {
+            Node::ForeignItem(&hir::ForeignItem {
                 ref attrs, span, node: hir::ForeignItemKind::Static(..), ..
             }) => {
                 let fn_attrs = cx.tcx.codegen_fn_attrs(def_id);
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index 03a2e0a82cf..31eeb5633fb 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -27,6 +27,7 @@
 #![allow(unused_attributes)]
 #![feature(libc)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(quote)]
 #![feature(range_contains)]
 #![feature(rustc_diagnostic_macros)]
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index d3039a05b6d..51b0299e63f 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -1449,6 +1449,7 @@ extern "C" {
     pub fn LLVMRustPrintTargetCPUs(T: &TargetMachine);
     pub fn LLVMRustPrintTargetFeatures(T: &TargetMachine);
 
+    pub fn LLVMRustGetHostCPUName(len: *mut usize) -> *const c_char;
     pub fn LLVMRustCreateTargetMachine(Triple: *const c_char,
                                        CPU: *const c_char,
                                        Features: *const c_char,
diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs
index ff26e0f35f0..9fcc33d82cf 100644
--- a/src/librustc_codegen_llvm/llvm_util.rs
+++ b/src/librustc_codegen_llvm/llvm_util.rs
@@ -17,6 +17,8 @@ use libc::c_int;
 use std::ffi::CString;
 use syntax::feature_gate::UnstableFeatures;
 
+use std::str;
+use std::slice;
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::Once;
 
@@ -262,3 +264,19 @@ pub(crate) fn print(req: PrintRequest, sess: &Session) {
         }
     }
 }
+
+pub fn target_cpu(sess: &Session) -> &str {
+    let name = match sess.opts.cg.target_cpu {
+        Some(ref s) => &**s,
+        None => &*sess.target.target.options.cpu
+    };
+    if name != "native" {
+        return name
+    }
+
+    unsafe {
+        let mut len = 0;
+        let ptr = llvm::LLVMRustGetHostCPUName(&mut len);
+        str::from_utf8(slice::from_raw_parts(ptr as *const u8, len)).unwrap()
+    }
+}
diff --git a/src/librustc_codegen_llvm/mir/constant.rs b/src/librustc_codegen_llvm/mir/constant.rs
index 2657543b2d1..b6c9658dd6f 100644
--- a/src/librustc_codegen_llvm/mir/constant.rs
+++ b/src/librustc_codegen_llvm/mir/constant.rs
@@ -57,7 +57,7 @@ pub fn scalar_to_llvm(
             let base_addr = match alloc_type {
                 Some(AllocType::Memory(alloc)) => {
                     let init = const_alloc_to_llvm(cx, alloc);
-                    if alloc.runtime_mutability == Mutability::Mutable {
+                    if alloc.mutability == Mutability::Mutable {
                         consts::addr_of_mut(cx, init, alloc.align, None)
                     } else {
                         consts::addr_of(cx, init, alloc.align, None)
@@ -134,7 +134,7 @@ pub fn codegen_static_initializer(
     let static_ = cx.tcx.const_eval(param_env.and(cid))?;
 
     let alloc = match static_.val {
-        ConstValue::ByRef(alloc, n) if n.bytes() == 0 => alloc,
+        ConstValue::ByRef(_, alloc, n) if n.bytes() == 0 => alloc,
         _ => bug!("static const eval returned {:#?}", static_),
     };
     Ok((const_alloc_to_llvm(cx, alloc), alloc))
diff --git a/src/librustc_codegen_llvm/mir/operand.rs b/src/librustc_codegen_llvm/mir/operand.rs
index 9537379813d..419e7298588 100644
--- a/src/librustc_codegen_llvm/mir/operand.rs
+++ b/src/librustc_codegen_llvm/mir/operand.rs
@@ -126,7 +126,7 @@ impl OperandRef<'ll, 'tcx> {
                 };
                 OperandValue::Pair(a_llval, b_llval)
             },
-            ConstValue::ByRef(alloc, offset) => {
+            ConstValue::ByRef(_, alloc, offset) => {
                 return Ok(PlaceRef::from_const_alloc(bx, layout, alloc, offset).load(bx));
             },
         };
diff --git a/src/librustc_codegen_llvm/mir/place.rs b/src/librustc_codegen_llvm/mir/place.rs
index ce3292eaa42..833dca8c75f 100644
--- a/src/librustc_codegen_llvm/mir/place.rs
+++ b/src/librustc_codegen_llvm/mir/place.rs
@@ -458,7 +458,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
                 let layout = cx.layout_of(self.monomorphize(&ty));
                 match bx.tcx().const_eval(param_env.and(cid)) {
                     Ok(val) => match val.val {
-                        mir::interpret::ConstValue::ByRef(alloc, offset) => {
+                        mir::interpret::ConstValue::ByRef(_, alloc, offset) => {
                             PlaceRef::from_const_alloc(bx, layout, alloc, offset)
                         }
                         _ => bug!("promoteds should have an allocation: {:?}", val),
diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs
index 635819e94e8..45db22ec6da 100644
--- a/src/librustc_codegen_utils/lib.rs
+++ b/src/librustc_codegen_utils/lib.rs
@@ -20,6 +20,7 @@
 #![feature(box_syntax)]
 #![feature(custom_attribute)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![allow(unused_attributes)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs
index 33ce06217a4..39b88b225ed 100644
--- a/src/librustc_codegen_utils/symbol_names.rs
+++ b/src/librustc_codegen_utils/symbol_names.rs
@@ -98,10 +98,10 @@
 //! DefPaths which are much more robust in the face of changes to the code base.
 
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
-use rustc::hir::map as hir_map;
+use rustc::hir::Node;
+use rustc::hir::CodegenFnAttrFlags;
 use rustc::hir::map::definitions::DefPathData;
 use rustc::ich::NodeIdHashingMode;
-use rustc::middle::weak_lang_items;
 use rustc::ty::item_path::{self, ItemPathBuffer, RootMode};
 use rustc::ty::query::Providers;
 use rustc::ty::subst::Substs;
@@ -111,7 +111,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_mir::monomorphize::item::{InstantiationMode, MonoItem, MonoItemExt};
 use rustc_mir::monomorphize::Instance;
 
-use syntax::attr;
 use syntax_pos::symbol::Symbol;
 
 use std::fmt::Write;
@@ -260,34 +259,30 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance
     }
 
     // FIXME(eddyb) Precompute a custom symbol name based on attributes.
-    let attrs = tcx.get_attrs(def_id);
     let is_foreign = if let Some(id) = node_id {
         match tcx.hir.get(id) {
-            hir_map::NodeForeignItem(_) => true,
+            Node::ForeignItem(_) => true,
             _ => false,
         }
     } else {
         tcx.is_foreign_item(def_id)
     };
 
-    if let Some(name) = weak_lang_items::link_name(&attrs) {
-        return name.to_string();
-    }
-
+    let attrs = tcx.codegen_fn_attrs(def_id);
     if is_foreign {
-        if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "link_name") {
+        if let Some(name) = attrs.link_name {
             return name.to_string();
         }
         // Don't mangle foreign items.
         return tcx.item_name(def_id).to_string();
     }
 
-    if let Some(name) = tcx.codegen_fn_attrs(def_id).export_name {
+    if let Some(name) = &attrs.export_name {
         // Use provided name
         return name.to_string();
     }
 
-    if attr::contains_name(&attrs, "no_mangle") {
+    if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) {
         // Don't mangle
         return tcx.item_name(def_id).to_string();
     }
diff --git a/src/librustc_cratesio_shim/src/lib.rs b/src/librustc_cratesio_shim/src/lib.rs
index 39087c5f746..481f2f54c5e 100644
--- a/src/librustc_cratesio_shim/src/lib.rs
+++ b/src/librustc_cratesio_shim/src/lib.rs
@@ -12,6 +12,7 @@
 #![allow(unused_extern_crates)]
 
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 
 extern crate bitflags;
 extern crate log;
diff --git a/src/librustc_data_structures/accumulate_vec.rs b/src/librustc_data_structures/accumulate_vec.rs
deleted file mode 100644
index 9423e6b3256..00000000000
--- a/src/librustc_data_structures/accumulate_vec.rs
+++ /dev/null
@@ -1,242 +0,0 @@
-// 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.
-
-//! A vector type intended to be used for collecting from iterators onto the stack.
-//!
-//! Space for up to N elements is provided on the stack.  If more elements are collected, Vec is
-//! used to store the values on the heap.
-//!
-//! The N above is determined by Array's implementor, by way of an associated constant.
-
-use std::ops::{Deref, DerefMut, RangeBounds};
-use std::iter::{self, IntoIterator, FromIterator};
-use std::slice;
-use std::vec;
-
-use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
-
-use array_vec::{self, Array, ArrayVec};
-
-#[derive(Hash, Debug)]
-pub enum AccumulateVec<A: Array> {
-    Array(ArrayVec<A>),
-    Heap(Vec<A::Element>)
-}
-
-impl<A> Clone for AccumulateVec<A>
-    where A: Array,
-          A::Element: Clone {
-    fn clone(&self) -> Self {
-        match *self {
-            AccumulateVec::Array(ref arr) => AccumulateVec::Array(arr.clone()),
-            AccumulateVec::Heap(ref vec) => AccumulateVec::Heap(vec.clone()),
-        }
-    }
-}
-
-impl<A: Array> AccumulateVec<A> {
-    pub fn new() -> AccumulateVec<A> {
-        AccumulateVec::Array(ArrayVec::new())
-    }
-
-    pub fn is_array(&self) -> bool {
-        match self {
-            AccumulateVec::Array(..) => true,
-            AccumulateVec::Heap(..) => false,
-        }
-    }
-
-    pub fn one(el: A::Element) -> Self {
-        iter::once(el).collect()
-    }
-
-    pub fn many<I: IntoIterator<Item=A::Element>>(iter: I) -> Self {
-        iter.into_iter().collect()
-    }
-
-    pub fn len(&self) -> usize {
-        match *self {
-            AccumulateVec::Array(ref arr) => arr.len(),
-            AccumulateVec::Heap(ref vec) => vec.len(),
-        }
-    }
-
-    pub fn is_empty(&self) -> bool {
-        self.len() == 0
-    }
-
-    pub fn pop(&mut self) -> Option<A::Element> {
-        match *self {
-            AccumulateVec::Array(ref mut arr) => arr.pop(),
-            AccumulateVec::Heap(ref mut vec) => vec.pop(),
-        }
-    }
-
-    pub fn drain<R>(&mut self, range: R) -> Drain<A>
-        where R: RangeBounds<usize>
-    {
-        match *self {
-            AccumulateVec::Array(ref mut v) => {
-                Drain::Array(v.drain(range))
-            },
-            AccumulateVec::Heap(ref mut v) => {
-                Drain::Heap(v.drain(range))
-            },
-        }
-    }
-}
-
-impl<A: Array> Deref for AccumulateVec<A> {
-    type Target = [A::Element];
-    fn deref(&self) -> &Self::Target {
-        match *self {
-            AccumulateVec::Array(ref v) => v,
-            AccumulateVec::Heap(ref v) => v,
-        }
-    }
-}
-
-impl<A: Array> DerefMut for AccumulateVec<A> {
-    fn deref_mut(&mut self) -> &mut [A::Element] {
-        match *self {
-            AccumulateVec::Array(ref mut v) => v,
-            AccumulateVec::Heap(ref mut v) => v,
-        }
-    }
-}
-
-impl<A: Array> FromIterator<A::Element> for AccumulateVec<A> {
-    fn from_iter<I>(iter: I) -> AccumulateVec<A> where I: IntoIterator<Item=A::Element> {
-        let iter = iter.into_iter();
-        if iter.size_hint().1.map_or(false, |n| n <= A::LEN) {
-            let mut v = ArrayVec::new();
-            v.extend(iter);
-            AccumulateVec::Array(v)
-        } else {
-            AccumulateVec::Heap(iter.collect())
-        }
-    }
-}
-
-pub struct IntoIter<A: Array> {
-    repr: IntoIterRepr<A>,
-}
-
-enum IntoIterRepr<A: Array> {
-    Array(array_vec::Iter<A>),
-    Heap(vec::IntoIter<A::Element>),
-}
-
-impl<A: Array> Iterator for IntoIter<A> {
-    type Item = A::Element;
-
-    fn next(&mut self) -> Option<A::Element> {
-        match self.repr {
-            IntoIterRepr::Array(ref mut arr) => arr.next(),
-            IntoIterRepr::Heap(ref mut iter) => iter.next(),
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        match self.repr {
-            IntoIterRepr::Array(ref iter) => iter.size_hint(),
-            IntoIterRepr::Heap(ref iter) => iter.size_hint(),
-        }
-    }
-}
-
-pub enum Drain<'a, A: Array>
-        where A::Element: 'a
-{
-    Array(array_vec::Drain<'a, A>),
-    Heap(vec::Drain<'a, A::Element>),
-}
-
-impl<'a, A: Array> Iterator for Drain<'a, A> {
-    type Item = A::Element;
-
-    fn next(&mut self) -> Option<A::Element> {
-        match *self {
-            Drain::Array(ref mut drain) => drain.next(),
-            Drain::Heap(ref mut drain) => drain.next(),
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        match *self {
-            Drain::Array(ref drain) => drain.size_hint(),
-            Drain::Heap(ref drain) => drain.size_hint(),
-        }
-    }
-}
-
-impl<A: Array> IntoIterator for AccumulateVec<A> {
-    type Item = A::Element;
-    type IntoIter = IntoIter<A>;
-    fn into_iter(self) -> Self::IntoIter {
-        IntoIter {
-            repr: match self {
-                AccumulateVec::Array(arr) => IntoIterRepr::Array(arr.into_iter()),
-                AccumulateVec::Heap(vec) => IntoIterRepr::Heap(vec.into_iter()),
-            }
-        }
-    }
-}
-
-impl<'a, A: Array> IntoIterator for &'a AccumulateVec<A> {
-    type Item = &'a A::Element;
-    type IntoIter = slice::Iter<'a, A::Element>;
-    fn into_iter(self) -> Self::IntoIter {
-        self.iter()
-    }
-}
-
-impl<'a, A: Array> IntoIterator for &'a mut AccumulateVec<A> {
-    type Item = &'a mut A::Element;
-    type IntoIter = slice::IterMut<'a, A::Element>;
-    fn into_iter(self) -> Self::IntoIter {
-        self.iter_mut()
-    }
-}
-
-impl<A: Array> From<Vec<A::Element>> for AccumulateVec<A> {
-    fn from(v: Vec<A::Element>) -> AccumulateVec<A> {
-        AccumulateVec::many(v)
-    }
-}
-
-impl<A: Array> Default for AccumulateVec<A> {
-    fn default() -> AccumulateVec<A> {
-        AccumulateVec::new()
-    }
-}
-
-impl<A> Encodable for AccumulateVec<A>
-    where A: Array,
-          A::Element: Encodable {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_seq(self.len(), |s| {
-            for (i, e) in self.iter().enumerate() {
-                s.emit_seq_elt(i, |s| e.encode(s))?;
-            }
-            Ok(())
-        })
-    }
-}
-
-impl<A> Decodable for AccumulateVec<A>
-    where A: Array,
-          A::Element: Decodable {
-    fn decode<D: Decoder>(d: &mut D) -> Result<AccumulateVec<A>, D::Error> {
-        d.read_seq(|d, len| {
-            (0..len).map(|i| d.read_seq_elt(i, |d| Decodable::decode(d))).collect()
-        })
-    }
-}
diff --git a/src/librustc_data_structures/graph/dominators/mod.rs b/src/librustc_data_structures/graph/dominators/mod.rs
index e54147cbe7c..9b7f4cec47b 100644
--- a/src/librustc_data_structures/graph/dominators/mod.rs
+++ b/src/librustc_data_structures/graph/dominators/mod.rs
@@ -38,13 +38,13 @@ pub fn dominators_given_rpo<G: ControlFlowGraph>(
 
     // compute the post order index (rank) for each node
     let mut post_order_rank: IndexVec<G::Node, usize> =
-        IndexVec::from_elem_n(usize::default(), graph.num_nodes());
+        (0..graph.num_nodes()).map(|_| 0).collect();
     for (index, node) in rpo.iter().rev().cloned().enumerate() {
         post_order_rank[node] = index;
     }
 
     let mut immediate_dominators: IndexVec<G::Node, Option<G::Node>> =
-        IndexVec::from_elem_n(Option::default(), graph.num_nodes());
+        (0..graph.num_nodes()).map(|_| None).collect();
     immediate_dominators[start_node] = Some(start_node);
 
     let mut changed = true;
diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs
index f21c898a28a..65fdf10a86d 100644
--- a/src/librustc_data_structures/indexed_set.rs
+++ b/src/librustc_data_structures/indexed_set.rs
@@ -19,6 +19,20 @@ use bitslice::{bitwise, Union, Subtract, Intersect};
 use indexed_vec::Idx;
 use rustc_serialize;
 
+/// This is implemented by all the index sets so that IdxSet::union() can be
+/// passed any type of index set.
+pub trait UnionIntoIdxSet<T: Idx> {
+    // Performs `other = other | self`.
+    fn union_into(&self, other: &mut IdxSet<T>) -> bool;
+}
+
+/// This is implemented by all the index sets so that IdxSet::subtract() can be
+/// passed any type of index set.
+pub trait SubtractFromIdxSet<T: Idx> {
+    // Performs `other = other - self`.
+    fn subtract_from(&self, other: &mut IdxSet<T>) -> bool;
+}
+
 /// Represents a set of some element type E, where each E is identified by some
 /// unique index type `T`.
 ///
@@ -68,34 +82,34 @@ impl<T: Idx> fmt::Debug for IdxSet<T> {
 }
 
 impl<T: Idx> IdxSet<T> {
-    fn new(init: Word, universe_size: usize) -> Self {
-        let num_words = (universe_size + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
+    fn new(init: Word, domain_size: usize) -> Self {
+        let num_words = (domain_size + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
         IdxSet {
             _pd: Default::default(),
             bits: vec![init; num_words],
         }
     }
 
-    /// Creates set holding every element whose index falls in range 0..universe_size.
-    pub fn new_filled(universe_size: usize) -> Self {
-        let mut result = Self::new(!0, universe_size);
-        result.trim_to(universe_size);
+    /// Creates set holding every element whose index falls in range 0..domain_size.
+    pub fn new_filled(domain_size: usize) -> Self {
+        let mut result = Self::new(!0, domain_size);
+        result.trim_to(domain_size);
         result
     }
 
     /// Creates set holding no elements.
-    pub fn new_empty(universe_size: usize) -> Self {
-        Self::new(0, universe_size)
+    pub fn new_empty(domain_size: usize) -> Self {
+        Self::new(0, domain_size)
     }
 
     /// Duplicates as a hybrid set.
     pub fn to_hybrid(&self) -> HybridIdxSet<T> {
-        // This universe_size may be slightly larger than the one specified
+        // This domain_size may be slightly larger than the one specified
         // upon creation, due to rounding up to a whole word. That's ok.
-        let universe_size = self.bits.len() * BITS_PER_WORD;
+        let domain_size = self.bits.len() * BITS_PER_WORD;
 
         // Note: we currently don't bother trying to make a Sparse set.
-        HybridIdxSet::Dense(self.to_owned(), universe_size)
+        HybridIdxSet::Dense(self.to_owned(), domain_size)
     }
 
     /// Removes all elements
@@ -105,19 +119,19 @@ impl<T: Idx> IdxSet<T> {
         }
     }
 
-    /// Sets all elements up to `universe_size`
-    pub fn set_up_to(&mut self, universe_size: usize) {
+    /// Sets all elements up to `domain_size`
+    pub fn set_up_to(&mut self, domain_size: usize) {
         for b in &mut self.bits {
             *b = !0;
         }
-        self.trim_to(universe_size);
+        self.trim_to(domain_size);
     }
 
-    /// Clear all elements above `universe_size`.
-    fn trim_to(&mut self, universe_size: usize) {
+    /// Clear all elements above `domain_size`.
+    fn trim_to(&mut self, domain_size: usize) {
         // `trim_block` is the first block where some bits have
         // to be cleared.
-        let trim_block = universe_size / BITS_PER_WORD;
+        let trim_block = domain_size / BITS_PER_WORD;
 
         // all the blocks above it have to be completely cleared.
         if trim_block < self.bits.len() {
@@ -125,9 +139,9 @@ impl<T: Idx> IdxSet<T> {
                 *b = 0;
             }
 
-            // at that block, the `universe_size % BITS_PER_WORD` lsbs
+            // at that block, the `domain_size % BITS_PER_WORD` LSBs
             // should remain.
-            let remaining_bits = universe_size % BITS_PER_WORD;
+            let remaining_bits = domain_size % BITS_PER_WORD;
             let mask = (1<<remaining_bits)-1;
             self.bits[trim_block] &= mask;
         }
@@ -164,48 +178,14 @@ impl<T: Idx> IdxSet<T> {
 
     /// Set `self = self | other` and return true if `self` changed
     /// (i.e., if new bits were added).
-    pub fn union(&mut self, other: &IdxSet<T>) -> bool {
-        bitwise(self.words_mut(), other.words(), &Union)
-    }
-
-    /// Like `union()`, but takes a `SparseIdxSet` argument.
-    fn union_sparse(&mut self, other: &SparseIdxSet<T>) -> bool {
-        let mut changed = false;
-        for elem in other.iter() {
-            changed |= self.add(&elem);
-        }
-        changed
-    }
-
-    /// Like `union()`, but takes a `HybridIdxSet` argument.
-    pub fn union_hybrid(&mut self, other: &HybridIdxSet<T>) -> bool {
-        match other {
-            HybridIdxSet::Sparse(sparse, _) => self.union_sparse(sparse),
-            HybridIdxSet::Dense(dense, _) => self.union(dense),
-        }
+    pub fn union(&mut self, other: &impl UnionIntoIdxSet<T>) -> bool {
+        other.union_into(self)
     }
 
     /// Set `self = self - other` and return true if `self` changed.
     /// (i.e., if any bits were removed).
-    pub fn subtract(&mut self, other: &IdxSet<T>) -> bool {
-        bitwise(self.words_mut(), other.words(), &Subtract)
-    }
-
-    /// Like `subtract()`, but takes a `SparseIdxSet` argument.
-    fn subtract_sparse(&mut self, other: &SparseIdxSet<T>) -> bool {
-        let mut changed = false;
-        for elem in other.iter() {
-            changed |= self.remove(&elem);
-        }
-        changed
-    }
-
-    /// Like `subtract()`, but takes a `HybridIdxSet` argument.
-    pub fn subtract_hybrid(&mut self, other: &HybridIdxSet<T>) -> bool {
-        match other {
-            HybridIdxSet::Sparse(sparse, _) => self.subtract_sparse(sparse),
-            HybridIdxSet::Dense(dense, _) => self.subtract(dense),
-        }
+    pub fn subtract(&mut self, other: &impl SubtractFromIdxSet<T>) -> bool {
+        other.subtract_from(self)
     }
 
     /// Set `self = self & other` and return true if `self` changed.
@@ -223,6 +203,18 @@ impl<T: Idx> IdxSet<T> {
     }
 }
 
+impl<T: Idx> UnionIntoIdxSet<T> for IdxSet<T> {
+    fn union_into(&self, other: &mut IdxSet<T>) -> bool {
+        bitwise(other.words_mut(), self.words(), &Union)
+    }
+}
+
+impl<T: Idx> SubtractFromIdxSet<T> for IdxSet<T> {
+    fn subtract_from(&self, other: &mut IdxSet<T>) -> bool {
+        bitwise(other.words_mut(), self.words(), &Subtract)
+    }
+}
+
 pub struct Iter<'a, T: Idx> {
     cur: Option<(Word, usize)>,
     iter: iter::Enumerate<slice::Iter<'a, Word>>,
@@ -293,8 +285,8 @@ impl<T: Idx> SparseIdxSet<T> {
         }
     }
 
-    fn to_dense(&self, universe_size: usize) -> IdxSet<T> {
-        let mut dense = IdxSet::new_empty(universe_size);
+    fn to_dense(&self, domain_size: usize) -> IdxSet<T> {
+        let mut dense = IdxSet::new_empty(domain_size);
         for elem in self.0.iter() {
             dense.add(elem);
         }
@@ -308,6 +300,26 @@ impl<T: Idx> SparseIdxSet<T> {
     }
 }
 
+impl<T: Idx> UnionIntoIdxSet<T> for SparseIdxSet<T> {
+    fn union_into(&self, other: &mut IdxSet<T>) -> bool {
+        let mut changed = false;
+        for elem in self.iter() {
+            changed |= other.add(&elem);
+        }
+        changed
+    }
+}
+
+impl<T: Idx> SubtractFromIdxSet<T> for SparseIdxSet<T> {
+    fn subtract_from(&self, other: &mut IdxSet<T>) -> bool {
+        let mut changed = false;
+        for elem in self.iter() {
+            changed |= other.remove(&elem);
+        }
+        changed
+    }
+}
+
 pub struct SparseIter<'a, T: Idx> {
     iter: slice::Iter<'a, T>,
 }
@@ -323,7 +335,7 @@ impl<'a, T: Idx> Iterator for SparseIter<'a, T> {
 /// Like IdxSet, but with a hybrid representation: sparse when there are few
 /// elements in the set, but dense when there are many. It's especially
 /// efficient for sets that typically have a small number of elements, but a
-/// large `universe_size`, and are cleared frequently.
+/// large `domain_size`, and are cleared frequently.
 #[derive(Clone, Debug)]
 pub enum HybridIdxSet<T: Idx> {
     Sparse(SparseIdxSet<T>, usize),
@@ -331,20 +343,16 @@ pub enum HybridIdxSet<T: Idx> {
 }
 
 impl<T: Idx> HybridIdxSet<T> {
-    pub fn new_empty(universe_size: usize) -> Self {
-        HybridIdxSet::Sparse(SparseIdxSet::new(), universe_size)
+    pub fn new_empty(domain_size: usize) -> Self {
+        HybridIdxSet::Sparse(SparseIdxSet::new(), domain_size)
     }
 
-    fn universe_size(&mut self) -> usize {
-        match *self {
+    pub fn clear(&mut self) {
+        let domain_size = match *self {
             HybridIdxSet::Sparse(_, size) => size,
             HybridIdxSet::Dense(_, size) => size,
-        }
-    }
-
-    pub fn clear(&mut self) {
-        let universe_size = self.universe_size();
-        *self = HybridIdxSet::new_empty(universe_size);
+        };
+        *self = HybridIdxSet::new_empty(domain_size);
     }
 
     /// Returns true iff set `self` contains `elem`.
@@ -374,11 +382,11 @@ impl<T: Idx> HybridIdxSet<T> {
                 //        appease the borrow checker.
                 let dummy = HybridIdxSet::Sparse(SparseIdxSet::new(), 0);
                 match mem::replace(self, dummy) {
-                    HybridIdxSet::Sparse(sparse, universe_size) => {
-                        let mut dense = sparse.to_dense(universe_size);
+                    HybridIdxSet::Sparse(sparse, domain_size) => {
+                        let mut dense = sparse.to_dense(domain_size);
                         let changed = dense.add(elem);
                         assert!(changed);
-                        mem::replace(self, HybridIdxSet::Dense(dense, universe_size));
+                        mem::replace(self, HybridIdxSet::Dense(dense, domain_size));
                         changed
                     }
                     _ => panic!("impossible"),
@@ -401,7 +409,7 @@ impl<T: Idx> HybridIdxSet<T> {
     /// Converts to a dense set, consuming itself in the process.
     pub fn to_dense(self) -> IdxSet<T> {
         match self {
-            HybridIdxSet::Sparse(sparse, universe_size) => sparse.to_dense(universe_size),
+            HybridIdxSet::Sparse(sparse, domain_size) => sparse.to_dense(domain_size),
             HybridIdxSet::Dense(dense, _) => dense,
         }
     }
@@ -415,6 +423,24 @@ impl<T: Idx> HybridIdxSet<T> {
     }
 }
 
+impl<T: Idx> UnionIntoIdxSet<T> for HybridIdxSet<T> {
+    fn union_into(&self, other: &mut IdxSet<T>) -> bool {
+        match self {
+            HybridIdxSet::Sparse(sparse, _) => sparse.union_into(other),
+            HybridIdxSet::Dense(dense, _) => dense.union_into(other),
+        }
+    }
+}
+
+impl<T: Idx> SubtractFromIdxSet<T> for HybridIdxSet<T> {
+    fn subtract_from(&self, other: &mut IdxSet<T>) -> bool {
+        match self {
+            HybridIdxSet::Sparse(sparse, _) => sparse.subtract_from(other),
+            HybridIdxSet::Dense(dense, _) => dense.subtract_from(other),
+        }
+    }
+}
+
 pub enum HybridIter<'a, T: Idx> {
     Sparse(SparseIter<'a, T>),
     Dense(Iter<'a, T>),
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index 1eef7870c01..7915650fd89 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -20,6 +20,8 @@
       html_favicon_url = "https://www.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]
 
+#![feature(in_band_lifetimes)]
+#![feature(impl_header_lifetime_elision)]
 #![feature(unboxed_closures)]
 #![feature(fn_traits)]
 #![feature(unsize)]
@@ -27,6 +29,7 @@
 #![feature(optin_builtin_traits)]
 #![cfg_attr(stage0, feature(macro_vis_matcher))]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(allow_internal_unstable)]
 #![feature(vec_resize_with)]
 
@@ -58,7 +61,6 @@ extern crate rustc_cratesio_shim;
 pub use rustc_serialize::hex::ToHex;
 
 pub mod svh;
-pub mod accumulate_vec;
 pub mod array_vec;
 pub mod base_n;
 pub mod bitslice;
@@ -85,6 +87,7 @@ pub mod thin_vec;
 pub mod transitive_relation;
 pub mod tuple_slice;
 pub use ena::unify;
+pub mod vec_linked_list;
 pub mod work_queue;
 pub mod fingerprint;
 
diff --git a/src/librustc_data_structures/small_vec.rs b/src/librustc_data_structures/small_vec.rs
index e4e6a3d1a9c..075b70c6426 100644
--- a/src/librustc_data_structures/small_vec.rs
+++ b/src/librustc_data_structures/small_vec.rs
@@ -8,11 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! A vector type intended to be used for collecting from iterators onto the stack.
+//! A vector type intended to be used for small vectors.
 //!
-//! Space for up to N elements is provided on the stack.  If more elements are collected, Vec is
-//! used to store the values on the heap. SmallVec is similar to AccumulateVec, but adds
-//! the ability to push elements.
+//! Space for up to N elements is provided on the stack. If more elements are collected, Vec is
+//! used to store the values on the heap.
 //!
 //! The N above is determined by Array's implementor, by way of an associated constant.
 
diff --git a/src/librustc_data_structures/vec_linked_list.rs b/src/librustc_data_structures/vec_linked_list.rs
new file mode 100644
index 00000000000..390dca6b905
--- /dev/null
+++ b/src/librustc_data_structures/vec_linked_list.rs
@@ -0,0 +1,83 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use indexed_vec::{Idx, IndexVec};
+
+pub fn iter<Ls>(
+    first: Option<Ls::LinkIndex>,
+    links: &'a Ls,
+) -> impl Iterator<Item = Ls::LinkIndex> + 'a
+where
+    Ls: Links,
+{
+    VecLinkedListIterator {
+        links: links,
+        current: first,
+    }
+}
+
+pub struct VecLinkedListIterator<Ls>
+where
+    Ls: Links,
+{
+    links: Ls,
+    current: Option<Ls::LinkIndex>,
+}
+
+impl<Ls> Iterator for VecLinkedListIterator<Ls>
+where
+    Ls: Links,
+{
+    type Item = Ls::LinkIndex;
+
+    fn next(&mut self) -> Option<Ls::LinkIndex> {
+        if let Some(c) = self.current {
+            self.current = <Ls as Links>::next(&self.links, c);
+            Some(c)
+        } else {
+            None
+        }
+    }
+}
+
+pub trait Links {
+    type LinkIndex: Copy;
+
+    fn next(links: &Self, index: Self::LinkIndex) -> Option<Self::LinkIndex>;
+}
+
+impl<Ls> Links for &Ls
+where
+    Ls: Links,
+{
+    type LinkIndex = Ls::LinkIndex;
+
+    fn next(links: &Self, index: Ls::LinkIndex) -> Option<Ls::LinkIndex> {
+        <Ls as Links>::next(links, index)
+    }
+}
+
+pub trait LinkElem {
+    type LinkIndex: Copy;
+
+    fn next(elem: &Self) -> Option<Self::LinkIndex>;
+}
+
+impl<L, E> Links for IndexVec<L, E>
+where
+    E: LinkElem<LinkIndex = L>,
+    L: Idx,
+{
+    type LinkIndex = L;
+
+    fn next(links: &Self, index: L) -> Option<L> {
+        <E as LinkElem>::next(&links[index])
+    }
+}
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index f88c619bf77..13e1df6e538 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -21,6 +21,7 @@
 #![feature(box_syntax)]
 #![cfg_attr(unix, feature(libc))]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(option_replace)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
@@ -185,27 +186,29 @@ pub fn run<F>(run_compiler: F) -> isize
     where F: FnOnce() -> (CompileResult, Option<Session>) + Send + 'static
 {
     let result = monitor(move || {
-        let (result, session) = run_compiler();
-        if let Err(CompileIncomplete::Errored(_)) = result {
-            match session {
-                Some(sess) => {
-                    sess.abort_if_errors();
-                    panic!("error reported but abort_if_errors didn't abort???");
-                }
-                None => {
-                    let emitter =
-                        errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto,
-                                                               None,
-                                                               true,
-                                                               false);
-                    let handler = errors::Handler::with_emitter(true, false, Box::new(emitter));
-                    handler.emit(&MultiSpan::new(),
-                                 "aborting due to previous error(s)",
-                                 errors::Level::Fatal);
-                    panic::resume_unwind(Box::new(errors::FatalErrorMarker));
+        syntax::with_globals(|| {
+            let (result, session) = run_compiler();
+            if let Err(CompileIncomplete::Errored(_)) = result {
+                match session {
+                    Some(sess) => {
+                        sess.abort_if_errors();
+                        panic!("error reported but abort_if_errors didn't abort???");
+                    }
+                    None => {
+                        let emitter =
+                            errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto,
+                                                                None,
+                                                                true,
+                                                                false);
+                        let handler = errors::Handler::with_emitter(true, false, Box::new(emitter));
+                        handler.emit(&MultiSpan::new(),
+                                    "aborting due to previous error(s)",
+                                    errors::Level::Fatal);
+                        panic::resume_unwind(Box::new(errors::FatalErrorMarker));
+                    }
                 }
             }
-        }
+        });
     });
 
     match result {
@@ -471,17 +474,15 @@ pub fn run_compiler<'a>(args: &[String],
                         emitter_dest: Option<Box<dyn Write + Send>>)
                         -> (CompileResult, Option<Session>)
 {
-    syntax::with_globals(|| {
-        let matches = match handle_options(args) {
-            Some(matches) => matches,
-            None => return (Ok(()), None),
-        };
+    let matches = match handle_options(args) {
+        Some(matches) => matches,
+        None => return (Ok(()), None),
+    };
 
-        let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
+    let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
 
-        driver::spawn_thread_pool(sopts, |sopts| {
-            run_compiler_with_pool(matches, sopts, cfg, callbacks, file_loader, emitter_dest)
-        })
+    driver::spawn_thread_pool(sopts, |sopts| {
+        run_compiler_with_pool(matches, sopts, cfg, callbacks, file_loader, emitter_dest)
     })
 }
 
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 65cbee821e8..c49631515ea 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -355,33 +355,33 @@ impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> {
 impl<'hir> pprust::PpAnn for IdentifiedAnnotation<'hir> {
     fn pre(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> {
         match node {
-            pprust::NodeExpr(_) => s.popen(),
+            pprust::AnnNode::Expr(_) => s.popen(),
             _ => Ok(()),
         }
     }
     fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> {
         match node {
-            pprust::NodeIdent(_) |
-            pprust::NodeName(_) => Ok(()),
+            pprust::AnnNode::Ident(_) |
+            pprust::AnnNode::Name(_) => Ok(()),
 
-            pprust::NodeItem(item) => {
+            pprust::AnnNode::Item(item) => {
                 s.s.space()?;
                 s.synth_comment(item.id.to_string())
             }
-            pprust::NodeSubItem(id) => {
+            pprust::AnnNode::SubItem(id) => {
                 s.s.space()?;
                 s.synth_comment(id.to_string())
             }
-            pprust::NodeBlock(blk) => {
+            pprust::AnnNode::Block(blk) => {
                 s.s.space()?;
                 s.synth_comment(format!("block {}", blk.id))
             }
-            pprust::NodeExpr(expr) => {
+            pprust::AnnNode::Expr(expr) => {
                 s.s.space()?;
                 s.synth_comment(expr.id.to_string())?;
                 s.pclose()
             }
-            pprust::NodePat(pat) => {
+            pprust::AnnNode::Pat(pat) => {
                 s.s.space()?;
                 s.synth_comment(format!("pat {}", pat.id))
             }
@@ -414,34 +414,34 @@ impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> {
     }
     fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
         match node {
-            pprust_hir::NodeExpr(_) => s.popen(),
+            pprust_hir::AnnNode::Expr(_) => s.popen(),
             _ => Ok(()),
         }
     }
     fn post(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
         match node {
-            pprust_hir::NodeName(_) => Ok(()),
-            pprust_hir::NodeItem(item) => {
+            pprust_hir::AnnNode::Name(_) => Ok(()),
+            pprust_hir::AnnNode::Item(item) => {
                 s.s.space()?;
                 s.synth_comment(format!("node_id: {} hir local_id: {}",
                                         item.id, item.hir_id.local_id.0))
             }
-            pprust_hir::NodeSubItem(id) => {
+            pprust_hir::AnnNode::SubItem(id) => {
                 s.s.space()?;
                 s.synth_comment(id.to_string())
             }
-            pprust_hir::NodeBlock(blk) => {
+            pprust_hir::AnnNode::Block(blk) => {
                 s.s.space()?;
                 s.synth_comment(format!("block node_id: {} hir local_id: {}",
                                         blk.id, blk.hir_id.local_id.0))
             }
-            pprust_hir::NodeExpr(expr) => {
+            pprust_hir::AnnNode::Expr(expr) => {
                 s.s.space()?;
                 s.synth_comment(format!("node_id: {} hir local_id: {}",
                                         expr.id, expr.hir_id.local_id.0))?;
                 s.pclose()
             }
-            pprust_hir::NodePat(pat) => {
+            pprust_hir::AnnNode::Pat(pat) => {
                 s.s.space()?;
                 s.synth_comment(format!("pat node_id: {} hir local_id: {}",
                                         pat.id, pat.hir_id.local_id.0))
@@ -467,13 +467,13 @@ impl<'a> PrinterSupport for HygieneAnnotation<'a> {
 impl<'a> pprust::PpAnn for HygieneAnnotation<'a> {
     fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> {
         match node {
-            pprust::NodeIdent(&ast::Ident { name, span }) => {
+            pprust::AnnNode::Ident(&ast::Ident { name, span }) => {
                 s.s.space()?;
                 // FIXME #16420: this doesn't display the connections
                 // between syntax contexts
                 s.synth_comment(format!("{}{:?}", name.as_u32(), span.ctxt()))
             }
-            pprust::NodeName(&name) => {
+            pprust::AnnNode::Name(&name) => {
                 s.s.space()?;
                 s.synth_comment(name.as_u32().to_string())
             }
@@ -519,13 +519,13 @@ impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> {
     }
     fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
         match node {
-            pprust_hir::NodeExpr(_) => s.popen(),
+            pprust_hir::AnnNode::Expr(_) => s.popen(),
             _ => Ok(()),
         }
     }
     fn post(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
         match node {
-            pprust_hir::NodeExpr(expr) => {
+            pprust_hir::AnnNode::Expr(expr) => {
                 s.s.space()?;
                 s.s.word("as")?;
                 s.s.space()?;
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index 3582c2359c8..d31db4b2d00 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -17,6 +17,7 @@
 #![feature(range_contains)]
 #![cfg_attr(unix, feature(libc))]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(optin_builtin_traits)]
 
 extern crate atty;
diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs
index ad8714fa4d5..e100b49c7f2 100644
--- a/src/librustc_incremental/lib.rs
+++ b/src/librustc_incremental/lib.rs
@@ -15,6 +15,7 @@
       html_root_url = "https://doc.rust-lang.org/nightly/")]
 
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(specialization)]
 
 #![recursion_limit="256"]
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index 7f2da5a326a..f715057541f 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -30,7 +30,7 @@ use std::vec::Vec;
 use rustc::dep_graph::{DepNode, label_strs};
 use rustc::hir;
 use rustc::hir::{ItemKind as HirItem, ImplItemKind, TraitItemKind};
-use rustc::hir::map::Node as HirNode;
+use rustc::hir::Node as HirNode;
 use rustc::hir::def_id::DefId;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::intravisit;
@@ -336,7 +336,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
     fn auto_labels(&mut self, item_id: ast::NodeId, attr: &Attribute) -> (&'static str, Labels) {
         let node = self.tcx.hir.get(item_id);
         let (name, labels) = match node {
-            HirNode::NodeItem(item) => {
+            HirNode::Item(item) => {
                 match item.node {
                     // note: these are in the same order as hir::Item_;
                     // FIXME(michaelwoerister): do commented out ones
@@ -399,22 +399,23 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
                     _ => self.tcx.sess.span_fatal(
                         attr.span,
                         &format!(
-                            "clean/dirty auto-assertions not yet defined for NodeItem.node={:?}",
+                            "clean/dirty auto-assertions not yet defined \
+                             for Node::Item.node={:?}",
                             item.node
                         )
                     ),
                 }
             },
-            HirNode::NodeTraitItem(item) => {
+            HirNode::TraitItem(item) => {
                 match item.node {
-                    TraitItemKind::Method(..) => ("NodeTraitItem", LABELS_FN_IN_TRAIT),
+                    TraitItemKind::Method(..) => ("Node::TraitItem", LABELS_FN_IN_TRAIT),
                     TraitItemKind::Const(..) => ("NodeTraitConst", LABELS_CONST_IN_TRAIT),
                     TraitItemKind::Type(..) => ("NodeTraitType", LABELS_CONST_IN_TRAIT),
                 }
             },
-            HirNode::NodeImplItem(item) => {
+            HirNode::ImplItem(item) => {
                 match item.node {
-                    ImplItemKind::Method(..) => ("NodeImplItem", LABELS_FN_IN_IMPL),
+                    ImplItemKind::Method(..) => ("Node::ImplItem", LABELS_FN_IN_IMPL),
                     ImplItemKind::Const(..) => ("NodeImplConst", LABELS_CONST_IN_IMPL),
                     ImplItemKind::Type(..) => ("NodeImplType", LABELS_CONST_IN_IMPL),
                     ImplItemKind::Existential(..) => ("NodeImplType", LABELS_CONST_IN_IMPL),
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 92a2ea2bf2d..c497627415f 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -34,7 +34,7 @@ use rustc::cfg;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty};
 use rustc::traits;
-use rustc::hir::map as hir_map;
+use hir::Node;
 use util::nodemap::NodeSet;
 use lint::{LateContext, LintContext, LintArray};
 use lint::{LintPass, LateLintPass, EarlyLintPass, EarlyContext};
@@ -46,7 +46,6 @@ use syntax::tokenstream::{TokenTree, TokenStream};
 use syntax::ast;
 use syntax::attr;
 use syntax::source_map::Spanned;
-use syntax::edition::Edition;
 use syntax::feature_gate::{AttributeGate, AttributeType, Stability, deprecated_attributes};
 use syntax_pos::{BytePos, Span, SyntaxContext};
 use syntax::symbol::keywords;
@@ -427,7 +426,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
                 let real_trait = trait_ref.path.def.def_id();
                 if let Some(node_id) = cx.tcx.hir.as_local_node_id(real_trait) {
                     match cx.tcx.hir.find(node_id) {
-                        Some(hir_map::NodeItem(item)) => {
+                        Some(Node::Item(item)) => {
                             if let hir::VisibilityKind::Inherited = item.vis.node {
                                 for impl_item_ref in impl_item_refs {
                                     self.private_traits.insert(impl_item_ref.id.node_id);
@@ -629,8 +628,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations {
 declare_lint! {
     pub ANONYMOUS_PARAMETERS,
     Allow,
-    "detects anonymous parameters",
-    Edition::Edition2018 => Warn
+    "detects anonymous parameters"
 }
 
 /// Checks for use of anonymous parameters (RFC 1685)
@@ -981,7 +979,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
 
         fn expr_refers_to_this_fn(cx: &LateContext, fn_id: ast::NodeId, id: ast::NodeId) -> bool {
             match cx.tcx.hir.get(id) {
-                hir_map::NodeExpr(&hir::Expr { node: hir::ExprKind::Call(ref callee, _), .. }) => {
+                Node::Expr(&hir::Expr { node: hir::ExprKind::Call(ref callee, _), .. }) => {
                     let def = if let hir::ExprKind::Path(ref qpath) = callee.node {
                         cx.tables.qpath_def(qpath, callee.hir_id)
                     } else {
@@ -1004,7 +1002,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
             use rustc::ty::adjustment::*;
 
             // Ignore non-expressions.
-            let expr = if let hir_map::NodeExpr(e) = cx.tcx.hir.get(id) {
+            let expr = if let Node::Expr(e) = cx.tcx.hir.get(id) {
                 e
             } else {
                 return false;
@@ -1614,21 +1612,15 @@ fn validate_const<'a, 'tcx>(
     gid: ::rustc::mir::interpret::GlobalId<'tcx>,
     what: &str,
 ) {
-    let mut ecx = ::rustc_mir::interpret::mk_eval_cx(tcx, gid.instance, param_env).unwrap();
+    let ecx = ::rustc_mir::interpret::mk_eval_cx(tcx, gid.instance, param_env).unwrap();
     let result = (|| {
-        use rustc_target::abi::LayoutOf;
-        use rustc_mir::interpret::OpTy;
-
-        let op = ecx.const_value_to_op(constant.val)?;
-        let layout = ecx.layout_of(constant.ty)?;
-        let place = ecx.allocate_op(OpTy { op, layout })?.into();
-
-        let mut todo = vec![(place, Vec::new())];
+        let op = ecx.const_to_op(constant)?;
+        let mut todo = vec![(op, Vec::new())];
         let mut seen = FxHashSet();
-        seen.insert(place);
-        while let Some((place, mut path)) = todo.pop() {
-            ecx.validate_mplace(
-                place,
+        seen.insert(op);
+        while let Some((op, mut path)) = todo.pop() {
+            ecx.validate_operand(
+                op,
                 &mut path,
                 &mut seen,
                 &mut todo,
@@ -1864,7 +1856,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnameableTestFunctions {
                     if attr.name() == "test" {
                         let parent = cx.tcx.hir.get_parent(it.id);
                         match cx.tcx.hir.find(parent) {
-                            Some(hir_map::NodeItem(hir::Item {node: hir::ItemKind::Mod(_), ..})) |
+                            Some(Node::Item(hir::Item {node: hir::ItemKind::Mod(_), ..})) |
                             None => {}
                             _ => {
                                 cx.struct_span_lint(
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 7d802787105..05b11e3ba3a 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -28,6 +28,7 @@
 #![feature(box_syntax)]
 #![cfg_attr(stage0, feature(macro_vis_matcher))]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(macro_at_most_once_rep)]
@@ -276,7 +277,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
         FutureIncompatibleInfo {
             id: LintId::of(ANONYMOUS_PARAMETERS),
             reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
-            edition: None,
+            edition: Some(Edition::Edition2018),
         },
         FutureIncompatibleInfo {
             id: LintId::of(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES),
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index d9f6e7de5b5..2c410e8efb1 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -10,7 +10,7 @@
 
 #![allow(non_snake_case)]
 
-use rustc::hir::map as hir_map;
+use rustc::hir::Node;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
 use rustc::ty::layout::{self, IntegerExt, LayoutOf};
@@ -137,7 +137,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
                         };
                         if lit_val < min || lit_val > max {
                             let parent_id = cx.tcx.hir.get_parent_node(e.id);
-                            if let hir_map::NodeExpr(parent_expr) = cx.tcx.hir.get(parent_id) {
+                            if let Node::Expr(parent_expr) = cx.tcx.hir.get(parent_id) {
                                 if let hir::ExprKind::Cast(..) = parent_expr.node {
                                     if let ty::Char = cx.tables.expr_ty(parent_expr).sty {
                                         let mut err = cx.struct_span_lint(
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index 387660473a8..13605e993a5 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(static_nobundle)]
 
 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
diff --git a/src/librustc_lsan/lib.rs b/src/librustc_lsan/lib.rs
index b3ba86ad8a4..ed8fd305977 100644
--- a/src/librustc_lsan/lib.rs
+++ b/src/librustc_lsan/lib.rs
@@ -11,6 +11,7 @@
 #![sanitizer_runtime]
 #![feature(alloc_system)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(sanitizer_runtime)]
 #![feature(staged_api)]
 #![no_std]
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index 09a8bea0941..107245488ac 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -16,6 +16,7 @@
 #![feature(libc)]
 #![feature(macro_at_most_once_rep)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(proc_macro_internals)]
 #![feature(proc_macro_quote)]
 #![feature(quote)]
diff --git a/src/librustc_mir/borrow_check/flows.rs b/src/librustc_mir/borrow_check/flows.rs
index 90dc96cbd3c..192fa2b9eea 100644
--- a/src/librustc_mir/borrow_check/flows.rs
+++ b/src/librustc_mir/borrow_check/flows.rs
@@ -89,6 +89,10 @@ impl<'b, 'gcx, 'tcx> FlowsAtLocation for Flows<'b, 'gcx, 'tcx> {
         each_flow!(self, reset_to_entry_of(bb));
     }
 
+    fn reset_to_exit_of(&mut self, bb: BasicBlock) {
+        each_flow!(self, reset_to_exit_of(bb));
+    }
+
     fn reconstruct_statement_effect(&mut self, location: Location) {
         each_flow!(self, reconstruct_statement_effect(location));
     }
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 6181eae5f60..16d34082642 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -12,6 +12,7 @@
 
 use borrow_check::nll::region_infer::RegionInferenceContext;
 use rustc::hir;
+use rustc::hir::Node;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::definitions::DefPathData;
 use rustc::infer::InferCtxt;
@@ -232,7 +233,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
     ));
 
     let movable_generator = match tcx.hir.get(id) {
-        hir::map::Node::NodeExpr(&hir::Expr {
+        Node::Expr(&hir::Expr {
             node: hir::ExprKind::Closure(.., Some(hir::GeneratorMovability::Static)),
             ..
         }) => false,
diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs
index 251586cd794..f96ef909c0d 100644
--- a/src/librustc_mir/borrow_check/mutability_errors.rs
+++ b/src/librustc_mir/borrow_check/mutability_errors.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use rustc::hir;
+use rustc::hir::Node;
 use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Mir};
 use rustc::mir::{Mutability, Place, Projection, ProjectionElem, Static};
 use rustc::ty::{self, TyCtxt};
@@ -246,7 +247,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
                     .var_hir_id
                     .assert_crate_local();
                 let upvar_node_id = self.tcx.hir.hir_to_node_id(upvar_hir_id);
-                if let Some(hir::map::NodeBinding(pat)) = self.tcx.hir.find(upvar_node_id) {
+                if let Some(Node::Binding(pat)) = self.tcx.hir.find(upvar_node_id) {
                     if let hir::PatKind::Binding(
                         hir::BindingAnnotation::Unannotated,
                         _,
diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs
index aa88fa11174..a35117f2e35 100644
--- a/src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs
+++ b/src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs
@@ -17,7 +17,7 @@ use rustc::mir::visit::{MirVisitable, PlaceContext, Visitor};
 use rustc::mir::{Local, Location, Mir};
 use rustc::ty::{RegionVid, TyCtxt};
 use rustc_data_structures::fx::FxHashSet;
-use util::liveness::{self, DefUse, LivenessMode};
+use util::liveness::{self, DefUse};
 
 crate fn find<'tcx>(
     mir: &Mir<'tcx>,
@@ -32,10 +32,6 @@ crate fn find<'tcx>(
         tcx,
         region_vid,
         start_point,
-        liveness_mode: LivenessMode {
-            include_regular_use: true,
-            include_drops: true,
-        },
     };
 
     uf.find()
@@ -47,7 +43,6 @@ struct UseFinder<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
     tcx: TyCtxt<'cx, 'gcx, 'tcx>,
     region_vid: RegionVid,
     start_point: Location,
-    liveness_mode: LivenessMode,
 }
 
 impl<'cx, 'gcx, 'tcx> UseFinder<'cx, 'gcx, 'tcx> {
@@ -108,7 +103,6 @@ impl<'cx, 'gcx, 'tcx> UseFinder<'cx, 'gcx, 'tcx> {
             mir: self.mir,
             tcx: self.tcx,
             region_vid: self.region_vid,
-            liveness_mode: self.liveness_mode,
             def_use_result: None,
         };
 
@@ -122,7 +116,6 @@ struct DefUseVisitor<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
     mir: &'cx Mir<'tcx>,
     tcx: TyCtxt<'cx, 'gcx, 'tcx>,
     region_vid: RegionVid,
-    liveness_mode: LivenessMode,
     def_use_result: Option<DefUseResult>,
 }
 
@@ -146,23 +139,12 @@ impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'gcx, 'tcx> {
         });
 
         if found_it {
-            match liveness::categorize(context, self.liveness_mode) {
-                Some(DefUse::Def) => {
-                    self.def_use_result = Some(DefUseResult::Def);
-                }
-
-                Some(DefUse::Use) => {
-                    self.def_use_result = if context.is_drop() {
-                        Some(DefUseResult::UseDrop { local })
-                    } else {
-                        Some(DefUseResult::UseLive { local })
-                    };
-                }
-
-                None => {
-                    self.def_use_result = None;
-                }
-            }
+            self.def_use_result = match liveness::categorize(context) {
+                Some(DefUse::Def) => Some(DefUseResult::Def),
+                Some(DefUse::Use) => Some(DefUseResult::UseLive { local }),
+                Some(DefUse::Drop) => Some(DefUseResult::UseDrop { local }),
+                None => None,
+            };
         }
     }
 }
diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs
index 40df78d6bfd..b80f9784d6f 100644
--- a/src/librustc_mir/borrow_check/nll/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/mod.rs
@@ -12,7 +12,7 @@ use borrow_check::borrow_set::BorrowSet;
 use borrow_check::location::{LocationIndex, LocationTable};
 use borrow_check::nll::facts::AllFactsExt;
 use borrow_check::nll::type_check::{MirTypeckResults, MirTypeckRegionConstraints};
-use borrow_check::nll::type_check::liveness::liveness_map::{NllLivenessMap, LocalWithRegion};
+use borrow_check::nll::type_check::liveness::liveness_map::NllLivenessMap;
 use borrow_check::nll::region_infer::values::RegionValueElements;
 use dataflow::indexes::BorrowIndex;
 use dataflow::move_paths::MoveData;
@@ -22,9 +22,7 @@ use rustc::hir::def_id::DefId;
 use rustc::infer::InferCtxt;
 use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Mir};
 use rustc::ty::{self, RegionKind, RegionVid};
-use rustc::util::nodemap::FxHashMap;
 use rustc_errors::Diagnostic;
-use std::collections::BTreeSet;
 use std::fmt::Debug;
 use std::env;
 use std::io;
@@ -32,12 +30,11 @@ use std::path::PathBuf;
 use std::rc::Rc;
 use std::str::FromStr;
 use transform::MirSource;
-use util::liveness::{LivenessResults, LiveVarSet};
 
 use self::mir_util::PassWhere;
 use polonius_engine::{Algorithm, Output};
 use util as mir_util;
-use util::pretty::{self, ALIGN};
+use util::pretty;
 
 mod constraint_generation;
 pub mod explain_borrow;
@@ -111,8 +108,6 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
     let MirTypeckResults {
         constraints,
         universal_region_relations,
-        liveness,
-        liveness_map,
     } = type_check::type_check(
         infcx,
         param_env,
@@ -205,8 +200,6 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
     // write unit-tests, as well as helping with debugging.
     dump_mir_results(
         infcx,
-        &liveness,
-        &liveness_map,
         MirSource::item(def_id),
         &mir,
         &regioncx,
@@ -222,8 +215,6 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
 
 fn dump_mir_results<'a, 'gcx, 'tcx>(
     infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-    liveness: &LivenessResults<LocalWithRegion>,
-    liveness_map: &NllLivenessMap,
     source: MirSource,
     mir: &Mir<'tcx>,
     regioncx: &RegionInferenceContext,
@@ -233,34 +224,6 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
         return;
     }
 
-    let regular_liveness_per_location: FxHashMap<_, _> = mir
-        .basic_blocks()
-        .indices()
-        .flat_map(|bb| {
-            let mut results = vec![];
-            liveness
-                .regular
-                .simulate_block(&mir, bb, liveness_map, |location, local_set| {
-                    results.push((location, local_set.clone()));
-                });
-            results
-        })
-        .collect();
-
-    let drop_liveness_per_location: FxHashMap<_, _> = mir
-        .basic_blocks()
-        .indices()
-        .flat_map(|bb| {
-            let mut results = vec![];
-            liveness
-                .drop
-                .simulate_block(&mir, bb, liveness_map, |location, local_set| {
-                    results.push((location, local_set.clone()));
-                });
-            results
-        })
-        .collect();
-
     mir_util::dump_mir(
         infcx.tcx,
         None,
@@ -283,26 +246,10 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
                     }
                 }
 
-                PassWhere::BeforeLocation(location) => {
-                    let s = live_variable_set(
-                        &regular_liveness_per_location[&location],
-                        &drop_liveness_per_location[&location],
-                    );
-                    writeln!(
-                        out,
-                        "{:ALIGN$} | Live variables on entry to {:?}: {}",
-                        "",
-                        location,
-                        s,
-                        ALIGN = ALIGN
-                    )?;
+                PassWhere::BeforeLocation(_) => {
                 }
 
-                // After each basic block, dump out the values
-                // that are live on exit from the basic block.
-                PassWhere::AfterTerminator(bb) => {
-                    let s = live_variable_set(&liveness.regular.outs[bb], &liveness.drop.outs[bb]);
-                    writeln!(out, "    | Live variables on exit from {:?}: {}", bb, s)?;
+                PassWhere::AfterTerminator(_) => {
                 }
 
                 PassWhere::BeforeBlock(_) | PassWhere::AfterLocation(_) | PassWhere::AfterCFG => {}
@@ -420,33 +367,3 @@ impl ToRegionVid for RegionVid {
         self
     }
 }
-
-fn live_variable_set(
-    regular: &LiveVarSet<LocalWithRegion>,
-    drops: &LiveVarSet<LocalWithRegion>
-) -> String {
-    // sort and deduplicate:
-    let all_locals: BTreeSet<_> = regular.iter().chain(drops.iter()).collect();
-
-    // construct a string with each local, including `(drop)` if it is
-    // only dropped, versus a regular use.
-    let mut string = String::new();
-    for local in all_locals {
-        string.push_str(&format!("{:?}", local));
-
-        if !regular.contains(&local) {
-            assert!(drops.contains(&local));
-            string.push_str(" (drop)");
-        }
-
-        string.push_str(", ");
-    }
-
-    let len = if string.is_empty() {
-        0
-    } else {
-        string.len() - 2
-    };
-
-    format!("[{}]", &string[..len])
-}
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs
index 8db5809e53f..ae5d5790673 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs
@@ -10,7 +10,7 @@
 
 use rustc::mir::{BasicBlock, Location, Mir};
 use rustc::ty::{self, RegionVid};
-use rustc_data_structures::bitvec::SparseBitMatrix;
+use rustc_data_structures::bitvec::{BitArray, SparseBitMatrix};
 use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::indexed_vec::IndexVec;
 use std::fmt::Debug;
@@ -20,13 +20,18 @@ use std::rc::Rc;
 crate struct RegionValueElements {
     /// For each basic block, how many points are contained within?
     statements_before_block: IndexVec<BasicBlock, usize>,
+
+    /// Map backward from each point to the basic block that it
+    /// belongs to.
+    basic_blocks: IndexVec<PointIndex, BasicBlock>,
+
     num_points: usize,
 }
 
 impl RegionValueElements {
     crate fn new(mir: &Mir<'_>) -> Self {
         let mut num_points = 0;
-        let statements_before_block = mir
+        let statements_before_block: IndexVec<BasicBlock, usize> = mir
             .basic_blocks()
             .iter()
             .map(|block_data| {
@@ -41,14 +46,25 @@ impl RegionValueElements {
         );
         debug!("RegionValueElements: num_points={:#?}", num_points);
 
+        let mut basic_blocks = IndexVec::with_capacity(num_points);
+        for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
+            basic_blocks.extend((0 .. bb_data.statements.len() + 1).map(|_| bb));
+        }
+
         Self {
             statements_before_block,
+            basic_blocks,
             num_points,
         }
     }
 
+    /// Total number of point indices
+    crate fn num_points(&self) -> usize {
+        self.num_points
+    }
+
     /// Converts a `Location` into a `PointIndex`. O(1).
-    fn point_from_location(&self, location: Location) -> PointIndex {
+    crate fn point_from_location(&self, location: Location) -> PointIndex {
         let Location {
             block,
             statement_index,
@@ -57,39 +73,50 @@ impl RegionValueElements {
         PointIndex::new(start_index + statement_index)
     }
 
-    /// Converts a `PointIndex` back to a location. O(N) where N is
-    /// the number of blocks; could be faster if we ever cared.
-    crate fn to_location(&self, i: PointIndex) -> Location {
-        let point_index = i.index();
-
-        // Find the basic block. We have a vector with the
-        // starting index of the statement in each block. Imagine
-        // we have statement #22, and we have a vector like:
-        //
-        // [0, 10, 20]
-        //
-        // In that case, this represents point_index 2 of
-        // basic block BB2. We know this because BB0 accounts for
-        // 0..10, BB1 accounts for 11..20, and BB2 accounts for
-        // 20...
-        //
-        // To compute this, we could do a binary search, but
-        // because I am lazy we instead iterate through to find
-        // the last point where the "first index" (0, 10, or 20)
-        // was less than the statement index (22). In our case, this will
-        // be (BB2, 20).
-        //
-        // Nit: we could do a binary search here but I'm too lazy.
-        let (block, &first_index) = self
-            .statements_before_block
-            .iter_enumerated()
-            .filter(|(_, first_index)| **first_index <= point_index)
-            .last()
-            .unwrap();
-
-        Location {
-            block,
-            statement_index: point_index - first_index,
+    /// Converts a `Location` into a `PointIndex`. O(1).
+    crate fn entry_point(&self, block: BasicBlock) -> PointIndex {
+        let start_index = self.statements_before_block[block];
+        PointIndex::new(start_index)
+    }
+
+    /// Converts a `PointIndex` back to a location. O(1).
+    crate fn to_location(&self, index: PointIndex) -> Location {
+        assert!(index.index() < self.num_points);
+        let block = self.basic_blocks[index];
+        let start_index = self.statements_before_block[block];
+        let statement_index = index.index() - start_index;
+        Location { block, statement_index }
+    }
+
+    /// Sometimes we get point-indices back from bitsets that may be
+    /// out of range (because they round up to the nearest 2^N number
+    /// of bits). Use this function to filter such points out if you
+    /// like.
+    crate fn point_in_range(&self, index: PointIndex) -> bool {
+        index.index() < self.num_points
+    }
+
+    /// Pushes all predecessors of `index` onto `stack`.
+    crate fn push_predecessors(
+        &self,
+        mir: &Mir<'_>,
+        index: PointIndex,
+        stack: &mut Vec<PointIndex>,
+    ) {
+        let Location { block, statement_index } = self.to_location(index);
+        if statement_index == 0 {
+            // If this is a basic block head, then the predecessors are
+            // the the terminators of other basic blocks
+            stack.extend(
+                mir
+                    .predecessors_for(block)
+                    .iter()
+                    .map(|&pred_bb| mir.terminator_loc(pred_bb))
+                    .map(|pred_loc| self.point_from_location(pred_loc)),
+            );
+        } else {
+            // Otherwise, the pred is just the previous statement
+            stack.push(PointIndex::new(index.index() - 1));
         }
     }
 }
@@ -151,6 +178,13 @@ impl<N: Idx> LivenessValues<N> {
         self.points.add(row, index)
     }
 
+    /// Adds all the elements in the given bit array into the given
+    /// region. Returns true if any of them are newly added.
+    crate fn add_elements(&mut self, row: N, locations: &BitArray<PointIndex>) -> bool {
+        debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations);
+        self.points.merge_into(row, locations)
+    }
+
     /// Adds all the control-flow points to the values for `r`.
     crate fn add_all_points(&mut self, row: N) {
         self.points.add_all(row);
@@ -169,6 +203,7 @@ impl<N: Idx> LivenessValues<N> {
                 .row(r)
                 .into_iter()
                 .flat_map(|set| set.iter())
+                .take_while(|&p| self.elements.point_in_range(p))
                 .map(|p| self.elements.to_location(p))
                 .map(RegionElement::Location),
         )
@@ -277,7 +312,11 @@ impl<N: Idx> RegionValues<N> {
         self.points
             .row(r)
             .into_iter()
-            .flat_map(move |set| set.iter().map(move |p| self.elements.to_location(p)))
+            .flat_map(move |set| {
+                set.iter()
+                    .take_while(move |&p| self.elements.point_in_range(p))
+                    .map(move |p| self.elements.to_location(p))
+            })
     }
 
     /// Returns just the universal regions that are contained in a given region's value.
@@ -366,6 +405,19 @@ impl ToElementIndex for ty::UniverseIndex {
     }
 }
 
+crate fn location_set_str(
+    elements: &RegionValueElements,
+    points: impl IntoIterator<Item = PointIndex>,
+) -> String {
+    region_value_str(
+        points
+            .into_iter()
+            .take_while(|&p| elements.point_in_range(p))
+            .map(|p| elements.to_location(p))
+            .map(RegionElement::Location),
+    )
+}
+
 fn region_value_str(elements: impl IntoIterator<Item = RegionElement>) -> String {
     let mut result = String::new();
     result.push_str("{");
diff --git a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs
index e4b1aacd34f..e21c490622c 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs
@@ -14,7 +14,7 @@ use borrow_check::nll::type_check::constraint_conversion;
 use borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints};
 use borrow_check::nll::universal_regions::UniversalRegions;
 use borrow_check::nll::ToRegionVid;
-use rustc::hir::def_id::DefId;
+use rustc::infer::canonical::QueryRegionConstraint;
 use rustc::infer::outlives::free_region_map::FreeRegionRelations;
 use rustc::infer::region_constraints::GenericKind;
 use rustc::infer::InferCtxt;
@@ -23,7 +23,6 @@ use rustc::traits::query::type_op::{self, TypeOp};
 use rustc::ty::{self, RegionVid, Ty};
 use rustc_data_structures::transitive_relation::TransitiveRelation;
 use std::rc::Rc;
-use syntax::ast;
 
 #[derive(Debug)]
 crate struct UniversalRegionRelations<'tcx> {
@@ -67,7 +66,6 @@ crate struct CreateResult<'tcx> {
 
 crate fn create(
     infcx: &InferCtxt<'_, '_, 'tcx>,
-    mir_def_id: DefId,
     param_env: ty::ParamEnv<'tcx>,
     location_table: &LocationTable,
     implicit_region_bound: Option<ty::Region<'tcx>>,
@@ -75,11 +73,8 @@ crate fn create(
     constraints: &mut MirTypeckRegionConstraints<'tcx>,
     all_facts: &mut Option<AllFacts>,
 ) -> CreateResult<'tcx> {
-    let mir_node_id = infcx.tcx.hir.as_local_node_id(mir_def_id).unwrap();
     UniversalRegionRelationsBuilder {
         infcx,
-        mir_def_id,
-        mir_node_id,
         param_env,
         implicit_region_bound,
         constraints,
@@ -212,8 +207,6 @@ impl UniversalRegionRelations<'tcx> {
 
 struct UniversalRegionRelationsBuilder<'this, 'gcx: 'tcx, 'tcx: 'this> {
     infcx: &'this InferCtxt<'this, 'gcx, 'tcx>,
-    mir_def_id: DefId,
-    mir_node_id: ast::NodeId,
     param_env: ty::ParamEnv<'tcx>,
     location_table: &'this LocationTable,
     universal_regions: Rc<UniversalRegions<'tcx>>,
@@ -248,14 +241,16 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> {
         let constraint_sets: Vec<_> = unnormalized_input_output_tys
             .flat_map(|ty| {
                 debug!("build: input_or_output={:?}", ty);
-                let (ty, constraints) = self
+                let (ty, constraints1) = self
                     .param_env
                     .and(type_op::normalize::Normalize::new(ty))
                     .fully_perform(self.infcx)
                     .unwrap_or_else(|_| bug!("failed to normalize {:?}", ty));
-                self.add_implied_bounds(ty);
+                let constraints2 = self.add_implied_bounds(ty);
                 normalized_inputs_and_output.push(ty);
-                constraints
+                constraints1
+                    .into_iter()
+                    .chain(constraints2)
             })
             .collect();
 
@@ -306,13 +301,15 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> {
     /// either the return type of the MIR or one of its arguments. At
     /// the same time, compute and add any implied bounds that come
     /// from this local.
-    fn add_implied_bounds(&mut self, ty: Ty<'tcx>) {
+    fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<Rc<Vec<QueryRegionConstraint<'tcx>>>> {
         debug!("add_implied_bounds(ty={:?})", ty);
-        let span = self.infcx.tcx.def_span(self.mir_def_id);
-        let bounds = self
-            .infcx
-            .implied_outlives_bounds(self.param_env, self.mir_node_id, ty, span);
+        let (bounds, constraints) =
+            self.param_env
+            .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
+            .fully_perform(self.infcx)
+            .unwrap_or_else(|_| bug!("failed to compute implied bounds {:?}", ty));
         self.add_outlives_bounds(bounds);
+        constraints
     }
 
     /// Registers the `OutlivesBound` items from `outlives_bounds` in
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs
index 89e8c76b22f..15affbbc27a 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/liveness_map.rs
@@ -10,9 +10,9 @@
 
 //! For the NLL computation, we need to compute liveness, but only for those
 //! local variables whose types contain regions. The others are not of interest
-//! to us. This file defines a new index type (LocalWithRegion) that indexes into
+//! to us. This file defines a new index type (LiveVar) that indexes into
 //! a list of "variables whose type contain regions". It also defines a map from
-//! Local to LocalWithRegion and vice versa -- this map can be given to the
+//! Local to LiveVar and vice versa -- this map can be given to the
 //! liveness code so that it only operates over variables with regions in their
 //! types, instead of all variables.
 
@@ -23,7 +23,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use util::liveness::LiveVariableMap;
 
-/// Map between Local and LocalWithRegion indices: the purpose of this
+/// Map between Local and LiveVar indices: the purpose of this
 /// map is to define the subset of local variables for which we need
 /// to do a liveness computation. We only need to compute whether a
 /// variable `X` is live if that variable contains some region `R` in
@@ -32,10 +32,10 @@ use util::liveness::LiveVariableMap;
 crate struct NllLivenessMap {
     /// For each local variable, contains `Some(i)` if liveness is
     /// needed for this variable.
-    pub from_local: IndexVec<Local, Option<LocalWithRegion>>,
+    pub from_local: IndexVec<Local, Option<LiveVar>>,
 
-    /// For each `LocalWithRegion`, maps back to the original `Local` index.
-    pub to_local: IndexVec<LocalWithRegion, Local>,
+    /// For each `LiveVar`, maps back to the original `Local` index.
+    pub to_local: IndexVec<LiveVar, Local>,
 }
 
 impl LiveVariableMap for NllLivenessMap {
@@ -43,7 +43,7 @@ impl LiveVariableMap for NllLivenessMap {
         self.from_local[local]
     }
 
-    type LiveVar = LocalWithRegion;
+    type LiveVar = LiveVar;
 
     fn from_live_var(&self, local: Self::LiveVar) -> Local {
         self.to_local[local]
@@ -93,5 +93,10 @@ impl NllLivenessMap {
     }
 }
 
-/// Index given to each local variable whose type contains a region.
-newtype_index!(LocalWithRegion);
+/// Index given to each local variable for which we need to
+/// compute liveness information. For many locals, we are able to
+/// skip liveness information: for example, those variables whose
+/// types contain no regions.
+newtype_index!(
+    LiveVar
+);
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs
new file mode 100644
index 00000000000..73d285c2f2e
--- /dev/null
+++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs
@@ -0,0 +1,159 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use borrow_check::nll::region_infer::values::{PointIndex, RegionValueElements};
+use borrow_check::nll::type_check::liveness::liveness_map::{LiveVar, NllLivenessMap};
+use rustc::mir::visit::{PlaceContext, Visitor};
+use rustc::mir::{Local, Location, Mir};
+use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_data_structures::vec_linked_list as vll;
+use util::liveness::{categorize, DefUse, LiveVariableMap};
+
+/// A map that cross references each local with the locations where it
+/// is defined (assigned), used, or dropped. Used during liveness
+/// computation.
+crate struct LocalUseMap<'me> {
+    liveness_map: &'me NllLivenessMap,
+
+    /// Head of a linked list of **definitions** of each variable --
+    /// definition in this context means assignment, e.g. `x` is
+    /// defined in `x = y` but not `y`; that first def is the head of
+    /// a linked list that lets you enumerate all places the variable
+    /// is assigned.
+    first_def_at: IndexVec<LiveVar, Option<AppearanceIndex>>,
+
+    /// Head of a linked list of **uses** of each variable -- use in
+    /// this context means that the existing value of the variable is
+    /// read or modified. e.g., `y` is used in `x = y` but not `x`.
+    /// Note that `DROP(x)` terminators are excluded from this list.
+    first_use_at: IndexVec<LiveVar, Option<AppearanceIndex>>,
+
+    /// Head of a linked list of **drops** of each variable -- these
+    /// are a special category of uses corresponding to the drop that
+    /// we add for each local variable.
+    first_drop_at: IndexVec<LiveVar, Option<AppearanceIndex>>,
+
+    appearances: IndexVec<AppearanceIndex, Appearance>,
+}
+
+struct Appearance {
+    point_index: PointIndex,
+    next: Option<AppearanceIndex>,
+}
+
+newtype_index!(AppearanceIndex);
+
+impl vll::LinkElem for Appearance {
+    type LinkIndex = AppearanceIndex;
+
+    fn next(elem: &Self) -> Option<AppearanceIndex> {
+        elem.next
+    }
+}
+
+impl LocalUseMap<'me> {
+    crate fn build(
+        liveness_map: &'me NllLivenessMap,
+        elements: &RegionValueElements,
+        mir: &Mir<'_>,
+    ) -> Self {
+        let nones = IndexVec::from_elem_n(None, liveness_map.num_variables());
+        let mut local_use_map = LocalUseMap {
+            liveness_map,
+            first_def_at: nones.clone(),
+            first_use_at: nones.clone(),
+            first_drop_at: nones,
+            appearances: IndexVec::new(),
+        };
+
+        LocalUseMapBuild {
+            local_use_map: &mut local_use_map,
+            elements,
+        }.visit_mir(mir);
+
+        local_use_map
+    }
+
+    crate fn defs(&self, local: LiveVar) -> impl Iterator<Item = PointIndex> + '_ {
+        vll::iter(self.first_def_at[local], &self.appearances)
+            .map(move |aa| self.appearances[aa].point_index)
+    }
+
+    crate fn uses(&self, local: LiveVar) -> impl Iterator<Item = PointIndex> + '_ {
+        vll::iter(self.first_use_at[local], &self.appearances)
+            .map(move |aa| self.appearances[aa].point_index)
+    }
+
+    crate fn drops(&self, local: LiveVar) -> impl Iterator<Item = PointIndex> + '_ {
+        vll::iter(self.first_drop_at[local], &self.appearances)
+            .map(move |aa| self.appearances[aa].point_index)
+    }
+}
+
+struct LocalUseMapBuild<'me, 'map: 'me> {
+    local_use_map: &'me mut LocalUseMap<'map>,
+    elements: &'me RegionValueElements,
+}
+
+impl LocalUseMapBuild<'_, '_> {
+    fn insert_def(&mut self, local: LiveVar, location: Location) {
+        Self::insert(
+            self.elements,
+            &mut self.local_use_map.first_def_at[local],
+            &mut self.local_use_map.appearances,
+            location,
+        );
+    }
+
+    fn insert_use(&mut self, local: LiveVar, location: Location) {
+        Self::insert(
+            self.elements,
+            &mut self.local_use_map.first_use_at[local],
+            &mut self.local_use_map.appearances,
+            location,
+        );
+    }
+
+    fn insert_drop(&mut self, local: LiveVar, location: Location) {
+        Self::insert(
+            self.elements,
+            &mut self.local_use_map.first_drop_at[local],
+            &mut self.local_use_map.appearances,
+            location,
+        );
+    }
+
+    fn insert(
+        elements: &RegionValueElements,
+        first_appearance: &mut Option<AppearanceIndex>,
+        appearances: &mut IndexVec<AppearanceIndex, Appearance>,
+        location: Location,
+    ) {
+        let point_index = elements.point_from_location(location);
+        let appearance_index = appearances.push(Appearance {
+            point_index,
+            next: *first_appearance,
+        });
+        *first_appearance = Some(appearance_index);
+    }
+}
+
+impl Visitor<'tcx> for LocalUseMapBuild<'_, '_> {
+    fn visit_local(&mut self, &local: &Local, context: PlaceContext<'tcx>, location: Location) {
+        if let Some(local_with_region) = self.local_use_map.liveness_map.from_local(local) {
+            match categorize(context) {
+                Some(DefUse::Def) => self.insert_def(local_with_region, location),
+                Some(DefUse::Use) => self.insert_use(local_with_region, location),
+                Some(DefUse::Drop) => self.insert_drop(local_with_region, location),
+                _ => (),
+            }
+        }
+    }
+}
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs
index a9b69cfe761..b3fc73e9b7b 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs
@@ -8,26 +8,23 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use borrow_check::nll::region_infer::values::RegionValueElements;
 use borrow_check::nll::constraints::ConstraintSet;
-use borrow_check::nll::type_check::AtLocation;
-use borrow_check::nll::{LocalWithRegion, NllLivenessMap};
+use borrow_check::nll::NllLivenessMap;
 use borrow_check::nll::universal_regions::UniversalRegions;
-use dataflow::move_paths::{HasMoveData, MoveData};
+use dataflow::move_paths::MoveData;
 use dataflow::MaybeInitializedPlaces;
-use dataflow::{FlowAtLocation, FlowsAtLocation};
-use rustc::infer::canonical::QueryRegionConstraint;
-use rustc::mir::{BasicBlock, Location, Mir};
-use rustc::traits::query::dropck_outlives::DropckOutlivesResult;
-use rustc::traits::query::type_op::outlives::DropckOutlives;
-use rustc::traits::query::type_op::TypeOp;
-use rustc::ty::{RegionVid, Ty, TypeFoldable};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use dataflow::FlowAtLocation;
+use rustc::mir::Mir;
+use rustc::ty::RegionVid;
+use rustc_data_structures::fx::FxHashSet;
 use std::rc::Rc;
-use util::liveness::{LiveVariableMap, LivenessResults};
 
 use super::TypeChecker;
 
 crate mod liveness_map;
+mod local_use_map;
+mod trace;
 
 /// Combines liveness analysis with initialization analysis to
 /// determine which variables are live at which points, both due to
@@ -38,40 +35,23 @@ crate mod liveness_map;
 /// NB. This computation requires normalization; therefore, it must be
 /// performed before
 pub(super) fn generate<'gcx, 'tcx>(
-    cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
+    typeck: &mut TypeChecker<'_, 'gcx, 'tcx>,
     mir: &Mir<'tcx>,
+    elements: &Rc<RegionValueElements>,
     flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
     move_data: &MoveData<'tcx>,
-) -> (LivenessResults<LocalWithRegion>, NllLivenessMap) {
+) {
+    debug!("liveness::generate");
     let free_regions = {
-        let borrowck_context = cx.borrowck_context.as_ref().unwrap();
+        let borrowck_context = typeck.borrowck_context.as_ref().unwrap();
         regions_that_outlive_free_regions(
-            cx.infcx.num_region_vars(),
+            typeck.infcx.num_region_vars(),
             &borrowck_context.universal_regions,
             &borrowck_context.constraints.outlives_constraints,
         )
     };
-    let liveness_map = NllLivenessMap::compute(cx.tcx(), &free_regions, mir);
-    let liveness = LivenessResults::compute(mir, &liveness_map);
-
-    // For everything else, it is only live where it is actually used.
-    if !liveness_map.is_empty() {
-        let mut generator = TypeLivenessGenerator {
-            cx,
-            mir,
-            liveness: &liveness,
-            flow_inits,
-            move_data,
-            drop_data: FxHashMap(),
-            map: &liveness_map,
-        };
-
-        for bb in mir.basic_blocks().indices() {
-            generator.add_liveness_constraints(bb);
-        }
-    }
-
-    (liveness, liveness_map)
+    let liveness_map = NllLivenessMap::compute(typeck.tcx(), &free_regions, mir);
+    trace::trace(typeck, mir, elements, flow_inits, move_data, &liveness_map);
 }
 
 /// Compute all regions that are (currently) known to outlive free
@@ -112,198 +92,3 @@ fn regions_that_outlive_free_regions(
     // Return the final set of things we visited.
     outlives_free_region
 }
-
-struct TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx>
-where
-    'typeck: 'gen,
-    'flow: 'gen,
-    'tcx: 'typeck + 'flow,
-    'gcx: 'tcx,
-{
-    cx: &'gen mut TypeChecker<'typeck, 'gcx, 'tcx>,
-    mir: &'gen Mir<'tcx>,
-    liveness: &'gen LivenessResults<LocalWithRegion>,
-    flow_inits: &'gen mut FlowAtLocation<MaybeInitializedPlaces<'flow, 'gcx, 'tcx>>,
-    move_data: &'gen MoveData<'tcx>,
-    drop_data: FxHashMap<Ty<'tcx>, DropData<'tcx>>,
-    map: &'gen NllLivenessMap,
-}
-
-struct DropData<'tcx> {
-    dropck_result: DropckOutlivesResult<'tcx>,
-    region_constraint_data: Option<Rc<Vec<QueryRegionConstraint<'tcx>>>>,
-}
-
-impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx> {
-    /// Liveness constraints:
-    ///
-    /// > If a variable V is live at point P, then all regions R in the type of V
-    /// > must include the point P.
-    fn add_liveness_constraints(&mut self, bb: BasicBlock) {
-        debug!("add_liveness_constraints(bb={:?})", bb);
-
-        self.liveness
-            .regular
-            .simulate_block(self.mir, bb, self.map, |location, live_locals| {
-                for live_local in live_locals.iter() {
-                    let local = self.map.from_live_var(live_local);
-                    let live_local_ty = self.mir.local_decls[local].ty;
-                    Self::push_type_live_constraint(&mut self.cx, live_local_ty, location);
-                }
-            });
-
-        let mut all_live_locals: Vec<(Location, Vec<LocalWithRegion>)> = vec![];
-        self.liveness
-            .drop
-            .simulate_block(self.mir, bb, self.map, |location, live_locals| {
-                all_live_locals.push((location, live_locals.iter().collect()));
-            });
-        debug!(
-            "add_liveness_constraints: all_live_locals={:#?}",
-            all_live_locals
-        );
-
-        let terminator_index = self.mir.basic_blocks()[bb].statements.len();
-        self.flow_inits.reset_to_entry_of(bb);
-        while let Some((location, live_locals)) = all_live_locals.pop() {
-            for live_local in live_locals {
-                debug!(
-                    "add_liveness_constraints: location={:?} live_local={:?}",
-                    location, live_local
-                );
-
-                if log_enabled!(::log::Level::Debug) {
-                    self.flow_inits.each_state_bit(|mpi_init| {
-                        debug!(
-                            "add_liveness_constraints: location={:?} initialized={:?}",
-                            location,
-                            &self.flow_inits.operator().move_data().move_paths[mpi_init]
-                        );
-                    });
-                }
-
-                let local = self.map.from_live_var(live_local);
-                let mpi = self.move_data.rev_lookup.find_local(local);
-                if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) {
-                    debug!(
-                        "add_liveness_constraints: mpi={:?} has initialized child {:?}",
-                        self.move_data.move_paths[mpi],
-                        self.move_data.move_paths[initialized_child]
-                    );
-
-                    let local = self.map.from_live_var(live_local);
-                    let live_local_ty = self.mir.local_decls[local].ty;
-                    self.add_drop_live_constraint(live_local, live_local_ty, location);
-                }
-            }
-
-            if location.statement_index == terminator_index {
-                debug!(
-                    "add_liveness_constraints: reconstruct_terminator_effect from {:#?}",
-                    location
-                );
-                self.flow_inits.reconstruct_terminator_effect(location);
-            } else {
-                debug!(
-                    "add_liveness_constraints: reconstruct_statement_effect from {:#?}",
-                    location
-                );
-                self.flow_inits.reconstruct_statement_effect(location);
-            }
-            self.flow_inits.apply_local_effect(location);
-        }
-    }
-
-    /// Some variable with type `live_ty` is "regular live" at
-    /// `location` -- i.e., it may be used later. This means that all
-    /// regions appearing in the type `live_ty` must be live at
-    /// `location`.
-    fn push_type_live_constraint<T>(
-        cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
-        value: T,
-        location: Location,
-    ) where
-        T: TypeFoldable<'tcx>,
-    {
-        debug!(
-            "push_type_live_constraint(live_ty={:?}, location={:?})",
-            value, location
-        );
-
-        cx.tcx().for_each_free_region(&value, |live_region| {
-            if let Some(ref mut borrowck_context) = cx.borrowck_context {
-                let region_vid = borrowck_context
-                    .universal_regions
-                    .to_region_vid(live_region);
-                borrowck_context
-                    .constraints
-                    .liveness_constraints
-                    .add_element(region_vid, location);
-
-                if let Some(all_facts) = borrowck_context.all_facts {
-                    let start_index = borrowck_context.location_table.start_index(location);
-                    all_facts.region_live_at.push((region_vid, start_index));
-
-                    let mid_index = borrowck_context.location_table.mid_index(location);
-                    all_facts.region_live_at.push((region_vid, mid_index));
-                }
-            }
-        });
-    }
-
-    /// Some variable with type `live_ty` is "drop live" at `location`
-    /// -- i.e., it may be dropped later. This means that *some* of
-    /// the regions in its type must be live at `location`. The
-    /// precise set will depend on the dropck constraints, and in
-    /// particular this takes `#[may_dangle]` into account.
-    fn add_drop_live_constraint(
-        &mut self,
-        dropped_local: LocalWithRegion,
-        dropped_ty: Ty<'tcx>,
-        location: Location,
-    ) {
-        debug!(
-            "add_drop_live_constraint(dropped_local={:?}, dropped_ty={:?}, location={:?})",
-            dropped_local, dropped_ty, location
-        );
-
-        let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({
-            let cx = &mut self.cx;
-            move || Self::compute_drop_data(cx, dropped_ty)
-        });
-
-        if let Some(data) = &drop_data.region_constraint_data {
-            self.cx.push_region_constraints(location.boring(), data);
-        }
-
-        drop_data.dropck_result.report_overflows(
-            self.cx.infcx.tcx,
-            self.mir.source_info(location).span,
-            dropped_ty,
-        );
-
-        // All things in the `outlives` array may be touched by
-        // the destructor and must be live at this point.
-        for &kind in &drop_data.dropck_result.kinds {
-            Self::push_type_live_constraint(&mut self.cx, kind, location);
-        }
-    }
-
-    fn compute_drop_data(
-        cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
-        dropped_ty: Ty<'tcx>,
-    ) -> DropData<'tcx> {
-        debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,);
-
-        let param_env = cx.param_env;
-        let (dropck_result, region_constraint_data) = param_env
-            .and(DropckOutlives::new(dropped_ty))
-            .fully_perform(cx.infcx)
-            .unwrap();
-
-        DropData {
-            dropck_result,
-            region_constraint_data,
-        }
-    }
-}
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs
new file mode 100644
index 00000000000..79589ce9733
--- /dev/null
+++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs
@@ -0,0 +1,553 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use borrow_check::nll::region_infer::values::{self, PointIndex, RegionValueElements};
+use borrow_check::nll::type_check::liveness::liveness_map::{LiveVar, NllLivenessMap};
+use borrow_check::nll::type_check::liveness::local_use_map::LocalUseMap;
+use borrow_check::nll::type_check::AtLocation;
+use borrow_check::nll::type_check::TypeChecker;
+use dataflow::move_paths::indexes::MovePathIndex;
+use dataflow::move_paths::MoveData;
+use dataflow::{FlowAtLocation, FlowsAtLocation, MaybeInitializedPlaces};
+use rustc::infer::canonical::QueryRegionConstraint;
+use rustc::mir::{BasicBlock, Local, Location, Mir};
+use rustc::traits::query::dropck_outlives::DropckOutlivesResult;
+use rustc::traits::query::type_op::outlives::DropckOutlives;
+use rustc::traits::query::type_op::TypeOp;
+use rustc::ty::{Ty, TypeFoldable};
+use rustc_data_structures::bitvec::BitArray;
+use rustc_data_structures::fx::FxHashMap;
+use std::rc::Rc;
+use util::liveness::LiveVariableMap;
+
+/// This is the heart of the liveness computation. For each variable X
+/// that requires a liveness computation, it walks over all the uses
+/// of X and does a reverse depth-first search ("trace") through the
+/// MIR. This search stops when we find a definition of that variable.
+/// The points visited in this search is the USE-LIVE set for the variable;
+/// of those points is added to all the regions that appear in the variable's
+/// type.
+///
+/// We then also walks through each *drop* of those variables and does
+/// another search, stopping when we reach a use or definition. This
+/// is the DROP-LIVE set of points. Each of the points in the
+/// DROP-LIVE set are to the liveness sets for regions found in the
+/// `dropck_outlives` result of the variable's type (in particular,
+/// this respects `#[may_dangle]` annotations).
+pub(super) fn trace(
+    typeck: &mut TypeChecker<'_, 'gcx, 'tcx>,
+    mir: &Mir<'tcx>,
+    elements: &Rc<RegionValueElements>,
+    flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
+    move_data: &MoveData<'tcx>,
+    liveness_map: &NllLivenessMap,
+) {
+    debug!("trace()");
+
+    if liveness_map.is_empty() {
+        return;
+    }
+
+    let local_use_map = &LocalUseMap::build(liveness_map, elements, mir);
+
+    let cx = LivenessContext {
+        typeck,
+        mir,
+        flow_inits,
+        elements,
+        local_use_map,
+        move_data,
+        liveness_map,
+        drop_data: FxHashMap::default(),
+    };
+
+    LivenessResults::new(cx).compute_for_all_locals();
+}
+
+/// Contextual state for the type-liveness generator.
+struct LivenessContext<'me, 'typeck, 'flow, 'gcx, 'tcx>
+where
+    'typeck: 'me,
+    'flow: 'me,
+    'tcx: 'typeck + 'flow,
+    'gcx: 'tcx,
+{
+    /// Current type-checker, giving us our inference context etc.
+    typeck: &'me mut TypeChecker<'typeck, 'gcx, 'tcx>,
+
+    /// Defines the `PointIndex` mapping
+    elements: &'me RegionValueElements,
+
+    /// MIR we are analyzing.
+    mir: &'me Mir<'tcx>,
+
+    /// Mapping to/from the various indices used for initialization tracking.
+    move_data: &'me MoveData<'tcx>,
+
+    /// Cache for the results of `dropck_outlives` query.
+    drop_data: FxHashMap<Ty<'tcx>, DropData<'tcx>>,
+
+    /// Results of dataflow tracking which variables (and paths) have been
+    /// initialized.
+    flow_inits: &'me mut FlowAtLocation<MaybeInitializedPlaces<'flow, 'gcx, 'tcx>>,
+
+    /// Index indicating where each variable is assigned, used, or
+    /// dropped.
+    local_use_map: &'me LocalUseMap<'me>,
+
+    /// Map tracking which variables need liveness computation.
+    liveness_map: &'me NllLivenessMap,
+}
+
+struct DropData<'tcx> {
+    dropck_result: DropckOutlivesResult<'tcx>,
+    region_constraint_data: Option<Rc<Vec<QueryRegionConstraint<'tcx>>>>,
+}
+
+struct LivenessResults<'me, 'typeck, 'flow, 'gcx, 'tcx>
+where
+    'typeck: 'me,
+    'flow: 'me,
+    'tcx: 'typeck + 'flow,
+    'gcx: 'tcx,
+{
+    cx: LivenessContext<'me, 'typeck, 'flow, 'gcx, 'tcx>,
+
+    /// Set of points that define the current local.
+    defs: BitArray<PointIndex>,
+
+    /// Points where the current variable is "use live" -- meaning
+    /// that there is a future "full use" that may use its value.
+    use_live_at: BitArray<PointIndex>,
+
+    /// Points where the current variable is "drop live" -- meaning
+    /// that there is no future "full use" that may use its value, but
+    /// there is a future drop.
+    drop_live_at: BitArray<PointIndex>,
+
+    /// Locations where drops may occur.
+    drop_locations: Vec<Location>,
+
+    /// Stack used when doing (reverse) DFS.
+    stack: Vec<PointIndex>,
+}
+
+impl LivenessResults<'me, 'typeck, 'flow, 'gcx, 'tcx> {
+    fn new(cx: LivenessContext<'me, 'typeck, 'flow, 'gcx, 'tcx>) -> Self {
+        let num_points = cx.elements.num_points();
+        LivenessResults {
+            cx,
+            defs: BitArray::new(num_points),
+            use_live_at: BitArray::new(num_points),
+            drop_live_at: BitArray::new(num_points),
+            drop_locations: vec![],
+            stack: vec![],
+        }
+    }
+
+    fn compute_for_all_locals(&mut self) {
+        for live_local in self.cx.liveness_map.to_local.indices() {
+            let local = self.cx.liveness_map.from_live_var(live_local);
+            debug!("local={:?} live_local={:?}", local, live_local);
+
+            self.reset_local_state();
+            self.add_defs_for(live_local);
+            self.compute_use_live_points_for(live_local);
+            self.compute_drop_live_points_for(live_local);
+
+            let local_ty = self.cx.mir.local_decls[local].ty;
+
+            if !self.use_live_at.is_empty() {
+                self.cx.add_use_live_facts_for(local_ty, &self.use_live_at);
+            }
+
+            if !self.drop_live_at.is_empty() {
+                self.cx.add_drop_live_facts_for(
+                    local,
+                    local_ty,
+                    &self.drop_locations,
+                    &self.drop_live_at,
+                );
+            }
+        }
+    }
+
+    /// Clear the value of fields that are "per local variable".
+    fn reset_local_state(&mut self) {
+        self.defs.clear();
+        self.use_live_at.clear();
+        self.drop_live_at.clear();
+        self.drop_locations.clear();
+        assert!(self.stack.is_empty());
+    }
+
+    /// Adds the definitions of `local` into `self.defs`.
+    fn add_defs_for(&mut self, live_local: LiveVar) {
+        for def in self.cx.local_use_map.defs(live_local) {
+            debug!("- defined at {:?}", def);
+            self.defs.insert(def);
+        }
+    }
+
+    /// Compute all points where local is "use live" -- meaning its
+    /// current value may be used later (except by a drop). This is
+    /// done by walking backwards from each use of `live_local` until we
+    /// find a `def` of local.
+    ///
+    /// Requires `add_defs_for(live_local)` to have been executed.
+    fn compute_use_live_points_for(&mut self, live_local: LiveVar) {
+        debug!("compute_use_live_points_for(live_local={:?})", live_local);
+
+        self.stack.extend(self.cx.local_use_map.uses(live_local));
+        while let Some(p) = self.stack.pop() {
+            if self.defs.contains(p) {
+                continue;
+            }
+
+            if self.use_live_at.insert(p) {
+                self.cx
+                    .elements
+                    .push_predecessors(self.cx.mir, p, &mut self.stack)
+            }
+        }
+    }
+
+    /// Compute all points where local is "drop live" -- meaning its
+    /// current value may be dropped later (but not used). This is
+    /// done by iterating over the drops of `local` where `local` (or
+    /// some subpart of `local`) is initialized. For each such drop,
+    /// we walk backwards until we find a point where `local` is
+    /// either defined or use-live.
+    ///
+    /// Requires `compute_use_live_points_for` and `add_defs_for` to
+    /// have been executed.
+    fn compute_drop_live_points_for(&mut self, live_local: LiveVar) {
+        debug!("compute_drop_live_points_for(live_local={:?})", live_local);
+
+        let local = self.cx.liveness_map.from_live_var(live_local);
+        let mpi = self.cx.move_data.rev_lookup.find_local(local);
+        debug!("compute_drop_live_points_for: mpi = {:?}", mpi);
+
+        // Find the drops where `local` is initialized.
+        for drop_point in self.cx.local_use_map.drops(live_local) {
+            let location = self.cx.elements.to_location(drop_point);
+            debug_assert_eq!(self.cx.mir.terminator_loc(location.block), location,);
+
+            if self.cx.initialized_at_terminator(location.block, mpi) {
+                if self.drop_live_at.insert(drop_point) {
+                    self.drop_locations.push(location);
+                    self.stack.push(drop_point);
+                }
+            }
+        }
+
+        debug!(
+            "compute_drop_live_points_for: drop_locations={:?}",
+            self.drop_locations
+        );
+
+        // Reverse DFS. But for drops, we do it a bit differently.
+        // The stack only ever stores *terminators of blocks*. Within
+        // a block, we walk back the statements in an inner loop.
+        'next_block: while let Some(term_point) = self.stack.pop() {
+            self.compute_drop_live_points_for_block(mpi, term_point);
+        }
+    }
+
+    /// Executes one iteration of the drop-live analysis loop.
+    ///
+    /// The parameter `mpi` is the `MovePathIndex` of the local variable
+    /// we are currently analyzing.
+    ///
+    /// The point `term_point` represents some terminator in the MIR,
+    /// where the local `mpi` is drop-live on entry to that terminator.
+    ///
+    /// This method adds all drop-live points within the block and --
+    /// where applicable -- pushes the terminators of preceding blocks
+    /// onto `self.stack`.
+    fn compute_drop_live_points_for_block(&mut self, mpi: MovePathIndex, term_point: PointIndex) {
+        debug!(
+            "compute_drop_live_points_for_block(mpi={:?}, term_point={:?})",
+            self.cx.move_data.move_paths[mpi].place,
+            self.cx.elements.to_location(term_point),
+        );
+
+        // We are only invoked with terminators where `mpi` is
+        // drop-live on entry.
+        debug_assert!(self.drop_live_at.contains(term_point));
+
+        // Otherwise, scan backwards through the statements in the
+        // block.  One of them may be either a definition or use
+        // live point.
+        let term_location = self.cx.elements.to_location(term_point);
+        debug_assert_eq!(
+            self.cx.mir.terminator_loc(term_location.block),
+            term_location,
+        );
+        let block = term_location.block;
+        let entry_point = self.cx.elements.entry_point(term_location.block);
+        for p in (entry_point..term_point).rev() {
+            debug!(
+                "compute_drop_live_points_for_block: p = {:?}",
+                self.cx.elements.to_location(p),
+            );
+
+            if self.defs.contains(p) {
+                debug!("compute_drop_live_points_for_block: def site");
+                return;
+            }
+
+            if self.use_live_at.contains(p) {
+                debug!("compute_drop_live_points_for_block: use-live at {:?}", p);
+                return;
+            }
+
+            if !self.drop_live_at.insert(p) {
+                debug!("compute_drop_live_points_for_block: already drop-live");
+                return;
+            }
+        }
+
+        for &pred_block in self.cx.mir.predecessors_for(block).iter() {
+            debug!(
+                "compute_drop_live_points_for_block: pred_block = {:?}",
+                pred_block,
+            );
+
+            // Check whether the variable is (at least partially)
+            // initialized at the exit of this predecessor. If so, we
+            // want to enqueue it on our list. If not, go check the
+            // next block.
+            //
+            // Note that we only need to check whether `live_local`
+            // became de-initialized at basic block boundaries. If it
+            // were to become de-initialized within the block, that
+            // would have been a "use-live" transition in the earlier
+            // loop, and we'd have returned already.
+            //
+            // NB. It's possible that the pred-block ends in a call
+            // which stores to the variable; in that case, the
+            // variable may be uninitialized "at exit" because this
+            // call only considers the *unconditional effects* of the
+            // terminator. *But*, in that case, the terminator is also
+            // a *definition* of the variable, in which case we want
+            // to stop the search anyhow. (But see Note 1 below.)
+            if !self.cx.initialized_at_exit(pred_block, mpi) {
+                debug!("compute_drop_live_points_for_block: not initialized");
+                continue;
+            }
+
+            let pred_term_loc = self.cx.mir.terminator_loc(pred_block);
+            let pred_term_point = self.cx.elements.point_from_location(pred_term_loc);
+
+            // If the terminator of this predecessor either *assigns*
+            // our value or is a "normal use", then stop.
+            if self.defs.contains(pred_term_point) {
+                debug!(
+                    "compute_drop_live_points_for_block: defined at {:?}",
+                    pred_term_loc
+                );
+                continue;
+            }
+
+            if self.use_live_at.contains(pred_term_point) {
+                debug!(
+                    "compute_drop_live_points_for_block: use-live at {:?}",
+                    pred_term_loc
+                );
+                continue;
+            }
+
+            // Otherwise, we are drop-live on entry to the terminator,
+            // so walk it.
+            if self.drop_live_at.insert(pred_term_point) {
+                debug!("compute_drop_live_points_for_block: pushed to stack");
+                self.stack.push(pred_term_point);
+            }
+        }
+
+        // Note 1. There is a weird scenario that you might imagine
+        // being problematic here, but which actually cannot happen.
+        // The problem would be if we had a variable that *is* initialized
+        // (but dead) on entry to the terminator, and where the current value
+        // will be dropped in the case of unwind. In that case, we ought to
+        // consider `X` to be drop-live in between the last use and call.
+        // Here is the example:
+        //
+        // ```
+        // BB0 {
+        //   X = ...
+        //   use(X); // last use
+        //   ...     // <-- X ought to be drop-live here
+        //   X = call() goto BB1 unwind BB2
+        // }
+        //
+        // BB1 {
+        //   DROP(X)
+        // }
+        //
+        // BB2 {
+        //   DROP(X)
+        // }
+        // ```
+        //
+        // However, the current code would, when walking back from BB2,
+        // simply stop and never explore BB0. This seems bad! But it turns
+        // out this code is flawed anyway -- note that the existing value of
+        // `X` would leak in the case where unwinding did *not* occur.
+        //
+        // What we *actually* generate is a store to a temporary
+        // for the call (`TMP = call()...`) and then a
+        // `DropAndReplace` to swap that with `X`
+        // (`DropAndReplace` has very particular semantics).
+    }
+}
+
+impl LivenessContext<'_, '_, '_, '_, 'tcx> {
+    /// True if the local variable (or some part of it) is initialized in
+    /// the terminator of `block`. We need to check this to determine if a
+    /// DROP of some local variable will have an effect -- note that
+    /// drops, as they may unwind, are always terminators.
+    fn initialized_at_terminator(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool {
+        // Compute the set of initialized paths at terminator of block
+        // by resetting to the start of the block and then applying
+        // the effects of all statements. This is the only way to get
+        // "just ahead" of a terminator.
+        self.flow_inits.reset_to_entry_of(block);
+        for statement_index in 0..self.mir[block].statements.len() {
+            let location = Location {
+                block,
+                statement_index,
+            };
+            self.flow_inits.reconstruct_statement_effect(location);
+            self.flow_inits.apply_local_effect(location);
+        }
+
+        self.flow_inits.has_any_child_of(mpi).is_some()
+    }
+
+    /// True if the path `mpi` (or some part of it) is initialized at
+    /// the exit of `block`.
+    ///
+    /// **Warning:** Does not account for the result of `Call`
+    /// instructions.
+    fn initialized_at_exit(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool {
+        self.flow_inits.reset_to_exit_of(block);
+        self.flow_inits.has_any_child_of(mpi).is_some()
+    }
+
+    /// Store the result that all regions in `value` are live for the
+    /// points `live_at`.
+    fn add_use_live_facts_for(
+        &mut self,
+        value: impl TypeFoldable<'tcx>,
+        live_at: &BitArray<PointIndex>,
+    ) {
+        debug!("add_use_live_facts_for(value={:?})", value);
+
+        Self::make_all_regions_live(self.elements, &mut self.typeck, value, live_at)
+    }
+
+    /// Some variable with type `live_ty` is "drop live" at `location`
+    /// -- i.e., it may be dropped later. This means that *some* of
+    /// the regions in its type must be live at `location`. The
+    /// precise set will depend on the dropck constraints, and in
+    /// particular this takes `#[may_dangle]` into account.
+    fn add_drop_live_facts_for(
+        &mut self,
+        dropped_local: Local,
+        dropped_ty: Ty<'tcx>,
+        drop_locations: &[Location],
+        live_at: &BitArray<PointIndex>,
+    ) {
+        debug!(
+            "add_drop_live_constraint(\
+             dropped_local={:?}, \
+             dropped_ty={:?}, \
+             drop_locations={:?}, \
+             live_at={:?})",
+            dropped_local,
+            dropped_ty,
+            drop_locations,
+            values::location_set_str(self.elements, live_at.iter()),
+        );
+
+        let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({
+            let typeck = &mut self.typeck;
+            move || Self::compute_drop_data(typeck, dropped_ty)
+        });
+
+        if let Some(data) = &drop_data.region_constraint_data {
+            for &drop_location in drop_locations {
+                self.typeck
+                    .push_region_constraints(drop_location.boring(), data);
+            }
+        }
+
+        drop_data.dropck_result.report_overflows(
+            self.typeck.infcx.tcx,
+            self.mir.source_info(*drop_locations.first().unwrap()).span,
+            dropped_ty,
+        );
+
+        // All things in the `outlives` array may be touched by
+        // the destructor and must be live at this point.
+        for &kind in &drop_data.dropck_result.kinds {
+            Self::make_all_regions_live(self.elements, &mut self.typeck, kind, live_at);
+        }
+    }
+
+    fn make_all_regions_live(
+        elements: &RegionValueElements,
+        typeck: &mut TypeChecker<'_, '_, 'tcx>,
+        value: impl TypeFoldable<'tcx>,
+        live_at: &BitArray<PointIndex>,
+    ) {
+        debug!("make_all_regions_live(value={:?})", value);
+        debug!(
+            "make_all_regions_live: live_at={}",
+            values::location_set_str(elements, live_at.iter()),
+        );
+
+        let tcx = typeck.tcx();
+        tcx.for_each_free_region(&value, |live_region| {
+            let borrowck_context = typeck.borrowck_context.as_mut().unwrap();
+            let live_region_vid = borrowck_context
+                .universal_regions
+                .to_region_vid(live_region);
+            borrowck_context
+                .constraints
+                .liveness_constraints
+                .add_elements(live_region_vid, live_at);
+
+            if let Some(_) = borrowck_context.all_facts {
+                bug!("polonius liveness facts not implemented yet")
+            }
+        });
+    }
+
+    fn compute_drop_data(
+        typeck: &mut TypeChecker<'_, 'gcx, 'tcx>,
+        dropped_ty: Ty<'tcx>,
+    ) -> DropData<'tcx> {
+        debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,);
+
+        let param_env = typeck.param_env;
+        let (dropck_result, region_constraint_data) = param_env
+            .and(DropckOutlives::new(dropped_ty))
+            .fully_perform(typeck.infcx)
+            .unwrap();
+
+        DropData {
+            dropck_result,
+            region_constraint_data,
+        }
+    }
+}
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 5c14e552cfd..3a5857f775f 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -18,9 +18,7 @@ use borrow_check::nll::facts::AllFacts;
 use borrow_check::nll::region_infer::values::{LivenessValues, RegionValueElements};
 use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
 use borrow_check::nll::type_check::free_region_relations::{CreateResult, UniversalRegionRelations};
-use borrow_check::nll::type_check::liveness::liveness_map::NllLivenessMap;
 use borrow_check::nll::universal_regions::UniversalRegions;
-use borrow_check::nll::LocalWithRegion;
 use borrow_check::nll::ToRegionVid;
 use dataflow::move_paths::MoveData;
 use dataflow::FlowAtLocation;
@@ -43,7 +41,6 @@ use std::fmt;
 use std::rc::Rc;
 use syntax_pos::{Span, DUMMY_SP};
 use transform::{MirPass, MirSource};
-use util::liveness::LivenessResults;
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::indexed_vec::Idx;
@@ -135,7 +132,6 @@ pub(crate) fn type_check<'gcx, 'tcx>(
         normalized_inputs_and_output,
     } = free_region_relations::create(
         infcx,
-        mir_def_id,
         param_env,
         location_table,
         Some(implicit_region_bound),
@@ -144,7 +140,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
         all_facts,
     );
 
-    let (liveness, liveness_map) = {
+    {
         let mut borrowck_context = BorrowCheckContext {
             universal_regions,
             location_table,
@@ -170,16 +166,14 @@ pub(crate) fn type_check<'gcx, 'tcx>(
                     &universal_region_relations,
                     &normalized_inputs_and_output,
                 );
-                liveness::generate(cx, mir, flow_inits, move_data)
+                liveness::generate(cx, mir, elements, flow_inits, move_data);
             },
-        )
-    };
+        );
+    }
 
     MirTypeckResults {
         constraints,
         universal_region_relations,
-        liveness,
-        liveness_map,
     }
 }
 
@@ -673,8 +667,6 @@ struct BorrowCheckContext<'a, 'tcx: 'a> {
 crate struct MirTypeckResults<'tcx> {
     crate constraints: MirTypeckRegionConstraints<'tcx>,
     crate universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
-    crate liveness: LivenessResults<LocalWithRegion>,
-    crate liveness_map: NllLivenessMap,
 }
 
 /// A collection of region constraints that must be satisfied for the
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index dc88446319c..f178ea8bdba 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -14,6 +14,7 @@ use build::scope::{CachedBlock, DropKind};
 use hair::cx::Cx;
 use hair::{LintLevel, BindingMode, PatternKind};
 use rustc::hir;
+use rustc::hir::Node;
 use rustc::hir::def_id::{DefId, LocalDefId};
 use rustc::middle::region;
 use rustc::mir::*;
@@ -40,9 +41,9 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
 
     // Figure out what primary body this item has.
     let body_id = match tcx.hir.get(id) {
-        hir::map::NodeVariant(variant) =>
+        Node::Variant(variant) =>
             return create_constructor_shim(tcx, id, &variant.node.data),
-        hir::map::NodeStructCtor(ctor) =>
+        Node::StructCtor(ctor) =>
             return create_constructor_shim(tcx, id, ctor),
 
         _ => match tcx.hir.maybe_body_owned_by(id) {
@@ -520,7 +521,7 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
                 by_ref,
                 mutability: Mutability::Not,
             };
-            if let Some(hir::map::NodeBinding(pat)) = tcx.hir.find(var_id) {
+            if let Some(Node::Binding(pat)) = tcx.hir.find(var_id) {
                 if let hir::PatKind::Binding(_, _, ident, _) = pat.node {
                     decl.debug_name = ident.name;
 
diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/const_eval.rs
index 8e77af7526e..295fca839c8 100644
--- a/src/librustc_mir/interpret/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -8,29 +8,29 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// Not in interpret to make sure we do not use private implementation details
+
 use std::fmt;
 use std::error::Error;
 
-use rustc::hir;
+use rustc::hir::{self, def_id::DefId};
 use rustc::mir::interpret::ConstEvalErr;
 use rustc::mir;
-use rustc::ty::{self, TyCtxt, Instance};
-use rustc::ty::layout::{LayoutOf, Primitive, TyLayout, Size};
+use rustc::ty::{self, TyCtxt, Instance, query::TyCtxtAt};
+use rustc::ty::layout::{LayoutOf, TyLayout};
 use rustc::ty::subst::Subst;
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 
 use syntax::ast::Mutability;
 use syntax::source_map::Span;
-use syntax::source_map::DUMMY_SP;
-use syntax::symbol::Symbol;
 
 use rustc::mir::interpret::{
     EvalResult, EvalError, EvalErrorKind, GlobalId,
-    Scalar, AllocId, Allocation, ConstValue,
+    Scalar, Allocation, ConstValue,
 };
-use super::{
-    Place, PlaceExtra, PlaceTy, MemPlace, OpTy, Operand, Value,
-    EvalContext, StackPopCleanup, Memory, MemoryKind, MPlaceTy,
+use interpret::{self,
+    Place, PlaceTy, MemPlace, OpTy, Operand, Value,
+    EvalContext, StackPopCleanup, MemoryKind,
 };
 
 pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
@@ -43,14 +43,14 @@ pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
     let param_env = tcx.param_env(instance.def_id());
     let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
     // insert a stack frame so any queries have the correct substs
-    ecx.stack.push(super::eval_context::Frame {
+    ecx.stack.push(interpret::Frame {
         block: mir::START_BLOCK,
         locals: IndexVec::new(),
         instance,
         span,
         mir,
         return_place: Place::null(tcx),
-        return_to_block: StackPopCleanup::None,
+        return_to_block: StackPopCleanup::Goto(None), // never pop
         stmt: 0,
     });
     Ok(ecx)
@@ -71,7 +71,7 @@ pub fn mk_eval_cx<'a, 'tcx>(
         mir.span,
         mir,
         Place::null(tcx),
-        StackPopCleanup::None,
+        StackPopCleanup::Goto(None), // never pop
     )?;
     Ok(ecx)
 }
@@ -103,15 +103,17 @@ pub fn op_to_const<'tcx>(
     let val = match normalized_op {
         Err(MemPlace { ptr, align, extra }) => {
             // extract alloc-offset pair
-            assert_eq!(extra, PlaceExtra::None);
+            assert!(extra.is_none());
             let ptr = ptr.to_ptr()?;
             let alloc = ecx.memory.get(ptr.alloc_id)?;
             assert!(alloc.align.abi() >= align.abi());
             assert!(alloc.bytes.len() as u64 - ptr.offset.bytes() >= op.layout.size.bytes());
             let mut alloc = alloc.clone();
             alloc.align = align;
+            // FIXME shouldnt it be the case that `mark_static_initialized` has already
+            // interned this?  I thought that is the entire point of that `FinishStatic` stuff?
             let alloc = ecx.tcx.intern_const_alloc(alloc);
-            ConstValue::ByRef(alloc, ptr.offset)
+            ConstValue::ByRef(ptr.alloc_id, alloc, ptr.offset)
         },
         Ok(Value::Scalar(x)) =>
             ConstValue::Scalar(x.not_undef()?),
@@ -120,13 +122,6 @@ pub fn op_to_const<'tcx>(
     };
     Ok(ty::Const::from_const_value(ecx.tcx.tcx, val, op.layout.ty))
 }
-pub fn const_to_op<'tcx>(
-    ecx: &mut EvalContext<'_, '_, 'tcx, CompileTimeEvaluator>,
-    cnst: &'tcx ty::Const<'tcx>,
-) -> EvalResult<'tcx, OpTy<'tcx>> {
-    let op = ecx.const_value_to_op(cnst.val)?;
-    Ok(OpTy { op, layout: ecx.layout_of(cnst.ty)? })
-}
 
 fn eval_body_and_ecx<'a, 'mir, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -134,7 +129,6 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>(
     mir: Option<&'mir mir::Mir<'tcx>>,
     param_env: ty::ParamEnv<'tcx>,
 ) -> (EvalResult<'tcx, OpTy<'tcx>>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) {
-    debug!("eval_body_and_ecx: {:?}, {:?}", cid, param_env);
     // we start out with the best span we have
     // and try improving it down the road when more information is available
     let span = tcx.def_span(cid.instance.def_id());
@@ -151,7 +145,7 @@ fn eval_body_using_ecx<'a, 'mir, 'tcx>(
     mir: Option<&'mir mir::Mir<'tcx>>,
     param_env: ty::ParamEnv<'tcx>,
 ) -> EvalResult<'tcx, OpTy<'tcx>> {
-    debug!("eval_body: {:?}, {:?}", cid, param_env);
+    debug!("eval_body_using_ecx: {:?}, {:?}", cid, param_env);
     let tcx = ecx.tcx.tcx;
     let mut mir = match mir {
         Some(mir) => mir,
@@ -163,29 +157,33 @@ fn eval_body_using_ecx<'a, 'mir, 'tcx>(
     let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
     assert!(!layout.is_unsized());
     let ret = ecx.allocate(layout, MemoryKind::Stack)?;
-    let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span);
-    let is_static = tcx.is_static(cid.instance.def_id());
-    let mutability = if is_static == Some(hir::Mutability::MutMutable) || internally_mutable {
-        Mutability::Mutable
-    } else {
-        Mutability::Immutable
-    };
-    let cleanup = StackPopCleanup::MarkStatic(mutability);
+
     let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id()));
     let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p));
-    trace!("const_eval: pushing stack frame for global: {}{}", name, prom);
+    trace!("eval_body_using_ecx: pushing stack frame for global: {}{}", name, prom);
     assert!(mir.arg_count == 0);
     ecx.push_stack_frame(
         cid.instance,
         mir.span,
         mir,
         Place::Ptr(*ret),
-        cleanup,
+        StackPopCleanup::None { cleanup: false },
     )?;
 
     // The main interpreter loop.
-    while ecx.step()? {}
+    ecx.run()?;
 
+    // Intern the result
+    let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span);
+    let is_static = tcx.is_static(cid.instance.def_id());
+    let mutability = if is_static == Some(hir::Mutability::MutMutable) || internally_mutable {
+        Mutability::Mutable
+    } else {
+        Mutability::Immutable
+    };
+    ecx.memory.intern_static(ret.ptr.to_ptr()?.alloc_id, mutability)?;
+
+    debug!("eval_body_using_ecx done: {:?}", *ret);
     Ok(ret.into())
 }
 
@@ -234,72 +232,33 @@ impl Error for ConstEvalError {
     }
 }
 
-impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
+impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeEvaluator {
     type MemoryData = ();
     type MemoryKinds = !;
-    fn eval_fn_call<'a>(
+
+    const MUT_STATIC_KIND: Option<!> = None; // no mutating of statics allowed
+
+    fn find_fn<'a>(
         ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
-        destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
         args: &[OpTy<'tcx>],
-        span: Span,
-    ) -> EvalResult<'tcx, bool> {
+        dest: Option<PlaceTy<'tcx>>,
+        ret: Option<mir::BasicBlock>,
+    ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> {
         debug!("eval_fn_call: {:?}", instance);
         if !ecx.tcx.is_const_fn(instance.def_id()) {
-            let def_id = instance.def_id();
-            // Some fn calls are actually BinOp intrinsics
-            let _: ! = if let Some((op, oflo)) = ecx.tcx.is_binop_lang_item(def_id) {
-                let (dest, bb) = destination.expect("128 lowerings can't diverge");
-                let l = ecx.read_value(args[0])?;
-                let r = ecx.read_value(args[1])?;
-                if oflo {
-                    ecx.binop_with_overflow(op, l, r, dest)?;
-                } else {
-                    ecx.binop_ignore_overflow(op, l, r, dest)?;
-                }
-                ecx.goto_block(bb);
-                return Ok(true);
-            } else if Some(def_id) == ecx.tcx.lang_items().panic_fn() {
-                assert!(args.len() == 1);
-                // &(&'static str, &'static str, u32, u32)
-                let ptr = ecx.read_value(args[0])?;
-                let place = ecx.ref_to_mplace(ptr)?;
-                let (msg, file, line, col) = (
-                    place_field(ecx, 0, place)?,
-                    place_field(ecx, 1, place)?,
-                    place_field(ecx, 2, place)?,
-                    place_field(ecx, 3, place)?,
-                );
-
-                let msg = to_str(ecx, msg)?;
-                let file = to_str(ecx, file)?;
-                let line = to_u32(line)?;
-                let col = to_u32(col)?;
-                return Err(EvalErrorKind::Panic { msg, file, line, col }.into());
-            } else if Some(def_id) == ecx.tcx.lang_items().begin_panic_fn() {
-                assert!(args.len() == 2);
-                // &'static str, &(&'static str, u32, u32)
-                let msg = ecx.read_value(args[0])?;
-                let ptr = ecx.read_value(args[1])?;
-                let place = ecx.ref_to_mplace(ptr)?;
-                let (file, line, col) = (
-                    place_field(ecx, 0, place)?,
-                    place_field(ecx, 1, place)?,
-                    place_field(ecx, 2, place)?,
-                );
-
-                let msg = to_str(ecx, msg.value)?;
-                let file = to_str(ecx, file)?;
-                let line = to_u32(line)?;
-                let col = to_u32(col)?;
-                return Err(EvalErrorKind::Panic { msg, file, line, col }.into());
-            } else {
-                return Err(
-                    ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(),
-                );
-            };
+            // Some functions we support even if they are non-const -- but avoid testing
+            // that for const fn!
+            if ecx.hook_fn(instance, args, dest)? {
+                ecx.goto_block(ret)?; // fully evaluated and done
+                return Ok(None);
+            }
+            return Err(
+                ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(),
+            );
         }
-        let mir = match ecx.load_mir(instance.def) {
+        // This is a const fn. Call it.
+        Ok(Some(match ecx.load_mir(instance.def) {
             Ok(mir) => mir,
             Err(err) => {
                 if let EvalErrorKind::NoMirFor(ref path) = err.kind {
@@ -310,94 +269,23 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
                 }
                 return Err(err);
             }
-        };
-        let (return_place, return_to_block) = match destination {
-            Some((place, block)) => (*place, StackPopCleanup::Goto(block)),
-            None => (Place::null(&ecx), StackPopCleanup::None),
-        };
-
-        ecx.push_stack_frame(
-            instance,
-            span,
-            mir,
-            return_place,
-            return_to_block,
-        )?;
-
-        Ok(false)
+        }))
     }
 
-
     fn call_intrinsic<'a>(
         ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
         dest: PlaceTy<'tcx>,
-        target: mir::BasicBlock,
     ) -> EvalResult<'tcx> {
-        let substs = instance.substs;
-
-        let intrinsic_name = &ecx.tcx.item_name(instance.def_id()).as_str()[..];
-        match intrinsic_name {
-            "min_align_of" => {
-                let elem_ty = substs.type_at(0);
-                let elem_align = ecx.layout_of(elem_ty)?.align.abi();
-                let align_val = Scalar::Bits {
-                    bits: elem_align as u128,
-                    size: dest.layout.size.bytes() as u8,
-                };
-                ecx.write_scalar(align_val, dest)?;
-            }
-
-            "size_of" => {
-                let ty = substs.type_at(0);
-                let size = ecx.layout_of(ty)?.size.bytes() as u128;
-                let size_val = Scalar::Bits {
-                    bits: size,
-                    size: dest.layout.size.bytes() as u8,
-                };
-                ecx.write_scalar(size_val, dest)?;
-            }
-
-            "type_id" => {
-                let ty = substs.type_at(0);
-                let type_id = ecx.tcx.type_id_hash(ty) as u128;
-                let id_val = Scalar::Bits {
-                    bits: type_id,
-                    size: dest.layout.size.bytes() as u8,
-                };
-                ecx.write_scalar(id_val, dest)?;
-            }
-            "ctpop" | "cttz" | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" | "bswap" => {
-                let ty = substs.type_at(0);
-                let layout_of = ecx.layout_of(ty)?;
-                let bits = ecx.read_scalar(args[0])?.to_bits(layout_of.size)?;
-                let kind = match layout_of.abi {
-                    ty::layout::Abi::Scalar(ref scalar) => scalar.value,
-                    _ => Err(::rustc::mir::interpret::EvalErrorKind::TypeNotPrimitive(ty))?,
-                };
-                let out_val = if intrinsic_name.ends_with("_nonzero") {
-                    if bits == 0 {
-                        return err!(Intrinsic(format!("{} called on 0", intrinsic_name)));
-                    }
-                    numeric_intrinsic(intrinsic_name.trim_right_matches("_nonzero"), bits, kind)?
-                } else {
-                    numeric_intrinsic(intrinsic_name, bits, kind)?
-                };
-                ecx.write_scalar(out_val, dest)?;
-            }
-
-            name => return Err(
-                ConstEvalError::NeedsRfc(format!("calling intrinsic `{}`", name)).into()
-            ),
+        if ecx.emulate_intrinsic(instance, args, dest)? {
+            return Ok(());
         }
-
-        ecx.goto_block(target);
-
-        // Since we pushed no stack frame, the main loop will act
-        // as if the call just completed and it's returning to the
-        // current frame.
-        Ok(())
+        // An intrinsic that we do not support
+        let intrinsic_name = &ecx.tcx.item_name(instance.def_id()).as_str()[..];
+        Err(
+            ConstEvalError::NeedsRfc(format!("calling intrinsic `{}`", intrinsic_name)).into()
+        )
     }
 
     fn try_ptr_op<'a>(
@@ -417,23 +305,11 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
         }
     }
 
-    fn mark_static_initialized<'a>(
-        _mem: &mut Memory<'a, 'mir, 'tcx, Self>,
-        _id: AllocId,
-        _mutability: Mutability,
-    ) -> EvalResult<'tcx, bool> {
-        Ok(false)
-    }
-
-    fn init_static<'a>(
-        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
-        cid: GlobalId<'tcx>,
-    ) -> EvalResult<'tcx, AllocId> {
-        Ok(ecx
-            .tcx
-            .alloc_map
-            .lock()
-            .intern_static(cid.instance.def_id()))
+    fn find_foreign_static<'a>(
+        _tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
+        _def_id: DefId,
+    ) -> EvalResult<'tcx, &'tcx Allocation> {
+        err!(ReadForeignStatic)
     }
 
     fn box_alloc<'a>(
@@ -444,50 +320,6 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
             ConstEvalError::NeedsRfc("heap allocations via `box` keyword".to_string()).into(),
         )
     }
-
-    fn global_item_with_linkage<'a>(
-        _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
-        _instance: ty::Instance<'tcx>,
-        _mutability: Mutability,
-    ) -> EvalResult<'tcx> {
-        Err(
-            ConstEvalError::NotConst("statics with `linkage` attribute".to_string()).into(),
-        )
-    }
-}
-
-fn place_field<'a, 'tcx, 'mir>(
-    ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
-    i: u64,
-    place: MPlaceTy<'tcx>,
-) -> EvalResult<'tcx, Value> {
-    let place = ecx.mplace_field(place, i)?;
-    Ok(ecx.try_read_value_from_mplace(place)?.expect("bad panic arg layout"))
-}
-
-fn to_str<'a, 'tcx, 'mir>(
-    ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
-    val: Value,
-) -> EvalResult<'tcx, Symbol> {
-    if let Value::ScalarPair(ptr, len) = val {
-        let len = len.not_undef()?.to_bits(ecx.memory.pointer_size())?;
-        let bytes = ecx.memory.read_bytes(ptr.not_undef()?, Size::from_bytes(len as u64))?;
-        let str = ::std::str::from_utf8(bytes)
-            .map_err(|err| EvalErrorKind::ValidationFailure(err.to_string()))?;
-        Ok(Symbol::intern(str))
-    } else {
-        bug!("panic arg is not a str")
-    }
-}
-
-fn to_u32<'a, 'tcx, 'mir>(
-    val: Value,
-) -> EvalResult<'tcx, u32> {
-    if let Value::Scalar(n) = val {
-        Ok(n.not_undef()?.to_bits(Size::from_bits(32))? as u32)
-    } else {
-        bug!("panic arg is not a str")
-    }
 }
 
 /// Project to a field of a (variant of a) const
@@ -500,10 +332,10 @@ pub fn const_field<'a, 'tcx>(
     value: &'tcx ty::Const<'tcx>,
 ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
     trace!("const_field: {:?}, {:?}, {:?}", instance, field, value);
-    let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
+    let ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
     let result = (|| {
         // get the operand again
-        let op = const_to_op(&mut ecx, value)?;
+        let op = ecx.const_to_op(value)?;
         // downcast
         let down = match variant {
             None => op,
@@ -532,36 +364,25 @@ pub fn const_variant_index<'a, 'tcx>(
     val: &'tcx ty::Const<'tcx>,
 ) -> EvalResult<'tcx, usize> {
     trace!("const_variant_index: {:?}, {:?}", instance, val);
-    let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
-    let op = const_to_op(&mut ecx, val)?;
-    ecx.read_discriminant_as_variant_index(op)
+    let ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
+    let op = ecx.const_to_op(val)?;
+    Ok(ecx.read_discriminant(op)?.1)
 }
 
 pub fn const_to_allocation_provider<'a, 'tcx>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    _tcx: TyCtxt<'a, 'tcx, 'tcx>,
     val: &'tcx ty::Const<'tcx>,
 ) -> &'tcx Allocation {
+    // FIXME: This really does not need to be a query.  Instead, we should have a query for statics
+    // that returns an allocation directly (or an `AllocId`?), after doing a sanity check of the
+    // value and centralizing error reporting.
     match val.val {
-        ConstValue::ByRef(alloc, offset) => {
+        ConstValue::ByRef(_, alloc, offset) => {
             assert_eq!(offset.bytes(), 0);
             return alloc;
         },
-        _ => ()
+        _ => bug!("const_to_allocation called on non-static"),
     }
-    let result = || -> EvalResult<'tcx, &'tcx Allocation> {
-        let mut ecx = EvalContext::new(
-            tcx.at(DUMMY_SP),
-            ty::ParamEnv::reveal_all(),
-            CompileTimeEvaluator,
-            ());
-        let op = const_to_op(&mut ecx, val)?;
-        // Make a new allocation, copy things there
-        let ptr = ecx.allocate(op.layout, MemoryKind::Stack)?;
-        ecx.copy_op(op, ptr.into())?;
-        let alloc = ecx.memory.get(ptr.to_ptr()?.alloc_id)?;
-        Ok(tcx.intern_const_alloc(alloc.clone()))
-    };
-    result().expect("unable to convert ConstValue to Allocation")
 }
 
 pub fn const_eval_provider<'a, 'tcx>(
@@ -626,23 +447,3 @@ pub fn const_eval_provider<'a, 'tcx>(
         err.into()
     })
 }
-
-fn numeric_intrinsic<'tcx>(
-    name: &str,
-    bits: u128,
-    kind: Primitive,
-) -> EvalResult<'tcx, Scalar> {
-    let size = match kind {
-        Primitive::Int(integer, _) => integer.size(),
-        _ => bug!("invalid `{}` argument: {:?}", name, bits),
-    };
-    let extra = 128 - size.bits() as u128;
-    let bits_out = match name {
-        "ctpop" => bits.count_ones() as u128,
-        "ctlz" => bits.leading_zeros() as u128 - extra,
-        "cttz" => (bits << extra).trailing_zeros() as u128 - extra,
-        "bswap" => (bits << extra).swap_bytes(),
-        _ => bug!("not a numeric intrinsic: {}", name),
-    };
-    Ok(Scalar::Bits { bits: bits_out, size: size.bytes() as u8 })
-}
diff --git a/src/librustc_mir/dataflow/at_location.rs b/src/librustc_mir/dataflow/at_location.rs
index 0dfc5b5b4b7..d97c0c9b430 100644
--- a/src/librustc_mir/dataflow/at_location.rs
+++ b/src/librustc_mir/dataflow/at_location.rs
@@ -28,6 +28,15 @@ pub trait FlowsAtLocation {
     /// Reset the state bitvector to represent the entry to block `bb`.
     fn reset_to_entry_of(&mut self, bb: BasicBlock);
 
+    /// Reset the state bitvector to represent the exit of the
+    /// terminator of block `bb`.
+    ///
+    /// **Important:** In the case of a `Call` terminator, these
+    /// effects do *not* include the result of storing the destination
+    /// of the call, since that is edge-dependent (in other words, the
+    /// effects don't apply to the unwind edge).
+    fn reset_to_exit_of(&mut self, bb: BasicBlock);
+
     /// Build gen + kill sets for statement at `loc`.
     ///
     /// Note that invoking this method alone does not change the
@@ -129,8 +138,8 @@ where
         F: FnOnce(Iter<BD::Idx>),
     {
         let mut curr_state = self.curr_state.clone();
-        curr_state.union_hybrid(&self.stmt_gen);
-        curr_state.subtract_hybrid(&self.stmt_kill);
+        curr_state.union(&self.stmt_gen);
+        curr_state.subtract(&self.stmt_kill);
         f(curr_state.iter());
     }
 }
@@ -142,6 +151,12 @@ impl<BD> FlowsAtLocation for FlowAtLocation<BD>
         self.curr_state.overwrite(self.base_results.sets().on_entry_set_for(bb.index()));
     }
 
+    fn reset_to_exit_of(&mut self, bb: BasicBlock) {
+        self.reset_to_entry_of(bb);
+        self.curr_state.union(self.base_results.sets().gen_set_for(bb.index()));
+        self.curr_state.subtract(self.base_results.sets().kill_set_for(bb.index()));
+    }
+
     fn reconstruct_statement_effect(&mut self, loc: Location) {
         self.stmt_gen.clear();
         self.stmt_kill.clear();
@@ -193,8 +208,8 @@ impl<BD> FlowsAtLocation for FlowAtLocation<BD>
     }
 
     fn apply_local_effect(&mut self, _loc: Location) {
-        self.curr_state.union_hybrid(&self.stmt_gen);
-        self.curr_state.subtract_hybrid(&self.stmt_kill);
+        self.curr_state.union(&self.stmt_gen);
+        self.curr_state.subtract(&self.stmt_kill);
     }
 }
 
diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs
index 598e827b256..fd6569feb5c 100644
--- a/src/librustc_mir/dataflow/mod.rs
+++ b/src/librustc_mir/dataflow/mod.rs
@@ -241,8 +241,8 @@ impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> where BD: Bi
                 let sets = self.builder.flow_state.sets.for_block(bb.index());
                 debug_assert!(in_out.words().len() == sets.on_entry.words().len());
                 in_out.overwrite(sets.on_entry);
-                in_out.union_hybrid(sets.gen_set);
-                in_out.subtract_hybrid(sets.kill_set);
+                in_out.union(sets.gen_set);
+                in_out.subtract(sets.kill_set);
             }
             self.builder.propagate_bits_into_graph_successors_of(
                 in_out, (bb, bb_data), &mut dirty_queue);
@@ -454,14 +454,18 @@ pub struct AllSets<E: Idx> {
     /// For each block, bits valid on entry to the block.
     on_entry_sets: Vec<IdxSet<E>>,
 
-    /// For each block, bits generated by executing the statements in
-    /// the block. (For comparison, the Terminator for each block is
-    /// handled in a flow-specific manner during propagation.)
+    /// For each block, bits generated by executing the statements +
+    /// terminator in the block -- with one caveat. In particular, for
+    /// *call terminators*, the effect of storing the destination is
+    /// not included, since that only takes effect on the **success**
+    /// edge (and not the unwind edge).
     gen_sets: Vec<HybridIdxSet<E>>,
 
-    /// For each block, bits killed by executing the statements in the
-    /// block. (For comparison, the Terminator for each block is
-    /// handled in a flow-specific manner during propagation.)
+    /// For each block, bits killed by executing the statements +
+    /// terminator in the block -- with one caveat. In particular, for
+    /// *call terminators*, the effect of storing the destination is
+    /// not included, since that only takes effect on the **success**
+    /// edge (and not the unwind edge).
     kill_sets: Vec<HybridIdxSet<E>>,
 }
 
@@ -534,8 +538,8 @@ impl<'a, E:Idx> BlockSets<'a, E> {
     }
 
     fn apply_local_effect(&mut self) {
-        self.on_entry.union_hybrid(&self.gen_set);
-        self.on_entry.subtract_hybrid(&self.kill_set);
+        self.on_entry.union(self.gen_set);
+        self.on_entry.subtract(self.kill_set);
     }
 }
 
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 7153a388467..8be1f52a9cd 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -78,7 +78,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                     mut expr: Expr<'tcx>,
                                     adjustment: &Adjustment<'tcx>)
                                     -> Expr<'tcx> {
-    let Expr { temp_lifetime, span, .. } = expr;
+    let Expr { temp_lifetime, mut span, .. } = expr;
     let kind = match adjustment.kind {
         Adjust::ReifyFnPointer => {
             ExprKind::ReifyFnPointer { source: expr.to_ref() }
@@ -96,6 +96,25 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             ExprKind::Cast { source: expr.to_ref() }
         }
         Adjust::Deref(None) => {
+            // Adjust the span from the block, to the last expression of the
+            // block. This is a better span when returning a mutable reference
+            // with too short a lifetime. The error message will use the span
+            // from the assignment to the return place, which should only point
+            // at the returned value, not the entire function body.
+            //
+            // fn return_short_lived<'a>(x: &'a mut i32) -> &'static mut i32 {
+            //      x
+            //   // ^ error message points at this expression.
+            // }
+            //
+            // We don't need to do this adjustment in the next match arm since
+            // deref coercions always start with a built-in deref.
+            if let ExprKind::Block { body } = expr.kind {
+                if let Some(ref last_expr) = body.expr {
+                    span = last_expr.span;
+                    expr.span = span;
+                }
+            }
             ExprKind::Deref { arg: expr.to_ref() }
         }
         Adjust::Deref(Some(deref)) => {
@@ -180,6 +199,13 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             ExprKind::Use { source: cast_expr.to_ref() }
         }
         Adjust::Unsize => {
+            // See the above comment for Adjust::Deref
+            if let ExprKind::Block { body } = expr.kind {
+                if let Some(ref last_expr) = body.expr {
+                    span = last_expr.span;
+                    expr.span = span;
+                }
+            }
             ExprKind::Unsize { source: expr.to_ref() }
         }
     };
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index ef21348cd3c..c9fd1d04e54 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -19,6 +19,7 @@ use hair::*;
 use rustc_data_structures::indexed_vec::Idx;
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::hir::map::blocks::FnLikeNode;
+use rustc::hir::Node;
 use rustc::middle::region;
 use rustc::infer::InferCtxt;
 use rustc::ty::subst::Subst;
@@ -202,7 +203,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
     pub fn pattern_from_hir(&mut self, p: &hir::Pat) -> Pattern<'tcx> {
         let tcx = self.tcx.global_tcx();
         let p = match tcx.hir.get(p.id) {
-            hir::map::NodePat(p) | hir::map::NodeBinding(p) => p,
+            Node::Pat(p) | Node::Binding(p) => p,
             node => bug!("pattern became {:?}", node)
         };
         Pattern::from_hir(tcx,
diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs
index 4522f477959..d0d1c5d6610 100644
--- a/src/librustc_mir/interpret/cast.rs
+++ b/src/librustc_mir/interpret/cast.rs
@@ -32,7 +32,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         }
     }
 
-    crate fn cast(
+    pub fn cast(
         &mut self,
         src: OpTy<'tcx>,
         kind: CastKind,
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index fa70a1500d0..455c3fc281a 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -32,10 +32,9 @@ use rustc::mir::interpret::{
 };
 
 use syntax::source_map::{self, Span};
-use syntax::ast::Mutability;
 
 use super::{
-    Value, Operand, MemPlace, MPlaceTy, Place, PlaceExtra,
+    Value, Operand, MemPlace, MPlaceTy, Place,
     Memory, Machine
 };
 
@@ -56,15 +55,15 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
     pub(crate) stack: Vec<Frame<'mir, 'tcx>>,
 
     /// The maximum number of stack frames allowed
-    pub(crate) stack_limit: usize,
+    pub(super) stack_limit: usize,
 
     /// When this value is negative, it indicates the number of interpreter
     /// steps *until* the loop detector is enabled. When it is positive, it is
     /// the number of steps after the detector has been enabled modulo the loop
     /// detector period.
-    pub(crate) steps_since_detector_enabled: isize,
+    pub(super) steps_since_detector_enabled: isize,
 
-    pub(crate) loop_detector: InfiniteLoopDetector<'a, 'mir, 'tcx, M>,
+    pub(super) loop_detector: InfiniteLoopDetector<'a, 'mir, 'tcx, M>,
 }
 
 /// A stack frame.
@@ -85,7 +84,7 @@ pub struct Frame<'mir, 'tcx: 'mir> {
     ////////////////////////////////////////////////////////////////////////////////
     // Return place and locals
     ////////////////////////////////////////////////////////////////////////////////
-    /// The block to return to when returning from the current stack frame
+    /// Work to perform when returning from this function
     pub return_to_block: StackPopCleanup,
 
     /// The location where the result of the current stack frame should be written to.
@@ -157,6 +156,18 @@ impl<'mir, 'tcx: 'mir> Hash for Frame<'mir, 'tcx> {
     }
 }
 
+#[derive(Clone, Debug, Eq, PartialEq, Hash)]
+pub enum StackPopCleanup {
+    /// Jump to the next block in the caller, or cause UB if None (that's a function
+    /// that may never return).
+    Goto(Option<mir::BasicBlock>),
+    /// Just do nohing: Used by Main and for the box_alloc hook in miri.
+    /// `cleanup` says whether locals are deallocated.  Static computation
+    /// wants them leaked to intern what they need (and just throw away
+    /// the entire `ecx` when it is done).
+    None { cleanup: bool },
+}
+
 // State of a local variable
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub enum LocalValue {
@@ -188,7 +199,7 @@ impl<'tcx> LocalValue {
 type EvalSnapshot<'a, 'mir, 'tcx, M>
     = (M, Vec<Frame<'mir, 'tcx>>, Memory<'a, 'mir, 'tcx, M>);
 
-pub(crate) struct InfiniteLoopDetector<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
+pub(super) struct InfiniteLoopDetector<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
     /// The set of all `EvalSnapshot` *hashes* observed by this detector.
     ///
     /// When a collision occurs in this table, we store the full snapshot in
@@ -251,20 +262,6 @@ impl<'a, 'mir, 'tcx, M> InfiniteLoopDetector<'a, 'mir, 'tcx, M>
     }
 }
 
-#[derive(Clone, Debug, Eq, PartialEq, Hash)]
-pub enum StackPopCleanup {
-    /// The stackframe existed to compute the initial value of a static/constant, make sure it
-    /// isn't modifyable afterwards in case of constants.
-    /// In case of `static mut`, mark the memory to ensure it's never marked as immutable through
-    /// references or deallocated
-    MarkStatic(Mutability),
-    /// A regular stackframe added due to a function call will need to get forwarded to the next
-    /// block
-    Goto(mir::BasicBlock),
-    /// The main function and diverging functions have nowhere to return to
-    None,
-}
-
 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for &'a EvalContext<'a, 'mir, 'tcx, M> {
     #[inline]
     fn data_layout(&self) -> &layout::TargetDataLayout {
@@ -388,7 +385,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
     }
 
     pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
-        let ptr = self.memory.allocate_bytes(s.as_bytes());
+        let ptr = self.memory.allocate_static_bytes(s.as_bytes());
         Ok(Value::new_slice(Scalar::Ptr(ptr), s.len() as u64, self.tcx.tcx))
     }
 
@@ -465,90 +462,94 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
     }
 
     /// Return the actual dynamic size and alignment of the place at the given type.
-    /// Note that the value does not matter if the type is sized. For unsized types,
-    /// the value has to be a fat pointer, and we only care about the "extra" data in it.
-    pub fn size_and_align_of_mplace(
+    /// Only the "extra" (metadata) part of the place matters.
+    pub(super) fn size_and_align_of(
         &self,
-        mplace: MPlaceTy<'tcx>,
+        metadata: Option<Scalar>,
+        layout: TyLayout<'tcx>,
     ) -> EvalResult<'tcx, (Size, Align)> {
-        if let PlaceExtra::None = mplace.extra {
-            assert!(!mplace.layout.is_unsized());
-            Ok(mplace.layout.size_and_align())
-        } else {
-            let layout = mplace.layout;
-            assert!(layout.is_unsized());
-            match layout.ty.sty {
-                ty::Adt(..) | ty::Tuple(..) => {
-                    // First get the size of all statically known fields.
-                    // Don't use type_of::sizing_type_of because that expects t to be sized,
-                    // and it also rounds up to alignment, which we want to avoid,
-                    // as the unsized field's alignment could be smaller.
-                    assert!(!layout.ty.is_simd());
-                    debug!("DST layout: {:?}", layout);
-
-                    let sized_size = layout.fields.offset(layout.fields.count() - 1);
-                    let sized_align = layout.align;
-                    debug!(
-                        "DST {} statically sized prefix size: {:?} align: {:?}",
-                        layout.ty,
-                        sized_size,
-                        sized_align
-                    );
-
-                    // Recurse to get the size of the dynamically sized field (must be
-                    // the last field).
-                    let field = self.mplace_field(mplace, layout.fields.count() as u64 - 1)?;
-                    let (unsized_size, unsized_align) = self.size_and_align_of_mplace(field)?;
-
-                    // FIXME (#26403, #27023): We should be adding padding
-                    // to `sized_size` (to accommodate the `unsized_align`
-                    // required of the unsized field that follows) before
-                    // summing it with `sized_size`. (Note that since #26403
-                    // is unfixed, we do not yet add the necessary padding
-                    // here. But this is where the add would go.)
-
-                    // Return the sum of sizes and max of aligns.
-                    let size = sized_size + unsized_size;
-
-                    // Choose max of two known alignments (combined value must
-                    // be aligned according to more restrictive of the two).
-                    let align = sized_align.max(unsized_align);
-
-                    // Issue #27023: must add any necessary padding to `size`
-                    // (to make it a multiple of `align`) before returning it.
-                    //
-                    // Namely, the returned size should be, in C notation:
-                    //
-                    //   `size + ((size & (align-1)) ? align : 0)`
-                    //
-                    // emulated via the semi-standard fast bit trick:
-                    //
-                    //   `(size + (align-1)) & -align`
-
-                    Ok((size.abi_align(align), align))
-                }
-                ty::Dynamic(..) => {
-                    let vtable = match mplace.extra {
-                        PlaceExtra::Vtable(vtable) => vtable,
-                        _ => bug!("Expected vtable"),
-                    };
-                    // the second entry in the vtable is the dynamic size of the object.
-                    self.read_size_and_align_from_vtable(vtable)
-                }
-
-                ty::Slice(_) | ty::Str => {
-                    let len = match mplace.extra {
-                        PlaceExtra::Length(len) => len,
-                        _ => bug!("Expected length"),
-                    };
-                    let (elem_size, align) = layout.field(self, 0)?.size_and_align();
-                    Ok((elem_size * len, align))
-                }
+        let metadata = match metadata {
+            None => {
+                assert!(!layout.is_unsized());
+                return Ok(layout.size_and_align())
+            }
+            Some(metadata) => {
+                assert!(layout.is_unsized());
+                metadata
+            }
+        };
+        match layout.ty.sty {
+            ty::Adt(..) | ty::Tuple(..) => {
+                // First get the size of all statically known fields.
+                // Don't use type_of::sizing_type_of because that expects t to be sized,
+                // and it also rounds up to alignment, which we want to avoid,
+                // as the unsized field's alignment could be smaller.
+                assert!(!layout.ty.is_simd());
+                debug!("DST layout: {:?}", layout);
+
+                let sized_size = layout.fields.offset(layout.fields.count() - 1);
+                let sized_align = layout.align;
+                debug!(
+                    "DST {} statically sized prefix size: {:?} align: {:?}",
+                    layout.ty,
+                    sized_size,
+                    sized_align
+                );
+
+                // Recurse to get the size of the dynamically sized field (must be
+                // the last field).
+                let field = layout.field(self, layout.fields.count() - 1)?;
+                let (unsized_size, unsized_align) = self.size_and_align_of(Some(metadata), field)?;
+
+                // FIXME (#26403, #27023): We should be adding padding
+                // to `sized_size` (to accommodate the `unsized_align`
+                // required of the unsized field that follows) before
+                // summing it with `sized_size`. (Note that since #26403
+                // is unfixed, we do not yet add the necessary padding
+                // here. But this is where the add would go.)
+
+                // Return the sum of sizes and max of aligns.
+                let size = sized_size + unsized_size;
+
+                // Choose max of two known alignments (combined value must
+                // be aligned according to more restrictive of the two).
+                let align = sized_align.max(unsized_align);
+
+                // Issue #27023: must add any necessary padding to `size`
+                // (to make it a multiple of `align`) before returning it.
+                //
+                // Namely, the returned size should be, in C notation:
+                //
+                //   `size + ((size & (align-1)) ? align : 0)`
+                //
+                // emulated via the semi-standard fast bit trick:
+                //
+                //   `(size + (align-1)) & -align`
+
+                Ok((size.abi_align(align), align))
+            }
+            ty::Dynamic(..) => {
+                let vtable = metadata.to_ptr()?;
+                // the second entry in the vtable is the dynamic size of the object.
+                self.read_size_and_align_from_vtable(vtable)
+            }
 
-                _ => bug!("size_of_val::<{:?}> not supported", layout.ty),
+            ty::Slice(_) | ty::Str => {
+                let len = metadata.to_usize(self)?;
+                let (elem_size, align) = layout.field(self, 0)?.size_and_align();
+                Ok((elem_size * len, align))
             }
+
+            _ => bug!("size_and_align_of::<{:?}> not supported", layout.ty),
         }
     }
+    #[inline]
+    pub fn size_and_align_of_mplace(
+        &self,
+        mplace: MPlaceTy<'tcx>
+    ) -> EvalResult<'tcx, (Size, Align)> {
+        self.size_and_align_of(mplace.extra, mplace.layout)
+    }
 
     pub fn push_stack_frame(
         &mut self,
@@ -628,25 +629,19 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
 
     pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
         ::log_settings::settings().indentation -= 1;
-        M::end_region(self, None)?;
         let frame = self.stack.pop().expect(
             "tried to pop a stack frame, but there were none",
         );
         match frame.return_to_block {
-            StackPopCleanup::MarkStatic(mutable) => {
-                if let Place::Ptr(MemPlace { ptr, .. }) = frame.return_place {
-                    // FIXME: to_ptr()? might be too extreme here,
-                    // static zsts might reach this under certain conditions
-                    self.memory.mark_static_initialized(
-                        ptr.to_ptr()?.alloc_id,
-                        mutable,
-                    )?
-                } else {
-                    bug!("StackPopCleanup::MarkStatic on: {:?}", frame.return_place);
+            StackPopCleanup::Goto(block) => {
+                self.goto_block(block)?;
+            }
+            StackPopCleanup::None { cleanup } => {
+                if !cleanup {
+                    // Leak the locals
+                    return Ok(());
                 }
             }
-            StackPopCleanup::Goto(target) => self.goto_block(target),
-            StackPopCleanup::None => {}
         }
         // deallocate all locals that are backed by an allocation
         for local in frame.locals {
@@ -656,7 +651,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
         Ok(())
     }
 
-    crate fn deallocate_local(&mut self, local: LocalValue) -> EvalResult<'tcx> {
+    pub(super) fn deallocate_local(&mut self, local: LocalValue) -> EvalResult<'tcx> {
         // FIXME: should we tell the user that there was a local which was never written to?
         if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
             trace!("deallocating local");
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
new file mode 100644
index 00000000000..35e3253ca7f
--- /dev/null
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -0,0 +1,175 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Intrinsics and other functions that the miri engine executes without
+//! looking at their MIR.  Intrinsics/functions supported here are shared by CTFE
+//! and miri.
+
+use syntax::symbol::Symbol;
+use rustc::ty;
+use rustc::ty::layout::{LayoutOf, Primitive};
+use rustc::mir::interpret::{
+    EvalResult, EvalErrorKind, Scalar,
+};
+
+use super::{
+    Machine, PlaceTy, OpTy, EvalContext,
+};
+
+
+fn numeric_intrinsic<'tcx>(
+    name: &str,
+    bits: u128,
+    kind: Primitive,
+) -> EvalResult<'tcx, Scalar> {
+    let size = match kind {
+        Primitive::Int(integer, _) => integer.size(),
+        _ => bug!("invalid `{}` argument: {:?}", name, bits),
+    };
+    let extra = 128 - size.bits() as u128;
+    let bits_out = match name {
+        "ctpop" => bits.count_ones() as u128,
+        "ctlz" => bits.leading_zeros() as u128 - extra,
+        "cttz" => (bits << extra).trailing_zeros() as u128 - extra,
+        "bswap" => (bits << extra).swap_bytes(),
+        _ => bug!("not a numeric intrinsic: {}", name),
+    };
+    Ok(Scalar::Bits { bits: bits_out, size: size.bytes() as u8 })
+}
+
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
+    /// Returns whether emulation happened.
+    pub fn emulate_intrinsic(
+        &mut self,
+        instance: ty::Instance<'tcx>,
+        args: &[OpTy<'tcx>],
+        dest: PlaceTy<'tcx>,
+    ) -> EvalResult<'tcx, bool> {
+        let substs = instance.substs;
+
+        let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..];
+        match intrinsic_name {
+            "min_align_of" => {
+                let elem_ty = substs.type_at(0);
+                let elem_align = self.layout_of(elem_ty)?.align.abi();
+                let align_val = Scalar::Bits {
+                    bits: elem_align as u128,
+                    size: dest.layout.size.bytes() as u8,
+                };
+                self.write_scalar(align_val, dest)?;
+            }
+
+            "size_of" => {
+                let ty = substs.type_at(0);
+                let size = self.layout_of(ty)?.size.bytes() as u128;
+                let size_val = Scalar::Bits {
+                    bits: size,
+                    size: dest.layout.size.bytes() as u8,
+                };
+                self.write_scalar(size_val, dest)?;
+            }
+
+            "type_id" => {
+                let ty = substs.type_at(0);
+                let type_id = self.tcx.type_id_hash(ty) as u128;
+                let id_val = Scalar::Bits {
+                    bits: type_id,
+                    size: dest.layout.size.bytes() as u8,
+                };
+                self.write_scalar(id_val, dest)?;
+            }
+            "ctpop" | "cttz" | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" | "bswap" => {
+                let ty = substs.type_at(0);
+                let layout_of = self.layout_of(ty)?;
+                let bits = self.read_scalar(args[0])?.to_bits(layout_of.size)?;
+                let kind = match layout_of.abi {
+                    ty::layout::Abi::Scalar(ref scalar) => scalar.value,
+                    _ => Err(::rustc::mir::interpret::EvalErrorKind::TypeNotPrimitive(ty))?,
+                };
+                let out_val = if intrinsic_name.ends_with("_nonzero") {
+                    if bits == 0 {
+                        return err!(Intrinsic(format!("{} called on 0", intrinsic_name)));
+                    }
+                    numeric_intrinsic(intrinsic_name.trim_right_matches("_nonzero"), bits, kind)?
+                } else {
+                    numeric_intrinsic(intrinsic_name, bits, kind)?
+                };
+                self.write_scalar(out_val, dest)?;
+            }
+
+            _ => return Ok(false),
+        }
+
+        Ok(true)
+    }
+
+    /// "Intercept" a function call because we have something special to do for it.
+    /// Returns whether an intercept happened.
+    pub fn hook_fn(
+        &mut self,
+        instance: ty::Instance<'tcx>,
+        args: &[OpTy<'tcx>],
+        dest: Option<PlaceTy<'tcx>>,
+    ) -> EvalResult<'tcx, bool> {
+        let def_id = instance.def_id();
+        // Some fn calls are actually BinOp intrinsics
+        if let Some((op, oflo)) = self.tcx.is_binop_lang_item(def_id) {
+            let dest = dest.expect("128 lowerings can't diverge");
+            let l = self.read_value(args[0])?;
+            let r = self.read_value(args[1])?;
+            if oflo {
+                self.binop_with_overflow(op, l, r, dest)?;
+            } else {
+                self.binop_ignore_overflow(op, l, r, dest)?;
+            }
+            return Ok(true);
+        } else if Some(def_id) == self.tcx.lang_items().panic_fn() {
+            assert!(args.len() == 1);
+            // &(&'static str, &'static str, u32, u32)
+            let ptr = self.read_value(args[0])?;
+            let place = self.ref_to_mplace(ptr)?;
+            let (msg, file, line, col) = (
+                self.mplace_field(place, 0)?,
+                self.mplace_field(place, 1)?,
+                self.mplace_field(place, 2)?,
+                self.mplace_field(place, 3)?,
+            );
+
+            let msg_place = self.ref_to_mplace(self.read_value(msg.into())?)?;
+            let msg = Symbol::intern(self.read_str(msg_place)?);
+            let file_place = self.ref_to_mplace(self.read_value(file.into())?)?;
+            let file = Symbol::intern(self.read_str(file_place)?);
+            let line = self.read_scalar(line.into())?.to_u32()?;
+            let col = self.read_scalar(col.into())?.to_u32()?;
+            return Err(EvalErrorKind::Panic { msg, file, line, col }.into());
+        } else if Some(def_id) == self.tcx.lang_items().begin_panic_fn() {
+            assert!(args.len() == 2);
+            // &'static str, &(&'static str, u32, u32)
+            let msg = args[0];
+            let ptr = self.read_value(args[1])?;
+            let place = self.ref_to_mplace(ptr)?;
+            let (file, line, col) = (
+                self.mplace_field(place, 0)?,
+                self.mplace_field(place, 1)?,
+                self.mplace_field(place, 2)?,
+            );
+
+            let msg_place = self.ref_to_mplace(self.read_value(msg.into())?)?;
+            let msg = Symbol::intern(self.read_str(msg_place)?);
+            let file_place = self.ref_to_mplace(self.read_value(file.into())?)?;
+            let file = Symbol::intern(self.read_str(file_place)?);
+            let line = self.read_scalar(line.into())?.to_u32()?;
+            let col = self.read_scalar(col.into())?.to_u32()?;
+            return Err(EvalErrorKind::Panic { msg, file, line, col }.into());
+        } else {
+            return Ok(false);
+        }
+    }
+}
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index 1fcdab2be62..a8fae2b4871 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -14,14 +14,12 @@
 
 use std::hash::Hash;
 
-use rustc::mir::interpret::{AllocId, EvalResult, Scalar, Pointer, AccessKind, GlobalId};
-use super::{EvalContext, PlaceTy, OpTy, Memory};
-
+use rustc::hir::def_id::DefId;
+use rustc::mir::interpret::{Allocation, EvalResult, Scalar};
 use rustc::mir;
-use rustc::ty::{self, layout::TyLayout};
-use rustc::ty::layout::Size;
-use syntax::source_map::Span;
-use syntax::ast::Mutability;
+use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt};
+
+use super::{EvalContext, PlaceTy, OpTy};
 
 /// Methods of this trait signifies a point where CTFE evaluation would fail
 /// and some use case dependent behaviour can instead be applied
@@ -30,31 +28,47 @@ pub trait Machine<'mir, 'tcx>: Clone + Eq + Hash {
     type MemoryData: Clone + Eq + Hash;
 
     /// Additional memory kinds a machine wishes to distinguish from the builtin ones
-    type MemoryKinds: ::std::fmt::Debug + PartialEq + Copy + Clone;
+    type MemoryKinds: ::std::fmt::Debug + Copy + Clone + Eq + Hash;
+
+    /// The memory kind to use for mutated statics -- or None if those are not supported.
+    const MUT_STATIC_KIND: Option<Self::MemoryKinds>;
 
     /// Entry point to all function calls.
     ///
-    /// Returns Ok(true) when the function was handled completely
-    /// e.g. due to missing mir
-    ///
-    /// Returns Ok(false) if a new stack frame was pushed
-    fn eval_fn_call<'a>(
+    /// Returns either the mir to use for the call, or `None` if execution should
+    /// just proceed (which usually means this hook did all the work that the
+    /// called function should usually have done).  In the latter case, it is
+    /// this hook's responsibility to call `goto_block(ret)` to advance the instruction pointer!
+    /// (This is to support functions like `__rust_maybe_catch_panic` that neither find a MIR
+    /// nor just jump to `ret`, but instead push their own stack frame.)
+    /// Passing `dest`and `ret` in the same `Option` proved very annoying when only one of them
+    /// was used.
+    fn find_fn<'a>(
         ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
-        destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
         args: &[OpTy<'tcx>],
-        span: Span,
-    ) -> EvalResult<'tcx, bool>;
+        dest: Option<PlaceTy<'tcx>>,
+        ret: Option<mir::BasicBlock>,
+    ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>>;
 
-    /// directly process an intrinsic without pushing a stack frame.
+    /// Directly process an intrinsic without pushing a stack frame.
+    /// If this returns successfully, the engine will take care of jumping to the next block.
     fn call_intrinsic<'a>(
         ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
         dest: PlaceTy<'tcx>,
-        target: mir::BasicBlock,
     ) -> EvalResult<'tcx>;
 
+    /// Called for read access to a foreign static item.
+    /// This can be called multiple times for the same static item and should return consistent
+    /// results.  Once the item is *written* the first time, as usual for statics a copy is
+    /// made and this function is not called again.
+    fn find_foreign_static<'a>(
+        tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
+        def_id: DefId,
+    ) -> EvalResult<'tcx, &'tcx Allocation>;
+
     /// Called for all binary operations except on float types.
     ///
     /// Returns `None` if the operation should be handled by the integer
@@ -70,20 +84,6 @@ pub trait Machine<'mir, 'tcx>: Clone + Eq + Hash {
         right_layout: TyLayout<'tcx>,
     ) -> EvalResult<'tcx, Option<(Scalar, bool)>>;
 
-    /// Called when trying to mark machine defined `MemoryKinds` as static
-    fn mark_static_initialized<'a>(
-        _mem: &mut Memory<'a, 'mir, 'tcx, Self>,
-        _id: AllocId,
-        _mutability: Mutability,
-    ) -> EvalResult<'tcx, bool>;
-
-    /// Called when requiring a pointer to a static. Non const eval can
-    /// create a mutable memory location for `static mut`
-    fn init_static<'a>(
-        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
-        cid: GlobalId<'tcx>,
-    ) -> EvalResult<'tcx, AllocId>;
-
     /// Heap allocations via the `box` keyword
     ///
     /// Returns a pointer to the allocated memory
@@ -92,42 +92,7 @@ pub trait Machine<'mir, 'tcx>: Clone + Eq + Hash {
         dest: PlaceTy<'tcx>,
     ) -> EvalResult<'tcx>;
 
-    /// Called when trying to access a global declared with a `linkage` attribute
-    fn global_item_with_linkage<'a>(
-        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
-        instance: ty::Instance<'tcx>,
-        mutability: Mutability,
-    ) -> EvalResult<'tcx>;
-
-    fn check_locks<'a>(
-        _mem: &Memory<'a, 'mir, 'tcx, Self>,
-        _ptr: Pointer,
-        _size: Size,
-        _access: AccessKind,
-    ) -> EvalResult<'tcx> {
-        Ok(())
-    }
-
-    fn add_lock<'a>(
-        _mem: &mut Memory<'a, 'mir, 'tcx, Self>,
-        _id: AllocId,
-    ) {}
-
-    fn free_lock<'a>(
-        _mem: &mut Memory<'a, 'mir, 'tcx, Self>,
-        _id: AllocId,
-        _len: u64,
-    ) -> EvalResult<'tcx> {
-        Ok(())
-    }
-
-    fn end_region<'a>(
-        _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
-        _reg: Option<::rustc::middle::region::Scope>,
-    ) -> EvalResult<'tcx> {
-        Ok(())
-    }
-
+    /// Execute a validation operation
     fn validation_op<'a>(
         _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         _op: ::rustc::mir::ValidationOp,
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 6f1a126534c..240f977a5a0 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -20,26 +20,18 @@ use std::collections::VecDeque;
 use std::hash::{Hash, Hasher};
 use std::ptr;
 
-use rustc::hir::def_id::DefId;
-use rustc::ty::Instance;
-use rustc::ty::ParamEnv;
-use rustc::ty::query::TyCtxtAt;
-use rustc::ty::layout::{self, Align, TargetDataLayout, Size};
-use rustc::mir::interpret::{Pointer, AllocId, Allocation, AccessKind, ScalarMaybeUndef,
-                            EvalResult, Scalar, EvalErrorKind, GlobalId, AllocType, truncate};
+use rustc::ty::{self, Instance, query::TyCtxtAt};
+use rustc::ty::layout::{self, Align, TargetDataLayout, Size, HasDataLayout};
+use rustc::mir::interpret::{Pointer, AllocId, Allocation, ScalarMaybeUndef, GlobalId,
+                            EvalResult, Scalar, EvalErrorKind, AllocType, truncate};
 pub use rustc::mir::interpret::{write_target_uint, read_target_uint};
 use rustc_data_structures::fx::{FxHashSet, FxHashMap, FxHasher};
 
 use syntax::ast::Mutability;
 
-use super::{EvalContext, Machine};
+use super::Machine;
 
-
-////////////////////////////////////////////////////////////////////////////////
-// Allocations and pointers
-////////////////////////////////////////////////////////////////////////////////
-
-#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
 pub enum MemoryKind<T> {
     /// Error if deallocated except during a stack pop
     Stack,
@@ -47,24 +39,28 @@ pub enum MemoryKind<T> {
     Machine(T),
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// Top-level interpreter memory
-////////////////////////////////////////////////////////////////////////////////
-
 #[derive(Clone)]
 pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
     /// Additional data required by the Machine
     pub data: M::MemoryData,
 
-    /// Helps guarantee that stack allocations aren't deallocated via `rust_deallocate`
-    alloc_kind: FxHashMap<AllocId, MemoryKind<M::MemoryKinds>>,
-
-    /// Actual memory allocations (arbitrary bytes, may contain pointers into other allocations).
-    alloc_map: FxHashMap<AllocId, Allocation>,
+    /// Allocations local to this instance of the miri engine.  The kind
+    /// helps ensure that the same mechanism is used for allocation and
+    /// deallocation.  When an allocation is not found here, it is a
+    /// static and looked up in the `tcx` for read access.  Writing to
+    /// a static creates a copy here, in the machine.
+    alloc_map: FxHashMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation)>,
 
     pub tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
 }
 
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for &'a Memory<'a, 'mir, 'tcx, M> {
+    #[inline]
+    fn data_layout(&self) -> &TargetDataLayout {
+        &self.tcx.data_layout
+    }
+}
+
 impl<'a, 'mir, 'tcx, M> Eq for Memory<'a, 'mir, 'tcx, M>
     where M: Machine<'mir, 'tcx>,
           'tcx: 'a + 'mir,
@@ -77,13 +73,11 @@ impl<'a, 'mir, 'tcx, M> PartialEq for Memory<'a, 'mir, 'tcx, M>
     fn eq(&self, other: &Self) -> bool {
         let Memory {
             data,
-            alloc_kind,
             alloc_map,
             tcx: _,
         } = self;
 
         *data == other.data
-            && *alloc_kind == other.alloc_kind
             && *alloc_map == other.alloc_map
     }
 }
@@ -95,7 +89,6 @@ impl<'a, 'mir, 'tcx, M> Hash for Memory<'a, 'mir, 'tcx, M>
     fn hash<H: Hasher>(&self, state: &mut H) {
         let Memory {
             data,
-            alloc_kind: _,
             alloc_map: _,
             tcx: _,
         } = self;
@@ -108,10 +101,11 @@ impl<'a, 'mir, 'tcx, M> Hash for Memory<'a, 'mir, 'tcx, M>
         // iteration orders, we use a commutative operation (in this case
         // addition, but XOR would also work), to combine the hash of each
         // `Allocation`.
-        self.allocations()
-            .map(|allocs| {
+        self.alloc_map.iter()
+            .map(|(&id, alloc)| {
                 let mut h = FxHasher::default();
-                allocs.hash(&mut h);
+                id.hash(&mut h);
+                alloc.hash(&mut h);
                 h.finish()
             })
             .fold(0u64, |hash, x| hash.wrapping_add(x))
@@ -119,51 +113,79 @@ impl<'a, 'mir, 'tcx, M> Hash for Memory<'a, 'mir, 'tcx, M>
     }
 }
 
+/// Helper function to obtain the global (tcx) allocation for a static
+fn const_eval_static<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>>(
+    tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
+    id: AllocId
+) -> EvalResult<'tcx, &'tcx Allocation> {
+    let alloc = tcx.alloc_map.lock().get(id);
+    let def_id = match alloc {
+        Some(AllocType::Memory(mem)) => {
+            return Ok(mem)
+        }
+        Some(AllocType::Function(..)) => {
+            return err!(DerefFunctionPointer)
+        }
+        Some(AllocType::Static(did)) => {
+            did
+        }
+        None =>
+            return err!(DanglingPointerDeref),
+    };
+    // We got a "lazy" static that has not been computed yet, do some work
+    trace!("static_alloc: Need to compute {:?}", def_id);
+    if tcx.is_foreign_item(def_id) {
+        return M::find_foreign_static(tcx, def_id);
+    }
+    let instance = Instance::mono(tcx.tcx, def_id);
+    let gid = GlobalId {
+        instance,
+        promoted: None,
+    };
+    tcx.const_eval(ty::ParamEnv::reveal_all().and(gid)).map_err(|err| {
+        // no need to report anything, the const_eval call takes care of that for statics
+        assert!(tcx.is_static(def_id).is_some());
+        EvalErrorKind::ReferencedConstant(err).into()
+    }).map(|val| {
+        // FIXME We got our static (will be a ByRef), now we make a *copy*?!?
+        tcx.const_to_allocation(val)
+    })
+}
+
 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self {
         Memory {
             data,
-            alloc_kind: FxHashMap::default(),
             alloc_map: FxHashMap::default(),
             tcx,
         }
     }
 
-    pub fn allocations<'x>(
-        &'x self,
-    ) -> impl Iterator<Item = (AllocId, &'x Allocation)> {
-        self.alloc_map.iter().map(|(&id, alloc)| (id, alloc))
-    }
-
     pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> Pointer {
         self.tcx.alloc_map.lock().create_fn_alloc(instance).into()
     }
 
-    pub fn allocate_bytes(&mut self, bytes: &[u8]) -> Pointer {
+    pub fn allocate_static_bytes(&mut self, bytes: &[u8]) -> Pointer {
         self.tcx.allocate_bytes(bytes).into()
     }
 
-    /// kind is `None` for statics
-    pub fn allocate_value(
+    pub fn allocate_with(
         &mut self,
         alloc: Allocation,
         kind: MemoryKind<M::MemoryKinds>,
     ) -> EvalResult<'tcx, AllocId> {
         let id = self.tcx.alloc_map.lock().reserve();
-        M::add_lock(self, id);
-        self.alloc_map.insert(id, alloc);
-        self.alloc_kind.insert(id, kind);
+        self.alloc_map.insert(id, (kind, alloc));
         Ok(id)
     }
 
-    /// kind is `None` for statics
     pub fn allocate(
         &mut self,
         size: Size,
         align: Align,
         kind: MemoryKind<M::MemoryKinds>,
     ) -> EvalResult<'tcx, Pointer> {
-        self.allocate_value(Allocation::undef(size, align), kind).map(Pointer::from)
+        self.allocate_with(Allocation::undef(size, align), kind).map(Pointer::from)
     }
 
     pub fn reallocate(
@@ -178,15 +200,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         if ptr.offset.bytes() != 0 {
             return err!(ReallocateNonBasePtr);
         }
-        if self.alloc_map.contains_key(&ptr.alloc_id) {
-            let alloc_kind = self.alloc_kind[&ptr.alloc_id];
-            if alloc_kind != kind {
-                return err!(ReallocatedWrongMemoryKind(
-                    format!("{:?}", alloc_kind),
-                    format!("{:?}", kind),
-                ));
-            }
-        }
 
         // For simplicities' sake, we implement reallocate as "alloc, copy, dealloc"
         let new_ptr = self.allocate(new_size, new_align, kind)?;
@@ -196,20 +209,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
             new_ptr.into(),
             new_align,
             old_size.min(new_size),
-            /*nonoverlapping*/
-            true,
+            /*nonoverlapping*/ true,
         )?;
         self.deallocate(ptr, Some((old_size, old_align)), kind)?;
 
         Ok(new_ptr)
     }
 
+    /// Deallocate a local, or do nothing if that local has been made into a static
     pub fn deallocate_local(&mut self, ptr: Pointer) -> EvalResult<'tcx> {
-        match self.alloc_kind.get(&ptr.alloc_id).cloned() {
-            Some(MemoryKind::Stack) => self.deallocate(ptr, None, MemoryKind::Stack),
-            // Happens if the memory was interned into immutable memory
-            None => Ok(()),
-            other => bug!("local contained non-stack memory: {:?}", other),
+        // The allocation might be already removed by static interning.
+        // This can only really happen in the CTFE instance, not in miri.
+        if self.alloc_map.contains_key(&ptr.alloc_id) {
+            self.deallocate(ptr, None, MemoryKind::Stack)
+        } else {
+            Ok(())
         }
     }
 
@@ -223,9 +237,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
             return err!(DeallocateNonBasePtr);
         }
 
-        let alloc = match self.alloc_map.remove(&ptr.alloc_id) {
+        let (alloc_kind, alloc) = match self.alloc_map.remove(&ptr.alloc_id) {
             Some(alloc) => alloc,
             None => {
+                // Deallocating static memory -- always an error
                 return match self.tcx.alloc_map.lock().get(ptr.alloc_id) {
                     Some(AllocType::Function(..)) => err!(DeallocatedWrongMemoryKind(
                         "function".to_string(),
@@ -241,18 +256,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
             }
         };
 
-        let alloc_kind = self.alloc_kind
-                        .remove(&ptr.alloc_id)
-                        .expect("alloc_map out of sync with alloc_kind");
-
-        // It is okay for us to still holds locks on deallocation -- for example, we could store
-        // data we own in a local, and the local could be deallocated (from StorageDead) before the
-        // function returns. However, we should check *something*.  For now, we make sure that there
-        // is no conflicting write lock by another frame.  We *have* to permit deallocation if we
-        // hold a read lock.
-        // FIXME: Figure out the exact rules here.
-        M::free_lock(self, ptr.alloc_id, alloc.bytes.len() as u64)?;
-
         if alloc_kind != kind {
             return err!(DeallocatedWrongMemoryKind(
                 format!("{:?}", alloc_kind),
@@ -339,63 +342,37 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
 
 /// Allocation accessors
 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
-    fn const_eval_static(&self, def_id: DefId) -> EvalResult<'tcx, &'tcx Allocation> {
-        if self.tcx.is_foreign_item(def_id) {
-            return err!(ReadForeignStatic);
-        }
-        let instance = Instance::mono(self.tcx.tcx, def_id);
-        let gid = GlobalId {
-            instance,
-            promoted: None,
-        };
-        self.tcx.const_eval(ParamEnv::reveal_all().and(gid)).map_err(|err| {
-            // no need to report anything, the const_eval call takes care of that for statics
-            assert!(self.tcx.is_static(def_id).is_some());
-            EvalErrorKind::ReferencedConstant(err).into()
-        }).map(|val| {
-            self.tcx.const_to_allocation(val)
-        })
-    }
-
     pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
-        // normal alloc?
         match self.alloc_map.get(&id) {
-            Some(alloc) => Ok(alloc),
-            // uninitialized static alloc?
-            None => {
-                // static alloc?
-                let alloc = self.tcx.alloc_map.lock().get(id);
-                match alloc {
-                    Some(AllocType::Memory(mem)) => Ok(mem),
-                    Some(AllocType::Function(..)) => {
-                        Err(EvalErrorKind::DerefFunctionPointer.into())
-                    }
-                    Some(AllocType::Static(did)) => {
-                        self.const_eval_static(did)
-                    }
-                    None => Err(EvalErrorKind::DanglingPointerDeref.into()),
-                }
-            },
+            // Normal alloc?
+            Some(alloc) => Ok(&alloc.1),
+            // Static. No need to make any copies, just provide read access to the global static
+            // memory in tcx.
+            None => const_eval_static::<M>(self.tcx, id),
         }
     }
 
-    fn get_mut(
+    pub fn get_mut(
         &mut self,
         id: AllocId,
     ) -> EvalResult<'tcx, &mut Allocation> {
-        // normal alloc?
-        match self.alloc_map.get_mut(&id) {
-            Some(alloc) => Ok(alloc),
-            // uninitialized static alloc?
-            None => {
-                // no alloc or immutable alloc? produce an error
-                match self.tcx.alloc_map.lock().get(id) {
-                    Some(AllocType::Memory(..)) |
-                    Some(AllocType::Static(..)) => err!(ModifiedConstantMemory),
-                    Some(AllocType::Function(..)) => err!(DerefFunctionPointer),
-                    None => err!(DanglingPointerDeref),
-                }
-            },
+        // Static?
+        if !self.alloc_map.contains_key(&id) {
+            // Ask the machine for what to do
+            if let Some(kind) = M::MUT_STATIC_KIND {
+                // The machine supports mutating statics.  Make a copy, use that.
+                self.deep_copy_static(id, MemoryKind::Machine(kind))?;
+            } else {
+                return err!(ModifiedConstantMemory)
+            }
+        }
+        // If we come here, we know the allocation is in our map
+        let alloc = &mut self.alloc_map.get_mut(&id).unwrap().1;
+        // See if we are allowed to mutate this
+        if alloc.mutability == Mutability::Immutable {
+            err!(ModifiedConstantMemory)
+        } else {
+            Ok(alloc)
         }
     }
 
@@ -410,10 +387,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         }
     }
 
-    pub fn get_alloc_kind(&self, id: AllocId) -> Option<MemoryKind<M::MemoryKinds>> {
-        self.alloc_kind.get(&id).cloned()
-    }
-
     /// For debugging, print an allocation and all allocations it points to, recursively.
     pub fn dump_alloc(&self, id: AllocId) {
         if !log_enabled!(::log::Level::Trace) {
@@ -441,14 +414,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
             let (alloc, immutable) =
                 // normal alloc?
                 match self.alloc_map.get(&id) {
-                    Some(a) => (a, match self.alloc_kind[&id] {
+                    Some((kind, alloc)) => (alloc, match kind {
                         MemoryKind::Stack => " (stack)".to_owned(),
                         MemoryKind::Machine(m) => format!(" ({:?})", m),
                     }),
                     None => {
                         // static alloc?
                         match self.tcx.alloc_map.lock().get(id) {
-                            Some(AllocType::Memory(a)) => (a, "(immutable)".to_owned()),
+                            Some(AllocType::Memory(a)) => (a, " (immutable)".to_owned()),
                             Some(AllocType::Function(func)) => {
                                 trace!("{} {}", msg, func);
                                 continue;
@@ -509,9 +482,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
 
     pub fn leak_report(&self) -> usize {
         trace!("### LEAK REPORT ###");
+        let mut_static_kind = M::MUT_STATIC_KIND.map(|k| MemoryKind::Machine(k));
         let leaks: Vec<_> = self.alloc_map
-            .keys()
-            .cloned()
+            .iter()
+            .filter_map(|(&id, &(kind, _))|
+                // exclude mutable statics
+                if Some(kind) == mut_static_kind { None } else { Some(id) } )
             .collect();
         let n = leaks.len();
         self.dump_allocs(leaks);
@@ -534,7 +510,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         if size.bytes() == 0 {
             return Ok(&[]);
         }
-        M::check_locks(self, ptr, size, AccessKind::Read)?;
         // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
         self.check_bounds(ptr.offset(size, self)?, true)?;
         let alloc = self.get(ptr.alloc_id)?;
@@ -557,7 +532,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         if size.bytes() == 0 {
             return Ok(&mut []);
         }
-        M::check_locks(self, ptr, size, AccessKind::Write)?;
         // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
         self.check_bounds(ptr.offset(size, &*self)?, true)?;
         let alloc = self.get_mut(ptr.alloc_id)?;
@@ -591,22 +565,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
 
 /// Reading and writing
 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
-    /// mark an allocation pointed to by a static as static and initialized
-    fn mark_inner_allocation_initialized(
-        &mut self,
-        alloc: AllocId,
-        mutability: Mutability,
-    ) -> EvalResult<'tcx> {
-        match self.alloc_kind.get(&alloc) {
-            // do not go into statics
-            None => Ok(()),
-            // just locals and machine allocs
-            Some(_) => self.mark_static_initialized(alloc, mutability),
-        }
-    }
-
     /// mark an allocation as static and initialized, either mutable or not
-    pub fn mark_static_initialized(
+    pub fn intern_static(
         &mut self,
         alloc_id: AllocId,
         mutability: Mutability,
@@ -616,31 +576,48 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
             alloc_id,
             mutability
         );
-        // The machine handled it
-        if M::mark_static_initialized(self, alloc_id, mutability)? {
-            return Ok(())
-        }
-        let alloc = self.alloc_map.remove(&alloc_id);
-        match self.alloc_kind.remove(&alloc_id) {
-            None => {},
-            Some(MemoryKind::Machine(_)) => bug!("machine didn't handle machine alloc"),
-            Some(MemoryKind::Stack) => {},
-        }
-        if let Some(mut alloc) = alloc {
-            // ensure llvm knows not to put this into immutable memory
-            alloc.runtime_mutability = mutability;
-            let alloc = self.tcx.intern_const_alloc(alloc);
-            self.tcx.alloc_map.lock().set_id_memory(alloc_id, alloc);
-            // recurse into inner allocations
-            for &alloc in alloc.relocations.values() {
-                self.mark_inner_allocation_initialized(alloc, mutability)?;
+        // remove allocation
+        let (kind, mut alloc) = self.alloc_map.remove(&alloc_id).unwrap();
+        match kind {
+            MemoryKind::Machine(_) => bug!("Static cannot refer to machine memory"),
+            MemoryKind::Stack => {},
+        }
+        // ensure llvm knows not to put this into immutable memory
+        alloc.mutability = mutability;
+        let alloc = self.tcx.intern_const_alloc(alloc);
+        self.tcx.alloc_map.lock().set_id_memory(alloc_id, alloc);
+        // recurse into inner allocations
+        for &alloc in alloc.relocations.values() {
+            // FIXME: Reusing the mutability here is likely incorrect.  It is originally
+            // determined via `is_freeze`, and data is considered frozen if there is no
+            // `UnsafeCell` *immediately* in that data -- however, this search stops
+            // at references.  So whenever we follow a reference, we should likely
+            // assume immutability -- and we should make sure that the compiler
+            // does not permit code that would break this!
+            if self.alloc_map.contains_key(&alloc) {
+                // Not yet interned, so proceed recursively
+                self.intern_static(alloc, mutability)?;
             }
-        } else {
-            bug!("no allocation found for {:?}", alloc_id);
         }
         Ok(())
     }
 
+    /// The alloc_id must refer to a (mutable) static; a deep copy of that
+    /// static is made into this memory.
+    fn deep_copy_static(
+        &mut self,
+        id: AllocId,
+        kind: MemoryKind<M::MemoryKinds>,
+    ) -> EvalResult<'tcx> {
+        let alloc = const_eval_static::<M>(self.tcx, id)?;
+        if alloc.mutability == Mutability::Immutable {
+            return err!(ModifiedConstantMemory);
+        }
+        let old = self.alloc_map.insert(id, (kind, alloc.clone()));
+        assert!(old.is_none(), "deep_copy_static: must not overwrite existing memory");
+        Ok(())
+    }
+
     pub fn copy(
         &mut self,
         src: Scalar,
@@ -745,7 +722,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
                     return err!(ReadPointerAsBytes);
                 }
                 self.check_defined(ptr, p1)?;
-                M::check_locks(self, ptr, p1, AccessKind::Read)?;
                 Ok(&alloc.bytes[offset..offset + size])
             }
             None => err!(UnterminatedCString(ptr)),
@@ -802,9 +778,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         let bytes = self.get_bytes_unchecked(ptr, size, ptr_align.min(self.int_align(size)))?;
         // Undef check happens *after* we established that the alignment is correct.
         // We must not return Ok() for unaligned pointers!
-        if self.check_defined(ptr, size).is_err() {
-            // this inflates undefined bytes to the entire scalar,
-            // even if only a few bytes are undefined
+        if !self.is_defined(ptr, size)? {
+            // this inflates undefined bytes to the entire scalar, even if only a few
+            // bytes are undefined
             return Ok(ScalarMaybeUndef::Undef);
         }
         // Now we do the actual reading
@@ -990,16 +966,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         Ok(())
     }
 
-    fn check_defined(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
+    fn is_defined(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx, bool> {
         let alloc = self.get(ptr.alloc_id)?;
-        if !alloc.undef_mask.is_range_defined(
+        Ok(alloc.undef_mask.is_range_defined(
             ptr.offset,
             ptr.offset + size,
-        )
-        {
-            return err!(ReadUndefBytes);
+        ))
+    }
+
+    #[inline]
+    fn check_defined(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
+        if self.is_defined(ptr, size)? {
+            Ok(())
+        } else {
+            err!(ReadUndefBytes)
         }
-        Ok(())
     }
 
     pub fn mark_definedness(
@@ -1020,49 +1001,3 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         Ok(())
     }
 }
-
-////////////////////////////////////////////////////////////////////////////////
-// Unaligned accesses
-////////////////////////////////////////////////////////////////////////////////
-
-pub trait HasMemory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
-    fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M>;
-    fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M>;
-}
-
-impl<'a, 'mir, 'tcx, M> HasMemory<'a, 'mir, 'tcx, M> for Memory<'a, 'mir, 'tcx, M>
-    where M: Machine<'mir, 'tcx>
-{
-    #[inline]
-    fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
-        self
-    }
-
-    #[inline]
-    fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> {
-        self
-    }
-}
-
-impl<'a, 'mir, 'tcx, M> HasMemory<'a, 'mir, 'tcx, M> for EvalContext<'a, 'mir, 'tcx, M>
-    where M: Machine<'mir, 'tcx>
-{
-    #[inline]
-    fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
-        &mut self.memory
-    }
-
-    #[inline]
-    fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> {
-        &self.memory
-    }
-}
-
-impl<'a, 'mir, 'tcx, M> layout::HasDataLayout for &'a Memory<'a, 'mir, 'tcx, M>
-    where M: Machine<'mir, 'tcx>
-{
-    #[inline]
-    fn data_layout(&self) -> &TargetDataLayout {
-        &self.tcx.data_layout
-    }
-}
diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs
index 8192ef3d0f3..462c4b8889d 100644
--- a/src/librustc_mir/interpret/mod.rs
+++ b/src/librustc_mir/interpret/mod.rs
@@ -20,18 +20,23 @@ mod operator;
 mod step;
 mod terminator;
 mod traits;
-mod const_eval;
 mod validity;
+mod intrinsics;
 
 pub use self::eval_context::{
     EvalContext, Frame, StackPopCleanup, LocalValue,
 };
 
-pub use self::place::{Place, PlaceExtra, PlaceTy, MemPlace, MPlaceTy};
+pub use self::place::{Place, PlaceTy, MemPlace, MPlaceTy};
 
-pub use self::memory::{Memory, MemoryKind, HasMemory};
+pub use self::memory::{Memory, MemoryKind};
 
-pub use self::const_eval::{
+pub use self::machine::Machine;
+
+pub use self::operand::{Value, ValTy, Operand, OpTy};
+
+// reexports for compatibility
+pub use const_eval::{
     eval_promoted,
     mk_borrowck_eval_cx,
     mk_eval_cx,
@@ -42,7 +47,3 @@ pub use self::const_eval::{
     const_variant_index,
     op_to_const,
 };
-
-pub use self::machine::Machine;
-
-pub use self::operand::{Value, ValTy, Operand, OpTy};
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index aa4585fb892..9681b705d7e 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -11,16 +11,17 @@
 //! Functions concerning immediate values and operands, and reading from operands.
 //! All high-level functions to read from memory work on operands as sources.
 
+use std::hash::{Hash, Hasher};
 use std::convert::TryInto;
 
-use rustc::mir;
-use rustc::ty::layout::{self, Align, LayoutOf, TyLayout, HasDataLayout, IntegerExt};
+use rustc::{mir, ty};
+use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout, IntegerExt};
 use rustc_data_structures::indexed_vec::Idx;
 
 use rustc::mir::interpret::{
     GlobalId, ConstValue, Scalar, EvalResult, Pointer, ScalarMaybeUndef, EvalErrorKind
 };
-use super::{EvalContext, Machine, MemPlace, MPlaceTy, PlaceExtra, MemoryKind};
+use super::{EvalContext, Machine, MemPlace, MPlaceTy, MemoryKind};
 
 /// A `Value` represents a single immediate self-contained Rust value.
 ///
@@ -64,6 +65,14 @@ impl<'tcx> Value {
         self.to_scalar_or_undef().not_undef()
     }
 
+    #[inline]
+    pub fn to_scalar_pair(self) -> EvalResult<'tcx, (Scalar, Scalar)> {
+        match self {
+            Value::Scalar(..) => bug!("Got a thin pointer where a scalar pair was expected"),
+            Value::ScalarPair(a, b) => Ok((a.not_undef()?, b.not_undef()?))
+        }
+    }
+
     /// Convert the value into a pointer (or a pointer-sized integer).
     /// Throws away the second half of a ScalarPair!
     #[inline]
@@ -73,24 +82,6 @@ impl<'tcx> Value {
             Value::ScalarPair(ptr, _) => ptr.not_undef(),
         }
     }
-
-    pub fn to_scalar_dyn_trait(self) -> EvalResult<'tcx, (Scalar, Pointer)> {
-        match self {
-            Value::ScalarPair(ptr, vtable) =>
-                Ok((ptr.not_undef()?, vtable.to_ptr()?)),
-            _ => bug!("expected ptr and vtable, got {:?}", self),
-        }
-    }
-
-    pub fn to_scalar_slice(self, cx: impl HasDataLayout) -> EvalResult<'tcx, (Scalar, u64)> {
-        match self {
-            Value::ScalarPair(ptr, val) => {
-                let len = val.to_bits(cx.data_layout().pointer_size)?;
-                Ok((ptr.not_undef()?, len as u64))
-            }
-            _ => bug!("expected ptr and length, got {:?}", self),
-        }
-    }
 }
 
 // ScalarPair needs a type to interpret, so we often have a value and a type together
@@ -150,7 +141,7 @@ impl Operand {
 
 #[derive(Copy, Clone, Debug)]
 pub struct OpTy<'tcx> {
-    pub op: Operand,
+    crate op: Operand, // ideally we'd make this private, but we are not there yet
     pub layout: TyLayout<'tcx>,
 }
 
@@ -182,6 +173,20 @@ impl<'tcx> From<ValTy<'tcx>> for OpTy<'tcx> {
     }
 }
 
+// Validation needs to hash OpTy, but we cannot hash Layout -- so we just hash the type
+impl<'tcx> Hash for OpTy<'tcx> {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.op.hash(state);
+        self.layout.ty.hash(state);
+    }
+}
+impl<'tcx> PartialEq for OpTy<'tcx> {
+    fn eq(&self, other: &Self) -> bool {
+        self.op == other.op && self.layout.ty == other.layout.ty
+    }
+}
+impl<'tcx> Eq for OpTy<'tcx> {}
+
 impl<'tcx> OpTy<'tcx> {
     #[inline]
     pub fn from_ptr(ptr: Pointer, align: Align, layout: TyLayout<'tcx>) -> Self {
@@ -227,7 +232,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         &self,
         mplace: MPlaceTy<'tcx>,
     ) -> EvalResult<'tcx, Option<Value>> {
-        if mplace.extra != PlaceExtra::None {
+        if mplace.layout.is_unsized() {
+            // Dont touch unsized
             return Ok(None);
         }
         let (ptr, ptr_align) = mplace.to_scalar_ptr_align();
@@ -266,7 +272,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     /// Note that for a given layout, this operation will either always fail or always
     /// succeed!  Whether it succeeds depends on whether the layout can be represented
     /// in a `Value`, not on which data is stored there currently.
-    pub(super) fn try_read_value(
+    pub(crate) fn try_read_value(
         &self,
         src: OpTy<'tcx>,
     ) -> EvalResult<'tcx, Result<Value, MemPlace>> {
@@ -300,6 +306,18 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         }
     }
 
+    // Turn the MPlace into a string (must already be dereferenced!)
+    pub fn read_str(
+        &self,
+        mplace: MPlaceTy<'tcx>,
+    ) -> EvalResult<'tcx, &str> {
+        let len = mplace.len(self)?;
+        let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len as u64))?;
+        let str = ::std::str::from_utf8(bytes)
+            .map_err(|err| EvalErrorKind::ValidationFailure(err.to_string()))?;
+        Ok(str)
+    }
+
     pub fn uninit_operand(&mut self, layout: TyLayout<'tcx>) -> EvalResult<'tcx, Operand> {
         // This decides which types we will use the Immediate optimization for, and hence should
         // match what `try_read_value` and `eval_place_to_op` support.
@@ -360,7 +378,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         Ok(OpTy { op: Operand::Immediate(value), layout: field_layout })
     }
 
-    pub(super) fn operand_downcast(
+    pub fn operand_downcast(
         &self,
         op: OpTy<'tcx>,
         variant: usize,
@@ -411,12 +429,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     // avoid allocations.  If you already know the layout, you can pass it in
     // to avoid looking it up again.
     fn eval_place_to_op(
-        &mut self,
+        &self,
         mir_place: &mir::Place<'tcx>,
         layout: Option<TyLayout<'tcx>>,
     ) -> EvalResult<'tcx, OpTy<'tcx>> {
         use rustc::mir::Place::*;
-        Ok(match *mir_place {
+        let op = match *mir_place {
             Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer),
             Local(local) => {
                 let op = *self.frame().locals[local].access()?;
@@ -430,21 +448,18 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 self.operand_projection(op, &proj.elem)?
             }
 
-            // Everything else is an mplace, so we just call `eval_place`.
-            // Note that getting an mplace for a static aways requires `&mut`,
-            // so this does not "cost" us anything in terms if mutability.
-            Promoted(_) | Static(_) => {
-                let place = self.eval_place(mir_place)?;
-                place.to_mem_place().into()
-            }
-        })
+            _ => self.eval_place_to_mplace(mir_place)?.into(),
+        };
+
+        trace!("eval_place_to_op: got {:?}", *op);
+        Ok(op)
     }
 
     /// Evaluate the operand, returning a place where you can then find the data.
     /// if you already know the layout, you can save two some table lookups
     /// by passing it in here.
     pub fn eval_operand(
-        &mut self,
+        &self,
         mir_op: &mir::Operand<'tcx>,
         layout: Option<TyLayout<'tcx>>,
     ) -> EvalResult<'tcx, OpTy<'tcx>> {
@@ -469,8 +484,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     }
 
     /// Evaluate a bunch of operands at once
-    pub(crate) fn eval_operands(
-        &mut self,
+    pub(super) fn eval_operands(
+        &self,
         ops: &[mir::Operand<'tcx>],
     ) -> EvalResult<'tcx, Vec<OpTy<'tcx>>> {
         ops.into_iter()
@@ -479,12 +494,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     }
 
     // Also used e.g. when miri runs into a constant.
-    // Unfortunately, this needs an `&mut` to be able to allocate a copy of a `ByRef`
-    // constant.  This bleeds up to `eval_operand` needing `&mut`.
-    pub fn const_value_to_op(
-        &mut self,
+    pub(super) fn const_value_to_op(
+        &self,
         val: ConstValue<'tcx>,
     ) -> EvalResult<'tcx, Operand> {
+        trace!("const_value_to_op: {:?}", val);
         match val {
             ConstValue::Unevaluated(def_id, substs) => {
                 let instance = self.resolve(def_id, substs)?;
@@ -493,9 +507,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                     promoted: None,
                 })
             }
-            ConstValue::ByRef(alloc, offset) => {
-                // FIXME: Allocate new AllocId for all constants inside
-                let id = self.memory.allocate_value(alloc.clone(), MemoryKind::Stack)?;
+            ConstValue::ByRef(id, alloc, offset) => {
+                // We rely on mutability being set correctly in that allocation to prevent writes
+                // where none should happen -- and for `static mut`, we copy on demand anyway.
                 Ok(Operand::from_ptr(Pointer::new(id, offset), alloc.align))
             },
             ConstValue::ScalarPair(a, b) =>
@@ -504,52 +518,24 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 Ok(Operand::Immediate(Value::Scalar(x.into()))),
         }
     }
+    pub fn const_to_op(
+        &self,
+        cnst: &ty::Const<'tcx>,
+    ) -> EvalResult<'tcx, OpTy<'tcx>> {
+        let op = self.const_value_to_op(cnst.val)?;
+        Ok(OpTy { op, layout: self.layout_of(cnst.ty)? })
+    }
 
-    pub(super) fn global_to_op(&mut self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, Operand> {
+    pub(super) fn global_to_op(&self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, Operand> {
         let cv = self.const_eval(gid)?;
         self.const_value_to_op(cv.val)
     }
 
-    /// We cannot do self.read_value(self.eval_operand) due to eval_operand taking &mut self,
-    /// so this helps avoid unnecessary let.
-    #[inline]
-    pub fn eval_operand_and_read_value(
-        &mut self,
-        op: &mir::Operand<'tcx>,
-        layout: Option<TyLayout<'tcx>>,
-    ) -> EvalResult<'tcx, ValTy<'tcx>> {
-        let op = self.eval_operand(op, layout)?;
-        self.read_value(op)
-    }
-
-    /// reads a tag and produces the corresponding variant index
-    pub fn read_discriminant_as_variant_index(
+    /// Read discriminant, return the runtime value as well as the variant index.
+    pub fn read_discriminant(
         &self,
         rval: OpTy<'tcx>,
-    ) -> EvalResult<'tcx, usize> {
-        match rval.layout.variants {
-            layout::Variants::Single { index } => Ok(index),
-            layout::Variants::Tagged { .. } => {
-                let discr_val = self.read_discriminant_value(rval)?;
-                rval.layout.ty
-                    .ty_adt_def()
-                    .expect("tagged layout for non adt")
-                    .discriminants(self.tcx.tcx)
-                    .position(|var| var.val == discr_val)
-                    .ok_or_else(|| EvalErrorKind::InvalidDiscriminant.into())
-            }
-            layout::Variants::NicheFilling { .. } => {
-                let discr_val = self.read_discriminant_value(rval)?;
-                assert_eq!(discr_val as usize as u128, discr_val);
-                Ok(discr_val as usize)
-            },
-        }
-    }
-
-    pub fn read_discriminant_value(
-        &self,
-        rval: OpTy<'tcx>,
-    ) -> EvalResult<'tcx, u128> {
+    ) -> EvalResult<'tcx, (u128, usize)> {
         trace!("read_discriminant_value {:#?}", rval.layout);
         if rval.layout.abi == layout::Abi::Uninhabited {
             return err!(Unreachable);
@@ -560,20 +546,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 let discr_val = rval.layout.ty.ty_adt_def().map_or(
                     index as u128,
                     |def| def.discriminant_for_variant(*self.tcx, index).val);
-                return Ok(discr_val);
+                return Ok((discr_val, index));
             }
             layout::Variants::Tagged { .. } |
             layout::Variants::NicheFilling { .. } => {},
         }
+        // read raw discriminant value
         let discr_op = self.operand_field(rval, 0)?;
         let discr_val = self.read_value(discr_op)?;
-        trace!("discr value: {:?}", discr_val);
         let raw_discr = discr_val.to_scalar()?;
+        trace!("discr value: {:?}", raw_discr);
+        // post-process
         Ok(match rval.layout.variants {
             layout::Variants::Single { .. } => bug!(),
-            // FIXME: We should catch invalid discriminants here!
             layout::Variants::Tagged { .. } => {
-                if discr_val.layout.ty.is_signed() {
+                let real_discr = if discr_val.layout.ty.is_signed() {
                     let i = raw_discr.to_bits(discr_val.layout.size)? as i128;
                     // going from layout tag type to typeck discriminant type
                     // requires first sign extending with the layout discriminant
@@ -590,7 +577,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                     (truncatee << shift) >> shift
                 } else {
                     raw_discr.to_bits(discr_val.layout.size)?
-                }
+                };
+                // Make sure we catch invalid discriminants
+                let index = rval.layout.ty
+                    .ty_adt_def()
+                    .expect("tagged layout for non adt")
+                    .discriminants(self.tcx.tcx)
+                    .position(|var| var.val == real_discr)
+                    .ok_or_else(|| EvalErrorKind::InvalidDiscriminant(real_discr))?;
+                (real_discr, index)
             },
             layout::Variants::NicheFilling {
                 dataful_variant,
@@ -600,8 +595,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             } => {
                 let variants_start = *niche_variants.start() as u128;
                 let variants_end = *niche_variants.end() as u128;
-                match raw_discr {
+                let real_discr = match raw_discr {
                     Scalar::Ptr(_) => {
+                        // The niche must be just 0 (which a pointer value never is)
                         assert!(niche_start == 0);
                         assert!(variants_start == variants_end);
                         dataful_variant as u128
@@ -616,7 +612,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                             dataful_variant as u128
                         }
                     },
-                }
+                };
+                let index = real_discr as usize;
+                assert_eq!(index as u128, real_discr);
+                assert!(index < rval.layout.ty
+                    .ty_adt_def()
+                    .expect("tagged layout for non adt")
+                    .variants.len());
+                (real_discr, index)
             }
         })
     }
diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs
index 89293dc1012..13ed527e349 100644
--- a/src/librustc_mir/interpret/operator.rs
+++ b/src/librustc_mir/interpret/operator.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use rustc::mir;
-use rustc::ty::{self, layout::{self, TyLayout}};
+use rustc::ty::{self, layout::TyLayout};
 use syntax::ast::FloatTy;
 use rustc_apfloat::ieee::{Double, Single};
 use rustc_apfloat::Float;
@@ -48,44 +48,103 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
 }
 
 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
-    /// Returns the result of the specified operation and whether it overflowed.
-    pub fn binary_op(
+    fn binary_char_op(
         &self,
         bin_op: mir::BinOp,
-        ValTy { value: left, layout: left_layout }: ValTy<'tcx>,
-        ValTy { value: right, layout: right_layout }: ValTy<'tcx>,
+        l: char,
+        r: char,
     ) -> EvalResult<'tcx, (Scalar, bool)> {
         use rustc::mir::BinOp::*;
 
-        let left = left.to_scalar()?;
-        let right = right.to_scalar()?;
-
-        let left_kind = match left_layout.abi {
-            layout::Abi::Scalar(ref scalar) => scalar.value,
-            _ => return err!(TypeNotPrimitive(left_layout.ty)),
+        let res = match bin_op {
+            Eq => l == r,
+            Ne => l != r,
+            Lt => l < r,
+            Le => l <= r,
+            Gt => l > r,
+            Ge => l >= r,
+            _ => bug!("Invalid operation on char: {:?}", bin_op),
         };
-        let right_kind = match right_layout.abi {
-            layout::Abi::Scalar(ref scalar) => scalar.value,
-            _ => return err!(TypeNotPrimitive(right_layout.ty)),
+        return Ok((Scalar::from_bool(res), false));
+    }
+
+    fn binary_bool_op(
+        &self,
+        bin_op: mir::BinOp,
+        l: bool,
+        r: bool,
+    ) -> EvalResult<'tcx, (Scalar, bool)> {
+        use rustc::mir::BinOp::*;
+
+        let res = match bin_op {
+            Eq => l == r,
+            Ne => l != r,
+            Lt => l < r,
+            Le => l <= r,
+            Gt => l > r,
+            Ge => l >= r,
+            BitAnd => l & r,
+            BitOr => l | r,
+            BitXor => l ^ r,
+            _ => bug!("Invalid operation on bool: {:?}", bin_op),
         };
-        trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
-        bin_op, left, left_kind, right, right_kind);
+        return Ok((Scalar::from_bool(res), false));
+    }
 
-        // I: Handle operations that support pointers
-        if !left_kind.is_float() && !right_kind.is_float() {
-            if let Some(handled) =
-                M::try_ptr_op(self, bin_op, left, left_layout, right, right_layout)?
-            {
-                return Ok(handled);
-            }
+    fn binary_float_op(
+        &self,
+        bin_op: mir::BinOp,
+        fty: FloatTy,
+        // passing in raw bits
+        l: u128,
+        r: u128,
+    ) -> EvalResult<'tcx, (Scalar, bool)> {
+        use rustc::mir::BinOp::*;
+
+        macro_rules! float_math {
+            ($ty:path, $size:expr) => {{
+                let l = <$ty>::from_bits(l);
+                let r = <$ty>::from_bits(r);
+                let bitify = |res: ::rustc_apfloat::StatusAnd<$ty>| Scalar::Bits {
+                    bits: res.value.to_bits(),
+                    size: $size,
+                };
+                let val = match bin_op {
+                    Eq => Scalar::from_bool(l == r),
+                    Ne => Scalar::from_bool(l != r),
+                    Lt => Scalar::from_bool(l < r),
+                    Le => Scalar::from_bool(l <= r),
+                    Gt => Scalar::from_bool(l > r),
+                    Ge => Scalar::from_bool(l >= r),
+                    Add => bitify(l + r),
+                    Sub => bitify(l - r),
+                    Mul => bitify(l * r),
+                    Div => bitify(l / r),
+                    Rem => bitify(l % r),
+                    _ => bug!("invalid float op: `{:?}`", bin_op),
+                };
+                return Ok((val, false));
+            }};
+        }
+        match fty {
+            FloatTy::F32 => float_math!(Single, 4),
+            FloatTy::F64 => float_math!(Double, 8),
         }
+    }
 
-        // II: From now on, everything must be bytes, no pointers
-        let l = left.to_bits(left_layout.size)?;
-        let r = right.to_bits(right_layout.size)?;
+    fn binary_int_op(
+        &self,
+        bin_op: mir::BinOp,
+        // passing in raw bits
+        l: u128,
+        left_layout: TyLayout<'tcx>,
+        r: u128,
+        right_layout: TyLayout<'tcx>,
+    ) -> EvalResult<'tcx, (Scalar, bool)> {
+        use rustc::mir::BinOp::*;
 
-        // These ops can have an RHS with a different numeric type.
-        if right_kind.is_int() && (bin_op == Shl || bin_op == Shr) {
+        // Shift ops can have an RHS with a different numeric type.
+        if bin_op == Shl || bin_op == Shr {
             let signed = left_layout.abi.is_signed();
             let mut oflo = (r as u32 as u128) != r;
             let mut r = r as u32;
@@ -116,18 +175,20 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             }, oflo));
         }
 
-        if left_kind != right_kind {
+        // For the remaining ops, the types must be the same on both sides
+        if left_layout.ty != right_layout.ty {
             let msg = format!(
-                "unimplemented binary op {:?}: {:?} ({:?}), {:?} ({:?})",
+                "unimplemented asymmetric binary op {:?}: {:?} ({:?}), {:?} ({:?})",
                 bin_op,
-                left,
-                left_kind,
-                right,
-                right_kind
+                l,
+                left_layout.ty,
+                r,
+                right_layout.ty
             );
             return err!(Unimplemented(msg));
         }
 
+        // Operations that need special treatment for signed integers
         if left_layout.abi.is_signed() {
             let op: Option<fn(&i128, &i128) -> bool> = match bin_op {
                 Lt => Some(i128::lt),
@@ -180,38 +241,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             }
         }
 
-        if let ty::Float(fty) = left_layout.ty.sty {
-            macro_rules! float_math {
-                ($ty:path, $size:expr) => {{
-                    let l = <$ty>::from_bits(l);
-                    let r = <$ty>::from_bits(r);
-                    let bitify = |res: ::rustc_apfloat::StatusAnd<$ty>| Scalar::Bits {
-                        bits: res.value.to_bits(),
-                        size: $size,
-                    };
-                    let val = match bin_op {
-                        Eq => Scalar::from_bool(l == r),
-                        Ne => Scalar::from_bool(l != r),
-                        Lt => Scalar::from_bool(l < r),
-                        Le => Scalar::from_bool(l <= r),
-                        Gt => Scalar::from_bool(l > r),
-                        Ge => Scalar::from_bool(l >= r),
-                        Add => bitify(l + r),
-                        Sub => bitify(l - r),
-                        Mul => bitify(l * r),
-                        Div => bitify(l / r),
-                        Rem => bitify(l % r),
-                        _ => bug!("invalid float op: `{:?}`", bin_op),
-                    };
-                    return Ok((val, false));
-                }};
-            }
-            match fty {
-                FloatTy::F32 => float_math!(Single, 4),
-                FloatTy::F64 => float_math!(Double, 8),
-            }
-        }
-
         let size = left_layout.size.bytes() as u8;
 
         // only ints left
@@ -249,11 +278,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
 
             _ => {
                 let msg = format!(
-                    "unimplemented binary op {:?}: {:?} ({:?}), {:?} ({:?})",
+                    "unimplemented binary op {:?}: {:?}, {:?} (both {:?})",
                     bin_op,
-                    left,
-                    left_layout.ty,
-                    right,
+                    l,
+                    r,
                     right_layout.ty,
                 );
                 return err!(Unimplemented(msg));
@@ -263,6 +291,60 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         Ok((val, false))
     }
 
+    /// Returns the result of the specified operation and whether it overflowed.
+    pub fn binary_op(
+        &self,
+        bin_op: mir::BinOp,
+        ValTy { value: left, layout: left_layout }: ValTy<'tcx>,
+        ValTy { value: right, layout: right_layout }: ValTy<'tcx>,
+    ) -> EvalResult<'tcx, (Scalar, bool)> {
+        let left = left.to_scalar()?;
+        let right = right.to_scalar()?;
+
+        trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
+            bin_op, left, left_layout.ty, right, right_layout.ty);
+
+        match left_layout.ty.sty {
+            ty::Char => {
+                assert_eq!(left_layout.ty, right_layout.ty);
+                let left = left.to_char()?;
+                let right = right.to_char()?;
+                self.binary_char_op(bin_op, left, right)
+            }
+            ty::Bool => {
+                assert_eq!(left_layout.ty, right_layout.ty);
+                let left = left.to_bool()?;
+                let right = right.to_bool()?;
+                self.binary_bool_op(bin_op, left, right)
+            }
+            ty::Float(fty) => {
+                assert_eq!(left_layout.ty, right_layout.ty);
+                let left = left.to_bits(left_layout.size)?;
+                let right = right.to_bits(right_layout.size)?;
+                self.binary_float_op(bin_op, fty, left, right)
+            }
+            _ => {
+                // Must be integer(-like) types.  Don't forget about == on fn pointers.
+                assert!(left_layout.ty.is_integral() || left_layout.ty.is_unsafe_ptr() ||
+                    left_layout.ty.is_fn());
+                assert!(right_layout.ty.is_integral() || right_layout.ty.is_unsafe_ptr() ||
+                    right_layout.ty.is_fn());
+
+                // Handle operations that support pointer values
+                if let Some(handled) =
+                    M::try_ptr_op(self, bin_op, left, left_layout, right, right_layout)?
+                {
+                    return Ok(handled);
+                }
+
+                // Everything else only works with "proper" bits
+                let left = left.to_bits(left_layout.size)?;
+                let right = right.to_bits(right_layout.size)?;
+                self.binary_int_op(bin_op, left, left_layout, right, right_layout)
+            }
+        }
+    }
+
     pub fn unary_op(
         &self,
         un_op: mir::UnOp,
@@ -273,25 +355,42 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         use rustc_apfloat::ieee::{Single, Double};
         use rustc_apfloat::Float;
 
-        let size = layout.size;
-        let bytes = val.to_bits(size)?;
-
-        let result_bytes = match (un_op, &layout.ty.sty) {
-
-            (Not, ty::Bool) => !val.to_bool()? as u128,
-
-            (Not, _) => !bytes,
-
-            (Neg, ty::Float(FloatTy::F32)) => Single::to_bits(-Single::from_bits(bytes)),
-            (Neg, ty::Float(FloatTy::F64)) => Double::to_bits(-Double::from_bits(bytes)),
-
-            (Neg, _) if bytes == (1 << (size.bits() - 1)) => return err!(OverflowNeg),
-            (Neg, _) => (-(bytes as i128)) as u128,
-        };
+        trace!("Running unary op {:?}: {:?} ({:?})", un_op, val, layout.ty.sty);
 
-        Ok(Scalar::Bits {
-            bits: self.truncate(result_bytes, layout),
-            size: size.bytes() as u8,
-        })
+        match layout.ty.sty {
+            ty::Bool => {
+                let val = val.to_bool()?;
+                let res = match un_op {
+                    Not => !val,
+                    _ => bug!("Invalid bool op {:?}", un_op)
+                };
+                Ok(Scalar::from_bool(res))
+            }
+            ty::Float(fty) => {
+                let val = val.to_bits(layout.size)?;
+                let res = match (un_op, fty) {
+                    (Neg, FloatTy::F32) => Single::to_bits(-Single::from_bits(val)),
+                    (Neg, FloatTy::F64) => Double::to_bits(-Double::from_bits(val)),
+                    _ => bug!("Invalid float op {:?}", un_op)
+                };
+                Ok(Scalar::Bits { bits: res, size: layout.size.bytes() as u8 })
+            }
+            _ => {
+                assert!(layout.ty.is_integral());
+                let val = val.to_bits(layout.size)?;
+                let res = match un_op {
+                    Not => !val,
+                    Neg => {
+                        assert!(layout.abi.is_signed());
+                        (-(val as i128)) as u128
+                    }
+                };
+                // res needs tuncating
+                Ok(Scalar::Bits {
+                    bits: self.truncate(res, layout),
+                    size: layout.size.bytes() as u8,
+                })
+            }
+        }
     }
 }
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index f1c2b6b34fb..0a6fef30084 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -12,7 +12,6 @@
 //! into a place.
 //! All high-level functions to write to memory work on places as destinations.
 
-use std::hash::{Hash, Hasher};
 use std::convert::TryFrom;
 
 use rustc::mir;
@@ -32,7 +31,10 @@ pub struct MemPlace {
     /// However, it may never be undef.
     pub ptr: Scalar,
     pub align: Align,
-    pub extra: PlaceExtra,
+    /// Metadata for unsized places.  Interpretation is up to the type.
+    /// Must not be present for sized types, but can be missing for unsized types
+    /// (e.g. `extern type`).
+    pub extra: Option<Scalar>,
 }
 
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
@@ -48,14 +50,6 @@ pub enum Place {
     },
 }
 
-// Extra information for fat pointers / places
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum PlaceExtra {
-    None,
-    Length(u64),
-    Vtable(Pointer),
-}
-
 #[derive(Copy, Clone, Debug)]
 pub struct PlaceTy<'tcx> {
     place: Place,
@@ -101,7 +95,7 @@ impl MemPlace {
         MemPlace {
             ptr,
             align,
-            extra: PlaceExtra::None,
+            extra: None,
         }
     }
 
@@ -112,7 +106,7 @@ impl MemPlace {
 
     #[inline(always)]
     pub fn to_scalar_ptr_align(self) -> (Scalar, Align) {
-        assert_eq!(self.extra, PlaceExtra::None);
+        assert_eq!(self.extra, None);
         (self.ptr, self.align)
     }
 
@@ -127,13 +121,12 @@ impl MemPlace {
 
     /// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space.
     /// This is the inverse of `ref_to_mplace`.
-    pub fn to_ref(self, cx: impl HasDataLayout) -> Value {
+    pub fn to_ref(self) -> Value {
         // We ignore the alignment of the place here -- special handling for packed structs ends
         // at the `&` operator.
         match self.extra {
-            PlaceExtra::None => Value::Scalar(self.ptr.into()),
-            PlaceExtra::Length(len) => Value::new_slice(self.ptr.into(), len, cx),
-            PlaceExtra::Vtable(vtable) => Value::new_dyn_trait(self.ptr.into(), vtable),
+            None => Value::Scalar(self.ptr.into()),
+            Some(extra) => Value::ScalarPair(self.ptr.into(), extra.into()),
         }
     }
 }
@@ -145,33 +138,32 @@ impl<'tcx> MPlaceTy<'tcx> {
     }
 
     #[inline]
-    pub(super) fn len(self) -> u64 {
-        // Sanity check
-        let ty_len = match self.layout.fields {
-            layout::FieldPlacement::Array { count, .. } => count,
-            _ => bug!("Length for non-array layout {:?} requested", self.layout),
-        };
-        if let PlaceExtra::Length(len) = self.extra {
-            len
+    pub(super) fn len(self, cx: impl HasDataLayout) -> EvalResult<'tcx, u64> {
+        if self.layout.is_unsized() {
+            // We need to consult `extra` metadata
+            match self.layout.ty.sty {
+                ty::Slice(..) | ty::Str =>
+                    return self.extra.unwrap().to_usize(cx),
+                _ => bug!("len not supported on unsized type {:?}", self.layout.ty),
+            }
         } else {
-            ty_len
+            // Go through the layout.  There are lots of types that support a length,
+            // e.g. SIMD types.
+            match self.layout.fields {
+                layout::FieldPlacement::Array { count, .. } => Ok(count),
+                _ => bug!("len not supported on sized type {:?}", self.layout.ty),
+            }
         }
     }
-}
 
-// Validation needs to hash MPlaceTy, but we cannot hash Layout -- so we just hash the type
-impl<'tcx> Hash for MPlaceTy<'tcx> {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        self.mplace.hash(state);
-        self.layout.ty.hash(state);
-    }
-}
-impl<'tcx> PartialEq for MPlaceTy<'tcx> {
-    fn eq(&self, other: &Self) -> bool {
-        self.mplace == other.mplace && self.layout.ty == other.layout.ty
+    #[inline]
+    pub(super) fn vtable(self) -> EvalResult<'tcx, Pointer> {
+        match self.layout.ty.sty {
+            ty::Dynamic(..) => self.extra.unwrap().to_ptr(),
+            _ => bug!("vtable not supported on type {:?}", self.layout.ty),
+        }
     }
 }
-impl<'tcx> Eq for MPlaceTy<'tcx> {}
 
 impl<'tcx> OpTy<'tcx> {
     #[inline(always)]
@@ -246,28 +238,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
         let pointee_type = val.layout.ty.builtin_deref(true).unwrap().ty;
         let layout = self.layout_of(pointee_type)?;
-        let mplace = match self.tcx.struct_tail(pointee_type).sty {
-            ty::Dynamic(..) => {
-                let (ptr, vtable) = val.to_scalar_dyn_trait()?;
-                MemPlace {
-                    ptr,
-                    align: layout.align,
-                    extra: PlaceExtra::Vtable(vtable),
-                }
-            }
-            ty::Str | ty::Slice(_) => {
-                let (ptr, len) = val.to_scalar_slice(self)?;
-                MemPlace {
-                    ptr,
-                    align: layout.align,
-                    extra: PlaceExtra::Length(len),
-                }
-            }
-            _ => MemPlace {
-                ptr: val.to_scalar()?,
-                align: layout.align,
-                extra: PlaceExtra::None,
-            },
+        let align = layout.align;
+        let mplace = match *val {
+            Value::Scalar(ptr) =>
+                MemPlace { ptr: ptr.not_undef()?, align, extra: None },
+            Value::ScalarPair(ptr, extra) =>
+                MemPlace { ptr: ptr.not_undef()?, align, extra: Some(extra.not_undef()?) },
         };
         Ok(MPlaceTy { mplace, layout })
     }
@@ -286,9 +262,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             layout::FieldPlacement::Arbitrary { ref offsets, .. } =>
                 offsets[usize::try_from(field).unwrap()],
             layout::FieldPlacement::Array { stride, .. } => {
-                let len = base.len();
-                assert!(field < len,
-                        "Tried to access element {} of array/slice with length {}", field, len);
+                let len = base.len(self)?;
+                assert!(field < len, "Tried to access element {} of array/slice with length {}",
+                    field, len);
                 stride * field
             }
             layout::FieldPlacement::Union(count) => {
@@ -302,29 +278,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         // above). In that case, all fields are equal.
         let field_layout = base.layout.field(self, usize::try_from(field).unwrap_or(0))?;
 
-        // Adjust offset
-        let offset = match base.extra {
-            PlaceExtra::Vtable(vtable) => {
-                let (_, align) = self.read_size_and_align_from_vtable(vtable)?;
-                // FIXME: Is this right? Should we always do this, or only when actually
-                // accessing the field to which the vtable applies?
-                offset.abi_align(align)
-            }
-            _ => {
-                // No adjustment needed
-                offset
-            }
-        };
+        // Offset may need adjustment for unsized fields
+        let (extra, offset) = if field_layout.is_unsized() {
+            // re-use parent metadata to determine dynamic field layout
+            let (_, align) = self.size_and_align_of(base.extra, field_layout)?;
+            (base.extra, offset.abi_align(align))
 
-        let ptr = base.ptr.ptr_offset(offset, self)?;
-        let align = base.align.min(field_layout.align);
-        let extra = if !field_layout.is_unsized() {
-            PlaceExtra::None
         } else {
-            assert!(base.extra != PlaceExtra::None, "Expected fat ptr");
-            base.extra
+            // base.extra could be present; we might be accessing a sized field of an unsized
+            // struct.
+            (None, offset)
         };
 
+        let ptr = base.ptr.ptr_offset(offset, self)?;
+        let align = base.align.min(field_layout.align); // only use static information
+
         Ok(MPlaceTy { mplace: MemPlace { ptr, align, extra }, layout: field_layout })
     }
 
@@ -334,7 +302,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         &self,
         base: MPlaceTy<'tcx>,
     ) -> EvalResult<'tcx, impl Iterator<Item=EvalResult<'tcx, MPlaceTy<'tcx>>> + 'a> {
-        let len = base.len();
+        let len = base.len(self)?; // also asserts that we have a type where this makes sense
         let stride = match base.layout.fields {
             layout::FieldPlacement::Array { stride, .. } => stride,
             _ => bug!("mplace_array_fields: expected an array layout"),
@@ -344,7 +312,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         Ok((0..len).map(move |i| {
             let ptr = base.ptr.ptr_offset(i * stride, dl)?;
             Ok(MPlaceTy {
-                mplace: MemPlace { ptr, align: base.align, extra: PlaceExtra::None },
+                mplace: MemPlace { ptr, align: base.align, extra: None },
                 layout
             })
         }))
@@ -356,7 +324,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         from: u64,
         to: u64,
     ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
-        let len = base.len();
+        let len = base.len(self)?; // also asserts that we have a type where this makes sense
         assert!(from <= len - to);
 
         // Not using layout method because that works with usize, and does not work with slices
@@ -371,10 +339,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         // Compute extra and new layout
         let inner_len = len - to - from;
         let (extra, ty) = match base.layout.ty.sty {
+            // It is not nice to match on the type, but that seems to be the only way to
+            // implement this.
             ty::Array(inner, _) =>
-                (PlaceExtra::None, self.tcx.mk_array(inner, inner_len)),
-            ty::Slice(..) =>
-                (PlaceExtra::Length(inner_len), base.layout.ty),
+                (None, self.tcx.mk_array(inner, inner_len)),
+            ty::Slice(..) => {
+                let len = Scalar::Bits {
+                    bits: inner_len.into(),
+                    size: self.memory.pointer_size().bytes() as u8
+                };
+                (Some(len), base.layout.ty)
+            }
             _ =>
                 bug!("cannot subslice non-array type: `{:?}`", base.layout.ty),
         };
@@ -392,7 +367,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         variant: usize,
     ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
         // Downcasts only change the layout
-        assert_eq!(base.extra, PlaceExtra::None);
+        assert_eq!(base.extra, None);
         Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base })
     }
 
@@ -421,7 +396,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 min_length,
                 from_end,
             } => {
-                let n = base.len();
+                let n = base.len(self)?;
                 assert!(n >= min_length as u64);
 
                 let index = if from_end {
@@ -487,33 +462,24 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         })
     }
 
-    /// Compute a place.  You should only use this if you intend to write into this
-    /// place; for reading, a more efficient alternative is `eval_place_for_read`.
-    pub fn eval_place(&mut self, mir_place: &mir::Place<'tcx>) -> EvalResult<'tcx, PlaceTy<'tcx>> {
+    /// Evaluate statics and promoteds to an `MPlace`.  Used to share some code between
+    /// `eval_place` and `eval_place_to_op`.
+    pub(super) fn eval_place_to_mplace(
+        &self,
+        mir_place: &mir::Place<'tcx>
+    ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
         use rustc::mir::Place::*;
-        let place = match *mir_place {
-            Local(mir::RETURN_PLACE) => PlaceTy {
-                place: self.frame().return_place,
-                layout: self.layout_of_local(self.cur_frame(), mir::RETURN_PLACE)?,
-            },
-            Local(local) => PlaceTy {
-                place: Place::Local {
-                    frame: self.cur_frame(),
-                    local,
-                },
-                layout: self.layout_of_local(self.cur_frame(), local)?,
-            },
-
+        Ok(match *mir_place {
             Promoted(ref promoted) => {
                 let instance = self.frame().instance;
                 let op = self.global_to_op(GlobalId {
                     instance,
                     promoted: Some(promoted.0),
                 })?;
-                let mplace = op.to_mem_place();
+                let mplace = op.to_mem_place(); // these are always in memory
                 let ty = self.monomorphize(promoted.1, self.substs());
-                PlaceTy {
-                    place: Place::Ptr(mplace),
+                MPlaceTy {
+                    mplace,
                     layout: self.layout_of(ty)?,
                 }
             }
@@ -526,18 +492,51 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                     instance,
                     promoted: None
                 };
-                let alloc = Machine::init_static(self, cid)?;
-                MPlaceTy::from_aligned_ptr(alloc.into(), layout).into()
+                // Just create a lazy reference, so we can support recursive statics.
+                // tcx takes are of assigning every static one and only one unique AllocId.
+                // When the data here is ever actually used, memory will notice,
+                // and it knows how to deal with alloc_id that are present in the
+                // global table but not in its local memory: It calls back into tcx through
+                // a query, triggering the CTFE machinery to actually turn this lazy reference
+                // into a bunch of bytes.  IOW, statics are evaluated with CTFE even when
+                // this EvalContext uses another Machine (e.g., in miri).  This is what we
+                // want!  This way, computing statics works concistently between codegen
+                // and miri: They use the same query to eventually obtain a `ty::Const`
+                // and use that for further computation.
+                let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
+                MPlaceTy::from_aligned_ptr(alloc.into(), layout)
             }
 
+            _ => bug!("eval_place_to_mplace called on {:?}", mir_place),
+        })
+    }
+
+    /// Compute a place.  You should only use this if you intend to write into this
+    /// place; for reading, a more efficient alternative is `eval_place_for_read`.
+    pub fn eval_place(&mut self, mir_place: &mir::Place<'tcx>) -> EvalResult<'tcx, PlaceTy<'tcx>> {
+        use rustc::mir::Place::*;
+        let place = match *mir_place {
+            Local(mir::RETURN_PLACE) => PlaceTy {
+                place: self.frame().return_place,
+                layout: self.layout_of_local(self.cur_frame(), mir::RETURN_PLACE)?,
+            },
+            Local(local) => PlaceTy {
+                place: Place::Local {
+                    frame: self.cur_frame(),
+                    local,
+                },
+                layout: self.layout_of_local(self.cur_frame(), local)?,
+            },
+
             Projection(ref proj) => {
                 let place = self.eval_place(&proj.base)?;
                 self.place_projection(place, &proj.elem)?
             }
+
+            _ => self.eval_place_to_mplace(mir_place)?.into(),
         };
 
         self.dump_place(place.place);
-
         Ok(place)
     }
 
@@ -656,20 +655,26 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
         let mplace = match place.place {
             Place::Local { frame, local } => {
-                // FIXME: Consider not doing anything for a ZST, and just returning
-                // a fake pointer?
-
-                // We need the layout of the local.  We can NOT use the layout we got,
-                // that might e.g. be a downcast variant!
-                let local_layout = self.layout_of_local(frame, local)?;
-                // Make sure it has a place
-                let rval = *self.stack[frame].locals[local].access()?;
-                let mplace = self.allocate_op(OpTy { op: rval, layout: local_layout })?.mplace;
-                // This might have allocated the flag
-                *self.stack[frame].locals[local].access_mut()? =
-                    Operand::Indirect(mplace);
-                // done
-                mplace
+                match *self.stack[frame].locals[local].access()? {
+                    Operand::Indirect(mplace) => mplace,
+                    Operand::Immediate(value) => {
+                        // We need to make an allocation.
+                        // FIXME: Consider not doing anything for a ZST, and just returning
+                        // a fake pointer?  Are we even called for ZST?
+
+                        // We need the layout of the local.  We can NOT use the layout we got,
+                        // that might e.g. be an inner field of a struct with `Scalar` layout,
+                        // that has different alignment than the outer field.
+                        let local_layout = self.layout_of_local(frame, local)?;
+                        let ptr = self.allocate(local_layout, MemoryKind::Stack)?;
+                        self.write_value_to_mplace(value, ptr)?;
+                        let mplace = ptr.mplace;
+                        // Update the local
+                        *self.stack[frame].locals[local].access_mut()? =
+                            Operand::Indirect(mplace);
+                        mplace
+                    }
+                }
             }
             Place::Ptr(mplace) => mplace
         };
@@ -687,38 +692,19 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         Ok(MPlaceTy::from_aligned_ptr(ptr, layout))
     }
 
-    /// Make a place for an operand, allocating if needed
-    pub fn allocate_op(
-        &mut self,
-        OpTy { op, layout }: OpTy<'tcx>,
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
-        Ok(match op {
-            Operand::Indirect(mplace) => MPlaceTy { mplace, layout },
-            Operand::Immediate(value) => {
-                // FIXME: Is stack always right here?
-                let ptr = self.allocate(layout, MemoryKind::Stack)?;
-                self.write_value_to_mplace(value, ptr)?;
-                ptr
-            },
-        })
-    }
-
-    pub fn write_discriminant_value(
+    pub fn write_discriminant_index(
         &mut self,
         variant_index: usize,
         dest: PlaceTy<'tcx>,
     ) -> EvalResult<'tcx> {
         match dest.layout.variants {
             layout::Variants::Single { index } => {
-                if index != variant_index {
-                    // If the layout of an enum is `Single`, all
-                    // other variants are necessarily uninhabited.
-                    assert_eq!(dest.layout.for_variant(&self, variant_index).abi,
-                               layout::Abi::Uninhabited);
-                }
+                assert_eq!(index, variant_index);
             }
             layout::Variants::Tagged { ref tag, .. } => {
-                let discr_val = dest.layout.ty.ty_adt_def().unwrap()
+                let adt_def = dest.layout.ty.ty_adt_def().unwrap();
+                assert!(variant_index < adt_def.variants.len());
+                let discr_val = adt_def
                     .discriminant_for_variant(*self.tcx, variant_index)
                     .val;
 
@@ -741,6 +727,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 niche_start,
                 ..
             } => {
+                assert!(variant_index < dest.layout.ty.ty_adt_def().unwrap().variants.len());
                 if variant_index != dataful_variant {
                     let niche_dest =
                         self.place_field(dest, 0)?;
@@ -770,43 +757,25 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         Ok(OpTy { op, layout: place.layout })
     }
 
-    /// Turn a place that is a dyn trait (i.e., PlaceExtra::Vtable and the appropriate layout)
-    /// or a slice into the specific fixed-size place and layout that is given by the vtable/len.
-    /// This "unpacks" the existential quantifier, so to speak.
-    pub fn unpack_unsized_mplace(
-        &self,
-        mplace: MPlaceTy<'tcx>
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
-        trace!("Unpacking {:?} ({:?})", *mplace, mplace.layout.ty);
-        let layout = match mplace.extra {
-            PlaceExtra::Vtable(vtable) => {
-                // the drop function signature
-                let drop_instance = self.read_drop_type_from_vtable(vtable)?;
-                trace!("Found drop fn: {:?}", drop_instance);
-                let fn_sig = drop_instance.ty(*self.tcx).fn_sig(*self.tcx);
-                let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig);
-                // the drop function takes *mut T where T is the type being dropped, so get that
-                let ty = fn_sig.inputs()[0].builtin_deref(true).unwrap().ty;
-                let layout = self.layout_of(ty)?;
-                // Sanity checks
-                let (size, align) = self.read_size_and_align_from_vtable(vtable)?;
-                assert_eq!(size, layout.size);
-                assert_eq!(align.abi(), layout.align.abi()); // only ABI alignment is preserved
-                // FIXME: More checks for the vtable? We could make sure it is exactly
-                // the one one would expect for this type.
-                // Done!
-                layout
-            },
-            PlaceExtra::Length(len) => {
-                let ty = self.tcx.mk_array(mplace.layout.field(self, 0)?.ty, len);
-                self.layout_of(ty)?
-            }
-            PlaceExtra::None => bug!("Expected a fat pointer"),
-        };
-        trace!("Unpacked type: {:?}", layout.ty);
-        Ok(MPlaceTy {
-            mplace: MemPlace { extra: PlaceExtra::None, ..*mplace },
+    /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
+    /// Also return some more information so drop doesn't have to run the same code twice.
+    pub(super) fn unpack_dyn_trait(&self, mplace: MPlaceTy<'tcx>)
+    -> EvalResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx>)> {
+        let vtable = mplace.vtable()?; // also sanity checks the type
+        let (instance, ty) = self.read_drop_type_from_vtable(vtable)?;
+        let layout = self.layout_of(ty)?;
+
+        // More sanity checks
+        let (size, align) = self.read_size_and_align_from_vtable(vtable)?;
+        assert_eq!(size, layout.size);
+        assert_eq!(align.abi(), layout.align.abi()); // only ABI alignment is preserved
+        // FIXME: More checks for the vtable? We could make sure it is exactly
+        // the one one would expect for this type.
+
+        let mplace = MPlaceTy {
+            mplace: MemPlace { extra: None, ..*mplace },
             layout
-        })
+        };
+        Ok((instance, mplace))
     }
 }
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index 0271a09482c..933f06d3d10 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -76,8 +76,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         self.loop_detector.observe_and_analyze(&self.machine, &self.stack, &self.memory)
     }
 
+    pub fn run(&mut self) -> EvalResult<'tcx> {
+        while self.step()? {}
+        Ok(())
+    }
+
     /// Returns true as long as there are more things to do.
-    pub fn step(&mut self) -> EvalResult<'tcx, bool> {
+    fn step(&mut self) -> EvalResult<'tcx, bool> {
         if self.stack.is_empty() {
             return Ok(false);
         }
@@ -122,7 +127,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 variant_index,
             } => {
                 let dest = self.eval_place(place)?;
-                self.write_discriminant_value(variant_index, dest)?;
+                self.write_discriminant_index(variant_index, dest)?;
             }
 
             // Mark locals as alive
@@ -147,10 +152,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                     M::validation_op(self, op, operand)?;
                 }
             }
-            EndRegion(ce) => {
-                M::end_region(self, Some(ce))?;
-            }
 
+            EndRegion(..) => {}
             UserAssertTy(..) => {}
 
             // Defined to do nothing. These are added by optimization passes, to avoid changing the
@@ -185,9 +188,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
 
             BinaryOp(bin_op, ref left, ref right) => {
                 let layout = if binop_left_homogeneous(bin_op) { Some(dest.layout) } else { None };
-                let left = self.eval_operand_and_read_value(left, layout)?;
+                let left = self.read_value(self.eval_operand(left, layout)?)?;
                 let layout = if binop_right_homogeneous(bin_op) { Some(left.layout) } else { None };
-                let right = self.eval_operand_and_read_value(right, layout)?;
+                let right = self.read_value(self.eval_operand(right, layout)?)?;
                 self.binop_ignore_overflow(
                     bin_op,
                     left,
@@ -198,9 +201,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
 
             CheckedBinaryOp(bin_op, ref left, ref right) => {
                 // Due to the extra boolean in the result, we can never reuse the `dest.layout`.
-                let left = self.eval_operand_and_read_value(left, None)?;
+                let left = self.read_value(self.eval_operand(left, None)?)?;
                 let layout = if binop_right_homogeneous(bin_op) { Some(left.layout) } else { None };
-                let right = self.eval_operand_and_read_value(right, layout)?;
+                let right = self.read_value(self.eval_operand(right, layout)?)?;
                 self.binop_with_overflow(
                     bin_op,
                     left,
@@ -211,7 +214,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
 
             UnaryOp(un_op, ref operand) => {
                 // The operand always has the same type as the result.
-                let val = self.eval_operand_and_read_value(operand, Some(dest.layout))?;
+                let val = self.read_value(self.eval_operand(operand, Some(dest.layout))?)?;
                 let val = self.unary_op(un_op, val.to_scalar()?, dest.layout)?;
                 self.write_scalar(val, dest)?;
             }
@@ -219,7 +222,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             Aggregate(ref kind, ref operands) => {
                 let (dest, active_field_index) = match **kind {
                     mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
-                        self.write_discriminant_value(variant_index, dest)?;
+                        self.write_discriminant_index(variant_index, dest)?;
                         if adt_def.is_enum() {
                             (self.place_downcast(dest, variant_index)?, active_field_index)
                         } else {
@@ -243,7 +246,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             Repeat(ref operand, _) => {
                 let op = self.eval_operand(operand, None)?;
                 let dest = self.force_allocation(dest)?;
-                let length = dest.len();
+                let length = dest.len(&self)?;
 
                 if length > 0 {
                     // write the first
@@ -265,7 +268,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 // FIXME(CTFE): don't allow computing the length of arrays in const eval
                 let src = self.eval_place(place)?;
                 let mplace = self.force_allocation(src)?;
-                let len = mplace.len();
+                let len = mplace.len(&self)?;
                 let size = self.memory.pointer_size().bytes() as u8;
                 self.write_scalar(
                     Scalar::Bits {
@@ -278,7 +281,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
 
             Ref(_, _, ref place) => {
                 let src = self.eval_place(place)?;
-                let val = self.force_allocation(src)?.to_ref(&self);
+                let val = self.force_allocation(src)?.to_ref();
                 self.write_value(val, dest)?;
             }
 
@@ -309,7 +312,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
 
             Discriminant(ref place) => {
                 let place = self.eval_place(place)?;
-                let discr_val = self.read_discriminant_value(self.place_to_op(place)?)?;
+                let discr_val = self.read_discriminant(self.place_to_op(place)?)?.0;
                 let size = dest.layout.size.bytes() as u8;
                 self.write_scalar(Scalar::Bits {
                     bits: discr_val,
@@ -327,8 +330,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         debug!("{:?}", terminator.kind);
         self.tcx.span = terminator.source_info.span;
         self.memory.tcx.span = terminator.source_info.span;
+
+        let old_stack = self.cur_frame();
+        let old_bb = self.frame().block;
         self.eval_terminator(terminator)?;
         if !self.stack.is_empty() {
+            // This should change *something*
+            debug_assert!(self.cur_frame() != old_stack || self.frame().block != old_bb);
             debug!("// {:?}", self.frame().block);
         }
         Ok(())
diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator.rs
index aec7bb0c0d6..11826e0ce0c 100644
--- a/src/librustc_mir/interpret/terminator/mod.rs
+++ b/src/librustc_mir/interpret/terminator.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::borrow::Cow;
+
 use rustc::mir;
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::LayoutOf;
@@ -15,16 +17,20 @@ use syntax::source_map::Span;
 use rustc_target::spec::abi::Abi;
 
 use rustc::mir::interpret::{EvalResult, Scalar};
-use super::{EvalContext, Machine, Value, OpTy, PlaceTy, ValTy, Operand};
-
-use rustc_data_structures::indexed_vec::Idx;
-
-mod drop;
+use super::{
+    EvalContext, Machine, Value, OpTy, Place, PlaceTy, ValTy, Operand, StackPopCleanup
+};
 
 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
-    pub fn goto_block(&mut self, target: mir::BasicBlock) {
-        self.frame_mut().block = target;
-        self.frame_mut().stmt = 0;
+    #[inline]
+    pub fn goto_block(&mut self, target: Option<mir::BasicBlock>) -> EvalResult<'tcx> {
+        if let Some(target) = target {
+            self.frame_mut().block = target;
+            self.frame_mut().stmt = 0;
+            Ok(())
+        } else {
+            err!(Unreachable)
+        }
     }
 
     pub(super) fn eval_terminator(
@@ -38,7 +44,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 self.pop_stack_frame()?
             }
 
-            Goto { target } => self.goto_block(target),
+            Goto { target } => self.goto_block(Some(target))?,
 
             SwitchInt {
                 ref discr,
@@ -46,8 +52,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 ref targets,
                 ..
             } => {
-                let discr_val = self.eval_operand(discr, None)?;
-                let discr = self.read_value(discr_val)?;
+                let discr = self.read_value(self.eval_operand(discr, None)?)?;
                 trace!("SwitchInt({:?})", *discr);
 
                 // Branch to the `otherwise` case by default, if no match is found.
@@ -69,7 +74,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                     }
                 }
 
-                self.goto_block(target_block);
+                self.goto_block(Some(target_block))?;
             }
 
             Call {
@@ -78,9 +83,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 ref destination,
                 ..
             } => {
-                let destination = match *destination {
-                    Some((ref lv, target)) => Some((self.eval_place(lv)?, target)),
-                    None => None,
+                let (dest, ret) = match *destination {
+                    Some((ref lv, target)) => (Some(self.eval_place(lv)?), Some(target)),
+                    None => (None, None),
                 };
 
                 let func = self.eval_operand(func, None)?;
@@ -91,43 +96,44 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                         let instance_ty = instance.ty(*self.tcx);
                         match instance_ty.sty {
                             ty::FnDef(..) => {
-                                let real_sig = instance_ty.fn_sig(*self.tcx);
                                 let sig = self.tcx.normalize_erasing_late_bound_regions(
-                                    ty::ParamEnv::reveal_all(),
+                                    self.param_env,
                                     &sig,
                                 );
+                                let real_sig = instance_ty.fn_sig(*self.tcx);
                                 let real_sig = self.tcx.normalize_erasing_late_bound_regions(
-                                    ty::ParamEnv::reveal_all(),
+                                    self.param_env,
                                     &real_sig,
                                 );
                                 if !self.check_sig_compat(sig, real_sig)? {
                                     return err!(FunctionPointerTyMismatch(real_sig, sig));
                                 }
+                                (instance, sig)
                             }
-                            ref other => bug!("instance def ty: {:?}", other),
+                            _ => bug!("unexpected fn ptr to ty: {:?}", instance_ty),
                         }
-                        (instance, sig)
                     }
-                    ty::FnDef(def_id, substs) => (
-                        self.resolve(def_id, substs)?,
-                        func.layout.ty.fn_sig(*self.tcx),
-                    ),
+                    ty::FnDef(def_id, substs) => {
+                        let sig = func.layout.ty.fn_sig(*self.tcx);
+                        let sig = self.tcx.normalize_erasing_late_bound_regions(
+                            self.param_env,
+                            &sig,
+                        );
+                        (self.resolve(def_id, substs)?, sig)
+                    },
                     _ => {
                         let msg = format!("can't handle callee of type {:?}", func.layout.ty);
                         return err!(Unimplemented(msg));
                     }
                 };
                 let args = self.eval_operands(args)?;
-                let sig = self.tcx.normalize_erasing_late_bound_regions(
-                    ty::ParamEnv::reveal_all(),
-                    &sig,
-                );
                 self.eval_fn_call(
                     fn_def,
-                    destination,
                     &args[..],
+                    dest,
+                    ret,
                     terminator.source_info.span,
-                    sig,
+                    Some(sig),
                 )?;
             }
 
@@ -157,19 +163,18 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 target,
                 ..
             } => {
-                let cond_val = self.eval_operand_and_read_value(cond, None)?
-                    .to_scalar()?
-                    .to_bool()?;
+                let cond_val = self.read_value(self.eval_operand(cond, None)?)?
+                    .to_scalar()?.to_bool()?;
                 if expected == cond_val {
-                    self.goto_block(target);
+                    self.goto_block(Some(target))?;
                 } else {
                     use rustc::mir::interpret::EvalErrorKind::*;
                     return match *msg {
                         BoundsCheck { ref len, ref index } => {
-                            let len = self.eval_operand_and_read_value(len, None)
+                            let len = self.read_value(self.eval_operand(len, None)?)
                                 .expect("can't eval len").to_scalar()?
                                 .to_bits(self.memory().pointer_size())? as u64;
-                            let index = self.eval_operand_and_read_value(index, None)
+                            let index = self.read_value(self.eval_operand(index, None)?)
                                 .expect("can't eval index").to_scalar()?
                                 .to_bits(self.memory().pointer_size())? as u64;
                             err!(BoundsCheck { len, index })
@@ -270,138 +275,146 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         return Ok(false);
     }
 
+    /// Call this function -- pushing the stack frame and initializing the arguments.
+    /// `sig` is optional in case of FnPtr/FnDef -- but mandatory for closures!
     fn eval_fn_call(
         &mut self,
         instance: ty::Instance<'tcx>,
-        destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
         args: &[OpTy<'tcx>],
+        dest: Option<PlaceTy<'tcx>>,
+        ret: Option<mir::BasicBlock>,
         span: Span,
-        sig: ty::FnSig<'tcx>,
+        sig: Option<ty::FnSig<'tcx>>,
     ) -> EvalResult<'tcx> {
         trace!("eval_fn_call: {:#?}", instance);
-        if let Some((place, _)) = destination {
-            assert_eq!(place.layout.ty, sig.output());
-        }
+
         match instance.def {
             ty::InstanceDef::Intrinsic(..) => {
-                let (ret, target) = match destination {
+                // The intrinsic itself cannot diverge, so if we got here without a return
+                // place... (can happen e.g. for transmute returning `!`)
+                let dest = match dest {
                     Some(dest) => dest,
-                    _ => return err!(Unreachable),
+                    None => return err!(Unreachable)
                 };
-                M::call_intrinsic(self, instance, args, ret, target)?;
-                self.dump_place(*ret);
-                Ok(())
-            }
-            // FIXME: figure out why we can't just go through the shim
-            ty::InstanceDef::ClosureOnceShim { .. } => {
-                if M::eval_fn_call(self, instance, destination, args, span)? {
-                    return Ok(());
-                }
-                let mut arg_locals = self.frame().mir.args_iter();
-                match sig.abi {
-                    // closure as closure once
-                    Abi::RustCall => {
-                        for (arg_local, &op) in arg_locals.zip(args) {
-                            let dest = self.eval_place(&mir::Place::Local(arg_local))?;
-                            self.copy_op(op, dest)?;
-                        }
-                    }
-                    // non capture closure as fn ptr
-                    // need to inject zst ptr for closure object (aka do nothing)
-                    // and need to pack arguments
-                    Abi::Rust => {
-                        trace!(
-                            "args: {:#?}",
-                            self.frame().mir.args_iter().zip(args.iter())
-                                .map(|(local, arg)| (local, **arg, arg.layout.ty))
-                                .collect::<Vec<_>>()
-                        );
-                        let local = arg_locals.nth(1).unwrap();
-                        for (i, &op) in args.into_iter().enumerate() {
-                            let dest = self.eval_place(&mir::Place::Local(local).field(
-                                mir::Field::new(i),
-                                op.layout.ty,
-                            ))?;
-                            self.copy_op(op, dest)?;
-                        }
-                    }
-                    _ => bug!("bad ABI for ClosureOnceShim: {:?}", sig.abi),
-                }
+                M::call_intrinsic(self, instance, args, dest)?;
+                // No stack frame gets pushed, the main loop will just act as if the
+                // call completed.
+                self.goto_block(ret)?;
+                self.dump_place(*dest);
                 Ok(())
             }
+            ty::InstanceDef::ClosureOnceShim { .. } |
             ty::InstanceDef::FnPtrShim(..) |
             ty::InstanceDef::DropGlue(..) |
             ty::InstanceDef::CloneShim(..) |
             ty::InstanceDef::Item(_) => {
-                // Push the stack frame, and potentially be entirely done if the call got hooked
-                if M::eval_fn_call(self, instance, destination, args, span)? {
-                    // FIXME: Can we make it return the frame to push, instead
-                    // of the hook doing half of the work and us doing the argument
-                    // initialization?
-                    return Ok(());
-                }
+                let mir = match M::find_fn(self, instance, args, dest, ret)? {
+                    Some(mir) => mir,
+                    None => return Ok(()),
+                };
+
+                let return_place = match dest {
+                    Some(place) => *place,
+                    None => Place::null(&self),
+                };
+                self.push_stack_frame(
+                    instance,
+                    span,
+                    mir,
+                    return_place,
+                    StackPopCleanup::Goto(ret),
+                )?;
 
-                // Pass the arguments
-                let mut arg_locals = self.frame().mir.args_iter();
-                trace!("ABI: {:?}", sig.abi);
+                // If we didn't get a signture, ask `fn_sig`
+                let sig = sig.unwrap_or_else(|| {
+                    let fn_sig = instance.ty(*self.tcx).fn_sig(*self.tcx);
+                    self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig)
+                });
+                assert_eq!(sig.inputs().len(), args.len());
+                // We can't test the types, as it is fine if the types are ABI-compatible but
+                // not equal.
+
+                // Figure out how to pass which arguments.
+                // FIXME: Somehow this is horribly full of special cases here, and codegen has
+                // none of that.  What is going on?
                 trace!(
-                    "args: {:#?}",
-                    self.frame().mir.args_iter().zip(args.iter())
-                        .map(|(local, arg)| (local, **arg, arg.layout.ty)).collect::<Vec<_>>()
+                    "ABI: {:?}, args: {:#?}",
+                    sig.abi,
+                    args.iter()
+                        .map(|arg| (arg.layout.ty, format!("{:?}", **arg)))
+                        .collect::<Vec<_>>()
+                );
+                trace!(
+                    "spread_arg: {:?}, locals: {:#?}",
+                    mir.spread_arg,
+                    mir.args_iter()
+                        .map(|local|
+                            (local, self.layout_of_local(self.cur_frame(), local).unwrap().ty)
+                        )
+                        .collect::<Vec<_>>()
                 );
-                match sig.abi {
-                    Abi::RustCall => {
-                        assert_eq!(args.len(), 2);
-
-                        {
-                            // write first argument
-                            let first_local = arg_locals.next().unwrap();
-                            let dest = self.eval_place(&mir::Place::Local(first_local))?;
-                            self.copy_op(args[0], dest)?;
-                        }
 
-                        // unpack and write all other args
-                        let layout = args[1].layout;
-                        if let ty::Tuple(_) = layout.ty.sty {
-                            if layout.is_zst() {
-                                // Nothing to do, no need to unpack zsts
-                                return Ok(());
-                            }
-                            if self.frame().mir.args_iter().count() == layout.fields.count() + 1 {
-                                for (i, arg_local) in arg_locals.enumerate() {
-                                    let arg = self.operand_field(args[1], i as u64)?;
-                                    let dest = self.eval_place(&mir::Place::Local(arg_local))?;
-                                    self.copy_op(arg, dest)?;
-                                }
-                            } else {
-                                trace!("manual impl of rust-call ABI");
-                                // called a manual impl of a rust-call function
-                                let dest = self.eval_place(
-                                    &mir::Place::Local(arg_locals.next().unwrap()),
-                                )?;
-                                self.copy_op(args[1], dest)?;
-                            }
-                        } else {
-                            bug!(
-                                "rust-call ABI tuple argument was {:#?}",
-                                layout
-                            );
-                        }
+                // We have two iterators: Where the arguments come from,
+                // and where they go to.
+
+                // For where they come from: If the ABI is RustCall, we untuple the
+                // last incoming argument.  These do not have the same type,
+                // so to keep the code paths uniform we accept an allocation
+                // (for RustCall ABI only).
+                let args_effective : Cow<[OpTy<'tcx>]> =
+                    if sig.abi == Abi::RustCall && !args.is_empty() {
+                        // Untuple
+                        let (&untuple_arg, args) = args.split_last().unwrap();
+                        trace!("eval_fn_call: Will pass last argument by untupling");
+                        Cow::from(args.iter().map(|&a| Ok(a))
+                            .chain((0..untuple_arg.layout.fields.count()).into_iter()
+                                .map(|i| self.operand_field(untuple_arg, i as u64))
+                            )
+                            .collect::<EvalResult<Vec<OpTy<'tcx>>>>()?)
+                    } else {
+                        // Plain arg passing
+                        Cow::from(args)
+                    };
+
+                // Now we have to spread them out across the callee's locals,
+                // taking into account the `spread_arg`.
+                let mut args_iter = args_effective.iter();
+                let mut local_iter = mir.args_iter();
+                // HACK: ClosureOnceShim calls something that expects a ZST as
+                // first argument, but the callers do not actually pass that ZST.
+                // Codegen doesn't care because ZST arguments do not even exist there.
+                match instance.def {
+                    ty::InstanceDef::ClosureOnceShim { .. } if sig.abi == Abi::Rust => {
+                        let local = local_iter.next().unwrap();
+                        let dest = self.eval_place(&mir::Place::Local(local))?;
+                        assert!(dest.layout.is_zst());
                     }
-                    _ => {
-                        for (arg_local, &op) in arg_locals.zip(args) {
-                            let dest = self.eval_place(&mir::Place::Local(arg_local))?;
-                            self.copy_op(op, dest)?;
+                    _ => {}
+                }
+                // Now back to norml argument passing.
+                while let Some(local) = local_iter.next() {
+                    let dest = self.eval_place(&mir::Place::Local(local))?;
+                    if Some(local) == mir.spread_arg {
+                        // Must be a tuple
+                        for i in 0..dest.layout.fields.count() {
+                            let dest = self.place_field(dest, i as u64)?;
+                            self.copy_op(*args_iter.next().unwrap(), dest)?;
                         }
+                    } else {
+                        // Normal argument
+                        self.copy_op(*args_iter.next().unwrap(), dest)?;
                     }
                 }
+                // Now we should be done
+                assert!(args_iter.next().is_none());
                 Ok(())
             }
             // cannot use the shim here, because that will only result in infinite recursion
             ty::InstanceDef::Virtual(_, idx) => {
                 let ptr_size = self.memory.pointer_size();
                 let ptr_align = self.tcx.data_layout.pointer_align;
-                let (ptr, vtable) = self.read_value(args[0])?.to_scalar_dyn_trait()?;
+                let ptr = self.ref_to_mplace(self.read_value(args[0])?)?;
+                let vtable = ptr.vtable()?;
                 let fn_ptr = self.memory.read_ptr_sized(
                     vtable.offset(ptr_size * (idx as u64 + 3), &self)?,
                     ptr_align
@@ -415,11 +428,50 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 let pointee = args[0].layout.ty.builtin_deref(true).unwrap().ty;
                 let fake_fat_ptr_ty = self.tcx.mk_mut_ptr(pointee);
                 args[0].layout = self.layout_of(fake_fat_ptr_ty)?.field(&self, 0)?;
-                args[0].op = Operand::Immediate(Value::Scalar(ptr.into())); // strip vtable
+                args[0].op = Operand::Immediate(Value::Scalar(ptr.ptr.into())); // strip vtable
                 trace!("Patched self operand to {:#?}", args[0]);
                 // recurse with concrete function
-                self.eval_fn_call(instance, destination, &args, span, sig)
+                self.eval_fn_call(instance, &args, dest, ret, span, sig)
             }
         }
     }
+
+    fn drop_in_place(
+        &mut self,
+        place: PlaceTy<'tcx>,
+        instance: ty::Instance<'tcx>,
+        span: Span,
+        target: mir::BasicBlock,
+    ) -> EvalResult<'tcx> {
+        trace!("drop_in_place: {:?},\n  {:?}, {:?}", *place, place.layout.ty, instance);
+        // We take the address of the object.  This may well be unaligned, which is fine
+        // for us here.  However, unaligned accesses will probably make the actual drop
+        // implementation fail -- a problem shared by rustc.
+        let place = self.force_allocation(place)?;
+
+        let (instance, place) = match place.layout.ty.sty {
+            ty::Dynamic(..) => {
+                // Dropping a trait object.
+                self.unpack_dyn_trait(place)?
+            }
+            _ => (instance, place),
+        };
+
+        let arg = OpTy {
+            op: Operand::Immediate(place.to_ref()),
+            layout: self.layout_of(self.tcx.mk_mut_ptr(place.layout.ty))?,
+        };
+
+        let ty = self.tcx.mk_nil(); // return type is ()
+        let dest = PlaceTy::null(&self, self.layout_of(ty)?);
+
+        self.eval_fn_call(
+            instance,
+            &[arg],
+            Some(dest),
+            Some(target),
+            span,
+            None,
+        )
+    }
 }
diff --git a/src/librustc_mir/interpret/terminator/drop.rs b/src/librustc_mir/interpret/terminator/drop.rs
deleted file mode 100644
index 8e413aa8284..00000000000
--- a/src/librustc_mir/interpret/terminator/drop.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use rustc::mir::BasicBlock;
-use rustc::ty::{self, layout::LayoutOf};
-use syntax::source_map::Span;
-
-use rustc::mir::interpret::EvalResult;
-use interpret::{Machine, EvalContext, PlaceTy, PlaceExtra, OpTy, Operand};
-
-impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
-    pub(crate) fn drop_in_place(
-        &mut self,
-        place: PlaceTy<'tcx>,
-        instance: ty::Instance<'tcx>,
-        span: Span,
-        target: BasicBlock,
-    ) -> EvalResult<'tcx> {
-        trace!("drop_in_place: {:?},\n  {:?}, {:?}", *place, place.layout.ty, instance);
-        // We take the address of the object.  This may well be unaligned, which is fine for us
-        // here. However, unaligned accesses will probably make the actual drop implementation fail
-        // -- a problem shared by rustc.
-        let place = self.force_allocation(place)?;
-
-        let (instance, place) = match place.layout.ty.sty {
-            ty::Dynamic(..) => {
-                // Dropping a trait object.
-                let vtable = match place.extra {
-                    PlaceExtra::Vtable(vtable) => vtable,
-                    _ => bug!("Expected vtable when dropping {:#?}", place),
-                };
-                let place = self.unpack_unsized_mplace(place)?;
-                let instance = self.read_drop_type_from_vtable(vtable)?;
-                (instance, place)
-            }
-            _ => (instance, place),
-        };
-
-        let fn_sig = instance.ty(*self.tcx).fn_sig(*self.tcx);
-        let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig);
-
-        let arg = OpTy {
-            op: Operand::Immediate(place.to_ref(&self)),
-            layout: self.layout_of(self.tcx.mk_mut_ptr(place.layout.ty))?,
-        };
-
-        // This should always be (), but getting it from the sig seems
-        // easier than creating a layout of ().
-        let dest = PlaceTy::null(&self, self.layout_of(fn_sig.output())?);
-
-        self.eval_fn_call(
-            instance,
-            Some((dest, target)),
-            &[arg],
-            span,
-            fn_sig,
-        )
-    }
-}
diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs
index 4ce0563749a..74567b42974 100644
--- a/src/librustc_mir/interpret/traits.rs
+++ b/src/librustc_mir/interpret/traits.rs
@@ -68,7 +68,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             }
         }
 
-        self.memory.mark_static_initialized(
+        self.memory.intern_static(
             vtable.alloc_id,
             Mutability::Immutable,
         )?;
@@ -76,14 +76,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         Ok(vtable)
     }
 
+    /// Return the drop fn instance as well as the actual dynamic type
     pub fn read_drop_type_from_vtable(
         &self,
         vtable: Pointer,
-    ) -> EvalResult<'tcx, ty::Instance<'tcx>> {
+    ) -> EvalResult<'tcx, (ty::Instance<'tcx>, ty::Ty<'tcx>)> {
         // we don't care about the pointee type, we just want a pointer
         let pointer_align = self.tcx.data_layout.pointer_align;
         let drop_fn = self.memory.read_ptr_sized(vtable, pointer_align)?.to_ptr()?;
-        self.memory.get_fn(drop_fn)
+        let drop_instance = self.memory.get_fn(drop_fn)?;
+        trace!("Found drop fn: {:?}", drop_instance);
+        let fn_sig = drop_instance.ty(*self.tcx).fn_sig(*self.tcx);
+        let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig);
+        // the drop function takes *mut T where T is the type being dropped, so get that
+        let ty = fn_sig.inputs()[0].builtin_deref(true).unwrap().ty;
+        Ok((drop_instance, ty))
     }
 
     pub fn read_size_and_align_from_vtable(
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index b0dfceb2597..d50fd6e13c1 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -19,7 +19,7 @@ use rustc::mir::interpret::{
 };
 
 use super::{
-    MPlaceTy, Machine, EvalContext
+    OpTy, Machine, EvalContext
 };
 
 macro_rules! validation_failure{
@@ -187,39 +187,39 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         }
     }
 
-    /// This function checks the memory where `dest` points to.  The place must be sized
-    /// (i.e., dest.extra == PlaceExtra::None).
+    /// This function checks the data at `op`.
     /// It will error if the bits at the destination do not match the ones described by the layout.
     /// The `path` may be pushed to, but the part that is present when the function
     /// starts must not be changed!
-    pub fn validate_mplace(
+    pub fn validate_operand(
         &self,
-        dest: MPlaceTy<'tcx>,
+        dest: OpTy<'tcx>,
         path: &mut Vec<PathElem>,
-        seen: &mut FxHashSet<(MPlaceTy<'tcx>)>,
-        todo: &mut Vec<(MPlaceTy<'tcx>, Vec<PathElem>)>,
+        seen: &mut FxHashSet<(OpTy<'tcx>)>,
+        todo: &mut Vec<(OpTy<'tcx>, Vec<PathElem>)>,
     ) -> EvalResult<'tcx> {
-        self.memory.dump_alloc(dest.to_ptr()?.alloc_id);
-        trace!("validate_mplace: {:?}, {:#?}", *dest, dest.layout);
+        trace!("validate_operand: {:?}, {:#?}", *dest, dest.layout);
 
         // Find the right variant.  We have to handle this as a prelude, not via
         // proper recursion with the new inner layout, to be able to later nicely
         // print the field names of the enum field that is being accessed.
         let (variant, dest) = match dest.layout.variants {
-            layout::Variants::NicheFilling { niche: ref tag, .. } |
-            layout::Variants::Tagged { ref tag, .. } => {
-                let size = tag.value.size(self);
-                // we first read the tag value as scalar, to be able to validate it
-                let tag_mplace = self.mplace_field(dest, 0)?;
-                let tag_value = self.read_scalar(tag_mplace.into())?;
-                path.push(PathElem::Tag);
-                self.validate_scalar(
-                    tag_value, size, tag, &path, tag_mplace.layout.ty
-                )?;
-                path.pop(); // remove the element again
-                // then we read it again to get the index, to continue
-                let variant = self.read_discriminant_as_variant_index(dest.into())?;
-                let inner_dest = self.mplace_downcast(dest, variant)?;
+            layout::Variants::NicheFilling { .. } |
+            layout::Variants::Tagged { .. } => {
+                let variant = match self.read_discriminant(dest) {
+                    Ok(res) => res.1,
+                    Err(err) => match err.kind {
+                        EvalErrorKind::InvalidDiscriminant(val) =>
+                            return validation_failure!(
+                                format!("invalid enum discriminant {}", val), path
+                            ),
+                        _ =>
+                            return validation_failure!(
+                                format!("non-integer enum discriminant"), path
+                            ),
+                    }
+                };
+                let inner_dest = self.operand_downcast(dest, variant)?;
                 // Put the variant projection onto the path, as a field
                 path.push(PathElem::Field(dest.layout.ty
                                           .ty_adt_def()
@@ -229,6 +229,23 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 (variant, inner_dest)
             },
             layout::Variants::Single { index } => {
+                // Pre-processing for trait objects: Treat them at their real type.
+                // (We do not do this for slices and strings: For slices it is not needed,
+                // `mplace_array_fields` does the right thing, and for strings there is no
+                // real type that would show the actual length.)
+                let dest = match dest.layout.ty.sty {
+                    ty::Dynamic(..) => {
+                        let dest = dest.to_mem_place(); // immediate trait objects are not a thing
+                        match self.unpack_dyn_trait(dest) {
+                            Ok(res) => res.1.into(),
+                            Err(_) =>
+                                return validation_failure!(
+                                    "invalid vtable in fat pointer", path
+                                ),
+                        }
+                    }
+                    _ => dest
+                };
                 (index, dest)
             }
         };
@@ -251,7 +268,20 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                     // expectation.
                     layout::Abi::Scalar(ref scalar_layout) => {
                         let size = scalar_layout.value.size(self);
-                        let value = self.read_value(dest.into())?;
+                        let value = match self.read_value(dest) {
+                            Ok(val) => val,
+                            Err(err) => match err.kind {
+                                EvalErrorKind::PointerOutOfBounds { .. } |
+                                EvalErrorKind::ReadUndefBytes =>
+                                    return validation_failure!(
+                                        "uninitialized or out-of-bounds memory", path
+                                    ),
+                                _ =>
+                                    return validation_failure!(
+                                        "unrepresentable data", path
+                                    ),
+                            }
+                        };
                         let scalar = value.to_scalar_or_undef();
                         self.validate_scalar(scalar, size, scalar_layout, &path, dest.layout.ty)?;
                         if scalar_layout.value == Primitive::Pointer {
@@ -260,18 +290,18 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                                 let alloc_kind = self.tcx.alloc_map.lock().get(ptr.alloc_id);
                                 if let Some(AllocType::Static(did)) = alloc_kind {
                                     // statics from other crates are already checked.
-                                    // extern statics should not be validated as they have no body.
+                                    // extern statics cannot be validated as they have no body.
                                     if !did.is_local() || self.tcx.is_foreign_item(did) {
                                         return Ok(());
                                     }
                                 }
                                 if value.layout.ty.builtin_deref(false).is_some() {
-                                    trace!("Recursing below ptr {:#?}", value);
-                                    let ptr_place = self.ref_to_mplace(value)?;
-                                    // we have not encountered this pointer+layout
-                                    // combination before
-                                    if seen.insert(ptr_place) {
-                                        todo.push((ptr_place, path_clone_and_deref(path)));
+                                    let ptr_op = self.ref_to_mplace(value)?.into();
+                                    // we have not encountered this pointer+layout combination
+                                    // before.
+                                    if seen.insert(ptr_op) {
+                                        trace!("Recursing below ptr {:#?}", *value);
+                                        todo.push((ptr_op, path_clone_and_deref(path)));
                                     }
                                 }
                             }
@@ -285,49 +315,98 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 // The fields don't need to correspond to any bit pattern of the union's fields.
                 // See https://github.com/rust-lang/rust/issues/32836#issuecomment-406875389
             },
-            layout::FieldPlacement::Array { .. } => {
-                for (i, field) in self.mplace_array_fields(dest)?.enumerate() {
-                    let field = field?;
-                    path.push(PathElem::ArrayElem(i));
-                    self.validate_mplace(field, path, seen, todo)?;
-                    path.truncate(path_len);
+            layout::FieldPlacement::Array { .. } if !dest.layout.is_zst() => {
+                let dest = dest.to_mem_place(); // non-ZST array/slice/str cannot be immediate
+                // Special handling for strings to verify UTF-8
+                match dest.layout.ty.sty {
+                    ty::Str => {
+                        match self.read_str(dest) {
+                            Ok(_) => {},
+                            Err(err) => match err.kind {
+                                EvalErrorKind::PointerOutOfBounds { .. } |
+                                EvalErrorKind::ReadUndefBytes =>
+                                    // The error here looks slightly different than it does
+                                    // for slices, because we do not report the index into the
+                                    // str at which we are OOB.
+                                    return validation_failure!(
+                                        "uninitialized or out-of-bounds memory", path
+                                    ),
+                                _ =>
+                                    return validation_failure!(
+                                        "non-UTF-8 data in str", path
+                                    ),
+                            }
+                        }
+                    }
+                    _ => {
+                        // This handles the unsized case correctly as well, as well as
+                        // SIMD an all sorts of other array-like types.
+                        for (i, field) in self.mplace_array_fields(dest)?.enumerate() {
+                            let field = field?;
+                            path.push(PathElem::ArrayElem(i));
+                            self.validate_operand(field.into(), path, seen, todo)?;
+                            path.truncate(path_len);
+                        }
+                    }
                 }
             },
+            layout::FieldPlacement::Array { .. } => {
+                // An empty array.  Nothing to do.
+            }
             layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
-                // Fat pointers need special treatment.
+                // Fat pointers are treated like pointers, not aggregates.
                 if dest.layout.ty.builtin_deref(true).is_some() {
                     // This is a fat pointer.
-                    let ptr = match self.ref_to_mplace(self.read_value(dest.into())?) {
+                    let ptr = match self.read_value(dest.into())
+                        .and_then(|val| self.ref_to_mplace(val))
+                    {
                         Ok(ptr) => ptr,
-                        Err(err) => match err.kind {
-                            EvalErrorKind::ReadPointerAsBytes =>
-                                return validation_failure!(
-                                    "fat pointer length is not a valid integer", path
-                                ),
-                            EvalErrorKind::ReadBytesAsPointer =>
-                                return validation_failure!(
-                                    "fat pointer vtable is not a valid pointer", path
-                                ),
-                            _ => return Err(err),
-                        }
+                        Err(_) =>
+                            return validation_failure!(
+                                "undefined location or metadata in fat pointer", path
+                            ),
                     };
-                    let unpacked_ptr = self.unpack_unsized_mplace(ptr)?;
+                    // check metadata early, for better diagnostics
+                    match self.tcx.struct_tail(ptr.layout.ty).sty {
+                        ty::Dynamic(..) => {
+                            match ptr.extra.unwrap().to_ptr() {
+                                Ok(_) => {},
+                                Err(_) =>
+                                    return validation_failure!(
+                                        "non-pointer vtable in fat pointer", path
+                                    ),
+                            }
+                        }
+                        ty::Slice(..) | ty::Str => {
+                            match ptr.extra.unwrap().to_usize(self) {
+                                Ok(_) => {},
+                                Err(_) =>
+                                    return validation_failure!(
+                                        "non-integer slice length in fat pointer", path
+                                    ),
+                            }
+                        }
+                        _ =>
+                            bug!("Unexpected unsized type tail: {:?}",
+                                self.tcx.struct_tail(ptr.layout.ty)
+                            ),
+                    }
                     // for safe ptrs, recursively check it
                     if !dest.layout.ty.is_unsafe_ptr() {
-                        trace!("Recursing below fat ptr {:?} (unpacked: {:?})", ptr, unpacked_ptr);
-                        if seen.insert(unpacked_ptr) {
-                            todo.push((unpacked_ptr, path_clone_and_deref(path)));
+                        let ptr = ptr.into();
+                        if seen.insert(ptr) {
+                            trace!("Recursing below fat ptr {:?}", ptr);
+                            todo.push((ptr, path_clone_and_deref(path)));
                         }
                     }
                 } else {
                     // Not a pointer, perform regular aggregate handling below
                     for i in 0..offsets.len() {
-                        let field = self.mplace_field(dest, i as u64)?;
+                        let field = self.operand_field(dest, i as u64)?;
                         path.push(self.aggregate_field_path_elem(dest.layout.ty, variant, i));
-                        self.validate_mplace(field, path, seen, todo)?;
+                        self.validate_operand(field, path, seen, todo)?;
                         path.truncate(path_len);
                     }
-                    // FIXME: For a TyStr, check that this is valid UTF-8.
                 }
             }
         }
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 617efed31d9..f91ff3642cd 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -15,8 +15,9 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
 */
 
 #![cfg_attr(not(stage0), feature(nll))]
-#![feature(infer_outlives_requirements)]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(in_band_lifetimes)]
+#![feature(impl_header_lifetime_elision)]
 #![feature(slice_patterns)]
 #![feature(slice_sort_by_cached_key)]
 #![feature(box_patterns)]
@@ -82,6 +83,7 @@ pub mod transform;
 pub mod util;
 pub mod interpret;
 pub mod monomorphize;
+pub mod const_eval;
 
 pub use hair::pattern::check_crate as matchck_crate;
 use rustc::ty::query::Providers;
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index a1dbf9ddb03..52bbffa7519 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -191,7 +191,7 @@
 use rustc::hir::{self, CodegenFnAttrFlags};
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 
-use rustc::hir::map as hir_map;
+use rustc::hir::Node;
 use rustc::hir::def_id::DefId;
 use rustc::mir::interpret::{AllocId, ConstValue, ScalarMaybeUndef};
 use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
@@ -740,7 +740,7 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance:
     };
 
     return match tcx.hir.get_if_local(def_id) {
-        Some(hir_map::NodeForeignItem(..)) => {
+        Some(Node::ForeignItem(..)) => {
             false // foreign items are linked against, not codegened.
         }
         Some(_) => true,
@@ -1023,7 +1023,6 @@ impl<'b, 'a, 'v> RootCollector<'b, 'a, 'v> {
             MonoItemCollectionMode::Lazy => {
                 self.entry_fn == Some(def_id) ||
                 self.tcx.is_reachable_non_generic(def_id) ||
-                self.tcx.is_weak_lang_item(def_id) ||
                 self.tcx.codegen_fn_attrs(def_id).flags.contains(
                     CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
             }
@@ -1272,7 +1271,7 @@ fn collect_const<'a, 'tcx>(
         ConstValue::ScalarPair(Scalar::Ptr(ptr), _) |
         ConstValue::Scalar(Scalar::Ptr(ptr)) =>
             collect_miri(tcx, ptr.alloc_id, output),
-        ConstValue::ByRef(alloc, _offset) => {
+        ConstValue::ByRef(_id, alloc, _offset) => {
             for &id in alloc.relocations.values() {
                 collect_miri(tcx, id, output);
             }
diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs
index 7d7be69b355..c480fa41246 100644
--- a/src/librustc_mir/monomorphize/partitioning.rs
+++ b/src/librustc_mir/monomorphize/partitioning.rs
@@ -516,10 +516,8 @@ fn mono_item_visibility(
         //   visibility below. Like the weak lang items, though, we can't let
         //   LLVM internalize them as this decision is left up to the linker to
         //   omit them, so prevent them from being internalized.
-        let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id);
-        let std_internal_symbol = codegen_fn_attrs.flags
-            .contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
-        if tcx.is_weak_lang_item(def_id) || std_internal_symbol {
+        let attrs = tcx.codegen_fn_attrs(def_id);
+        if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
             *can_be_internalized = false;
         }
 
diff --git a/src/librustc_mir/transform/add_validation.rs b/src/librustc_mir/transform/add_validation.rs
index 9061b34ae44..6efefdaa004 100644
--- a/src/librustc_mir/transform/add_validation.rs
+++ b/src/librustc_mir/transform/add_validation.rs
@@ -85,7 +85,7 @@ fn place_context<'a, 'tcx, D>(
 fn fn_contains_unsafe<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource) -> bool {
     use rustc::hir::intravisit::{self, Visitor, FnKind};
     use rustc::hir::map::blocks::FnLikeNode;
-    use rustc::hir::map::Node;
+    use rustc::hir::Node;
 
     /// Decide if this is an unsafe block
     fn block_is_unsafe(block: &hir::Block) -> bool {
@@ -142,13 +142,13 @@ fn fn_contains_unsafe<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource) ->
             }
             // Check if this is an unsafe block, or an item
             match node {
-                Node::NodeExpr(&hir::Expr { node: hir::ExprKind::Block(ref block, _), ..}) => {
+                Node::Expr(&hir::Expr { node: hir::ExprKind::Block(ref block, _), ..}) => {
                     if block_is_unsafe(&*block) {
                         // Found an unsafe block, we can bail out here.
                         return true;
                     }
                 }
-                Node::NodeItem(..) => {
+                Node::Item(..) => {
                     // No walking up beyond items.  This makes sure the loop always terminates.
                     break;
                 }
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 5d284981c70..f6006ae045e 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -15,6 +15,7 @@ use rustc_data_structures::sync::Lrc;
 use rustc::ty::query::Providers;
 use rustc::ty::{self, TyCtxt};
 use rustc::hir;
+use rustc::hir::Node;
 use rustc::hir::def_id::DefId;
 use rustc::lint::builtin::{SAFE_EXTERN_STATICS, SAFE_PACKED_BORROWS, UNUSED_UNSAFE};
 use rustc::mir::*;
@@ -407,7 +408,7 @@ fn is_enclosed(tcx: TyCtxt,
     if parent_id != id {
         if used_unsafe.contains(&parent_id) {
             Some(("block".to_string(), parent_id))
-        } else if let Some(hir::map::NodeItem(&hir::Item {
+        } else if let Some(Node::Item(&hir::Item {
             node: hir::ItemKind::Fn(_, header, _, _),
             ..
         })) = tcx.hir.find(parent_id) {
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index fa11e6f0719..1715930dbb6 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -14,7 +14,7 @@
 
 use rustc::hir::def::Def;
 use rustc::mir::{Constant, Location, Place, Mir, Operand, Rvalue, Local};
-use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind};
+use rustc::mir::{NullOp, UnOp, StatementKind, Statement, BasicBlock, LocalKind};
 use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem};
 use rustc::mir::visit::{Visitor, PlaceContext};
 use rustc::mir::interpret::{
@@ -170,7 +170,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
                     | DoubleFree
                     | InvalidFunctionPointer
                     | InvalidBool
-                    | InvalidDiscriminant
+                    | InvalidDiscriminant(..)
                     | PointerOutOfBounds { .. }
                     | InvalidNullPointerUsage
                     | MemoryLockViolation { .. }
@@ -257,10 +257,9 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
         source_info: SourceInfo,
     ) -> Option<Const<'tcx>> {
         self.ecx.tcx.span = source_info.span;
-        match self.ecx.const_value_to_op(c.literal.val) {
+        match self.ecx.const_to_op(c.literal) {
             Ok(op) => {
-                let layout = self.tcx.layout_of(self.param_env.and(c.literal.ty)).ok()?;
-                Some((OpTy { op, layout }, c.span))
+                Some((op, c.span))
             },
             Err(error) => {
                 let (stacktrace, span) = self.ecx.generate_stacktrace(None);
@@ -382,6 +381,20 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
                 let (arg, _) = self.eval_operand(arg, source_info)?;
                 let val = self.use_ecx(source_info, |this| {
                     let prim = this.ecx.read_scalar(arg)?.not_undef()?;
+                    match op {
+                        UnOp::Neg => {
+                            // Need to do overflow check here: For actual CTFE, MIR
+                            // generation emits code that does this before calling the op.
+                            let size = arg.layout.size;
+                            if prim.to_bits(size)? == (1 << (size.bits() - 1)) {
+                                return err!(OverflowNeg);
+                            }
+                        }
+                        UnOp::Not => {
+                            // Cannot overflow
+                        }
+                    }
+                    // Now run the actual operation.
                     this.ecx.unary_op(op, prim, arg.layout)
                 })?;
                 Some((OpTy::from_scalar_value(val, place_layout), span))
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index db588884d8e..e9afa7df5c4 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -66,7 +66,7 @@ use rustc::mir::visit::{PlaceContext, Visitor, MutVisitor};
 use rustc::ty::{self, TyCtxt, AdtDef, Ty};
 use rustc::ty::subst::Substs;
 use util::dump_mir;
-use util::liveness::{self, IdentityMap, LivenessMode};
+use util::liveness::{self, IdentityMap};
 use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::indexed_set::IdxSet;
 use std::collections::HashMap;
@@ -402,10 +402,6 @@ fn locals_live_across_suspend_points<'a, 'tcx,>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let mut set = liveness::LiveVarSet::new_empty(mir.local_decls.len());
     let mut liveness = liveness::liveness_of_locals(
         mir,
-        LivenessMode {
-            include_regular_use: true,
-            include_drops: true,
-        },
         &IdentityMap::new(mir),
     );
     liveness::dump_mir(
diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs
index 63675f056ab..eda7de0fd79 100644
--- a/src/librustc_mir/transform/rustc_peek.rs
+++ b/src/librustc_mir/transform/rustc_peek.rs
@@ -209,8 +209,8 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             &mut sets, Location { block: bb, statement_index: j });
         results.0.operator.statement_effect(
             &mut sets, Location { block: bb, statement_index: j });
-        sets.on_entry.union_hybrid(sets.gen_set);
-        sets.on_entry.subtract_hybrid(sets.kill_set);
+        sets.on_entry.union(sets.gen_set);
+        sets.on_entry.subtract(sets.kill_set);
     }
 
     results.0.operator.before_terminator_effect(
diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs
index 04fa516a655..3ae470e1d4b 100644
--- a/src/librustc_mir/util/liveness.rs
+++ b/src/librustc_mir/util/liveness.rs
@@ -33,7 +33,6 @@
 //! generator yield points, all pre-existing references are invalidated, so this
 //! doesn't matter).
 
-use rustc::mir::visit::MirVisitable;
 use rustc::mir::visit::{PlaceContext, Visitor};
 use rustc::mir::Local;
 use rustc::mir::*;
@@ -50,17 +49,13 @@ use util::pretty::{dump_enabled, write_basic_block, write_mir_intro};
 pub type LiveVarSet<V> = IdxSet<V>;
 
 /// This gives the result of the liveness analysis at the boundary of
-/// basic blocks. You can use `simulate_block` to obtain the
-/// intra-block results.
+/// basic blocks.
 ///
 /// The `V` type defines the set of variables that we computed
 /// liveness for. This is often `Local`, in which case we computed
 /// liveness for all variables -- but it can also be some other type,
 /// which indicates a subset of the variables within the graph.
 pub struct LivenessResult<V: Idx> {
-    /// Liveness mode in use when these results were computed.
-    pub mode: LivenessMode,
-
     /// Live variables on exit to each basic block. This is equal to
     /// the union of the `ins` for each successor.
     pub outs: IndexVec<BasicBlock, LiveVarSet<V>>,
@@ -104,68 +99,11 @@ impl<'a, 'tcx> LiveVariableMap for IdentityMap<'a, 'tcx> {
     }
 }
 
-#[derive(Copy, Clone, Debug)]
-pub struct LivenessMode {
-    /// If true, then we will consider "regular uses" of a variable to be live.
-    /// For example, if the user writes `foo(x)`, then this is a regular use of
-    /// the variable `x`.
-    pub include_regular_use: bool,
-
-    /// If true, then we will consider (implicit) drops of a variable
-    /// to be live.  For example, if the user writes `{ let x =
-    /// vec![...]; .. }`, then the drop at the end of the block is an
-    /// implicit drop.
-    ///
-    /// NB. Despite its name, a call like `::std::mem::drop(x)` is
-    /// **not** considered a drop for this purposes, but rather a
-    /// regular use.
-    pub include_drops: bool,
-}
-
-/// A combination of liveness results, used in NLL.
-pub struct LivenessResults<V: Idx> {
-    /// Liveness results where a regular use makes a variable X live,
-    /// but not a drop.
-    pub regular: LivenessResult<V>,
-
-    /// Liveness results where a drop makes a variable X live,
-    /// but not a regular use.
-    pub drop: LivenessResult<V>,
-}
-
-impl<V: Idx> LivenessResults<V> {
-    pub fn compute<'tcx>(
-        mir: &Mir<'tcx>,
-        map: &impl LiveVariableMap<LiveVar = V>,
-    ) -> LivenessResults<V> {
-        LivenessResults {
-            regular: liveness_of_locals(
-                &mir,
-                LivenessMode {
-                    include_regular_use: true,
-                    include_drops: false,
-                },
-                map,
-            ),
-
-            drop: liveness_of_locals(
-                &mir,
-                LivenessMode {
-                    include_regular_use: false,
-                    include_drops: true,
-                },
-                map,
-            ),
-        }
-    }
-}
-
 /// Compute which local variables are live within the given function
 /// `mir`. The liveness mode `mode` determines what sorts of uses are
 /// considered to make a variable live (e.g., do drops count?).
 pub fn liveness_of_locals<'tcx, V: Idx>(
     mir: &Mir<'tcx>,
-    mode: LivenessMode,
     map: &impl LiveVariableMap<LiveVar = V>,
 ) -> LivenessResult<V> {
     let num_live_vars = map.num_variables();
@@ -173,7 +111,7 @@ pub fn liveness_of_locals<'tcx, V: Idx>(
     let def_use: IndexVec<_, DefsUses<V>> = mir
         .basic_blocks()
         .iter()
-        .map(|b| block(mode, map, b, num_live_vars))
+        .map(|b| block(map, b, num_live_vars))
         .collect();
 
     let mut outs: IndexVec<_, LiveVarSet<V>> = mir
@@ -208,80 +146,17 @@ pub fn liveness_of_locals<'tcx, V: Idx>(
         }
     }
 
-    LivenessResult { mode, outs }
-}
-
-impl<V: Idx> LivenessResult<V> {
-    /// Walks backwards through the statements/terminator in the given
-    /// basic block `block`.  At each point within `block`, invokes
-    /// the callback `op` with the current location and the set of
-    /// variables that are live on entry to that location.
-    pub fn simulate_block<'tcx, OP>(
-        &self,
-        mir: &Mir<'tcx>,
-        block: BasicBlock,
-        map: &impl LiveVariableMap<LiveVar = V>,
-        mut callback: OP,
-    ) where
-        OP: FnMut(Location, &LiveVarSet<V>),
-    {
-        let data = &mir[block];
-
-        // Get a copy of the bits on exit from the block.
-        let mut bits = self.outs[block].clone();
-
-        // Start with the maximal statement index -- i.e., right before
-        // the terminator executes.
-        let mut statement_index = data.statements.len();
-
-        // Compute liveness right before terminator and invoke callback.
-        let terminator_location = Location {
-            block,
-            statement_index,
-        };
-        let num_live_vars = map.num_variables();
-        let mut visitor = DefsUsesVisitor {
-            mode: self.mode,
-            map,
-            defs_uses: DefsUses {
-                defs: LiveVarSet::new_empty(num_live_vars),
-                uses: LiveVarSet::new_empty(num_live_vars),
-            },
-        };
-        // Visit the various parts of the basic block in reverse. If we go
-        // forward, the logic in `add_def` and `add_use` would be wrong.
-        visitor.update_bits_and_do_callback(
-            terminator_location,
-            &data.terminator,
-            &mut bits,
-            &mut callback,
-        );
-
-        // Compute liveness before each statement (in rev order) and invoke callback.
-        for statement in data.statements.iter().rev() {
-            statement_index -= 1;
-            let statement_location = Location {
-                block,
-                statement_index,
-            };
-            visitor.defs_uses.clear();
-            visitor.update_bits_and_do_callback(
-                statement_location,
-                statement,
-                &mut bits,
-                &mut callback,
-            );
-        }
-    }
+    LivenessResult { outs }
 }
 
 #[derive(Eq, PartialEq, Clone)]
 pub enum DefUse {
     Def,
     Use,
+    Drop,
 }
 
-pub fn categorize<'tcx>(context: PlaceContext<'tcx>, mode: LivenessMode) -> Option<DefUse> {
+pub fn categorize<'tcx>(context: PlaceContext<'tcx>) -> Option<DefUse> {
     match context {
         ///////////////////////////////////////////////////////////////////////////
         // DEFS
@@ -322,13 +197,8 @@ pub fn categorize<'tcx>(context: PlaceContext<'tcx>, mode: LivenessMode) -> Opti
         PlaceContext::Inspect |
         PlaceContext::Copy |
         PlaceContext::Move |
-        PlaceContext::Validate => {
-            if mode.include_regular_use {
-                Some(DefUse::Use)
-            } else {
-                None
-            }
-        }
+        PlaceContext::Validate =>
+            Some(DefUse::Use),
 
         ///////////////////////////////////////////////////////////////////////////
         // DROP USES
@@ -338,13 +208,8 @@ pub fn categorize<'tcx>(context: PlaceContext<'tcx>, mode: LivenessMode) -> Opti
         // uses in drop are special because `#[may_dangle]`
         // attributes can affect whether lifetimes must be live.
 
-        PlaceContext::Drop => {
-            if mode.include_drops {
-                Some(DefUse::Use)
-            } else {
-                None
-            }
-        }
+        PlaceContext::Drop =>
+            Some(DefUse::Drop),
     }
 }
 
@@ -353,7 +218,6 @@ where
     V: Idx,
     M: LiveVariableMap<LiveVar = V> + 'lv,
 {
-    mode: LivenessMode,
     map: &'lv M,
     defs_uses: DefsUses<V>,
 }
@@ -365,11 +229,6 @@ struct DefsUses<V: Idx> {
 }
 
 impl<V: Idx> DefsUses<V> {
-    fn clear(&mut self) {
-        self.uses.clear();
-        self.defs.clear();
-    }
-
     fn apply(&self, bits: &mut LiveVarSet<V>) -> bool {
         bits.subtract(&self.defs) | bits.union(&self.uses)
     }
@@ -404,29 +263,6 @@ impl<V: Idx> DefsUses<V> {
     }
 }
 
-impl<'lv, V, M> DefsUsesVisitor<'lv, V, M>
-where
-    V: Idx,
-    M: LiveVariableMap<LiveVar = V>,
-{
-    /// Update `bits` with the effects of `value` and call `callback`. We
-    /// should always visit in reverse order. This method assumes that we have
-    /// not visited anything before; if you have, clear `bits` first.
-    fn update_bits_and_do_callback<'tcx, OP>(
-        &mut self,
-        location: Location,
-        value: &impl MirVisitable<'tcx>,
-        bits: &mut LiveVarSet<V>,
-        callback: &mut OP,
-    ) where
-        OP: FnMut(Location, &LiveVarSet<V>),
-    {
-        value.apply(location, self);
-        self.defs_uses.apply(bits);
-        callback(location, bits);
-    }
-}
-
 impl<'tcx, 'lv, V, M> Visitor<'tcx> for DefsUsesVisitor<'lv, V, M>
 where
     V: Idx,
@@ -434,23 +270,21 @@ where
 {
     fn visit_local(&mut self, &local: &Local, context: PlaceContext<'tcx>, _: Location) {
         if let Some(v_index) = self.map.from_local(local) {
-            match categorize(context, self.mode) {
+            match categorize(context) {
                 Some(DefUse::Def) => self.defs_uses.add_def(v_index),
-                Some(DefUse::Use) => self.defs_uses.add_use(v_index),
-                None => (),
+                Some(DefUse::Use) | Some(DefUse::Drop) => self.defs_uses.add_use(v_index),
+                _ => (),
             }
         }
     }
 }
 
 fn block<'tcx, V: Idx>(
-    mode: LivenessMode,
     map: &impl LiveVariableMap<LiveVar = V>,
     b: &BasicBlockData<'tcx>,
     locals: usize,
 ) -> DefsUses<V> {
     let mut visitor = DefsUsesVisitor {
-        mode,
         map,
         defs_uses: DefsUses {
             defs: LiveVarSet::new_empty(locals),
@@ -526,7 +360,8 @@ pub fn write_mir_fn<'a, 'tcx, V: Idx>(
     write_mir_intro(tcx, src, mir, w)?;
     for block in mir.basic_blocks().indices() {
         let print = |w: &mut dyn Write, prefix, result: &IndexVec<BasicBlock, LiveVarSet<V>>| {
-            let live: Vec<String> = result[block].iter()
+            let live: Vec<String> = result[block]
+                .iter()
                 .map(|v| map.from_live_var(v))
                 .map(|local| format!("{:?}", local))
                 .collect();
diff --git a/src/librustc_msan/lib.rs b/src/librustc_msan/lib.rs
index b3ba86ad8a4..ed8fd305977 100644
--- a/src/librustc_msan/lib.rs
+++ b/src/librustc_msan/lib.rs
@@ -11,6 +11,7 @@
 #![sanitizer_runtime]
 #![feature(alloc_system)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(sanitizer_runtime)]
 #![feature(staged_api)]
 #![no_std]
diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs
index d62cb00923f..94ea229cbd9 100644
--- a/src/librustc_passes/lib.rs
+++ b/src/librustc_passes/lib.rs
@@ -19,6 +19,7 @@
        html_root_url = "https://doc.rust-lang.org/nightly/")]
 
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(rustc_diagnostic_macros)]
 
 #[macro_use]
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index 8ef20126e03..44030c284fd 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -13,7 +13,7 @@ use rustc::session::Session;
 
 use rustc::hir::map::Map;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
-use rustc::hir::{self, Destination};
+use rustc::hir::{self, Node, Destination};
 use syntax::ast;
 use syntax_pos::Span;
 
@@ -115,7 +115,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
 
                 if loop_id != ast::DUMMY_NODE_ID {
                     match self.hir_map.find(loop_id).unwrap() {
-                        hir::map::NodeBlock(_) => return,
+                        Node::Block(_) => return,
                         _=> (),
                     }
                 }
@@ -158,7 +158,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
 
                 match label.target_id {
                     Ok(loop_id) => {
-                        if let hir::map::NodeBlock(block) = self.hir_map.find(loop_id).unwrap() {
+                        if let Node::Block(block) = self.hir_map.find(loop_id).unwrap() {
                             struct_span_err!(self.sess, e.span, E0696,
                                             "`continue` pointing to a labeled block")
                                 .span_label(e.span,
diff --git a/src/librustc_platform_intrinsics/lib.rs b/src/librustc_platform_intrinsics/lib.rs
index d41f4cd61f7..62405150cd2 100644
--- a/src/librustc_platform_intrinsics/lib.rs
+++ b/src/librustc_platform_intrinsics/lib.rs
@@ -11,6 +11,7 @@
 #![allow(bad_style)]
 
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 
 pub struct Intrinsic {
     pub inputs: &'static [&'static Type],
diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs
index 67f53a67313..5b562666385 100644
--- a/src/librustc_plugin/lib.rs
+++ b/src/librustc_plugin/lib.rs
@@ -65,6 +65,7 @@
        html_root_url = "https://doc.rust-lang.org/nightly/")]
 
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(rustc_diagnostic_macros)]
 
 #[macro_use] extern crate syntax;
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index f68f2d0da68..5166f69ba03 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -13,6 +13,7 @@
        html_root_url = "https://doc.rust-lang.org/nightly/")]
 
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(rustc_diagnostic_macros)]
 
 #![recursion_limit="256"]
@@ -24,6 +25,7 @@ extern crate syntax_pos;
 extern crate rustc_data_structures;
 
 use rustc::hir::{self, PatKind};
+use hir::Node;
 use rustc::hir::def::Def;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId};
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
@@ -658,17 +660,17 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
         match self.tcx.hir.as_local_node_id(did) {
             Some(node_id) => {
                 let vis = match self.tcx.hir.get(node_id) {
-                    hir::map::NodeItem(item) => &item.vis,
-                    hir::map::NodeForeignItem(foreign_item) => &foreign_item.vis,
-                    hir::map::NodeImplItem(impl_item) => &impl_item.vis,
-                    hir::map::NodeTraitItem(..) |
-                    hir::map::NodeVariant(..) => {
+                    Node::Item(item) => &item.vis,
+                    Node::ForeignItem(foreign_item) => &foreign_item.vis,
+                    Node::ImplItem(impl_item) => &impl_item.vis,
+                    Node::TraitItem(..) |
+                    Node::Variant(..) => {
                         return self.def_id_visibility(self.tcx.hir.get_parent_did(node_id));
                     }
-                    hir::map::NodeStructCtor(vdata) => {
+                    Node::StructCtor(vdata) => {
                         let struct_node_id = self.tcx.hir.get_parent(node_id);
                         let struct_vis = match self.tcx.hir.get(struct_node_id) {
-                            hir::map::NodeItem(item) => &item.vis,
+                            Node::Item(item) => &item.vis,
                             node => bug!("unexpected node kind: {:?}", node),
                         };
                         let mut ctor_vis
@@ -1036,7 +1038,7 @@ impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
             // .. and it corresponds to a private type in the AST (this returns
             // None for type parameters)
             match self.tcx.hir.find(node_id) {
-                Some(hir::map::NodeItem(ref item)) => !item.vis.node.is_pub(),
+                Some(Node::Item(ref item)) => !item.vis.node.is_pub(),
                 Some(_) | None => false,
             }
         } else {
@@ -1468,8 +1470,8 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
             // Non-local means public (private items can't leave their crate, modulo bugs)
             if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
                 let hir_vis = match self.tcx.hir.find(node_id) {
-                    Some(hir::map::NodeItem(item)) => &item.vis,
-                    Some(hir::map::NodeForeignItem(item)) => &item.vis,
+                    Some(Node::Item(item)) => &item.vis,
+                    Some(Node::ForeignItem(item)) => &item.vis,
                     _ => bug!("expected item of foreign item"),
                 };
 
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 264f5c01135..78c518aea96 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -14,6 +14,7 @@
 
 #![feature(crate_visibility_modifier)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(rustc_diagnostic_macros)]
 #![feature(slice_sort_by_cached_key)]
 
@@ -1951,9 +1952,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
                                 "access to extern crates through prelude is experimental").emit();
                 }
 
-                let crate_id = self.crate_loader.process_path_extern(ident.name, ident.span);
-                let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
-                self.populate_module_if_necessary(crate_root);
+                let crate_root = self.load_extern_prelude_crate_if_needed(ident);
 
                 let binding = (crate_root, ty::Visibility::Public,
                                ident.span, Mark::root()).to_name_binding(self.arenas);
@@ -1981,6 +1980,13 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
         None
     }
 
+    fn load_extern_prelude_crate_if_needed(&mut self, ident: Ident) -> Module<'a> {
+        let crate_id = self.crate_loader.process_path_extern(ident.name, ident.span);
+        let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
+        self.populate_module_if_necessary(&crate_root);
+        crate_root
+    }
+
     fn hygienic_lexical_parent(&mut self, module: Module<'a>, span: &mut Span)
                                -> Option<Module<'a>> {
         if !module.expansion.is_descendant_of(span.ctxt().outer()) {
@@ -4227,16 +4233,11 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
         }
     }
 
-    /// When name resolution fails, this method can be used to look up candidate
-    /// entities with the expected name. It allows filtering them using the
-    /// supplied predicate (which should be used to only accept the types of
-    /// definitions expected e.g. traits). The lookup spans across all crates.
-    ///
-    /// NOTE: The method does not look into imports, but this is not a problem,
-    /// since we report the definitions (thus, the de-aliased imports).
-    fn lookup_import_candidates<FilterFn>(&mut self,
+    fn lookup_import_candidates_from_module<FilterFn>(&mut self,
                                           lookup_name: Name,
                                           namespace: Namespace,
+                                          start_module: &'a ModuleData<'a>,
+                                          crate_name: Ident,
                                           filter_fn: FilterFn)
                                           -> Vec<ImportSuggestion>
         where FilterFn: Fn(Def) -> bool
@@ -4244,7 +4245,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
         let mut candidates = Vec::new();
         let mut worklist = Vec::new();
         let mut seen_modules = FxHashSet();
-        worklist.push((self.graph_root, Vec::new(), false));
+        let not_local_module = crate_name != keywords::Crate.ident();
+        worklist.push((start_module, Vec::<ast::PathSegment>::new(), not_local_module));
 
         while let Some((in_module,
                         path_segments,
@@ -4263,17 +4265,14 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
                 if ident.name == lookup_name && ns == namespace {
                     if filter_fn(name_binding.def()) {
                         // create the path
-                        let mut segms = if self.session.rust_2018() && !in_module_is_extern {
+                        let mut segms = path_segments.clone();
+                        if self.session.rust_2018() {
                             // crate-local absolute paths start with `crate::` in edition 2018
                             // FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
-                            let mut full_segms = vec![
-                                ast::PathSegment::from_ident(keywords::Crate.ident())
-                            ];
-                            full_segms.extend(path_segments.clone());
-                            full_segms
-                        } else {
-                            path_segments.clone()
-                        };
+                            segms.insert(
+                                0, ast::PathSegment::from_ident(crate_name)
+                            );
+                        }
 
                         segms.push(ast::PathSegment::from_ident(ident));
                         let path = Path {
@@ -4299,7 +4298,14 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
                     let mut path_segments = path_segments.clone();
                     path_segments.push(ast::PathSegment::from_ident(ident));
 
-                    if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
+                    let is_extern_crate_that_also_appears_in_prelude =
+                        name_binding.is_extern_crate() &&
+                        self.session.rust_2018();
+
+                    let is_visible_to_user =
+                        !in_module_is_extern || name_binding.vis == ty::Visibility::Public;
+
+                    if !is_extern_crate_that_also_appears_in_prelude && is_visible_to_user {
                         // add the module to the lookup
                         let is_extern = in_module_is_extern || name_binding.is_extern_crate();
                         if seen_modules.insert(module.def_id().unwrap()) {
@@ -4313,6 +4319,45 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
         candidates
     }
 
+    /// When name resolution fails, this method can be used to look up candidate
+    /// entities with the expected name. It allows filtering them using the
+    /// supplied predicate (which should be used to only accept the types of
+    /// definitions expected e.g. traits). The lookup spans across all crates.
+    ///
+    /// NOTE: The method does not look into imports, but this is not a problem,
+    /// since we report the definitions (thus, the de-aliased imports).
+    fn lookup_import_candidates<FilterFn>(&mut self,
+                                          lookup_name: Name,
+                                          namespace: Namespace,
+                                          filter_fn: FilterFn)
+                                          -> Vec<ImportSuggestion>
+        where FilterFn: Fn(Def) -> bool
+    {
+        let mut suggestions = vec![];
+
+        suggestions.extend(
+            self.lookup_import_candidates_from_module(
+                lookup_name, namespace, self.graph_root, keywords::Crate.ident(), &filter_fn
+            )
+        );
+
+        if self.session.features_untracked().extern_prelude {
+            let extern_prelude_names = self.extern_prelude.clone();
+            for &krate_name in extern_prelude_names.iter() {
+                let krate_ident = Ident::with_empty_ctxt(krate_name);
+                let external_prelude_module = self.load_extern_prelude_crate_if_needed(krate_ident);
+
+                suggestions.extend(
+                    self.lookup_import_candidates_from_module(
+                        lookup_name, namespace, external_prelude_module, krate_ident, &filter_fn
+                    )
+                );
+            }
+        }
+
+        suggestions
+    }
+
     fn find_module(&mut self,
                    module_def: Def)
                    -> Option<(Module<'a>, ImportSuggestion)>
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 1549634e9b5..fd29dac5af8 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -13,6 +13,7 @@
        html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(custom_attribute)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![allow(unused_attributes)]
 
 #![recursion_limit="256"]
@@ -42,7 +43,7 @@ mod sig;
 
 use rustc::hir;
 use rustc::hir::def::Def as HirDef;
-use rustc::hir::map::{Node, NodeTraitItem, NodeImplItem};
+use rustc::hir::Node;
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::middle::cstore::ExternCrate;
 use rustc::session::config::CrateType;
@@ -419,7 +420,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         let (qualname, parent_scope, decl_id, docs, attributes) =
             match self.tcx.impl_of_method(self.tcx.hir.local_def_id(id)) {
                 Some(impl_id) => match self.tcx.hir.get_if_local(impl_id) {
-                    Some(Node::NodeItem(item)) => match item.node {
+                    Some(Node::Item(item)) => match item.node {
                         hir::ItemKind::Impl(.., ref ty, _) => {
                             let mut qualname = String::from("<");
                             qualname.push_str(&self.tcx.hir.node_to_pretty_string(ty.id));
@@ -428,7 +429,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                             let mut decl_id = None;
                             let mut docs = String::new();
                             let mut attrs = vec![];
-                            if let Some(NodeImplItem(item)) = self.tcx.hir.find(id) {
+                            if let Some(Node::ImplItem(item)) = self.tcx.hir.find(id) {
                                 docs = self.docs_for_attrs(&item.attrs);
                                 attrs = item.attrs.to_vec();
                             }
@@ -470,7 +471,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                         let mut docs = String::new();
                         let mut attrs = vec![];
 
-                        if let Some(NodeTraitItem(item)) = self.tcx.hir.find(id) {
+                        if let Some(Node::TraitItem(item)) = self.tcx.hir.find(id) {
                             docs = self.docs_for_attrs(&item.attrs);
                             attrs = item.attrs.to_vec();
                         }
@@ -540,7 +541,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         match expr.node {
             ast::ExprKind::Field(ref sub_ex, ident) => {
                 let hir_node = match self.tcx.hir.find(sub_ex.id) {
-                    Some(Node::NodeExpr(expr)) => expr,
+                    Some(Node::Expr(expr)) => expr,
                     _ => {
                         debug!(
                             "Missing or weird node for sub-expression {} in {:?}",
@@ -627,32 +628,32 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
 
     pub fn get_path_def(&self, id: NodeId) -> HirDef {
         match self.tcx.hir.get(id) {
-            Node::NodeTraitRef(tr) => tr.path.def,
+            Node::TraitRef(tr) => tr.path.def,
 
-            Node::NodeItem(&hir::Item {
+            Node::Item(&hir::Item {
                 node: hir::ItemKind::Use(ref path, _),
                 ..
             }) |
-            Node::NodeVisibility(&Spanned {
+            Node::Visibility(&Spanned {
                 node: hir::VisibilityKind::Restricted { ref path, .. }, .. }) => path.def,
 
-            Node::NodeExpr(&hir::Expr {
+            Node::Expr(&hir::Expr {
                 node: hir::ExprKind::Struct(ref qpath, ..),
                 ..
             }) |
-            Node::NodeExpr(&hir::Expr {
+            Node::Expr(&hir::Expr {
                 node: hir::ExprKind::Path(ref qpath),
                 ..
             }) |
-            Node::NodePat(&hir::Pat {
+            Node::Pat(&hir::Pat {
                 node: hir::PatKind::Path(ref qpath),
                 ..
             }) |
-            Node::NodePat(&hir::Pat {
+            Node::Pat(&hir::Pat {
                 node: hir::PatKind::Struct(ref qpath, ..),
                 ..
             }) |
-            Node::NodePat(&hir::Pat {
+            Node::Pat(&hir::Pat {
                 node: hir::PatKind::TupleStruct(ref qpath, ..),
                 ..
             }) => {
@@ -660,12 +661,12 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 self.tables.qpath_def(qpath, hir_id)
             }
 
-            Node::NodeBinding(&hir::Pat {
+            Node::Binding(&hir::Pat {
                 node: hir::PatKind::Binding(_, canonical_id, ..),
                 ..
             }) => HirDef::Local(canonical_id),
 
-            Node::NodeTy(ty) => if let hir::Ty {
+            Node::Ty(ty) => if let hir::Ty {
                 node: hir::TyKind::Path(ref qpath),
                 ..
             } = *ty
diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs
index 5f5cc4c5ff7..1e70a806cce 100644
--- a/src/librustc_target/lib.rs
+++ b/src/librustc_target/lib.rs
@@ -24,6 +24,7 @@
 #![feature(box_syntax)]
 #![feature(const_fn)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(slice_patterns)]
 
 #[macro_use]
diff --git a/src/librustc_target/spec/armebv7r_none_eabi.rs b/src/librustc_target/spec/armebv7r_none_eabi.rs
new file mode 100644
index 00000000000..8d3ff1b800f
--- /dev/null
+++ b/src/librustc_target/spec/armebv7r_none_eabi.rs
@@ -0,0 +1,40 @@
+// 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.
+
+// Targets the Big endian Cortex-R4/R5 processor (ARMv7-R)
+
+use std::default::Default;
+use spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    Ok(Target {
+        llvm_target: "armebv7r-unknown-none-eabi".to_string(),
+        target_endian: "big".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "E-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+        arch: "arm".to_string(),
+        target_os: "none".to_string(),
+        target_env: "".to_string(),
+        target_vendor: "".to_string(),
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+
+        options: TargetOptions {
+            executables: true,
+            linker: Some("rust-lld".to_owned()),
+            relocation_model: "static".to_string(),
+            panic_strategy: PanicStrategy::Abort,
+            max_atomic_width: Some(32),
+            abi_blacklist: super::arm_base::abi_blacklist(),
+            emit_debug_gdb_scripts: false,
+            .. Default::default()
+        },
+    })
+}
diff --git a/src/librustc_target/spec/armebv7r_none_eabihf.rs b/src/librustc_target/spec/armebv7r_none_eabihf.rs
index c111d2ffe8b..0343ea7bd17 100644
--- a/src/librustc_target/spec/armebv7r_none_eabihf.rs
+++ b/src/librustc_target/spec/armebv7r_none_eabihf.rs
@@ -11,11 +11,11 @@
 // Targets the Cortex-R4F/R5F processor (ARMv7-R)
 
 use std::default::Default;
-use spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
+use spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
     Ok(Target {
-        llvm_target: "armebv7r-none-eabihf".to_string(),
+        llvm_target: "armebv7r-unknown-none-eabihf".to_string(),
         target_endian: "big".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
@@ -24,13 +24,14 @@ pub fn target() -> TargetResult {
         target_os: "none".to_string(),
         target_env: String::new(),
         target_vendor: String::new(),
-        linker_flavor: LinkerFlavor::Gcc,
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
             executables: true,
+            linker: Some("rust-lld".to_owned()),
             relocation_model: "static".to_string(),
             panic_strategy: PanicStrategy::Abort,
-            features: "+v7,+vfp3,+d16,+fp-only-sp".to_string(),
+            features: "+vfp3,+d16,+fp-only-sp".to_string(),
             max_atomic_width: Some(32),
             abi_blacklist: super::arm_base::abi_blacklist(),
             emit_debug_gdb_scripts: false,
diff --git a/src/librustc_target/spec/armv7r_none_eabi.rs b/src/librustc_target/spec/armv7r_none_eabi.rs
new file mode 100644
index 00000000000..43148d593f1
--- /dev/null
+++ b/src/librustc_target/spec/armv7r_none_eabi.rs
@@ -0,0 +1,40 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Targets the Little-endian Cortex-R4/R5 processor (ARMv7-R)
+
+use std::default::Default;
+use spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    Ok(Target {
+        llvm_target: "armv7r-unknown-none-eabi".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+        arch: "arm".to_string(),
+        target_os: "none".to_string(),
+        target_env: "".to_string(),
+        target_vendor: "".to_string(),
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+
+        options: TargetOptions {
+            executables: true,
+            linker: Some("rust-lld".to_owned()),
+            relocation_model: "static".to_string(),
+            panic_strategy: PanicStrategy::Abort,
+            max_atomic_width: Some(32),
+            abi_blacklist: super::arm_base::abi_blacklist(),
+            emit_debug_gdb_scripts: false,
+            .. Default::default()
+        },
+    })
+}
diff --git a/src/librustc_target/spec/armv7r_none_eabihf.rs b/src/librustc_target/spec/armv7r_none_eabihf.rs
new file mode 100644
index 00000000000..036b0544c52
--- /dev/null
+++ b/src/librustc_target/spec/armv7r_none_eabihf.rs
@@ -0,0 +1,41 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Targets the Little-endian Cortex-R4F/R5F processor (ARMv7-R)
+
+use std::default::Default;
+use spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    Ok(Target {
+        llvm_target: "armv7r-unknown-none-eabihf".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+        arch: "arm".to_string(),
+        target_os: "none".to_string(),
+        target_env: "".to_string(),
+        target_vendor: "".to_string(),
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+
+        options: TargetOptions {
+            executables: true,
+            linker: Some("rust-lld".to_owned()),
+            relocation_model: "static".to_string(),
+            panic_strategy: PanicStrategy::Abort,
+            features: "+vfp3,+d16,+fp-only-sp".to_string(),
+            max_atomic_width: Some(32),
+            abi_blacklist: super::arm_base::abi_blacklist(),
+            emit_debug_gdb_scripts: false,
+            .. Default::default()
+        },
+    })
+}
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index 7608ccab66f..7c0cdf991ef 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -370,7 +370,10 @@ supported_targets! {
     ("armv7-apple-ios", armv7_apple_ios),
     ("armv7s-apple-ios", armv7s_apple_ios),
 
+    ("armebv7r-none-eabi", armebv7r_none_eabi),
     ("armebv7r-none-eabihf", armebv7r_none_eabihf),
+    ("armv7r-none-eabi", armv7r_none_eabi),
+    ("armv7r-none-eabihf", armv7r_none_eabihf),
 
     ("x86_64-sun-solaris", x86_64_sun_solaris),
     ("sparcv9-sun-solaris", sparcv9_sun_solaris),
diff --git a/src/librustc_target/spec/thumb_base.rs b/src/librustc_target/spec/thumb_base.rs
index fdaf1dc6110..4c9a4764eff 100644
--- a/src/librustc_target/spec/thumb_base.rs
+++ b/src/librustc_target/spec/thumb_base.rs
@@ -42,9 +42,8 @@ pub fn opts() -> TargetOptions {
     // See rust-lang/rfcs#1645 for a discussion about these defaults
     TargetOptions {
         executables: true,
-        // In 99%+ of cases, we want to use the `arm-none-eabi-gcc` compiler (there aren't many
-        // options around)
-        linker: Some("arm-none-eabi-gcc".to_string()),
+        // In most cases, LLD is good enough
+        linker: Some("rust-lld".to_string()),
         // Because these devices have very little resources having an unwinder is too onerous so we
         // default to "abort" because the "unwind" strategy is very rare.
         panic_strategy: PanicStrategy::Abort,
diff --git a/src/librustc_target/spec/thumbv6m_none_eabi.rs b/src/librustc_target/spec/thumbv6m_none_eabi.rs
index bfac1ba45e1..99034277abd 100644
--- a/src/librustc_target/spec/thumbv6m_none_eabi.rs
+++ b/src/librustc_target/spec/thumbv6m_none_eabi.rs
@@ -10,7 +10,7 @@
 
 // Targets the Cortex-M0, Cortex-M0+ and Cortex-M1 processors (ARMv6-M architecture)
 
-use spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
     Ok(Target {
@@ -23,7 +23,7 @@ pub fn target() -> TargetResult {
         target_os: "none".to_string(),
         target_env: String::new(),
         target_vendor: String::new(),
-        linker_flavor: LinkerFlavor::Gcc,
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
             // The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them
diff --git a/src/librustc_target/spec/thumbv7em_none_eabi.rs b/src/librustc_target/spec/thumbv7em_none_eabi.rs
index 0207f38dea8..17fad29dd29 100644
--- a/src/librustc_target/spec/thumbv7em_none_eabi.rs
+++ b/src/librustc_target/spec/thumbv7em_none_eabi.rs
@@ -19,7 +19,7 @@
 // To opt-in to hardware accelerated floating point operations, you can use, for example,
 // `-C target-feature=+vfp4` or `-C target-cpu=cortex-m4`.
 
-use spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
     Ok(Target {
@@ -32,7 +32,7 @@ pub fn target() -> TargetResult {
         target_os: "none".to_string(),
         target_env: String::new(),
         target_vendor: String::new(),
-        linker_flavor: LinkerFlavor::Gcc,
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
             max_atomic_width: Some(32),
diff --git a/src/librustc_target/spec/thumbv7em_none_eabihf.rs b/src/librustc_target/spec/thumbv7em_none_eabihf.rs
index bb1a42f0e28..02ede112ed3 100644
--- a/src/librustc_target/spec/thumbv7em_none_eabihf.rs
+++ b/src/librustc_target/spec/thumbv7em_none_eabihf.rs
@@ -18,7 +18,7 @@
 //
 // To opt into double precision hardware support, use the `-C target-feature=-fp-only-sp` flag.
 
-use spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
     Ok(Target {
@@ -31,7 +31,7 @@ pub fn target() -> TargetResult {
         target_os: "none".to_string(),
         target_env: String::new(),
         target_vendor: String::new(),
-        linker_flavor: LinkerFlavor::Gcc,
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
             // `+vfp4` is the lowest common denominator between the Cortex-M4 (vfp4-16) and the
diff --git a/src/librustc_target/spec/thumbv7m_none_eabi.rs b/src/librustc_target/spec/thumbv7m_none_eabi.rs
index 1eac13afd9a..f4fffade163 100644
--- a/src/librustc_target/spec/thumbv7m_none_eabi.rs
+++ b/src/librustc_target/spec/thumbv7m_none_eabi.rs
@@ -10,7 +10,7 @@
 
 // Targets the Cortex-M3 processor (ARMv7-M)
 
-use spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
     Ok(Target {
@@ -23,7 +23,7 @@ pub fn target() -> TargetResult {
         target_os: "none".to_string(),
         target_env: String::new(),
         target_vendor: String::new(),
-        linker_flavor: LinkerFlavor::Gcc,
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
             max_atomic_width: Some(32),
diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs
index 7fe1af81951..971dfa751f1 100644
--- a/src/librustc_traits/lib.rs
+++ b/src/librustc_traits/lib.rs
@@ -16,6 +16,7 @@
 #![feature(extern_prelude)]
 #![feature(in_band_lifetimes)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 
 #![recursion_limit="256"]
 
diff --git a/src/librustc_tsan/lib.rs b/src/librustc_tsan/lib.rs
index b3ba86ad8a4..ed8fd305977 100644
--- a/src/librustc_tsan/lib.rs
+++ b/src/librustc_tsan/lib.rs
@@ -11,6 +11,7 @@
 #![sanitizer_runtime]
 #![feature(alloc_system)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(sanitizer_runtime)]
 #![feature(staged_api)]
 #![no_std]
diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml
index 184cb9826ba..881fa2604bc 100644
--- a/src/librustc_typeck/Cargo.toml
+++ b/src/librustc_typeck/Cargo.toml
@@ -10,12 +10,13 @@ crate-type = ["dylib"]
 test = false
 
 [dependencies]
-log = "0.4"
-syntax = { path = "../libsyntax" }
 arena = { path = "../libarena" }
+log = "0.4"
 rustc = { path = "../librustc" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_errors = { path = "../librustc_errors" }
 rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
 rustc_target = { path = "../librustc_target" }
+smallvec = { version = "0.6.5", features = ["union"] }
+syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
-rustc_errors = { path = "../librustc_errors" }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 3c9452835fd..804aad3c0ec 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -12,8 +12,7 @@
 //! representation.  The main routine here is `ast_ty_to_ty()`: each use
 //! is parameterized by an instance of `AstConv`.
 
-use rustc_data_structures::accumulate_vec::AccumulateVec;
-use rustc_data_structures::array_vec::ArrayVec;
+use smallvec::SmallVec;
 use hir::{self, GenericArg, GenericArgs};
 use hir::def::Def;
 use hir::def_id::DefId;
@@ -431,18 +430,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
         // We manually build up the substitution, rather than using convenience
         // methods in subst.rs so that we can iterate over the arguments and
         // parameters in lock-step linearly, rather than trying to match each pair.
-        let mut substs: AccumulateVec<[Kind<'tcx>; 8]> = if count <= 8 {
-            AccumulateVec::Array(ArrayVec::new())
-        } else {
-            AccumulateVec::Heap(Vec::with_capacity(count))
-        };
-
-        fn push_kind<'tcx>(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, kind: Kind<'tcx>) {
-            match substs {
-                AccumulateVec::Array(ref mut arr) => arr.push(kind),
-                AccumulateVec::Heap(ref mut vec) => vec.push(kind),
-            }
-        }
+        let mut substs: SmallVec<[Kind<'tcx>; 8]> = SmallVec::with_capacity(count);
 
         // Iterate over each segment of the path.
         while let Some((def_id, defs)) = stack.pop() {
@@ -451,7 +439,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
             // If we have already computed substitutions for parents, we can use those directly.
             while let Some(&param) = params.peek() {
                 if let Some(&kind) = parent_substs.get(param.index as usize) {
-                    push_kind(&mut substs, kind);
+                    substs.push(kind);
                     params.next();
                 } else {
                     break;
@@ -463,7 +451,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
                 if let Some(&param) = params.peek() {
                     if param.index == 0 {
                         if let GenericParamDefKind::Type { .. } = param.kind {
-                            push_kind(&mut substs, self_ty.map(|ty| ty.into())
+                            substs.push(self_ty.map(|ty| ty.into())
                                 .unwrap_or_else(|| inferred_kind(None, param, true)));
                             params.next();
                         }
@@ -487,7 +475,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
                         match (arg, &param.kind) {
                             (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime)
                             | (GenericArg::Type(_), GenericParamDefKind::Type { .. }) => {
-                                push_kind(&mut substs, provided_kind(param, arg));
+                                substs.push(provided_kind(param, arg));
                                 args.next();
                                 params.next();
                             }
@@ -501,7 +489,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
                             (GenericArg::Type(_), GenericParamDefKind::Lifetime) => {
                                 // We expected a lifetime argument, but got a type
                                 // argument. That means we're inferring the lifetimes.
-                                push_kind(&mut substs, inferred_kind(None, param, infer_types));
+                                substs.push(inferred_kind(None, param, infer_types));
                                 params.next();
                             }
                         }
@@ -518,7 +506,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
                         match param.kind {
                             GenericParamDefKind::Lifetime | GenericParamDefKind::Type { .. } => {
                                 let kind = inferred_kind(Some(&substs), param, infer_types);
-                                push_kind(&mut substs, kind);
+                                substs.push(kind);
                             }
                         }
                         args.next();
@@ -1041,7 +1029,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
             .chain(auto_traits.into_iter().map(ty::ExistentialPredicate::AutoTrait))
             .chain(existential_projections
                    .map(|x| ty::ExistentialPredicate::Projection(*x.skip_binder())))
-            .collect::<AccumulateVec<[_; 8]>>();
+            .collect::<SmallVec<[_; 8]>>();
         v.sort_by(|a, b| a.stable_cmp(tcx, b));
         let existential_predicates = ty::Binder::bind(tcx.mk_existential_predicates(v.into_iter()));
 
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index b0b2799c793..85646b9ab67 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -17,7 +17,7 @@ use syntax::util::parser::PREC_POSTFIX;
 use syntax_pos::Span;
 use rustc::hir;
 use rustc::hir::def::Def;
-use rustc::hir::map::{NodeItem, NodeExpr};
+use rustc::hir::Node;
 use rustc::hir::{Item, ItemKind, print};
 use rustc::ty::{self, Ty, AssociatedItem};
 use rustc::ty::adjustment::AllowTwoPhase;
@@ -199,13 +199,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.node {
             if let hir::def::Def::Local(id) = path.def {
                 let parent = self.tcx.hir.get_parent_node(id);
-                if let Some(NodeExpr(hir::Expr {
+                if let Some(Node::Expr(hir::Expr {
                     id,
                     node: hir::ExprKind::Closure(_, decl, ..),
                     ..
                 })) = self.tcx.hir.find(parent) {
                     let parent = self.tcx.hir.get_parent_node(*id);
-                    if let (Some(NodeExpr(hir::Expr {
+                    if let (Some(Node::Expr(hir::Expr {
                         node: hir::ExprKind::MethodCall(path, span, expr),
                         ..
                     })), 1) = (self.tcx.hir.find(parent), decl.inputs.len()) {
@@ -377,7 +377,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         match self.tcx.hir.find(parent_id) {
             Some(parent) => {
                 // Shouldn't suggest `.into()` on `const`s.
-                if let NodeItem(Item { node: ItemKind::Const(_, _), .. }) = parent {
+                if let Node::Item(Item { node: ItemKind::Const(_, _), .. }) = parent {
                     // FIXME(estebank): modify once we decide to suggest `as` casts
                     return false;
                 }
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 14e36ba3429..abc32ed2ea0 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -13,6 +13,7 @@
 
 use check::FnCtxt;
 use rustc::hir::map as hir_map;
+use hir::Node;
 use rustc_data_structures::sync::Lrc;
 use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable};
 use hir::def::Def;
@@ -275,7 +276,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                         );
 
                                         match (filename, parent_node) {
-                                            (FileName::Real(_), hir_map::NodeLocal(hir::Local {
+                                            (FileName::Real(_), Node::Local(hir::Local {
                                                 source: hir::LocalSource::Normal,
                                                 ty,
                                                 ..
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 2b33f289346..bbb45c04e4e 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -132,7 +132,7 @@ use syntax_pos::{self, BytePos, Span, MultiSpan};
 
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
-use rustc::hir::map::Node;
+use rustc::hir::Node;
 use rustc::hir::{self, PatKind, ItemKind};
 use rustc::middle::lang_items;
 
@@ -761,7 +761,7 @@ fn primary_body_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              -> Option<(hir::BodyId, Option<&'tcx hir::FnDecl>)>
 {
     match tcx.hir.get(id) {
-        hir::map::NodeItem(item) => {
+        Node::Item(item) => {
             match item.node {
                 hir::ItemKind::Const(_, body) |
                 hir::ItemKind::Static(_, _, body) =>
@@ -772,7 +772,7 @@ fn primary_body_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     None,
             }
         }
-        hir::map::NodeTraitItem(item) => {
+        Node::TraitItem(item) => {
             match item.node {
                 hir::TraitItemKind::Const(_, Some(body)) =>
                     Some((body, None)),
@@ -782,7 +782,7 @@ fn primary_body_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     None,
             }
         }
-        hir::map::NodeImplItem(item) => {
+        Node::ImplItem(item) => {
             match item.node {
                 hir::ImplItemKind::Const(_, body) =>
                     Some((body, None)),
@@ -792,7 +792,7 @@ fn primary_body_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     None,
             }
         }
-        hir::map::NodeAnonConst(constant) => Some((constant.body, None)),
+        Node::AnonConst(constant) => Some((constant.body, None)),
         _ => None,
     }
 }
@@ -1167,7 +1167,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
                         );
                     }
 
-                    if let Node::NodeItem(item) = fcx.tcx.hir.get(fn_id) {
+                    if let Node::Item(item) = fcx.tcx.hir.get(fn_id) {
                         if let ItemKind::Fn(_, _, ref generics, _) = item.node {
                             if !generics.params.is_empty() {
                                 fcx.tcx.sess.span_err(
@@ -1214,7 +1214,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
                         );
                     }
 
-                    if let Node::NodeItem(item) = fcx.tcx.hir.get(fn_id) {
+                    if let Node::Item(item) = fcx.tcx.hir.get(fn_id) {
                         if let ItemKind::Fn(_, _, ref generics, _) = item.node {
                             if !generics.params.is_empty() {
                                 fcx.tcx.sess.span_err(
@@ -4646,7 +4646,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         if let Some(fn_id) = self.tcx.hir.get_return_block(blk_id) {
             let parent = self.tcx.hir.get(fn_id);
 
-            if let Node::NodeItem(&hir::Item {
+            if let Node::Item(&hir::Item {
                 name, node: hir::ItemKind::Fn(ref decl, ..), ..
             }) = parent {
                 decl.clone().and_then(|decl| {
@@ -4655,7 +4655,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     // but it will still present it as the reason for the expected type.
                     Some((decl, name != Symbol::intern("main")))
                 })
-            } else if let Node::NodeTraitItem(&hir::TraitItem {
+            } else if let Node::TraitItem(&hir::TraitItem {
                 node: hir::TraitItemKind::Method(hir::MethodSig {
                     ref decl, ..
                 }, ..), ..
@@ -4663,7 +4663,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 decl.clone().and_then(|decl| {
                     Some((decl, true))
                 })
-            } else if let Node::NodeImplItem(&hir::ImplItem {
+            } else if let Node::ImplItem(&hir::ImplItem {
                 node: hir::ImplItemKind::Method(hir::MethodSig {
                     ref decl, ..
                 }, ..), ..
@@ -5174,7 +5174,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // If our calling expression is indeed the function itself, we're good!
         // If not, generate an error that this can only be called directly.
         match self.tcx.hir.get(self.tcx.hir.get_parent_node(node_id)) {
-            Node::NodeExpr(expr) => {
+            Node::Expr(expr) => {
                 match expr.node {
                     hir::ExprKind::Call(ref callee, ..) => {
                         if callee.id == node_id {
diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs
index 52e6663792b..d7aec1d62cd 100644
--- a/src/librustc_typeck/check_unused.rs
+++ b/src/librustc_typeck/check_unused.rs
@@ -176,7 +176,12 @@ fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) {
         };
         let replacement = visibility_qualified(&item.vis, &base_replacement);
         tcx.struct_span_lint_node(lint, id, extern_crate.span, msg)
-            .span_suggestion_short(extern_crate.span, &help, replacement)
+            .span_suggestion_short_with_applicability(
+                extern_crate.span,
+                &help,
+                replacement,
+                Applicability::MachineApplicable,
+            )
             .emit();
     }
 }
diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs
index d01e7dbdfef..efc35fad820 100644
--- a/src/librustc_typeck/coherence/builtin.rs
+++ b/src/librustc_typeck/coherence/builtin.rs
@@ -23,7 +23,7 @@ use rustc::ty::util::CopyImplementationError;
 use rustc::infer;
 
 use rustc::hir::def_id::DefId;
-use rustc::hir::map as hir_map;
+use hir::Node;
 use rustc::hir::{self, ItemKind};
 
 pub fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_def_id: DefId) {
@@ -60,7 +60,7 @@ fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_did:
             // Destructors only work on nominal types.
             if let Some(impl_node_id) = tcx.hir.as_local_node_id(impl_did) {
                 match tcx.hir.find(impl_node_id) {
-                    Some(hir_map::NodeItem(item)) => {
+                    Some(Node::Item(item)) => {
                         let span = match item.node {
                             ItemKind::Impl(.., ref ty, _) => ty.span,
                             _ => item.span,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index e404eb4ecca..a42667ab45f 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -29,6 +29,7 @@ use constrained_type_params as ctp;
 use lint;
 use middle::lang_items::SizedTraitLangItem;
 use middle::resolve_lifetime as rl;
+use middle::weak_lang_items;
 use rustc::mir::mono::Linkage;
 use rustc::ty::query::Providers;
 use rustc::ty::subst::Substs;
@@ -49,10 +50,11 @@ use syntax::symbol::{keywords, Symbol};
 use syntax_pos::{Span, DUMMY_SP};
 
 use rustc::hir::def::{CtorKind, Def};
+use rustc::hir::Node;
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc::hir::GenericParamKind;
-use rustc::hir::{self, map as hir_map, CodegenFnAttrFlags, CodegenFnAttrs, Unsafety};
+use rustc::hir::{self, CodegenFnAttrFlags, CodegenFnAttrs, Unsafety};
 
 ///////////////////////////////////////////////////////////////////////////
 // Main entry point
@@ -237,7 +239,6 @@ fn type_param_predicates<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     (item_def_id, def_id): (DefId, DefId),
 ) -> ty::GenericPredicates<'tcx> {
-    use rustc::hir::map::*;
     use rustc::hir::*;
 
     // In the AST, bounds can derive from two places. Either
@@ -271,11 +272,11 @@ fn type_param_predicates<'a, 'tcx>(
 
     let item_node_id = tcx.hir.as_local_node_id(item_def_id).unwrap();
     let ast_generics = match tcx.hir.get(item_node_id) {
-        NodeTraitItem(item) => &item.generics,
+        Node::TraitItem(item) => &item.generics,
 
-        NodeImplItem(item) => &item.generics,
+        Node::ImplItem(item) => &item.generics,
 
-        NodeItem(item) => {
+        Node::Item(item) => {
             match item.node {
                 ItemKind::Fn(.., ref generics, _)
                 | ItemKind::Impl(_, _, _, ref generics, ..)
@@ -301,7 +302,7 @@ fn type_param_predicates<'a, 'tcx>(
             }
         }
 
-        NodeForeignItem(item) => match item.node {
+        Node::ForeignItem(item) => match item.node {
             ForeignItemKind::Fn(_, _, ref generics) => generics,
             _ => return result,
         },
@@ -594,12 +595,11 @@ fn convert_struct_variant<'a, 'tcx>(
 }
 
 fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::AdtDef {
-    use rustc::hir::map::*;
     use rustc::hir::*;
 
     let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
     let item = match tcx.hir.get(node_id) {
-        NodeItem(item) => item,
+        Node::Item(item) => item,
         _ => bug!(),
     };
 
@@ -670,7 +670,7 @@ fn super_predicates_of<'a, 'tcx>(
     let trait_node_id = tcx.hir.as_local_node_id(trait_def_id).unwrap();
 
     let item = match tcx.hir.get(trait_node_id) {
-        hir_map::NodeItem(item) => item,
+        Node::Item(item) => item,
         _ => bug!("trait_node_id {} is not an item", trait_node_id),
     };
 
@@ -739,7 +739,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::
 
 fn has_late_bound_regions<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    node: hir_map::Node<'tcx>,
+    node: Node<'tcx>,
 ) -> Option<Span> {
     struct LateBoundRegionsDetector<'a, 'tcx: 'a> {
         tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -825,25 +825,25 @@ fn has_late_bound_regions<'a, 'tcx>(
     }
 
     match node {
-        hir_map::NodeTraitItem(item) => match item.node {
+        Node::TraitItem(item) => match item.node {
             hir::TraitItemKind::Method(ref sig, _) => {
                 has_late_bound_regions(tcx, &item.generics, &sig.decl)
             }
             _ => None,
         },
-        hir_map::NodeImplItem(item) => match item.node {
+        Node::ImplItem(item) => match item.node {
             hir::ImplItemKind::Method(ref sig, _) => {
                 has_late_bound_regions(tcx, &item.generics, &sig.decl)
             }
             _ => None,
         },
-        hir_map::NodeForeignItem(item) => match item.node {
+        Node::ForeignItem(item) => match item.node {
             hir::ForeignItemKind::Fn(ref fn_decl, _, ref generics) => {
                 has_late_bound_regions(tcx, generics, fn_decl)
             }
             _ => None,
         },
-        hir_map::NodeItem(item) => match item.node {
+        Node::Item(item) => match item.node {
             hir::ItemKind::Fn(ref fn_decl, .., ref generics, _) => {
                 has_late_bound_regions(tcx, generics, fn_decl)
             }
@@ -854,22 +854,22 @@ fn has_late_bound_regions<'a, 'tcx>(
 }
 
 fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::Generics {
-    use rustc::hir::map::*;
     use rustc::hir::*;
 
     let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
 
     let node = tcx.hir.get(node_id);
     let parent_def_id = match node {
-        NodeImplItem(_) | NodeTraitItem(_) | NodeVariant(_) | NodeStructCtor(_) | NodeField(_) => {
+        Node::ImplItem(_) | Node::TraitItem(_) | Node::Variant(_)
+        | Node::StructCtor(_) | Node::Field(_) => {
             let parent_id = tcx.hir.get_parent(node_id);
             Some(tcx.hir.local_def_id(parent_id))
         }
-        NodeExpr(&hir::Expr {
+        Node::Expr(&hir::Expr {
             node: hir::ExprKind::Closure(..),
             ..
         }) => Some(tcx.closure_base_def_id(def_id)),
-        NodeItem(item) => match item.node {
+        Node::Item(item) => match item.node {
             ItemKind::Existential(hir::ExistTy { impl_trait_fn, .. }) => impl_trait_fn,
             _ => None,
         },
@@ -881,11 +881,11 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty
 
     let no_generics = hir::Generics::empty();
     let ast_generics = match node {
-        NodeTraitItem(item) => &item.generics,
+        Node::TraitItem(item) => &item.generics,
 
-        NodeImplItem(item) => &item.generics,
+        Node::ImplItem(item) => &item.generics,
 
-        NodeItem(item) => {
+        Node::Item(item) => {
             match item.node {
                 ItemKind::Fn(.., ref generics, _) | ItemKind::Impl(_, _, _, ref generics, ..) => {
                     generics
@@ -928,7 +928,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty
             }
         }
 
-        NodeForeignItem(item) => match item.node {
+        Node::ForeignItem(item) => match item.node {
             ForeignItemKind::Static(..) => &no_generics,
             ForeignItemKind::Fn(_, _, ref generics) => generics,
             ForeignItemKind::Type => &no_generics,
@@ -1023,7 +1023,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty
     // provide junk type parameter defs - the only place that
     // cares about anything but the length is instantiation,
     // and we don't do that for closures.
-    if let NodeExpr(&hir::Expr {
+    if let Node::Expr(&hir::Expr {
         node: hir::ExprKind::Closure(.., gen),
         ..
     }) = node
@@ -1093,7 +1093,6 @@ fn report_assoc_ty_on_inherent_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span:
 }
 
 fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
-    use rustc::hir::map::*;
     use rustc::hir::*;
 
     let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
@@ -1101,7 +1100,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
     let icx = ItemCtxt::new(tcx, def_id);
 
     match tcx.hir.get(node_id) {
-        NodeTraitItem(item) => match item.node {
+        Node::TraitItem(item) => match item.node {
             TraitItemKind::Method(..) => {
                 let substs = Substs::identity_for_item(tcx, def_id);
                 tcx.mk_fn_def(def_id, substs)
@@ -1112,7 +1111,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
             }
         },
 
-        NodeImplItem(item) => match item.node {
+        Node::ImplItem(item) => match item.node {
             ImplItemKind::Method(..) => {
                 let substs = Substs::identity_for_item(tcx, def_id);
                 tcx.mk_fn_def(def_id, substs)
@@ -1140,7 +1139,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
             }
         },
 
-        NodeItem(item) => {
+        Node::Item(item) => {
             match item.node {
                 ItemKind::Static(ref t, ..)
                 | ItemKind::Const(ref t, _)
@@ -1198,7 +1197,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
             }
         }
 
-        NodeForeignItem(foreign_item) => match foreign_item.node {
+        Node::ForeignItem(foreign_item) => match foreign_item.node {
             ForeignItemKind::Fn(..) => {
                 let substs = Substs::identity_for_item(tcx, def_id);
                 tcx.mk_fn_def(def_id, substs)
@@ -1207,8 +1206,8 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
             ForeignItemKind::Type => tcx.mk_foreign(def_id),
         },
 
-        NodeStructCtor(&ref def)
-        | NodeVariant(&Spanned {
+        Node::StructCtor(&ref def)
+        | Node::Variant(&Spanned {
             node: hir::VariantKind { data: ref def, .. },
             ..
         }) => match *def {
@@ -1221,9 +1220,9 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
             }
         },
 
-        NodeField(field) => icx.to_ty(&field.ty),
+        Node::Field(field) => icx.to_ty(&field.ty),
 
-        NodeExpr(&hir::Expr {
+        Node::Expr(&hir::Expr {
             node: hir::ExprKind::Closure(.., gen),
             ..
         }) => {
@@ -1239,16 +1238,16 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
             tcx.mk_closure(def_id, substs)
         }
 
-        NodeAnonConst(_) => match tcx.hir.get(tcx.hir.get_parent_node(node_id)) {
-            NodeTy(&hir::Ty {
+        Node::AnonConst(_) => match tcx.hir.get(tcx.hir.get_parent_node(node_id)) {
+            Node::Ty(&hir::Ty {
                 node: hir::TyKind::Array(_, ref constant),
                 ..
             })
-            | NodeTy(&hir::Ty {
+            | Node::Ty(&hir::Ty {
                 node: hir::TyKind::Typeof(ref constant),
                 ..
             })
-            | NodeExpr(&hir::Expr {
+            | Node::Expr(&hir::Expr {
                 node: ExprKind::Repeat(_, ref constant),
                 ..
             }) if constant.id == node_id =>
@@ -1256,7 +1255,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
                 tcx.types.usize
             }
 
-            NodeVariant(&Spanned {
+            Node::Variant(&Spanned {
                 node:
                     VariantKind {
                         disr_expr: Some(ref e),
@@ -1276,7 +1275,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
             }
         },
 
-        NodeGenericParam(param) => match param.kind {
+        Node::GenericParam(param) => match param.kind {
             hir::GenericParamKind::Type {
                 default: Some(ref ty),
                 ..
@@ -1294,7 +1293,6 @@ fn find_existential_constraints<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     def_id: DefId,
 ) -> ty::Ty<'tcx> {
-    use rustc::hir::map::*;
     use rustc::hir::*;
 
     struct ConstraintLocator<'a, 'tcx: 'a> {
@@ -1374,9 +1372,9 @@ fn find_existential_constraints<'a, 'tcx>(
     } else {
         trace!("parent: {:?}", tcx.hir.get(parent));
         match tcx.hir.get(parent) {
-            NodeItem(ref it) => intravisit::walk_item(&mut locator, it),
-            NodeImplItem(ref it) => intravisit::walk_impl_item(&mut locator, it),
-            NodeTraitItem(ref it) => intravisit::walk_trait_item(&mut locator, it),
+            Node::Item(ref it) => intravisit::walk_item(&mut locator, it),
+            Node::ImplItem(ref it) => intravisit::walk_impl_item(&mut locator, it),
+            Node::TraitItem(ref it) => intravisit::walk_trait_item(&mut locator, it),
             other => bug!(
                 "{:?} is not a valid parent of an existential type item",
                 other
@@ -1394,29 +1392,29 @@ fn find_existential_constraints<'a, 'tcx>(
 }
 
 fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::PolyFnSig<'tcx> {
-    use rustc::hir::map::*;
     use rustc::hir::*;
+    use rustc::hir::Node::*;
 
     let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
 
     let icx = ItemCtxt::new(tcx, def_id);
 
     match tcx.hir.get(node_id) {
-        NodeTraitItem(hir::TraitItem {
+        TraitItem(hir::TraitItem {
             node: TraitItemKind::Method(sig, _),
             ..
         })
-        | NodeImplItem(hir::ImplItem {
+        | ImplItem(hir::ImplItem {
             node: ImplItemKind::Method(sig, _),
             ..
         }) => AstConv::ty_of_fn(&icx, sig.header.unsafety, sig.header.abi, &sig.decl),
 
-        NodeItem(hir::Item {
+        Item(hir::Item {
             node: ItemKind::Fn(decl, header, _, _),
             ..
         }) => AstConv::ty_of_fn(&icx, header.unsafety, header.abi, decl),
 
-        NodeForeignItem(&hir::ForeignItem {
+        ForeignItem(&hir::ForeignItem {
             node: ForeignItemKind::Fn(ref fn_decl, _, _),
             ..
         }) => {
@@ -1424,8 +1422,8 @@ fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::PolyFnSig
             compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi)
         }
 
-        NodeStructCtor(&VariantData::Tuple(ref fields, _))
-        | NodeVariant(&Spanned {
+        StructCtor(&VariantData::Tuple(ref fields, _))
+        | Variant(&Spanned {
             node:
                 hir::VariantKind {
                     data: VariantData::Tuple(ref fields, _),
@@ -1446,7 +1444,7 @@ fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::PolyFnSig
             ))
         }
 
-        NodeExpr(&hir::Expr {
+        Expr(&hir::Expr {
             node: hir::ExprKind::Closure(..),
             ..
         }) => {
@@ -1624,7 +1622,6 @@ fn explicit_predicates_of<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     def_id: DefId,
 ) -> ty::GenericPredicates<'tcx> {
-    use rustc::hir::map::*;
     use rustc::hir::*;
 
     debug!("explicit_predicates_of(def_id={:?})", def_id);
@@ -1641,9 +1638,9 @@ fn explicit_predicates_of<'a, 'tcx>(
     let mut predicates = vec![];
 
     let ast_generics = match node {
-        NodeTraitItem(item) => &item.generics,
+        Node::TraitItem(item) => &item.generics,
 
-        NodeImplItem(item) => match item.node {
+        Node::ImplItem(item) => match item.node {
             ImplItemKind::Existential(ref bounds) => {
                 let substs = Substs::identity_for_item(tcx, def_id);
                 let anon_ty = tcx.mk_anon(def_id, substs);
@@ -1663,7 +1660,7 @@ fn explicit_predicates_of<'a, 'tcx>(
             _ => &item.generics,
         },
 
-        NodeItem(item) => {
+        Node::Item(item) => {
             match item.node {
                 ItemKind::Impl(_, _, defaultness, ref generics, ..) => {
                     if defaultness.is_default() {
@@ -1715,7 +1712,7 @@ fn explicit_predicates_of<'a, 'tcx>(
             }
         }
 
-        NodeForeignItem(item) => match item.node {
+        Node::ForeignItem(item) => match item.node {
             ForeignItemKind::Static(..) => &no_generics,
             ForeignItemKind::Fn(_, _, ref generics) => generics,
             ForeignItemKind::Type => &no_generics,
@@ -1875,7 +1872,7 @@ fn explicit_predicates_of<'a, 'tcx>(
     // before uses of `U`.  This avoids false ambiguity errors
     // in trait checking. See `setup_constraining_predicates`
     // for details.
-    if let NodeItem(&Item {
+    if let Node::Item(&Item {
         node: ItemKind::Impl(..),
         ..
     }) = node
@@ -2025,7 +2022,7 @@ fn compute_sig_of_foreign_fn_decl<'a, 'tcx>(
 
 fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
     match tcx.hir.get_if_local(def_id) {
-        Some(hir_map::NodeForeignItem(..)) => true,
+        Some(Node::ForeignItem(..)) => true,
         Some(_) => false,
         _ => bug!("is_foreign_item applied to non-local def-id {:?}", def_id),
     }
@@ -2281,6 +2278,8 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
                     codegen_fn_attrs.link_section = Some(val);
                 }
             }
+        } else if attr.check_name("link_name") {
+            codegen_fn_attrs.link_name = attr.value_str();
         }
     }
 
@@ -2300,5 +2299,25 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
         }
     }
 
+    // Weak lang items have the same semantics as "std internal" symbols in the
+    // sense that they're preserved through all our LTO passes and only
+    // strippable by the linker.
+    //
+    // Additionally weak lang items have predetermined symbol names.
+    if tcx.is_weak_lang_item(id) {
+        codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
+    }
+    if let Some(name) = weak_lang_items::link_name(&attrs) {
+        codegen_fn_attrs.export_name = Some(name);
+        codegen_fn_attrs.link_name = Some(name);
+    }
+
+    // Internal symbols to the standard library all have no_mangle semantics in
+    // that they have defined symbol names present in the function name. This
+    // also applies to weak symbols where they all have known symbol names.
+    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
+        codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
+    }
+
     codegen_fn_attrs
 }
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 2239154cbb7..f465ff4d621 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -76,6 +76,7 @@ This API is completely unstable and subject to change.
 #![feature(crate_visibility_modifier)]
 #![feature(exhaustive_patterns)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(quote)]
 #![feature(refcell_replace_swap)]
 #![feature(rustc_diagnostic_macros)]
@@ -95,6 +96,7 @@ extern crate rustc_platform_intrinsics as intrinsics;
 extern crate rustc_data_structures;
 extern crate rustc_errors as errors;
 extern crate rustc_target;
+extern crate smallvec;
 
 use rustc::hir;
 use rustc::lint;
@@ -102,7 +104,7 @@ use rustc::middle;
 use rustc::session;
 use rustc::util;
 
-use hir::map as hir_map;
+use hir::Node;
 use rustc::infer::InferOk;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt};
@@ -186,7 +188,7 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     match main_t.sty {
         ty::FnDef(..) => {
             match tcx.hir.find(main_id) {
-                Some(hir_map::NodeItem(it)) => {
+                Some(Node::Item(it)) => {
                     match it.node {
                         hir::ItemKind::Fn(.., ref generics, _) => {
                             let mut error = false;
@@ -258,7 +260,7 @@ fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     match start_t.sty {
         ty::FnDef(..) => {
             match tcx.hir.find(start_id) {
-                Some(hir_map::NodeItem(it)) => {
+                Some(Node::Item(it)) => {
                     match it.node {
                         hir::ItemKind::Fn(.., ref generics, _) => {
                             let mut error = false;
diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs
index ec36fa0fbc1..092e4d62e2e 100644
--- a/src/librustc_typeck/outlives/implicit_infer.rs
+++ b/src/librustc_typeck/outlives/implicit_infer.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use rustc::hir;
+use hir::Node;
 use rustc::hir::def_id::DefId;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::ty::subst::{Kind, Subst, UnpackedKind};
@@ -65,13 +66,12 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> {
 
         debug!("InferVisitor::visit_item(item={:?})", item_did);
 
-        let node_id = self
-            .tcx
+        let node_id = self.tcx
             .hir
             .as_local_node_id(item_did)
             .expect("expected local def-id");
         let item = match self.tcx.hir.get(node_id) {
-            hir::map::NodeItem(item) => item,
+            Node::Item(item) => item,
             _ => bug!(),
         };
 
@@ -108,8 +108,7 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> {
         // Therefore mark `predicates_added` as true and which will ensure
         // we walk the crates again and re-calculate predicates for all
         // items.
-        let item_predicates_len: usize = self
-            .global_inferred_outlives
+        let item_predicates_len: usize = self.global_inferred_outlives
             .get(&item_did)
             .map(|p| p.len())
             .unwrap_or(0);
@@ -191,7 +190,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
                     substs,
                     required_predicates,
                     explicit_map,
-                    false,
+                    IgnoreSelfTy(false),
                 );
             }
 
@@ -199,22 +198,29 @@ fn insert_required_predicates_to_be_wf<'tcx>(
                 // This corresponds to `dyn Trait<..>`. In this case, we should
                 // use the explicit predicates as well.
 
-                // We are passing type `ty` as a placeholder value with the function
-                // `with_self_ty`, since there is no concrete type `Self` for a
-                // `dyn Trait` at this stage. Therefore when checking explicit
-                // predicates in `check_explicit_predicates` we need to ignore
-                // checking the explicit_map for Self type.
                 debug!("Dynamic");
                 debug!("field_ty = {}", &field_ty);
                 debug!("ty in field = {}", &ty);
                 if let Some(ex_trait_ref) = obj.principal() {
+                    // Here, we are passing the type `usize` as a
+                    // placeholder value with the function
+                    // `with_self_ty`, since there is no concrete type
+                    // `Self` for a `dyn Trait` at this
+                    // stage. Therefore when checking explicit
+                    // predicates in `check_explicit_predicates` we
+                    // need to ignore checking the explicit_map for
+                    // Self type.
+                    let substs = ex_trait_ref
+                        .with_self_ty(tcx, tcx.types.usize)
+                        .skip_binder()
+                        .substs;
                     check_explicit_predicates(
                         tcx,
                         &ex_trait_ref.skip_binder().def_id,
-                        ex_trait_ref.with_self_ty(tcx, ty).skip_binder().substs,
+                        substs,
                         required_predicates,
                         explicit_map,
-                        true,
+                        IgnoreSelfTy(true),
                     );
                 }
             }
@@ -229,7 +235,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
                     obj.substs,
                     required_predicates,
                     explicit_map,
-                    false,
+                    IgnoreSelfTy(false),
                 );
             }
 
@@ -238,6 +244,8 @@ fn insert_required_predicates_to_be_wf<'tcx>(
     }
 }
 
+pub struct IgnoreSelfTy(bool);
+
 /// We also have to check the explicit predicates
 /// declared on the type.
 ///
@@ -259,7 +267,7 @@ pub fn check_explicit_predicates<'tcx>(
     substs: &[Kind<'tcx>],
     required_predicates: &mut RequiredPredicates<'tcx>,
     explicit_map: &mut ExplicitPredicatesMap<'tcx>,
-    ignore_self_ty: bool,
+    ignore_self_ty: IgnoreSelfTy,
 ) {
     debug!("def_id = {:?}", &def_id);
     debug!("substs = {:?}", &substs);
@@ -297,7 +305,7 @@ pub fn check_explicit_predicates<'tcx>(
         // to apply the substs, and not filter this predicate, we might then falsely
         // conclude that e.g. `X: 'x` was a reasonable inferred requirement.
         if let UnpackedKind::Type(ty) = outlives_predicate.0.unpack() {
-            if ty.is_self() && ignore_self_ty {
+            if ty.is_self() && ignore_self_ty.0 {
                 debug!("skipping self ty = {:?}", &ty);
                 continue;
             }
@@ -307,5 +315,4 @@ pub fn check_explicit_predicates<'tcx>(
         debug!("predicate = {:?}", &predicate);
         insert_outlives_predicate(tcx, predicate.0.into(), predicate.1, required_predicates);
     }
-    // }
 }
diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs
index 74ef62e0c63..63a424936eb 100644
--- a/src/librustc_typeck/outlives/mod.rs
+++ b/src/librustc_typeck/outlives/mod.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use hir::map as hir_map;
+use hir::Node;
 use rustc::hir;
 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc::ty::query::Providers;
@@ -40,7 +40,7 @@ fn inferred_outlives_of<'a, 'tcx>(
         .expect("expected local def-id");
 
     match tcx.hir.get(id) {
-        hir_map::NodeItem(item) => match item.node {
+        Node::Item(item) => match item.node {
             hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..) => {
                 let crate_map = tcx.inferred_outlives_crate(LOCAL_CRATE);
 
@@ -59,8 +59,7 @@ fn inferred_outlives_of<'a, 'tcx>(
                             ty::Predicate::TypeOutlives(p) => p.to_string(),
 
                             err => bug!("unexpected predicate {:?}", err),
-                        })
-                        .collect();
+                        }).collect();
                     pred.sort();
 
                     let span = tcx.def_span(item_def_id);
@@ -117,11 +116,9 @@ fn inferred_outlives_crate<'tcx>(
                             ty::Binder::bind(ty::OutlivesPredicate(region1, region2)),
                         ),
                     },
-                )
-                .collect();
+                ).collect();
             (def_id, Lrc::new(vec))
-        })
-        .collect();
+        }).collect();
 
     let empty_predicate = Lrc::new(Vec::new());
 
diff --git a/src/librustc_typeck/variance/mod.rs b/src/librustc_typeck/variance/mod.rs
index 3d70550c1df..aaa0fd8e099 100644
--- a/src/librustc_typeck/variance/mod.rs
+++ b/src/librustc_typeck/variance/mod.rs
@@ -15,6 +15,7 @@
 
 use arena;
 use rustc::hir;
+use hir::Node;
 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc::ty::{self, CrateVariancesMap, TyCtxt};
 use rustc::ty::query::Providers;
@@ -61,7 +62,7 @@ fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId)
         span_bug!(tcx.hir.span(id), "asked to compute variance for wrong kind of item")
     };
     match tcx.hir.get(id) {
-        hir::map::NodeItem(item) => match item.node {
+        Node::Item(item) => match item.node {
             hir::ItemKind::Enum(..) |
             hir::ItemKind::Struct(..) |
             hir::ItemKind::Union(..) |
@@ -70,25 +71,25 @@ fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId)
             _ => unsupported()
         },
 
-        hir::map::NodeTraitItem(item) => match item.node {
+        Node::TraitItem(item) => match item.node {
             hir::TraitItemKind::Method(..) => {}
 
             _ => unsupported()
         },
 
-        hir::map::NodeImplItem(item) => match item.node {
+        Node::ImplItem(item) => match item.node {
             hir::ImplItemKind::Method(..) => {}
 
             _ => unsupported()
         },
 
-        hir::map::NodeForeignItem(item) => match item.node {
+        Node::ForeignItem(item) => match item.node {
             hir::ForeignItemKind::Fn(..) => {}
 
             _ => unsupported()
         },
 
-        hir::map::NodeVariant(_) | hir::map::NodeStructCtor(_) => {}
+        Node::Variant(_) | Node::StructCtor(_) => {}
 
         _ => unsupported()
     }
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 5e78e8fe569..88c25567d29 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -223,7 +223,25 @@
             }
         }
     }
-    highlightSourceLines(null);
+
+    function expandSection(id) {
+        var elem = document.getElementById(id);
+        if (elem && isHidden(elem)) {
+            var h3 = elem.parentNode.previousSibling;
+            if (h3 && h3.tagName !== 'H3') {
+                h3 = h3.previousSibling; // skip div.docblock
+            }
+
+            if (h3) {
+                var collapses = h3.getElementsByClassName("collapse-toggle");
+                if (collapses.length > 0) {
+                    // The element is not visible, we need to make it appear!
+                    collapseDocs(collapses[0], "show");
+                }
+            }
+        }
+    }
+
     window.onhashchange = highlightSourceLines;
 
     // Gets the human-readable string for the virtual-key code of the
@@ -317,6 +335,15 @@
         }
     }
 
+    function findParentElement(elem, tagName) {
+        do {
+            if (elem && elem.tagName === tagName) {
+                return elem;
+            }
+        } while (elem = elem.parentNode);
+        return null;
+    }
+
     document.onkeypress = handleShortcut;
     document.onkeydown = handleShortcut;
     document.onclick = function(ev) {
@@ -354,6 +381,13 @@
         } else if (!hasClass(document.getElementById("help"), "hidden")) {
             addClass(document.getElementById("help"), "hidden");
             removeClass(document.body, "blur");
+        } else {
+            // Making a collapsed element visible on onhashchange seems
+            // too late
+            var a = findParentElement(ev.target, 'A');
+            if (a && a.hash) {
+                expandSection(a.hash.replace(/^#/, ''));
+            }
         }
     };
 
@@ -2213,21 +2247,7 @@
     autoCollapse(getPageId(), getCurrentValue("rustdoc-collapse") === "true");
 
     if (window.location.hash && window.location.hash.length > 0) {
-        var hash = getPageId();
-        if (hash !== null) {
-            var elem = document.getElementById(hash);
-            if (elem && elem.offsetParent === null) {
-                if (elem.parentNode && elem.parentNode.previousSibling) {
-                    var collapses = elem.parentNode
-                                        .previousSibling
-                                        .getElementsByClassName("collapse-toggle");
-                    if (collapses.length > 0) {
-                        // The element is not visible, we need to make it appear!
-                        collapseDocs(collapses[0], "show");
-                    }
-                }
-            }
-        }
+        expandSection(window.location.hash.replace(/^#/, ''));
     }
 }());
 
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index 57a111daa89..ffe6a40b369 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -497,6 +497,19 @@ h4 > code, h3 > code, .invisible > code {
 	font-size: 90%;
 }
 
+.content .stability {
+	position: relative;
+	margin-left: 33px;
+	margin-top: -13px;
+}
+.content .stability::before {
+	content: '˪';
+	font-size: 30px;
+	position: absolute;
+	top: -9px;
+	left: -13px;
+}
+
 nav {
 	border-bottom: 1px solid;
 	padding-bottom: 10px;
@@ -545,10 +558,8 @@ a {
 	left: -5px;
 }
 .small-section-header > .anchor {
-	left: -20px;
-}
-.small-section-header > .anchor:not(.field) {
 	left: -28px;
+	padding-right: 10px; /* avoid gap that causes hover to disappear */
 }
 .anchor:before {
 	content: '\2002\00a7\2002';
@@ -745,6 +756,7 @@ a.test-arrow:hover{
 .section-header:hover a:before {
 	position: absolute;
 	left: -25px;
+	padding-right: 10px; /* avoid gap that causes hover to disappear */
 	content: '\2002\00a7\2002';
 }
 
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index db19860d223..279151eb26d 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -17,6 +17,7 @@
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(set_stdio)]
 #![feature(slice_sort_by_cached_key)]
 #![feature(test)]
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 15a94b8adfc..451e24d6c0d 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -18,7 +18,7 @@ use syntax::attr;
 use syntax::source_map::Spanned;
 use syntax_pos::{self, Span};
 
-use rustc::hir::map as hir_map;
+use rustc::hir::Node;
 use rustc::hir::def::Def;
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::middle::privacy::AccessLevel;
@@ -295,7 +295,7 @@ impl<'a, 'tcx, 'rcx, 'cstore> RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> {
         if !self.view_item_stack.insert(def_node_id) { return false }
 
         let ret = match tcx.hir.get(def_node_id) {
-            hir_map::NodeItem(&hir::Item { node: hir::ItemKind::Mod(ref m), .. }) if glob => {
+            Node::Item(&hir::Item { node: hir::ItemKind::Mod(ref m), .. }) if glob => {
                 let prev = mem::replace(&mut self.inlining, true);
                 for i in &m.item_ids {
                     let i = self.cx.tcx.hir.expect_item(i.id);
@@ -304,13 +304,13 @@ impl<'a, 'tcx, 'rcx, 'cstore> RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> {
                 self.inlining = prev;
                 true
             }
-            hir_map::NodeItem(it) if !glob => {
+            Node::Item(it) if !glob => {
                 let prev = mem::replace(&mut self.inlining, true);
                 self.visit_item(it, renamed, om);
                 self.inlining = prev;
                 true
             }
-            hir_map::NodeForeignItem(it) if !glob => {
+            Node::ForeignItem(it) if !glob => {
                 // generate a fresh `extern {}` block if we want to inline a foreign item.
                 om.foreigns.push(hir::ForeignMod {
                     abi: tcx.hir.get_foreign_abi(it.id),
diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs
index 1f6ee3d867b..e87c2793ee8 100644
--- a/src/libserialize/lib.rs
+++ b/src/libserialize/lib.rs
@@ -25,6 +25,7 @@ Core encoding and decoding interfaces.
 #![feature(specialization)]
 #![feature(never_type)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![cfg_attr(test, feature(test))]
 
 pub use self::serialize::{Decoder, Encoder, Decodable, Encodable};
diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs
index b9aba1e9cab..6753ed4a3df 100644
--- a/src/libstd/alloc.rs
+++ b/src/libstd/alloc.rs
@@ -150,23 +150,23 @@ pub mod __default_lib_allocator {
     // linkage directives are provided as part of the current compiler allocator
     // ABI
 
-    #[no_mangle]
     #[rustc_std_internal_symbol]
+    #[cfg_attr(stage0, no_mangle)]
     pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
         let layout = Layout::from_size_align_unchecked(size, align);
         System.alloc(layout)
     }
 
-    #[no_mangle]
     #[rustc_std_internal_symbol]
+    #[cfg_attr(stage0, no_mangle)]
     pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
                                        size: usize,
                                        align: usize) {
         System.dealloc(ptr, Layout::from_size_align_unchecked(size, align))
     }
 
-    #[no_mangle]
     #[rustc_std_internal_symbol]
+    #[cfg_attr(stage0, no_mangle)]
     pub unsafe extern fn __rdl_realloc(ptr: *mut u8,
                                        old_size: usize,
                                        align: usize,
@@ -175,8 +175,8 @@ pub mod __default_lib_allocator {
         System.realloc(ptr, old_layout, new_size)
     }
 
-    #[no_mangle]
     #[rustc_std_internal_symbol]
+    #[cfg_attr(stage0, no_mangle)]
     pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
         let layout = Layout::from_size_align_unchecked(size, align);
         System.alloc_zeroed(layout)
diff --git a/src/libstd/future.rs b/src/libstd/future.rs
index cadb5c0ba5d..d9657f691c7 100644
--- a/src/libstd/future.rs
+++ b/src/libstd/future.rs
@@ -12,7 +12,7 @@
 
 use core::cell::Cell;
 use core::marker::Unpin;
-use core::mem::PinMut;
+use core::pin::PinMut;
 use core::option::Option;
 use core::ptr::NonNull;
 use core::task::{self, Poll};
diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs
index 4f6bda6cfe3..d70cf132b3c 100644
--- a/src/libstd/keyword_docs.rs
+++ b/src/libstd/keyword_docs.rs
@@ -56,3 +56,24 @@ mod fn_keyword { }
 ///
 /// [book]: https://doc.rust-lang.org/book/second-edition/ch03-01-variables-and-mutability.html
 mod let_keyword { }
+
+#[doc(keyword = "struct")]
+//
+/// The `struct` keyword.
+///
+/// The `struct` keyword is used to define a struct type.
+///
+/// Example:
+///
+/// ```
+/// struct Foo {
+///     field1: u32,
+///     field2: String,
+/// }
+/// ```
+///
+/// There are different kinds of structs. For more information, take a look at the
+/// [Rust Book][book].
+///
+/// [book]: https://doc.rust-lang.org/book/second-edition/ch05-01-defining-structs.html
+mod struct_keyword { }
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index f8b425bc785..310475d31fd 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -273,6 +273,7 @@
 #![feature(needs_panic_runtime)]
 #![feature(never_type)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(exhaustive_patterns)]
 #![feature(on_unimplemented)]
 #![feature(optin_builtin_traits)]
@@ -434,6 +435,8 @@ pub use alloc_crate::borrow;
 pub use alloc_crate::fmt;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use alloc_crate::format;
+#[unstable(feature = "pin", issue = "49150")]
+pub use alloc_crate::pin;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use alloc_crate::slice;
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index f15494c5fd7..6945a41a5e7 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -230,7 +230,7 @@ macro_rules! await {
         loop {
             if let $crate::task::Poll::Ready(x) =
                 $crate::future::poll_in_task_cx(unsafe {
-                    $crate::mem::PinMut::new_unchecked(&mut pinned)
+                    $crate::pin::PinMut::new_unchecked(&mut pinned)
                 })
             {
                 break x;
diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs
index b8c1c4f9e68..47547aedcbd 100644
--- a/src/libstd/panic.rs
+++ b/src/libstd/panic.rs
@@ -16,7 +16,7 @@ use any::Any;
 use cell::UnsafeCell;
 use fmt;
 use future::Future;
-use mem::PinMut;
+use pin::PinMut;
 use ops::{Deref, DerefMut};
 use panicking;
 use ptr::{Unique, NonNull};
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index 53babd449a9..58ac4e94408 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -626,6 +626,14 @@ impl Command {
 
     /// Sets the working directory for the child process.
     ///
+    /// # Platform-specific behavior
+    ///
+    /// If the program path is relative (e.g. `"./script.sh"`), it's ambiguous
+    /// whether it should be interpreted relative to the parent's working
+    /// directory or relative to `current_dir`. The behavior in this case is
+    /// platform specific and unstable, and it's recommended to use
+    /// [`canonicalize`] to get an absolute program path instead.
+    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -638,6 +646,8 @@ impl Command {
     ///         .spawn()
     ///         .expect("ls command failed to start");
     /// ```
+    ///
+    /// [`canonicalize`]: ../fs/fn.canonicalize.html
     #[stable(feature = "process", since = "1.0.0")]
     pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Command {
         self.inner.cwd(dir.as_ref().as_ref());
diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs
index f64cae810b9..70de4a6f2b6 100644
--- a/src/libstd/sys/windows/backtrace/mod.rs
+++ b/src/libstd/sys/windows/backtrace/mod.rs
@@ -152,7 +152,14 @@ type StackWalk64Fn = unsafe extern "system" fn(
 trait StackWalker {
     type Item: StackFrame;
 
-    fn walk(&self, c::DWORD, c::HANDLE, c::HANDLE, &mut Self::Item, &mut c::CONTEXT) -> c::BOOL;
+    fn walk(
+        &self,
+        _: c::DWORD,
+        _: c::HANDLE,
+        _: c::HANDLE,
+        _: &mut Self::Item,
+        _: &mut c::CONTEXT
+    ) -> c::BOOL;
 }
 
 impl StackWalker for StackWalkExFn {
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 2aaab6aaa16..c8ec273a03f 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -22,6 +22,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(macro_at_most_once_rep)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(rustc_attrs)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(slice_sort_by_cached_key)]
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index be63c8f060a..e78e1afe3a4 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub use self::AnnNode::*;
-
 use rustc_target::spec::abi::{self, Abi};
 use ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
 use ast::{SelfKind, GenericBound, TraitBoundModifier};
@@ -36,13 +34,13 @@ use std::iter::Peekable;
 use std::vec;
 
 pub enum AnnNode<'a> {
-    NodeIdent(&'a ast::Ident),
-    NodeName(&'a ast::Name),
-    NodeBlock(&'a ast::Block),
-    NodeItem(&'a ast::Item),
-    NodeSubItem(ast::NodeId),
-    NodeExpr(&'a ast::Expr),
-    NodePat(&'a ast::Pat),
+    Ident(&'a ast::Ident),
+    Name(&'a ast::Name),
+    Block(&'a ast::Block),
+    Item(&'a ast::Item),
+    SubItem(ast::NodeId),
+    Expr(&'a ast::Expr),
+    Pat(&'a ast::Pat),
 }
 
 pub trait PpAnn {
@@ -1196,7 +1194,7 @@ impl<'a> State<'a> {
         self.hardbreak_if_not_bol()?;
         self.maybe_print_comment(item.span.lo())?;
         self.print_outer_attributes(&item.attrs)?;
-        self.ann.pre(self, NodeItem(item))?;
+        self.ann.pre(self, AnnNode::Item(item))?;
         match item.node {
             ast::ItemKind::ExternCrate(orig_name) => {
                 self.head(&visibility_qualified(&item.vis, "extern crate"))?;
@@ -1439,7 +1437,7 @@ impl<'a> State<'a> {
                 self.end()?;
             }
         }
-        self.ann.post(self, NodeItem(item))
+        self.ann.post(self, AnnNode::Item(item))
     }
 
     fn print_trait_ref(&mut self, t: &ast::TraitRef) -> io::Result<()> {
@@ -1596,7 +1594,7 @@ impl<'a> State<'a> {
 
     pub fn print_trait_item(&mut self, ti: &ast::TraitItem)
                             -> io::Result<()> {
-        self.ann.pre(self, NodeSubItem(ti.id))?;
+        self.ann.pre(self, AnnNode::SubItem(ti.id))?;
         self.hardbreak_if_not_bol()?;
         self.maybe_print_comment(ti.span.lo())?;
         self.print_outer_attributes(&ti.attrs)?;
@@ -1638,11 +1636,11 @@ impl<'a> State<'a> {
                 }
             }
         }
-        self.ann.post(self, NodeSubItem(ti.id))
+        self.ann.post(self, AnnNode::SubItem(ti.id))
     }
 
     pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> io::Result<()> {
-        self.ann.pre(self, NodeSubItem(ii.id))?;
+        self.ann.pre(self, AnnNode::SubItem(ii.id))?;
         self.hardbreak_if_not_bol()?;
         self.maybe_print_comment(ii.span.lo())?;
         self.print_outer_attributes(&ii.attrs)?;
@@ -1672,7 +1670,7 @@ impl<'a> State<'a> {
                 }
             }
         }
-        self.ann.post(self, NodeSubItem(ii.id))
+        self.ann.post(self, AnnNode::SubItem(ii.id))
     }
 
     pub fn print_stmt(&mut self, st: &ast::Stmt) -> io::Result<()> {
@@ -1756,7 +1754,7 @@ impl<'a> State<'a> {
             BlockCheckMode::Default => ()
         }
         self.maybe_print_comment(blk.span.lo())?;
-        self.ann.pre(self, NodeBlock(blk))?;
+        self.ann.pre(self, AnnNode::Block(blk))?;
         self.bopen()?;
 
         self.print_inner_attributes(attrs)?;
@@ -1774,7 +1772,7 @@ impl<'a> State<'a> {
         }
 
         self.bclose_maybe_open(blk.span, indented, close_box)?;
-        self.ann.post(self, NodeBlock(blk))
+        self.ann.post(self, AnnNode::Block(blk))
     }
 
     fn print_else(&mut self, els: Option<&ast::Expr>) -> io::Result<()> {
@@ -2065,7 +2063,7 @@ impl<'a> State<'a> {
         }
 
         self.ibox(INDENT_UNIT)?;
-        self.ann.pre(self, NodeExpr(expr))?;
+        self.ann.pre(self, AnnNode::Expr(expr))?;
         match expr.node {
             ast::ExprKind::Box(ref expr) => {
                 self.word_space("box")?;
@@ -2385,7 +2383,7 @@ impl<'a> State<'a> {
                 self.print_block_with_attrs(blk, attrs)?
             }
         }
-        self.ann.post(self, NodeExpr(expr))?;
+        self.ann.post(self, AnnNode::Expr(expr))?;
         self.end()
     }
 
@@ -2404,7 +2402,7 @@ impl<'a> State<'a> {
         } else {
             self.s.word(&ident.as_str())?;
         }
-        self.ann.post(self, NodeIdent(&ident))
+        self.ann.post(self, AnnNode::Ident(&ident))
     }
 
     pub fn print_usize(&mut self, i: usize) -> io::Result<()> {
@@ -2413,7 +2411,7 @@ impl<'a> State<'a> {
 
     pub fn print_name(&mut self, name: ast::Name) -> io::Result<()> {
         self.s.word(&name.as_str())?;
-        self.ann.post(self, NodeName(&name))
+        self.ann.post(self, AnnNode::Name(&name))
     }
 
     pub fn print_for_decl(&mut self, loc: &ast::Local,
@@ -2537,7 +2535,7 @@ impl<'a> State<'a> {
 
     pub fn print_pat(&mut self, pat: &ast::Pat) -> io::Result<()> {
         self.maybe_print_comment(pat.span.lo())?;
-        self.ann.pre(self, NodePat(pat))?;
+        self.ann.pre(self, AnnNode::Pat(pat))?;
         /* Pat isn't normalized, but the beauty of it
          is that it doesn't matter */
         match pat.node {
@@ -2675,7 +2673,7 @@ impl<'a> State<'a> {
             }
             PatKind::Mac(ref m) => self.print_mac(m)?,
         }
-        self.ann.post(self, NodePat(pat))
+        self.ann.post(self, AnnNode::Pat(pat))
     }
 
     fn print_pats(&mut self, pats: &[P<ast::Pat>]) -> io::Result<()> {
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index 790a42007fb..84436b4e4ea 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -17,6 +17,7 @@
 #![feature(proc_macro_internals)]
 #![feature(decl_macro)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(str_escape)]
 
 #![feature(rustc_diagnostic_macros)]
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index bd70344b018..a493ea4f565 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -22,6 +22,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(custom_attribute)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(non_exhaustive)]
 #![feature(optin_builtin_traits)]
 #![feature(specialization)]
diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs
index a49fd67639d..df90be63937 100644
--- a/src/libterm/lib.rs
+++ b/src/libterm/lib.rs
@@ -51,6 +51,7 @@
 // Handle rustfmt skips
 #![feature(custom_attribute)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![allow(unused_attributes)]
 
 use std::io::prelude::*;
diff --git a/src/libtest/formatters/terse.rs b/src/libtest/formatters/terse.rs
index 22a06b9f605..6f7dfee53fa 100644
--- a/src/libtest/formatters/terse.rs
+++ b/src/libtest/formatters/terse.rs
@@ -18,6 +18,7 @@ pub(crate) struct TerseFormatter<T> {
     max_name_len: usize,
 
     test_count: usize,
+    total_test_count: usize,
 }
 
 impl<T: Write> TerseFormatter<T> {
@@ -33,6 +34,7 @@ impl<T: Write> TerseFormatter<T> {
             max_name_len,
             is_multithreaded,
             test_count: 0,
+            total_test_count: 0, // initialized later, when write_run_start is called
         }
     }
 
@@ -66,7 +68,8 @@ impl<T: Write> TerseFormatter<T> {
             // we insert a new line every 100 dots in order to flush the
             // screen when dealing with line-buffered output (e.g. piping to
             // `stamp` in the rust CI).
-            self.write_plain("\n")?;
+            let out = format!(" {}/{}\n", self.test_count+1, self.total_test_count);
+            self.write_plain(&out)?;
         }
 
         self.test_count += 1;
@@ -160,6 +163,7 @@ impl<T: Write> TerseFormatter<T> {
 
 impl<T: Write> OutputFormatter for TerseFormatter<T> {
     fn write_run_start(&mut self, test_count: usize) -> io::Result<()> {
+        self.total_test_count = test_count;
         let noun = if test_count != 1 { "tests" } else { "test" };
         self.write_plain(&format!("\nrunning {} {}\n", test_count, noun))
     }
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index 060ea1ea9b1..29d7cfd2a3a 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -36,6 +36,7 @@
 #![feature(fnbox)]
 #![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc))]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(set_stdio)]
 #![feature(panic_unwind)]
 #![feature(staged_api)]
diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs
index 424a7e3d009..3b94dc238d9 100644
--- a/src/libunwind/lib.rs
+++ b/src/libunwind/lib.rs
@@ -14,6 +14,7 @@
 #![feature(cfg_target_vendor)]
 #![feature(link_cfg)]
 #![cfg_attr(not(stage0), feature(nll))]
+#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
 #![feature(staged_api)]
 #![feature(unwind_attributes)]
 #![feature(static_nobundle)]
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index 46825efeee2..09befdaae37 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -359,6 +359,12 @@ extern "C" void LLVMRustPrintTargetFeatures(LLVMTargetMachineRef) {
 }
 #endif
 
+extern "C" const char* LLVMRustGetHostCPUName(size_t *len) {
+  StringRef Name = sys::getHostCPUName();
+  *len = Name.size();
+  return Name.data();
+}
+
 extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     const char *TripleStr, const char *CPU, const char *Feature,
     LLVMRustCodeModel RustCM, LLVMRustRelocMode RustReloc,
@@ -381,11 +387,6 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     return nullptr;
   }
 
-  StringRef RealCPU = CPU;
-  if (RealCPU == "native") {
-    RealCPU = sys::getHostCPUName();
-  }
-
   TargetOptions Options;
 
   Options.FloatABIType = FloatABI::Default;
@@ -417,7 +418,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
   if (RustCM != LLVMRustCodeModel::None)
     CM = fromRust(RustCM);
   TargetMachine *TM = TheTarget->createTargetMachine(
-      Trip.getTriple(), RealCPU, Feature, Options, RM, CM, OptLevel);
+      Trip.getTriple(), CPU, Feature, Options, RM, CM, OptLevel);
   return wrap(TM);
 }
 
diff --git a/src/test/mir-opt/nll/named-lifetimes-basic.rs b/src/test/mir-opt/nll/named-lifetimes-basic.rs
index adc0249a40c..ffc5603bb16 100644
--- a/src/test/mir-opt/nll/named-lifetimes-basic.rs
+++ b/src/test/mir-opt/nll/named-lifetimes-basic.rs
@@ -34,15 +34,15 @@ fn main() {
 // | '_#4r    | Local    | ['_#4r]
 // |
 // | Inferred Region Values
-// | '_#0r    | U0 | {bb0[0..=127], '_#0r}
-// | '_#1r    | U0 | {bb0[0..=127], '_#1r}
-// | '_#2r    | U0 | {bb0[0..=127], '_#2r}
-// | '_#3r    | U0 | {bb0[0..=127], '_#3r}
-// | '_#4r    | U0 | {bb0[0..=127], '_#4r}
-// | '_#5r    | U0 | {bb0[0..=127], '_#1r}
-// | '_#6r    | U0 | {bb0[0..=127], '_#2r}
-// | '_#7r    | U0 | {bb0[0..=127], '_#1r}
-// | '_#8r    | U0 | {bb0[0..=127], '_#3r}
+// | '_#0r    | U0 | {bb0[0..=1], '_#0r}
+// | '_#1r    | U0 | {bb0[0..=1], '_#1r}
+// | '_#2r    | U0 | {bb0[0..=1], '_#2r}
+// | '_#3r    | U0 | {bb0[0..=1], '_#3r}
+// | '_#4r    | U0 | {bb0[0..=1], '_#4r}
+// | '_#5r    | U0 | {bb0[0..=1], '_#1r}
+// | '_#6r    | U0 | {bb0[0..=1], '_#2r}
+// | '_#7r    | U0 | {bb0[0..=1], '_#1r}
+// | '_#8r    | U0 | {bb0[0..=1], '_#3r}
 // |
 // ...
 // fn use_x(_1: &'_#5r mut i32, _2: &'_#6r u32, _3: &'_#7r u32, _4: &'_#8r u32) -> bool {
diff --git a/src/test/run-make-fulldeps/target-cpu-native/Makefile b/src/test/run-make-fulldeps/target-cpu-native/Makefile
index 0c9d93ecb2a..fee41461612 100644
--- a/src/test/run-make-fulldeps/target-cpu-native/Makefile
+++ b/src/test/run-make-fulldeps/target-cpu-native/Makefile
@@ -1,5 +1,20 @@
 -include ../tools.mk
 
-all:
-	$(RUSTC) foo.rs -C target-cpu=native
+# I *really* don't want to deal with a cross-platform way to compare file sizes,
+# tests in `make` sort of are awful
+ifeq ($(TARGET),x86_64-unknown-linux-gnu)
+all: $(TMPDIR)/out.log
+	# Make sure no warnings about "unknown CPU `native`" were emitted
+	if [ "$$(wc -c $(TMPDIR)/out.log | cut -d' ' -f 1)" = "0" ]; then \
+	  echo no warnings generated; \
+	else \
+	  exit 1; \
+	fi
+else
+all: $(TMPDIR)/out.log
+endif
+
+
+$(TMPDIR)/out.log:
+	$(RUSTC) foo.rs -C target-cpu=native 2>&1 | tee $(TMPDIR)/out.log
 	$(call RUN,foo)
diff --git a/src/test/run-make-fulldeps/use-suggestions-rust-2018/Makefile b/src/test/run-make-fulldeps/use-suggestions-rust-2018/Makefile
new file mode 100644
index 00000000000..fc39691c507
--- /dev/null
+++ b/src/test/run-make-fulldeps/use-suggestions-rust-2018/Makefile
@@ -0,0 +1,7 @@
+-include ../tools.mk
+
+all:
+	$(RUSTC) ep-nested-lib.rs
+
+	$(RUSTC) use-suggestions.rs --edition=2018 --extern ep_nested_lib=$(TMPDIR)/libep_nested_lib.rlib 2>&1 | $(CGREP) "use ep_nested_lib::foo::bar::Baz"
+
diff --git a/src/test/run-make-fulldeps/use-suggestions-rust-2018/ep-nested-lib.rs b/src/test/run-make-fulldeps/use-suggestions-rust-2018/ep-nested-lib.rs
new file mode 100644
index 00000000000..c0bce6e3371
--- /dev/null
+++ b/src/test/run-make-fulldeps/use-suggestions-rust-2018/ep-nested-lib.rs
@@ -0,0 +1,17 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "rlib"]
+
+pub mod foo {
+    pub mod bar {
+        pub struct Baz;
+    }
+}
diff --git a/src/test/run-make-fulldeps/use-suggestions-rust-2018/use-suggestions.rs b/src/test/run-make-fulldeps/use-suggestions-rust-2018/use-suggestions.rs
new file mode 100644
index 00000000000..62730a5653f
--- /dev/null
+++ b/src/test/run-make-fulldeps/use-suggestions-rust-2018/use-suggestions.rs
@@ -0,0 +1,13 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    let x = Baz{};
+}
diff --git a/src/test/run-make/wasm-symbols-not-imported/Makefile b/src/test/run-make/wasm-symbols-not-imported/Makefile
new file mode 100644
index 00000000000..773e32a0315
--- /dev/null
+++ b/src/test/run-make/wasm-symbols-not-imported/Makefile
@@ -0,0 +1,16 @@
+-include ../../run-make-fulldeps/tools.mk
+
+ifeq ($(TARGET),wasm32-unknown-unknown)
+all:
+	$(RUSTC) foo.rs --target wasm32-unknown-unknown
+	$(NODE) verify-no-imports.js $(TMPDIR)/foo.wasm
+	$(RUSTC) foo.rs --target wasm32-unknown-unknown -C lto
+	$(NODE) verify-no-imports.js $(TMPDIR)/foo.wasm
+	$(RUSTC) foo.rs --target wasm32-unknown-unknown -O
+	$(NODE) verify-no-imports.js $(TMPDIR)/foo.wasm
+	$(RUSTC) foo.rs --target wasm32-unknown-unknown -O -C lto
+	$(NODE) verify-no-imports.js $(TMPDIR)/foo.wasm
+else
+all:
+endif
+
diff --git a/src/test/run-make/wasm-symbols-not-imported/foo.rs b/src/test/run-make/wasm-symbols-not-imported/foo.rs
new file mode 100644
index 00000000000..156db486a47
--- /dev/null
+++ b/src/test/run-make/wasm-symbols-not-imported/foo.rs
@@ -0,0 +1,26 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "cdylib"]
+
+#![feature(panic_implementation)]
+#![no_std]
+
+use core::panic::PanicInfo;
+
+#[no_mangle]
+pub extern fn foo() {
+    panic!()
+}
+
+#[panic_implementation]
+fn panic(_info: &PanicInfo) -> ! {
+    loop {}
+}
diff --git a/src/test/run-make/wasm-symbols-not-imported/verify-no-imports.js b/src/test/run-make/wasm-symbols-not-imported/verify-no-imports.js
new file mode 100644
index 00000000000..28a98b5f2c2
--- /dev/null
+++ b/src/test/run-make/wasm-symbols-not-imported/verify-no-imports.js
@@ -0,0 +1,20 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+const fs = require('fs');
+const process = require('process');
+const assert = require('assert');
+const buffer = fs.readFileSync(process.argv[2]);
+
+let m = new WebAssembly.Module(buffer);
+let list = WebAssembly.Module.imports(m);
+console.log('imports', list);
+if (list.length !== 0)
+  throw new Error("there are some imports");
diff --git a/src/test/run-pass-fulldeps/compiler-calls.rs b/src/test/run-pass-fulldeps/compiler-calls.rs
index baf9e0d5dc5..6283d054373 100644
--- a/src/test/run-pass-fulldeps/compiler-calls.rs
+++ b/src/test/run-pass-fulldeps/compiler-calls.rs
@@ -92,7 +92,9 @@ fn main() {
         let tc = TestCalls { count: &mut count };
         // we should never get use this filename, but lets make sure they are valid args.
         let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
-        rustc_driver::run_compiler(&args, Box::new(tc), None, None);
+        syntax::with_globals(|| {
+            rustc_driver::run_compiler(&args, Box::new(tc), None, None);
+        });
     }
     assert_eq!(count, 30);
 }
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/issue-40001-plugin.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/issue-40001-plugin.rs
index adcd2d605e3..f525e0f082a 100644
--- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/issue-40001-plugin.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/issue-40001-plugin.rs
@@ -27,6 +27,7 @@ use syntax::symbol::Symbol;
 use rustc::hir;
 use rustc::hir::intravisit;
 use rustc::hir::map as hir_map;
+use hir::Node;
 use rustc::lint::{LateContext, LintPass, LintArray, LateLintPass, LintContext};
 use rustc::ty;
 use syntax::{ast, source_map};
@@ -58,7 +59,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingWhitelistedAttrPass {
                 id: ast::NodeId) {
 
         let item = match cx.tcx.hir.get(id) {
-            hir_map::Node::NodeItem(item) => item,
+            Node::Item(item) => item,
             _ => cx.tcx.hir.expect_item(cx.tcx.hir.get_parent(id)),
         };
 
diff --git a/src/test/run-pass/async-await.rs b/src/test/run-pass/async-await.rs
index 99b8ad83bf6..46f22845907 100644
--- a/src/test/run-pass/async-await.rs
+++ b/src/test/run-pass/async-await.rs
@@ -12,8 +12,8 @@
 
 #![feature(arbitrary_self_types, async_await, await_macro, futures_api, pin)]
 
-use std::boxed::PinBox;
-use std::mem::PinMut;
+use std::pin::PinBox;
+use std::pin::PinMut;
 use std::future::Future;
 use std::sync::{
     Arc,
diff --git a/src/test/run-pass/ctfe/promotion.rs b/src/test/run-pass/ctfe/promotion.rs
index 2d228408254..28b876c308b 100644
--- a/src/test/run-pass/ctfe/promotion.rs
+++ b/src/test/run-pass/ctfe/promotion.rs
@@ -8,10 +8,18 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// compile-flags: -O
+
 fn foo(_: &'static [&'static str]) {}
 fn bar(_: &'static [&'static str; 3]) {}
+fn baz_i32(_: &'static i32) {}
+fn baz_u32(_: &'static u32) {}
 
 fn main() {
     foo(&["a", "b", "c"]);
     bar(&["d", "e", "f"]);
+
+    // make sure that these do not cause trouble despite overflowing
+    baz_u32(&(0-1));
+    baz_i32(&-std::i32::MIN);
 }
diff --git a/src/test/run-pass/futures-api.rs b/src/test/run-pass/futures-api.rs
index 476cb48c0d2..69a04437691 100644
--- a/src/test/run-pass/futures-api.rs
+++ b/src/test/run-pass/futures-api.rs
@@ -11,9 +11,9 @@
 #![feature(arbitrary_self_types, futures_api, pin)]
 #![allow(unused)]
 
-use std::boxed::PinBox;
+use std::pin::PinBox;
 use std::future::Future;
-use std::mem::PinMut;
+use std::pin::PinMut;
 use std::rc::Rc;
 use std::sync::{
     Arc,
diff --git a/src/test/rustdoc-js/pinbox-new.js b/src/test/rustdoc-js/pinbox-new.js
index 061c7b30741..55842dc8e45 100644
--- a/src/test/rustdoc-js/pinbox-new.js
+++ b/src/test/rustdoc-js/pinbox-new.js
@@ -14,7 +14,7 @@ const QUERY = 'pinbox::new';
 
 const EXPECTED = {
     'others': [
-        { 'path': 'std::boxed::PinBox', 'name': 'new' },
-        { 'path': 'alloc::boxed::PinBox', 'name': 'new' },
+        { 'path': 'std::pin::PinBox', 'name': 'new' },
+        { 'path': 'alloc::pin::PinBox', 'name': 'new' },
     ],
 };
diff --git a/src/test/rustdoc-js/vec-new.js b/src/test/rustdoc-js/vec-new.js
index 702953e2e9d..4a654ccb135 100644
--- a/src/test/rustdoc-js/vec-new.js
+++ b/src/test/rustdoc-js/vec-new.js
@@ -14,6 +14,6 @@ const EXPECTED = {
     'others': [
         { 'path': 'std::vec::Vec', 'name': 'new' },
         { 'path': 'std::vec::Vec', 'name': 'ne' },
-        { 'path': 'std::boxed::PinBox', 'name': 'new' },
+        { 'path': 'std::pin::PinBox', 'name': 'new' },
     ],
 };
diff --git a/src/test/ui/anon-params-deprecated.stderr b/src/test/ui/anon-params-deprecated.stderr
index e1c27ceefa9..691c3159a52 100644
--- a/src/test/ui/anon-params-deprecated.stderr
+++ b/src/test/ui/anon-params-deprecated.stderr
@@ -9,7 +9,7 @@ note: lint level defined here
    |
 LL | #![warn(anonymous_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
    = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
 
 warning: anonymous parameters are deprecated and will be removed in the next edition.
@@ -18,7 +18,7 @@ warning: anonymous parameters are deprecated and will be removed in the next edi
 LL |     fn bar_with_default_impl(String, String) {}
    |                              ^^^^^^ help: Try naming the parameter or explicitly ignoring it: `_: String`
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
    = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
 
 warning: anonymous parameters are deprecated and will be removed in the next edition.
@@ -27,6 +27,6 @@ warning: anonymous parameters are deprecated and will be removed in the next edi
 LL |     fn bar_with_default_impl(String, String) {}
    |                                      ^^^^^^ help: Try naming the parameter or explicitly ignoring it: `_: String`
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
    = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
 
diff --git a/src/test/ui/chalkify/lower_trait.rs b/src/test/ui/chalkify/lower_trait.rs
index 7c0f233a645..c5ba5beeca7 100644
--- a/src/test/ui/chalkify/lower_trait.rs
+++ b/src/test/ui/chalkify/lower_trait.rs
@@ -12,9 +12,9 @@
 
 #[rustc_dump_program_clauses] //~ ERROR program clause dump
 trait Foo<S, T, U> {
-    fn s(S) -> S;
-    fn t(T) -> T;
-    fn u(U) -> U;
+    fn s(_: S) -> S;
+    fn t(_: T) -> T;
+    fn u(_: U) -> U;
 }
 
 fn main() {
diff --git a/src/test/ui/chalkify/lower_trait_higher_rank.rs b/src/test/ui/chalkify/lower_trait_higher_rank.rs
index 47e9398d364..7fc48cfd56d 100644
--- a/src/test/ui/chalkify/lower_trait_higher_rank.rs
+++ b/src/test/ui/chalkify/lower_trait_higher_rank.rs
@@ -13,7 +13,7 @@
 #[rustc_dump_program_clauses] //~ ERROR program clause dump
 trait Foo<F> where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8
 {
-    fn s(F) -> F;
+    fn s(_: F) -> F;
 }
 
 fn main() {
diff --git a/src/test/ui/chalkify/lower_trait_where_clause.rs b/src/test/ui/chalkify/lower_trait_where_clause.rs
index 67ee7c28b6a..57e95e39cd9 100644
--- a/src/test/ui/chalkify/lower_trait_where_clause.rs
+++ b/src/test/ui/chalkify/lower_trait_where_clause.rs
@@ -15,9 +15,9 @@ use std::borrow::Borrow;
 
 #[rustc_dump_program_clauses] //~ ERROR program clause dump
 trait Foo<'a, 'b, S, T, U> where S: Debug, T: Borrow<U>, U: ?Sized, 'a: 'b, U: 'b {
-    fn s(S) -> S;
-    fn t(T) -> T;
-    fn u(U) -> U;
+    fn s(_: S) -> S;
+    fn t(_: T) -> T;
+    fn u(_: U) -> U;
 }
 
 fn main() {
diff --git a/src/test/ui/consts/const-eval/double_check2.stderr b/src/test/ui/consts/const-eval/double_check2.stderr
index 739af12d09c..21025877340 100644
--- a/src/test/ui/consts/const-eval/double_check2.stderr
+++ b/src/test/ui/consts/const-eval/double_check2.stderr
@@ -5,7 +5,7 @@ LL | / static FOO: (&Foo, &Bar) = unsafe {( //~ undefined behavior
 LL | |     Union { usize: &BAR }.foo,
 LL | |     Union { usize: &BAR }.bar,
 LL | | )};
-   | |___^ type validation failed: encountered 5 at .1.<deref>.<enum-tag>, but expected something in the range 42..=99
+   | |___^ type validation failed: encountered invalid enum discriminant 5 at .1.<deref>
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
 
diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr
index 98e9b598b54..572d08ddfee 100644
--- a/src/test/ui/consts/const-eval/ub-enum.stderr
+++ b/src/test/ui/consts/const-eval/ub-enum.stderr
@@ -2,7 +2,7 @@ error[E0080]: this constant likely exhibits undefined behavior
   --> $DIR/ub-enum.rs:22:1
    |
 LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.b };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer at .<enum-tag>, but expected something in the range 0..=0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer enum discriminant
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
 
@@ -10,7 +10,7 @@ error[E0080]: this constant likely exhibits undefined behavior
   --> $DIR/ub-enum.rs:35:1
    |
 LL | const BAD_ENUM2 : Enum2 = unsafe { TransmuteEnum2 { a: 0 }.b };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0 at .<enum-tag>, but expected something in the range 2..=2
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid enum discriminant 0
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
 
diff --git a/src/test/ui/crate-in-paths.rs b/src/test/ui/crate-in-paths.rs
new file mode 100644
index 00000000000..ef01294f941
--- /dev/null
+++ b/src/test/ui/crate-in-paths.rs
@@ -0,0 +1,22 @@
+// 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.
+
+// edition:2018
+
+#![feature(edition_2018_preview)]
+
+mod bar {
+    crate struct Foo;
+}
+
+fn main() {
+    Foo;
+    //~^ ERROR cannot find value `Foo` in this scope [E0425]
+}
diff --git a/src/test/ui/crate-in-paths.stderr b/src/test/ui/crate-in-paths.stderr
new file mode 100644
index 00000000000..5bb1a28ebb8
--- /dev/null
+++ b/src/test/ui/crate-in-paths.stderr
@@ -0,0 +1,13 @@
+error[E0425]: cannot find value `Foo` in this scope
+  --> $DIR/crate-in-paths.rs:20:5
+   |
+LL |     Foo;
+   |     ^^^ not found in this scope
+help: possible candidate is found in another module, you can import it into scope
+   |
+LL | use crate::bar::Foo;
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/future-incompatible-lint-group.stderr b/src/test/ui/future-incompatible-lint-group.stderr
index 56f4ff33eb2..c239131ee16 100644
--- a/src/test/ui/future-incompatible-lint-group.stderr
+++ b/src/test/ui/future-incompatible-lint-group.stderr
@@ -10,7 +10,7 @@ note: lint level defined here
 LL | #![deny(future_incompatible)]
    |         ^^^^^^^^^^^^^^^^^^^
    = note: #[deny(anonymous_parameters)] implied by #[deny(future_incompatible)]
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
    = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
 
 error: aborting due to previous error
diff --git a/src/test/ui/impl-trait/where-allowed.rs b/src/test/ui/impl-trait/where-allowed.rs
index 2891cd59e3e..69f6d202f14 100644
--- a/src/test/ui/impl-trait/where-allowed.rs
+++ b/src/test/ui/impl-trait/where-allowed.rs
@@ -125,7 +125,7 @@ trait InTraitDefnReturn {
 // Allowed and disallowed in trait impls
 trait DummyTrait {
     type Out;
-    fn in_trait_impl_parameter(impl Debug);
+    fn in_trait_impl_parameter(_: impl Debug);
     fn in_trait_impl_return() -> Self::Out;
 }
 impl DummyTrait for () {
diff --git a/src/test/ui/issue-52992.rs b/src/test/ui/issue-52992.rs
new file mode 100644
index 00000000000..2ece0ee9fee
--- /dev/null
+++ b/src/test/ui/issue-52992.rs
@@ -0,0 +1,37 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for an NLL-related ICE (#52992) -- computing
+// implied bounds was causing outlives relations that were not
+// properly handled.
+//
+// compile-pass
+
+#![feature(nll)]
+
+fn main() {}
+
+fn fail<'a>() -> Struct<'a, Generic<()>> {
+    Struct(&Generic(()))
+}
+
+struct Struct<'a, T>(&'a T) where
+    T: Trait + 'a,
+    T::AT: 'a; // only fails with this bound
+
+struct Generic<T>(T);
+
+trait Trait {
+    type AT;
+}
+
+impl<T> Trait for Generic<T> {
+    type AT = T; // only fails with a generic AT
+}
diff --git a/src/test/ui/issue-53419.rs b/src/test/ui/issue-53419.rs
new file mode 100644
index 00000000000..e4ade1b6323
--- /dev/null
+++ b/src/test/ui/issue-53419.rs
@@ -0,0 +1,21 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//compile-pass
+
+#![feature(infer_outlives_requirements)]
+
+struct Foo {
+    bar: for<'r> Fn(usize, &'r FnMut())
+}
+
+fn main() {
+}
+
diff --git a/src/test/ui/issue-53568.rs b/src/test/ui/issue-53568.rs
new file mode 100644
index 00000000000..6b479f75172
--- /dev/null
+++ b/src/test/ui/issue-53568.rs
@@ -0,0 +1,61 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for an NLL-related ICE (#53568) -- we failed to
+// resolve inference variables in "custom type-ops".
+//
+// compile-pass
+
+#![feature(nll)]
+#![allow(dead_code)]
+
+trait Future {
+    type Item;
+}
+
+impl<F, T> Future for F
+where F: Fn() -> T
+{
+    type Item = T;
+}
+
+trait Connect {}
+
+struct Connector<H> {
+    handler: H,
+}
+
+impl<H, T> Connect for Connector<H>
+where
+    T: 'static,
+    H: Future<Item = T>
+{
+}
+
+struct Client<C> {
+    connector: C,
+}
+
+fn build<C>(_connector: C) -> Client<C> {
+    unimplemented!()
+}
+
+fn client<H>(handler: H) -> Client<impl Connect>
+where H: Fn() + Copy
+{
+    let connector = Connector {
+        handler,
+    };
+    let client = build(connector);
+    client
+}
+
+fn main() { }
+
diff --git a/src/test/ui/issues/issue-17718-const-bad-values.rs b/src/test/ui/issues/issue-17718-const-bad-values.rs
index 17ec77d77ee..16cf4fd1b32 100644
--- a/src/test/ui/issues/issue-17718-const-bad-values.rs
+++ b/src/test/ui/issues/issue-17718-const-bad-values.rs
@@ -15,6 +15,5 @@ static mut S: usize = 3;
 const C2: &'static mut usize = unsafe { &mut S };
 //~^ ERROR: constants cannot refer to statics
 //~| ERROR: references in constants may only refer to immutable values
-//~| ERROR: references in constants may only refer to immutable values
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-17718-const-bad-values.stderr b/src/test/ui/issues/issue-17718-const-bad-values.stderr
index 0ab7f965b63..85424e5b73e 100644
--- a/src/test/ui/issues/issue-17718-const-bad-values.stderr
+++ b/src/test/ui/issues/issue-17718-const-bad-values.stderr
@@ -16,13 +16,7 @@ error[E0017]: references in constants may only refer to immutable values
 LL | const C2: &'static mut usize = unsafe { &mut S };
    |                                         ^^^^^^ constants require immutable values
 
-error[E0017]: references in constants may only refer to immutable values
-  --> $DIR/issue-17718-const-bad-values.rs:15:32
-   |
-LL | const C2: &'static mut usize = unsafe { &mut S };
-   |                                ^^^^^^^^^^^^^^^^^ constants require immutable values
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors occurred: E0013, E0017.
 For more information about an error, try `rustc --explain E0013`.
diff --git a/src/test/ui/issues/issue-46471-1.stderr b/src/test/ui/issues/issue-46471-1.stderr
index 7d12827dda5..3f098fa37ce 100644
--- a/src/test/ui/issues/issue-46471-1.stderr
+++ b/src/test/ui/issues/issue-46471-1.stderr
@@ -12,16 +12,13 @@ LL | }
 error[E0597]: `z` does not live long enough (Mir)
   --> $DIR/issue-46471-1.rs:16:9
    |
-LL |       let y = {
-   |  _____________-
-LL | |         let mut z = 0;
-LL | |         &mut z
-   | |         ^^^^^^ borrowed value does not live long enough
-LL | |     };
-   | |     -
-   | |     |
-   | |_____`z` dropped here while still borrowed
-   |       borrow later used here
+LL |         &mut z
+   |         ^^^^^^
+   |         |
+   |         borrowed value does not live long enough
+   |         borrow later used here
+LL |     };
+   |     - `z` dropped here while still borrowed
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/match/match-ref-mut-invariance.nll.stderr b/src/test/ui/match/match-ref-mut-invariance.nll.stderr
index 26fcaa65d77..40dd9e25a17 100644
--- a/src/test/ui/match/match-ref-mut-invariance.nll.stderr
+++ b/src/test/ui/match/match-ref-mut-invariance.nll.stderr
@@ -5,17 +5,14 @@ LL |         match self.0 { ref mut x => x } //~ ERROR mismatched types
    |                                     ^
 
 error: unsatisfied lifetime constraints
-  --> $DIR/match-ref-mut-invariance.rs:19:49
+  --> $DIR/match-ref-mut-invariance.rs:20:9
    |
-LL |   impl<'b> S<'b> {
-   |        -- lifetime `'b` defined here
-LL |       fn bar<'a>(&'a mut self) -> &'a mut &'a i32 {
-   |  ____________--___________________________________^
-   | |            |
-   | |            lifetime `'a` defined here
-LL | |         match self.0 { ref mut x => x } //~ ERROR mismatched types
-LL | |     }
-   | |_____^ returning this value requires that `'a` must outlive `'b`
+LL | impl<'b> S<'b> {
+   |      -- lifetime `'b` defined here
+LL |     fn bar<'a>(&'a mut self) -> &'a mut &'a i32 {
+   |            -- lifetime `'a` defined here
+LL |         match self.0 { ref mut x => x } //~ ERROR mismatched types
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr b/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr
index b1ec6adee9e..5314f37a3f8 100644
--- a/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr
+++ b/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr
@@ -5,18 +5,15 @@ LL |         x //~ ERROR mismatched types
    |         ^
 
 error: unsatisfied lifetime constraints
-  --> $DIR/match-ref-mut-let-invariance.rs:19:49
+  --> $DIR/match-ref-mut-let-invariance.rs:21:9
    |
-LL |   impl<'b> S<'b> {
-   |        -- lifetime `'b` defined here
-LL |       fn bar<'a>(&'a mut self) -> &'a mut &'a i32 {
-   |  ____________--___________________________________^
-   | |            |
-   | |            lifetime `'a` defined here
-LL | |         let ref mut x = self.0;
-LL | |         x //~ ERROR mismatched types
-LL | |     }
-   | |_____^ returning this value requires that `'a` must outlive `'b`
+LL | impl<'b> S<'b> {
+   |      -- lifetime `'b` defined here
+LL |     fn bar<'a>(&'a mut self) -> &'a mut &'a i32 {
+   |            -- lifetime `'a` defined here
+LL |         let ref mut x = self.0;
+LL |         x //~ ERROR mismatched types
+   |         ^ returning this value requires that `'a` must outlive `'b`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs b/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs
index 5538eca3629..808114f3fa9 100644
--- a/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs
+++ b/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs
@@ -8,10 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//compile-flags: -Z emit-end-regions -Zborrowck=mir
-
-
 #![allow(warnings)]
+#![feature(nll)]
 
 struct Wrap<'p> { p: &'p mut i32 }
 
diff --git a/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr b/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr
index 327454ee60e..6fc26d502d3 100644
--- a/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr
+++ b/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr
@@ -1,5 +1,5 @@
 error[E0506]: cannot assign to `x` because it is borrowed
-  --> $DIR/maybe-initialized-drop-implicit-fragment-drop.rs:32:5
+  --> $DIR/maybe-initialized-drop-implicit-fragment-drop.rs:30:5
    |
 LL |     let wrap = Wrap { p: &mut x };
    |                          ------ borrow of `x` occurs here
diff --git a/src/test/ui/nll/mir_check_cast_unsize.rs b/src/test/ui/nll/mir_check_cast_unsize.rs
index 695dddbf7e9..7ef6572a5d7 100644
--- a/src/test/ui/nll/mir_check_cast_unsize.rs
+++ b/src/test/ui/nll/mir_check_cast_unsize.rs
@@ -15,9 +15,9 @@
 use std::fmt::Debug;
 
 fn bar<'a>(x: &'a u32) -> &'static dyn Debug {
-    //~^ ERROR unsatisfied lifetime constraints
     x
-    //~^ WARNING not reporting region error due to nll
+    //~^ ERROR unsatisfied lifetime constraints
+    //~| WARNING not reporting region error due to nll
 }
 
 fn main() {}
diff --git a/src/test/ui/nll/mir_check_cast_unsize.stderr b/src/test/ui/nll/mir_check_cast_unsize.stderr
index 4219c07673a..a965e611f99 100644
--- a/src/test/ui/nll/mir_check_cast_unsize.stderr
+++ b/src/test/ui/nll/mir_check_cast_unsize.stderr
@@ -1,21 +1,16 @@
 warning: not reporting region error due to nll
-  --> $DIR/mir_check_cast_unsize.rs:19:5
+  --> $DIR/mir_check_cast_unsize.rs:18:5
    |
 LL |     x
    |     ^
 
 error: unsatisfied lifetime constraints
-  --> $DIR/mir_check_cast_unsize.rs:17:46
+  --> $DIR/mir_check_cast_unsize.rs:18:5
    |
-LL |   fn bar<'a>(x: &'a u32) -> &'static dyn Debug {
-   |  ________--____________________________________^
-   | |        |
-   | |        lifetime `'a` defined here
-LL | |     //~^ ERROR unsatisfied lifetime constraints
-LL | |     x
-LL | |     //~^ WARNING not reporting region error due to nll
-LL | | }
-   | |_^ returning this value requires that `'a` must outlive `'static`
+LL | fn bar<'a>(x: &'a u32) -> &'static dyn Debug {
+   |        -- lifetime `'a` defined here
+LL |     x
+   |     ^ returning this value requires that `'a` must outlive `'static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr
index 0d21dddc7c9..2dc0a10f425 100644
--- a/src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr
+++ b/src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr
@@ -5,20 +5,15 @@ LL |     ss
    |     ^^
 
 error: unsatisfied lifetime constraints
-  --> $DIR/object-lifetime-default-elision.rs:64:53
+  --> $DIR/object-lifetime-default-elision.rs:81:5
    |
-LL |   fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait {
-   |  __________--_--______________________________________^
-   | |          |  |
-   | |          |  lifetime `'b` defined here
-   | |          lifetime `'a` defined here
-LL | |     // Under old rules, the fully elaborated types of input/output were:
-LL | |     //
-LL | |     // for<'a,'b,'c>fn(&'a (SomeTrait+'c)) -> &'b (SomeTrait+'a)
-...  |
-LL | |         //~| ERROR cannot infer
-LL | | }
-   | |_^ returning this value requires that `'a` must outlive `'b`
+LL | fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait {
+   |          -- -- lifetime `'b` defined here
+   |          |
+   |          lifetime `'a` defined here
+...
+LL |     ss
+   |     ^^ returning this value requires that `'a` must outlive `'b`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr
index 5cfced1a72f..19279b53c1c 100644
--- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr
+++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr
@@ -11,18 +11,13 @@ LL |     ss.r = b; //~ ERROR 41:12: 41:13: explicit lifetime required in the typ
    |            ^
 
 error[E0621]: explicit lifetime required in the type of `ss`
-  --> $DIR/object-lifetime-default-from-box-error.rs:24:48
+  --> $DIR/object-lifetime-default-from-box-error.rs:28:5
    |
-LL |   fn load(ss: &mut SomeStruct) -> Box<SomeTrait> {
-   |  _____________---------------____________________^
-   | |             |
-   | |             help: add explicit lifetime `'static` to the type of `ss`: `&mut SomeStruct<'static>`
-LL | |     // `Box<SomeTrait>` defaults to a `'static` bound, so this return
-LL | |     // is illegal.
-LL | |
-LL | |     ss.r //~ ERROR explicit lifetime required in the type of `ss` [E0621]
-LL | | }
-   | |_^ lifetime `'static` required
+LL | fn load(ss: &mut SomeStruct) -> Box<SomeTrait> {
+   |             --------------- help: add explicit lifetime `'static` to the type of `ss`: `&mut SomeStruct<'static>`
+...
+LL |     ss.r //~ ERROR explicit lifetime required in the type of `ss` [E0621]
+   |     ^^^^ lifetime `'static` required
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/object-lifetime-default-from-box-error.rs:28:5
diff --git a/src/test/ui/panic-handler/panic-handler-std.stderr b/src/test/ui/panic-handler/panic-handler-std.stderr
index c34a993e2c5..b141a217164 100644
--- a/src/test/ui/panic-handler/panic-handler-std.stderr
+++ b/src/test/ui/panic-handler/panic-handler-std.stderr
@@ -8,6 +8,12 @@ LL | | }
    |
    = note: first defined in crate `std`.
 
-error: aborting due to previous error
+error: argument should be `&PanicInfo`
+  --> $DIR/panic-handler-std.rs:18:16
+   |
+LL | fn panic(info: PanicInfo) -> ! {
+   |                ^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0152`.
diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr
index 8338cf6a606..f0def1888b9 100644
--- a/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr
+++ b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr
@@ -31,43 +31,31 @@ LL |     let x: Box<Foo + 'static> = Box::new(v);
    |                                 ^^^^^^^^^^^ lifetime `'static` required
 
 error[E0621]: explicit lifetime required in the type of `v`
-  --> $DIR/region-object-lifetime-in-coercion.rs:23:38
+  --> $DIR/region-object-lifetime-in-coercion.rs:24:5
    |
-LL |   fn b(v: &[u8]) -> Box<Foo + 'static> {
-   |  _________-----________________________^
-   | |         |
-   | |         help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
-LL | |     Box::new(v)
-LL | |         //~^ ERROR explicit lifetime required in the type of `v` [E0621]
-LL | | }
-   | |_^ lifetime `'static` required
+LL | fn b(v: &[u8]) -> Box<Foo + 'static> {
+   |         ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
+LL |     Box::new(v)
+   |     ^^^^^^^^^^^ lifetime `'static` required
 
 error[E0621]: explicit lifetime required in the type of `v`
-  --> $DIR/region-object-lifetime-in-coercion.rs:28:28
+  --> $DIR/region-object-lifetime-in-coercion.rs:31:5
    |
-LL |   fn c(v: &[u8]) -> Box<Foo> {
-   |  _________-----______________^
-   | |         |
-   | |         help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
-LL | |     // same as previous case due to RFC 599
-LL | |
-LL | |     Box::new(v)
-LL | |         //~^ ERROR explicit lifetime required in the type of `v` [E0621]
-LL | | }
-   | |_^ lifetime `'static` required
+LL | fn c(v: &[u8]) -> Box<Foo> {
+   |         ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
+...
+LL |     Box::new(v)
+   |     ^^^^^^^^^^^ lifetime `'static` required
 
 error: unsatisfied lifetime constraints
-  --> $DIR/region-object-lifetime-in-coercion.rs:35:41
+  --> $DIR/region-object-lifetime-in-coercion.rs:36:5
    |
-LL |   fn d<'a,'b>(v: &'a [u8]) -> Box<Foo+'b> {
-   |  ______--_--______________________________^
-   | |      |  |
-   | |      |  lifetime `'b` defined here
-   | |      lifetime `'a` defined here
-LL | |     Box::new(v)
-LL | |         //~^ ERROR cannot infer an appropriate lifetime due to conflicting
-LL | | }
-   | |_^ returning this value requires that `'a` must outlive `'b`
+LL | fn d<'a,'b>(v: &'a [u8]) -> Box<Foo+'b> {
+   |      -- -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+LL |     Box::new(v)
+   |     ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/regions/regions-close-object-into-object-2.nll.stderr b/src/test/ui/regions/regions-close-object-into-object-2.nll.stderr
index 701becc24d7..85724cfabd8 100644
--- a/src/test/ui/regions/regions-close-object-into-object-2.nll.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-2.nll.stderr
@@ -5,15 +5,12 @@ LL |     box B(&*v) as Box<X> //~ ERROR cannot infer
    |           ^^^
 
 error: unsatisfied lifetime constraints
-  --> $DIR/regions-close-object-into-object-2.rs:19:57
+  --> $DIR/regions-close-object-into-object-2.rs:20:5
    |
-LL |   fn g<'a, T: 'static>(v: Box<A<T>+'a>) -> Box<X+'static> {
-   |  ______--_________________________________________________^
-   | |      |
-   | |      lifetime `'a` defined here
-LL | |     box B(&*v) as Box<X> //~ ERROR cannot infer
-LL | | }
-   | |_^ returning this value requires that `'a` must outlive `'static`
+LL | fn g<'a, T: 'static>(v: Box<A<T>+'a>) -> Box<X+'static> {
+   |      -- lifetime `'a` defined here
+LL |     box B(&*v) as Box<X> //~ ERROR cannot infer
+   |     ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
 
 error[E0597]: `*v` does not live long enough
   --> $DIR/regions-close-object-into-object-2.rs:20:11
diff --git a/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr b/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr
index e01ae145e90..3dc8df3608f 100644
--- a/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr
@@ -28,17 +28,6 @@ warning: not reporting region error due to nll
 LL |     box B(&*v) as Box<X> //~ ERROR cannot infer
    |     ^^^^^^^^^^
 
-error: unsatisfied lifetime constraints
-  --> $DIR/regions-close-object-into-object-4.rs:19:51
-   |
-LL |   fn i<'a, T, U>(v: Box<A<U>+'a>) -> Box<X+'static> {
-   |  ______--___________________________________________^
-   | |      |
-   | |      lifetime `'a` defined here
-LL | |     box B(&*v) as Box<X> //~ ERROR cannot infer
-LL | | }
-   | |_^ returning this value requires that `'a` must outlive `'static`
-
 error[E0310]: the parameter type `U` may not live long enough
   --> $DIR/regions-close-object-into-object-4.rs:20:5
    |
@@ -47,6 +36,14 @@ LL |     box B(&*v) as Box<X> //~ ERROR cannot infer
    |
    = help: consider adding an explicit lifetime bound `U: 'static`...
 
+error: unsatisfied lifetime constraints
+  --> $DIR/regions-close-object-into-object-4.rs:20:5
+   |
+LL | fn i<'a, T, U>(v: Box<A<U>+'a>) -> Box<X+'static> {
+   |      -- lifetime `'a` defined here
+LL |     box B(&*v) as Box<X> //~ ERROR cannot infer
+   |     ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
 error[E0310]: the parameter type `U` may not live long enough
   --> $DIR/regions-close-object-into-object-4.rs:20:9
    |
diff --git a/src/test/ui/regions/regions-proc-bound-capture.nll.stderr b/src/test/ui/regions/regions-proc-bound-capture.nll.stderr
index 00728aa4783..f19feed1752 100644
--- a/src/test/ui/regions/regions-proc-bound-capture.nll.stderr
+++ b/src/test/ui/regions/regions-proc-bound-capture.nll.stderr
@@ -5,16 +5,13 @@ LL |     Box::new(move|| { *x }) //~ ERROR explicit lifetime required in the typ
    |              ^^^^^^^^^^^^^
 
 error[E0621]: explicit lifetime required in the type of `x`
-  --> $DIR/regions-proc-bound-capture.rs:17:62
+  --> $DIR/regions-proc-bound-capture.rs:19:5
    |
-LL |   fn static_proc(x: &isize) -> Box<FnMut()->(isize) + 'static> {
-   |  ___________________------_____________________________________^
-   | |                   |
-   | |                   help: add explicit lifetime `'static` to the type of `x`: `&'static isize`
-LL | |     // This is illegal, because the region bound on `proc` is 'static.
-LL | |     Box::new(move|| { *x }) //~ ERROR explicit lifetime required in the type of `x` [E0621]
-LL | | }
-   | |_^ lifetime `'static` required
+LL | fn static_proc(x: &isize) -> Box<FnMut()->(isize) + 'static> {
+   |                   ------ help: add explicit lifetime `'static` to the type of `x`: `&'static isize`
+LL |     // This is illegal, because the region bound on `proc` is 'static.
+LL |     Box::new(move|| { *x }) //~ ERROR explicit lifetime required in the type of `x` [E0621]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.nll.stderr b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.nll.stderr
index 37454ff78a1..89575ca9bc8 100644
--- a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.nll.stderr
+++ b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.nll.stderr
@@ -5,16 +5,14 @@ LL |     &mut ***p //~ ERROR 14:5: 14:14: lifetime mismatch [E0623]
    |     ^^^^^^^^^
 
 error: unsatisfied lifetime constraints
-  --> $DIR/regions-reborrow-from-shorter-mut-ref-mut-ref.rs:13:85
+  --> $DIR/regions-reborrow-from-shorter-mut-ref-mut-ref.rs:14:5
    |
-LL |   fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut isize) -> &'b mut isize {
-   |  ______________________--__--_________________________________________________________^
-   | |                      |   |
-   | |                      |   lifetime `'b` defined here
-   | |                      lifetime `'a` defined here
-LL | |     &mut ***p //~ ERROR 14:5: 14:14: lifetime mismatch [E0623]
-LL | | }
-   | |_^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+LL | fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut isize) -> &'b mut isize {
+   |                      --  -- lifetime `'b` defined here
+   |                      |
+   |                      lifetime `'a` defined here
+LL |     &mut ***p //~ ERROR 14:5: 14:14: lifetime mismatch [E0623]
+   |     ^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.nll.stderr b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.nll.stderr
index 455ee6f7949..9c57813f26b 100644
--- a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.nll.stderr
+++ b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.nll.stderr
@@ -5,16 +5,14 @@ LL |     &mut **p //~ ERROR 16:5: 16:13: lifetime mismatch [E0623]
    |     ^^^^^^^^
 
 error: unsatisfied lifetime constraints
-  --> $DIR/regions-reborrow-from-shorter-mut-ref.rs:15:73
+  --> $DIR/regions-reborrow-from-shorter-mut-ref.rs:16:5
    |
-LL |   fn copy_borrowed_ptr<'a, 'b>(p: &'a mut &'b mut isize) -> &'b mut isize {
-   |  ______________________--__--_____________________________________________^
-   | |                      |   |
-   | |                      |   lifetime `'b` defined here
-   | |                      lifetime `'a` defined here
-LL | |     &mut **p //~ ERROR 16:5: 16:13: lifetime mismatch [E0623]
-LL | | }
-   | |_^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+LL | fn copy_borrowed_ptr<'a, 'b>(p: &'a mut &'b mut isize) -> &'b mut isize {
+   |                      --  -- lifetime `'b` defined here
+   |                      |
+   |                      lifetime `'a` defined here
+LL |     &mut **p //~ ERROR 16:5: 16:13: lifetime mismatch [E0623]
+   |     ^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr b/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr
index 99bee4a36c1..01db25a07f7 100644
--- a/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr
+++ b/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr
@@ -11,18 +11,15 @@ LL |     x //~ ERROR mismatched types
    |     ^
 
 error: unsatisfied lifetime constraints
-  --> $DIR/regions-trait-object-subtyping.rs:23:51
+  --> $DIR/regions-trait-object-subtyping.rs:25:5
    |
-LL |   fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy {
-   |  _________--_--_____________________________________^
-   | |         |  |
-   | |         |  lifetime `'b` defined here
-   | |         lifetime `'a` defined here
-LL | |     // Without knowing 'a:'b, we can't coerce
-LL | |     x //~ ERROR lifetime bound not satisfied
-LL | |      //~^ ERROR cannot infer an appropriate lifetime
-LL | | }
-   | |_^ returning this value requires that `'a` must outlive `'b`
+LL | fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy {
+   |         -- -- lifetime `'b` defined here
+   |         |
+   |         lifetime `'a` defined here
+LL |     // Without knowing 'a:'b, we can't coerce
+LL |     x //~ ERROR lifetime bound not satisfied
+   |     ^ returning this value requires that `'a` must outlive `'b`
 
 error: unsatisfied lifetime constraints
   --> $DIR/regions-trait-object-subtyping.rs:32:5
diff --git a/src/test/ui/rust-2018/auxiliary/remove-extern-crate.rs b/src/test/ui/rust-2018/auxiliary/remove-extern-crate.rs
new file mode 100644
index 00000000000..9daaca1fb8f
--- /dev/null
+++ b/src/test/ui/rust-2018/auxiliary/remove-extern-crate.rs
@@ -0,0 +1,19 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[macro_export]
+macro_rules! foo {
+    () => ()
+}
+
+#[macro_export]
+macro_rules! bar {
+    () => ()
+}
diff --git a/src/test/ui/rust-2018/remove-extern-crate.fixed b/src/test/ui/rust-2018/remove-extern-crate.fixed
new file mode 100644
index 00000000000..995be4290b8
--- /dev/null
+++ b/src/test/ui/rust-2018/remove-extern-crate.fixed
@@ -0,0 +1,39 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-rustfix
+// edition:2018
+// compile-pass
+// aux-build:remove-extern-crate.rs
+
+#![warn(rust_2018_idioms)]
+
+
+use core as another_name;
+use remove_extern_crate;
+#[macro_use]
+extern crate remove_extern_crate as something_else;
+
+fn main() {
+    another_name::mem::drop(3);
+    another::foo();
+    remove_extern_crate::foo!();
+    bar!();
+}
+
+mod another {
+    use core;
+    use remove_extern_crate;
+
+    pub fn foo() {
+        core::mem::drop(4);
+        remove_extern_crate::foo!();
+    }
+}
diff --git a/src/test/ui/rust-2018/remove-extern-crate.rs b/src/test/ui/rust-2018/remove-extern-crate.rs
new file mode 100644
index 00000000000..3ab97a74287
--- /dev/null
+++ b/src/test/ui/rust-2018/remove-extern-crate.rs
@@ -0,0 +1,39 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-rustfix
+// edition:2018
+// compile-pass
+// aux-build:remove-extern-crate.rs
+
+#![warn(rust_2018_idioms)]
+
+extern crate core;
+extern crate core as another_name;
+use remove_extern_crate;
+#[macro_use]
+extern crate remove_extern_crate as something_else;
+
+fn main() {
+    another_name::mem::drop(3);
+    another::foo();
+    remove_extern_crate::foo!();
+    bar!();
+}
+
+mod another {
+    extern crate core;
+    use remove_extern_crate;
+
+    pub fn foo() {
+        core::mem::drop(4);
+        remove_extern_crate::foo!();
+    }
+}
diff --git a/src/test/ui/rust-2018/remove-extern-crate.stderr b/src/test/ui/rust-2018/remove-extern-crate.stderr
new file mode 100644
index 00000000000..752a7b180de
--- /dev/null
+++ b/src/test/ui/rust-2018/remove-extern-crate.stderr
@@ -0,0 +1,25 @@
+warning: unused extern crate
+  --> $DIR/remove-extern-crate.rs:18:1
+   |
+LL | extern crate core;
+   | ^^^^^^^^^^^^^^^^^^ help: remove it
+   |
+note: lint level defined here
+  --> $DIR/remove-extern-crate.rs:16:9
+   |
+LL | #![warn(rust_2018_idioms)]
+   |         ^^^^^^^^^^^^^^^^
+   = note: #[warn(unused_extern_crates)] implied by #[warn(rust_2018_idioms)]
+
+warning: `extern crate` is not idiomatic in the new edition
+  --> $DIR/remove-extern-crate.rs:19:1
+   |
+LL | extern crate core as another_name;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
+
+warning: `extern crate` is not idiomatic in the new edition
+  --> $DIR/remove-extern-crate.rs:32:5
+   |
+LL |     extern crate core;
+   |     ^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
+
diff --git a/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr b/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr
index f522521b400..f8e5e3914eb 100644
--- a/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr
+++ b/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr
@@ -1,17 +1,12 @@
 error[E0597]: `tmp0` does not live long enough
   --> $DIR/regions-close-over-type-parameter-2.rs:33:20
    |
-LL |       let _ = {
-   |  _____________-
-LL | |         let tmp0 = 3;
-LL | |         let tmp1 = &tmp0;
-   | |                    ^^^^^ borrowed value does not live long enough
-LL | |         repeater3(tmp1)
-LL | |     };
-   | |     -
-   | |     |
-   | |_____`tmp0` dropped here while still borrowed
-   |       borrow later used here
+LL |         let tmp1 = &tmp0;
+   |                    ^^^^^ borrowed value does not live long enough
+LL |         repeater3(tmp1)
+   |         --------------- borrow later used here
+LL |     };
+   |     - `tmp0` dropped here while still borrowed
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr
index 799b0982b94..58939b0f64f 100644
--- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr
+++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr
@@ -23,16 +23,13 @@ LL |     Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: unsatisfied lifetime constraints
-  --> $DIR/dyn-trait-underscore.rs:16:52
+  --> $DIR/dyn-trait-underscore.rs:18:5
    |
-LL |   fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
-   |  ________________-___________________________________^
-   | |                |
-   | |                let's call the lifetime of this reference `'1`
-LL | |     //                      ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static`
-LL | |     Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
-LL | | }
-   | |_^ returning this value requires that `'1` must outlive `'static`
+LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
+   |                - let's call the lifetime of this reference `'1`
+LL |     //                      ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static`
+LL |     Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
+   |     ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/union-ub-fat-ptr.rs b/src/test/ui/union-ub-fat-ptr.rs
index ffa824fc6af..0c42d28eb00 100644
--- a/src/test/ui/union-ub-fat-ptr.rs
+++ b/src/test/ui/union-ub-fat-ptr.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![allow(unused)]
+
 // normalize-stderr-test "alignment \d+" -> "alignment N"
 // normalize-stderr-test "offset \d+" -> "offset N"
 // normalize-stderr-test "allocation \d+" -> "allocation N"
@@ -37,7 +39,8 @@ union SliceTransmute {
     bad: BadSliceRepr,
     slice: &'static [u8],
     str: &'static str,
-    my_str: &'static Str,
+    my_str: &'static MyStr,
+    my_slice: &'static MySliceBool,
 }
 
 #[repr(C)]
@@ -71,7 +74,12 @@ union DynTransmute {
 trait Trait {}
 impl Trait for bool {}
 
-struct Str(str);
+// custom unsized type
+struct MyStr(str);
+
+// custom unsized type with sized fields
+struct MySlice<T: ?Sized>(bool, T);
+type MySliceBool = MySlice<[bool]>;
 
 // OK
 const A: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.str};
@@ -81,8 +89,8 @@ const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 }
 // bad str
 const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str};
 //~^ ERROR this constant likely exhibits undefined behavior
-// bad str in Str
-const C2: &Str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str};
+// bad str in user-defined unsized type
+const C2: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str};
 //~^ ERROR this constant likely exhibits undefined behavior
 
 // OK
@@ -107,10 +115,25 @@ const F: &Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3
 // bad data *inside* the trait object
 const G: &Trait = &unsafe { BoolTransmute { val: 3 }.bl };
 //~^ ERROR this constant likely exhibits undefined behavior
-
 // bad data *inside* the slice
 const H: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }];
 //~^ ERROR this constant likely exhibits undefined behavior
 
+// good MySliceBool
+const I1: &MySliceBool = &MySlice(true, [false]);
+// bad: sized field is not okay
+const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]);
+//~^ ERROR this constant likely exhibits undefined behavior
+// bad: unsized part is not okay
+const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
+//~^ ERROR this constant likely exhibits undefined behavior
+
+// invalid UTF-8
+const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
+//~^ ERROR this constant likely exhibits undefined behavior
+// invalid UTF-8 in user-defined str-like
+const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str };
+//~^ ERROR this constant likely exhibits undefined behavior
+
 fn main() {
 }
diff --git a/src/test/ui/union-ub-fat-ptr.stderr b/src/test/ui/union-ub-fat-ptr.stderr
index cc22422304d..5d817dce205 100644
--- a/src/test/ui/union-ub-fat-ptr.stderr
+++ b/src/test/ui/union-ub-fat-ptr.stderr
@@ -1,69 +1,69 @@
 error[E0080]: this constant likely exhibits undefined behavior
-  --> $DIR/union-ub-fat-ptr.rs:79:1
+  --> $DIR/union-ub-fat-ptr.rs:87:1
    |
 LL | const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str};
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access at offset N, outside bounds of allocation N which has size N
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or out-of-bounds memory at .<deref>
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
 
 error[E0080]: this constant likely exhibits undefined behavior
-  --> $DIR/union-ub-fat-ptr.rs:82:1
+  --> $DIR/union-ub-fat-ptr.rs:90:1
    |
 LL | const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str};
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered fat pointer length is not a valid integer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
 
 error[E0080]: this constant likely exhibits undefined behavior
-  --> $DIR/union-ub-fat-ptr.rs:85:1
+  --> $DIR/union-ub-fat-ptr.rs:93:1
    |
-LL | const C2: &Str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str};
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered fat pointer length is not a valid integer
+LL | const C2: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str};
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
 
 error[E0080]: this constant likely exhibits undefined behavior
-  --> $DIR/union-ub-fat-ptr.rs:91:1
+  --> $DIR/union-ub-fat-ptr.rs:99:1
    |
 LL | const B2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice};
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access at offset N, outside bounds of allocation N which has size N
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or out-of-bounds memory at .<deref>[1]
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
 
 error[E0080]: this constant likely exhibits undefined behavior
-  --> $DIR/union-ub-fat-ptr.rs:94:1
+  --> $DIR/union-ub-fat-ptr.rs:102:1
    |
 LL | const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice};
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered fat pointer length is not a valid integer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
 
 error[E0080]: this constant likely exhibits undefined behavior
-  --> $DIR/union-ub-fat-ptr.rs:98:1
+  --> $DIR/union-ub-fat-ptr.rs:106:1
    |
 LL | const D: &Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tried to access memory with alignment N, but alignment N is required
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid vtable in fat pointer at .<deref>
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
 
 error[E0080]: this constant likely exhibits undefined behavior
-  --> $DIR/union-ub-fat-ptr.rs:101:1
+  --> $DIR/union-ub-fat-ptr.rs:109:1
    |
 LL | const E: &Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a memory access tried to interpret some bytes as a pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid vtable in fat pointer at .<deref>
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
 
 error[E0080]: this constant likely exhibits undefined behavior
-  --> $DIR/union-ub-fat-ptr.rs:104:1
+  --> $DIR/union-ub-fat-ptr.rs:112:1
    |
 LL | const F: &Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered fat pointer vtable is not a valid pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-pointer vtable in fat pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
 
 error[E0080]: this constant likely exhibits undefined behavior
-  --> $DIR/union-ub-fat-ptr.rs:108:1
+  --> $DIR/union-ub-fat-ptr.rs:116:1
    |
 LL | const G: &Trait = &unsafe { BoolTransmute { val: 3 }.bl };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>, but expected something in the range 0..=1
@@ -71,13 +71,45 @@ LL | const G: &Trait = &unsafe { BoolTransmute { val: 3 }.bl };
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
 
 error[E0080]: this constant likely exhibits undefined behavior
-  --> $DIR/union-ub-fat-ptr.rs:112:1
+  --> $DIR/union-ub-fat-ptr.rs:119:1
    |
 LL | const H: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>[0], but expected something in the range 0..=1
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
 
-error: aborting due to 10 previous errors
+error[E0080]: this constant likely exhibits undefined behavior
+  --> $DIR/union-ub-fat-ptr.rs:125:1
+   |
+LL | const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.0, but expected something in the range 0..=1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+  --> $DIR/union-ub-fat-ptr.rs:128:1
+   |
+LL | const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.1[0], but expected something in the range 0..=1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+  --> $DIR/union-ub-fat-ptr.rs:132:1
+   |
+LL | const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-UTF-8 data in str at .<deref>
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+  --> $DIR/union-ub-fat-ptr.rs:135:1
+   |
+LL | const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-UTF-8 data in str at .<deref>.0
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: aborting due to 14 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 76c15f6601a..f43bd88d04f 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -63,7 +63,10 @@ static TARGETS: &'static [&'static str] = &[
     "armv7-unknown-cloudabi-eabihf",
     "armv7-unknown-linux-gnueabihf",
     "armv7-unknown-linux-musleabihf",
+    "armebv7r-none-eabi",
     "armebv7r-none-eabihf",
+    "armv7r-none-eabi",
+    "armv7r-none-eabihf",
     "armv7s-apple-ios",
     "asmjs-unknown-emscripten",
     "i386-apple-ios",
@@ -324,15 +327,7 @@ impl Builder {
         self.package("llvm-tools-preview", &mut manifest.pkg, TARGETS);
         self.package("lldb-preview", &mut manifest.pkg, TARGETS);
 
-        let clippy_present = manifest.pkg.contains_key("clippy-preview");
-        let rls_present = manifest.pkg.contains_key("rls-preview");
-        let rustfmt_present = manifest.pkg.contains_key("rustfmt-preview");
-        let llvm_tools_present = manifest.pkg.contains_key("llvm-tools-preview");
-        let lldb_present = manifest.pkg.contains_key("lldb-preview");
-
-        if rls_present {
-            manifest.renames.insert("rls".to_owned(), Rename { to: "rls-preview".to_owned() });
-        }
+        manifest.renames.insert("rls".to_owned(), Rename { to: "rls-preview".to_owned() });
 
         let mut pkg = Package {
             version: self.cached_version("rust")
@@ -371,40 +366,17 @@ impl Builder {
                 });
             }
 
-            if clippy_present {
-                extensions.push(Component {
-                    pkg: "clippy-preview".to_string(),
-                    target: host.to_string(),
-                });
-            }
-            if rls_present {
-                extensions.push(Component {
-                    pkg: "rls-preview".to_string(),
-                    target: host.to_string(),
-                });
-            }
-            if rustfmt_present {
-                extensions.push(Component {
-                    pkg: "rustfmt-preview".to_string(),
-                    target: host.to_string(),
-                });
-            }
-            if llvm_tools_present {
-                extensions.push(Component {
-                    pkg: "llvm-tools-preview".to_string(),
-                    target: host.to_string(),
-                });
-            }
-            if lldb_present {
-                extensions.push(Component {
-                    pkg: "lldb-preview".to_string(),
-                    target: host.to_string(),
-                });
-            }
-            extensions.push(Component {
-                pkg: "rust-analysis".to_string(),
-                target: host.to_string(),
-            });
+            // Tools are always present in the manifest, but might be marked as unavailable if they
+            // weren't built
+            extensions.extend(vec![
+                Component { pkg: "clippy-preview".to_string(), target: host.to_string() },
+                Component { pkg: "rls-preview".to_string(), target: host.to_string() },
+                Component { pkg: "rustfmt-preview".to_string(), target: host.to_string() },
+                Component { pkg: "llvm-tools-preview".to_string(), target: host.to_string() },
+                Component { pkg: "lldb-preview".to_string(), target: host.to_string() },
+                Component { pkg: "rust-analysis".to_string(), target: host.to_string() },
+            ]);
+
             for target in TARGETS {
                 if target != host {
                     extensions.push(Component {
@@ -459,32 +431,43 @@ impl Builder {
                pkgname: &str,
                dst: &mut BTreeMap<String, Package>,
                targets: &[&str]) {
-        let version = match *self.cached_version(pkgname) {
-            Some(ref version) => version.clone(),
-            None => {
-                println!("Skipping package {}", pkgname);
-                return;
-            }
+        let (version, is_present) = match *self.cached_version(pkgname) {
+            Some(ref version) => (version.clone(), true),
+            None => (String::new(), false),
         };
 
         let targets = targets.iter().map(|name| {
-            let filename = self.filename(pkgname, name);
-            let digest = match self.digests.remove(&filename) {
-                Some(digest) => digest,
-                None => return (name.to_string(), Target::unavailable()),
-            };
-            let xz_filename = filename.replace(".tar.gz", ".tar.xz");
-            let xz_digest = self.digests.remove(&xz_filename);
-
-            (name.to_string(), Target {
-                available: true,
-                url: Some(self.url(&filename)),
-                hash: Some(digest),
-                xz_url: xz_digest.as_ref().map(|_| self.url(&xz_filename)),
-                xz_hash: xz_digest,
-                components: None,
-                extensions: None,
-            })
+            if is_present {
+                let filename = self.filename(pkgname, name);
+                let digest = match self.digests.remove(&filename) {
+                    Some(digest) => digest,
+                    None => return (name.to_string(), Target::unavailable()),
+                };
+                let xz_filename = filename.replace(".tar.gz", ".tar.xz");
+                let xz_digest = self.digests.remove(&xz_filename);
+
+                (name.to_string(), Target {
+                    available: true,
+                    url: Some(self.url(&filename)),
+                    hash: Some(digest),
+                    xz_url: xz_digest.as_ref().map(|_| self.url(&xz_filename)),
+                    xz_hash: xz_digest,
+                    components: None,
+                    extensions: None,
+                })
+            } else {
+                // If the component is not present for this build add it anyway but mark it as
+                // unavailable -- this way rustup won't allow upgrades without --force
+                (name.to_string(), Target {
+                    available: false,
+                    url: None,
+                    hash: None,
+                    xz_url: None,
+                    xz_hash: None,
+                    components: None,
+                    extensions: None,
+                })
+            }
         }).collect();
 
         dst.insert(pkgname.to_string(), Package {
diff --git a/src/tools/clippy b/src/tools/clippy
-Subproject dda656652e2e1a8d615a712d7f7482c25fa0a9c
+Subproject 628934424e9c181a4162b3a5d01e4211ee98b7b