about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml13
-rw-r--r--appveyor.yml18
-rw-r--r--src/Cargo.lock15
-rw-r--r--src/Cargo.toml4
-rw-r--r--src/bootstrap/README.md4
-rw-r--r--src/bootstrap/bin/rustc.rs18
-rw-r--r--src/bootstrap/bootstrap.py31
-rw-r--r--src/bootstrap/check.rs4
-rw-r--r--src/bootstrap/compile.rs38
-rw-r--r--src/bootstrap/doc.rs4
-rw-r--r--src/bootstrap/flags.rs3
-rw-r--r--src/bootstrap/lib.rs15
-rw-r--r--src/bootstrap/metadata.rs4
-rw-r--r--src/bootstrap/mk/Makefile.in2
-rw-r--r--src/bootstrap/sanity.rs4
-rw-r--r--src/bootstrap/step.rs59
-rw-r--r--src/ci/docker/arm-android/Dockerfile46
-rwxr-xr-xsrc/ci/docker/arm-android/accept-licenses.sh (renamed from src/ci/docker/android/accept-licenses.sh)0
-rw-r--r--src/ci/docker/arm-android/install-ndk.sh33
-rw-r--r--src/ci/docker/arm-android/install-sdk.sh (renamed from src/ci/docker/android/install-sdk.sh)0
-rwxr-xr-xsrc/ci/docker/arm-android/start-emulator.sh (renamed from src/ci/docker/android/start-emulator.sh)0
-rw-r--r--src/ci/docker/armhf-gnu/Dockerfile6
-rw-r--r--src/ci/docker/cross/Dockerfile6
-rw-r--r--src/ci/docker/dist-android/Dockerfile (renamed from src/ci/docker/android/Dockerfile)20
-rw-r--r--src/ci/docker/dist-android/install-ndk.sh (renamed from src/ci/docker/android/install-ndk.sh)7
-rw-r--r--src/ci/docker/dist-arm-linux/Dockerfile6
-rw-r--r--src/ci/docker/dist-armv7-aarch64-linux/Dockerfile6
-rw-r--r--src/ci/docker/dist-freebsd/Dockerfile6
-rw-r--r--src/ci/docker/dist-mips-linux/Dockerfile6
-rw-r--r--src/ci/docker/dist-mips64-linux/Dockerfile6
-rw-r--r--src/ci/docker/dist-powerpc-linux/Dockerfile6
-rw-r--r--src/ci/docker/dist-powerpc64-linux/Dockerfile6
-rw-r--r--src/ci/docker/dist-s390x-linux-netbsd/Dockerfile6
-rw-r--r--src/ci/docker/dist-x86-linux/Dockerfile7
-rw-r--r--src/ci/docker/emscripten/Dockerfile6
-rw-r--r--src/ci/docker/i686-gnu-nopt/Dockerfile6
-rw-r--r--src/ci/docker/i686-gnu/Dockerfile6
-rw-r--r--src/ci/docker/linux-tested-targets/Dockerfile14
-rw-r--r--src/ci/docker/linux-tested-targets/build-musl.sh5
-rwxr-xr-xsrc/ci/docker/run.sh6
-rw-r--r--src/ci/docker/x86_64-gnu-aux/Dockerfile6
-rw-r--r--src/ci/docker/x86_64-gnu-debug/Dockerfile6
-rw-r--r--src/ci/docker/x86_64-gnu-distcheck/Dockerfile6
-rw-r--r--src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile6
-rw-r--r--src/ci/docker/x86_64-gnu-incremental/Dockerfile6
-rw-r--r--src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile6
-rw-r--r--src/ci/docker/x86_64-gnu-nopt/Dockerfile6
-rw-r--r--src/ci/docker/x86_64-gnu/Dockerfile6
-rwxr-xr-xsrc/ci/run.sh10
-rw-r--r--src/ci/shared.sh29
-rw-r--r--src/doc/book/src/README.md2
-rw-r--r--src/doc/book/src/SUMMARY.md12
-rw-r--r--src/doc/book/src/advanced-linking.md145
-rw-r--r--src/doc/book/src/box-syntax-and-patterns.md100
-rw-r--r--src/doc/book/src/casting-between-types.md9
-rw-r--r--src/doc/book/src/concurrency.md2
-rw-r--r--src/doc/book/src/conditional-compilation.md5
-rw-r--r--src/doc/book/src/ffi.md4
-rw-r--r--src/doc/book/src/functions.md15
-rw-r--r--src/doc/book/src/getting-started.md4
-rw-r--r--src/doc/book/src/lang-items.md84
-rw-r--r--src/doc/book/src/loops.md3
-rw-r--r--src/doc/book/src/macros.md9
-rw-r--r--src/doc/book/src/nightly-rust.md100
-rw-r--r--src/doc/book/src/procedural-macros.md75
-rw-r--r--src/doc/book/src/the-stack-and-the-heap.md2
-rw-r--r--src/doc/book/src/unsafe.md2
-rw-r--r--src/doc/book/src/using-rust-without-the-standard-library.md2
-rw-r--r--src/doc/guide-plugins.md2
-rw-r--r--src/doc/nomicon/src/exception-safety.md4
-rw-r--r--src/doc/nomicon/src/phantom-data.md22
-rw-r--r--src/doc/reference/src/attributes.md4
-rw-r--r--src/doc/reference/src/linkage.md2
-rw-r--r--src/doc/reference/src/macros.md2
-rw-r--r--src/doc/unstable-book/.gitignore1
-rw-r--r--src/doc/unstable-book/src/SUMMARY.md94
-rw-r--r--src/doc/unstable-book/src/abi-msp430-interrupt.md7
-rw-r--r--src/doc/unstable-book/src/abi-ptx.md5
-rw-r--r--src/doc/unstable-book/src/abi-sysv64.md7
-rw-r--r--src/doc/unstable-book/src/abi-unadjusted.md6
-rw-r--r--src/doc/unstable-book/src/abi-vectorcall.md7
-rw-r--r--src/doc/unstable-book/src/advanced-slice-patterns.md (renamed from src/doc/book/src/slice-patterns.md)19
-rw-r--r--src/doc/unstable-book/src/alloc-jemalloc.md62
-rw-r--r--src/doc/unstable-book/src/alloc-system.md62
-rw-r--r--src/doc/unstable-book/src/allocator.md (renamed from src/doc/book/src/custom-allocators.md)71
-rw-r--r--src/doc/unstable-book/src/allow-internal-unstable.md6
-rw-r--r--src/doc/unstable-book/src/asm.md (renamed from src/doc/book/src/inline-assembly.md)9
-rw-r--r--src/doc/unstable-book/src/associated-consts.md (renamed from src/doc/book/src/associated-constants.md)8
-rw-r--r--src/doc/unstable-book/src/associated-type-defaults.md10
-rw-r--r--src/doc/unstable-book/src/attr-literals.md10
-rw-r--r--src/doc/unstable-book/src/box-patterns.md32
-rw-r--r--src/doc/unstable-book/src/box-syntax.md22
-rw-r--r--src/doc/unstable-book/src/cfg-target-feature.md10
-rw-r--r--src/doc/unstable-book/src/cfg-target-has-atomic.md10
-rw-r--r--src/doc/unstable-book/src/cfg-target-thread-local.md10
-rw-r--r--src/doc/unstable-book/src/cfg-target-vendor.md10
-rw-r--r--src/doc/unstable-book/src/compiler-builtins.md6
-rw-r--r--src/doc/unstable-book/src/concat-idents.md10
-rw-r--r--src/doc/unstable-book/src/conservative-impl-trait.md10
-rw-r--r--src/doc/unstable-book/src/const-fn.md10
-rw-r--r--src/doc/unstable-book/src/const-indexing.md10
-rw-r--r--src/doc/unstable-book/src/custom-attribute.md10
-rw-r--r--src/doc/unstable-book/src/custom-derive.md10
-rw-r--r--src/doc/unstable-book/src/default-type-parameter-fallback.md10
-rw-r--r--src/doc/unstable-book/src/drop-types-in-const.md10
-rw-r--r--src/doc/unstable-book/src/dropck-eyepatch.md10
-rw-r--r--src/doc/unstable-book/src/dropck-parametricity.md10
-rw-r--r--src/doc/unstable-book/src/exclusive-range-pattern.md10
-rw-r--r--src/doc/unstable-book/src/field-init-shorthand.md10
-rw-r--r--src/doc/unstable-book/src/fundamental.md10
-rw-r--r--src/doc/unstable-book/src/generic-param-attrs.md10
-rw-r--r--src/doc/unstable-book/src/i128-type.md10
-rw-r--r--src/doc/unstable-book/src/inclusive-range-syntax.md10
-rw-r--r--src/doc/unstable-book/src/intrinsics.md (renamed from src/doc/book/src/intrinsics.md)13
-rw-r--r--src/doc/unstable-book/src/lang-items.md (renamed from src/doc/book/src/no-stdlib.md)102
-rw-r--r--src/doc/unstable-book/src/link-args.md32
-rw-r--r--src/doc/unstable-book/src/link-cfg.md10
-rw-r--r--src/doc/unstable-book/src/link-llvm-intrinsics.md10
-rw-r--r--src/doc/unstable-book/src/linkage.md10
-rw-r--r--src/doc/unstable-book/src/log-syntax.md10
-rw-r--r--src/doc/unstable-book/src/loop-break-value.md10
-rw-r--r--src/doc/unstable-book/src/macro-reexport.md10
-rw-r--r--src/doc/unstable-book/src/main.md10
-rw-r--r--src/doc/unstable-book/src/naked-functions.md10
-rw-r--r--src/doc/unstable-book/src/needs-allocator.md10
-rw-r--r--src/doc/unstable-book/src/needs-panic-runtime.md10
-rw-r--r--src/doc/unstable-book/src/never-type.md10
-rw-r--r--src/doc/unstable-book/src/no-core.md10
-rw-r--r--src/doc/unstable-book/src/no-debug.md10
-rw-r--r--src/doc/unstable-book/src/non-ascii-idents.md10
-rw-r--r--src/doc/unstable-book/src/omit-gdb-pretty-printer-section.md6
-rw-r--r--src/doc/unstable-book/src/on-unimplemented.md10
-rw-r--r--src/doc/unstable-book/src/optin-builtin-traits.md9
-rw-r--r--src/doc/unstable-book/src/panic-runtime.md10
-rw-r--r--src/doc/unstable-book/src/placement-in-syntax.md10
-rw-r--r--src/doc/unstable-book/src/platform-intrinsics.md10
-rw-r--r--src/doc/unstable-book/src/plugin-registrar.md13
-rw-r--r--src/doc/unstable-book/src/plugin.md263
-rw-r--r--src/doc/unstable-book/src/prelude-import.md6
-rw-r--r--src/doc/unstable-book/src/proc-macro.md10
-rw-r--r--src/doc/unstable-book/src/pub-restricted.md10
-rw-r--r--src/doc/unstable-book/src/quote.md10
-rw-r--r--src/doc/unstable-book/src/relaxed-adts.md10
-rw-r--r--src/doc/unstable-book/src/repr-simd.md10
-rw-r--r--src/doc/unstable-book/src/rustc-attrs.md10
-rw-r--r--src/doc/unstable-book/src/rustc-diagnostic-macros.md6
-rw-r--r--src/doc/unstable-book/src/sanitizer-runtime.md6
-rw-r--r--src/doc/unstable-book/src/simd-ffi.md10
-rw-r--r--src/doc/unstable-book/src/simd.md10
-rw-r--r--src/doc/unstable-book/src/slice-patterns.md27
-rw-r--r--src/doc/unstable-book/src/specialization.md8
-rw-r--r--src/doc/unstable-book/src/staged-api.md6
-rw-r--r--src/doc/unstable-book/src/start.md10
-rw-r--r--src/doc/unstable-book/src/static-nobundle.md10
-rw-r--r--src/doc/unstable-book/src/static-recursion.md10
-rw-r--r--src/doc/unstable-book/src/stmt-expr-attributes.md10
-rw-r--r--src/doc/unstable-book/src/struct-field-attributes.md10
-rw-r--r--src/doc/unstable-book/src/structural-match.md10
-rw-r--r--src/doc/unstable-book/src/target-feature.md6
-rw-r--r--src/doc/unstable-book/src/test.md (renamed from src/doc/book/src/benchmark-tests.md)12
-rw-r--r--src/doc/unstable-book/src/the-unstable-book.md22
-rw-r--r--src/doc/unstable-book/src/thread-local.md10
-rw-r--r--src/doc/unstable-book/src/trace-macros.md10
-rw-r--r--src/doc/unstable-book/src/type-ascription.md10
-rw-r--r--src/doc/unstable-book/src/unboxed-closures.md10
-rw-r--r--src/doc/unstable-book/src/untagged-unions.md10
-rw-r--r--src/doc/unstable-book/src/unwind-attributes.md6
-rw-r--r--src/doc/unstable-book/src/use-extern-macros.md10
-rw-r--r--src/doc/unstable-book/src/windows-subsystem.md10
-rw-r--r--src/liballoc_jemalloc/lib.rs12
-rw-r--r--src/libcollections/fmt.rs25
-rw-r--r--src/libcollections/string.rs45
-rw-r--r--src/libcollections/vec.rs8
-rw-r--r--src/libcompiler_builtins/build.rs10
-rw-r--r--src/libcore/slice.rs2
-rw-r--r--src/libcore/str/mod.rs14
m---------src/liblibc0
-rw-r--r--src/librustc/cfg/construct.rs36
-rw-r--r--src/librustc/dep_graph/dep_node.rs8
-rw-r--r--src/librustc/dep_graph/dep_tracking_map.rs6
-rw-r--r--src/librustc/diagnostics.rs90
-rw-r--r--src/librustc/hir/def.rs5
-rw-r--r--src/librustc/hir/intravisit.rs24
-rw-r--r--src/librustc/hir/lowering.rs196
-rw-r--r--src/librustc/hir/map/mod.rs44
-rw-r--r--src/librustc/hir/mod.rs61
-rw-r--r--src/librustc/hir/print.rs12
-rw-r--r--src/librustc/infer/error_reporting.rs53
-rw-r--r--src/librustc/infer/mod.rs31
-rw-r--r--src/librustc/lib.rs2
-rw-r--r--src/librustc/middle/astconv_util.rs83
-rw-r--r--src/librustc/middle/const_val.rs21
-rw-r--r--src/librustc/middle/cstore.rs95
-rw-r--r--src/librustc/middle/dead.rs9
-rw-r--r--src/librustc/middle/effect.rs4
-rw-r--r--src/librustc/middle/expr_use_visitor.rs1
-rw-r--r--src/librustc/middle/intrinsicck.rs8
-rw-r--r--src/librustc/middle/liveness.rs57
-rw-r--r--src/librustc/middle/mem_categorization.rs1
-rw-r--r--src/librustc/middle/resolve_lifetime.rs4
-rw-r--r--src/librustc/middle/stability.rs34
-rw-r--r--src/librustc/mir/mod.rs9
-rw-r--r--src/librustc/mir/tcx.rs2
-rw-r--r--src/librustc/mir/transform.rs4
-rw-r--r--src/librustc/session/config.rs73
-rw-r--r--src/librustc/session/mod.rs13
-rw-r--r--src/librustc/traits/error_reporting.rs458
-rw-r--r--src/librustc/traits/fulfill.rs139
-rw-r--r--src/librustc/traits/mod.rs3
-rw-r--r--src/librustc/traits/object_safety.rs20
-rw-r--r--src/librustc/traits/project.rs44
-rw-r--r--src/librustc/traits/select.rs30
-rw-r--r--src/librustc/traits/specialize/mod.rs2
-rw-r--r--src/librustc/traits/specialize/specialization_graph.rs2
-rw-r--r--src/librustc/traits/structural_impls.rs27
-rw-r--r--src/librustc/traits/util.rs2
-rw-r--r--src/librustc/ty/adjustment.rs4
-rw-r--r--src/librustc/ty/contents.rs2
-rw-r--r--src/librustc/ty/context.rs211
-rw-r--r--src/librustc/ty/error.rs8
-rw-r--r--src/librustc/ty/fast_reject.rs2
-rw-r--r--src/librustc/ty/flags.rs10
-rw-r--r--src/librustc/ty/fold.rs13
-rw-r--r--src/librustc/ty/inhabitedness/mod.rs2
-rw-r--r--src/librustc/ty/item_path.rs2
-rw-r--r--src/librustc/ty/layout.rs13
-rw-r--r--src/librustc/ty/maps.rs425
-rw-r--r--src/librustc/ty/mod.rs409
-rw-r--r--src/librustc/ty/relate.rs24
-rw-r--r--src/librustc/ty/structural_impls.rs90
-rw-r--r--src/librustc/ty/sty.rs72
-rw-r--r--src/librustc/ty/subst.rs14
-rw-r--r--src/librustc/ty/trait_def.rs75
-rw-r--r--src/librustc/ty/util.rs125
-rw-r--r--src/librustc/ty/walk.rs10
-rw-r--r--src/librustc/util/ppaux.rs57
-rw-r--r--src/librustc_back/target/mod.rs1
-rw-r--r--src/librustc_back/target/sparcv9_sun_solaris.rs35
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs2
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs2
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/move_error.rs2
-rw-r--r--src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs3
-rw-r--r--src/librustc_borrowck/borrowck/mir/elaborate_drops.rs11
-rw-r--r--src/librustc_borrowck/borrowck/mir/gather_moves.rs2
-rw-r--r--src/librustc_borrowck/borrowck/mir/mod.rs2
-rw-r--r--src/librustc_const_eval/_match.rs117
-rw-r--r--src/librustc_const_eval/check_match.rs38
-rw-r--r--src/librustc_const_eval/diagnostics.rs16
-rw-r--r--src/librustc_const_eval/eval.rs700
-rw-r--r--src/librustc_const_eval/lib.rs1
-rw-r--r--src/librustc_const_eval/pattern.rs24
-rw-r--r--src/librustc_const_math/float.rs47
-rw-r--r--src/librustc_const_math/int.rs248
-rw-r--r--src/librustc_const_math/lib.rs2
-rw-r--r--src/librustc_driver/driver.rs32
-rw-r--r--src/librustc_driver/pretty.rs12
-rw-r--r--src/librustc_driver/test.rs16
-rw-r--r--src/librustc_incremental/calculate_svh/svh_visitor.rs12
-rw-r--r--src/librustc_incremental/persist/data.rs5
-rw-r--r--src/librustc_incremental/persist/dirty_clean.rs6
-rw-r--r--src/librustc_incremental/persist/load.rs12
-rw-r--r--src/librustc_incremental/persist/preds/mod.rs21
-rw-r--r--src/librustc_incremental/persist/save.rs7
-rw-r--r--src/librustc_lint/bad_style.rs2
-rw-r--r--src/librustc_lint/builtin.rs12
-rw-r--r--src/librustc_lint/types.rs65
-rw-r--r--src/librustc_metadata/creader.rs14
-rw-r--r--src/librustc_metadata/cstore.rs2
-rw-r--r--src/librustc_metadata/cstore_impl.rs201
-rw-r--r--src/librustc_metadata/decoder.rs195
-rw-r--r--src/librustc_metadata/encoder.rs104
-rw-r--r--src/librustc_metadata/lib.rs1
-rw-r--r--src/librustc_metadata/schema.rs37
-rw-r--r--src/librustc_mir/build/expr/as_lvalue.rs1
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs4
-rw-r--r--src/librustc_mir/build/expr/category.rs1
-rw-r--r--src/librustc_mir/build/expr/into.rs3
-rw-r--r--src/librustc_mir/build/matches/mod.rs6
-rw-r--r--src/librustc_mir/build/matches/test.rs13
-rw-r--r--src/librustc_mir/build/mod.rs11
-rw-r--r--src/librustc_mir/build/scope.rs22
-rw-r--r--src/librustc_mir/hair/cx/expr.rs37
-rw-r--r--src/librustc_mir/hair/cx/mod.rs13
-rw-r--r--src/librustc_mir/hair/mod.rs7
-rw-r--r--src/librustc_mir/lib.rs6
-rw-r--r--src/librustc_mir/mir_map.rs164
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs154
-rw-r--r--src/librustc_mir/transform/type_check.rs8
-rw-r--r--src/librustc_passes/consts.rs19
-rw-r--r--src/librustc_passes/diagnostics.rs16
-rw-r--r--src/librustc_passes/loops.rs49
-rw-r--r--src/librustc_passes/mir_stats.rs2
-rw-r--r--src/librustc_passes/rvalues.rs2
-rw-r--r--src/librustc_passes/static_recursion.rs24
-rw-r--r--src/librustc_privacy/lib.rs12
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs7
-rw-r--r--src/librustc_resolve/diagnostics.rs27
-rw-r--r--src/librustc_resolve/lib.rs119
-rw-r--r--src/librustc_resolve/macros.rs65
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs4
-rw-r--r--src/librustc_save_analysis/lib.rs6
-rw-r--r--src/librustc_save_analysis/span_utils.rs67
-rw-r--r--src/librustc_trans/abi.rs24
-rw-r--r--src/librustc_trans/base.rs29
-rw-r--r--src/librustc_trans/builder.rs9
-rw-r--r--src/librustc_trans/callee.rs90
-rw-r--r--src/librustc_trans/collector.rs40
-rw-r--r--src/librustc_trans/common.rs23
-rw-r--r--src/librustc_trans/consts.rs10
-rw-r--r--src/librustc_trans/context.rs16
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs18
-rw-r--r--src/librustc_trans/debuginfo/mod.rs18
-rw-r--r--src/librustc_trans/debuginfo/type_names.rs9
-rw-r--r--src/librustc_trans/debuginfo/utils.rs8
-rw-r--r--src/librustc_trans/declare.rs8
-rw-r--r--src/librustc_trans/disr.rs38
-rw-r--r--src/librustc_trans/glue.rs21
-rw-r--r--src/librustc_trans/intrinsic.rs34
-rw-r--r--src/librustc_trans/meth.rs8
-rw-r--r--src/librustc_trans/mir/block.rs15
-rw-r--r--src/librustc_trans/mir/constant.rs49
-rw-r--r--src/librustc_trans/mir/mod.rs21
-rw-r--r--src/librustc_trans/mir/rvalue.rs30
-rw-r--r--src/librustc_trans/trans_item.rs19
-rw-r--r--src/librustc_trans/type_of.rs6
-rw-r--r--src/librustc_typeck/astconv.rs315
-rw-r--r--src/librustc_typeck/check/callee.rs36
-rw-r--r--src/librustc_typeck/check/closure.rs44
-rw-r--r--src/librustc_typeck/check/coercion.rs73
-rw-r--r--src/librustc_typeck/check/compare_method.rs69
-rw-r--r--src/librustc_typeck/check/demand.rs4
-rw-r--r--src/librustc_typeck/check/dropck.rs25
-rw-r--r--src/librustc_typeck/check/intrinsic.rs156
-rw-r--r--src/librustc_typeck/check/method/confirm.rs19
-rw-r--r--src/librustc_typeck/check/method/mod.rs17
-rw-r--r--src/librustc_typeck/check/method/probe.rs6
-rw-r--r--src/librustc_typeck/check/method/suggest.rs36
-rw-r--r--src/librustc_typeck/check/mod.rs634
-rw-r--r--src/librustc_typeck/check/regionck.rs21
-rw-r--r--src/librustc_typeck/check/upvar.rs2
-rw-r--r--src/librustc_typeck/check/wfcheck.rs107
-rw-r--r--src/librustc_typeck/check/writeback.rs112
-rw-r--r--src/librustc_typeck/check_unused.rs3
-rw-r--r--src/librustc_typeck/coherence/builtin.rs59
-rw-r--r--src/librustc_typeck/coherence/inherent.rs356
-rw-r--r--src/librustc_typeck/coherence/mod.rs210
-rw-r--r--src/librustc_typeck/coherence/orphan.rs227
-rw-r--r--src/librustc_typeck/coherence/overlap.rs213
-rw-r--r--src/librustc_typeck/coherence/unsafety.rs17
-rw-r--r--src/librustc_typeck/collect.rs2127
-rw-r--r--src/librustc_typeck/diagnostics.rs156
-rw-r--r--src/librustc_typeck/impl_wf_check.rs43
-rw-r--r--src/librustc_typeck/lib.rs117
-rw-r--r--src/librustc_typeck/variance/constraints.rs33
-rw-r--r--src/librustc_typeck/variance/solve.rs2
-rw-r--r--src/librustc_typeck/variance/terms.rs9
-rw-r--r--src/librustdoc/clean/inline.rs17
-rw-r--r--src/librustdoc/clean/mod.rs41
-rw-r--r--src/librustdoc/core.rs10
-rw-r--r--src/librustdoc/test.rs12
-rw-r--r--src/librustdoc/visit_ast.rs2
-rw-r--r--src/librustdoc/visit_lib.rs2
-rw-r--r--src/libstd/build.rs4
-rw-r--r--src/libstd/collections/hash/map.rs34
-rw-r--r--src/libstd/panic.rs2
-rw-r--r--src/libstd/panicking.rs10
-rw-r--r--src/libstd/sync/barrier.rs76
-rw-r--r--src/libstd/sync/mutex.rs4
-rw-r--r--src/libstd/sys/redox/backtrace.rs11
-rw-r--r--src/libstd/sys/redox/mod.rs2
-rw-r--r--src/libstd/sys/redox/net/tcp.rs4
-rw-r--r--src/libstd/sys/redox/net/udp.rs8
-rw-r--r--src/libstd/sys/unix/backtrace/mod.rs5
-rw-r--r--src/libstd/sys/unix/backtrace/printing/dladdr.rs62
-rw-r--r--src/libstd/sys/unix/backtrace/printing/mod.rs7
-rw-r--r--src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs52
-rw-r--r--src/libstd/sys/unix/backtrace/tracing/gcc_s.rs161
-rw-r--r--src/libstd/sys/unix/fs.rs27
-rw-r--r--src/libstd/sys/unix/os.rs2
-rw-r--r--src/libstd/sys/unix/process/magenta.rs2
-rw-r--r--src/libstd/sys/unix/process/process_fuchsia.rs4
-rw-r--r--src/libstd/sys/windows/backtrace/backtrace_gnu.rs (renamed from src/libstd/sys/windows/backtrace_gnu.rs)0
-rw-r--r--src/libstd/sys/windows/backtrace/mod.rs (renamed from src/libstd/sys/windows/backtrace.rs)151
-rw-r--r--src/libstd/sys/windows/backtrace/printing/mod.rs20
-rw-r--r--src/libstd/sys/windows/backtrace/printing/msvc.rs83
-rw-r--r--src/libstd/sys/windows/printing/msvc.rs73
-rw-r--r--src/libstd/sys_common/backtrace.rs279
-rw-r--r--src/libstd/sys_common/gnu/libbacktrace.rs344
-rw-r--r--src/libstd/thread/mod.rs9
-rw-r--r--src/libsyntax/attr.rs23
-rw-r--r--src/libsyntax/ext/base.rs2
-rw-r--r--src/libsyntax/feature_gate.rs21
-rw-r--r--src/libsyntax/parse/lexer/mod.rs46
-rw-r--r--src/libsyntax/visit.rs49
-rw-r--r--src/libsyntax_ext/deriving/generic/mod.rs2
-rw-r--r--src/libtest/lib.rs6
-rw-r--r--src/libtest/stats.rs4
-rw-r--r--src/libunwind/libunwind.rs2
-rw-r--r--src/rustc/std_shim/Cargo.toml46
-rw-r--r--src/rustc/test_shim/Cargo.toml16
-rw-r--r--src/test/COMPILER_TESTS.md (renamed from COMPILER_TESTS.md)0
-rw-r--r--src/test/codegen/function-arguments.rs4
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs29
-rw-r--r--src/test/compile-fail/E0081.rs6
-rw-r--r--src/test/compile-fail/E0117.rs2
-rw-r--r--src/test/compile-fail/E0306.rs24
-rw-r--r--src/test/compile-fail/asm-bad-clobber.rs1
-rw-r--r--src/test/compile-fail/asm-in-bad-modifier.rs1
-rw-r--r--src/test/compile-fail/asm-misplaced-option.rs1
-rw-r--r--src/test/compile-fail/asm-out-assign-imm.rs1
-rw-r--r--src/test/compile-fail/asm-out-no-modifier.rs1
-rw-r--r--src/test/compile-fail/asm-out-read-uninit.rs1
-rw-r--r--src/test/compile-fail/associated-const-array-len.rs3
-rw-r--r--src/test/compile-fail/associated-const-type-parameter-arrays-2.rs2
-rw-r--r--src/test/compile-fail/associated-const-type-parameter-arrays.rs2
-rw-r--r--src/test/compile-fail/closure-no-fn.rs24
-rw-r--r--src/test/compile-fail/coherence-cross-crate-conflict.rs1
-rw-r--r--src/test/compile-fail/coherence-default-trait-impl.rs2
-rw-r--r--src/test/compile-fail/coherence-impls-sized.rs12
-rw-r--r--src/test/compile-fail/const-array-oob.rs4
-rw-r--r--src/test/compile-fail/const-block-non-item-statement-2.rs26
-rw-r--r--src/test/compile-fail/const-block-non-item-statement.rs21
-rw-r--r--src/test/compile-fail/const-call.rs6
-rw-r--r--src/test/compile-fail/const-eval-overflow-4b.rs6
-rw-r--r--src/test/compile-fail/const-eval-span.rs7
-rw-r--r--src/test/compile-fail/const-integer-bool-ops.rs79
-rw-r--r--src/test/compile-fail/const-tup-index-span.rs4
-rw-r--r--src/test/compile-fail/cycle-projection-based-on-where-clause.rs1
-rw-r--r--src/test/compile-fail/cycle-trait-default-type-trait.rs1
-rw-r--r--src/test/compile-fail/cycle-trait-supertrait-indirect.rs6
-rw-r--r--src/test/compile-fail/default_ty_param_conflict.rs2
-rw-r--r--src/test/compile-fail/default_ty_param_conflict_cross_crate.rs2
-rw-r--r--src/test/compile-fail/discrim-ill-typed.rs16
-rw-r--r--src/test/compile-fail/enum-discrim-too-small.rs16
-rw-r--r--src/test/compile-fail/feature-gate-closure_to_fn_coercion.rs45
-rw-r--r--src/test/compile-fail/feature-gate-static_recursion.rs49
-rw-r--r--src/test/compile-fail/generic-non-trailing-defaults.rs4
-rw-r--r--src/test/compile-fail/generic-type-params-forward-mention.rs2
-rw-r--r--src/test/compile-fail/impl-trait/auto-trait-leak.rs17
-rw-r--r--src/test/compile-fail/impl-trait/equality.rs17
-rw-r--r--src/test/compile-fail/invalid-path-in-const.rs3
-rw-r--r--src/test/compile-fail/issue-12511.rs7
-rw-r--r--src/test/compile-fail/issue-15524.rs18
-rw-r--r--src/test/compile-fail/issue-18183.rs4
-rw-r--r--src/test/compile-fail/issue-20772.rs1
-rw-r--r--src/test/compile-fail/issue-21177.rs3
-rw-r--r--src/test/compile-fail/issue-22933-2.rs6
-rw-r--r--src/test/compile-fail/issue-23217.rs3
-rw-r--r--src/test/compile-fail/issue-28586.rs3
-rw-r--r--src/test/compile-fail/issue-3008-2.rs2
-rw-r--r--src/test/compile-fail/issue-31910.rs4
-rw-r--r--src/test/compile-fail/issue-3521.rs4
-rw-r--r--src/test/compile-fail/issue-35869.rs4
-rw-r--r--src/test/compile-fail/issue-37131.rs4
-rw-r--r--src/test/compile-fail/issue-37576.rs55
-rw-r--r--src/test/compile-fail/issue-39559.rs10
-rw-r--r--src/test/compile-fail/issue-8761.rs4
-rw-r--r--src/test/compile-fail/match-privately-empty.rs30
-rw-r--r--src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs1
-rw-r--r--src/test/compile-fail/non-constant-expr-for-vec-repeat.rs2
-rw-r--r--src/test/compile-fail/resolve-label.rs3
-rw-r--r--src/test/compile-fail/resolve-self-in-impl.rs28
-rw-r--r--src/test/compile-fail/uninhabited-matches-feature-gated.rs10
-rw-r--r--src/test/incremental/hashes/enum_defs.rs5
-rw-r--r--src/test/incremental/issue-39828/auxiliary/generic.rs18
-rw-r--r--src/test/incremental/issue-39828/issue-39828.rs (renamed from src/libstd/sys/windows/printing/gnu.rs)26
-rw-r--r--src/test/mir-opt/simplify_if.rs2
-rw-r--r--src/test/parse-fail/range_inclusive_gate.rs2
-rw-r--r--src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot16
-rw-r--r--src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot48
-rw-r--r--src/test/run-make/sysroot-crates-are-unstable/Makefile34
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/auxiliary/issue-40001-plugin.rs66
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/issue-40001.rs (renamed from src/test/compile-fail/E0079.rs)12
-rw-r--r--src/test/run-pass/associated-types-sugar-path.rs3
-rw-r--r--src/test/run-pass/auxiliary/clibrary.rs (renamed from src/rustc/test_shim/lib.rs)8
-rw-r--r--src/test/run-pass/auxiliary/issue_39823.rs (renamed from src/test/compile-fail/static-recursion-gate.rs)13
-rw-r--r--src/test/run-pass/backtrace-debuginfo.rs4
-rw-r--r--src/test/run-pass/backtrace.rs3
-rw-r--r--src/test/run-pass/closure-to-fn-coercion.rs41
-rw-r--r--src/test/run-pass/impl-trait/auto-trait-leak.rs13
-rw-r--r--src/test/run-pass/impl-trait/equality.rs13
-rw-r--r--src/test/run-pass/issue-2063-resource.rs2
-rw-r--r--src/test/run-pass/issue-2063.rs2
-rw-r--r--src/test/run-pass/issue-25145.rs (renamed from src/test/compile-fail/issue-25145.rs)6
-rw-r--r--src/test/run-pass/issue-38972.rs (renamed from src/rustc/std_shim/lib.rs)22
-rw-r--r--src/test/run-pass/issue-39548.rs (renamed from src/libstd/sys/unix/backtrace/printing/gnu.rs)8
-rw-r--r--src/test/run-pass/issue-39823.rs34
-rw-r--r--src/test/run-pass/iter-sum-overflow-overflow-checks.rs35
-rw-r--r--src/test/run-pass/lib-defaults.rs23
-rw-r--r--src/test/run-pass/loop-break-value.rs10
-rw-r--r--src/test/run-pass/panic-safe.rs5
-rw-r--r--src/test/run-pass/static-recursive.rs2
-rw-r--r--src/test/ui/mismatched_types/E0053.stderr3
-rw-r--r--src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr3
-rw-r--r--src/test/ui/resolve/issue-23305.stderr11
-rw-r--r--src/test/ui/resolve/levenshtein.stderr8
-rw-r--r--src/test/ui/span/E0204.stderr18
-rw-r--r--src/tools/build-manifest/src/main.rs28
-rw-r--r--src/tools/compiletest/src/runtest.rs17
-rw-r--r--src/tools/tidy/src/features.rs6
500 files changed, 9579 insertions, 8178 deletions
diff --git a/.travis.yml b/.travis.yml
index c4b97def312..442d02aca78 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,10 +12,11 @@ matrix:
   fast_finish: true
   include:
     # Linux builders, all docker images
-    - env: IMAGE=android DEPLOY=1
+    - env: IMAGE=arm-android
     - env: IMAGE=armhf-gnu
     - env: IMAGE=cross DEPLOY=1
     - env: IMAGE=linux-tested-targets DEPLOY=1
+    - env: IMAGE=dist-android DEPLOY=1
     - env: IMAGE=dist-arm-linux DEPLOY=1
     - env: IMAGE=dist-armv7-aarch64-linux DEPLOY=1
     - env: IMAGE=dist-freebsd DEPLOY=1
@@ -45,8 +46,8 @@ matrix:
       os: osx
       osx_image: xcode8.2
       install: &osx_install_sccache >
-        curl -L https://api.pub.build.mozilla.org/tooltool/sha512/d0025b286468cc5ada83b23d3fafbc936b9f190eaa7d4a981715b18e8e3bf720a7bcee7bfe758cfdeb8268857f6098fd52dcdd8818232692a30ce91039936596 |
-          tar xJf - -C /usr/local/bin --strip-components=1
+        travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-apple-darwin &&
+          chmod +x /usr/local/bin/sccache
     - env: >
         RUST_CHECK_TARGET=check
         RUST_CONFIGURE_ARGS=--build=i686-apple-darwin
@@ -63,8 +64,10 @@ matrix:
       os: osx
       osx_image: xcode8.2
       install: >
-        curl -L https://api.pub.build.mozilla.org/tooltool/sha512/d0025b286468cc5ada83b23d3fafbc936b9f190eaa7d4a981715b18e8e3bf720a7bcee7bfe758cfdeb8268857f6098fd52dcdd8818232692a30ce91039936596 |
-          tar xJf - -C /usr/local/bin --strip-components=1 && brew uninstall --ignore-dependencies openssl && brew install openssl --universal --without-test
+        travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-apple-darwin &&
+          chmod +x /usr/local/bin/sccache &&
+          brew uninstall --ignore-dependencies openssl &&
+          brew install openssl --universal --without-test
     - env: >
         RUST_CHECK_TARGET=dist
         RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended"
diff --git a/appveyor.yml b/appveyor.yml
index 44791b033a6..9a0a4d81f9b 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -103,7 +103,7 @@ install:
   # /usr/bin/python2.7.exe is not. To ensure we use the right interpreter we
   # move `C:\Python27` ahead in PATH and then also make sure the `python2.7.exe`
   # file exists in there (which it doesn't by default).
-  - if defined MINGW_URL appveyor DownloadFile %MINGW_URL%/%MINGW_ARCHIVE%
+  - if defined MINGW_URL appveyor-retry appveyor DownloadFile %MINGW_URL%/%MINGW_ARCHIVE%
   - if defined MINGW_URL 7z x -y %MINGW_ARCHIVE% > nul
   - if defined MINGW_URL set PATH=%CD%\%MINGW_DIR%\bin;C:\msys64\usr\bin;%PATH%
 
@@ -115,14 +115,12 @@ install:
   - set PATH=C:\Python27;%PATH%
 
   # Download and install sccache
-  - appveyor DownloadFile https://api.pub.build.mozilla.org/tooltool/sha512/%SCCACHE_DIGEST%
-  - mv %SCCACHE_DIGEST% sccache.tar.bz2
-  - 7z x -y sccache.tar.bz2 > nul
-  - 7z x -y sccache.tar > nul
-  - set PATH=%PATH%;%CD%\sccache2
+  - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-pc-windows-msvc
+  - mv 2017-02-25-sccache-x86_64-pc-windows-msvc sccache
+  - set PATH=%PATH%;%CD%
 
   # Install InnoSetup to get `iscc` used to produce installers
-  - choco install -y InnoSetup
+  - appveyor-retry choco install -y InnoSetup
   - set PATH="C:\Program Files (x86)\Inno Setup 5";%PATH%
 
   # Help debug some handle issues on AppVeyor
@@ -133,18 +131,14 @@ install:
   - handle.exe -accepteula -help
 
 test_script:
-  - git submodule update --init
+  - appveyor-retry sh -c 'git submodule deinit -f . && git submodule update --init'
   - set SRC=.
   - set NO_CCACHE=1
   - sh src/ci/run.sh
 
 cache:
-  - "build/i686-pc-windows-gnu/llvm -> src/rustllvm/llvm-auto-clean-trigger"
-  - "build/x86_64-pc-windows-gnu/llvm -> src/rustllvm/llvm-auto-clean-trigger"
   - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger"
   - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger"
-  - "i686-pc-windows-gnu/llvm -> src/rustllvm/llvm-auto-clean-trigger"
-  - "x86_64-pc-windows-gnu/llvm -> src/rustllvm/llvm-auto-clean-trigger"
   - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger"
   - "x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger"
 
diff --git a/src/Cargo.lock b/src/Cargo.lock
index f17095f9609..16a641cc96d 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -812,14 +812,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "std_shim"
-version = "0.0.0"
-dependencies = [
- "core 0.0.0",
- "std 0.0.0",
-]
-
-[[package]]
 name = "std_unicode"
 version = "0.0.0"
 dependencies = [
@@ -885,13 +877,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "test_shim"
-version = "0.0.0"
-dependencies = [
- "test 0.0.0",
-]
-
-[[package]]
 name = "thread-id"
 version = "3.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/Cargo.toml b/src/Cargo.toml
index d8dedd11f35..0dafbb8428e 100644
--- a/src/Cargo.toml
+++ b/src/Cargo.toml
@@ -2,8 +2,8 @@
 members = [
   "bootstrap",
   "rustc",
-  "rustc/std_shim",
-  "rustc/test_shim",
+  "libstd",
+  "libtest",
   "tools/cargotest",
   "tools/compiletest",
   "tools/error_index_generator",
diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md
index ac84edb4038..2f7757fb1d5 100644
--- a/src/bootstrap/README.md
+++ b/src/bootstrap/README.md
@@ -267,8 +267,8 @@ build/
 The current build is unfortunately not quite as simple as `cargo build` in a
 directory, but rather the compiler is split into three different Cargo projects:
 
-* `src/rustc/std_shim` - a project which builds and compiles libstd
-* `src/rustc/test_shim` - a project which builds and compiles libtest
+* `src/libstd` - the standard library
+* `src/libtest` - testing support, depends on libstd
 * `src/rustc` - the actual compiler itself
 
 Each "project" has a corresponding Cargo.lock file with all dependencies, and
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index 62e476bd737..a996240f616 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -68,6 +68,7 @@ fn main() {
     };
     let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
     let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
+    let mut on_fail = env::var_os("RUSTC_ON_FAIL").map(|of| Command::new(of));
 
     let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc));
     let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir));
@@ -217,9 +218,20 @@ fn main() {
     }
 
     // Actually run the compiler!
-    std::process::exit(match exec_cmd(&mut cmd) {
-        Ok(s) => s.code().unwrap_or(0xfe),
-        Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e),
+    std::process::exit(if let Some(ref mut on_fail) = on_fail {
+        match cmd.status() {
+            Ok(s) if s.success() => 0,
+            _ => {
+                println!("\nDid not run successfully:\n{:?}\n-------------", cmd);
+                exec_cmd(on_fail).expect("could not run the backup command");
+                1
+            }
+        }
+    } else {
+        std::process::exit(match exec_cmd(&mut cmd) {
+            Ok(s) => s.code().unwrap_or(0xfe),
+            Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e),
+        })
     })
 }
 
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 7ca7ef4bd72..c1ee0c29ac9 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -59,6 +59,16 @@ def delete_if_present(path, verbose):
 
 
 def download(path, url, probably_big, verbose):
+    for x in range(0, 4):
+        try:
+            _download(path, url, probably_big, verbose, True)
+            return
+        except RuntimeError:
+            print("\nspurious failure, trying again")
+    _download(path, url, probably_big, verbose, False)
+
+
+def _download(path, url, probably_big, verbose, exception):
     if probably_big or verbose:
         print("downloading {}".format(url))
     # see http://serverfault.com/questions/301128/how-to-download
@@ -66,13 +76,16 @@ def download(path, url, probably_big, verbose):
         run(["PowerShell.exe", "/nologo", "-Command",
              "(New-Object System.Net.WebClient)"
              ".DownloadFile('{}', '{}')".format(url, path)],
-            verbose=verbose)
+            verbose=verbose,
+            exception=exception)
     else:
         if probably_big or verbose:
             option = "-#"
         else:
             option = "-s"
-        run(["curl", option, "--retry", "3", "-Sf", "-o", path, url], verbose=verbose)
+        run(["curl", option, "--retry", "3", "-Sf", "-o", path, url],
+            verbose=verbose,
+            exception=exception)
 
 
 def verify(path, sha_path, verbose):
@@ -112,7 +125,7 @@ def unpack(tarball, dst, verbose=False, match=None):
             shutil.move(tp, fp)
     shutil.rmtree(os.path.join(dst, fname))
 
-def run(args, verbose=False):
+def run(args, verbose=False, exception=False):
     if verbose:
         print("running: " + ' '.join(args))
     sys.stdout.flush()
@@ -122,7 +135,7 @@ def run(args, verbose=False):
     code = ret.wait()
     if code != 0:
         err = "failed to run: " + ' '.join(args)
-        if verbose:
+        if verbose or exception:
             raise RuntimeError(err)
         sys.exit(err)
 
@@ -342,8 +355,12 @@ class RustBuild(object):
         env = os.environ.copy()
         env["CARGO_TARGET_DIR"] = build_dir
         env["RUSTC"] = self.rustc()
-        env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib")
-        env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib")
+        env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \
+                                 (os.pathsep + env["LD_LIBRARY_PATH"]) \
+                                 if "LD_LIBRARY_PATH" in env else ""
+        env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \
+                                   (os.pathsep + env["DYLD_LIBRARY_PATH"]) \
+                                   if "DYLD_LIBRARY_PATH" in env else ""
         env["PATH"] = os.path.join(self.bin_root(), "bin") + \
                       os.pathsep + env["PATH"]
         if not os.path.isfile(self.cargo()):
@@ -472,6 +489,8 @@ class RustBuild(object):
             ostype += 'abi64'
         elif cputype in {'powerpc', 'ppc', 'ppc64'}:
             cputype = 'powerpc'
+        elif cputype == 'sparcv9':
+            pass
         elif cputype in {'amd64', 'x86_64', 'x86-64', 'x64'}:
             cputype = 'x86_64'
         else:
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 00758460bec..dfe96b51799 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -346,10 +346,10 @@ pub fn krate(build: &Build,
              krate: Option<&str>) {
     let (name, path, features, root) = match mode {
         Mode::Libstd => {
-            ("libstd", "src/rustc/std_shim", build.std_features(), "std_shim")
+            ("libstd", "src/libstd", build.std_features(), "std")
         }
         Mode::Libtest => {
-            ("libtest", "src/rustc/test_shim", String::new(), "test_shim")
+            ("libtest", "src/libtest", String::new(), "test")
         }
         Mode::Librustc => {
             ("librustc", "src/rustc", build.rustc_features(), "rustc-main")
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 0b1a1f39d8d..cea8b133666 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -21,7 +21,7 @@ use std::fs::{self, File};
 use std::path::{Path, PathBuf};
 use std::process::Command;
 
-use build_helper::{output, mtime};
+use build_helper::{output, mtime, up_to_date};
 use filetime::FileTime;
 
 use util::{exe, libdir, is_dylib, copy};
@@ -64,7 +64,7 @@ pub fn std(build: &Build, target: &str, compiler: &Compiler) {
     }
     cargo.arg("--features").arg(features)
          .arg("--manifest-path")
-         .arg(build.src.join("src/rustc/std_shim/Cargo.toml"));
+         .arg(build.src.join("src/libstd/Cargo.toml"));
 
     if let Some(target) = build.config.target_config.get(target) {
         if let Some(ref jemalloc) = target.jemalloc {
@@ -132,21 +132,29 @@ pub fn build_startup_objects(build: &Build, for_compiler: &Compiler, target: &st
 
     let compiler = Compiler::new(0, &build.config.build);
     let compiler_path = build.compiler_path(&compiler);
-    let into = build.sysroot_libdir(for_compiler, target);
-    t!(fs::create_dir_all(&into));
-
-    for file in t!(fs::read_dir(build.src.join("src/rtstartup"))) {
-        let file = t!(file);
-        let mut cmd = Command::new(&compiler_path);
-        build.run(cmd.env("RUSTC_BOOTSTRAP", "1")
-                     .arg("--target").arg(target)
-                     .arg("--emit=obj")
-                     .arg("--out-dir").arg(&into)
-                     .arg(file.path()));
+    let src_dir = &build.src.join("src/rtstartup");
+    let dst_dir = &build.native_dir(target).join("rtstartup");
+    let sysroot_dir = &build.sysroot_libdir(for_compiler, target);
+    t!(fs::create_dir_all(dst_dir));
+    t!(fs::create_dir_all(sysroot_dir));
+
+    for file in &["rsbegin", "rsend"] {
+        let src_file = &src_dir.join(file.to_string() + ".rs");
+        let dst_file = &dst_dir.join(file.to_string() + ".o");
+        if !up_to_date(src_file, dst_file) {
+            let mut cmd = Command::new(&compiler_path);
+            build.run(cmd.env("RUSTC_BOOTSTRAP", "1")
+                        .arg("--target").arg(target)
+                        .arg("--emit=obj")
+                        .arg("--out-dir").arg(dst_dir)
+                        .arg(src_file));
+        }
+
+        copy(dst_file, &sysroot_dir.join(file.to_string() + ".o"));
     }
 
     for obj in ["crt2.o", "dllcrt2.o"].iter() {
-        copy(&compiler_file(build.cc(target), obj), &into.join(obj));
+        copy(&compiler_file(build.cc(target), obj), &sysroot_dir.join(obj));
     }
 }
 
@@ -162,7 +170,7 @@ pub fn test(build: &Build, target: &str, compiler: &Compiler) {
     build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target));
     let mut cargo = build.cargo(compiler, Mode::Libtest, target, "build");
     cargo.arg("--manifest-path")
-         .arg(build.src.join("src/rustc/test_shim/Cargo.toml"));
+         .arg(build.src.join("src/libtest/Cargo.toml"));
     build.run(&mut cargo);
     update_mtime(build, &libtest_stamp(build, compiler, target));
 }
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index f4a66714166..5fd6570e161 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -148,7 +148,7 @@ pub fn std(build: &Build, stage: u32, target: &str) {
 
     let mut cargo = build.cargo(&compiler, Mode::Libstd, target, "doc");
     cargo.arg("--manifest-path")
-         .arg(build.src.join("src/rustc/std_shim/Cargo.toml"))
+         .arg(build.src.join("src/libstd/Cargo.toml"))
          .arg("--features").arg(build.std_features());
 
     // We don't want to build docs for internal std dependencies unless
@@ -194,7 +194,7 @@ pub fn test(build: &Build, stage: u32, target: &str) {
 
     let mut cargo = build.cargo(&compiler, Mode::Libtest, target, "doc");
     cargo.arg("--manifest-path")
-         .arg(build.src.join("src/rustc/test_shim/Cargo.toml"));
+         .arg(build.src.join("src/libtest/Cargo.toml"));
     build.run(&mut cargo);
     cp_r(&out_dir, &out)
 }
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index c5bbfd89b27..b55f3d710ca 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -28,6 +28,7 @@ use step;
 /// Deserialized version of all flags for this compile.
 pub struct Flags {
     pub verbose: usize, // verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
+    pub on_fail: Option<String>,
     pub stage: Option<u32>,
     pub keep_stage: Option<u32>,
     pub build: String,
@@ -81,6 +82,7 @@ impl Flags {
         opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
         opts.optmulti("", "host", "host targets to build", "HOST");
         opts.optmulti("", "target", "target targets to build", "TARGET");
+        opts.optopt("", "on-fail", "command to run on failure", "CMD");
         opts.optopt("", "stage", "stage to build", "N");
         opts.optopt("", "keep-stage", "stage to keep without recompiling", "N");
         opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
@@ -283,6 +285,7 @@ To learn more about a subcommand, run `./x.py <command> -h`
         Flags {
             verbose: m.opt_count("v"),
             stage: stage,
+            on_fail: m.opt_str("on-fail"),
             keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()),
             build: m.opt_str("build").unwrap_or_else(|| {
                 env::var("BUILD").unwrap()
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 7bd611eb53e..2b34142b3b0 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -499,6 +499,10 @@ impl Build {
             cargo.env("RUSTC_INCREMENTAL", incr_dir);
         }
 
+        if let Some(ref on_fail) = self.flags.on_fail {
+            cargo.env("RUSTC_ON_FAIL", on_fail);
+        }
+
         let verbose = cmp::max(self.config.verbose, self.flags.verbose);
         cargo.env("RUSTC_VERBOSE", format!("{}", verbose));
 
@@ -828,17 +832,6 @@ impl Build {
         if target.contains("apple-darwin") {
             base.push("-stdlib=libc++".into());
         }
-        // This is a hack, because newer binutils broke things on some vms/distros
-        // (i.e., linking against unknown relocs disabled by the following flag)
-        // See: https://github.com/rust-lang/rust/issues/34978
-        match target {
-            "i586-unknown-linux-gnu" |
-            "i686-unknown-linux-musl" |
-            "x86_64-unknown-linux-musl" => {
-                base.push("-Wa,-mrelax-relocations=no".into());
-            },
-            _ => {},
-        }
         return base
     }
 
diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs
index 8befb105ff6..5ab542b6a24 100644
--- a/src/bootstrap/metadata.rs
+++ b/src/bootstrap/metadata.rs
@@ -43,8 +43,8 @@ struct ResolveNode {
 }
 
 pub fn build(build: &mut Build) {
-    build_krate(build, "src/rustc/std_shim");
-    build_krate(build, "src/rustc/test_shim");
+    build_krate(build, "src/libstd");
+    build_krate(build, "src/libtest");
     build_krate(build, "src/rustc");
 }
 
diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in
index 536095503e0..457ac825832 100644
--- a/src/bootstrap/mk/Makefile.in
+++ b/src/bootstrap/mk/Makefile.in
@@ -71,6 +71,8 @@ install:
 	$(Q)$(BOOTSTRAP) dist --install $(BOOTSTRAP_ARGS)
 tidy:
 	$(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS)
+prepare:
+	$(Q)$(BOOTSTRAP) build nonexistent/path/to/trigger/cargo/metadata
 
 check-stage2-T-arm-linux-androideabi-H-x86_64-unknown-linux-gnu:
 	$(Q)$(BOOTSTRAP) test --target arm-linux-androideabi
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs
index 8e79c2d27d1..bc439d6f782 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/sanity.rs
@@ -198,10 +198,6 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
 ");
             }
         }
-
-        if target.contains("arm-linux-android") {
-            need_cmd("adb".as_ref());
-        }
     }
 
     for host in build.flags.host.iter() {
diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs
index 36738b81c18..dcd3407e174 100644
--- a/src/bootstrap/step.rs
+++ b/src/bootstrap/step.rs
@@ -246,14 +246,14 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
     crate_rule(build,
                &mut rules,
                "libstd-link",
-               "build-crate-std_shim",
+               "build-crate-std",
                compile::std_link)
         .dep(|s| s.name("startup-objects"))
         .dep(|s| s.name("create-sysroot").target(s.host));
     crate_rule(build,
                &mut rules,
                "libtest-link",
-               "build-crate-test_shim",
+               "build-crate-test",
                compile::test_link)
         .dep(|s| s.name("libstd-link"));
     crate_rule(build,
@@ -263,13 +263,13 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
                compile::rustc_link)
         .dep(|s| s.name("libtest-link"));
 
-    for (krate, path, _default) in krates("std_shim") {
+    for (krate, path, _default) in krates("std") {
         rules.build(&krate.build_step, path)
              .dep(|s| s.name("startup-objects"))
              .dep(move |s| s.name("rustc").host(&build.config.build).target(s.host))
              .run(move |s| compile::std(build, s.target, &s.compiler()));
     }
-    for (krate, path, _default) in krates("test_shim") {
+    for (krate, path, _default) in krates("test") {
         rules.build(&krate.build_step, path)
              .dep(|s| s.name("libstd-link"))
              .run(move |s| compile::test(build, s.target, &s.compiler()));
@@ -384,7 +384,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
               "pretty", "run-fail-fulldeps");
     }
 
-    for (krate, path, _default) in krates("std_shim") {
+    for (krate, path, _default) in krates("std") {
         rules.test(&krate.test_step, path)
              .dep(|s| s.name("libtest"))
              .dep(|s| s.name("emulator-copy-libs"))
@@ -400,7 +400,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
                                     Mode::Libstd, TestKind::Test, None));
 
     // std benchmarks
-    for (krate, path, _default) in krates("std_shim") {
+    for (krate, path, _default) in krates("std") {
         rules.bench(&krate.bench_step, path)
              .dep(|s| s.name("libtest"))
              .dep(|s| s.name("emulator-copy-libs"))
@@ -415,7 +415,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
          .run(move |s| check::krate(build, &s.compiler(), s.target,
                                     Mode::Libstd, TestKind::Bench, None));
 
-    for (krate, path, _default) in krates("test_shim") {
+    for (krate, path, _default) in krates("test") {
         rules.test(&krate.test_step, path)
              .dep(|s| s.name("libtest"))
              .dep(|s| s.name("emulator-copy-libs"))
@@ -577,6 +577,15 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
          })
          .default(build.config.docs)
          .run(move |s| doc::rustbook(build, s.target, "reference"));
+    rules.doc("doc-unstable-book", "src/doc/unstable-book")
+         .dep(move |s| {
+             s.name("tool-rustbook")
+              .host(&build.config.build)
+              .target(&build.config.build)
+              .stage(0)
+         })
+         .default(build.config.docs)
+         .run(move |s| doc::rustbook(build, s.target, "unstable-book"));
     rules.doc("doc-standalone", "src/doc")
          .dep(move |s| {
              s.name("rustc")
@@ -592,13 +601,13 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
          .default(build.config.docs)
          .host(true)
          .run(move |s| doc::error_index(build, s.target));
-    for (krate, path, default) in krates("std_shim") {
+    for (krate, path, default) in krates("std") {
         rules.doc(&krate.doc_step, path)
              .dep(|s| s.name("libstd-link"))
              .default(default && build.config.docs)
              .run(move |s| doc::std(build, s.stage, s.target));
     }
-    for (krate, path, default) in krates("test_shim") {
+    for (krate, path, default) in krates("test") {
         rules.doc(&krate.doc_step, path)
              .dep(|s| s.name("libtest-link"))
              .default(default && build.config.compiler_docs)
@@ -1163,23 +1172,23 @@ mod tests {
 
         let mut build = Build::new(flags, config);
         let cwd = env::current_dir().unwrap();
-        build.crates.insert("std_shim".to_string(), ::Crate {
-            name: "std_shim".to_string(),
+        build.crates.insert("std".to_string(), ::Crate {
+            name: "std".to_string(),
             deps: Vec::new(),
-            path: cwd.join("src/std_shim"),
-            doc_step: "doc-std_shim".to_string(),
-            build_step: "build-crate-std_shim".to_string(),
-            test_step: "test-std_shim".to_string(),
-            bench_step: "bench-std_shim".to_string(),
+            path: cwd.join("src/std"),
+            doc_step: "doc-std".to_string(),
+            build_step: "build-crate-std".to_string(),
+            test_step: "test-std".to_string(),
+            bench_step: "bench-std".to_string(),
         });
-        build.crates.insert("test_shim".to_string(), ::Crate {
-            name: "test_shim".to_string(),
+        build.crates.insert("test".to_string(), ::Crate {
+            name: "test".to_string(),
             deps: Vec::new(),
-            path: cwd.join("src/test_shim"),
-            doc_step: "doc-test_shim".to_string(),
-            build_step: "build-crate-test_shim".to_string(),
-            test_step: "test-test_shim".to_string(),
-            bench_step: "bench-test_shim".to_string(),
+            path: cwd.join("src/test"),
+            doc_step: "doc-test".to_string(),
+            build_step: "build-crate-test".to_string(),
+            test_step: "test-test".to_string(),
+            bench_step: "bench-test".to_string(),
         });
         build.crates.insert("rustc-main".to_string(), ::Crate {
             name: "rustc-main".to_string(),
@@ -1369,7 +1378,7 @@ mod tests {
         let all = rules.expand(&plan);
         println!("all rules: {:#?}", all);
         assert!(!all.contains(&step.name("rustc")));
-        assert!(!all.contains(&step.name("build-crate-std_shim").stage(1)));
+        assert!(!all.contains(&step.name("build-crate-std").stage(1)));
 
         // all stage0 compiles should be for the build target, A
         for step in all.iter().filter(|s| s.stage == 0) {
@@ -1434,7 +1443,7 @@ mod tests {
 
         assert!(!plan.iter().any(|s| s.name.contains("rustc")));
         assert!(plan.iter().all(|s| {
-            !s.name.contains("test_shim") || s.target == "C"
+            !s.name.contains("test") || s.target == "C"
         }));
     }
 
diff --git a/src/ci/docker/arm-android/Dockerfile b/src/ci/docker/arm-android/Dockerfile
new file mode 100644
index 00000000000..4c89ce12531
--- /dev/null
+++ b/src/ci/docker/arm-android/Dockerfile
@@ -0,0 +1,46 @@
+FROM ubuntu:16.04
+
+RUN dpkg --add-architecture i386 && \
+    apt-get update && \
+    apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  file \
+  curl \
+  ca-certificates \
+  python2.7 \
+  git \
+  cmake \
+  unzip \
+  expect \
+  openjdk-9-jre \
+  sudo \
+  libstdc++6:i386 \
+  xz-utils \
+  libssl-dev \
+  pkg-config
+
+WORKDIR /android/
+ENV PATH=$PATH:/android/ndk-arm-9/bin:/android/sdk/tools:/android/sdk/platform-tools
+
+COPY install-ndk.sh install-sdk.sh accept-licenses.sh /android/
+RUN sh /android/install-ndk.sh
+RUN sh /android/install-sdk.sh
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+
+COPY start-emulator.sh /android/
+
+ENTRYPOINT ["/usr/bin/dumb-init", "--", "/android/start-emulator.sh"]
+
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-24-sccache-x86_64-unknown-linux-gnu && \
+      chmod +x /usr/local/bin/sccache
+
+ENV RUST_CONFIGURE_ARGS \
+      --target=arm-linux-androideabi \
+      --arm-linux-androideabi-ndk=/android/ndk-arm-9
+
+ENV SCRIPT python2.7 ../x.py test --target arm-linux-androideabi
diff --git a/src/ci/docker/android/accept-licenses.sh b/src/ci/docker/arm-android/accept-licenses.sh
index 8d8f60a5ec2..8d8f60a5ec2 100755
--- a/src/ci/docker/android/accept-licenses.sh
+++ b/src/ci/docker/arm-android/accept-licenses.sh
diff --git a/src/ci/docker/arm-android/install-ndk.sh b/src/ci/docker/arm-android/install-ndk.sh
new file mode 100644
index 00000000000..389ec062110
--- /dev/null
+++ b/src/ci/docker/arm-android/install-ndk.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# 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.
+
+set -ex
+
+cpgdb() {
+  cp android-ndk-r11c/prebuilt/linux-x86_64/bin/gdb /android/$1/bin/$2-gdb
+  cp android-ndk-r11c/prebuilt/linux-x86_64/bin/gdb-orig /android/$1/bin/gdb-orig
+  cp -r android-ndk-r11c/prebuilt/linux-x86_64/share /android/$1/share
+}
+
+# Prep the Android NDK
+#
+# See https://github.com/servo/servo/wiki/Building-for-Android
+curl -O https://dl.google.com/android/repository/android-ndk-r11c-linux-x86_64.zip
+unzip -q android-ndk-r11c-linux-x86_64.zip
+bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
+        --platform=android-9 \
+        --toolchain=arm-linux-androideabi-4.9 \
+        --install-dir=/android/ndk-arm-9 \
+        --ndk-dir=/android/android-ndk-r11c \
+        --arch=arm
+cpgdb ndk-arm-9 arm-linux-androideabi
+
+rm -rf ./android-ndk-r11c-linux-x86_64.zip ./android-ndk-r11c
diff --git a/src/ci/docker/android/install-sdk.sh b/src/ci/docker/arm-android/install-sdk.sh
index 2db1d46ba22..2db1d46ba22 100644
--- a/src/ci/docker/android/install-sdk.sh
+++ b/src/ci/docker/arm-android/install-sdk.sh
diff --git a/src/ci/docker/android/start-emulator.sh b/src/ci/docker/arm-android/start-emulator.sh
index 24c477d87f1..24c477d87f1 100755
--- a/src/ci/docker/android/start-emulator.sh
+++ b/src/ci/docker/arm-android/start-emulator.sh
diff --git a/src/ci/docker/armhf-gnu/Dockerfile b/src/ci/docker/armhf-gnu/Dockerfile
index e64f65438cb..39b7e9df4b8 100644
--- a/src/ci/docker/armhf-gnu/Dockerfile
+++ b/src/ci/docker/armhf-gnu/Dockerfile
@@ -73,9 +73,9 @@ RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static
 # TODO: What is this?!
 RUN curl -O http://ftp.nl.debian.org/debian/dists/jessie/main/installer-armhf/current/images/device-tree/vexpress-v2p-ca15-tc1.dtb
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/cross/Dockerfile b/src/ci/docker/cross/Dockerfile
index 52c5b83f263..1d5be59186b 100644
--- a/src/ci/docker/cross/Dockerfile
+++ b/src/ci/docker/cross/Dockerfile
@@ -21,9 +21,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/android/Dockerfile b/src/ci/docker/dist-android/Dockerfile
index ae1bfd9e40a..6d433cc1509 100644
--- a/src/ci/docker/android/Dockerfile
+++ b/src/ci/docker/dist-android/Dockerfile
@@ -23,21 +23,17 @@ RUN dpkg --add-architecture i386 && \
 WORKDIR /android/
 ENV PATH=$PATH:/android/ndk-arm-9/bin:/android/sdk/tools:/android/sdk/platform-tools
 
-COPY install-ndk.sh install-sdk.sh accept-licenses.sh /android/
+COPY install-ndk.sh /android/
 RUN sh /android/install-ndk.sh
-RUN sh /android/install-sdk.sh
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
     rm dumb-init_*.deb
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
 
-COPY start-emulator.sh /android/
-
-ENTRYPOINT ["/usr/bin/dumb-init", "--", "/android/start-emulator.sh"]
-
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 ENV TARGETS=arm-linux-androideabi
 ENV TARGETS=$TARGETS,i686-linux-android
@@ -51,8 +47,4 @@ ENV RUST_CONFIGURE_ARGS \
       --i686-linux-android-ndk=/android/ndk-x86-9 \
       --aarch64-linux-android-ndk=/android/ndk-aarch64
 
-# Just a smoke test in dist to see if this works for now, we should expand this
-# to all the targets above eventually.
-ENV SCRIPT \
-  python2.7 ../x.py test --target arm-linux-androideabi && \
-  python2.7 ../x.py dist --target $TARGETS
+ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
diff --git a/src/ci/docker/android/install-ndk.sh b/src/ci/docker/dist-android/install-ndk.sh
index 418ce69c5b1..19c1b94e784 100644
--- a/src/ci/docker/android/install-ndk.sh
+++ b/src/ci/docker/dist-android/install-ndk.sh
@@ -11,12 +11,6 @@
 
 set -ex
 
-cpgdb() {
-  cp android-ndk-r11c/prebuilt/linux-x86_64/bin/gdb /android/$1/bin/$2-gdb
-  cp android-ndk-r11c/prebuilt/linux-x86_64/bin/gdb-orig /android/$1/bin/gdb-orig
-  cp -r android-ndk-r11c/prebuilt/linux-x86_64/share /android/$1/share
-}
-
 # Prep the Android NDK
 #
 # See https://github.com/servo/servo/wiki/Building-for-Android
@@ -28,7 +22,6 @@ bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
         --install-dir=/android/ndk-arm-9 \
         --ndk-dir=/android/android-ndk-r11c \
         --arch=arm
-cpgdb ndk-arm-9 arm-linux-androideabi
 bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
         --platform=android-21 \
         --toolchain=aarch64-linux-android-4.9 \
diff --git a/src/ci/docker/dist-arm-linux/Dockerfile b/src/ci/docker/dist-arm-linux/Dockerfile
index e5619564b05..e2ab6f636af 100644
--- a/src/ci/docker/dist-arm-linux/Dockerfile
+++ b/src/ci/docker/dist-arm-linux/Dockerfile
@@ -27,9 +27,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile b/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile
index 5b94d5a9727..5528b05104b 100644
--- a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile
+++ b/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile
@@ -27,9 +27,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/dist-freebsd/Dockerfile b/src/ci/docker/dist-freebsd/Dockerfile
index c39e298e3ce..43e0734b74a 100644
--- a/src/ci/docker/dist-freebsd/Dockerfile
+++ b/src/ci/docker/dist-freebsd/Dockerfile
@@ -25,9 +25,9 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini
     rm dumb-init_*.deb
 ENTRYPOINT ["/usr/bin/dumb-init", "--"]
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 ENV \
     AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \
diff --git a/src/ci/docker/dist-mips-linux/Dockerfile b/src/ci/docker/dist-mips-linux/Dockerfile
index 5d8b3cfeae2..a99e9292df5 100644
--- a/src/ci/docker/dist-mips-linux/Dockerfile
+++ b/src/ci/docker/dist-mips-linux/Dockerfile
@@ -17,9 +17,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/dist-mips64-linux/Dockerfile b/src/ci/docker/dist-mips64-linux/Dockerfile
index 8feba12e722..865d7ea5ea2 100644
--- a/src/ci/docker/dist-mips64-linux/Dockerfile
+++ b/src/ci/docker/dist-mips64-linux/Dockerfile
@@ -17,9 +17,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/dist-powerpc-linux/Dockerfile b/src/ci/docker/dist-powerpc-linux/Dockerfile
index e5ffbfc090d..4ca39eae53f 100644
--- a/src/ci/docker/dist-powerpc-linux/Dockerfile
+++ b/src/ci/docker/dist-powerpc-linux/Dockerfile
@@ -27,9 +27,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile
index 7d13bc3d438..2aeff7a0b90 100644
--- a/src/ci/docker/dist-powerpc64-linux/Dockerfile
+++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile
@@ -27,9 +27,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile
index 7f4c6d4647c..79ffac73425 100644
--- a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile
+++ b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile
@@ -27,9 +27,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-x86-linux/Dockerfile
index f9324991aa0..3f6f71c41b5 100644
--- a/src/ci/docker/dist-x86-linux/Dockerfile
+++ b/src/ci/docker/dist-x86-linux/Dockerfile
@@ -74,10 +74,9 @@ RUN curl -Lo /rustroot/dumb-init \
       chmod +x /rustroot/dumb-init
 ENTRYPOINT ["/rustroot/dumb-init", "--"]
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      xz --decompress | \
-      tar xf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 ENV HOSTS=i686-unknown-linux-gnu
 ENV HOSTS=$HOSTS,x86_64-unknown-linux-gnu
diff --git a/src/ci/docker/emscripten/Dockerfile b/src/ci/docker/emscripten/Dockerfile
index 84e12eb6c3e..0757547bd2d 100644
--- a/src/ci/docker/emscripten/Dockerfile
+++ b/src/ci/docker/emscripten/Dockerfile
@@ -14,9 +14,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils \
   lib32stdc++6
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/i686-gnu-nopt/Dockerfile b/src/ci/docker/i686-gnu-nopt/Dockerfile
index 1ffb24981c5..61f8e3dd06a 100644
--- a/src/ci/docker/i686-gnu-nopt/Dockerfile
+++ b/src/ci/docker/i686-gnu-nopt/Dockerfile
@@ -13,9 +13,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   xz-utils
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/i686-gnu/Dockerfile b/src/ci/docker/i686-gnu/Dockerfile
index 84b98712b33..1dcdc5591f5 100644
--- a/src/ci/docker/i686-gnu/Dockerfile
+++ b/src/ci/docker/i686-gnu/Dockerfile
@@ -13,9 +13,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   xz-utils
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/linux-tested-targets/Dockerfile b/src/ci/docker/linux-tested-targets/Dockerfile
index feb73bebbdb..06c14a96101 100644
--- a/src/ci/docker/linux-tested-targets/Dockerfile
+++ b/src/ci/docker/linux-tested-targets/Dockerfile
@@ -25,15 +25,23 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini
     rm dumb-init_*.deb
 ENTRYPOINT ["/usr/bin/dumb-init", "--"]
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 ENV RUST_CONFIGURE_ARGS \
       --target=x86_64-unknown-linux-musl,i686-unknown-linux-musl,i586-unknown-linux-gnu \
       --musl-root-x86_64=/musl-x86_64 \
       --musl-root-i686=/musl-i686
 
+# Newer binutils broke things on some vms/distros (i.e., linking against
+# unknown relocs disabled by the following flag), so we need to go out of our
+# way to produce "super compatible" binaries.
+#
+# See: https://github.com/rust-lang/rust/issues/34978
+ENV CFLAGS_i686_unknown_linux_gnu=-Wa,-mrelax-relocations=no \
+    CFLAGS_x86_64_unknown_linux_gnu=-Wa,-mrelax-relocations=no
+
 ENV SCRIPT \
       python2.7 ../x.py test \
           --target x86_64-unknown-linux-musl \
diff --git a/src/ci/docker/linux-tested-targets/build-musl.sh b/src/ci/docker/linux-tested-targets/build-musl.sh
index 260dc11509f..ce62c392241 100644
--- a/src/ci/docker/linux-tested-targets/build-musl.sh
+++ b/src/ci/docker/linux-tested-targets/build-musl.sh
@@ -11,7 +11,10 @@
 
 set -ex
 
-export CFLAGS="-fPIC"
+# We need to mitigate rust-lang/rust#34978 when compiling musl itself as well
+export CFLAGS="-fPIC -Wa,-mrelax-relocations=no"
+export CXXFLAGS="-Wa,-mrelax-relocations=no"
+
 MUSL=musl-1.1.14
 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf -
 cd $MUSL
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index 892c5baa5c6..1e61f216910 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 # 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.
@@ -19,7 +19,9 @@ ci_dir="`dirname $docker_dir`"
 src_dir="`dirname $ci_dir`"
 root_dir="`dirname $src_dir`"
 
-docker \
+source "$ci_dir/shared.sh"
+
+retry docker \
   build \
   --rm \
   -t rust-ci \
diff --git a/src/ci/docker/x86_64-gnu-aux/Dockerfile b/src/ci/docker/x86_64-gnu-aux/Dockerfile
index 607163ea547..ac46a35a0bc 100644
--- a/src/ci/docker/x86_64-gnu-aux/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-aux/Dockerfile
@@ -14,9 +14,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile
index f54e4e562f8..1f577b4e8ae 100644
--- a/src/ci/docker/x86_64-gnu-debug/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile
@@ -13,9 +13,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   xz-utils
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile
index afa99ca2b86..66cf2a5939f 100644
--- a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile
@@ -15,9 +15,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile
index 206103b92e9..3919daeabae 100644
--- a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile
@@ -13,9 +13,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   xz-utils
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/x86_64-gnu-incremental/Dockerfile b/src/ci/docker/x86_64-gnu-incremental/Dockerfile
index 3e084f4a3c3..b01b430cc68 100644
--- a/src/ci/docker/x86_64-gnu-incremental/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-incremental/Dockerfile
@@ -13,9 +13,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   xz-utils
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile
index aabfc0cd1bd..89c5a6c89d3 100644
--- a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile
@@ -16,9 +16,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   zlib1g-dev \
   xz-utils
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/x86_64-gnu-nopt/Dockerfile
index d28dc3de1b4..be731e2b0d8 100644
--- a/src/ci/docker/x86_64-gnu-nopt/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-nopt/Dockerfile
@@ -13,9 +13,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   xz-utils
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/x86_64-gnu/Dockerfile b/src/ci/docker/x86_64-gnu/Dockerfile
index 427498fabb2..02a8fb964ff 100644
--- a/src/ci/docker/x86_64-gnu/Dockerfile
+++ b/src/ci/docker/x86_64-gnu/Dockerfile
@@ -13,9 +13,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   xz-utils
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/run.sh b/src/ci/run.sh
index c4b25565993..53d16f6239e 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 # 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.
@@ -20,6 +20,9 @@ if [ "$NO_CHANGE_USER" = "" ]; then
   fi
 fi
 
+ci_dir=`cd $(dirname $0) && pwd`
+source "$ci_dir/shared.sh"
+
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-sccache"
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-quiet-tests"
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-manage-submodules"
@@ -54,9 +57,8 @@ else
   fi
 fi
 
-set -ex
-
 $SRC/configure $RUST_CONFIGURE_ARGS
+retry make prepare
 
 if [ "$TRAVIS_OS_NAME" = "osx" ]; then
     ncpus=$(sysctl -n hw.ncpu)
@@ -64,6 +66,8 @@ else
     ncpus=$(grep processor /proc/cpuinfo | wc -l)
 fi
 
+set -x
+
 if [ ! -z "$SCRIPT" ]; then
   sh -x -c "$SCRIPT"
 else
diff --git a/src/ci/shared.sh b/src/ci/shared.sh
new file mode 100644
index 00000000000..ecd9b7e98a4
--- /dev/null
+++ b/src/ci/shared.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# 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.
+
+# See http://unix.stackexchange.com/questions/82598
+function retry {
+  local n=1
+  local max=5
+  local delay=15
+  while true; do
+    echo "Attempting:" "$@"
+    "$@" && break || {
+      if [[ $n -lt $max ]]; then
+        ((n++))
+        echo "Command failed. Attempt $n/$max:"
+      else
+        echo "The command has failed after $n attempts."
+        exit 1
+      fi
+    }
+  done
+}
diff --git a/src/doc/book/src/README.md b/src/doc/book/src/README.md
index 9162642b1cc..ade4d52c1eb 100644
--- a/src/doc/book/src/README.md
+++ b/src/doc/book/src/README.md
@@ -21,7 +21,6 @@ is the first. After this:
 * [Tutorial: Guessing Game][gg] - Learn some Rust with a small project.
 * [Syntax and Semantics][ss] - Each bit of Rust, broken down into small chunks.
 * [Effective Rust][er] - Higher-level concepts for writing excellent Rust code.
-* [Nightly Rust][nr] - Cutting-edge features that aren’t in stable builds yet.
 * [Glossary][gl] - A reference of terms used in the book.
 * [Bibliography][bi] - Background on Rust's influences, papers about Rust.
 
@@ -29,7 +28,6 @@ is the first. After this:
 [gg]: guessing-game.html
 [er]: effective-rust.html
 [ss]: syntax-and-semantics.html
-[nr]: nightly-rust.html
 [gl]: glossary.html
 [bi]: bibliography.html
 
diff --git a/src/doc/book/src/SUMMARY.md b/src/doc/book/src/SUMMARY.md
index 74b9b7fa5b2..c3763cdf9d6 100644
--- a/src/doc/book/src/SUMMARY.md
+++ b/src/doc/book/src/SUMMARY.md
@@ -55,18 +55,6 @@
     * [Release Channels](release-channels.md)
     * [Using Rust without the standard library](using-rust-without-the-standard-library.md)
     * [Procedural Macros (and custom derive)](procedural-macros.md)
-* [Nightly Rust](nightly-rust.md)
-    * [Compiler Plugins](compiler-plugins.md)
-    * [Inline Assembly](inline-assembly.md)
-    * [No stdlib](no-stdlib.md)
-    * [Intrinsics](intrinsics.md)
-    * [Lang items](lang-items.md)
-    * [Advanced linking](advanced-linking.md)
-    * [Benchmark Tests](benchmark-tests.md)
-    * [Box Syntax and Patterns](box-syntax-and-patterns.md)
-    * [Slice Patterns](slice-patterns.md)
-    * [Associated Constants](associated-constants.md)
-    * [Custom Allocators](custom-allocators.md)
 * [Glossary](glossary.md)
 * [Syntax Index](syntax-index.md)
 * [Bibliography](bibliography.md)
diff --git a/src/doc/book/src/advanced-linking.md b/src/doc/book/src/advanced-linking.md
deleted file mode 100644
index a882d6d2ebe..00000000000
--- a/src/doc/book/src/advanced-linking.md
+++ /dev/null
@@ -1,145 +0,0 @@
-# Advanced Linking
-
-The common cases of linking with Rust have been covered earlier in this book,
-but supporting the range of linking possibilities made available by other
-languages is important for Rust to achieve seamless interaction with native
-libraries.
-
-# Link args
-
-There is one other way to tell `rustc` how to customize linking, and that is via
-the `link_args` attribute. This attribute is applied to `extern` blocks and
-specifies raw flags which need to get passed to the linker when producing an
-artifact. An example usage would be:
-
-```rust,no_run
-#![feature(link_args)]
-
-#[link_args = "-foo -bar -baz"]
-extern {}
-# fn main() {}
-```
-
-Note that this feature is currently hidden behind the `feature(link_args)` gate
-because this is not a sanctioned way of performing linking. Right now `rustc`
-shells out to the system linker (`gcc` on most systems, `link.exe` on MSVC),
-so it makes sense to provide extra command line
-arguments, but this will not always be the case. In the future `rustc` may use
-LLVM directly to link native libraries, in which case `link_args` will have no
-meaning. You can achieve the same effect as the `link_args` attribute with the
-`-C link-args` argument to `rustc`.
-
-It is highly recommended to *not* use this attribute, and rather use the more
-formal `#[link(...)]` attribute on `extern` blocks instead.
-
-# Static linking
-
-Static linking refers to the process of creating output that contains all
-required libraries and so doesn't need libraries installed on every system where
-you want to use your compiled project. Pure-Rust dependencies are statically
-linked by default so you can use created binaries and libraries without
-installing Rust everywhere. By contrast, native libraries
-(e.g. `libc` and `libm`) are usually dynamically linked, but it is possible to
-change this and statically link them as well.
-
-Linking is a very platform-dependent topic, and static linking may not even be
-possible on some platforms! This section assumes some basic familiarity with
-linking on your platform of choice.
-
-## Linux
-
-By default, all Rust programs on Linux will link to the system `libc` along with
-a number of other libraries. Let's look at an example on a 64-bit Linux machine
-with GCC and `glibc` (by far the most common `libc` on Linux):
-
-```text
-$ cat example.rs
-fn main() {}
-$ rustc example.rs
-$ ldd example
-        linux-vdso.so.1 =>  (0x00007ffd565fd000)
-        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fa81889c000)
-        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa81867e000)
-        librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fa818475000)
-        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fa81825f000)
-        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa817e9a000)
-        /lib64/ld-linux-x86-64.so.2 (0x00007fa818cf9000)
-        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa817b93000)
-```
-
-Dynamic linking on Linux can be undesirable if you wish to use new library
-features on old systems or target systems which do not have the required
-dependencies for your program to run.
-
-Static linking is supported via an alternative `libc`, [`musl`](http://www.musl-libc.org). You can compile
-your own version of Rust with `musl` enabled and install it into a custom
-directory with the instructions below:
-
-```text
-$ mkdir musldist
-$ PREFIX=$(pwd)/musldist
-$
-$ # Build musl
-$ curl -O http://www.musl-libc.org/releases/musl-1.1.10.tar.gz
-$ tar xf musl-1.1.10.tar.gz
-$ cd musl-1.1.10/
-musl-1.1.10 $ ./configure --disable-shared --prefix=$PREFIX
-musl-1.1.10 $ make
-musl-1.1.10 $ make install
-musl-1.1.10 $ cd ..
-$ du -h musldist/lib/libc.a
-2.2M    musldist/lib/libc.a
-$
-$ # Build libunwind.a
-$ curl -O http://llvm.org/releases/3.7.0/llvm-3.7.0.src.tar.xz
-$ tar xf llvm-3.7.0.src.tar.xz
-$ cd llvm-3.7.0.src/projects/
-llvm-3.7.0.src/projects $ curl http://llvm.org/releases/3.7.0/libunwind-3.7.0.src.tar.xz | tar xJf -
-llvm-3.7.0.src/projects $ mv libunwind-3.7.0.src libunwind
-llvm-3.7.0.src/projects $ mkdir libunwind/build
-llvm-3.7.0.src/projects $ cd libunwind/build
-llvm-3.7.0.src/projects/libunwind/build $ cmake -DLLVM_PATH=../../.. -DLIBUNWIND_ENABLE_SHARED=0 ..
-llvm-3.7.0.src/projects/libunwind/build $ make
-llvm-3.7.0.src/projects/libunwind/build $ cp lib/libunwind.a $PREFIX/lib/
-llvm-3.7.0.src/projects/libunwind/build $ cd ../../../../
-$ du -h musldist/lib/libunwind.a
-164K    musldist/lib/libunwind.a
-$
-$ # Build musl-enabled rust
-$ git clone https://github.com/rust-lang/rust.git muslrust
-$ cd muslrust
-muslrust $ ./configure --target=x86_64-unknown-linux-musl --musl-root=$PREFIX --prefix=$PREFIX
-muslrust $ make
-muslrust $ make install
-muslrust $ cd ..
-$ du -h musldist/bin/rustc
-12K     musldist/bin/rustc
-```
-
-You now have a build of a `musl`-enabled Rust! Because we've installed it to a
-custom prefix we need to make sure our system can find the binaries and appropriate
-libraries when we try and run it:
-
-```text
-$ export PATH=$PREFIX/bin:$PATH
-$ export LD_LIBRARY_PATH=$PREFIX/lib:$LD_LIBRARY_PATH
-```
-
-Let's try it out!
-
-```text
-$ echo 'fn main() { println!("hi!"); panic!("failed"); }' > example.rs
-$ rustc --target=x86_64-unknown-linux-musl example.rs
-$ ldd example
-        not a dynamic executable
-$ ./example
-hi!
-thread 'main' panicked at 'failed', example.rs:1
-```
-
-Success! This binary can be copied to almost any Linux machine with the same
-machine architecture and run without issues.
-
-`cargo build` also permits the `--target` option so you should be able to build
-your crates as normal. However, you may need to recompile your native libraries
-against `musl` before they can be linked against.
diff --git a/src/doc/book/src/box-syntax-and-patterns.md b/src/doc/book/src/box-syntax-and-patterns.md
deleted file mode 100644
index f03e881f474..00000000000
--- a/src/doc/book/src/box-syntax-and-patterns.md
+++ /dev/null
@@ -1,100 +0,0 @@
-#  Box Syntax and Patterns
-
-Currently the only stable way to create a `Box` is via the `Box::new` method.
-Also it is not possible in stable Rust to destructure a `Box` in a match
-pattern. The unstable `box` keyword can be used to both create and destructure
-a `Box`. An example usage would be:
-
-```rust
-#![feature(box_syntax, box_patterns)]
-
-fn main() {
-    let b = Some(box 5);
-    match b {
-        Some(box n) if n < 0 => {
-            println!("Box contains negative number {}", n);
-        },
-        Some(box n) if n >= 0 => {
-            println!("Box contains non-negative number {}", n);
-        },
-        None => {
-            println!("No box");
-        },
-        _ => unreachable!()
-    }
-}
-```
-
-Note that these features are currently hidden behind the `box_syntax` (box
-creation) and `box_patterns` (destructuring and pattern matching) gates
-because the syntax may still change in the future.
-
-# Returning Pointers
-
-In many languages with pointers, you'd return a pointer from a function
-so as to avoid copying a large data structure. For example:
-
-```rust
-struct BigStruct {
-    one: i32,
-    two: i32,
-    // Etc.
-    one_hundred: i32,
-}
-
-fn foo(x: Box<BigStruct>) -> Box<BigStruct> {
-    Box::new(*x)
-}
-
-fn main() {
-    let x = Box::new(BigStruct {
-        one: 1,
-        two: 2,
-        one_hundred: 100,
-    });
-
-    let y = foo(x);
-}
-```
-
-The idea is that by passing around a box, you're only copying a pointer, rather
-than the hundred `i32`s that make up the `BigStruct`.
-
-This is an antipattern in Rust. Instead, write this:
-
-```rust
-#![feature(box_syntax)]
-
-struct BigStruct {
-    one: i32,
-    two: i32,
-    // Etc.
-    one_hundred: i32,
-}
-
-fn foo(x: Box<BigStruct>) -> BigStruct {
-    *x
-}
-
-fn main() {
-    let x = Box::new(BigStruct {
-        one: 1,
-        two: 2,
-        one_hundred: 100,
-    });
-
-    let y: Box<BigStruct> = box foo(x);
-}
-```
-
-This gives you flexibility without sacrificing performance.
-
-You may think that this gives us terrible performance: return a value and then
-immediately box it up ?! Isn't this pattern the worst of both worlds? Rust is
-smarter than that. There is no copy in this code. `main` allocates enough room
-for the `box`, passes a pointer to that memory into `foo` as `x`, and then
-`foo` writes the value straight into the `Box<T>`.
-
-This is important enough that it bears repeating: pointers are not for
-optimizing returning values from your code. Allow the caller to choose how they
-want to use your output.
diff --git a/src/doc/book/src/casting-between-types.md b/src/doc/book/src/casting-between-types.md
index 853fb1ec254..26cd718475e 100644
--- a/src/doc/book/src/casting-between-types.md
+++ b/src/doc/book/src/casting-between-types.md
@@ -151,12 +151,9 @@ elements of the array. These kinds of casts are very dangerous, because they
 make assumptions about the way that multiple underlying structures are
 implemented. For this, we need something more dangerous.
 
-The `transmute` function is provided by a [compiler intrinsic][intrinsics], and
-what it does is very simple, but very scary. It tells Rust to treat a value of
-one type as though it were another type. It does this regardless of the
-typechecking system, and completely trusts you.
-
-[intrinsics]: intrinsics.html
+The `transmute` function is very simple, but very scary. It tells Rust to treat
+a value of one type as though it were another type. It does this regardless of
+the typechecking system, and completely trusts you.
 
 In our previous example, we know that an array of four `u8`s represents a `u32`
 properly, and so we want to do the cast. Using `transmute` instead of `as`,
diff --git a/src/doc/book/src/concurrency.md b/src/doc/book/src/concurrency.md
index a64178c26f2..afed379fe47 100644
--- a/src/doc/book/src/concurrency.md
+++ b/src/doc/book/src/concurrency.md
@@ -36,7 +36,7 @@ down the channel and to the other thread. Therefore, we'd ensure that `Send` was
 implemented for that type.
 
 In the opposite way, if we were wrapping a library with [FFI][ffi] that isn't
-threadsafe, we wouldn't want to implement `Send`, and so the compiler will help
+thread-safe, we wouldn't want to implement `Send`, and so the compiler will help
 us enforce that it can't leave the current thread.
 
 [ffi]: ffi.html
diff --git a/src/doc/book/src/conditional-compilation.md b/src/doc/book/src/conditional-compilation.md
index 938c1c51326..0562e9fc430 100644
--- a/src/doc/book/src/conditional-compilation.md
+++ b/src/doc/book/src/conditional-compilation.md
@@ -79,8 +79,7 @@ Will be the same as `#[b]` if `a` is set by `cfg` attribute, and nothing otherwi
 
 # cfg!
 
-The `cfg!` [syntax extension][compilerplugins] lets you use these kinds of flags
-elsewhere in your code, too:
+The `cfg!` macro lets you use these kinds of flags elsewhere in your code, too:
 
 ```rust
 if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
@@ -88,7 +87,5 @@ if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
 }
 ```
 
-[compilerplugins]: compiler-plugins.html
-
 These will be replaced by a `true` or `false` at compile-time, depending on the
 configuration settings.
diff --git a/src/doc/book/src/ffi.md b/src/doc/book/src/ffi.md
index cccefd8dfe7..e9e2dab73ef 100644
--- a/src/doc/book/src/ffi.md
+++ b/src/doc/book/src/ffi.md
@@ -408,7 +408,7 @@ libraries:
 * Static - `#[link(name = "my_build_dependency", kind = "static")]`
 * Frameworks - `#[link(name = "CoreFoundation", kind = "framework")]`
 
-Note that frameworks are only available on OSX targets.
+Note that frameworks are only available on macOS targets.
 
 The different `kind` values are meant to differentiate how the native library
 participates in linkage. From a linkage perspective, the Rust compiler creates
@@ -437,7 +437,7 @@ A few examples of how this model can be used are:
   is included in a final target (like a binary), the native library will be
   linked in.
 
-On OSX, frameworks behave with the same semantics as a dynamic library.
+On macOS, frameworks behave with the same semantics as a dynamic library.
 
 # Unsafe blocks
 
diff --git a/src/doc/book/src/functions.md b/src/doc/book/src/functions.md
index eff77a54d83..96c8e9f5d68 100644
--- a/src/doc/book/src/functions.md
+++ b/src/doc/book/src/functions.md
@@ -230,6 +230,19 @@ If you want more information, you can get a backtrace by setting the
 ```text
 $ RUST_BACKTRACE=1 ./diverges
 thread 'main' panicked at 'This function never returns!', hello.rs:2
+Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
+stack backtrace:
+  hello::diverges
+        at ./hello.rs:2
+  hello::main
+        at ./hello.rs:6
+```
+
+If you want the complete backtrace and filenames:
+
+```text
+$ RUST_BACKTRACE=full ./diverges
+thread 'main' panicked at 'This function never returns!', hello.rs:2
 stack backtrace:
    1:     0x7f402773a829 - sys::backtrace::write::h0942de78b6c02817K8r
    2:     0x7f402773d7fc - panicking::on_panic::h3f23f9d0b5f4c91bu9w
@@ -262,7 +275,7 @@ note: Run with `RUST_BACKTRACE=1` for a backtrace.
 `RUST_BACKTRACE` also works with Cargo’s `run` command:
 
 ```text
-$ RUST_BACKTRACE=1 cargo run
+$ RUST_BACKTRACE=full cargo run
      Running `target/debug/diverges`
 thread 'main' panicked at 'This function never returns!', hello.rs:2
 stack backtrace:
diff --git a/src/doc/book/src/getting-started.md b/src/doc/book/src/getting-started.md
index 6208b1f4c12..06ea24fef3c 100644
--- a/src/doc/book/src/getting-started.md
+++ b/src/doc/book/src/getting-started.md
@@ -167,7 +167,7 @@ fn main() {
 }
 ```
 
-Save the file, and go back to your terminal window. On Linux or OSX, enter the
+Save the file, and go back to your terminal window. On Linux or macOS, enter the
 following commands:
 
 ```bash
@@ -253,7 +253,7 @@ $ rustc main.rs
 
 If you come from a C or C++ background, you'll notice that this is similar to
 `gcc` or `clang`. After compiling successfully, Rust should output a binary
-executable, which you can see on Linux or OSX by entering the `ls` command in
+executable, which you can see on Linux or macOS by entering the `ls` command in
 your shell as follows:
 
 ```bash
diff --git a/src/doc/book/src/lang-items.md b/src/doc/book/src/lang-items.md
deleted file mode 100644
index 9bd64d38179..00000000000
--- a/src/doc/book/src/lang-items.md
+++ /dev/null
@@ -1,84 +0,0 @@
-# Lang items
-
-> **Note**: lang items are often provided by crates in the Rust distribution,
-> and lang items themselves have an unstable interface. It is recommended to use
-> officially distributed crates instead of defining your own lang items.
-
-The `rustc` compiler has certain pluggable operations, that is,
-functionality that isn't hard-coded into the language, but is
-implemented in libraries, with a special marker to tell the compiler
-it exists. The marker is the attribute `#[lang = "..."]` and there are
-various different values of `...`, i.e. various different 'lang
-items'.
-
-For example, `Box` pointers require two lang items, one for allocation
-and one for deallocation. A freestanding program that uses the `Box`
-sugar for dynamic allocations via `malloc` and `free`:
-
-```rust,ignore
-#![feature(lang_items, box_syntax, start, libc, core_intrinsics)]
-#![no_std]
-use core::intrinsics;
-
-extern crate libc;
-
-#[lang = "owned_box"]
-pub struct Box<T>(*mut T);
-
-#[lang = "exchange_malloc"]
-unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
-    let p = libc::malloc(size as libc::size_t) as *mut u8;
-
-    // Check if `malloc` failed:
-    if p as usize == 0 {
-        intrinsics::abort();
-    }
-
-    p
-}
-
-#[lang = "exchange_free"]
-unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
-    libc::free(ptr as *mut libc::c_void)
-}
-
-#[lang = "box_free"]
-unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
-    deallocate(ptr as *mut u8, ::core::mem::size_of_val(&*ptr), ::core::mem::align_of_val(&*ptr));
-}
-
-#[start]
-fn main(argc: isize, argv: *const *const u8) -> isize {
-    let x = box 1;
-
-    0
-}
-
-#[lang = "eh_personality"] extern fn rust_eh_personality() {}
-#[lang = "panic_fmt"] extern fn rust_begin_panic() -> ! { unsafe { intrinsics::abort() } }
-# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
-# #[no_mangle] pub extern fn rust_eh_register_frames () {}
-# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
-```
-
-Note the use of `abort`: the `exchange_malloc` lang item is assumed to
-return a valid pointer, and so needs to do the check internally.
-
-Other features provided by lang items include:
-
-- overloadable operators via traits: the traits corresponding to the
-  `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all
-  marked with lang items; those specific four are `eq`, `ord`,
-  `deref`, and `add` respectively.
-- stack unwinding and general failure; the `eh_personality`,
-  `eh_unwind_resume`, `fail` and `fail_bounds_checks` lang items.
-- the traits in `std::marker` used to indicate types of
-  various kinds; lang items `send`, `sync` and `copy`.
-- the marker types and variance indicators found in
-  `std::marker`; lang items `covariant_type`,
-  `contravariant_lifetime`, etc.
-
-Lang items are loaded lazily by the compiler; e.g. if one never uses
-`Box` then there is no need to define functions for `exchange_malloc`
-and `exchange_free`. `rustc` will emit an error when an item is needed
-but not found in the current crate or any that it depends on.
diff --git a/src/doc/book/src/loops.md b/src/doc/book/src/loops.md
index ec4acfa3112..b7658d57a9e 100644
--- a/src/doc/book/src/loops.md
+++ b/src/doc/book/src/loops.md
@@ -100,7 +100,8 @@ developers.
 
 ### Enumerate
 
-When you need to keep track of how many times you already looped, you can use the `.enumerate()` function.
+When you need to keep track of how many times you have already looped, you can
+use the `.enumerate()` function.
 
 #### On ranges:
 
diff --git a/src/doc/book/src/macros.md b/src/doc/book/src/macros.md
index 93f63ddc0a5..fa8e8975a5b 100644
--- a/src/doc/book/src/macros.md
+++ b/src/doc/book/src/macros.md
@@ -761,12 +761,3 @@ to typecheck, and don’t want to worry about writing out the body of the
 function. One example of this situation is implementing a trait with multiple
 required methods, where you want to tackle one at a time. Define the others
 as `unimplemented!` until you’re ready to write them.
-
-# Procedural macros
-
-If Rust’s macro system can’t do what you need, you may want to write a
-[compiler plugin](compiler-plugins.html) instead. Compared to `macro_rules!`
-macros, this is significantly more work, the interfaces are much less stable,
-and bugs can be much harder to track down. In exchange you get the
-flexibility of running arbitrary Rust code within the compiler. Syntax
-extension plugins are sometimes called ‘procedural macros’ for this reason.
diff --git a/src/doc/book/src/nightly-rust.md b/src/doc/book/src/nightly-rust.md
deleted file mode 100644
index 5dfaa9e0fa8..00000000000
--- a/src/doc/book/src/nightly-rust.md
+++ /dev/null
@@ -1,100 +0,0 @@
-# Nightly Rust
-
-Rust provides three distribution channels for Rust: nightly, beta, and stable.
-Unstable features are only available on nightly Rust. For more details on this
-process, see [Stability as a deliverable][stability].
-
-[stability]: http://blog.rust-lang.org/2014/10/30/Stability.html
-
-To install nightly Rust, you can use [rustup.rs][rustup]:
-
-[rustup]: https://rustup.rs
-
-```bash
-$ curl https://sh.rustup.rs -sSf | sh
-$ rustup install nightly
-```
-
-If you're concerned about the [potential insecurity][insecurity] of using `curl
-| sh`, please keep reading and see our disclaimer below. And feel free to
-use a two-step version of the installation and examine our installation script:
-
-```bash
-$ curl https://sh.rustup.rs -sSf -o rustup.sh
-$ sh rustup.sh
-$ rustup install nightly
-```
-
-[insecurity]: http://curlpipesh.tumblr.com
-
-If you're on Windows, please download the [rustup installer][installer]
-and run it.
-
-[installer]: https://win.rustup.rs
-
-## Uninstalling
-
-If you decide you don't want Rust anymore, we'll be a bit sad, but that's okay.
-Not every programming language is great for everyone. Just run the uninstall
-command:
-
-```bash
-$ rustup self uninstall
-```
-
-Some people, and somewhat rightfully so, get very upset when we tell you to
-`curl | sh`. Basically, when you do this, you are trusting that the good
-people who maintain Rust aren't going to hack your computer and do bad things.
-That's a good instinct! If you're one of those people, please check out the
-documentation on [building Rust from Source][from-source], or [the official
-binary downloads][install-page].
-
-[from-source]: https://github.com/rust-lang/rust#building-from-source
-[install-page]: https://www.rust-lang.org/install.html
-
-Oh, we should also mention the officially supported platforms:
-
-* Windows (7+)
-* Linux (2.6.18 or later, various distributions), x86 and x86-64
-* OSX 10.7 (Lion) or greater, x86 and x86-64
-
-We extensively test Rust on these platforms, and a few others, too, like
-Android. But these are the ones most likely to work, as they have the most
-testing.
-
-Finally, a comment about Windows. Rust considers Windows to be a first-class
-platform upon release, but if we're honest, the Windows experience isn't as
-integrated as the Linux/OS X experience is. We're working on it! If anything
-does not work, it is a bug. Please let us know if that happens. Each and every
-commit is tested against Windows like any other platform.
-
-If you've got Rust installed, you can open up a shell, and type this:
-
-```bash
-$ rustc --version
-```
-
-You should see the version number, commit hash, commit date and build date:
-
-```bash
-rustc 1.0.0-nightly (f11f3e7ba 2015-01-04) (built 2015-01-06)
-```
-
-If you did, Rust has been installed successfully! Congrats!
-
-This installer also installs a copy of the documentation locally, so you can
-read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location.
-On Windows, it's in a `share/doc` directory, inside wherever you installed Rust
-to.
-
-If not, there are a number of places where you can get help. The easiest is
-[the #rust IRC channel on irc.mozilla.org][irc], which you can access through
-[Mibbit][mibbit]. Click that link, and you'll be chatting with other Rustaceans
-(a silly nickname we call ourselves), and we can help you out. Other great
-resources include [the users forum][users], and [Stack Overflow][stackoverflow].
-
-[irc]: irc://irc.mozilla.org/#rust
-[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
-[users]: https://users.rust-lang.org/
-[stackoverflow]: http://stackoverflow.com/questions/tagged/rust
-
diff --git a/src/doc/book/src/procedural-macros.md b/src/doc/book/src/procedural-macros.md
index 079324d56d1..4f5a6a7c033 100644
--- a/src/doc/book/src/procedural-macros.md
+++ b/src/doc/book/src/procedural-macros.md
@@ -170,7 +170,7 @@ a representation of our type (which can be either a `struct` or an `enum`).
 Check out the [docs](https://docs.rs/syn/0.10.5/syn/struct.MacroInput.html),
 there is some useful information there. We are able to get the name of the
 type using `ast.ident`. The `quote!` macro lets us write up the Rust code
-that we wish to return and convert it into `Tokens`. `quote!` let's us use some
+that we wish to return and convert it into `Tokens`. `quote!` lets us use some
 really cool templating mechanics; we simply write `#name` and `quote!` will
 replace it with the variable named `name`. You can even do some repetition
 similar to regular macros work. You should check out the
@@ -211,3 +211,76 @@ Hello, World! My name is Waffles
 ```
 
 We've done it!
+
+## Custom Attributes
+
+In some cases it might make sense to allow users some kind of configuration.
+For example, the user might want to overwrite the name that is printed in the `hello_world()` method.
+
+This can be achieved with custom attributes:
+
+```rust,ignore
+#[derive(HelloWorld)]
+#[HelloWorldName = "the best Pancakes"]
+struct Pancakes;
+
+fn main() {
+    Pancakes::hello_world();
+}
+```
+
+If we try to compile this though, the compiler will respond with an error:
+
+```bash
+error: The attribute `HelloWorldName` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
+```
+
+The compiler needs to know that we're handling this attribute and to not respond with an error.
+This is done in the `hello-world-derive` crate by adding `attributes` to the `proc_macro_derive` attribute:
+
+```rust,ignore
+#[proc_macro_derive(HelloWorld, attributes(HelloWorldName))]
+pub fn hello_world(input: TokenStream) -> TokenStream 
+```
+
+Multiple attributes can be specified that way.
+
+## Raising Errors
+
+Let's assume that we do not want to accept enums as input to our custom derive method.
+
+This condition can be easily checked with the help of `syn`. 
+But how do we tell the user, that we do not accept enums?
+The idiomatic way to report errors in procedural macros is to panic:
+
+```rust,ignore
+fn impl_hello_world(ast: &syn::MacroInput) -> quote::Tokens {
+    let name = &ast.ident;
+    // Check if derive(HelloWorld) was specified for a struct
+    if let syn::Body::Struct(_) = ast.body {
+        // Yes, this is a struct
+        quote! {
+            impl HelloWorld for #name {
+                fn hello_world() {
+                    println!("Hello, World! My name is {}", stringify!(#name));
+                }
+            }
+        }
+    } else {
+        //Nope. This is an Enum. We cannot handle these!
+       panic!("#[derive(HelloWorld)] is only defined for structs, not for enums!");
+    }
+}
+```
+
+If a user now tries to derive `HelloWorld` from an enum they will be greeted with following, hopefully helpful, error:
+
+```bash
+error: custom derive attribute panicked
+  --> src/main.rs
+   |
+   | #[derive(HelloWorld)]
+   |          ^^^^^^^^^^
+   |
+   = help: message: #[derive(HelloWorld)] is only defined for structs, not for enums!
+```
diff --git a/src/doc/book/src/the-stack-and-the-heap.md b/src/doc/book/src/the-stack-and-the-heap.md
index b9b3b801eae..6866505df13 100644
--- a/src/doc/book/src/the-stack-and-the-heap.md
+++ b/src/doc/book/src/the-stack-and-the-heap.md
@@ -86,7 +86,7 @@ to a large number, representing how much RAM your computer has. For example, if
 you have a gigabyte of RAM, your addresses go from `0` to `1,073,741,823`. That
 number comes from 2<sup>30</sup>, the number of bytes in a gigabyte. [^gigabyte]
 
-[^gigabyte]: ‘Gigabyte’ can mean two things: 10^9, or 2^30. The SI standard resolved this by stating that ‘gigabyte’ is 10^9, and ‘gibibyte’ is 2^30. However, very few people use this terminology, and rely on context to differentiate. We follow in that tradition here.
+[^gigabyte]: ‘Gigabyte’ can mean two things: 10<sup>9</sup>, or 2<sup>30</sup>. The IEC standard resolved this by stating that ‘gigabyte’ is 10<sup>9</sup>, and ‘gibibyte’ is 2<sup>30</sup>. However, very few people use this terminology, and rely on context to differentiate. We follow in that tradition here.
 
 This memory is kind of like a giant array: addresses start at zero and go
 up to the final number. So here’s a diagram of our first stack frame:
diff --git a/src/doc/book/src/unsafe.md b/src/doc/book/src/unsafe.md
index e90a4b1c268..9bf59fe2abd 100644
--- a/src/doc/book/src/unsafe.md
+++ b/src/doc/book/src/unsafe.md
@@ -139,4 +139,4 @@ I’ll repeat again: even though you _can_ do arbitrary things in unsafe blocks
 and functions doesn’t mean you should. The compiler will act as though you’re
 upholding its invariants, so be careful!
 
-[intrinsics]: intrinsics.html
+[intrinsics]: ../unstable-book/intrinsics.html
diff --git a/src/doc/book/src/using-rust-without-the-standard-library.md b/src/doc/book/src/using-rust-without-the-standard-library.md
index 8458f9314f9..709d10f4e47 100644
--- a/src/doc/book/src/using-rust-without-the-standard-library.md
+++ b/src/doc/book/src/using-rust-without-the-standard-library.md
@@ -9,7 +9,7 @@ don’t want to use the standard library via an attribute: `#![no_std]`.
 > Note: This feature is technically stable, but there are some caveats. For
 > one, you can build a `#![no_std]` _library_ on stable, but not a _binary_.
 > For details on binaries without the standard library, see [the nightly
-> chapter on `#![no_std]`](no-stdlib.html)
+> chapter on 'lang items'](../unstable-book/lang-items.html#using-libc)
 
 To use `#![no_std]`, add it to your crate root:
 
diff --git a/src/doc/guide-plugins.md b/src/doc/guide-plugins.md
index 742433b99ac..1ba28c0117d 100644
--- a/src/doc/guide-plugins.md
+++ b/src/doc/guide-plugins.md
@@ -1,4 +1,4 @@
 % The (old) Rust Compiler Plugins Guide
 
 This content has moved into
-[the Rust Programming Language book](book/compiler-plugins.html).
+[the Unstable Book](unstable-book/plugin.html).
diff --git a/src/doc/nomicon/src/exception-safety.md b/src/doc/nomicon/src/exception-safety.md
index 80e72cd5e36..a3cbc6abd69 100644
--- a/src/doc/nomicon/src/exception-safety.md
+++ b/src/doc/nomicon/src/exception-safety.md
@@ -93,7 +93,7 @@ uselessly. We would rather have the following:
 ```text
 bubble_up(heap, index):
     let elem = heap[index]
-    while index != 0 && element < heap[parent(index)]:
+    while index != 0 && elem < heap[parent(index)]:
         heap[index] = heap[parent(index)]
         index = parent(index)
     heap[index] = elem
@@ -137,7 +137,7 @@ If Rust had `try` and `finally` like in Java, we could do the following:
 bubble_up(heap, index):
     let elem = heap[index]
     try:
-        while index != 0 && element < heap[parent(index)]:
+        while index != 0 && elem < heap[parent(index)]:
             heap[index] = heap[parent(index)]
             index = parent(index)
     finally:
diff --git a/src/doc/nomicon/src/phantom-data.md b/src/doc/nomicon/src/phantom-data.md
index 72fa2e2a777..32539c2d01f 100644
--- a/src/doc/nomicon/src/phantom-data.md
+++ b/src/doc/nomicon/src/phantom-data.md
@@ -82,5 +82,23 @@ standard library made a utility for itself called `Unique<T>` which:
 
 * wraps a `*const T` for variance
 * includes a `PhantomData<T>`
-* auto-derives Send/Sync as if T was contained
-* marks the pointer as NonZero for the null-pointer optimization
+* auto-derives `Send`/`Sync` as if T was contained
+* marks the pointer as `NonZero` for the null-pointer optimization
+
+## Table of `PhantomData` patterns
+
+Here’s a table of all the wonderful ways `PhantomData` could be used:
+
+| Phantom type                | `'a`      | `T`                       |
+|-----------------------------|-----------|---------------------------|
+| `PhantomData<T>`            | -         | variant (with drop check) |
+| `PhantomData<&'a T>`        | variant   | variant                   |
+| `PhantomData<&'a mut T>`    | variant   | invariant                 |
+| `PhantomData<*const T>`     | -         | variant                   |
+| `PhantomData<*mut T>`       | -         | invariant                 |
+| `PhantomData<fn(T)>`        | -         | contravariant (*)         |
+| `PhantomData<fn() -> T>`    | -         | variant                   |
+| `PhantomData<fn(T) -> T>`   | -         | invariant                 |
+| `PhantomData<Cell<&'a ()>>` | invariant | -                         |
+
+(*) If contravariance gets scrapped, this would be invariant.
diff --git a/src/doc/reference/src/attributes.md b/src/doc/reference/src/attributes.md
index da43e1cc057..31814ef8c57 100644
--- a/src/doc/reference/src/attributes.md
+++ b/src/doc/reference/src/attributes.md
@@ -219,7 +219,7 @@ command line using `--cfg` (e.g. `rustc main.rs --cfg foo --cfg 'bar="baz"'`).
 Rust code then checks for their presence using the `#[cfg(...)]` attribute:
 
 ```
-// The function is only included in the build when compiling for OSX
+// The function is only included in the build when compiling for macOS
 #[cfg(target_os = "macos")]
 fn macos_only() {
   // ...
@@ -317,7 +317,7 @@ For any lint check `C`:
 
 The lint checks supported by the compiler can be found via `rustc -W help`,
 along with their default settings.  [Compiler
-plugins](../book/compiler-plugins.html#lint-plugins) can provide additional
+plugins](../unstable-book/plugin.html#lint-plugins) can provide additional
 lint checks.
 
 ```{.ignore}
diff --git a/src/doc/reference/src/linkage.md b/src/doc/reference/src/linkage.md
index 4755e4be8b6..28297a8ec1f 100644
--- a/src/doc/reference/src/linkage.md
+++ b/src/doc/reference/src/linkage.md
@@ -46,7 +46,7 @@ be ignored in favor of only building the artifacts specified by command line.
 * `--crate-type=cdylib`, `#[crate_type = "cdylib"]` - A dynamic system
   library will be produced.  This is used when compiling Rust code as
   a dynamic library to be loaded from another language.  This output type will
-  create `*.so` files on Linux, `*.dylib` files on OSX, and `*.dll` files on
+  create `*.so` files on Linux, `*.dylib` files on macOS, and `*.dll` files on
   Windows.
 
 * `--crate-type=rlib`, `#[crate_type = "rlib"]` - A "Rust library" file will be
diff --git a/src/doc/reference/src/macros.md b/src/doc/reference/src/macros.md
index 9ec5f2d6945..d64c40dcad8 100644
--- a/src/doc/reference/src/macros.md
+++ b/src/doc/reference/src/macros.md
@@ -14,4 +14,4 @@ And one unstable way: [compiler plugins].
 
 [Macros]: ../book/macros.html
 [Procedural Macros]: ../book/procedural-macros.html
-[compiler plugins]: ../book/compiler-plugins.html
+[compiler plugins]: ../unstable-book/plugin.html
diff --git a/src/doc/unstable-book/.gitignore b/src/doc/unstable-book/.gitignore
new file mode 100644
index 00000000000..7585238efed
--- /dev/null
+++ b/src/doc/unstable-book/.gitignore
@@ -0,0 +1 @@
+book
diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md
new file mode 100644
index 00000000000..ee8ae9a9839
--- /dev/null
+++ b/src/doc/unstable-book/src/SUMMARY.md
@@ -0,0 +1,94 @@
+[The Unstable Book](the-unstable-book.md)
+
+- [asm](asm.md)
+- [alloc_system](alloc-system.md)
+- [alloc_jemalloc](alloc-jemalloc.md)
+- [test](test.md)
+- [concat_idents](concat-idents.md)
+- [link_args](link-args.md)
+- [log_syntax](log-syntax.md)
+- [non_ascii_idents](non-ascii-idents.md)
+- [plugin_registrar](plugin-registrar.md)
+- [thread_local](thread-local.md)
+- [trace_macros](trace-macros.md)
+- [intrinsics](intrinsics.md)
+- [lang_items](lang-items.md)
+- [link_llvm_intrinsics](link-llvm-intrinsics.md)
+- [linkage](linkage.md)
+- [quote](quote.md)
+- [simd](simd.md)
+- [rustc_diagnostic_macros](rustc-diagnostic-macros.md)
+- [advanced_slice_patterns](advanced-slice-patterns.md)
+- [box_syntax](box-syntax.md)
+- [placement_in_syntax](placement-in-syntax.md)
+- [unboxed_closures](unboxed-closures.md)
+- [allocator](allocator.md)
+- [fundamental](fundamental.md)
+- [main](main.md)
+- [needs_allocator](needs-allocator.md)
+- [on_unimplemented](on-unimplemented.md)
+- [plugin](plugin.md)
+- [simd_ffi](simd-ffi.md)
+- [start](start.md)
+- [structural_match](structural-match.md)
+- [panic_runtime](panic-runtime.md)
+- [needs_panic_runtime](needs-panic-runtime.md)
+- [optin_builtin_traits](optin-builtin-traits.md)
+- [macro_reexport](macro-reexport.md)
+- [staged_api](staged-api.md)
+- [no_core](no-core.md)
+- [box_patterns](box-patterns.md)
+- [dropck_parametricity](dropck-parametricity.md)
+- [dropck_eyepatch](dropck-eyepatch.md)
+- [custom_attribute](custom-attribute.md)
+- [custom_derive](custom-derive.md)
+- [rustc_attrs](rustc-attrs.md)
+- [allow_internal_unstable](allow-internal-unstable.md)
+- [slice_patterns](slice-patterns.md)
+- [associated_consts](associated-consts.md)
+- [const_fn](const-fn.md)
+- [const_indexing](const-indexing.md)
+- [prelude_import](prelude-import.md)
+- [static_recursion](static-recursion.md)
+- [default_type_parameter_fallback](default-type-parameter-fallback.md)
+- [associated_type_defaults](associated-type-defaults.md)
+- [repr_simd](repr-simd.md)
+- [cfg_target_feature](cfg-target-feature.md)
+- [platform_intrinsics](platform-intrinsics.md)
+- [unwind_attributes](unwind-attributes.md)
+- [naked_functions](naked-functions.md)
+- [no_debug](no-debug.md)
+- [omit_gdb_pretty_printer_section](omit-gdb-pretty-printer-section.md)
+- [cfg_target_vendor](cfg-target-vendor.md)
+- [stmt_expr_attributes](stmt-expr-attributes.md)
+- [type_ascription](type-ascription.md)
+- [cfg_target_thread_local](cfg-target-thread-local.md)
+- [abi_vectorcall](abi-vectorcall.md)
+- [inclusive_range_syntax](inclusive-range-syntax.md)
+- [exclusive_range_pattern](exclusive-range-pattern.md)
+- [specialization](specialization.md)
+- [pub_restricted](pub-restricted.md)
+- [drop_types_in_const](drop-types-in-const.md)
+- [cfg_target_has_atomic](cfg-target-has-atomic.md)
+- [conservative_impl_trait](conservative-impl-trait.md)
+- [relaxed_adts](relaxed-adts.md)
+- [never_type](never-type.md)
+- [attr_literals](attr-literals.md)
+- [abi_sysv64](abi-sysv64.md)
+- [untagged_unions](untagged-unions.md)
+- [compiler_builtins](compiler-builtins.md)
+- [generic_param_attrs](generic-param-attrs.md)
+- [field_init_shorthand](field-init-shorthand.md)
+- [windows_subsystem](windows-subsystem.md)
+- [link_cfg](link-cfg.md)
+- [use_extern_macros](use-extern-macros.md)
+- [loop_break_value](loop-break-value.md)
+- [target_feature](target-feature.md)
+- [abi_ptx](abi-ptx.md)
+- [i128_type](i128-type.md)
+- [abi_unadjusted](abi-unadjusted.md)
+- [proc_macro](proc-macro.md)
+- [struct_field_attributes](struct-field-attributes.md)
+- [static_nobundle](static-nobundle.md)
+- [abi_msp430_interrupt](abi-msp430-interrupt.md)
+- [sanitizer_runtime](sanitizer-runtime.md)
diff --git a/src/doc/unstable-book/src/abi-msp430-interrupt.md b/src/doc/unstable-book/src/abi-msp430-interrupt.md
new file mode 100644
index 00000000000..9b2c7f29897
--- /dev/null
+++ b/src/doc/unstable-book/src/abi-msp430-interrupt.md
@@ -0,0 +1,7 @@
+# `abi_msp430_interrupt`
+
+The tracking issue for this feature is: [#38487]
+
+[#38487]: https://github.com/rust-lang/rust/issues/38487
+
+------------------------
diff --git a/src/doc/unstable-book/src/abi-ptx.md b/src/doc/unstable-book/src/abi-ptx.md
new file mode 100644
index 00000000000..9c1b8868ace
--- /dev/null
+++ b/src/doc/unstable-book/src/abi-ptx.md
@@ -0,0 +1,5 @@
+# `abi_ptx`
+
+The tracking issue for this feature is: None.
+
+------------------------
diff --git a/src/doc/unstable-book/src/abi-sysv64.md b/src/doc/unstable-book/src/abi-sysv64.md
new file mode 100644
index 00000000000..27f61d56342
--- /dev/null
+++ b/src/doc/unstable-book/src/abi-sysv64.md
@@ -0,0 +1,7 @@
+# `abi_sysv64`
+
+The tracking issue for this feature is: [#36167]
+
+[#36167]: https://github.com/rust-lang/rust/issues/36167
+
+------------------------
diff --git a/src/doc/unstable-book/src/abi-unadjusted.md b/src/doc/unstable-book/src/abi-unadjusted.md
new file mode 100644
index 00000000000..2e3113abdbf
--- /dev/null
+++ b/src/doc/unstable-book/src/abi-unadjusted.md
@@ -0,0 +1,6 @@
+# `abi_unadjusted`
+
+The tracking issue for this feature is: none.
+
+------------------------
+
diff --git a/src/doc/unstable-book/src/abi-vectorcall.md b/src/doc/unstable-book/src/abi-vectorcall.md
new file mode 100644
index 00000000000..3e36b1569fd
--- /dev/null
+++ b/src/doc/unstable-book/src/abi-vectorcall.md
@@ -0,0 +1,7 @@
+# `abi_vectorcall`
+
+The tracking issue for this feature is: none.
+
+------------------------
+
+
diff --git a/src/doc/book/src/slice-patterns.md b/src/doc/unstable-book/src/advanced-slice-patterns.md
index 3f7398dde5e..30d22ca8208 100644
--- a/src/doc/book/src/slice-patterns.md
+++ b/src/doc/unstable-book/src/advanced-slice-patterns.md
@@ -1,20 +1,13 @@
-# Slice patterns
+# `advanced_slice_patterns`
 
-If you want to match against a slice or array, you can use `&` with the
-`slice_patterns` feature:
+The tracking issue for this feature is: [#23121]
 
-```rust
-#![feature(slice_patterns)]
+[#23121]: https://github.com/rust-lang/rust/issues/23121
 
-fn main() {
-    let v = vec!["match_this", "1"];
+See also [`slice_patterns`](slice-patterns.html).
+
+------------------------
 
-    match &v[..] {
-        &["match_this", second] => println!("The second element is {}", second),
-        _ => {},
-    }
-}
-```
 
 The `advanced_slice_patterns` gate lets you use `..` to indicate any number of
 elements inside a pattern matching a slice. This wildcard can only be used once
diff --git a/src/doc/unstable-book/src/alloc-jemalloc.md b/src/doc/unstable-book/src/alloc-jemalloc.md
new file mode 100644
index 00000000000..9bffa2ff99b
--- /dev/null
+++ b/src/doc/unstable-book/src/alloc-jemalloc.md
@@ -0,0 +1,62 @@
+# `alloc_jemalloc`
+
+The tracking issue for this feature is: [#33082]
+
+[#33082]: https://github.com/rust-lang/rust/issues/33082
+
+See also [`alloc_system`](alloc-system.html).
+
+------------------------
+
+The compiler currently ships two default allocators: `alloc_system` and
+`alloc_jemalloc` (some targets don't have jemalloc, however). These allocators
+are normal Rust crates and contain an implementation of the routines to
+allocate and deallocate memory. The standard library is not compiled assuming
+either one, and the compiler will decide which allocator is in use at
+compile-time depending on the type of output artifact being produced.
+
+Binaries generated by the compiler will use `alloc_jemalloc` by default (where
+available). In this situation the compiler "controls the world" in the sense of
+it has power over the final link. Primarily this means that the allocator
+decision can be left up the compiler.
+
+Dynamic and static libraries, however, will use `alloc_system` by default. Here
+Rust is typically a 'guest' in another application or another world where it
+cannot authoritatively decide what allocator is in use. As a result it resorts
+back to the standard APIs (e.g. `malloc` and `free`) for acquiring and releasing
+memory.
+
+# Switching Allocators
+
+Although the compiler's default choices may work most of the time, it's often
+necessary to tweak certain aspects. Overriding the compiler's decision about
+which allocator is in use is done simply by linking to the desired allocator:
+
+```rust,no_run
+#![feature(alloc_system)]
+
+extern crate alloc_system;
+
+fn main() {
+    let a = Box::new(4); // Allocates from the system allocator.
+    println!("{}", a);
+}
+```
+
+In this example the binary generated will not link to jemalloc by default but
+instead use the system allocator. Conversely to generate a dynamic library which
+uses jemalloc by default one would write:
+
+```rust,ignore
+#![feature(alloc_jemalloc)]
+#![crate_type = "dylib"]
+
+extern crate alloc_jemalloc;
+
+pub fn foo() {
+    let a = Box::new(4); // Allocates from jemalloc.
+    println!("{}", a);
+}
+# fn main() {}
+```
+
diff --git a/src/doc/unstable-book/src/alloc-system.md b/src/doc/unstable-book/src/alloc-system.md
new file mode 100644
index 00000000000..6fa89179d8e
--- /dev/null
+++ b/src/doc/unstable-book/src/alloc-system.md
@@ -0,0 +1,62 @@
+# `alloc_system`
+
+The tracking issue for this feature is: [#33082]
+
+[#33082]: https://github.com/rust-lang/rust/issues/33082
+
+See also [`alloc_jemalloc`](alloc-jemalloc.html).
+
+------------------------
+
+The compiler currently ships two default allocators: `alloc_system` and
+`alloc_jemalloc` (some targets don't have jemalloc, however). These allocators
+are normal Rust crates and contain an implementation of the routines to
+allocate and deallocate memory. The standard library is not compiled assuming
+either one, and the compiler will decide which allocator is in use at
+compile-time depending on the type of output artifact being produced.
+
+Binaries generated by the compiler will use `alloc_jemalloc` by default (where
+available). In this situation the compiler "controls the world" in the sense of
+it has power over the final link. Primarily this means that the allocator
+decision can be left up the compiler.
+
+Dynamic and static libraries, however, will use `alloc_system` by default. Here
+Rust is typically a 'guest' in another application or another world where it
+cannot authoritatively decide what allocator is in use. As a result it resorts
+back to the standard APIs (e.g. `malloc` and `free`) for acquiring and releasing
+memory.
+
+# Switching Allocators
+
+Although the compiler's default choices may work most of the time, it's often
+necessary to tweak certain aspects. Overriding the compiler's decision about
+which allocator is in use is done simply by linking to the desired allocator:
+
+```rust,no_run
+#![feature(alloc_system)]
+
+extern crate alloc_system;
+
+fn main() {
+    let a = Box::new(4); // Allocates from the system allocator.
+    println!("{}", a);
+}
+```
+
+In this example the binary generated will not link to jemalloc by default but
+instead use the system allocator. Conversely to generate a dynamic library which
+uses jemalloc by default one would write:
+
+```rust,ignore
+#![feature(alloc_jemalloc)]
+#![crate_type = "dylib"]
+
+extern crate alloc_jemalloc;
+
+pub fn foo() {
+    let a = Box::new(4); // Allocates from jemalloc.
+    println!("{}", a);
+}
+# fn main() {}
+```
+
diff --git a/src/doc/book/src/custom-allocators.md b/src/doc/unstable-book/src/allocator.md
index 154b5f0f4e2..7261641698f 100644
--- a/src/doc/book/src/custom-allocators.md
+++ b/src/doc/unstable-book/src/allocator.md
@@ -1,69 +1,10 @@
-# Custom Allocators
+# `allocator`
 
-Allocating memory isn't always the easiest thing to do, and while Rust generally
-takes care of this by default it often becomes necessary to customize how
-allocation occurs. The compiler and standard library currently allow switching
-out the default global allocator in use at compile time. The design is currently
-spelled out in [RFC 1183][rfc] but this will walk you through how to get your
-own allocator up and running.
+The tracking issue for this feature is: [#27389]
 
-[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1183-swap-out-jemalloc.md
+[#27389]: https://github.com/rust-lang/rust/issues/27389
 
-# Default Allocator
-
-The compiler currently ships two default allocators: `alloc_system` and
-`alloc_jemalloc` (some targets don't have jemalloc, however). These allocators
-are normal Rust crates and contain an implementation of the routines to
-allocate and deallocate memory. The standard library is not compiled assuming
-either one, and the compiler will decide which allocator is in use at
-compile-time depending on the type of output artifact being produced.
-
-Binaries generated by the compiler will use `alloc_jemalloc` by default (where
-available). In this situation the compiler "controls the world" in the sense of
-it has power over the final link. Primarily this means that the allocator
-decision can be left up the compiler.
-
-Dynamic and static libraries, however, will use `alloc_system` by default. Here
-Rust is typically a 'guest' in another application or another world where it
-cannot authoritatively decide what allocator is in use. As a result it resorts
-back to the standard APIs (e.g. `malloc` and `free`) for acquiring and releasing
-memory.
-
-# Switching Allocators
-
-Although the compiler's default choices may work most of the time, it's often
-necessary to tweak certain aspects. Overriding the compiler's decision about
-which allocator is in use is done simply by linking to the desired allocator:
-
-```rust,no_run
-#![feature(alloc_system)]
-
-extern crate alloc_system;
-
-fn main() {
-    let a = Box::new(4); // Allocates from the system allocator.
-    println!("{}", a);
-}
-```
-
-In this example the binary generated will not link to jemalloc by default but
-instead use the system allocator. Conversely to generate a dynamic library which
-uses jemalloc by default one would write:
-
-```rust,ignore
-#![feature(alloc_jemalloc)]
-#![crate_type = "dylib"]
-
-extern crate alloc_jemalloc;
-
-pub fn foo() {
-    let a = Box::new(4); // Allocates from jemalloc.
-    println!("{}", a);
-}
-# fn main() {}
-```
-
-# Writing a custom allocator
+------------------------
 
 Sometimes even the choices of jemalloc vs the system allocator aren't enough and
 an entirely new custom allocator is required. In this you'll write your own
@@ -154,7 +95,7 @@ fn main() {
 }
 ```
 
-# Custom allocator limitations
+## Custom allocator limitations
 
 There are a few restrictions when working with custom allocators which may cause
 compiler errors:
@@ -169,3 +110,5 @@ compiler errors:
   depend on a crate which needs an allocator (e.g. circular dependencies are not
   allowed). This basically means that allocators must restrict themselves to
   libcore currently.
+
+
diff --git a/src/doc/unstable-book/src/allow-internal-unstable.md b/src/doc/unstable-book/src/allow-internal-unstable.md
new file mode 100644
index 00000000000..74709ad5aeb
--- /dev/null
+++ b/src/doc/unstable-book/src/allow-internal-unstable.md
@@ -0,0 +1,6 @@
+# `allow_internal_unstable`
+
+The tracking issue for this feature is: None.
+
+------------------------
+
diff --git a/src/doc/book/src/inline-assembly.md b/src/doc/unstable-book/src/asm.md
index 4262289acbf..032d9d81240 100644
--- a/src/doc/book/src/inline-assembly.md
+++ b/src/doc/unstable-book/src/asm.md
@@ -1,4 +1,10 @@
-# Inline Assembly
+# `asm`
+
+The tracking issue for this feature is: [#29722]
+
+[#29722]: https://github.com/rust-lang/rust/issues/29722
+
+------------------------
 
 For extremely low-level manipulations and performance reasons, one
 might wish to control the CPU directly. Rust supports using inline
@@ -182,3 +188,4 @@ documentation as well][llvm-docs] for more information about clobbers,
 constraints, etc.
 
 [llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions
+
diff --git a/src/doc/book/src/associated-constants.md b/src/doc/unstable-book/src/associated-consts.md
index 61bad3d3948..d661108e7d9 100644
--- a/src/doc/book/src/associated-constants.md
+++ b/src/doc/unstable-book/src/associated-consts.md
@@ -1,4 +1,10 @@
-# Associated Constants
+# `associated_consts`
+
+The tracking issue for this feature is: [#29646]
+
+[#29646]: https://github.com/rust-lang/rust/issues/29646
+
+------------------------
 
 With the `associated_consts` feature, you can define constants like this:
 
diff --git a/src/doc/unstable-book/src/associated-type-defaults.md b/src/doc/unstable-book/src/associated-type-defaults.md
new file mode 100644
index 00000000000..56cc8a5b306
--- /dev/null
+++ b/src/doc/unstable-book/src/associated-type-defaults.md
@@ -0,0 +1,10 @@
+# `associated_type_defaults`
+
+The tracking issue for this feature is: [#29661]
+
+[#29661]: https://github.com/rust-lang/rust/issues/29661
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/attr-literals.md b/src/doc/unstable-book/src/attr-literals.md
new file mode 100644
index 00000000000..67eee214a4f
--- /dev/null
+++ b/src/doc/unstable-book/src/attr-literals.md
@@ -0,0 +1,10 @@
+# `attr_literals`
+
+The tracking issue for this feature is: [#34981]
+
+[#34981]: https://github.com/rust-lang/rust/issues/34981
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/box-patterns.md b/src/doc/unstable-book/src/box-patterns.md
new file mode 100644
index 00000000000..86346364a71
--- /dev/null
+++ b/src/doc/unstable-book/src/box-patterns.md
@@ -0,0 +1,32 @@
+# `box_patterns`
+
+The tracking issue for this feature is: [#29641]
+
+[#29641]: https://github.com/rust-lang/rust/issues/29641
+
+See also [`box_syntax`](box-syntax.html)
+
+------------------------
+
+Box patterns let you match on `Box<T>`s:
+
+
+```rust
+#![feature(box_patterns)]
+
+fn main() {
+    let b = Some(Box::new(5));
+    match b {
+        Some(box n) if n < 0 => {
+            println!("Box contains negative number {}", n);
+        },
+        Some(box n) if n >= 0 => {
+            println!("Box contains non-negative number {}", n);
+        },
+        None => {
+            println!("No box");
+        },
+        _ => unreachable!()
+    }
+}
+```
diff --git a/src/doc/unstable-book/src/box-syntax.md b/src/doc/unstable-book/src/box-syntax.md
new file mode 100644
index 00000000000..47aade0d045
--- /dev/null
+++ b/src/doc/unstable-book/src/box-syntax.md
@@ -0,0 +1,22 @@
+# `box_syntax`
+
+The tracking issue for this feature is: [#27779]
+
+[#27779]: https://github.com/rust-lang/rust/issues/27779
+
+See also [`box_patterns`](box-patterns.html)
+
+------------------------
+
+Currently the only stable way to create a `Box` is via the `Box::new` method.
+Also it is not possible in stable Rust to destructure a `Box` in a match
+pattern. The unstable `box` keyword can be used to create a `Box`. An example
+usage would be:
+
+```rust
+#![feature(box_syntax)]
+
+fn main() {
+    let b = box 5;
+}
+```
diff --git a/src/doc/unstable-book/src/cfg-target-feature.md b/src/doc/unstable-book/src/cfg-target-feature.md
new file mode 100644
index 00000000000..ddd88bdc2cb
--- /dev/null
+++ b/src/doc/unstable-book/src/cfg-target-feature.md
@@ -0,0 +1,10 @@
+# `cfg_target_feature`
+
+The tracking issue for this feature is: [#29717]
+
+[#29717]: https://github.com/rust-lang/rust/issues/29717
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/cfg-target-has-atomic.md b/src/doc/unstable-book/src/cfg-target-has-atomic.md
new file mode 100644
index 00000000000..7496e42e1cd
--- /dev/null
+++ b/src/doc/unstable-book/src/cfg-target-has-atomic.md
@@ -0,0 +1,10 @@
+# `cfg_target_has_atomic`
+
+The tracking issue for this feature is: [#32976]
+
+[#32976]: https://github.com/rust-lang/rust/issues/32976
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/cfg-target-thread-local.md b/src/doc/unstable-book/src/cfg-target-thread-local.md
new file mode 100644
index 00000000000..a5adb38db3d
--- /dev/null
+++ b/src/doc/unstable-book/src/cfg-target-thread-local.md
@@ -0,0 +1,10 @@
+# `cfg_target_thread_local`
+
+The tracking issue for this feature is: [#29594]
+
+[#29594]: https://github.com/rust-lang/rust/issues/29594
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/cfg-target-vendor.md b/src/doc/unstable-book/src/cfg-target-vendor.md
new file mode 100644
index 00000000000..ddd88bdc2cb
--- /dev/null
+++ b/src/doc/unstable-book/src/cfg-target-vendor.md
@@ -0,0 +1,10 @@
+# `cfg_target_feature`
+
+The tracking issue for this feature is: [#29717]
+
+[#29717]: https://github.com/rust-lang/rust/issues/29717
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/compiler-builtins.md b/src/doc/unstable-book/src/compiler-builtins.md
new file mode 100644
index 00000000000..3ec3cba257a
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-builtins.md
@@ -0,0 +1,6 @@
+# `compiler_builtins`
+
+The tracking issue for this feature is: None.
+
+------------------------
+
diff --git a/src/doc/unstable-book/src/concat-idents.md b/src/doc/unstable-book/src/concat-idents.md
new file mode 100644
index 00000000000..c9a48293dba
--- /dev/null
+++ b/src/doc/unstable-book/src/concat-idents.md
@@ -0,0 +1,10 @@
+# `concat_idents`
+
+The tracking issue for this feature is: [#29599]
+
+[#29599]: https://github.com/rust-lang/rust/issues/29599
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/conservative-impl-trait.md b/src/doc/unstable-book/src/conservative-impl-trait.md
new file mode 100644
index 00000000000..7d8bda439bd
--- /dev/null
+++ b/src/doc/unstable-book/src/conservative-impl-trait.md
@@ -0,0 +1,10 @@
+# `conservative_impl_trait`
+
+The tracking issue for this feature is: [#34511]
+
+[#34511]: https://github.com/rust-lang/rust/issues/34511
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/const-fn.md b/src/doc/unstable-book/src/const-fn.md
new file mode 100644
index 00000000000..9b7942c408a
--- /dev/null
+++ b/src/doc/unstable-book/src/const-fn.md
@@ -0,0 +1,10 @@
+# `const_fn`
+
+The tracking issue for this feature is: [#24111]
+
+[#24111]: https://github.com/rust-lang/rust/issues/24111
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/const-indexing.md b/src/doc/unstable-book/src/const-indexing.md
new file mode 100644
index 00000000000..bd92b0b1b47
--- /dev/null
+++ b/src/doc/unstable-book/src/const-indexing.md
@@ -0,0 +1,10 @@
+# `const_indexing`
+
+The tracking issue for this feature is: [#29947]
+
+[#29947]: https://github.com/rust-lang/rust/issues/29947
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/custom-attribute.md b/src/doc/unstable-book/src/custom-attribute.md
new file mode 100644
index 00000000000..838f09670d2
--- /dev/null
+++ b/src/doc/unstable-book/src/custom-attribute.md
@@ -0,0 +1,10 @@
+# `custom_attribute`
+
+The tracking issue for this feature is: [#29642]
+
+[#29642]: https://github.com/rust-lang/rust/issues/29642
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/custom-derive.md b/src/doc/unstable-book/src/custom-derive.md
new file mode 100644
index 00000000000..d5fdd2b708b
--- /dev/null
+++ b/src/doc/unstable-book/src/custom-derive.md
@@ -0,0 +1,10 @@
+# `custom_derive`
+
+The tracking issue for this feature is: [#29644]
+
+[#29644]: https://github.com/rust-lang/rust/issues/29644
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/default-type-parameter-fallback.md b/src/doc/unstable-book/src/default-type-parameter-fallback.md
new file mode 100644
index 00000000000..fd16dbf8985
--- /dev/null
+++ b/src/doc/unstable-book/src/default-type-parameter-fallback.md
@@ -0,0 +1,10 @@
+# `default_type_parameter_fallback`
+
+The tracking issue for this feature is: [#27336]
+
+[#27336]: https://github.com/rust-lang/rust/issues/27336
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/drop-types-in-const.md b/src/doc/unstable-book/src/drop-types-in-const.md
new file mode 100644
index 00000000000..b3367d0df44
--- /dev/null
+++ b/src/doc/unstable-book/src/drop-types-in-const.md
@@ -0,0 +1,10 @@
+# `drop_types_in_const`
+
+The tracking issue for this feature is: [#33156]
+
+[#33156]: https://github.com/rust-lang/rust/issues/33156
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/dropck-eyepatch.md b/src/doc/unstable-book/src/dropck-eyepatch.md
new file mode 100644
index 00000000000..2f189e9b645
--- /dev/null
+++ b/src/doc/unstable-book/src/dropck-eyepatch.md
@@ -0,0 +1,10 @@
+# `dropck_eyepatch`
+
+The tracking issue for this feature is: [#34761]
+
+[#34761]: https://github.com/rust-lang/rust/issues/34761
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/dropck-parametricity.md b/src/doc/unstable-book/src/dropck-parametricity.md
new file mode 100644
index 00000000000..c5ae721954b
--- /dev/null
+++ b/src/doc/unstable-book/src/dropck-parametricity.md
@@ -0,0 +1,10 @@
+# `dropck_parametricity`
+
+The tracking issue for this feature is: [#28498]
+
+[#28498]: https://github.com/rust-lang/rust/issues/28498
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/exclusive-range-pattern.md b/src/doc/unstable-book/src/exclusive-range-pattern.md
new file mode 100644
index 00000000000..b669ce83132
--- /dev/null
+++ b/src/doc/unstable-book/src/exclusive-range-pattern.md
@@ -0,0 +1,10 @@
+# `exclusive_range_pattern`
+
+The tracking issue for this feature is: [#37854]
+
+[#37854]: https://github.com/rust-lang/rust/issues/37854
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/field-init-shorthand.md b/src/doc/unstable-book/src/field-init-shorthand.md
new file mode 100644
index 00000000000..e737dbaa4ec
--- /dev/null
+++ b/src/doc/unstable-book/src/field-init-shorthand.md
@@ -0,0 +1,10 @@
+# `field_init_shorthand`
+
+The tracking issue for this feature is: [#37340]
+
+[#37340]: https://github.com/rust-lang/rust/issues/37340
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/fundamental.md b/src/doc/unstable-book/src/fundamental.md
new file mode 100644
index 00000000000..a068dadf95d
--- /dev/null
+++ b/src/doc/unstable-book/src/fundamental.md
@@ -0,0 +1,10 @@
+# `fundamental`
+
+The tracking issue for this feature is: [#29635]
+
+[#29635]: https://github.com/rust-lang/rust/issues/29635
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/generic-param-attrs.md b/src/doc/unstable-book/src/generic-param-attrs.md
new file mode 100644
index 00000000000..ba49c850e4d
--- /dev/null
+++ b/src/doc/unstable-book/src/generic-param-attrs.md
@@ -0,0 +1,10 @@
+# `generic_param_attrs`
+
+The tracking issue for this feature is: [#34761]
+
+[#34761]: https://github.com/rust-lang/rust/issues/34761
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/i128-type.md b/src/doc/unstable-book/src/i128-type.md
new file mode 100644
index 00000000000..ffcf45feb2a
--- /dev/null
+++ b/src/doc/unstable-book/src/i128-type.md
@@ -0,0 +1,10 @@
+# `i128_type`
+
+The tracking issue for this feature is: [#35118]
+
+[#35118]: https://github.com/rust-lang/rust/issues/35118
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/inclusive-range-syntax.md b/src/doc/unstable-book/src/inclusive-range-syntax.md
new file mode 100644
index 00000000000..74d85536399
--- /dev/null
+++ b/src/doc/unstable-book/src/inclusive-range-syntax.md
@@ -0,0 +1,10 @@
+# `inclusive_range_syntax`
+
+The tracking issue for this feature is: [#28237]
+
+[#28237]: https://github.com/rust-lang/rust/issues/28237
+
+------------------------
+
+
+
diff --git a/src/doc/book/src/intrinsics.md b/src/doc/unstable-book/src/intrinsics.md
index e1edce3e80f..bc35c2a0305 100644
--- a/src/doc/book/src/intrinsics.md
+++ b/src/doc/unstable-book/src/intrinsics.md
@@ -1,8 +1,13 @@
-# Intrinsics
+# `intrinsics`
+
+The tracking issue for this feature is: None.
+
+Intrinsics are never intended to be stable directly, but intrinsics are often
+exported in some sort of stable manner. Prefer using the stable interfaces to
+the intrinsic directly when you can.
+
+------------------------
 
-> **Note**: intrinsics will forever have an unstable interface, it is
-> recommended to use the stable interfaces of libcore rather than intrinsics
-> directly.
 
 These are imported as if they were FFI functions, with the special
 `rust-intrinsic` ABI. For example, if one was in a freestanding
diff --git a/src/doc/book/src/no-stdlib.md b/src/doc/unstable-book/src/lang-items.md
index dcb0fbc8005..375b8bd6b82 100644
--- a/src/doc/book/src/no-stdlib.md
+++ b/src/doc/unstable-book/src/lang-items.md
@@ -1,23 +1,97 @@
-# No stdlib
+# `lang_items`
 
-Rust’s standard library provides a lot of useful functionality, but assumes
-support for various features of its host system: threads, networking, heap
-allocation, and others. There are systems that do not have these features,
-however, and Rust can work with those too! To do so, we tell Rust that we
-don’t want to use the standard library via an attribute: `#![no_std]`.
+The tracking issue for this feature is: None.
 
-> Note: This feature is technically stable, but there are some caveats. For
-> one, you can build a `#![no_std]` _library_ on stable, but not a _binary_.
-> For details on libraries without the standard library, see [the chapter on
-> `#![no_std]`](using-rust-without-the-standard-library.html)
+------------------------
 
-Obviously there's more to life than just libraries: one can use
-`#[no_std]` with an executable.
+The `rustc` compiler has certain pluggable operations, that is,
+functionality that isn't hard-coded into the language, but is
+implemented in libraries, with a special marker to tell the compiler
+it exists. The marker is the attribute `#[lang = "..."]` and there are
+various different values of `...`, i.e. various different 'lang
+items'.
+
+For example, `Box` pointers require two lang items, one for allocation
+and one for deallocation. A freestanding program that uses the `Box`
+sugar for dynamic allocations via `malloc` and `free`:
+
+```rust,ignore
+#![feature(lang_items, box_syntax, start, libc, core_intrinsics)]
+#![no_std]
+use core::intrinsics;
+
+extern crate libc;
+
+#[lang = "owned_box"]
+pub struct Box<T>(*mut T);
+
+#[lang = "exchange_malloc"]
+unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
+    let p = libc::malloc(size as libc::size_t) as *mut u8;
+
+    // Check if `malloc` failed:
+    if p as usize == 0 {
+        intrinsics::abort();
+    }
+
+    p
+}
+
+#[lang = "exchange_free"]
+unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
+    libc::free(ptr as *mut libc::c_void)
+}
+
+#[lang = "box_free"]
+unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
+    deallocate(ptr as *mut u8, ::core::mem::size_of_val(&*ptr), ::core::mem::align_of_val(&*ptr));
+}
+
+#[start]
+fn main(argc: isize, argv: *const *const u8) -> isize {
+    let x = box 1;
+
+    0
+}
+
+#[lang = "eh_personality"] extern fn rust_eh_personality() {}
+#[lang = "panic_fmt"] extern fn rust_begin_panic() -> ! { unsafe { intrinsics::abort() } }
+# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
+# #[no_mangle] pub extern fn rust_eh_register_frames () {}
+# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
+```
+
+Note the use of `abort`: the `exchange_malloc` lang item is assumed to
+return a valid pointer, and so needs to do the check internally.
+
+Other features provided by lang items include:
+
+- overloadable operators via traits: the traits corresponding to the
+  `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all
+  marked with lang items; those specific four are `eq`, `ord`,
+  `deref`, and `add` respectively.
+- stack unwinding and general failure; the `eh_personality`,
+  `eh_unwind_resume`, `fail` and `fail_bounds_checks` lang items.
+- the traits in `std::marker` used to indicate types of
+  various kinds; lang items `send`, `sync` and `copy`.
+- the marker types and variance indicators found in
+  `std::marker`; lang items `covariant_type`,
+  `contravariant_lifetime`, etc.
+
+Lang items are loaded lazily by the compiler; e.g. if one never uses
+`Box` then there is no need to define functions for `exchange_malloc`
+and `exchange_free`. `rustc` will emit an error when an item is needed
+but not found in the current crate or any that it depends on.
+
+Most lang items are defined by `libcore`, but if you're trying to build
+an executable without the standard library, you'll run into the need
+for lang items. The rest of this page focuses on this use-case, even though
+lang items are a bit broader than that.
 
 ### Using libc
 
-In order to build a `#[no_std]` executable we will need libc as a dependency. We can specify
-this using our `Cargo.toml` file:
+In order to build a `#[no_std]` executable we will need libc as a dependency.
+We can specify this using our `Cargo.toml` file:
 
 ```toml
 [dependencies]
diff --git a/src/doc/unstable-book/src/link-args.md b/src/doc/unstable-book/src/link-args.md
new file mode 100644
index 00000000000..2507197661a
--- /dev/null
+++ b/src/doc/unstable-book/src/link-args.md
@@ -0,0 +1,32 @@
+# `link_args`
+
+The tracking issue for this feature is: [#29596]
+
+[#29596]: https://github.com/rust-lang/rust/issues/29596
+
+------------------------
+
+You can tell `rustc` how to customize linking, and that is via the `link_args`
+attribute. This attribute is applied to `extern` blocks and specifies raw flags
+which need to get passed to the linker when producing an artifact. An example
+usage would be:
+
+```rust,no_run
+#![feature(link_args)]
+
+#[link_args = "-foo -bar -baz"]
+extern {}
+# fn main() {}
+```
+
+Note that this feature is currently hidden behind the `feature(link_args)` gate
+because this is not a sanctioned way of performing linking. Right now `rustc`
+shells out to the system linker (`gcc` on most systems, `link.exe` on MSVC), so
+it makes sense to provide extra command line arguments, but this will not
+always be the case. In the future `rustc` may use LLVM directly to link native
+libraries, in which case `link_args` will have no meaning. You can achieve the
+same effect as the `link_args` attribute with the `-C link-args` argument to
+`rustc`.
+
+It is highly recommended to *not* use this attribute, and rather use the more
+formal `#[link(...)]` attribute on `extern` blocks instead.
diff --git a/src/doc/unstable-book/src/link-cfg.md b/src/doc/unstable-book/src/link-cfg.md
new file mode 100644
index 00000000000..7393d0628e4
--- /dev/null
+++ b/src/doc/unstable-book/src/link-cfg.md
@@ -0,0 +1,10 @@
+# `link_cfg`
+
+The tracking issue for this feature is: [#37406]
+
+[#37406]: https://github.com/rust-lang/rust/issues/37406
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/link-llvm-intrinsics.md b/src/doc/unstable-book/src/link-llvm-intrinsics.md
new file mode 100644
index 00000000000..ba639cb57fc
--- /dev/null
+++ b/src/doc/unstable-book/src/link-llvm-intrinsics.md
@@ -0,0 +1,10 @@
+# `link_llvm_intrinsics`
+
+The tracking issue for this feature is: [#29602]
+
+[#29602]: https://github.com/rust-lang/rust/issues/29602
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/linkage.md b/src/doc/unstable-book/src/linkage.md
new file mode 100644
index 00000000000..5773d28a00e
--- /dev/null
+++ b/src/doc/unstable-book/src/linkage.md
@@ -0,0 +1,10 @@
+# `linkage`
+
+The tracking issue for this feature is: [#29603]
+
+[#29603]: https://github.com/rust-lang/rust/issues/29603
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/log-syntax.md b/src/doc/unstable-book/src/log-syntax.md
new file mode 100644
index 00000000000..b13f5ccfd91
--- /dev/null
+++ b/src/doc/unstable-book/src/log-syntax.md
@@ -0,0 +1,10 @@
+# `log_syntax`
+
+The tracking issue for this feature is: [#29598]
+
+[#29598]: https://github.com/rust-lang/rust/issues/29598
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/loop-break-value.md b/src/doc/unstable-book/src/loop-break-value.md
new file mode 100644
index 00000000000..54d6e62ce4c
--- /dev/null
+++ b/src/doc/unstable-book/src/loop-break-value.md
@@ -0,0 +1,10 @@
+# `loop_break_value`
+
+The tracking issue for this feature is: [#37339]
+
+[#37339]: https://github.com/rust-lang/rust/issues/37339
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/macro-reexport.md b/src/doc/unstable-book/src/macro-reexport.md
new file mode 100644
index 00000000000..32ffa3b4c31
--- /dev/null
+++ b/src/doc/unstable-book/src/macro-reexport.md
@@ -0,0 +1,10 @@
+# `macro_reexport`
+
+The tracking issue for this feature is: [#29638]
+
+[#29638]: https://github.com/rust-lang/rust/issues/29638
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/main.md b/src/doc/unstable-book/src/main.md
new file mode 100644
index 00000000000..579aabfff88
--- /dev/null
+++ b/src/doc/unstable-book/src/main.md
@@ -0,0 +1,10 @@
+# `main`
+
+The tracking issue for this feature is: [#29634]
+
+[#29634]: https://github.com/rust-lang/rust/issues/29634
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/naked-functions.md b/src/doc/unstable-book/src/naked-functions.md
new file mode 100644
index 00000000000..e56ce4770aa
--- /dev/null
+++ b/src/doc/unstable-book/src/naked-functions.md
@@ -0,0 +1,10 @@
+# `naked_functions`
+
+The tracking issue for this feature is: [#32408]
+
+[#32408]: https://github.com/rust-lang/rust/issues/32408
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/needs-allocator.md b/src/doc/unstable-book/src/needs-allocator.md
new file mode 100644
index 00000000000..22aa10b2183
--- /dev/null
+++ b/src/doc/unstable-book/src/needs-allocator.md
@@ -0,0 +1,10 @@
+# `needs_allocator`
+
+The tracking issue for this feature is: [#27389]
+
+[#27389]: https://github.com/rust-lang/rust/issues/27389
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/needs-panic-runtime.md b/src/doc/unstable-book/src/needs-panic-runtime.md
new file mode 100644
index 00000000000..627c946c1bb
--- /dev/null
+++ b/src/doc/unstable-book/src/needs-panic-runtime.md
@@ -0,0 +1,10 @@
+# `needs_panic_runtime`
+
+The tracking issue for this feature is: [#32837]
+
+[#32837]: https://github.com/rust-lang/rust/issues/32837
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/never-type.md b/src/doc/unstable-book/src/never-type.md
new file mode 100644
index 00000000000..3b3729a4b21
--- /dev/null
+++ b/src/doc/unstable-book/src/never-type.md
@@ -0,0 +1,10 @@
+# `never_type`
+
+The tracking issue for this feature is: [#35121]
+
+[#35121]: https://github.com/rust-lang/rust/issues/35121
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/no-core.md b/src/doc/unstable-book/src/no-core.md
new file mode 100644
index 00000000000..6238753447c
--- /dev/null
+++ b/src/doc/unstable-book/src/no-core.md
@@ -0,0 +1,10 @@
+# `no_core`
+
+The tracking issue for this feature is: [#29639]
+
+[#29639]: https://github.com/rust-lang/rust/issues/29639
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/no-debug.md b/src/doc/unstable-book/src/no-debug.md
new file mode 100644
index 00000000000..7536ed9d4e1
--- /dev/null
+++ b/src/doc/unstable-book/src/no-debug.md
@@ -0,0 +1,10 @@
+# `no_debug`
+
+The tracking issue for this feature is: [#29721]
+
+[#29721]: https://github.com/rust-lang/rust/issues/29721
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/non-ascii-idents.md b/src/doc/unstable-book/src/non-ascii-idents.md
new file mode 100644
index 00000000000..f426022ab3a
--- /dev/null
+++ b/src/doc/unstable-book/src/non-ascii-idents.md
@@ -0,0 +1,10 @@
+# `non_ascii_idents`
+
+The tracking issue for this feature is: [#28979]
+
+[#28979]: https://github.com/rust-lang/rust/issues/28979
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/omit-gdb-pretty-printer-section.md b/src/doc/unstable-book/src/omit-gdb-pretty-printer-section.md
new file mode 100644
index 00000000000..d8ac520fcb5
--- /dev/null
+++ b/src/doc/unstable-book/src/omit-gdb-pretty-printer-section.md
@@ -0,0 +1,6 @@
+# `omit_gdb_pretty_printer_section`
+
+The tracking issue for this feature is: None.
+
+------------------------
+
diff --git a/src/doc/unstable-book/src/on-unimplemented.md b/src/doc/unstable-book/src/on-unimplemented.md
new file mode 100644
index 00000000000..81f284d0a6a
--- /dev/null
+++ b/src/doc/unstable-book/src/on-unimplemented.md
@@ -0,0 +1,10 @@
+# `on_unimplemented`
+
+The tracking issue for this feature is: [#29628]
+
+[#29628]: https://github.com/rust-lang/rust/issues/29628
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/optin-builtin-traits.md b/src/doc/unstable-book/src/optin-builtin-traits.md
new file mode 100644
index 00000000000..0b2d60accd5
--- /dev/null
+++ b/src/doc/unstable-book/src/optin-builtin-traits.md
@@ -0,0 +1,9 @@
+# `optin_builtin_traits`
+
+The tracking issue for this feature is: [#13231]
+
+[#13231]: https://github.com/rust-lang/rust/issues/13231
+
+------------------------
+
+
diff --git a/src/doc/unstable-book/src/panic-runtime.md b/src/doc/unstable-book/src/panic-runtime.md
new file mode 100644
index 00000000000..65b067e8296
--- /dev/null
+++ b/src/doc/unstable-book/src/panic-runtime.md
@@ -0,0 +1,10 @@
+# `panic_runtime`
+
+The tracking issue for this feature is: [#32837]
+
+[#32837]: https://github.com/rust-lang/rust/issues/32837
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/placement-in-syntax.md b/src/doc/unstable-book/src/placement-in-syntax.md
new file mode 100644
index 00000000000..da12559a01b
--- /dev/null
+++ b/src/doc/unstable-book/src/placement-in-syntax.md
@@ -0,0 +1,10 @@
+# `placement_in_syntax`
+
+The tracking issue for this feature is: [#27779]
+
+[#27779]: https://github.com/rust-lang/rust/issues/27779
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/platform-intrinsics.md b/src/doc/unstable-book/src/platform-intrinsics.md
new file mode 100644
index 00000000000..377ac8f7342
--- /dev/null
+++ b/src/doc/unstable-book/src/platform-intrinsics.md
@@ -0,0 +1,10 @@
+# `platform_intrinsics`
+
+The tracking issue for this feature is: [#27731]
+
+[#27731]: https://github.com/rust-lang/rust/issues/27731
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/plugin-registrar.md b/src/doc/unstable-book/src/plugin-registrar.md
new file mode 100644
index 00000000000..ca3738bd93f
--- /dev/null
+++ b/src/doc/unstable-book/src/plugin-registrar.md
@@ -0,0 +1,13 @@
+# `plugin_registrar`
+
+The tracking issue for this feature is: [#29597]
+
+[#29597]: https://github.com/rust-lang/rust/issues/29597
+
+This feature is part of "compiler plugins." It will often be used with the
+[`plugin`] and `rustc_private` features as well. For more details, see
+their docs.
+
+[`plugin`]: plugin.html
+
+------------------------
diff --git a/src/doc/unstable-book/src/plugin.md b/src/doc/unstable-book/src/plugin.md
new file mode 100644
index 00000000000..ca69b7084d3
--- /dev/null
+++ b/src/doc/unstable-book/src/plugin.md
@@ -0,0 +1,263 @@
+# `plugin`
+
+The tracking issue for this feature is: [#29597]
+
+[#29597]: https://github.com/rust-lang/rust/issues/29597
+
+
+This feature is part of "compiler plugins." It will often be used with the
+[`plugin_registrar`] and `rustc_private` features.
+
+[`plugin_registrar`]: plugin-registrar.html
+
+------------------------
+
+`rustc` can load compiler plugins, which are user-provided libraries that
+extend the compiler's behavior with new syntax extensions, lint checks, etc.
+
+A plugin is a dynamic library crate with a designated *registrar* function that
+registers extensions with `rustc`. Other crates can load these extensions using
+the crate attribute `#![plugin(...)]`.  See the
+`rustc_plugin` documentation for more about the
+mechanics of defining and loading a plugin.
+
+If present, arguments passed as `#![plugin(foo(... args ...))]` are not
+interpreted by rustc itself.  They are provided to the plugin through the
+`Registry`'s `args` method.
+
+In the vast majority of cases, a plugin should *only* be used through
+`#![plugin]` and not through an `extern crate` item.  Linking a plugin would
+pull in all of libsyntax and librustc as dependencies of your crate.  This is
+generally unwanted unless you are building another plugin.  The
+`plugin_as_library` lint checks these guidelines.
+
+The usual practice is to put compiler plugins in their own crate, separate from
+any `macro_rules!` macros or ordinary Rust code meant to be used by consumers
+of a library.
+
+# Syntax extensions
+
+Plugins can extend Rust's syntax in various ways. One kind of syntax extension
+is the procedural macro. These are invoked the same way as [ordinary
+macros](../book/macros.html), but the expansion is performed by arbitrary Rust
+code that manipulates syntax trees at
+compile time.
+
+Let's write a plugin
+[`roman_numerals.rs`](https://github.com/rust-lang/rust/blob/master/src/test/run-pass-fulldeps/auxiliary/roman_numerals.rs)
+that implements Roman numeral integer literals.
+
+```rust,ignore
+#![crate_type="dylib"]
+#![feature(plugin_registrar, rustc_private)]
+
+extern crate syntax;
+extern crate rustc;
+extern crate rustc_plugin;
+
+use syntax::parse::token;
+use syntax::tokenstream::TokenTree;
+use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
+use syntax::ext::build::AstBuilder;  // A trait for expr_usize.
+use syntax::ext::quote::rt::Span;
+use rustc_plugin::Registry;
+
+fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
+        -> Box<MacResult + 'static> {
+
+    static NUMERALS: &'static [(&'static str, usize)] = &[
+        ("M", 1000), ("CM", 900), ("D", 500), ("CD", 400),
+        ("C",  100), ("XC",  90), ("L",  50), ("XL",  40),
+        ("X",   10), ("IX",   9), ("V",   5), ("IV",   4),
+        ("I",    1)];
+
+    if args.len() != 1 {
+        cx.span_err(
+            sp,
+            &format!("argument should be a single identifier, but got {} arguments", args.len()));
+        return DummyResult::any(sp);
+    }
+
+    let text = match args[0] {
+        TokenTree::Token(_, token::Ident(s)) => s.to_string(),
+        _ => {
+            cx.span_err(sp, "argument should be a single identifier");
+            return DummyResult::any(sp);
+        }
+    };
+
+    let mut text = &*text;
+    let mut total = 0;
+    while !text.is_empty() {
+        match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) {
+            Some(&(rn, val)) => {
+                total += val;
+                text = &text[rn.len()..];
+            }
+            None => {
+                cx.span_err(sp, "invalid Roman numeral");
+                return DummyResult::any(sp);
+            }
+        }
+    }
+
+    MacEager::expr(cx.expr_usize(sp, total))
+}
+
+#[plugin_registrar]
+pub fn plugin_registrar(reg: &mut Registry) {
+    reg.register_macro("rn", expand_rn);
+}
+```
+
+Then we can use `rn!()` like any other macro:
+
+```rust,ignore
+#![feature(plugin)]
+#![plugin(roman_numerals)]
+
+fn main() {
+    assert_eq!(rn!(MMXV), 2015);
+}
+```
+
+The advantages over a simple `fn(&str) -> u32` are:
+
+* The (arbitrarily complex) conversion is done at compile time.
+* Input validation is also performed at compile time.
+* It can be extended to allow use in patterns, which effectively gives
+  a way to define new literal syntax for any data type.
+
+In addition to procedural macros, you can define new
+[`derive`](../reference/attributes.html#derive)-like attributes and other kinds
+of extensions.  See `Registry::register_syntax_extension` and the
+`SyntaxExtension` enum.  For a more involved macro example, see
+[`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs).
+
+
+## Tips and tricks
+
+Some of the [macro debugging tips](../book/macros.html#debugging-macro-code) are applicable.
+
+You can use `syntax::parse` to turn token trees into
+higher-level syntax elements like expressions:
+
+```rust,ignore
+fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
+        -> Box<MacResult+'static> {
+
+    let mut parser = cx.new_parser_from_tts(args);
+
+    let expr: P<Expr> = parser.parse_expr();
+```
+
+Looking through [`libsyntax` parser
+code](https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/parser.rs)
+will give you a feel for how the parsing infrastructure works.
+
+Keep the `Span`s of everything you parse, for better error reporting. You can
+wrap `Spanned` around your custom data structures.
+
+Calling `ExtCtxt::span_fatal` will immediately abort compilation. It's better to
+instead call `ExtCtxt::span_err` and return `DummyResult` so that the compiler
+can continue and find further errors.
+
+To print syntax fragments for debugging, you can use `span_note` together with
+`syntax::print::pprust::*_to_string`.
+
+The example above produced an integer literal using `AstBuilder::expr_usize`.
+As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of
+quasiquote macros. They are undocumented and very rough around the edges.
+However, the implementation may be a good starting point for an improved
+quasiquote as an ordinary plugin library.
+
+
+# Lint plugins
+
+Plugins can extend [Rust's lint
+infrastructure](../reference/attributes.html#lint-check-attributes) with
+additional checks for code style, safety, etc. Now let's write a plugin
+[`lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/run-pass-fulldeps/auxiliary/lint_plugin_test.rs)
+that warns about any item named `lintme`.
+
+```rust,ignore
+#![feature(plugin_registrar)]
+#![feature(box_syntax, rustc_private)]
+
+extern crate syntax;
+
+// Load rustc as a plugin to get macros
+#[macro_use]
+extern crate rustc;
+extern crate rustc_plugin;
+
+use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass,
+                  EarlyLintPassObject, LintArray};
+use rustc_plugin::Registry;
+use syntax::ast;
+
+declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
+
+struct Pass;
+
+impl LintPass for Pass {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(TEST_LINT)
+    }
+}
+
+impl EarlyLintPass for Pass {
+    fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
+        if it.ident.name.as_str() == "lintme" {
+            cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
+        }
+    }
+}
+
+#[plugin_registrar]
+pub fn plugin_registrar(reg: &mut Registry) {
+    reg.register_early_lint_pass(box Pass as EarlyLintPassObject);
+}
+```
+
+Then code like
+
+```rust,ignore
+#![plugin(lint_plugin_test)]
+
+fn lintme() { }
+```
+
+will produce a compiler warning:
+
+```txt
+foo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default
+foo.rs:4 fn lintme() { }
+         ^~~~~~~~~~~~~~~
+```
+
+The components of a lint plugin are:
+
+* one or more `declare_lint!` invocations, which define static `Lint` structs;
+
+* a struct holding any state needed by the lint pass (here, none);
+
+* a `LintPass`
+  implementation defining how to check each syntax element. A single
+  `LintPass` may call `span_lint` for several different `Lint`s, but should
+  register them all through the `get_lints` method.
+
+Lint passes are syntax traversals, but they run at a late stage of compilation
+where type information is available. `rustc`'s [built-in
+lints](https://github.com/rust-lang/rust/blob/master/src/librustc/lint/builtin.rs)
+mostly use the same infrastructure as lint plugins, and provide examples of how
+to access type information.
+
+Lints defined by plugins are controlled by the usual [attributes and compiler
+flags](../reference/attributes.html#lint-check-attributes), e.g.
+`#[allow(test_lint)]` or `-A test-lint`. These identifiers are derived from the
+first argument to `declare_lint!`, with appropriate case and punctuation
+conversion.
+
+You can run `rustc -W help foo.rs` to see a list of lints known to `rustc`,
+including those provided by plugins loaded by `foo.rs`.
diff --git a/src/doc/unstable-book/src/prelude-import.md b/src/doc/unstable-book/src/prelude-import.md
new file mode 100644
index 00000000000..75dae5cfb74
--- /dev/null
+++ b/src/doc/unstable-book/src/prelude-import.md
@@ -0,0 +1,6 @@
+# `prelude_import`
+
+The tracking issue for this feature is: None.
+
+------------------------
+
diff --git a/src/doc/unstable-book/src/proc-macro.md b/src/doc/unstable-book/src/proc-macro.md
new file mode 100644
index 00000000000..f8b53bd5a2f
--- /dev/null
+++ b/src/doc/unstable-book/src/proc-macro.md
@@ -0,0 +1,10 @@
+# `proc_macro`
+
+The tracking issue for this feature is: [#38356]
+
+[#38356]: https://github.com/rust-lang/rust/issues/38356
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/pub-restricted.md b/src/doc/unstable-book/src/pub-restricted.md
new file mode 100644
index 00000000000..730461813cb
--- /dev/null
+++ b/src/doc/unstable-book/src/pub-restricted.md
@@ -0,0 +1,10 @@
+# `pub_restricted`
+
+The tracking issue for this feature is: [#32409]
+
+[#32409]: https://github.com/rust-lang/rust/issues/32409
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/quote.md b/src/doc/unstable-book/src/quote.md
new file mode 100644
index 00000000000..b4e078d920c
--- /dev/null
+++ b/src/doc/unstable-book/src/quote.md
@@ -0,0 +1,10 @@
+# `quote`
+
+The tracking issue for this feature is: [#29601]
+
+[#29601]: https://github.com/rust-lang/rust/issues/29601
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/relaxed-adts.md b/src/doc/unstable-book/src/relaxed-adts.md
new file mode 100644
index 00000000000..170570e06a2
--- /dev/null
+++ b/src/doc/unstable-book/src/relaxed-adts.md
@@ -0,0 +1,10 @@
+# `relaxed_adts`
+
+The tracking issue for this feature is: [#35626]
+
+[#35626]: https://github.com/rust-lang/rust/issues/35626
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/repr-simd.md b/src/doc/unstable-book/src/repr-simd.md
new file mode 100644
index 00000000000..c6f051e4fff
--- /dev/null
+++ b/src/doc/unstable-book/src/repr-simd.md
@@ -0,0 +1,10 @@
+# `repr_simd`
+
+The tracking issue for this feature is: [#27731]
+
+[#27731]: https://github.com/rust-lang/rust/issues/27731
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/rustc-attrs.md b/src/doc/unstable-book/src/rustc-attrs.md
new file mode 100644
index 00000000000..d1f18cead06
--- /dev/null
+++ b/src/doc/unstable-book/src/rustc-attrs.md
@@ -0,0 +1,10 @@
+# `rustc_attrs`
+
+The tracking issue for this feature is: [#29642]
+
+[#29642]: https://github.com/rust-lang/rust/issues/29642
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/rustc-diagnostic-macros.md b/src/doc/unstable-book/src/rustc-diagnostic-macros.md
new file mode 100644
index 00000000000..0df6ca12089
--- /dev/null
+++ b/src/doc/unstable-book/src/rustc-diagnostic-macros.md
@@ -0,0 +1,6 @@
+# `rustc_diagnostic_macros`
+
+The tracking issue for this feature is: None.
+
+------------------------
+
diff --git a/src/doc/unstable-book/src/sanitizer-runtime.md b/src/doc/unstable-book/src/sanitizer-runtime.md
new file mode 100644
index 00000000000..f19504de58e
--- /dev/null
+++ b/src/doc/unstable-book/src/sanitizer-runtime.md
@@ -0,0 +1,6 @@
+# `sanitizer_runtime`
+
+The tracking issue for this feature is: None.
+
+------------------------
+
diff --git a/src/doc/unstable-book/src/simd-ffi.md b/src/doc/unstable-book/src/simd-ffi.md
new file mode 100644
index 00000000000..d85779c3d3d
--- /dev/null
+++ b/src/doc/unstable-book/src/simd-ffi.md
@@ -0,0 +1,10 @@
+# `simd_ffi`
+
+The tracking issue for this feature is: [#27731]
+
+[#27731]: https://github.com/rust-lang/rust/issues/27731
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/simd.md b/src/doc/unstable-book/src/simd.md
new file mode 100644
index 00000000000..13c9722c524
--- /dev/null
+++ b/src/doc/unstable-book/src/simd.md
@@ -0,0 +1,10 @@
+# `simd`
+
+The tracking issue for this feature is: [#27731]
+
+[#27731]: https://github.com/rust-lang/rust/issues/27731
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/slice-patterns.md b/src/doc/unstable-book/src/slice-patterns.md
new file mode 100644
index 00000000000..1e9e1eaafda
--- /dev/null
+++ b/src/doc/unstable-book/src/slice-patterns.md
@@ -0,0 +1,27 @@
+# `slice_patterns`
+
+The tracking issue for this feature is: [#23121]
+
+[#23121]: https://github.com/rust-lang/rust/issues/23121
+
+See also [`advanced_slice_patterns`](advanced-slice-patterns.html).
+
+------------------------
+
+
+If you want to match against a slice or array, you can use `&` with the
+`slice_patterns` feature:
+
+```rust
+#![feature(slice_patterns)]
+
+fn main() {
+    let v = vec!["match_this", "1"];
+
+    match &v[..] {
+        &["match_this", second] => println!("The second element is {}", second),
+        _ => {},
+    }
+}
+```
+
diff --git a/src/doc/unstable-book/src/specialization.md b/src/doc/unstable-book/src/specialization.md
new file mode 100644
index 00000000000..59f27343b66
--- /dev/null
+++ b/src/doc/unstable-book/src/specialization.md
@@ -0,0 +1,8 @@
+# `specialization`
+
+The tracking issue for this feature is: [#31844]
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/staged-api.md b/src/doc/unstable-book/src/staged-api.md
new file mode 100644
index 00000000000..1409e570e88
--- /dev/null
+++ b/src/doc/unstable-book/src/staged-api.md
@@ -0,0 +1,6 @@
+# `staged_api`
+
+The tracking issue for this feature is: None.
+
+------------------------
+
diff --git a/src/doc/unstable-book/src/start.md b/src/doc/unstable-book/src/start.md
new file mode 100644
index 00000000000..1ea6d59c78d
--- /dev/null
+++ b/src/doc/unstable-book/src/start.md
@@ -0,0 +1,10 @@
+# `start`
+
+The tracking issue for this feature is: [#29633]
+
+[#29633]: https://github.com/rust-lang/rust/issues/29633
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/static-nobundle.md b/src/doc/unstable-book/src/static-nobundle.md
new file mode 100644
index 00000000000..97b9d71d433
--- /dev/null
+++ b/src/doc/unstable-book/src/static-nobundle.md
@@ -0,0 +1,10 @@
+# `static_nobundle`
+
+The tracking issue for this feature is: [#37403]
+
+[#37403]: https://github.com/rust-lang/rust/issues/37403
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/static-recursion.md b/src/doc/unstable-book/src/static-recursion.md
new file mode 100644
index 00000000000..d419ea41c6f
--- /dev/null
+++ b/src/doc/unstable-book/src/static-recursion.md
@@ -0,0 +1,10 @@
+# `static_recursion`
+
+The tracking issue for this feature is: [#29719]
+
+[#29719]: https://github.com/rust-lang/rust/issues/29719
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/stmt-expr-attributes.md b/src/doc/unstable-book/src/stmt-expr-attributes.md
new file mode 100644
index 00000000000..71092fcf290
--- /dev/null
+++ b/src/doc/unstable-book/src/stmt-expr-attributes.md
@@ -0,0 +1,10 @@
+# `stmt_expr_attributes`
+
+The tracking issue for this feature is: [#15701]
+
+[#15701]: https://github.com/rust-lang/rust/issues/15701
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/struct-field-attributes.md b/src/doc/unstable-book/src/struct-field-attributes.md
new file mode 100644
index 00000000000..1a94562968d
--- /dev/null
+++ b/src/doc/unstable-book/src/struct-field-attributes.md
@@ -0,0 +1,10 @@
+# `struct_field_attributes`
+
+The tracking issue for this feature is: [#38814]
+
+[#38814]: https://github.com/rust-lang/rust/issues/38814
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/structural-match.md b/src/doc/unstable-book/src/structural-match.md
new file mode 100644
index 00000000000..b3ca26e6474
--- /dev/null
+++ b/src/doc/unstable-book/src/structural-match.md
@@ -0,0 +1,10 @@
+# `structural_match`
+
+The tracking issue for this feature is: [#31434]
+
+[#31434]: https://github.com/rust-lang/rust/issues/31434
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/target-feature.md b/src/doc/unstable-book/src/target-feature.md
new file mode 100644
index 00000000000..85ab1ab39ef
--- /dev/null
+++ b/src/doc/unstable-book/src/target-feature.md
@@ -0,0 +1,6 @@
+# `target_feature`
+
+The tracking issue for this feature is: None.
+
+------------------------
+
diff --git a/src/doc/book/src/benchmark-tests.md b/src/doc/unstable-book/src/test.md
index a6ae2b3049a..6b4a3a677db 100644
--- a/src/doc/book/src/benchmark-tests.md
+++ b/src/doc/unstable-book/src/test.md
@@ -1,7 +1,13 @@
-# Benchmark tests
+# `test`
 
-Rust supports benchmark tests, which can test the performance of your
-code. Let's make our `src/lib.rs` look like this (comments elided):
+The tracking issue for this feature is: None.
+
+------------------------
+
+The internals of the `test` crate are unstable, behind the `test` flag.  The
+most widely used part of the `test` crate are benchmark tests, which can test
+the performance of your code.  Let's make our `src/lib.rs` look like this
+(comments elided):
 
 ```rust,ignore
 #![feature(test)]
diff --git a/src/doc/unstable-book/src/the-unstable-book.md b/src/doc/unstable-book/src/the-unstable-book.md
new file mode 100644
index 00000000000..dfbfe4cab97
--- /dev/null
+++ b/src/doc/unstable-book/src/the-unstable-book.md
@@ -0,0 +1,22 @@
+# The Unstable Book
+
+Welcome to the Unstable Book! This book consists of a number of chapters,
+each one organized by a "feature flag." That is, when using an unstable
+feature of Rust, you must use a flag, like this:
+
+```rust
+#![feature(box_syntax)]
+
+fn main() {
+    let five = box 5;
+}
+```
+
+The `box_syntax` feature [has a chapter][box] describing how to use it.
+
+[box]: box-syntax.html
+
+Because this documentation relates to unstable features, we make no guarantees
+that what is contained here is accurate or up to date. It's developed on a
+best-effort basis. Each page will have a link to its tracking issue with the
+latest developments; you might want to check those as well.
diff --git a/src/doc/unstable-book/src/thread-local.md b/src/doc/unstable-book/src/thread-local.md
new file mode 100644
index 00000000000..83de2f9cd4b
--- /dev/null
+++ b/src/doc/unstable-book/src/thread-local.md
@@ -0,0 +1,10 @@
+# `thread_local`
+
+The tracking issue for this feature is: [#29594]
+
+[#29594]: https://github.com/rust-lang/rust/issues/29594
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/trace-macros.md b/src/doc/unstable-book/src/trace-macros.md
new file mode 100644
index 00000000000..856f1b0a7bb
--- /dev/null
+++ b/src/doc/unstable-book/src/trace-macros.md
@@ -0,0 +1,10 @@
+# `trace_macros`
+
+The tracking issue for this feature is: [#29598]
+
+[#29598]: https://github.com/rust-lang/rust/issues/29598
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/type-ascription.md b/src/doc/unstable-book/src/type-ascription.md
new file mode 100644
index 00000000000..3ebd0d87ccf
--- /dev/null
+++ b/src/doc/unstable-book/src/type-ascription.md
@@ -0,0 +1,10 @@
+# `type_ascription`
+
+The tracking issue for this feature is: [#23416]
+
+[#23416]: https://github.com/rust-lang/rust/issues/23416
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/unboxed-closures.md b/src/doc/unstable-book/src/unboxed-closures.md
new file mode 100644
index 00000000000..2cbb436ce0b
--- /dev/null
+++ b/src/doc/unstable-book/src/unboxed-closures.md
@@ -0,0 +1,10 @@
+# `unboxed_closures`
+
+The tracking issue for this feature is: [#29625]
+
+[#29625]: https://github.com/rust-lang/rust/issues/29625
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/untagged-unions.md b/src/doc/unstable-book/src/untagged-unions.md
new file mode 100644
index 00000000000..6fe4f088ac2
--- /dev/null
+++ b/src/doc/unstable-book/src/untagged-unions.md
@@ -0,0 +1,10 @@
+# `untagged_unions`
+
+The tracking issue for this feature is: [#32836]
+
+[#32836]: https://github.com/rust-lang/rust/issues/32836
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/unwind-attributes.md b/src/doc/unstable-book/src/unwind-attributes.md
new file mode 100644
index 00000000000..0167a33b081
--- /dev/null
+++ b/src/doc/unstable-book/src/unwind-attributes.md
@@ -0,0 +1,6 @@
+# `unwind_attributes`
+
+The tracking issue for this feature is: None.
+
+------------------------
+
diff --git a/src/doc/unstable-book/src/use-extern-macros.md b/src/doc/unstable-book/src/use-extern-macros.md
new file mode 100644
index 00000000000..bc614911502
--- /dev/null
+++ b/src/doc/unstable-book/src/use-extern-macros.md
@@ -0,0 +1,10 @@
+# `use_extern_macros`
+
+The tracking issue for this feature is: [#35896]
+
+[#35896]: https://github.com/rust-lang/rust/issues/35896
+
+------------------------
+
+
+
diff --git a/src/doc/unstable-book/src/windows-subsystem.md b/src/doc/unstable-book/src/windows-subsystem.md
new file mode 100644
index 00000000000..80583352fbf
--- /dev/null
+++ b/src/doc/unstable-book/src/windows-subsystem.md
@@ -0,0 +1,10 @@
+# `windows_subsystem`
+
+The tracking issue for this feature is: [#37499]
+
+[#37499]: https://github.com/rust-lang/rust/issues/37499
+
+------------------------
+
+
+
diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs
index 8d81a09f5af..a496ab870c6 100644
--- a/src/liballoc_jemalloc/lib.rs
+++ b/src/liballoc_jemalloc/lib.rs
@@ -122,18 +122,6 @@ mod imp {
         let flags = align_to_flags(align);
         unsafe { nallocx(size as size_t, flags) as usize }
     }
-
-    // These symbols are used by jemalloc on android but the really old android
-    // we're building on doesn't have them defined, so just make sure the symbols
-    // are available.
-    #[no_mangle]
-    #[cfg(all(target_os = "android", not(cargobuild)))]
-    pub extern "C" fn pthread_atfork(_prefork: *mut u8,
-                                     _postfork_parent: *mut u8,
-                                     _postfork_child: *mut u8)
-                                     -> i32 {
-        0
-    }
 }
 
 #[cfg(dummy_jemalloc)]
diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs
index bd74848a01d..079541235a2 100644
--- a/src/libcollections/fmt.rs
+++ b/src/libcollections/fmt.rs
@@ -62,7 +62,7 @@
 //!
 //! A format string is required to use all of its arguments, otherwise it is a
 //! compile-time error. You may refer to the same argument more than once in the
-//! format string, although it must always be referred to with the same type.
+//! format string.
 //!
 //! ## Named parameters
 //!
@@ -89,19 +89,8 @@
 //!
 //! ## Argument types
 //!
-//! Each argument's type is dictated by the format string. It is a requirement
-//! that every argument is only ever referred to by one type. For example, this
-//! is an invalid format string:
-//!
-//! ```text
-//! {0:x} {0:o}
-//! ```
-//!
-//! This is invalid because the first argument is both referred to as a
-//! hexadecimal as well as an
-//! octal.
-//!
-//! There are various parameters which do require a particular type, however.
+//! Each argument's type is dictated by the format string.
+//! There are various parameters which require a particular type, however.
 //! An example is the `{:.*}` syntax, which sets the number of decimal places
 //! in floating-point types:
 //!
@@ -113,13 +102,7 @@
 //!
 //! If this syntax is used, then the number of characters to print precedes the
 //! actual object being formatted, and the number of characters must have the
-//! type `usize`. Although a `usize` can be printed with `{}`, it is invalid to
-//! reference an argument as such. For example this is another invalid format
-//! string:
-//!
-//! ```text
-//! {:.*} {0}
-//! ```
+//! type `usize`.
 //!
 //! ## Formatting traits
 //!
diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs
index e92eb4ff7bd..6839b698a56 100644
--- a/src/libcollections/string.rs
+++ b/src/libcollections/string.rs
@@ -999,6 +999,9 @@ impl String {
     /// If `new_len` is greater than the string's current length, this has no
     /// effect.
     ///
+    /// Note that this method has no effect on the allocated capacity
+    /// of the string
+    ///
     /// # Panics
     ///
     /// Panics if `new_len` does not lie on a [`char`] boundary.
@@ -1629,6 +1632,43 @@ impl hash::Hash for String {
     }
 }
 
+/// Implements the `+` operator for concatenating two strings.
+///
+/// This consumes the `String` on the left-hand side and re-uses its buffer (growing it if
+/// necessary). This is done to avoid allocating a new `String` and copying the entire contents on
+/// every operation, which would lead to `O(n^2)` running time when building an `n`-byte string by
+/// repeated concatenation.
+///
+/// The string on the right-hand side is only borrowed; its contents are copied into the returned
+/// `String`.
+///
+/// # Examples
+///
+/// Concatenating two `String`s takes the first by value and borrows the second:
+///
+/// ```
+/// let a = String::from("hello");
+/// let b = String::from(" world");
+/// let c = a + &b;
+/// // `a` is moved and can no longer be used here.
+/// ```
+///
+/// If you want to keep using the first `String`, you can clone it and append to the clone instead:
+///
+/// ```
+/// let a = String::from("hello");
+/// let b = String::from(" world");
+/// let c = a.clone() + &b;
+/// // `a` is still valid here.
+/// ```
+///
+/// Concatenating `&str` slices can be done by converting the first to a `String`:
+///
+/// ```
+/// let a = "hello";
+/// let b = " world";
+/// let c = a.to_string() + b;
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> Add<&'a str> for String {
     type Output = String;
@@ -1640,6 +1680,11 @@ impl<'a> Add<&'a str> for String {
     }
 }
 
+/// Implements the `+=` operator for appending to a `String`.
+///
+/// This has the same behavior as the [`push_str()`] method.
+///
+/// [`push_str()`]: struct.String.html#method.push_str
 #[stable(feature = "stringaddassign", since = "1.12.0")]
 impl<'a> AddAssign<&'a str> for String {
     #[inline]
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index 9e3f117f9b2..3134e3c2ce1 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -548,6 +548,9 @@ impl<T> Vec<T> {
     /// The [`drain`] method can emulate `truncate`, but causes the excess
     /// elements to be returned instead of dropped.
     ///
+    /// Note that this method has no effect on the allocated capacity
+    /// of the vector.
+    ///
     /// # Examples
     ///
     /// Truncating a five element vector to two elements:
@@ -1092,6 +1095,9 @@ impl<T> Vec<T> {
 
     /// Clears the vector, removing all values.
     ///
+    /// Note that this method has no effect on the allocated capacity
+    /// of the vector.
+    ///
     /// # Examples
     ///
     /// ```
@@ -1776,6 +1782,7 @@ array_impls! {
     30 31 32
 }
 
+/// Implements comparison of vectors, lexicographically.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: PartialOrd> PartialOrd for Vec<T> {
     #[inline]
@@ -1787,6 +1794,7 @@ impl<T: PartialOrd> PartialOrd for Vec<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Eq> Eq for Vec<T> {}
 
+/// Implements ordering of vectors, lexicographically.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Ord> Ord for Vec<T> {
     #[inline]
diff --git a/src/libcompiler_builtins/build.rs b/src/libcompiler_builtins/build.rs
index 5360bbdeacd..16ecf882566 100644
--- a/src/libcompiler_builtins/build.rs
+++ b/src/libcompiler_builtins/build.rs
@@ -92,7 +92,15 @@ fn main() {
         // compiler-rt's build system already
         cfg.flag("-fno-builtin");
         cfg.flag("-fvisibility=hidden");
-        cfg.flag("-fomit-frame-pointer");
+        // Accepted practice on Solaris is to never omit frame pointer so that
+        // system observability tools work as expected.  In addition, at least
+        // on Solaris, -fomit-frame-pointer on sparcv9 appears to generate
+        // references to data outside of the current stack frame.  A search of
+        // the gcc bug database provides a variety of issues surrounding
+        // -fomit-frame-pointer on non-x86 platforms.
+        if !target.contains("solaris") && !target.contains("sparc") {
+            cfg.flag("-fomit-frame-pointer");
+        }
         cfg.flag("-ffreestanding");
         cfg.define("VISIBILITY_HIDDEN", None);
     }
diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs
index 3e0b8425573..0331c5d4ba4 100644
--- a/src/libcore/slice.rs
+++ b/src/libcore/slice.rs
@@ -2202,6 +2202,7 @@ impl<A, B> PartialEq<[B]> for [A] where A: PartialEq<B> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Eq> Eq for [T] {}
 
+/// Implements comparison of vectors lexicographically.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Ord> Ord for [T] {
     fn cmp(&self, other: &[T]) -> Ordering {
@@ -2209,6 +2210,7 @@ impl<T: Ord> Ord for [T] {
     }
 }
 
+/// Implements comparison of vectors lexicographically.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: PartialOrd> PartialOrd for [T] {
     fn partial_cmp(&self, other: &[T]) -> Option<Ordering> {
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 49a6b1b5fce..925cd84154a 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -1366,6 +1366,13 @@ mod traits {
     use ops;
     use str::eq_slice;
 
+    /// Implements ordering of strings.
+    ///
+    /// Strings are ordered  lexicographically by their byte values.  This orders Unicode code
+    /// points based on their positions in the code charts.  This is not necessarily the same as
+    /// "alphabetical" order, which varies by language and locale.  Sorting strings according to
+    /// culturally-accepted standards requires locale-specific data that is outside the scope of
+    /// the `str` type.
     #[stable(feature = "rust1", since = "1.0.0")]
     impl Ord for str {
         #[inline]
@@ -1387,6 +1394,13 @@ mod traits {
     #[stable(feature = "rust1", since = "1.0.0")]
     impl Eq for str {}
 
+    /// Implements comparison operations on strings.
+    ///
+    /// Strings are compared lexicographically by their byte values.  This compares Unicode code
+    /// points based on their positions in the code charts.  This is not necessarily the same as
+    /// "alphabetical" order, which varies by language and locale.  Comparing strings according to
+    /// culturally-accepted standards requires locale-specific data that is outside the scope of
+    /// the `str` type.
     #[stable(feature = "rust1", since = "1.0.0")]
     impl PartialOrd for str {
         #[inline]
diff --git a/src/liblibc b/src/liblibc
-Subproject 7a3754f2bb5e65eb39adacb189c362617303217
+Subproject 64d954c6a76e896fbf7ed5c17e77c40e388abe8
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 59505933289..122543aee40 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -220,15 +220,24 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                 // Note that `break` and `continue` statements
                 // may cause additional edges.
 
-                // Is the condition considered part of the loop?
                 let loopback = self.add_dummy_node(&[pred]);              // 1
-                let cond_exit = self.expr(&cond, loopback);             // 2
-                let expr_exit = self.add_ast_node(expr.id, &[cond_exit]); // 3
+
+                // Create expr_exit without pred (cond_exit)
+                let expr_exit = self.add_ast_node(expr.id, &[]);         // 3
+
+                // The LoopScope needs to be on the loop_scopes stack while evaluating the
+                // condition and the body of the loop (both can break out of the loop)
                 self.loop_scopes.push(LoopScope {
                     loop_id: expr.id,
                     continue_index: loopback,
                     break_index: expr_exit
                 });
+
+                let cond_exit = self.expr(&cond, loopback);             // 2
+
+                // Add pred (cond_exit) to expr_exit
+                self.add_contained_edge(cond_exit, expr_exit);
+
                 let body_exit = self.block(&body, cond_exit);          // 4
                 self.add_contained_edge(body_exit, loopback);            // 5
                 self.loop_scopes.pop();
@@ -294,17 +303,17 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                 self.add_unreachable_node()
             }
 
-            hir::ExprBreak(label, ref opt_expr) => {
+            hir::ExprBreak(destination, ref opt_expr) => {
                 let v = self.opt_expr(opt_expr, pred);
-                let loop_scope = self.find_scope(expr, label);
+                let loop_scope = self.find_scope(expr, destination);
                 let b = self.add_ast_node(expr.id, &[v]);
                 self.add_exiting_edge(expr, b,
                                       loop_scope, loop_scope.break_index);
                 self.add_unreachable_node()
             }
 
-            hir::ExprAgain(label) => {
-                let loop_scope = self.find_scope(expr, label);
+            hir::ExprAgain(destination) => {
+                let loop_scope = self.find_scope(expr, destination);
                 let a = self.add_ast_node(expr.id, &[pred]);
                 self.add_exiting_edge(expr, a,
                                       loop_scope, loop_scope.continue_index);
@@ -579,17 +588,18 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
 
     fn find_scope(&self,
                   expr: &hir::Expr,
-                  label: Option<hir::Label>) -> LoopScope {
-        match label {
-            None => *self.loop_scopes.last().unwrap(),
-            Some(label) => {
+                  destination: hir::Destination) -> LoopScope {
+
+        match destination.loop_id.into() {
+            Ok(loop_id) => {
                 for l in &self.loop_scopes {
-                    if l.loop_id == label.loop_id {
+                    if l.loop_id == loop_id {
                         return *l;
                     }
                 }
-                span_bug!(expr.span, "no loop scope for id {}", label.loop_id);
+                span_bug!(expr.span, "no loop scope for id {}", loop_id);
             }
+            Err(err) => span_bug!(expr.span, "loop scope error: {}",  err)
         }
     }
 }
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 96d1a925425..e0233d6f8b9 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -70,6 +70,7 @@ pub enum DepNode<D: Clone + Debug> {
     Resolve,
     EntryPoint,
     CheckEntryFn,
+    CoherenceCheckTrait(D),
     CoherenceCheckImpl(D),
     CoherenceOverlapCheck(D),
     CoherenceOverlapCheckSpecial(D),
@@ -109,11 +110,13 @@ pub enum DepNode<D: Clone + Debug> {
     // predicates for an item wind up in `ItemSignature`).
     AssociatedItems(D),
     ItemSignature(D),
+    TypeParamPredicates((D, D)),
     SizedConstraint(D),
     AssociatedItemDefIds(D),
     InherentImpls(D),
     TypeckTables(D),
     UsedTraitImports(D),
+    MonomorphicConstEval(D),
 
     // The set of impls for a given trait. Ultimately, it would be
     // nice to get more fine-grained here (e.g., to include a
@@ -239,6 +242,7 @@ impl<D: Clone + Debug> DepNode<D> {
             MetaData(ref d) => op(d).map(MetaData),
             CollectItem(ref d) => op(d).map(CollectItem),
             CollectItemSig(ref d) => op(d).map(CollectItemSig),
+            CoherenceCheckTrait(ref d) => op(d).map(CoherenceCheckTrait),
             CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
             CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
             CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial),
@@ -258,11 +262,15 @@ impl<D: Clone + Debug> DepNode<D> {
             TransInlinedItem(ref d) => op(d).map(TransInlinedItem),
             AssociatedItems(ref d) => op(d).map(AssociatedItems),
             ItemSignature(ref d) => op(d).map(ItemSignature),
+            TypeParamPredicates((ref item, ref param)) => {
+                Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
+            }
             SizedConstraint(ref d) => op(d).map(SizedConstraint),
             AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
             InherentImpls(ref d) => op(d).map(InherentImpls),
             TypeckTables(ref d) => op(d).map(TypeckTables),
             UsedTraitImports(ref d) => op(d).map(UsedTraitImports),
+            MonomorphicConstEval(ref d) => op(d).map(MonomorphicConstEval),
             TraitImpls(ref d) => op(d).map(TraitImpls),
             TraitItems(ref d) => op(d).map(TraitItems),
             ReprHints(ref d) => op(d).map(ReprHints),
diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs
index 2ffc3951cc9..9f45e66f0d9 100644
--- a/src/librustc/dep_graph/dep_tracking_map.rs
+++ b/src/librustc/dep_graph/dep_tracking_map.rs
@@ -11,6 +11,7 @@
 use hir::def_id::DefId;
 use rustc_data_structures::fx::FxHashMap;
 use std::cell::RefCell;
+use std::collections::hash_map::Entry;
 use std::ops::Index;
 use std::hash::Hash;
 use std::marker::PhantomData;
@@ -67,6 +68,11 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
         assert!(old_value.is_none());
     }
 
+    pub fn entry(&mut self, k: M::Key) -> Entry<M::Key, M::Value> {
+        self.write(&k);
+        self.map.entry(k)
+    }
+
     pub fn contains_key(&self, k: &M::Key) -> bool {
         self.read(k);
         self.map.contains_key(k)
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index cf51dad5142..b1b1b849437 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -390,44 +390,6 @@ RFC. It is, however, [currently unimplemented][iss15872].
 [iss15872]: https://github.com/rust-lang/rust/issues/15872
 "##,
 
-E0109: r##"
-You tried to give a type parameter to a type which doesn't need it. Erroneous
-code example:
-
-```compile_fail,E0109
-type X = u32<i32>; // error: type parameters are not allowed on this type
-```
-
-Please check that you used the correct type and recheck its definition. Perhaps
-it doesn't need the type parameter.
-
-Example:
-
-```
-type X = u32; // this compiles
-```
-
-Note that type parameters for enum-variant constructors go after the variant,
-not after the enum (Option::None::<u32>, not Option::<u32>::None).
-"##,
-
-E0110: r##"
-You tried to give a lifetime parameter to a type which doesn't need it.
-Erroneous code example:
-
-```compile_fail,E0110
-type X = u32<'static>; // error: lifetime parameters are not allowed on
-                       //        this type
-```
-
-Please check that the correct type was used and recheck its definition; perhaps
-it doesn't need the lifetime parameter. Example:
-
-```
-type X = u32; // ok!
-```
-"##,
-
 E0133: r##"
 Unsafe code was used outside of an unsafe function or block.
 
@@ -627,41 +589,6 @@ attributes:
 See also https://doc.rust-lang.org/book/no-stdlib.html
 "##,
 
-E0229: r##"
-An associated type binding was done outside of the type parameter declaration
-and `where` clause. Erroneous code example:
-
-```compile_fail,E0229
-pub trait Foo {
-    type A;
-    fn boo(&self) -> <Self as Foo>::A;
-}
-
-struct Bar;
-
-impl Foo for isize {
-    type A = usize;
-    fn boo(&self) -> usize { 42 }
-}
-
-fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
-// error: associated type bindings are not allowed here
-```
-
-To solve this error, please move the type bindings in the type parameter
-declaration:
-
-```ignore
-fn baz<I: Foo<A=Bar>>(x: &<I as Foo>::A) {} // ok!
-```
-
-Or in the `where` clause:
-
-```ignore
-fn baz<I>(x: &<I as Foo>::A) where I: Foo<A=Bar> {}
-```
-"##,
-
 E0261: r##"
 When using a lifetime like `'a` in a type, it must be declared before being
 used.
@@ -1390,6 +1317,23 @@ error. To resolve it, add an `else` block having the same type as the `if`
 block.
 "##,
 
+E0391: r##"
+This error indicates that some types or traits depend on each other
+and therefore cannot be constructed.
+
+The following example contains a circular dependency between two traits:
+
+```compile_fail,E0391
+trait FirstTrait : SecondTrait {
+
+}
+
+trait SecondTrait : FirstTrait {
+
+}
+```
+"##,
+
 E0398: r##"
 In Rust 1.3, the default object lifetime bounds are expected to change, as
 described in RFC #1156 [1]. You are getting a warning because the compiler
diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index 53b7be74f85..aedb8fef288 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -11,6 +11,7 @@
 use hir::def_id::DefId;
 use util::nodemap::NodeMap;
 use syntax::ast;
+use syntax::ext::base::MacroKind;
 use hir;
 
 #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
@@ -53,7 +54,7 @@ pub enum Def {
     Label(ast::NodeId),
 
     // Macro namespace
-    Macro(DefId),
+    Macro(DefId, MacroKind),
 
     // Both namespaces
     Err,
@@ -141,7 +142,7 @@ impl Def {
             Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) |
             Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
             Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
-            Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id) => {
+            Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id, ..) => {
                 id
             }
 
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 1df67615069..fd6796ccc0b 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -1006,18 +1006,22 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
         ExprPath(ref qpath) => {
             visitor.visit_qpath(qpath, expression.id, expression.span);
         }
-        ExprBreak(None, ref opt_expr) => {
+        ExprBreak(label, ref opt_expr) => {
+            label.ident.map(|ident| {
+                if let Ok(loop_id) = label.loop_id.into() {
+                    visitor.visit_def_mention(Def::Label(loop_id));
+                }
+                visitor.visit_name(ident.span, ident.node.name);
+            });
             walk_list!(visitor, visit_expr, opt_expr);
         }
-        ExprBreak(Some(label), ref opt_expr) => {
-            visitor.visit_def_mention(Def::Label(label.loop_id));
-            visitor.visit_name(label.span, label.name);
-            walk_list!(visitor, visit_expr, opt_expr);
-        }
-        ExprAgain(None) => {}
-        ExprAgain(Some(label)) => {
-            visitor.visit_def_mention(Def::Label(label.loop_id));
-            visitor.visit_name(label.span, label.name);
+        ExprAgain(label) => {
+            label.ident.map(|ident| {
+                if let Ok(loop_id) = label.loop_id.into() {
+                    visitor.visit_def_mention(Def::Label(loop_id));
+                }
+                visitor.visit_name(ident.span, ident.node.name);
+            });
         }
         ExprRet(ref optional_expression) => {
             walk_list!(visitor, visit_expr, optional_expression);
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index c87ce6505fc..468421a68b5 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -50,6 +50,7 @@ use util::nodemap::{DefIdMap, NodeMap, FxHashMap};
 
 use std::collections::BTreeMap;
 use std::iter;
+use std::mem;
 
 use syntax::attr;
 use syntax::ast::*;
@@ -79,6 +80,12 @@ pub struct LoweringContext<'a> {
     impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
     bodies: FxHashMap<hir::BodyId, hir::Body>,
 
+    trait_impls: BTreeMap<DefId, Vec<NodeId>>,
+    trait_default_impl: BTreeMap<DefId, NodeId>,
+
+    loop_scopes: Vec<NodeId>,
+    is_in_loop_condition: bool,
+
     type_def_lifetime_params: DefIdMap<usize>,
 }
 
@@ -112,6 +119,10 @@ pub fn lower_crate(sess: &Session,
         trait_items: BTreeMap::new(),
         impl_items: BTreeMap::new(),
         bodies: FxHashMap(),
+        trait_impls: BTreeMap::new(),
+        trait_default_impl: BTreeMap::new(),
+        loop_scopes: Vec::new(),
+        is_in_loop_condition: false,
         type_def_lifetime_params: DefIdMap(),
     }.lower_crate(krate)
 }
@@ -195,6 +206,8 @@ impl<'a> LoweringContext<'a> {
             trait_items: self.trait_items,
             impl_items: self.impl_items,
             bodies: self.bodies,
+            trait_impls: self.trait_impls,
+            trait_default_impl: self.trait_default_impl,
         }
     }
 
@@ -244,6 +257,55 @@ impl<'a> LoweringContext<'a> {
         span
     }
 
+    fn with_loop_scope<T, F>(&mut self, loop_id: NodeId, f: F) -> T
+        where F: FnOnce(&mut LoweringContext) -> T
+    {
+        // We're no longer in the base loop's condition; we're in another loop.
+        let was_in_loop_condition = self.is_in_loop_condition;
+        self.is_in_loop_condition = false;
+
+        let len = self.loop_scopes.len();
+        self.loop_scopes.push(loop_id);
+
+        let result = f(self);
+        assert_eq!(len + 1, self.loop_scopes.len(),
+            "Loop scopes should be added and removed in stack order");
+
+        self.loop_scopes.pop().unwrap();
+
+        self.is_in_loop_condition = was_in_loop_condition;
+
+        result
+    }
+
+    fn with_loop_condition_scope<T, F>(&mut self, f: F) -> T
+        where F: FnOnce(&mut LoweringContext) -> T
+    {
+        let was_in_loop_condition = self.is_in_loop_condition;
+        self.is_in_loop_condition = true;
+
+        let result = f(self);
+
+        self.is_in_loop_condition = was_in_loop_condition;
+
+        result
+    }
+
+    fn with_new_loop_scopes<T, F>(&mut self, f: F) -> T
+        where F: FnOnce(&mut LoweringContext) -> T
+    {
+        let was_in_loop_condition = self.is_in_loop_condition;
+        self.is_in_loop_condition = false;
+
+        let loop_scopes = mem::replace(&mut self.loop_scopes, Vec::new());
+        let result = f(self);
+        mem::replace(&mut self.loop_scopes, loop_scopes);
+
+        self.is_in_loop_condition = was_in_loop_condition;
+
+        result
+    }
+
     fn with_parent_def<T, F>(&mut self, parent_id: NodeId, f: F) -> T
         where F: FnOnce(&mut LoweringContext) -> T
     {
@@ -271,17 +333,24 @@ impl<'a> LoweringContext<'a> {
         o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name))
     }
 
-    fn lower_label(&mut self, id: NodeId, label: Option<Spanned<Ident>>) -> Option<hir::Label> {
-        label.map(|sp_ident| {
-            hir::Label {
-                span: sp_ident.span,
-                name: sp_ident.node.name,
-                loop_id: match self.expect_full_def(id) {
-                    Def::Label(loop_id) => loop_id,
-                    _ => DUMMY_NODE_ID
+    fn lower_destination(&mut self, destination: Option<(NodeId, Spanned<Ident>)>)
+        -> hir::Destination
+    {
+        match destination {
+            Some((id, label_ident)) => hir::Destination {
+                ident: Some(label_ident),
+                loop_id: if let Def::Label(loop_id) = self.expect_full_def(id) {
+                    hir::LoopIdResult::Ok(loop_id)
+                } else {
+                    hir::LoopIdResult::Err(hir::LoopIdError::UnresolvedLabel)
                 }
+            },
+            None => hir::Destination {
+                ident: None,
+                loop_id: self.loop_scopes.last().map(|innermost_loop_id| Ok(*innermost_loop_id))
+                            .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)).into()
             }
-        })
+        }
     }
 
     fn lower_attrs(&mut self, attrs: &Vec<Attribute>) -> hir::HirVec<Attribute> {
@@ -463,7 +532,7 @@ impl<'a> LoweringContext<'a> {
                         return n;
                     }
                     assert!(!def_id.is_local());
-                    let (n, _) = self.sess.cstore.item_generics_own_param_counts(def_id);
+                    let n = self.sess.cstore.item_generics_cloned(def_id).regions.len();
                     self.type_def_lifetime_params.insert(def_id, n);
                     n
                 });
@@ -992,15 +1061,17 @@ impl<'a> LoweringContext<'a> {
                                self.record_body(value, None))
             }
             ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
-                let body = self.lower_block(body);
-                let body = self.expr_block(body, ThinVec::new());
-                let body_id = self.record_body(body, Some(decl));
-                hir::ItemFn(self.lower_fn_decl(decl),
-                            self.lower_unsafety(unsafety),
-                            self.lower_constness(constness),
-                            abi,
-                            self.lower_generics(generics),
-                            body_id)
+                self.with_new_loop_scopes(|this| {
+                    let body = this.lower_block(body);
+                    let body = this.expr_block(body, ThinVec::new());
+                    let body_id = this.record_body(body, Some(decl));
+                    hir::ItemFn(this.lower_fn_decl(decl),
+                                              this.lower_unsafety(unsafety),
+                                              this.lower_constness(constness),
+                                              abi,
+                                              this.lower_generics(generics),
+                                              body_id)
+                })
             }
             ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)),
             ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)),
@@ -1025,14 +1096,27 @@ impl<'a> LoweringContext<'a> {
                 hir::ItemUnion(vdata, self.lower_generics(generics))
             }
             ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
+                let trait_ref = self.lower_trait_ref(trait_ref);
+
+                if let Def::Trait(def_id) = trait_ref.path.def {
+                    self.trait_default_impl.insert(def_id, id);
+                }
+
                 hir::ItemDefaultImpl(self.lower_unsafety(unsafety),
-                                     self.lower_trait_ref(trait_ref))
+                                     trait_ref)
             }
             ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => {
                 let new_impl_items = impl_items.iter()
                                                .map(|item| self.lower_impl_item_ref(item))
                                                .collect();
                 let ifce = ifce.as_ref().map(|trait_ref| self.lower_trait_ref(trait_ref));
+
+                if let Some(ref trait_ref) = ifce {
+                    if let Def::Trait(def_id) = trait_ref.path.def {
+                        self.trait_impls.entry(def_id).or_insert(vec![]).push(id);
+                    }
+                }
+
                 hir::ItemImpl(self.lower_unsafety(unsafety),
                               self.lower_impl_polarity(polarity),
                               self.lower_generics(generics),
@@ -1562,13 +1646,17 @@ impl<'a> LoweringContext<'a> {
                     hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk), else_opt)
                 }
                 ExprKind::While(ref cond, ref body, opt_ident) => {
-                    hir::ExprWhile(P(self.lower_expr(cond)), self.lower_block(body),
-                                   self.lower_opt_sp_ident(opt_ident))
+                    self.with_loop_scope(e.id, |this|
+                        hir::ExprWhile(
+                            this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
+                            this.lower_block(body),
+                            this.lower_opt_sp_ident(opt_ident)))
                 }
                 ExprKind::Loop(ref body, opt_ident) => {
-                    hir::ExprLoop(self.lower_block(body),
-                                  self.lower_opt_sp_ident(opt_ident),
-                                  hir::LoopSource::Loop)
+                    self.with_loop_scope(e.id, |this|
+                        hir::ExprLoop(this.lower_block(body),
+                                      this.lower_opt_sp_ident(opt_ident),
+                                      hir::LoopSource::Loop))
                 }
                 ExprKind::Match(ref expr, ref arms) => {
                     hir::ExprMatch(P(self.lower_expr(expr)),
@@ -1576,12 +1664,14 @@ impl<'a> LoweringContext<'a> {
                                    hir::MatchSource::Normal)
                 }
                 ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => {
-                    self.with_parent_def(e.id, |this| {
-                        let expr = this.lower_expr(body);
-                        hir::ExprClosure(this.lower_capture_clause(capture_clause),
-                                         this.lower_fn_decl(decl),
-                                         this.record_body(expr, Some(decl)),
-                                         fn_decl_span)
+                    self.with_new_loop_scopes(|this| {
+                        this.with_parent_def(e.id, |this| {
+                            let expr = this.lower_expr(body);
+                            hir::ExprClosure(this.lower_capture_clause(capture_clause),
+                                             this.lower_fn_decl(decl),
+                                             this.record_body(expr, Some(decl)),
+                                             fn_decl_span)
+                        })
                     })
                 }
                 ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk)),
@@ -1660,10 +1750,29 @@ impl<'a> LoweringContext<'a> {
                     hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional))
                 }
                 ExprKind::Break(opt_ident, ref opt_expr) => {
-                    hir::ExprBreak(self.lower_label(e.id, opt_ident),
-                                   opt_expr.as_ref().map(|x| P(self.lower_expr(x))))
+                    let label_result = if self.is_in_loop_condition && opt_ident.is_none() {
+                        hir::Destination {
+                            ident: opt_ident,
+                            loop_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
+                        }
+                    } else {
+                        self.lower_destination(opt_ident.map(|ident| (e.id, ident)))
+                    };
+                    hir::ExprBreak(
+                            label_result,
+                            opt_expr.as_ref().map(|x| P(self.lower_expr(x))))
                 }
-                ExprKind::Continue(opt_ident) => hir::ExprAgain(self.lower_label(e.id, opt_ident)),
+                ExprKind::Continue(opt_ident) =>
+                    hir::ExprAgain(
+                        if self.is_in_loop_condition && opt_ident.is_none() {
+                            hir::Destination {
+                                ident: opt_ident,
+                                loop_id: Err(
+                                    hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
+                            }
+                        } else {
+                            self.lower_destination(opt_ident.map( |ident| (e.id, ident)))
+                        }),
                 ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))),
                 ExprKind::InlineAsm(ref asm) => {
                     let hir_asm = hir::InlineAsm {
@@ -1804,9 +1913,16 @@ impl<'a> LoweringContext<'a> {
                     //     }
                     //   }
 
+                    // Note that the block AND the condition are evaluated in the loop scope.
+                    // This is done to allow `break` from inside the condition of the loop.
+                    let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| (
+                        this.lower_block(body),
+                        this.expr_break(e.span, ThinVec::new()),
+                        this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))),
+                    ));
+
                     // `<pat> => <body>`
                     let pat_arm = {
-                        let body = self.lower_block(body);
                         let body_expr = P(self.expr_block(body, ThinVec::new()));
                         let pat = self.lower_pat(pat);
                         self.arm(hir_vec![pat], body_expr)
@@ -1815,13 +1931,11 @@ impl<'a> LoweringContext<'a> {
                     // `_ => break`
                     let break_arm = {
                         let pat_under = self.pat_wild(e.span);
-                        let break_expr = self.expr_break(e.span, ThinVec::new());
                         self.arm(hir_vec![pat_under], break_expr)
                     };
 
                     // `match <sub_expr> { ... }`
                     let arms = hir_vec![pat_arm, break_arm];
-                    let sub_expr = P(self.lower_expr(sub_expr));
                     let match_expr = self.expr(e.span,
                                                hir::ExprMatch(sub_expr,
                                                               arms,
@@ -1863,7 +1977,7 @@ impl<'a> LoweringContext<'a> {
 
                     // `::std::option::Option::Some(<pat>) => <body>`
                     let pat_arm = {
-                        let body_block = self.lower_block(body);
+                        let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body));
                         let body_expr = P(self.expr_block(body_block, ThinVec::new()));
                         let pat = self.lower_pat(pat);
                         let some_pat = self.pat_some(e.span, pat);
@@ -1873,7 +1987,8 @@ impl<'a> LoweringContext<'a> {
 
                     // `::std::option::Option::None => break`
                     let break_arm = {
-                        let break_expr = self.expr_break(e.span, ThinVec::new());
+                        let break_expr = self.with_loop_scope(e.id, |this|
+                            this.expr_break(e.span, ThinVec::new()));
                         let pat = self.pat_none(e.span);
                         self.arm(hir_vec![pat], break_expr)
                     };
@@ -2151,7 +2266,8 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn expr_break(&mut self, span: Span, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
-        P(self.expr(span, hir::ExprBreak(None, None), attrs))
+        let expr_break = hir::ExprBreak(self.lower_destination(None), None);
+        P(self.expr(span, expr_break, attrs))
     }
 
     fn expr_call(&mut self, span: Span, e: P<hir::Expr>, args: hir::HirVec<hir::Expr>)
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 9f31b5b456b..20b4d8d8a8f 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -437,6 +437,50 @@ impl<'hir> Map<'hir> {
         self.local_def_id(self.body_owner(id))
     }
 
+    pub fn ty_param_owner(&self, id: NodeId) -> NodeId {
+        match self.get(id) {
+            NodeItem(&Item { node: ItemTrait(..), .. }) => id,
+            NodeTyParam(_) => self.get_parent_node(id),
+            _ => {
+                bug!("ty_param_owner: {} not a type parameter",
+                    self.node_to_string(id))
+            }
+        }
+    }
+
+    pub fn ty_param_name(&self, id: NodeId) -> Name {
+        match self.get(id) {
+            NodeItem(&Item { node: ItemTrait(..), .. }) => {
+                keywords::SelfType.name()
+            }
+            NodeTyParam(tp) => tp.name,
+            _ => {
+                bug!("ty_param_name: {} not a type parameter",
+                    self.node_to_string(id))
+            }
+        }
+    }
+
+    pub fn trait_impls(&self, trait_did: DefId) -> &'hir [NodeId] {
+        self.dep_graph.read(DepNode::TraitImpls(trait_did));
+
+        // NB: intentionally bypass `self.forest.krate()` so that we
+        // do not trigger a read of the whole krate here
+        self.forest.krate.trait_impls.get(&trait_did).map_or(&[], |xs| &xs[..])
+    }
+
+    pub fn trait_default_impl(&self, trait_did: DefId) -> Option<NodeId> {
+        self.dep_graph.read(DepNode::TraitImpls(trait_did));
+
+        // NB: intentionally bypass `self.forest.krate()` so that we
+        // do not trigger a read of the whole krate here
+        self.forest.krate.trait_default_impl.get(&trait_did).cloned()
+    }
+
+    pub fn trait_is_auto(&self, trait_did: DefId) -> bool {
+        self.trait_default_impl(trait_did).is_some()
+    }
+
     /// Get the attributes on the krate. This is preferable to
     /// invoking `krate.attrs` because it registers a tighter
     /// dep-graph access.
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 4ebe416e1bf..8b6c75886ba 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -36,7 +36,7 @@ use util::nodemap::{NodeMap, FxHashMap, FxHashSet};
 use syntax_pos::{Span, ExpnId, DUMMY_SP};
 use syntax::codemap::{self, Spanned};
 use syntax::abi::Abi;
-use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect};
+use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
 use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
 use syntax::ptr::P;
 use syntax::symbol::{Symbol, keywords};
@@ -410,6 +410,9 @@ pub struct Crate {
     pub trait_items: BTreeMap<TraitItemId, TraitItem>,
     pub impl_items: BTreeMap<ImplItemId, ImplItem>,
     pub bodies: FxHashMap<BodyId, Body>,
+
+    pub trait_impls: BTreeMap<DefId, Vec<NodeId>>,
+    pub trait_default_impl: BTreeMap<DefId, NodeId>,
 }
 
 impl Crate {
@@ -959,9 +962,9 @@ pub enum Expr_ {
     /// A referencing operation (`&a` or `&mut a`)
     ExprAddrOf(Mutability, P<Expr>),
     /// A `break`, with an optional label to break
-    ExprBreak(Option<Label>, Option<P<Expr>>),
+    ExprBreak(Destination, Option<P<Expr>>),
     /// A `continue`, with an optional label
-    ExprAgain(Option<Label>),
+    ExprAgain(Destination),
     /// A `return`, with an optional value to be returned
     ExprRet(Option<P<Expr>>),
 
@@ -1030,12 +1033,56 @@ pub enum LoopSource {
     ForLoop,
 }
 
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum LoopIdError {
+    OutsideLoopScope,
+    UnlabeledCfInWhileCondition,
+    UnresolvedLabel,
+}
 
+impl fmt::Display for LoopIdError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(match *self {
+            LoopIdError::OutsideLoopScope => "not inside loop scope",
+            LoopIdError::UnlabeledCfInWhileCondition =>
+                "unlabeled control flow (break or continue) in while condition",
+            LoopIdError::UnresolvedLabel => "label not found",
+        }, f)
+    }
+}
+
+// FIXME(cramertj) this should use `Result` once master compiles w/ a vesion of Rust where
+// `Result` implements `Encodable`/`Decodable`
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub struct Label {
-    pub span: Span,
-    pub name: Name,
-    pub loop_id: NodeId
+pub enum LoopIdResult {
+    Ok(NodeId),
+    Err(LoopIdError),
+}
+impl Into<Result<NodeId, LoopIdError>> for LoopIdResult {
+    fn into(self) -> Result<NodeId, LoopIdError> {
+        match self {
+            LoopIdResult::Ok(ok) => Ok(ok),
+            LoopIdResult::Err(err) => Err(err),
+        }
+    }
+}
+impl From<Result<NodeId, LoopIdError>> for LoopIdResult {
+    fn from(res: Result<NodeId, LoopIdError>) -> Self {
+        match res {
+            Ok(ok) => LoopIdResult::Ok(ok),
+            Err(err) => LoopIdResult::Err(err),
+        }
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub struct Destination {
+    // This is `Some(_)` iff there is an explicit user-specified `label
+    pub ident: Option<Spanned<Ident>>,
+
+    // These errors are caught and then reported during the diagnostics pass in
+    // librustc_passes/loops.rs
+    pub loop_id: LoopIdResult,
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index e058c48c591..3411de9bb5d 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -1354,11 +1354,11 @@ impl<'a> State<'a> {
             hir::ExprPath(ref qpath) => {
                 self.print_qpath(qpath, true)?
             }
-            hir::ExprBreak(opt_label, ref opt_expr) => {
+            hir::ExprBreak(label, ref opt_expr) => {
                 word(&mut self.s, "break")?;
                 space(&mut self.s)?;
-                if let Some(label) = opt_label {
-                    self.print_name(label.name)?;
+                if let Some(label_ident) = label.ident {
+                    self.print_name(label_ident.node.name)?;
                     space(&mut self.s)?;
                 }
                 if let Some(ref expr) = *opt_expr {
@@ -1366,11 +1366,11 @@ impl<'a> State<'a> {
                     space(&mut self.s)?;
                 }
             }
-            hir::ExprAgain(opt_label) => {
+            hir::ExprAgain(label) => {
                 word(&mut self.s, "continue")?;
                 space(&mut self.s)?;
-                if let Some(label) = opt_label {
-                    self.print_name(label.name)?;
+                if let Some(label_ident) = label.ident {
+                    self.print_name(label_ident.node.name)?;
                     space(&mut self.s)?
                 }
             }
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index 9295fb2ee32..f48ff87689f 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -379,40 +379,41 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                          values: Option<ValuePairs<'tcx>>,
                          terr: &TypeError<'tcx>)
     {
-        let expected_found = match values {
-            None => None,
-            Some(values) => match self.values_str(&values) {
-                Some((expected, found)) => Some((expected, found)),
-                None => {
-                    // Derived error. Cancel the emitter.
-                    self.tcx.sess.diagnostic().cancel(diag);
-                    return
-                }
+        let (expected_found, is_simple_error) = match values {
+            None => (None, false),
+            Some(values) => {
+                let is_simple_error = match values {
+                    ValuePairs::Types(exp_found) => {
+                        exp_found.expected.is_primitive() && exp_found.found.is_primitive()
+                    }
+                    _ => false,
+                };
+                let vals = match self.values_str(&values) {
+                    Some((expected, found)) => Some((expected, found)),
+                    None => {
+                        // Derived error. Cancel the emitter.
+                        self.tcx.sess.diagnostic().cancel(diag);
+                        return
+                    }
+                };
+                (vals, is_simple_error)
             }
         };
 
         let span = cause.span;
 
         if let Some((expected, found)) = expected_found {
-            let is_simple_error = if let &TypeError::Sorts(ref values) = terr {
-                values.expected.is_primitive() && values.found.is_primitive()
-            } else {
-                false
-            };
-
-            if !is_simple_error {
-                if expected == found {
-                    if let &TypeError::Sorts(ref values) = terr {
-                        diag.note_expected_found_extra(
-                            &"type", &expected, &found,
-                            &format!(" ({})", values.expected.sort_string(self.tcx)),
-                            &format!(" ({})", values.found.sort_string(self.tcx)));
-                    } else {
-                        diag.note_expected_found(&"type", &expected, &found);
-                    }
-                } else {
+            match (terr, is_simple_error, expected == found) {
+                (&TypeError::Sorts(ref values), false,  true) => {
+                    diag.note_expected_found_extra(
+                        &"type", &expected, &found,
+                        &format!(" ({})", values.expected.sort_string(self.tcx)),
+                        &format!(" ({})", values.found.sort_string(self.tcx)));
+                }
+                (_, false,  _) => {
                     diag.note_expected_found(&"type", &expected, &found);
                 }
+                _ => (),
             }
         }
 
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index c3a6a62764d..a929060cf98 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -505,7 +505,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
             evaluation_cache: traits::EvaluationCache::new(),
             projection_cache: RefCell::new(traits::ProjectionCache::new()),
             reported_trait_errors: RefCell::new(FxHashSet()),
-            projection_mode: Reveal::NotSpecializable,
+            projection_mode: Reveal::UserFacing,
             tainted_by_errors_flag: Cell::new(false),
             err_count_on_creation: self.sess.err_count(),
             obligations_in_snapshot: Cell::new(false),
@@ -600,7 +600,7 @@ impl_trans_normalize!('gcx,
     Ty<'gcx>,
     &'gcx Substs<'gcx>,
     ty::FnSig<'gcx>,
-    &'gcx ty::BareFnTy<'gcx>,
+    ty::PolyFnSig<'gcx>,
     ty::ClosureSubsts<'gcx>,
     ty::PolyTraitRef<'gcx>,
     ty::ExistentialTraitRef<'gcx>
@@ -1197,16 +1197,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// as the substitutions for the default, `(T, U)`.
     pub fn type_var_for_def(&self,
                             span: Span,
-                            def: &ty::TypeParameterDef<'tcx>,
+                            def: &ty::TypeParameterDef,
                             substs: &[Kind<'tcx>])
                             -> Ty<'tcx> {
-        let default = def.default.map(|default| {
-            type_variable::Default {
+        let default = if def.has_default {
+            let default = self.tcx.item_type(def.def_id);
+            Some(type_variable::Default {
                 ty: default.subst_spanned(self.tcx, substs, Some(span)),
                 origin_span: span,
-                def_id: def.default_def_id
-            }
-        });
+                def_id: def.def_id
+            })
+        } else {
+            None
+        };
 
 
         let ty_var_id = self.type_variables
@@ -1646,20 +1649,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         Some(self.tcx.closure_kind(def_id))
     }
 
-    pub fn closure_type(&self,
-                        def_id: DefId,
-                        substs: ty::ClosureSubsts<'tcx>)
-                        -> ty::ClosureTy<'tcx>
-    {
+    pub fn closure_type(&self, def_id: DefId) -> ty::PolyFnSig<'tcx> {
         if let InferTables::InProgress(tables) = self.tables {
             if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
-                if let Some(ty) = tables.borrow().closure_tys.get(&id) {
-                    return ty.subst(self.tcx, substs.substs);
+                if let Some(&ty) = tables.borrow().closure_tys.get(&id) {
+                    return ty;
                 }
             }
         }
 
-        self.tcx.closure_type(def_id, substs)
+        self.tcx.closure_type(def_id)
     }
 }
 
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index d144f7575a2..c4fccdcb9eb 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -39,6 +39,7 @@
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
 #![feature(slice_patterns)]
+#![feature(specialization)]
 #![feature(staged_api)]
 #![feature(unboxed_closures)]
 
@@ -75,7 +76,6 @@ pub mod infer;
 pub mod lint;
 
 pub mod middle {
-    pub mod astconv_util;
     pub mod expr_use_visitor;
     pub mod const_val;
     pub mod cstore;
diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs
deleted file mode 100644
index 3418034b069..00000000000
--- a/src/librustc/middle/astconv_util.rs
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
- * This module contains a simple utility routine
- * used by both `typeck` and `const_eval`.
- * Almost certainly this could (and should) be refactored out of existence.
- */
-
-use hir;
-use hir::def::Def;
-use ty::{Ty, TyCtxt};
-
-use syntax_pos::Span;
-
-impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-    pub fn prohibit_type_params(self, segments: &[hir::PathSegment]) {
-        for segment in segments {
-            for typ in segment.parameters.types() {
-                struct_span_err!(self.sess, typ.span, E0109,
-                                 "type parameters are not allowed on this type")
-                    .span_label(typ.span, &format!("type parameter not allowed"))
-                    .emit();
-                break;
-            }
-            for lifetime in segment.parameters.lifetimes() {
-                struct_span_err!(self.sess, lifetime.span, E0110,
-                                 "lifetime parameters are not allowed on this type")
-                    .span_label(lifetime.span,
-                                &format!("lifetime parameter not allowed on this type"))
-                    .emit();
-                break;
-            }
-            for binding in segment.parameters.bindings() {
-                self.prohibit_projection(binding.span);
-                break;
-            }
-        }
-    }
-
-    pub fn prohibit_projection(self, span: Span)
-    {
-        let mut err = struct_span_err!(self.sess, span, E0229,
-                                       "associated type bindings are not allowed here");
-        err.span_label(span, &format!("associate type not allowed here")).emit();
-    }
-
-    pub fn prim_ty_to_ty(self,
-                         segments: &[hir::PathSegment],
-                         nty: hir::PrimTy)
-                         -> Ty<'tcx> {
-        self.prohibit_type_params(segments);
-        match nty {
-            hir::TyBool => self.types.bool,
-            hir::TyChar => self.types.char,
-            hir::TyInt(it) => self.mk_mach_int(it),
-            hir::TyUint(uit) => self.mk_mach_uint(uit),
-            hir::TyFloat(ft) => self.mk_mach_float(ft),
-            hir::TyStr => self.mk_str()
-        }
-    }
-
-    /// If a type in the AST is a primitive type, return the ty::Ty corresponding
-    /// to it.
-    pub fn ast_ty_to_prim_ty(self, ast_ty: &hir::Ty) -> Option<Ty<'tcx>> {
-        if let hir::TyPath(hir::QPath::Resolved(None, ref path)) = ast_ty.node {
-            if let Def::PrimTy(nty) = path.def {
-                Some(self.prim_ty_to_ty(&path.segments, nty))
-            } else {
-                None
-            }
-        } else {
-            None
-        }
-    }
-}
diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index 11919db479c..d81f89827d9 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -12,28 +12,30 @@ use syntax::symbol::InternedString;
 use syntax::ast;
 use std::rc::Rc;
 use hir::def_id::DefId;
+use ty::subst::Substs;
 use rustc_const_math::*;
+
 use self::ConstVal::*;
 pub use rustc_const_math::ConstInt;
 
 use std::collections::BTreeMap;
 
 #[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
-pub enum ConstVal {
+pub enum ConstVal<'tcx> {
     Float(ConstFloat),
     Integral(ConstInt),
     Str(InternedString),
     ByteStr(Rc<Vec<u8>>),
     Bool(bool),
-    Function(DefId),
-    Struct(BTreeMap<ast::Name, ConstVal>),
-    Tuple(Vec<ConstVal>),
-    Array(Vec<ConstVal>),
-    Repeat(Box<ConstVal>, u64),
+    Function(DefId, &'tcx Substs<'tcx>),
+    Struct(BTreeMap<ast::Name, ConstVal<'tcx>>),
+    Tuple(Vec<ConstVal<'tcx>>),
+    Array(Vec<ConstVal<'tcx>>),
+    Repeat(Box<ConstVal<'tcx>>, u64),
     Char(char),
 }
 
-impl ConstVal {
+impl<'tcx> ConstVal<'tcx> {
     pub fn description(&self) -> &'static str {
         match *self {
             Float(f) => f.description(),
@@ -43,7 +45,7 @@ impl ConstVal {
             Bool(_) => "boolean",
             Struct(_) => "struct",
             Tuple(_) => "tuple",
-            Function(_) => "function definition",
+            Function(..) => "function definition",
             Array(..) => "array",
             Repeat(..) => "repeat",
             Char(..) => "char",
@@ -53,8 +55,7 @@ impl ConstVal {
     pub fn to_const_int(&self) -> Option<ConstInt> {
         match *self {
             ConstVal::Integral(i) => Some(i),
-            ConstVal::Bool(true) => Some(ConstInt::Infer(1)),
-            ConstVal::Bool(false) => Some(ConstInt::Infer(0)),
+            ConstVal::Bool(b) => Some(ConstInt::U8(b as u8)),
             ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)),
             _ => None
         }
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 2d80fc32c46..4a7027b8997 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -28,13 +28,12 @@ use hir::map as hir_map;
 use hir::map::definitions::{Definitions, DefKey, DisambiguatedDefPathData};
 use hir::svh::Svh;
 use middle::lang_items;
-use middle::resolve_lifetime::ObjectLifetimeDefault;
-use ty::{self, Ty, TyCtxt};
-use mir::Mir;
+use ty::{self, TyCtxt};
 use session::Session;
 use session::search_paths::PathKind;
 use util::nodemap::{NodeSet, DefIdMap};
 
+use std::any::Any;
 use std::collections::BTreeMap;
 use std::path::PathBuf;
 use std::rc::Rc;
@@ -164,32 +163,18 @@ pub struct ExternCrate {
 
 /// A store of Rust crates, through with their metadata
 /// can be accessed.
-pub trait CrateStore<'tcx> {
+pub trait CrateStore {
+    fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc<Any>;
+
     // item info
     fn describe_def(&self, def: DefId) -> Option<Def>;
     fn def_span(&self, sess: &Session, def: DefId) -> Span;
     fn stability(&self, def: DefId) -> Option<attr::Stability>;
     fn deprecation(&self, def: DefId) -> Option<attr::Deprecation>;
     fn visibility(&self, def: DefId) -> ty::Visibility;
-    fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind;
-    fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-                      -> ty::ClosureTy<'tcx>;
-    fn item_variances(&self, def: DefId) -> Vec<ty::Variance>;
-    fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                     -> Ty<'tcx>;
     fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>>;
-    fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                           -> ty::GenericPredicates<'tcx>;
-    fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                                 -> ty::GenericPredicates<'tcx>;
-    fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                         -> ty::Generics<'tcx>;
-    fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize);
-    fn item_generics_object_lifetime_defaults(&self, def: DefId)
-                                              -> Vec<ObjectLifetimeDefault>;
+    fn item_generics_cloned(&self, def: DefId) -> ty::Generics;
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>;
-    fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef;
-    fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> &'tcx ty::AdtDef;
     fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>;
     fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId>;
 
@@ -197,21 +182,15 @@ pub trait CrateStore<'tcx> {
     fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>;
 
     // impl info
-    fn associated_item_def_ids(&self, def_id: DefId) -> Vec<DefId>;
-    fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                          -> Option<ty::TraitRef<'tcx>>;
     fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity;
-    fn custom_coerce_unsized_kind(&self, def: DefId)
-                                  -> Option<ty::adjustment::CustomCoerceUnsized>;
     fn impl_parent(&self, impl_def_id: DefId) -> Option<DefId>;
 
     // trait/impl-item info
     fn trait_of_item(&self, def_id: DefId) -> Option<DefId>;
-    fn associated_item(&self, def: DefId) -> Option<ty::AssociatedItem>;
+    fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem;
 
     // flags
     fn is_const_fn(&self, did: DefId) -> bool;
-    fn is_defaulted_trait(&self, did: DefId) -> bool;
     fn is_default_impl(&self, impl_did: DefId) -> bool;
     fn is_foreign_item(&self, did: DefId) -> bool;
     fn is_dllimport_foreign_item(&self, def: DefId) -> bool;
@@ -257,12 +236,11 @@ pub trait CrateStore<'tcx> {
     fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro;
 
     // misc. metadata
-    fn maybe_get_item_body<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                               -> Option<&'tcx hir::Body>;
+    fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+                                     -> Option<&'tcx hir::Body>;
     fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body>;
     fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool;
 
-    fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx>;
     fn is_item_mir_available(&self, def: DefId) -> bool;
 
     // This is basically a 1-based range of ints, which is a little
@@ -277,10 +255,10 @@ pub trait CrateStore<'tcx> {
     fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>;
     fn used_crate_source(&self, cnum: CrateNum) -> CrateSource;
     fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum>;
-    fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                           reexports: &def::ExportMap,
-                           link_meta: &LinkMeta,
-                           reachable: &NodeSet) -> Vec<u8>;
+    fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                 reexports: &def::ExportMap,
+                                 link_meta: &LinkMeta,
+                                 reachable: &NodeSet) -> Vec<u8>;
     fn metadata_encoding_version(&self) -> &[u8];
 }
 
@@ -314,39 +292,23 @@ pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
 /// A dummy crate store that does not support any non-local crates,
 /// for test purposes.
 pub struct DummyCrateStore;
+
 #[allow(unused_variables)]
-impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
+impl CrateStore for DummyCrateStore {
+    fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc<Any>
+        { bug!("crate_data_as_rc_any") }
     // item info
     fn describe_def(&self, def: DefId) -> Option<Def> { bug!("describe_def") }
     fn def_span(&self, sess: &Session, def: DefId) -> Span { bug!("def_span") }
     fn stability(&self, def: DefId) -> Option<attr::Stability> { bug!("stability") }
     fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> { bug!("deprecation") }
     fn visibility(&self, def: DefId) -> ty::Visibility { bug!("visibility") }
-    fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind { bug!("closure_kind") }
-    fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-                      -> ty::ClosureTy<'tcx>  { bug!("closure_ty") }
-    fn item_variances(&self, def: DefId) -> Vec<ty::Variance> { bug!("item_variances") }
-    fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                     -> Ty<'tcx> { bug!("item_type") }
     fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>> {
         bug!("visible_parent_map")
     }
-    fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                           -> ty::GenericPredicates<'tcx> { bug!("item_predicates") }
-    fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                                 -> ty::GenericPredicates<'tcx> { bug!("item_super_predicates") }
-    fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                         -> ty::Generics<'tcx> { bug!("item_generics") }
-    fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize)
-        { bug!("item_generics_own_param_counts") }
-    fn item_generics_object_lifetime_defaults(&self, def: DefId)
-                                              -> Vec<ObjectLifetimeDefault>
-        { bug!("item_generics_object_lifetime_defaults") }
+    fn item_generics_cloned(&self, def: DefId) -> ty::Generics
+        { bug!("item_generics_cloned") }
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute> { bug!("item_attrs") }
-    fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef
-        { bug!("trait_def") }
-    fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> &'tcx ty::AdtDef
-        { bug!("adt_def") }
     fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name> { bug!("fn_arg_names") }
     fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId> { vec![] }
 
@@ -354,23 +316,16 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId> { vec![] }
 
     // impl info
-    fn associated_item_def_ids(&self, def_id: DefId) -> Vec<DefId>
-        { bug!("associated_items") }
-    fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                          -> Option<ty::TraitRef<'tcx>> { bug!("impl_trait_ref") }
     fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity { bug!("impl_polarity") }
-    fn custom_coerce_unsized_kind(&self, def: DefId)
-                                  -> Option<ty::adjustment::CustomCoerceUnsized>
-        { bug!("custom_coerce_unsized_kind") }
     fn impl_parent(&self, def: DefId) -> Option<DefId> { bug!("impl_parent") }
 
     // trait/impl-item info
     fn trait_of_item(&self, def_id: DefId) -> Option<DefId> { bug!("trait_of_item") }
-    fn associated_item(&self, def: DefId) -> Option<ty::AssociatedItem> { bug!("associated_item") }
+    fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem
+        { bug!("associated_item_cloned") }
 
     // flags
     fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") }
-    fn is_defaulted_trait(&self, did: DefId) -> bool { bug!("is_defaulted_trait") }
     fn is_default_impl(&self, impl_did: DefId) -> bool { bug!("is_default_impl") }
     fn is_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") }
     fn is_dllimport_foreign_item(&self, id: DefId) -> bool { false }
@@ -429,8 +384,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") }
 
     // misc. metadata
-    fn maybe_get_item_body<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                               -> Option<&'tcx hir::Body> {
+    fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+                                     -> Option<&'tcx hir::Body> {
         bug!("maybe_get_item_body")
     }
     fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {
@@ -440,8 +395,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
         bug!("const_is_rvalue_promotable_to_static")
     }
 
-    fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                        -> Mir<'tcx> { bug!("get_item_mir") }
     fn is_item_mir_available(&self, def: DefId) -> bool {
         bug!("is_item_mir_available")
     }
@@ -459,7 +412,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
         { vec![] }
     fn used_crate_source(&self, cnum: CrateNum) -> CrateSource { bug!("used_crate_source") }
     fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> { None }
-    fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            reexports: &def::ExportMap,
                            link_meta: &LinkMeta,
                            reachable: &NodeSet) -> Vec<u8> { vec![] }
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index ae349667f9d..cc6d6e88dee 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -159,10 +159,9 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
             hir_map::NodeItem(item) => {
                 match item.node {
                     hir::ItemStruct(..) | hir::ItemUnion(..) => {
-                        self.struct_has_extern_repr = item.attrs.iter().any(|attr| {
-                            attr::find_repr_attrs(self.tcx.sess.diagnostic(), attr)
-                                .contains(&attr::ReprExtern)
-                        });
+                        let def_id = self.tcx.hir.local_def_id(item.id);
+                        let def = self.tcx.lookup_adt_def(def_id);
+                        self.struct_has_extern_repr = def.repr.c;
 
                         intravisit::walk_item(self, &item);
                     }
@@ -478,7 +477,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
         // method of a private type is used, but the type itself is never
         // called directly.
         if let Some(impl_list) =
-                self.tcx.inherent_impls.borrow().get(&self.tcx.hir.local_def_id(id)) {
+                self.tcx.maps.inherent_impls.borrow().get(&self.tcx.hir.local_def_id(id)) {
             for &impl_did in impl_list.iter() {
                 for &item_did in &self.tcx.associated_item_def_ids(impl_did)[..] {
                     if let Some(item_node_id) = self.tcx.hir.as_local_node_id(item_did) {
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index ab33c3843aa..5af8e7e52d8 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -44,8 +44,8 @@ enum RootUnsafeContext {
 
 fn type_is_unsafe_function(ty: Ty) -> bool {
     match ty.sty {
-        ty::TyFnDef(.., ref f) |
-        ty::TyFnPtr(ref f) => f.unsafety == hir::Unsafety::Unsafe,
+        ty::TyFnDef(.., f) |
+        ty::TyFnPtr(f) => f.unsafety() == hir::Unsafety::Unsafe,
         _ => false,
     }
 }
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 2ca0069560c..a44679b0b3e 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -715,6 +715,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                 adjustment::Adjust::NeverToAny |
                 adjustment::Adjust::ReifyFnPointer |
                 adjustment::Adjust::UnsafeFnPointer |
+                adjustment::Adjust::ClosureFnPointer |
                 adjustment::Adjust::MutToConstPointer => {
                     // Creating a closure/fn-pointer or unsizing consumes
                     // the input and stores it into the resulting rvalue.
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index 05be35df959..cdbf92e93a4 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -40,7 +40,7 @@ struct ExprVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
     fn def_id_is_transmute(&self, def_id: DefId) -> bool {
         let intrinsic = match self.infcx.tcx.item_type(def_id).sty {
-            ty::TyFnDef(.., ref bfty) => bfty.abi == RustIntrinsic,
+            ty::TyFnDef(.., bfty) => bfty.abi() == RustIntrinsic,
             _ => return false
         };
         intrinsic && self.infcx.tcx.item_name(def_id) == "transmute"
@@ -137,9 +137,9 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for ExprVisitor<'a, 'gcx, 'tcx> {
                 let typ = self.infcx.tables.borrow().node_id_to_type(expr.id);
                 let typ = self.infcx.tcx.lift_to_global(&typ).unwrap();
                 match typ.sty {
-                    ty::TyFnDef(.., ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
-                        let from = bare_fn_ty.sig.skip_binder().inputs()[0];
-                        let to = bare_fn_ty.sig.skip_binder().output();
+                    ty::TyFnDef(.., sig) if sig.abi() == RustIntrinsic => {
+                        let from = sig.inputs().skip_binder()[0];
+                        let to = *sig.output().skip_binder();
                         self.check_transmute(expr.span, from, to, expr.id);
                     }
                     _ => {
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 7fa3365694c..a8c1559ae23 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -675,23 +675,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         Ok(())
     }
 
-    fn find_loop_scope(&self,
-                       opt_label: Option<hir::Label>,
-                       sp: Span)
-                       -> NodeId {
-        match opt_label {
-            Some(label) => label.loop_id,
-            None => {
-                // Vanilla 'break' or 'continue', so use the enclosing
-                // loop scope
-                if self.loop_scope.is_empty() {
-                    span_bug!(sp, "break outside loop");
-                } else {
-                    *self.loop_scope.last().unwrap()
-                }
-            }
-        }
-    }
 
     #[allow(unused_must_use)]
     fn ln_str(&self, ln: LiveNode) -> String {
@@ -1018,9 +1001,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), exit_ln)
           }
 
-          hir::ExprBreak(opt_label, ref opt_expr) => {
+          hir::ExprBreak(label, ref opt_expr) => {
               // Find which label this break jumps to
-              let sc = self.find_loop_scope(opt_label, expr.span);
+              let sc = match label.loop_id.into() {
+                  Ok(loop_id) => loop_id,
+                  Err(err) => span_bug!(expr.span, "loop scope error: {}", err),
+              };
 
               // Now that we know the label we're going to,
               // look it up in the break loop nodes table
@@ -1031,9 +1017,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
               }
           }
 
-          hir::ExprAgain(opt_label) => {
+          hir::ExprAgain(label) => {
               // Find which label this expr continues to
-              let sc = self.find_loop_scope(opt_label, expr.span);
+              let sc = match label.loop_id.into() {
+                  Ok(loop_id) => loop_id,
+                  Err(err) => span_bug!(expr.span, "loop scope error: {}", err),
+              };
+
 
               // Now that we know the label we're going to,
               // look it up in the continue loop nodes table
@@ -1297,12 +1287,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         debug!("propagate_through_loop: using id for loop body {} {}",
                expr.id, self.ir.tcx.hir.node_to_pretty_string(body.id));
 
-        let cond_ln = match kind {
-            LoopLoop => ln,
-            WhileLoop(ref cond) => self.propagate_through_expr(&cond, ln),
-        };
-        let body_ln = self.with_loop_nodes(expr.id, succ, ln, |this| {
-            this.propagate_through_block(body, cond_ln)
+        let (cond_ln, body_ln) = self.with_loop_nodes(expr.id, succ, ln, |this| {
+            let cond_ln = match kind {
+                LoopLoop => ln,
+                WhileLoop(ref cond) => this.propagate_through_expr(&cond, ln),
+            };
+            let body_ln = this.propagate_through_block(body, cond_ln);
+            (cond_ln, body_ln)
         });
 
         // repeat until fixed point is reached:
@@ -1441,12 +1432,16 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                  body: &hir::Body)
     {
         let fn_ty = self.ir.tcx.item_type(self.ir.tcx.hir.local_def_id(id));
-        let fn_ret = match fn_ty.sty {
-            ty::TyClosure(closure_def_id, substs) =>
-                self.ir.tcx.closure_type(closure_def_id, substs).sig.output(),
-            _ => fn_ty.fn_ret()
+        let fn_sig = match fn_ty.sty {
+            ty::TyClosure(closure_def_id, substs) => {
+                self.ir.tcx.closure_type(closure_def_id)
+                    .subst(self.ir.tcx, substs.substs)
+            }
+            _ => fn_ty.fn_sig()
         };
 
+        let fn_ret = fn_sig.output();
+
         // within the fn body, late-bound regions are liberated
         // and must outlive the *call-site* of the function.
         let fn_ret =
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 627753039ba..b0c85e2ef4c 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -464,6 +464,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                     adjustment::Adjust::NeverToAny |
                     adjustment::Adjust::ReifyFnPointer |
                     adjustment::Adjust::UnsafeFnPointer |
+                    adjustment::Adjust::ClosureFnPointer |
                     adjustment::Adjust::MutToConstPointer |
                     adjustment::Adjust::DerefRef {..} => {
                         debug!("cat_expr({:?}): {:?}",
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 9bad98dda83..37749816eb1 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -995,7 +995,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             } else {
                 let cstore = &self.sess.cstore;
                 self.xcrate_object_lifetime_defaults.entry(def_id).or_insert_with(|| {
-                    cstore.item_generics_object_lifetime_defaults(def_id)
+                    cstore.item_generics_cloned(def_id).types.into_iter().map(|def| {
+                        def.object_lifetime_default
+                    }).collect()
                 })
             };
             unsubst.iter().map(|set| {
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 487e13b47fe..baa22d70614 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -433,23 +433,27 @@ struct Checker<'a, 'tcx: 'a> {
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     // (See issue #38412)
-    fn skip_stability_check_due_to_privacy(self, def_id: DefId) -> bool {
-        let visibility = {
-            // Check if `def_id` is a trait method.
-            match self.sess.cstore.associated_item(def_id) {
-                Some(ty::AssociatedItem { container: ty::TraitContainer(trait_def_id), .. }) => {
-                    // Trait methods do not declare visibility (even
-                    // for visibility info in cstore). Use containing
-                    // trait instead, so methods of pub traits are
-                    // themselves considered pub.
-                    self.sess.cstore.visibility(trait_def_id)
-                }
-                _ => {
-                    // Otherwise, cstore info works directly.
-                    self.sess.cstore.visibility(def_id)
+    fn skip_stability_check_due_to_privacy(self, mut def_id: DefId) -> bool {
+        // Check if `def_id` is a trait method.
+        match self.sess.cstore.describe_def(def_id) {
+            Some(Def::Method(_)) |
+            Some(Def::AssociatedTy(_)) |
+            Some(Def::AssociatedConst(_)) => {
+                match self.associated_item(def_id).container {
+                    ty::TraitContainer(trait_def_id) => {
+                        // Trait methods do not declare visibility (even
+                        // for visibility info in cstore). Use containing
+                        // trait instead, so methods of pub traits are
+                        // themselves considered pub.
+                        def_id = trait_def_id;
+                    }
+                    _ => {}
                 }
             }
-        };
+            _ => {}
+        }
+
+        let visibility = self.sess.cstore.visibility(def_id);
 
         match visibility {
             // must check stability for pub items.
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 3403cf04774..40ebc97a78a 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -542,7 +542,7 @@ impl<'tcx> Terminator<'tcx> {
 impl<'tcx> TerminatorKind<'tcx> {
     pub fn if_<'a, 'gcx>(tcx: ty::TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>,
                          t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
-        static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::Infer(0)];
+        static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::U8(0)];
         TerminatorKind::SwitchInt {
             discr: cond,
             switch_ty: tcx.types.bool,
@@ -1022,6 +1022,9 @@ pub enum CastKind {
     /// Convert unique, zero-sized type for a fn to fn()
     ReifyFnPointer,
 
+    /// Convert non capturing closure to fn()
+    ClosureFnPointer,
+
     /// Convert safe fn() to unsafe fn()
     UnsafeFnPointer,
 
@@ -1221,7 +1224,7 @@ pub enum Literal<'tcx> {
         substs: &'tcx Substs<'tcx>,
     },
     Value {
-        value: ConstVal,
+        value: ConstVal<'tcx>,
     },
     Promoted {
         // Index into the `promoted` vector of `Mir`.
@@ -1268,7 +1271,7 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
             write!(fmt, "b\"{}\"", escaped)
         }
         Bool(b) => write!(fmt, "{:?}", b),
-        Function(def_id) => write!(fmt, "{}", item_path_str(def_id)),
+        Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)),
         Struct(_) | Tuple(_) | Array(_) | Repeat(..) =>
             bug!("ConstVal `{:?}` should not be in MIR", const_val),
         Char(c) => write!(fmt, "{:?}", c),
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 5c8d031caf6..50a80305bee 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -173,7 +173,7 @@ impl<'tcx> Rvalue<'tcx> {
             Rvalue::Discriminant(ref lval) => {
                 let ty = lval.ty(mir, tcx).to_ty(tcx);
                 if let ty::TyAdt(adt_def, _) = ty.sty {
-                    Some(adt_def.discr_ty.to_ty(tcx))
+                    Some(adt_def.repr.discr_type().to_ty(tcx))
                 } else {
                     // Undefined behaviour, bug for now; may want to return something for
                     // the `discriminant` intrinsic later.
diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs
index 652fef76f28..4cbbb67c7e4 100644
--- a/src/librustc/mir/transform.rs
+++ b/src/librustc/mir/transform.rs
@@ -114,14 +114,14 @@ impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T {
                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     hooks: &mut [Box<for<'s> MirPassHook<'s>>])
     {
-        let def_ids = tcx.mir_map.borrow().keys();
+        let def_ids = tcx.maps.mir.borrow().keys();
         for def_id in def_ids {
             if !def_id.is_local() {
                 continue;
             }
 
             let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
-            let mir = &mut tcx.mir_map.borrow()[&def_id].borrow_mut();
+            let mir = &mut tcx.maps.mir.borrow()[&def_id].borrow_mut();
             tcx.dep_graph.write(DepNode::Mir(def_id));
 
             let id = tcx.hir.as_local_node_id(def_id).unwrap();
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 24615f2fa69..5fff03dabce 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -51,7 +51,7 @@ pub struct Config {
     pub uint_type: UintTy,
 }
 
-#[derive(Clone)]
+#[derive(Clone, Hash)]
 pub enum Sanitizer {
     Address,
     Leak,
@@ -288,7 +288,7 @@ top_level_options!(
         //            much sense: The search path can stay the same while the
         //            things discovered there might have changed on disk.
         search_paths: SearchPaths [TRACKED],
-        libs: Vec<(String, Option<String>, cstore::NativeLibraryKind)> [TRACKED],
+        libs: Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> [TRACKED],
         maybe_sysroot: Option<PathBuf> [TRACKED],
 
         target_triple: String [TRACKED],
@@ -804,6 +804,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
         "save all temporary output files during compilation"),
     rpath: bool = (false, parse_bool, [UNTRACKED],
         "set rpath values in libs/exes"),
+    overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "use overflow checks for integer arithmetic"),
     no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
         "don't pre-populate the pass manager with a list of passes"),
     no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
@@ -970,7 +972,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
           "encode MIR of all functions into the crate metadata"),
     osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
           "pass `-install_name @rpath/...` to the OSX linker"),
-    sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [UNTRACKED],
+    sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
                                    "Use a sanitizer"),
 }
 
@@ -1495,18 +1497,18 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
         let mut parts = s.splitn(2, '=');
         let kind = parts.next().unwrap();
         let (name, kind) = match (parts.next(), kind) {
-            (None, name) |
-            (Some(name), "dylib") => (name, cstore::NativeUnknown),
-            (Some(name), "framework") => (name, cstore::NativeFramework),
-            (Some(name), "static") => (name, cstore::NativeStatic),
-            (Some(name), "static-nobundle") => (name, cstore::NativeStaticNobundle),
+            (None, name) => (name, None),
+            (Some(name), "dylib") => (name, Some(cstore::NativeUnknown)),
+            (Some(name), "framework") => (name, Some(cstore::NativeFramework)),
+            (Some(name), "static") => (name, Some(cstore::NativeStatic)),
+            (Some(name), "static-nobundle") => (name, Some(cstore::NativeStaticNobundle)),
             (_, s) => {
                 early_error(error_format, &format!("unknown library kind `{}`, expected \
                                                   one of dylib, framework, or static",
                                                  s));
             }
         };
-        if kind == cstore::NativeStaticNobundle && !nightly_options::is_nightly_build() {
+        if kind == Some(cstore::NativeStaticNobundle) && !nightly_options::is_nightly_build() {
             early_error(error_format, &format!("the library kind 'static-nobundle' is only \
                                                 accepted on the nightly compiler"));
         }
@@ -1728,7 +1730,7 @@ mod dep_tracking {
     use std::path::PathBuf;
     use std::collections::hash_map::DefaultHasher;
     use super::{Passes, CrateType, OptLevel, DebugInfoLevel,
-                OutputTypes, Externs, ErrorOutputType};
+                OutputTypes, Externs, ErrorOutputType, Sanitizer};
     use syntax::feature_gate::UnstableFeatures;
     use rustc_back::PanicStrategy;
 
@@ -1772,6 +1774,7 @@ mod dep_tracking {
     impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
     impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
     impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
+    impl_dep_tracking_hash_via_hash!(Option<cstore::NativeLibraryKind>);
     impl_dep_tracking_hash_via_hash!(CrateType);
     impl_dep_tracking_hash_via_hash!(PanicStrategy);
     impl_dep_tracking_hash_via_hash!(Passes);
@@ -1781,12 +1784,14 @@ mod dep_tracking {
     impl_dep_tracking_hash_via_hash!(Externs);
     impl_dep_tracking_hash_via_hash!(OutputTypes);
     impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
+    impl_dep_tracking_hash_via_hash!(Sanitizer);
+    impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
 
     impl_dep_tracking_hash_for_sortable_vec_of!(String);
     impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
     impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
     impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>,
-                                                 cstore::NativeLibraryKind));
+                                                 Option<cstore::NativeLibraryKind>));
     impl DepTrackingHash for SearchPaths {
         fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
             let mut elems: Vec<_> = self
@@ -2230,24 +2235,24 @@ mod tests {
         let mut v4 = super::basic_options();
 
         // Reference
-        v1.libs = vec![(String::from("a"), None, cstore::NativeStatic),
-                       (String::from("b"), None, cstore::NativeFramework),
-                       (String::from("c"), None, cstore::NativeUnknown)];
+        v1.libs = vec![(String::from("a"), None, Some(cstore::NativeStatic)),
+                       (String::from("b"), None, Some(cstore::NativeFramework)),
+                       (String::from("c"), None, Some(cstore::NativeUnknown))];
 
         // Change label
-        v2.libs = vec![(String::from("a"), None, cstore::NativeStatic),
-                       (String::from("X"), None, cstore::NativeFramework),
-                       (String::from("c"), None, cstore::NativeUnknown)];
+        v2.libs = vec![(String::from("a"), None, Some(cstore::NativeStatic)),
+                       (String::from("X"), None, Some(cstore::NativeFramework)),
+                       (String::from("c"), None, Some(cstore::NativeUnknown))];
 
         // Change kind
-        v3.libs = vec![(String::from("a"), None, cstore::NativeStatic),
-                       (String::from("b"), None, cstore::NativeStatic),
-                       (String::from("c"), None, cstore::NativeUnknown)];
+        v3.libs = vec![(String::from("a"), None, Some(cstore::NativeStatic)),
+                       (String::from("b"), None, Some(cstore::NativeStatic)),
+                       (String::from("c"), None, Some(cstore::NativeUnknown))];
 
         // Change new-name
-        v4.libs = vec![(String::from("a"), None, cstore::NativeStatic),
-                       (String::from("b"), Some(String::from("X")), cstore::NativeFramework),
-                       (String::from("c"), None, cstore::NativeUnknown)];
+        v4.libs = vec![(String::from("a"), None, Some(cstore::NativeStatic)),
+                       (String::from("b"), Some(String::from("X")), Some(cstore::NativeFramework)),
+                       (String::from("c"), None, Some(cstore::NativeUnknown))];
 
         assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
         assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
@@ -2267,17 +2272,17 @@ mod tests {
         let mut v3 = super::basic_options();
 
         // Reference
-        v1.libs = vec![(String::from("a"), None, cstore::NativeStatic),
-                       (String::from("b"), None, cstore::NativeFramework),
-                       (String::from("c"), None, cstore::NativeUnknown)];
+        v1.libs = vec![(String::from("a"), None, Some(cstore::NativeStatic)),
+                       (String::from("b"), None, Some(cstore::NativeFramework)),
+                       (String::from("c"), None, Some(cstore::NativeUnknown))];
 
-        v2.libs = vec![(String::from("b"), None, cstore::NativeFramework),
-                       (String::from("a"), None, cstore::NativeStatic),
-                       (String::from("c"), None, cstore::NativeUnknown)];
+        v2.libs = vec![(String::from("b"), None, Some(cstore::NativeFramework)),
+                       (String::from("a"), None, Some(cstore::NativeStatic)),
+                       (String::from("c"), None, Some(cstore::NativeUnknown))];
 
-        v3.libs = vec![(String::from("c"), None, cstore::NativeUnknown),
-                       (String::from("a"), None, cstore::NativeStatic),
-                       (String::from("b"), None, cstore::NativeFramework)];
+        v3.libs = vec![(String::from("c"), None, Some(cstore::NativeUnknown)),
+                       (String::from("a"), None, Some(cstore::NativeStatic)),
+                       (String::from("b"), None, Some(cstore::NativeFramework))];
 
         assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
         assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
@@ -2346,6 +2351,10 @@ mod tests {
         assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
 
         opts = reference.clone();
+        opts.cg.overflow_checks = Some(true);
+        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+        opts = reference.clone();
         opts.cg.no_prepopulate_passes = true;
         assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
 
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index f10ea3544f2..3ba82f34c32 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -64,7 +64,7 @@ pub struct Session {
     pub target: config::Config,
     pub host: Target,
     pub opts: config::Options,
-    pub cstore: Rc<for<'a> CrateStore<'a>>,
+    pub cstore: Rc<CrateStore>,
     pub parse_sess: ParseSess,
     // For a library crate, this is always none
     pub entry_fn: RefCell<Option<(NodeId, Span)>>,
@@ -372,6 +372,11 @@ impl Session {
     pub fn nonzeroing_move_hints(&self) -> bool {
         self.opts.debugging_opts.enable_nonzeroing_move_hints
     }
+    pub fn overflow_checks(&self) -> bool {
+        self.opts.cg.overflow_checks
+            .or(self.opts.debugging_opts.force_overflow_checks)
+            .unwrap_or(self.opts.debug_assertions)
+    }
 
     pub fn must_not_eliminate_frame_pointers(&self) -> bool {
         self.opts.debuginfo != DebugInfoLevel::NoDebugInfo ||
@@ -505,7 +510,7 @@ pub fn build_session(sopts: config::Options,
                      dep_graph: &DepGraph,
                      local_crate_source_file: Option<PathBuf>,
                      registry: errors::registry::Registry,
-                     cstore: Rc<for<'a> CrateStore<'a>>)
+                     cstore: Rc<CrateStore>)
                      -> Session {
     build_session_with_codemap(sopts,
                                dep_graph,
@@ -520,7 +525,7 @@ pub fn build_session_with_codemap(sopts: config::Options,
                                   dep_graph: &DepGraph,
                                   local_crate_source_file: Option<PathBuf>,
                                   registry: errors::registry::Registry,
-                                  cstore: Rc<for<'a> CrateStore<'a>>,
+                                  cstore: Rc<CrateStore>,
                                   codemap: Rc<codemap::CodeMap>,
                                   emitter_dest: Option<Box<Write + Send>>)
                                   -> Session {
@@ -570,7 +575,7 @@ pub fn build_session_(sopts: config::Options,
                       local_crate_source_file: Option<PathBuf>,
                       span_diagnostic: errors::Handler,
                       codemap: Rc<codemap::CodeMap>,
-                      cstore: Rc<for<'a> CrateStore<'a>>)
+                      cstore: Rc<CrateStore>)
                       -> Session {
     let host = match Target::search(config::host_triple()) {
         Ok(t) => t,
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 70ca5fe83a9..f850fd97727 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -21,7 +21,6 @@ use super::{
     SelectionContext,
     SelectionError,
     ObjectSafetyViolation,
-    MethodViolationCode,
 };
 
 use fmt_macros::{Parser, Piece, Position};
@@ -267,61 +266,63 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
         let span = obligation.cause.span;
         let mut report = None;
-        for item in self.tcx.get_attrs(def_id).iter() {
-            if item.check_name("rustc_on_unimplemented") {
-                let err_sp = item.meta().span.substitute_dummy(span);
-                let trait_str = self.tcx.item_path_str(trait_ref.def_id);
-                if let Some(istring) = item.value_str() {
-                    let istring = &*istring.as_str();
-                    let generics = self.tcx.item_generics(trait_ref.def_id);
-                    let generic_map = generics.types.iter().map(|param| {
-                        (param.name.as_str().to_string(),
-                         trait_ref.substs.type_for_def(param).to_string())
-                    }).collect::<FxHashMap<String, String>>();
-                    let parser = Parser::new(istring);
-                    let mut errored = false;
-                    let err: String = parser.filter_map(|p| {
-                        match p {
-                            Piece::String(s) => Some(s),
-                            Piece::NextArgument(a) => match a.position {
-                                Position::ArgumentNamed(s) => match generic_map.get(s) {
-                                    Some(val) => Some(val),
-                                    None => {
-                                        span_err!(self.tcx.sess, err_sp, E0272,
-                                                       "the #[rustc_on_unimplemented] \
-                                                                attribute on \
-                                                                trait definition for {} refers to \
-                                                                non-existent type parameter {}",
-                                                               trait_str, s);
-                                        errored = true;
-                                        None
-                                    }
-                                },
-                                _ => {
-                                    span_err!(self.tcx.sess, err_sp, E0273,
-                                              "the #[rustc_on_unimplemented] attribute \
-                                               on trait definition for {} must have \
-                                               named format arguments, eg \
-                                               `#[rustc_on_unimplemented = \
-                                                \"foo {{T}}\"]`", trait_str);
+        if let Some(item) = self.tcx
+            .get_attrs(def_id)
+            .into_iter()
+            .filter(|a| a.check_name("rustc_on_unimplemented"))
+            .next()
+        {
+            let err_sp = item.meta().span.substitute_dummy(span);
+            let trait_str = self.tcx.item_path_str(trait_ref.def_id);
+            if let Some(istring) = item.value_str() {
+                let istring = &*istring.as_str();
+                let generics = self.tcx.item_generics(trait_ref.def_id);
+                let generic_map = generics.types.iter().map(|param| {
+                    (param.name.as_str().to_string(),
+                        trait_ref.substs.type_for_def(param).to_string())
+                }).collect::<FxHashMap<String, String>>();
+                let parser = Parser::new(istring);
+                let mut errored = false;
+                let err: String = parser.filter_map(|p| {
+                    match p {
+                        Piece::String(s) => Some(s),
+                        Piece::NextArgument(a) => match a.position {
+                            Position::ArgumentNamed(s) => match generic_map.get(s) {
+                                Some(val) => Some(val),
+                                None => {
+                                    span_err!(self.tcx.sess, err_sp, E0272,
+                                                    "the #[rustc_on_unimplemented] \
+                                                            attribute on \
+                                                            trait definition for {} refers to \
+                                                            non-existent type parameter {}",
+                                                            trait_str, s);
                                     errored = true;
                                     None
                                 }
+                            },
+                            _ => {
+                                span_err!(self.tcx.sess, err_sp, E0273,
+                                            "the #[rustc_on_unimplemented] attribute \
+                                            on trait definition for {} must have \
+                                            named format arguments, eg \
+                                            `#[rustc_on_unimplemented = \
+                                            \"foo {{T}}\"]`", trait_str);
+                                errored = true;
+                                None
                             }
                         }
-                    }).collect();
-                    // Report only if the format string checks out
-                    if !errored {
-                        report = Some(err);
                     }
-                } else {
-                    span_err!(self.tcx.sess, err_sp, E0274,
-                                            "the #[rustc_on_unimplemented] attribute on \
-                                                     trait definition for {} must have a value, \
-                                                     eg `#[rustc_on_unimplemented = \"foo\"]`",
-                                                     trait_str);
+                }).collect();
+                // Report only if the format string checks out
+                if !errored {
+                    report = Some(err);
                 }
-                break;
+            } else {
+                span_err!(self.tcx.sess, err_sp, E0274,
+                                        "the #[rustc_on_unimplemented] attribute on \
+                                                    trait definition for {} must have a value, \
+                                                    eg `#[rustc_on_unimplemented = \"foo\"]`",
+                                                    trait_str);
             }
         }
         report
@@ -359,34 +360,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn report_similar_impl_candidates(&self,
-                                      trait_ref: ty::PolyTraitRef<'tcx>,
+                                      impl_candidates: Vec<ty::TraitRef<'tcx>>,
                                       err: &mut DiagnosticBuilder)
     {
-        let simp = fast_reject::simplify_type(self.tcx,
-                                              trait_ref.skip_binder().self_ty(),
-                                              true);
-        let mut impl_candidates = Vec::new();
-        let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id());
-
-        match simp {
-            Some(simp) => trait_def.for_each_impl(self.tcx, |def_id| {
-                let imp = self.tcx.impl_trait_ref(def_id).unwrap();
-                let imp_simp = fast_reject::simplify_type(self.tcx,
-                                                          imp.self_ty(),
-                                                          true);
-                if let Some(imp_simp) = imp_simp {
-                    if simp != imp_simp {
-                        return;
-                    }
-                }
-                impl_candidates.push(imp);
-            }),
-            None => trait_def.for_each_impl(self.tcx, |def_id| {
-                impl_candidates.push(
-                    self.tcx.impl_trait_ref(def_id).unwrap());
-            })
-        };
-
         if impl_candidates.is_empty() {
             return;
         }
@@ -525,127 +501,118 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                         lint_id)
                         .emit();
                     return;
-                } else {
-                    match obligation.predicate {
-                        ty::Predicate::Trait(ref trait_predicate) => {
-                            let trait_predicate =
-                                self.resolve_type_vars_if_possible(trait_predicate);
-
-                            if self.tcx.sess.has_errors() && trait_predicate.references_error() {
-                                return;
-                            } else {
-                                let trait_ref = trait_predicate.to_poly_trait_ref();
-                                let (post_message, pre_message) = match self.get_parent_trait_ref(
-                                    &obligation.cause.code)
-                                {
-                                    Some(t) => {
-                                        (format!(" in `{}`", t), format!("within `{}`, ", t))
-                                    }
-                                    None => (String::new(), String::new()),
-                                };
-                                let mut err = struct_span_err!(
-                                    self.tcx.sess,
-                                    span,
-                                    E0277,
-                                    "the trait bound `{}` is not satisfied{}",
-                                    trait_ref.to_predicate(),
-                                    post_message);
-                                err.span_label(span,
-                                               &format!("{}the trait `{}` is not \
-                                                         implemented for `{}`",
-                                                        pre_message,
-                                                        trait_ref,
-                                                        trait_ref.self_ty()));
-
-                                // Try to report a help message
-
-                                if !trait_ref.has_infer_types() &&
-                                    self.predicate_can_apply(trait_ref) {
-                                    // If a where-clause may be useful, remind the
-                                    // user that they can add it.
-                                    //
-                                    // don't display an on-unimplemented note, as
-                                    // these notes will often be of the form
-                                    //     "the type `T` can't be frobnicated"
-                                    // which is somewhat confusing.
-                                    err.help(&format!("consider adding a `where {}` bound",
-                                                      trait_ref.to_predicate()));
-                                } else if let Some(s) = self.on_unimplemented_note(trait_ref,
-                                                                                   obligation) {
-                                    // If it has a custom "#[rustc_on_unimplemented]"
-                                    // error message, let's display it!
-                                    err.note(&s);
-                                } else {
-                                    // If we can't show anything useful, try to find
-                                    // similar impls.
-                                    let impl_candidates =
-                                        self.find_similar_impl_candidates(trait_ref);
-                                    if impl_candidates.len() > 0 {
-                                        self.report_similar_impl_candidates(trait_ref, &mut err);
-                                    }
-                                }
-                                err
-                            }
-                        }
+                }
+                match obligation.predicate {
+                    ty::Predicate::Trait(ref trait_predicate) => {
+                        let trait_predicate =
+                            self.resolve_type_vars_if_possible(trait_predicate);
 
-                        ty::Predicate::Equate(ref predicate) => {
-                            let predicate = self.resolve_type_vars_if_possible(predicate);
-                            let err = self.equality_predicate(&obligation.cause,
-                                                              &predicate).err().unwrap();
-                            struct_span_err!(self.tcx.sess, span, E0278,
-                                "the requirement `{}` is not satisfied (`{}`)",
-                                predicate, err)
+                        if self.tcx.sess.has_errors() && trait_predicate.references_error() {
+                            return;
                         }
-
-                        ty::Predicate::RegionOutlives(ref predicate) => {
-                            let predicate = self.resolve_type_vars_if_possible(predicate);
-                            let err = self.region_outlives_predicate(&obligation.cause,
-                                                                     &predicate).err().unwrap();
-                            struct_span_err!(self.tcx.sess, span, E0279,
-                                "the requirement `{}` is not satisfied (`{}`)",
-                                predicate, err)
+                        let trait_ref = trait_predicate.to_poly_trait_ref();
+                        let (post_message, pre_message) =
+                            self.get_parent_trait_ref(&obligation.cause.code)
+                                .map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t)))
+                                .unwrap_or((String::new(), String::new()));
+                        let mut err = struct_span_err!(
+                            self.tcx.sess,
+                            span,
+                            E0277,
+                            "the trait bound `{}` is not satisfied{}",
+                            trait_ref.to_predicate(),
+                            post_message);
+                        err.span_label(span,
+                                        &format!("{}the trait `{}` is not \
+                                                    implemented for `{}`",
+                                                pre_message,
+                                                trait_ref,
+                                                trait_ref.self_ty()));
+
+                        // Try to report a help message
+
+                        if !trait_ref.has_infer_types() &&
+                            self.predicate_can_apply(trait_ref) {
+                            // If a where-clause may be useful, remind the
+                            // user that they can add it.
+                            //
+                            // don't display an on-unimplemented note, as
+                            // these notes will often be of the form
+                            //     "the type `T` can't be frobnicated"
+                            // which is somewhat confusing.
+                            err.help(&format!("consider adding a `where {}` bound",
+                                                trait_ref.to_predicate()));
+                        } else if let Some(s) = self.on_unimplemented_note(trait_ref,
+                                                                            obligation) {
+                            // If it has a custom "#[rustc_on_unimplemented]"
+                            // error message, let's display it!
+                            err.note(&s);
+                        } else {
+                            // If we can't show anything useful, try to find
+                            // similar impls.
+                            let impl_candidates = self.find_similar_impl_candidates(trait_ref);
+                            self.report_similar_impl_candidates(impl_candidates, &mut err);
                         }
+                        err
+                    }
 
-                        ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
-                            let predicate =
-                                self.resolve_type_vars_if_possible(&obligation.predicate);
-                            struct_span_err!(self.tcx.sess, span, E0280,
-                                "the requirement `{}` is not satisfied",
-                                predicate)
-                        }
+                    ty::Predicate::Equate(ref predicate) => {
+                        let predicate = self.resolve_type_vars_if_possible(predicate);
+                        let err = self.equality_predicate(&obligation.cause,
+                                                            &predicate).err().unwrap();
+                        struct_span_err!(self.tcx.sess, span, E0278,
+                            "the requirement `{}` is not satisfied (`{}`)",
+                            predicate, err)
+                    }
 
-                        ty::Predicate::ObjectSafe(trait_def_id) => {
-                            let violations = self.tcx.object_safety_violations(trait_def_id);
-                            self.tcx.report_object_safety_error(span,
-                                                                trait_def_id,
-                                                                violations)
-                        }
+                    ty::Predicate::RegionOutlives(ref predicate) => {
+                        let predicate = self.resolve_type_vars_if_possible(predicate);
+                        let err = self.region_outlives_predicate(&obligation.cause,
+                                                                    &predicate).err().unwrap();
+                        struct_span_err!(self.tcx.sess, span, E0279,
+                            "the requirement `{}` is not satisfied (`{}`)",
+                            predicate, err)
+                    }
 
-                        ty::Predicate::ClosureKind(closure_def_id, kind) => {
-                            let found_kind = self.closure_kind(closure_def_id).unwrap();
-                            let closure_span = self.tcx.hir.span_if_local(closure_def_id).unwrap();
-                            let mut err = struct_span_err!(
-                                self.tcx.sess, closure_span, E0525,
-                                "expected a closure that implements the `{}` trait, \
-                                 but this closure only implements `{}`",
-                                kind,
-                                found_kind);
-                            err.span_note(
-                                obligation.cause.span,
-                                &format!("the requirement to implement \
-                                          `{}` derives from here", kind));
-                            err.emit();
-                            return;
-                        }
+                    ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
+                        let predicate =
+                            self.resolve_type_vars_if_possible(&obligation.predicate);
+                        struct_span_err!(self.tcx.sess, span, E0280,
+                            "the requirement `{}` is not satisfied",
+                            predicate)
+                    }
 
-                        ty::Predicate::WellFormed(ty) => {
-                            // WF predicates cannot themselves make
-                            // errors. They can only block due to
-                            // ambiguity; otherwise, they always
-                            // degenerate into other obligations
-                            // (which may fail).
-                            span_bug!(span, "WF predicate not satisfied for {:?}", ty);
-                        }
+                    ty::Predicate::ObjectSafe(trait_def_id) => {
+                        let violations = self.tcx.object_safety_violations(trait_def_id);
+                        self.tcx.report_object_safety_error(span,
+                                                            trait_def_id,
+                                                            violations)
+                    }
+
+                    ty::Predicate::ClosureKind(closure_def_id, kind) => {
+                        let found_kind = self.closure_kind(closure_def_id).unwrap();
+                        let closure_span = self.tcx.hir.span_if_local(closure_def_id).unwrap();
+                        let mut err = struct_span_err!(
+                            self.tcx.sess, closure_span, E0525,
+                            "expected a closure that implements the `{}` trait, \
+                                but this closure only implements `{}`",
+                            kind,
+                            found_kind);
+                        err.span_note(
+                            obligation.cause.span,
+                            &format!("the requirement to implement \
+                                        `{}` derives from here", kind));
+                        err.emit();
+                        return;
+                    }
+
+                    ty::Predicate::WellFormed(ty) => {
+                        // WF predicates cannot themselves make
+                        // errors. They can only block due to
+                        // ambiguity; otherwise, they always
+                        // degenerate into other obligations
+                        // (which may fail).
+                        span_bug!(span, "WF predicate not satisfied for {:?}", ty);
                     }
                 }
             }
@@ -713,38 +680,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             if !reported_violations.insert(violation.clone()) {
                 continue;
             }
-            let buf;
-            let note = match violation {
-                ObjectSafetyViolation::SizedSelf => {
-                    "the trait cannot require that `Self : Sized`"
-                }
-
-                ObjectSafetyViolation::SupertraitSelf => {
-                    "the trait cannot use `Self` as a type parameter \
-                         in the supertrait listing"
-                }
-
-                ObjectSafetyViolation::Method(name,
-                                              MethodViolationCode::StaticMethod) => {
-                    buf = format!("method `{}` has no receiver", name);
-                    &buf
-                }
-
-                ObjectSafetyViolation::Method(name,
-                                              MethodViolationCode::ReferencesSelf) => {
-                    buf = format!("method `{}` references the `Self` type \
-                                       in its arguments or return type",
-                                  name);
-                    &buf
-                }
-
-                ObjectSafetyViolation::Method(name,
-                                              MethodViolationCode::Generic) => {
-                    buf = format!("method `{}` has generic type parameters", name);
-                    &buf
-                }
-            };
-            err.note(note);
+            err.note(&violation.error_msg());
         }
         err
     }
@@ -774,46 +710,46 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 let trait_ref = data.to_poly_trait_ref();
                 let self_ty = trait_ref.self_ty();
                 if predicate.references_error() {
-                } else {
-                    // Typically, this ambiguity should only happen if
-                    // there are unresolved type inference variables
-                    // (otherwise it would suggest a coherence
-                    // failure). But given #21974 that is not necessarily
-                    // the case -- we can have multiple where clauses that
-                    // are only distinguished by a region, which results
-                    // in an ambiguity even when all types are fully
-                    // known, since we don't dispatch based on region
-                    // relationships.
-
-                    // This is kind of a hack: it frequently happens that some earlier
-                    // error prevents types from being fully inferred, and then we get
-                    // a bunch of uninteresting errors saying something like "<generic
-                    // #0> doesn't implement Sized".  It may even be true that we
-                    // could just skip over all checks where the self-ty is an
-                    // inference variable, but I was afraid that there might be an
-                    // inference variable created, registered as an obligation, and
-                    // then never forced by writeback, and hence by skipping here we'd
-                    // be ignoring the fact that we don't KNOW the type works
-                    // out. Though even that would probably be harmless, given that
-                    // we're only talking about builtin traits, which are known to be
-                    // inhabited. But in any case I just threw in this check for
-                    // has_errors() to be sure that compilation isn't happening
-                    // anyway. In that case, why inundate the user.
-                    if !self.tcx.sess.has_errors() {
-                        if
-                            self.tcx.lang_items.sized_trait()
-                            .map_or(false, |sized_id| sized_id == trait_ref.def_id())
-                        {
-                            self.need_type_info(obligation, self_ty);
-                        } else {
-                            let mut err = struct_span_err!(self.tcx.sess,
-                                                           obligation.cause.span, E0283,
-                                                           "type annotations required: \
-                                                            cannot resolve `{}`",
-                                                           predicate);
-                            self.note_obligation_cause(&mut err, obligation);
-                            err.emit();
-                        }
+                    return;
+                }
+                // Typically, this ambiguity should only happen if
+                // there are unresolved type inference variables
+                // (otherwise it would suggest a coherence
+                // failure). But given #21974 that is not necessarily
+                // the case -- we can have multiple where clauses that
+                // are only distinguished by a region, which results
+                // in an ambiguity even when all types are fully
+                // known, since we don't dispatch based on region
+                // relationships.
+
+                // This is kind of a hack: it frequently happens that some earlier
+                // error prevents types from being fully inferred, and then we get
+                // a bunch of uninteresting errors saying something like "<generic
+                // #0> doesn't implement Sized".  It may even be true that we
+                // could just skip over all checks where the self-ty is an
+                // inference variable, but I was afraid that there might be an
+                // inference variable created, registered as an obligation, and
+                // then never forced by writeback, and hence by skipping here we'd
+                // be ignoring the fact that we don't KNOW the type works
+                // out. Though even that would probably be harmless, given that
+                // we're only talking about builtin traits, which are known to be
+                // inhabited. But in any case I just threw in this check for
+                // has_errors() to be sure that compilation isn't happening
+                // anyway. In that case, why inundate the user.
+                if !self.tcx.sess.has_errors() {
+                    if
+                        self.tcx.lang_items.sized_trait()
+                        .map_or(false, |sized_id| sized_id == trait_ref.def_id())
+                    {
+                        self.need_type_info(obligation, self_ty);
+                    } else {
+                        let mut err = struct_span_err!(self.tcx.sess,
+                                                        obligation.cause.span, E0283,
+                                                        "type annotations required: \
+                                                        cannot resolve `{}`",
+                                                        predicate);
+                        self.note_obligation_cause(&mut err, obligation);
+                        err.emit();
                     }
                 }
             }
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 23c28037a3c..b87d1846437 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -11,11 +11,9 @@
 use dep_graph::DepGraph;
 use infer::{InferCtxt, InferOk};
 use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt, ToPredicate};
-use ty::subst::Subst;
 use rustc_data_structures::obligation_forest::{ObligationForest, Error};
 use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor};
 use std::marker::PhantomData;
-use std::mem;
 use syntax::ast;
 use util::nodemap::{FxHashSet, NodeMap};
 use hir::def_id::DefId;
@@ -23,9 +21,8 @@ use hir::def_id::DefId;
 use super::CodeAmbiguity;
 use super::CodeProjectionError;
 use super::CodeSelectionError;
-use super::{FulfillmentError, FulfillmentErrorCode, SelectionError};
-use super::{ObligationCause, BuiltinDerivedObligation};
-use super::{PredicateObligation, TraitObligation, Obligation};
+use super::{FulfillmentError, FulfillmentErrorCode};
+use super::{ObligationCause, PredicateObligation, Obligation};
 use super::project;
 use super::select::SelectionContext;
 use super::Unimplemented;
@@ -82,10 +79,6 @@ pub struct FulfillmentContext<'tcx> {
     // obligations (otherwise, it's easy to fail to walk to a
     // particular node-id).
     region_obligations: NodeMap<Vec<RegionObligation<'tcx>>>,
-
-    // A list of obligations that need to be deferred to
-    // a later time for them to be properly fulfilled.
-    deferred_obligations: Vec<DeferredObligation<'tcx>>,
 }
 
 #[derive(Clone)]
@@ -101,100 +94,12 @@ pub struct PendingPredicateObligation<'tcx> {
     pub stalled_on: Vec<Ty<'tcx>>,
 }
 
-/// An obligation which cannot be fulfilled in the context
-/// it was registered in, such as auto trait obligations on
-/// `impl Trait`, which require the concrete type to be
-/// available, only guaranteed after finishing type-checking.
-#[derive(Clone, Debug)]
-pub struct DeferredObligation<'tcx> {
-    pub predicate: ty::PolyTraitPredicate<'tcx>,
-    pub cause: ObligationCause<'tcx>
-}
-
-impl<'a, 'gcx, 'tcx> DeferredObligation<'tcx> {
-    /// If possible, create a `DeferredObligation` from
-    /// a trait predicate which had failed selection,
-    /// but could succeed later.
-    pub fn from_select_error(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                             obligation: &TraitObligation<'tcx>,
-                             selection_err: &SelectionError<'tcx>)
-                             -> Option<DeferredObligation<'tcx>> {
-        if let Unimplemented = *selection_err {
-            if DeferredObligation::must_defer(tcx, &obligation.predicate) {
-                return Some(DeferredObligation {
-                    predicate: obligation.predicate.clone(),
-                    cause: obligation.cause.clone()
-                });
-            }
-        }
-
-        None
-    }
-
-    /// Returns true if the given trait predicate can be
-    /// fulfilled at a later time.
-    pub fn must_defer(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                      predicate: &ty::PolyTraitPredicate<'tcx>)
-                      -> bool {
-        // Auto trait obligations on `impl Trait`.
-        if tcx.trait_has_default_impl(predicate.def_id()) {
-            let substs = predicate.skip_binder().trait_ref.substs;
-            if substs.types().count() == 1 && substs.regions().next().is_none() {
-                if let ty::TyAnon(..) = predicate.skip_binder().self_ty().sty {
-                    return true;
-                }
-            }
-        }
-
-        false
-    }
-
-    /// If possible, return the nested obligations required
-    /// to fulfill this obligation.
-    pub fn try_select(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
-                      -> Option<Vec<PredicateObligation<'tcx>>> {
-        if let ty::TyAnon(def_id, substs) = self.predicate.skip_binder().self_ty().sty {
-            let ty = if def_id.is_local() {
-                tcx.item_types.borrow().get(&def_id).cloned()
-            } else {
-                Some(tcx.item_type(def_id))
-            };
-            // We can resolve the `impl Trait` to its concrete type.
-            if let Some(concrete_ty) = ty.subst(tcx, substs) {
-                let predicate = ty::TraitRef {
-                    def_id: self.predicate.def_id(),
-                    substs: tcx.mk_substs_trait(concrete_ty, &[])
-                }.to_predicate();
-
-                let original_obligation = Obligation::new(self.cause.clone(),
-                                                          self.predicate.clone());
-                let cause = original_obligation.derived_cause(BuiltinDerivedObligation);
-                return Some(vec![Obligation::new(cause, predicate)]);
-            }
-        }
-
-        None
-    }
-
-    /// Return the `PredicateObligation` this was created from.
-    pub fn to_obligation(&self) -> PredicateObligation<'tcx> {
-        let predicate = ty::Predicate::Trait(self.predicate.clone());
-        Obligation::new(self.cause.clone(), predicate)
-    }
-
-    /// Return an error as if this obligation had failed.
-    pub fn to_error(&self) -> FulfillmentError<'tcx> {
-        FulfillmentError::new(self.to_obligation(), CodeSelectionError(Unimplemented))
-    }
-}
-
 impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
     /// Creates a new fulfillment context.
     pub fn new() -> FulfillmentContext<'tcx> {
         FulfillmentContext {
             predicates: ObligationForest::new(),
             region_obligations: NodeMap(),
-            deferred_obligations: vec![],
         }
     }
 
@@ -294,16 +199,10 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
     {
         self.select_where_possible(infcx)?;
 
-        // Fail all of the deferred obligations that haven't
-        // been otherwise removed from the context.
-        let deferred_errors = self.deferred_obligations.iter()
-                                  .map(|d| d.to_error());
-
         let errors: Vec<_> =
             self.predicates.to_errors(CodeAmbiguity)
                            .into_iter()
                            .map(|e| to_fulfillment_error(e))
-                           .chain(deferred_errors)
                            .collect();
         if errors.is_empty() {
             Ok(())
@@ -324,10 +223,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
         self.predicates.pending_obligations()
     }
 
-    pub fn take_deferred_obligations(&mut self) -> Vec<DeferredObligation<'tcx>> {
-        mem::replace(&mut self.deferred_obligations, vec![])
-    }
-
     /// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it
     /// only attempts to select obligations that haven't been seen before.
     fn select(&mut self, selcx: &mut SelectionContext<'a, 'gcx, 'tcx>)
@@ -343,7 +238,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
             let outcome = self.predicates.process_obligations(&mut FulfillProcessor {
                 selcx: selcx,
                 region_obligations: &mut self.region_obligations,
-                deferred_obligations: &mut self.deferred_obligations
             });
             debug!("select: outcome={:?}", outcome);
 
@@ -378,7 +272,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
 struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> {
     selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
     region_obligations: &'a mut NodeMap<Vec<RegionObligation<'tcx>>>,
-    deferred_obligations: &'a mut Vec<DeferredObligation<'tcx>>
 }
 
 impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, 'tcx> {
@@ -391,8 +284,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
     {
         process_predicate(self.selcx,
                           obligation,
-                          self.region_obligations,
-                          self.deferred_obligations)
+                          self.region_obligations)
             .map(|os| os.map(|os| os.into_iter().map(|o| PendingPredicateObligation {
                 obligation: o,
                 stalled_on: vec![]
@@ -432,8 +324,7 @@ fn trait_ref_type_vars<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 't
 fn process_predicate<'a, 'gcx, 'tcx>(
     selcx: &mut SelectionContext<'a, 'gcx, 'tcx>,
     pending_obligation: &mut PendingPredicateObligation<'tcx>,
-    region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>,
-    deferred_obligations: &mut Vec<DeferredObligation<'tcx>>)
+    region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
     -> Result<Option<Vec<PredicateObligation<'tcx>>>,
               FulfillmentErrorCode<'tcx>>
 {
@@ -502,21 +393,7 @@ fn process_predicate<'a, 'gcx, 'tcx>(
                     info!("selecting trait `{:?}` at depth {} yielded Err",
                           data, obligation.recursion_depth);
 
-                    let defer = DeferredObligation::from_select_error(selcx.tcx(),
-                                                                      &trait_obligation,
-                                                                      &selection_err);
-                    if let Some(deferred_obligation) = defer {
-                        if let Some(nested) = deferred_obligation.try_select(selcx.tcx()) {
-                            Ok(Some(nested))
-                        } else {
-                            // Pretend that the obligation succeeded,
-                            // but record it for later.
-                            deferred_obligations.push(deferred_obligation);
-                            Ok(Some(vec![]))
-                        }
-                    } else {
-                        Err(CodeSelectionError(selection_err))
-                    }
+                    Err(CodeSelectionError(selection_err))
                 }
             }
         }
@@ -714,12 +591,6 @@ impl<'a, 'gcx, 'tcx> GlobalFulfilledPredicates<'gcx> {
             // already has the required read edges, so we don't need
             // to add any more edges here.
             if data.is_global() {
-                // Don't cache predicates which were fulfilled
-                // by deferring them for later fulfillment.
-                if DeferredObligation::must_defer(tcx, data) {
-                    return;
-                }
-
                 if let Some(data) = tcx.lift_to_global(data) {
                     if self.set.insert(data.clone()) {
                         debug!("add_if_global: global predicate `{:?}` added", data);
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 58ab713ef27..7e7d06e4b81 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -31,7 +31,6 @@ pub use self::coherence::orphan_check;
 pub use self::coherence::overlapping_impls;
 pub use self::coherence::OrphanCheckErr;
 pub use self::fulfill::{FulfillmentContext, GlobalFulfilledPredicates, RegionObligation};
-pub use self::fulfill::DeferredObligation;
 pub use self::project::MismatchedProjectionTypes;
 pub use self::project::{normalize, normalize_projection_type, Normalized};
 pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal};
@@ -474,7 +473,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let elaborated_env = unnormalized_env.with_caller_bounds(predicates);
 
-    tcx.infer_ctxt(elaborated_env, Reveal::NotSpecializable).enter(|infcx| {
+    tcx.infer_ctxt(elaborated_env, Reveal::UserFacing).enter(|infcx| {
         let predicates = match fully_normalize(&infcx, cause,
                                                &infcx.parameter_environment.caller_bounds) {
             Ok(predicates) => predicates,
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index 60808fbc741..2ebe0d459fa 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc/traits/object_safety.rs
@@ -23,6 +23,7 @@ use hir::def_id::DefId;
 use traits;
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::subst::Substs;
+use std::borrow::Cow;
 use syntax::ast;
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -38,6 +39,25 @@ pub enum ObjectSafetyViolation {
     Method(ast::Name, MethodViolationCode),
 }
 
+impl ObjectSafetyViolation {
+    pub fn error_msg(&self) -> Cow<'static, str> {
+        match *self {
+            ObjectSafetyViolation::SizedSelf =>
+                "the trait cannot require that `Self : Sized`".into(),
+            ObjectSafetyViolation::SupertraitSelf =>
+                "the trait cannot use `Self` as a type parameter \
+                 in the supertrait listing".into(),
+            ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod) =>
+                format!("method `{}` has no receiver", name).into(),
+            ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelf) =>
+                format!("method `{}` references the `Self` type \
+                         in its arguments or return type", name).into(),
+            ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) =>
+                format!("method `{}` has generic type parameters", name).into(),
+        }
+    }
+}
+
 /// Reasons a method might not be object-safe.
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub enum MethodViolationCode {
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 6f645b5f94d..3d8f9e41c67 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -38,36 +38,6 @@ use util::common::FN_OUTPUT_NAME;
 /// more or less conservative.
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub enum Reveal {
-    /// FIXME (#32205)
-    /// At coherence-checking time, we're still constructing the
-    /// specialization graph, and thus we only project
-    /// non-`default` associated types that are defined directly in
-    /// the applicable impl. (This behavior should be improved over
-    /// time, to allow for successful projections modulo cycles
-    /// between different impls).
-    ///
-    /// Here's an example that will fail due to the restriction:
-    ///
-    /// ```
-    /// trait Assoc {
-    ///     type Output;
-    /// }
-    ///
-    /// impl<T> Assoc for T {
-    ///     type Output = bool;
-    /// }
-    ///
-    /// impl Assoc for u8 {} // <- inherits the non-default type from above
-    ///
-    /// trait Foo {}
-    /// impl Foo for u32 {}
-    /// impl Foo for <u8 as Assoc>::Output {}  // <- this projection will fail
-    /// ```
-    ///
-    /// The projection would succeed if `Output` had been defined
-    /// directly in the impl for `u8`.
-    ExactMatch,
-
     /// At type-checking time, we refuse to project any associated
     /// type that is marked `default`. Non-`default` ("final") types
     /// are always projected. This is necessary in general for
@@ -90,7 +60,7 @@ pub enum Reveal {
     /// fn main() {
     ///     let <() as Assoc>::Output = true;
     /// }
-    NotSpecializable,
+    UserFacing,
 
     /// At trans time, all monomorphic projections will succeed.
     /// Also, `impl Trait` is normalized to the concrete type,
@@ -1208,7 +1178,8 @@ fn confirm_closure_candidate<'cx, 'gcx, 'tcx>(
     -> Progress<'tcx>
 {
     let closure_typer = selcx.closure_typer();
-    let closure_type = closure_typer.closure_type(vtable.closure_def_id, vtable.substs);
+    let closure_type = closure_typer.closure_type(vtable.closure_def_id)
+        .subst(selcx.tcx(), vtable.substs.substs);
     let Normalized {
         value: closure_type,
         obligations
@@ -1224,7 +1195,7 @@ fn confirm_closure_candidate<'cx, 'gcx, 'tcx>(
 
     confirm_callable_candidate(selcx,
                                obligation,
-                               &closure_type.sig,
+                               closure_type,
                                util::TupleArgumentsFlag::No)
         .with_addl_obligations(vtable.nested)
         .with_addl_obligations(obligations)
@@ -1233,7 +1204,7 @@ fn confirm_closure_candidate<'cx, 'gcx, 'tcx>(
 fn confirm_callable_candidate<'cx, 'gcx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    fn_sig: &ty::PolyFnSig<'tcx>,
+    fn_sig: ty::PolyFnSig<'tcx>,
     flag: util::TupleArgumentsFlag)
     -> Progress<'tcx>
 {
@@ -1346,8 +1317,9 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>(
     -> Option<specialization_graph::NodeItem<ty::AssociatedItem>>
 {
     let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id;
+    let trait_def = selcx.tcx().lookup_trait_def(trait_def_id);
 
-    if selcx.projection_mode() == Reveal::ExactMatch {
+    if !trait_def.is_complete(selcx.tcx()) {
         let impl_node = specialization_graph::Node::Impl(impl_def_id);
         for item in impl_node.items(selcx.tcx()) {
             if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name {
@@ -1359,7 +1331,7 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>(
         }
         None
     } else {
-        selcx.tcx().lookup_trait_def(trait_def_id)
+        trait_def
             .ancestors(impl_def_id)
             .defs(selcx.tcx(), assoc_ty_name, ty::AssociatedKind::Type)
             .next()
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 40c62762c3c..4c4ace0d8ba 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -1405,16 +1405,18 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             }
 
             // provide an impl, but only for suitable `fn` pointers
-            ty::TyFnDef(.., &ty::BareFnTy {
+            ty::TyFnDef(.., ty::Binder(ty::FnSig {
                 unsafety: hir::Unsafety::Normal,
                 abi: Abi::Rust,
-                ref sig,
-            }) |
-            ty::TyFnPtr(&ty::BareFnTy {
+                variadic: false,
+                ..
+            })) |
+            ty::TyFnPtr(ty::Binder(ty::FnSig {
                 unsafety: hir::Unsafety::Normal,
                 abi: Abi::Rust,
-                ref sig
-            }) if !sig.variadic() => {
+                variadic: false,
+                ..
+            })) => {
                 candidates.vec.push(FnPointerCandidate);
             }
 
@@ -1476,8 +1478,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     // `assemble_candidates_from_object_ty`.
                 }
                 ty::TyParam(..) |
-                ty::TyProjection(..) |
-                ty::TyAnon(..) => {
+                ty::TyProjection(..) => {
                     // In these cases, we don't know what the actual
                     // type is.  Therefore, we cannot break it down
                     // into its constituent types. So we don't
@@ -1900,7 +1901,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             ty::TyDynamic(..) |
             ty::TyParam(..) |
             ty::TyProjection(..) |
-            ty::TyAnon(..) |
             ty::TyInfer(ty::TyVar(_)) |
             ty::TyInfer(ty::FreshTy(_)) |
             ty::TyInfer(ty::FreshIntTy(_)) |
@@ -1945,6 +1945,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     .map(|f| f.ty(self.tcx(), substs))
                     .collect()
             }
+
+            ty::TyAnon(def_id, substs) => {
+                // We can resolve the `impl Trait` to its concrete type,
+                // which enforces a DAG between the functions requiring
+                // the auto trait bounds in question.
+                vec![self.tcx().item_type(def_id).subst(self.tcx(), substs)]
+            }
         }
     }
 
@@ -2777,11 +2784,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                                       substs: ty::ClosureSubsts<'tcx>)
                                       -> ty::PolyTraitRef<'tcx>
     {
-        let closure_type = self.infcx.closure_type(closure_def_id, substs);
+        let closure_type = self.infcx.closure_type(closure_def_id)
+            .subst(self.tcx(), substs.substs);
         let ty::Binder((trait_ref, _)) =
             self.tcx().closure_trait_ref_and_return_type(obligation.predicate.def_id(),
                                                          obligation.predicate.0.self_ty(), // (1)
-                                                         &closure_type.sig,
+                                                         closure_type,
                                                          util::TupleArgumentsFlag::No);
         // (1) Feels icky to skip the binder here, but OTOH we know
         // that the self-type is an unboxed closure type and hence is
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 0fe054b30ba..79df7de04f5 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -189,7 +189,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              .subst(tcx, &penv.free_substs);
 
     // Create a infcx, taking the predicates of impl1 as assumptions:
-    let result = tcx.infer_ctxt(penv, Reveal::ExactMatch).enter(|infcx| {
+    let result = tcx.infer_ctxt(penv, Reveal::UserFacing).enter(|infcx| {
         // Normalize the trait reference. The WF rules ought to ensure
         // that this always succeeds.
         let impl1_trait_ref =
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs
index 368b1fb4bcb..40eb6939567 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc/traits/specialize/specialization_graph.rs
@@ -108,7 +108,7 @@ impl<'a, 'gcx, 'tcx> Children {
             let possible_sibling = *slot;
 
             let tcx = tcx.global_tcx();
-            let (le, ge) = tcx.infer_ctxt((), Reveal::ExactMatch).enter(|infcx| {
+            let (le, ge) = tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
                 let overlap = traits::overlapping_impls(&infcx,
                                                         possible_sibling,
                                                         impl_def_id);
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index dedb126d7ff..717c171db2a 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -269,20 +269,6 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> {
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for traits::DeferredObligation<'a> {
-    type Lifted = traits::DeferredObligation<'tcx>;
-    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.predicate).and_then(|predicate| {
-            tcx.lift(&self.cause).map(|cause| {
-                traits::DeferredObligation {
-                    predicate: predicate,
-                    cause: cause
-                }
-            })
-        })
-    }
-}
-
 // For trans only.
 impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
     type Lifted = traits::Vtable<'tcx, ()>;
@@ -589,16 +575,3 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCause<'tcx> {
         self.code.visit_with(visitor)
     }
 }
-
-impl<'tcx> TypeFoldable<'tcx> for traits::DeferredObligation<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        traits::DeferredObligation {
-            predicate: self.predicate.fold_with(folder),
-            cause: self.cause.fold_with(folder)
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.predicate.visit_with(visitor) || self.cause.visit_with(visitor)
-    }
-}
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index 7b2882bb64f..602f27a64d4 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -482,7 +482,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn closure_trait_ref_and_return_type(self,
         fn_trait_def_id: DefId,
         self_ty: Ty<'tcx>,
-        sig: &ty::PolyFnSig<'tcx>,
+        sig: ty::PolyFnSig<'tcx>,
         tuple_arguments: TupleArgumentsFlag)
         -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)>
     {
diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs
index 333a5c74cb4..34977822bc6 100644
--- a/src/librustc/ty/adjustment.rs
+++ b/src/librustc/ty/adjustment.rs
@@ -33,6 +33,9 @@ pub enum Adjust<'tcx> {
     /// Go from a safe fn pointer to an unsafe fn pointer.
     UnsafeFnPointer,
 
+    // Go from a non-capturing closure to an fn pointer.
+    ClosureFnPointer,
+
     /// Go from a mut raw pointer to a const raw pointer.
     MutToConstPointer,
 
@@ -120,6 +123,7 @@ impl<'tcx> Adjustment<'tcx> {
 
             Adjust::ReifyFnPointer |
             Adjust::UnsafeFnPointer |
+            Adjust::ClosureFnPointer |
             Adjust::MutToConstPointer |
             Adjust::DerefRef {..} => false,
         }
diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs
index 56621c57eb8..e1429598291 100644
--- a/src/librustc/ty/contents.rs
+++ b/src/librustc/ty/contents.rs
@@ -219,7 +219,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
                         res = res - TC::OwnsDtor;
                     }
 
-                    if def.has_dtor() {
+                    if def.has_dtor(tcx) {
                         res = res | TC::OwnsDtor;
                     }
 
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 19bb8a63aa2..6961e0da362 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -10,7 +10,7 @@
 
 //! type context book-keeping
 
-use dep_graph::{DepGraph, DepTrackingMap};
+use dep_graph::DepGraph;
 use session::Session;
 use lint;
 use middle;
@@ -32,26 +32,26 @@ use ty::{self, TraitRef, Ty, TypeAndMut};
 use ty::{TyS, TypeVariants, Slice};
 use ty::{AdtKind, AdtDef, ClosureSubsts, Region};
 use hir::FreevarMap;
-use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
+use ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
 use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
 use ty::TypeVariants::*;
 use ty::layout::{Layout, TargetDataLayout};
 use ty::inhabitedness::DefIdForest;
 use ty::maps;
-use util::common::MemoizationMap;
 use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
 use util::nodemap::{FxHashMap, FxHashSet};
 use rustc_data_structures::accumulate_vec::AccumulateVec;
 
 use arena::{TypedArena, DroplessArena};
+use rustc_data_structures::indexed_vec::IndexVec;
 use std::borrow::Borrow;
 use std::cell::{Cell, RefCell};
 use std::hash::{Hash, Hasher};
 use std::mem;
 use std::ops::Deref;
-use std::rc::Rc;
 use std::iter;
 use std::cmp::Ordering;
+use syntax::abi;
 use syntax::ast::{self, Name, NodeId};
 use syntax::attr;
 use syntax::symbol::{Symbol, keywords};
@@ -64,7 +64,7 @@ pub struct GlobalArenas<'tcx> {
     layout: TypedArena<Layout>,
 
     // references
-    generics: TypedArena<ty::Generics<'tcx>>,
+    generics: TypedArena<ty::Generics>,
     trait_def: TypedArena<ty::TraitDef>,
     adt_def: TypedArena<ty::AdtDef>,
     mir: TypedArena<RefCell<Mir<'tcx>>>,
@@ -93,7 +93,6 @@ pub struct CtxtInterners<'tcx> {
     type_: RefCell<FxHashSet<Interned<'tcx, TyS<'tcx>>>>,
     type_list: RefCell<FxHashSet<Interned<'tcx, Slice<Ty<'tcx>>>>>,
     substs: RefCell<FxHashSet<Interned<'tcx, Substs<'tcx>>>>,
-    bare_fn: RefCell<FxHashSet<Interned<'tcx, BareFnTy<'tcx>>>>,
     region: RefCell<FxHashSet<Interned<'tcx, Region>>>,
     existential_predicates: RefCell<FxHashSet<Interned<'tcx, Slice<ExistentialPredicate<'tcx>>>>>,
 }
@@ -105,7 +104,6 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
             type_: RefCell::new(FxHashSet()),
             type_list: RefCell::new(FxHashSet()),
             substs: RefCell::new(FxHashSet()),
-            bare_fn: RefCell::new(FxHashSet()),
             region: RefCell::new(FxHashSet()),
             existential_predicates: RefCell::new(FxHashSet()),
         }
@@ -218,9 +216,9 @@ pub struct TypeckTables<'tcx> {
     pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
 
     /// Records the type of each closure.
-    pub closure_tys: NodeMap<ty::ClosureTy<'tcx>>,
+    pub closure_tys: NodeMap<ty::PolyFnSig<'tcx>>,
 
-    /// Records the type of each closure.
+    /// Records the kind of each closure.
     pub closure_kinds: NodeMap<ty::ClosureKind>,
 
     /// For each fn, records the "liberated" types of its arguments
@@ -242,6 +240,14 @@ pub struct TypeckTables<'tcx> {
 
     /// Lints for the body of this fn generated by typeck.
     pub lints: lint::LintTable,
+
+    /// Set of trait imports actually used in the method resolution.
+    /// This is used for warning unused imports.
+    pub used_trait_imports: DefIdSet,
+
+    /// If any errors occurred while type-checking this body,
+    /// this field will be set to `true`.
+    pub tainted_by_errors: bool,
 }
 
 impl<'tcx> TypeckTables<'tcx> {
@@ -259,6 +265,8 @@ impl<'tcx> TypeckTables<'tcx> {
             fru_field_types: NodeMap(),
             cast_kinds: NodeMap(),
             lints: lint::LintTable::new(),
+            used_trait_imports: DefIdSet(),
+            tainted_by_errors: false,
         }
     }
 
@@ -389,6 +397,8 @@ pub struct GlobalCtxt<'tcx> {
     global_arenas: &'tcx GlobalArenas<'tcx>,
     global_interners: CtxtInterners<'tcx>,
 
+    pub sess: &'tcx Session,
+
     pub specializes_cache: RefCell<traits::SpecializesCache>,
 
     pub dep_graph: DepGraph,
@@ -396,8 +406,6 @@ pub struct GlobalCtxt<'tcx> {
     /// Common types, pre-interned for your convenience.
     pub types: CommonTypes<'tcx>,
 
-    pub sess: &'tcx Session,
-
     /// Map indicating what traits are in scope for places where this
     /// is relevant; generated by resolve.
     pub trait_map: TraitMap,
@@ -412,44 +420,9 @@ pub struct GlobalCtxt<'tcx> {
     // borrowck. (They are not used during trans, and hence are not
     // serialized or needed for cross-crate fns.)
     free_region_maps: RefCell<NodeMap<FreeRegionMap>>,
-    // FIXME: jroesch make this a refcell
-
-    pub tables: RefCell<DepTrackingMap<maps::TypeckTables<'tcx>>>,
-
-    /// Maps from a trait item to the trait item "descriptor"
-    pub associated_items: RefCell<DepTrackingMap<maps::AssociatedItems<'tcx>>>,
-
-    /// Maps from an impl/trait def-id to a list of the def-ids of its items
-    pub associated_item_def_ids: RefCell<DepTrackingMap<maps::AssociatedItemDefIds<'tcx>>>,
-
-    pub impl_trait_refs: RefCell<DepTrackingMap<maps::ImplTraitRefs<'tcx>>>,
-    pub trait_defs: RefCell<DepTrackingMap<maps::TraitDefs<'tcx>>>,
-    pub adt_defs: RefCell<DepTrackingMap<maps::AdtDefs<'tcx>>>,
-    pub adt_sized_constraint: RefCell<DepTrackingMap<maps::AdtSizedConstraint<'tcx>>>,
-
-    /// Maps from the def-id of an item (trait/struct/enum/fn) to its
-    /// associated generics and predicates.
-    pub generics: RefCell<DepTrackingMap<maps::Generics<'tcx>>>,
-    pub predicates: RefCell<DepTrackingMap<maps::Predicates<'tcx>>>,
-
-    /// Maps from the def-id of a trait to the list of
-    /// super-predicates. This is a subset of the full list of
-    /// predicates. We store these in a separate map because we must
-    /// evaluate them even during type conversion, often before the
-    /// full predicates are available (note that supertraits have
-    /// additional acyclicity requirements).
-    pub super_predicates: RefCell<DepTrackingMap<maps::Predicates<'tcx>>>,
 
     pub hir: hir_map::Map<'tcx>,
-
-    /// Maps from the def-id of a function/method or const/static
-    /// to its MIR. Mutation is done at an item granularity to
-    /// allow MIR optimization passes to function and still
-    /// access cross-crate MIR (e.g. inlining or const eval).
-    ///
-    /// Note that cross-crate MIR appears to be always borrowed
-    /// (in the `RefCell` sense) to prevent accidental mutation.
-    pub mir_map: RefCell<DepTrackingMap<maps::Mir<'tcx>>>,
+    pub maps: maps::Maps<'tcx>,
 
     // Records the free variables refrenced by every closure
     // expression. Do not track deps for this, just recompute it from
@@ -458,18 +431,12 @@ pub struct GlobalCtxt<'tcx> {
 
     pub maybe_unused_trait_imports: NodeSet,
 
-    // Records the type of every item.
-    pub item_types: RefCell<DepTrackingMap<maps::Types<'tcx>>>,
-
     // Internal cache for metadata decoding. No need to track deps on this.
     pub rcache: RefCell<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
 
     // Cache for the type-contents routine. FIXME -- track deps?
     pub tc_cache: RefCell<FxHashMap<Ty<'tcx>, ty::contents::TypeContents>>,
 
-    // FIXME no dep tracking, but we should be able to remove this
-    pub ty_param_defs: RefCell<NodeMap<ty::TypeParameterDef<'tcx>>>,
-
     // FIXME dep tracking -- should be harmless enough
     pub normalized_cache: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
 
@@ -477,18 +444,9 @@ pub struct GlobalCtxt<'tcx> {
 
     pub lang_items: middle::lang_items::LanguageItems,
 
-    /// Maps from def-id of a type or region parameter to its
-    /// (inferred) variance.
-    pub item_variance_map: RefCell<DepTrackingMap<maps::ItemVariances<'tcx>>>,
-
     /// True if the variance has been computed yet; false otherwise.
     pub variance_computed: Cell<bool>,
 
-    /// Maps a DefId of a type to a list of its inherent impls.
-    /// Contains implementations of methods that are inherent to a type.
-    /// Methods in these implementations don't need to be exported.
-    pub inherent_impls: RefCell<DepTrackingMap<maps::InherentImpls<'tcx>>>,
-
     /// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
     /// present in this set can be warned about.
     pub used_unsafe: RefCell<NodeSet>,
@@ -498,10 +456,6 @@ pub struct GlobalCtxt<'tcx> {
     /// about.
     pub used_mut_nodes: RefCell<NodeSet>,
 
-    /// Set of trait imports actually used in the method resolution.
-    /// This is used for warning unused imports.
-    pub used_trait_imports: RefCell<DepTrackingMap<maps::UsedTraitImports<'tcx>>>,
-
     /// The set of external nominal types whose implementations have been read.
     /// This is used for lazy resolution of methods.
     pub populated_external_types: RefCell<DefIdSet>,
@@ -528,23 +482,9 @@ pub struct GlobalCtxt<'tcx> {
     /// (i.e., no type or lifetime parameters).
     pub fulfilled_predicates: RefCell<traits::GlobalFulfilledPredicates<'tcx>>,
 
-    /// Caches the representation hints for struct definitions.
-    repr_hint_cache: RefCell<DepTrackingMap<maps::ReprHints<'tcx>>>,
-
     /// Maps Expr NodeId's to `true` iff `&expr` can have 'static lifetime.
     pub rvalue_promotable_to_static: RefCell<NodeMap<bool>>,
 
-    /// Caches CoerceUnsized kinds for impls on custom types.
-    pub custom_coerce_unsized_kinds: RefCell<DefIdMap<ty::adjustment::CustomCoerceUnsized>>,
-
-    /// Records the type of each closure. The def ID is the ID of the
-    /// expression defining the closure.
-    pub closure_tys: RefCell<DepTrackingMap<maps::ClosureTypes<'tcx>>>,
-
-    /// Records the type of each closure. The def ID is the ID of the
-    /// expression defining the closure.
-    pub closure_kinds: RefCell<DepTrackingMap<maps::ClosureKinds<'tcx>>>,
-
     /// Maps Fn items to a collection of fragment infos.
     ///
     /// The main goal is to identify data (each of which may be moved
@@ -592,6 +532,15 @@ pub struct GlobalCtxt<'tcx> {
     stability_interner: RefCell<FxHashSet<&'tcx attr::Stability>>,
 
     layout_interner: RefCell<FxHashSet<&'tcx Layout>>,
+
+    /// A vector of every trait accessible in the whole crate
+    /// (i.e. including those from subcrates). This is used only for
+    /// error reporting, and so is lazily initialised and generally
+    /// shouldn't taint the common path (hence the RefCell).
+    pub all_traits: RefCell<Option<Vec<DefId>>>,
+
+    /// HIR Ty -> Ty lowering cache.
+    pub ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
 }
 
 impl<'tcx> GlobalCtxt<'tcx> {
@@ -646,15 +595,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn type_parameter_def(self,
-                              node_id: NodeId)
-                              -> ty::TypeParameterDef<'tcx>
-    {
-        self.ty_param_defs.borrow().get(&node_id).unwrap().clone()
-    }
-
-    pub fn alloc_generics(self, generics: ty::Generics<'gcx>)
-                          -> &'gcx ty::Generics<'gcx> {
+    pub fn alloc_generics(self, generics: ty::Generics) -> &'gcx ty::Generics {
         self.global_arenas.generics.alloc(generics)
     }
 
@@ -673,12 +614,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn alloc_adt_def(self,
                          did: DefId,
                          kind: AdtKind,
-                         discr_ty: Option<attr::IntType>,
                          variants: Vec<ty::VariantDef>,
                          repr: ReprOptions)
                          -> &'gcx ty::AdtDef {
-        let discr_ty = discr_ty.unwrap_or(attr::UnsignedInt(ast::UintTy::U8));
-        let def = ty::AdtDef::new(self, did, kind, discr_ty, variants, repr);
+        let def = ty::AdtDef::new(self, did, kind, variants, repr);
         self.global_arenas.adt_def.alloc(def)
     }
 
@@ -737,6 +676,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// value (types, substs, etc.) can only be used while `ty::tls` has a valid
     /// reference to the context, to allow formatting values that need it.
     pub fn create_and_enter<F, R>(s: &'tcx Session,
+                                  local_providers: ty::maps::Providers<'tcx>,
+                                  extern_providers: ty::maps::Providers<'tcx>,
                                   arenas: &'tcx GlobalArenas<'tcx>,
                                   arena: &'tcx DroplessArena,
                                   resolutions: ty::Resolutions,
@@ -754,7 +695,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         let common_types = CommonTypes::new(&interners);
         let dep_graph = hir.dep_graph.clone();
         let fulfilled_predicates = traits::GlobalFulfilledPredicates::new(dep_graph.clone());
+        let max_cnum = s.cstore.crates().iter().map(|c| c.as_usize()).max().unwrap_or(0);
+        let mut providers = IndexVec::from_elem_n(extern_providers, max_cnum + 1);
+        providers[LOCAL_CRATE] = local_providers;
         tls::enter_global(GlobalCtxt {
+            sess: s,
             specializes_cache: RefCell::new(traits::SpecializesCache::new()),
             global_arenas: arenas,
             global_interners: interners,
@@ -763,46 +708,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             named_region_map: named_region_map,
             region_maps: region_maps,
             free_region_maps: RefCell::new(FxHashMap()),
-            item_variance_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             variance_computed: Cell::new(false),
-            sess: s,
             trait_map: resolutions.trait_map,
-            tables: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            impl_trait_refs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            trait_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            adt_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            adt_sized_constraint: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            generics: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            super_predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             fulfilled_predicates: RefCell::new(fulfilled_predicates),
             hir: hir,
-            mir_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
+            maps: maps::Maps::new(dep_graph, providers),
             freevars: RefCell::new(resolutions.freevars),
             maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports,
-            item_types: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             rcache: RefCell::new(FxHashMap()),
             tc_cache: RefCell::new(FxHashMap()),
-            associated_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            associated_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            ty_param_defs: RefCell::new(NodeMap()),
             normalized_cache: RefCell::new(FxHashMap()),
             inhabitedness_cache: RefCell::new(FxHashMap()),
             lang_items: lang_items,
-            inherent_impls: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             used_unsafe: RefCell::new(NodeSet()),
             used_mut_nodes: RefCell::new(NodeSet()),
-            used_trait_imports: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             populated_external_types: RefCell::new(DefIdSet()),
             populated_external_primitive_impls: RefCell::new(DefIdSet()),
             stability: RefCell::new(stability),
             selection_cache: traits::SelectionCache::new(),
             evaluation_cache: traits::EvaluationCache::new(),
-            repr_hint_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             rvalue_promotable_to_static: RefCell::new(NodeMap()),
-            custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
-            closure_tys: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            closure_kinds: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             fragment_infos: RefCell::new(DefIdMap()),
             crate_name: Symbol::intern(crate_name),
             data_layout: data_layout,
@@ -811,6 +736,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             layout_depth: Cell::new(0),
             derive_macros: RefCell::new(NodeMap()),
             stability_interner: RefCell::new(FxHashSet()),
+            all_traits: RefCell::new(None),
+            ast_ty_to_ty_cache: RefCell::new(NodeMap()),
        }, f)
     }
 }
@@ -933,23 +860,6 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Slice<ExistentialPredicate<'a>> {
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for &'a BareFnTy<'a> {
-    type Lifted = &'tcx BareFnTy<'tcx>;
-    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
-                             -> Option<&'tcx BareFnTy<'tcx>> {
-        if tcx.interners.arena.in_arena(*self as *const _) {
-            return Some(unsafe { mem::transmute(*self) });
-        }
-        // Also try in the global tcx if we're not that.
-        if !tcx.is_global() {
-            self.lift_to_tcx(tcx.global_tcx())
-        } else {
-            None
-        }
-    }
-}
-
-
 pub mod tls {
     use super::{CtxtInterners, GlobalCtxt, TyCtxt};
 
@@ -1102,7 +1012,6 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
             TyDynamic, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon);
 
         println!("Substs interner: #{}", self.interners.substs.borrow().len());
-        println!("BareFnTy interner: #{}", self.interners.bare_fn.borrow().len());
         println!("Region interner: #{}", self.interners.region.borrow().len());
         println!("Stability interner: #{}", self.stability_interner.borrow().len());
         println!("Layout interner: #{}", self.layout_interner.borrow().len());
@@ -1161,12 +1070,6 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[Kind<'lcx>]> for Interned<'tcx, Substs<'tcx>> {
     }
 }
 
-impl<'tcx: 'lcx, 'lcx> Borrow<BareFnTy<'lcx>> for Interned<'tcx, BareFnTy<'tcx>> {
-    fn borrow<'a>(&'a self) -> &'a BareFnTy<'lcx> {
-        self.0
-    }
-}
-
 impl<'tcx> Borrow<Region> for Interned<'tcx, Region> {
     fn borrow<'a>(&'a self) -> &'a Region {
         self.0
@@ -1255,9 +1158,6 @@ fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool {
 }
 
 direct_interners!('tcx,
-    bare_fn: mk_bare_fn(|fty: &BareFnTy| {
-        keep_local(&fty.sig)
-    }) -> BareFnTy<'tcx>,
     region: mk_region(|r| {
         match r {
             &ty::ReVar(_) | &ty::ReSkolemized(..) => true,
@@ -1283,12 +1183,11 @@ slice_interners!(
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Create an unsafe fn ty based on a safe fn ty.
-    pub fn safe_to_unsafe_fn_ty(self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> {
-        assert_eq!(bare_fn.unsafety, hir::Unsafety::Normal);
-        self.mk_fn_ptr(self.mk_bare_fn(ty::BareFnTy {
+    pub fn safe_to_unsafe_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
+        assert_eq!(sig.unsafety(), hir::Unsafety::Normal);
+        self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig {
             unsafety: hir::Unsafety::Unsafe,
-            abi: bare_fn.abi,
-            sig: bare_fn.sig.clone()
+            ..sig
         }))
     }
 
@@ -1415,11 +1314,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     pub fn mk_fn_def(self, def_id: DefId,
                      substs: &'tcx Substs<'tcx>,
-                     fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> {
+                     fty: PolyFnSig<'tcx>) -> Ty<'tcx> {
         self.mk_ty(TyFnDef(def_id, substs, fty))
     }
 
-    pub fn mk_fn_ptr(self, fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> {
+    pub fn mk_fn_ptr(self, fty: PolyFnSig<'tcx>) -> Ty<'tcx> {
         self.mk_ty(TyFnPtr(fty))
     }
 
@@ -1513,14 +1412,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn mk_fn_sig<I>(self, inputs: I, output: I::Item, variadic: bool)
+    pub fn mk_fn_sig<I>(self,
+                        inputs: I,
+                        output: I::Item,
+                        variadic: bool,
+                        unsafety: hir::Unsafety,
+                        abi: abi::Abi)
         -> <I::Item as InternIteratorElement<Ty<'tcx>, ty::FnSig<'tcx>>>::Output
         where I: Iterator,
               I::Item: InternIteratorElement<Ty<'tcx>, ty::FnSig<'tcx>>
     {
         inputs.chain(iter::once(output)).intern_with(|xs| ty::FnSig {
             inputs_and_output: self.intern_type_list(xs),
-            variadic: variadic
+            variadic, unsafety, abi
         })
     }
 
@@ -1547,15 +1451,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     {
         self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from))
     }
-
-    /// Obtain the representation annotation for a struct definition.
-    pub fn lookup_repr_hints(self, did: DefId) -> Rc<Vec<attr::ReprAttr>> {
-        self.repr_hint_cache.memoize(did, || {
-            Rc::new(self.get_attrs(did).iter().flat_map(|meta| {
-                attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter()
-            }).collect())
-        })
-    }
 }
 
 pub trait InternAs<T: ?Sized, R> {
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index 3ab3fc899e7..44a3aabc056 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -10,7 +10,7 @@
 
 use hir::def_id::DefId;
 use infer::type_variable;
-use ty::{self, BoundRegion, Region, Ty, TyCtxt};
+use ty::{self, BoundRegion, DefIdTree, Region, Ty, TyCtxt};
 
 use std::fmt;
 use syntax::abi;
@@ -287,8 +287,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                         db.span_note(span, "a default was defined here...");
                     }
                     None => {
+                        let item_def_id = self.parent(expected.def_id).unwrap();
                         db.note(&format!("a default is defined on `{}`",
-                                         self.item_path_str(expected.def_id)));
+                                         self.item_path_str(item_def_id)));
                     }
                 }
 
@@ -301,8 +302,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                         db.span_note(span, "a second default was defined here...");
                     }
                     None => {
+                        let item_def_id = self.parent(found.def_id).unwrap();
                         db.note(&format!("a second default is defined on `{}`",
-                                         self.item_path_str(found.def_id)));
+                                         self.item_path_str(item_def_id)));
                     }
                 }
 
diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs
index 981cf0897a0..3d2cc4c598a 100644
--- a/src/librustc/ty/fast_reject.rs
+++ b/src/librustc/ty/fast_reject.rs
@@ -76,7 +76,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
             Some(TupleSimplifiedType(tys.len()))
         }
         ty::TyFnDef(.., ref f) | ty::TyFnPtr(ref f) => {
-            Some(FunctionSimplifiedType(f.sig.skip_binder().inputs().len()))
+            Some(FunctionSimplifiedType(f.skip_binder().inputs().len()))
         }
         ty::TyProjection(_) | ty::TyParam(_) => {
             if can_simplify_params {
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index 2012917f93a..384f99ceb4e 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -155,13 +155,13 @@ impl FlagComputation {
                 self.add_tys(&ts[..]);
             }
 
-            &ty::TyFnDef(_, substs, ref f) => {
+            &ty::TyFnDef(_, substs, f) => {
                 self.add_substs(substs);
-                self.add_fn_sig(&f.sig);
+                self.add_fn_sig(f);
             }
 
-            &ty::TyFnPtr(ref f) => {
-                self.add_fn_sig(&f.sig);
+            &ty::TyFnPtr(f) => {
+                self.add_fn_sig(f);
             }
         }
     }
@@ -177,7 +177,7 @@ impl FlagComputation {
         }
     }
 
-    fn add_fn_sig(&mut self, fn_sig: &ty::PolyFnSig) {
+    fn add_fn_sig(&mut self, fn_sig: ty::PolyFnSig) {
         let mut computation = FlagComputation::new();
 
         computation.add_tys(fn_sig.skip_binder().inputs());
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index 10754825a8c..e29653c9e88 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -159,19 +159,6 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized {
         sig.super_fold_with(self)
     }
 
-    fn fold_bare_fn_ty(&mut self,
-                       fty: &'tcx ty::BareFnTy<'tcx>)
-                       -> &'tcx ty::BareFnTy<'tcx>
-    {
-        fty.super_fold_with(self)
-    }
-
-    fn fold_closure_ty(&mut self,
-                       fty: &ty::ClosureTy<'tcx>)
-                       -> ty::ClosureTy<'tcx> {
-        fty.super_fold_with(self)
-    }
-
     fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
         r.super_fold_with(self)
     }
diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs
index 24ca476e5ff..77c863a0123 100644
--- a/src/librustc/ty/inhabitedness/mod.rs
+++ b/src/librustc/ty/inhabitedness/mod.rs
@@ -187,7 +187,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
                         //      which contains a Foo<((T, T), (T, T))>
                         //      which contains a Foo<(((T, T), (T, T)), ((T, T), (T, T)))>
                         //      etc.
-                        let error = format!("reached recursion limit while checking
+                        let error = format!("reached recursion limit while checking \
                                              inhabitedness of `{}`", self);
                         tcx.sess.fatal(&error);
                     }
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index f45f00b4dec..7bf1ba155b5 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -201,7 +201,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         } else {
             // for local crates, check whether type info is
             // available; typeck might not have completed yet
-            self.impl_trait_refs.borrow().contains_key(&impl_def_id)
+            self.maps.impl_trait_ref.borrow().contains_key(&impl_def_id)
         };
 
         if !use_types {
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index f429053d8bb..e7895ca7990 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -1146,7 +1146,7 @@ impl<'a, 'gcx, 'tcx> Layout {
             }
 
             // SIMD vector types.
-            ty::TyAdt(def, ..) if def.is_simd() => {
+            ty::TyAdt(def, ..) if def.repr.simd => {
                 let element = ty.simd_type(tcx);
                 match *element.layout(infcx)? {
                     Scalar { value, .. } => {
@@ -1181,8 +1181,8 @@ impl<'a, 'gcx, 'tcx> Layout {
                     let (mut min, mut max, mut non_zero) = (i64::max_value(),
                                                             i64::min_value(),
                                                             true);
-                    for v in &def.variants {
-                        let x = v.disr_val as i128 as i64;
+                    for discr in def.discriminants(tcx) {
+                        let x = discr.to_u128_unchecked() as i64;
                         if x == 0 { non_zero = false; }
                         if x < min { min = x; }
                         if x > max { max = x; }
@@ -1222,9 +1222,8 @@ impl<'a, 'gcx, 'tcx> Layout {
                     let fields = def.variants[0].fields.iter().map(|field| {
                         field.ty(tcx, substs).layout(infcx)
                     }).collect::<Result<Vec<_>, _>>()?;
-                    let packed = tcx.lookup_packed(def.did);
                     let layout = if def.is_union() {
-                        let mut un = Union::new(dl, packed);
+                        let mut un = Union::new(dl, def.repr.packed);
                         un.extend(dl, fields.iter().map(|&f| Ok(f)), ty)?;
                         UntaggedUnion { variants: un }
                     } else {
@@ -1240,7 +1239,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                 // non-empty body, explicit discriminants should have
                 // been rejected by a checker before this point.
                 for (i, v) in def.variants.iter().enumerate() {
-                    if i as u128 != v.disr_val {
+                    if v.discr != ty::VariantDiscr::Relative(i) {
                         bug!("non-C-like enum {} with specified discriminants",
                             tcx.item_path_str(def.did));
                     }
@@ -1348,7 +1347,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                     return Err(LayoutError::SizeOverflow(ty));
                 }
 
-                let typeck_ity = Integer::from_attr(dl, def.discr_ty);
+                let typeck_ity = Integer::from_attr(dl, def.repr.discr_type());
                 if typeck_ity < min_ity {
                     // It is a bug if Layout decided on a greater discriminant size than typeck for
                     // some reason at this point (based on values discriminant can take on). Mostly
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index d7341d148b7..fd1403b15bc 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -8,46 +8,391 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use dep_graph::{DepNode, DepTrackingMapConfig};
-use hir::def_id::DefId;
+use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig};
+use hir::def_id::{CrateNum, DefId};
+use middle::const_val::ConstVal;
 use mir;
-use ty::{self, Ty};
-use util::nodemap::DefIdSet;
+use ty::{self, Ty, TyCtxt};
 
-use std::cell::RefCell;
-use std::marker::PhantomData;
+use rustc_data_structures::indexed_vec::IndexVec;
+use std::cell::{RefCell, RefMut};
 use std::rc::Rc;
-use syntax::attr;
-
-macro_rules! dep_map_ty {
-    ($ty_name:ident : $node_name:ident ($key:ty) -> $value:ty) => {
-        pub struct $ty_name<'tcx> {
-            data: PhantomData<&'tcx ()>
-        }
-
-        impl<'tcx> DepTrackingMapConfig for $ty_name<'tcx> {
-            type Key = $key;
-            type Value = $value;
-            fn to_dep_node(key: &$key) -> DepNode<DefId> { DepNode::$node_name(*key) }
-        }
-    }
-}
-
-dep_map_ty! { AssociatedItems: AssociatedItems(DefId) -> ty::AssociatedItem }
-dep_map_ty! { Types: ItemSignature(DefId) -> Ty<'tcx> }
-dep_map_ty! { Generics: ItemSignature(DefId) -> &'tcx ty::Generics<'tcx> }
-dep_map_ty! { Predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> }
-dep_map_ty! { SuperPredicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> }
-dep_map_ty! { AssociatedItemDefIds: AssociatedItemDefIds(DefId) -> Rc<Vec<DefId>> }
-dep_map_ty! { ImplTraitRefs: ItemSignature(DefId) -> Option<ty::TraitRef<'tcx>> }
-dep_map_ty! { TraitDefs: ItemSignature(DefId) -> &'tcx ty::TraitDef }
-dep_map_ty! { AdtDefs: ItemSignature(DefId) -> &'tcx ty::AdtDef }
-dep_map_ty! { AdtSizedConstraint: SizedConstraint(DefId) -> Ty<'tcx> }
-dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc<Vec<ty::Variance>> }
-dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Vec<DefId> }
-dep_map_ty! { ReprHints: ReprHints(DefId) -> Rc<Vec<attr::ReprAttr>> }
-dep_map_ty! { Mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>> }
-dep_map_ty! { ClosureKinds: ItemSignature(DefId) -> ty::ClosureKind }
-dep_map_ty! { ClosureTypes: ItemSignature(DefId) -> ty::ClosureTy<'tcx> }
-dep_map_ty! { TypeckTables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx> }
-dep_map_ty! { UsedTraitImports: UsedTraitImports(DefId) -> DefIdSet }
+use syntax_pos::{Span, DUMMY_SP};
+
+trait Key {
+    fn map_crate(&self) -> CrateNum;
+    fn default_span(&self, tcx: TyCtxt) -> Span;
+}
+
+impl Key for CrateNum {
+    fn map_crate(&self) -> CrateNum {
+        *self
+    }
+    fn default_span(&self, _: TyCtxt) -> Span {
+        DUMMY_SP
+    }
+}
+
+impl Key for DefId {
+    fn map_crate(&self) -> CrateNum {
+        self.krate
+    }
+    fn default_span(&self, tcx: TyCtxt) -> Span {
+        tcx.def_span(*self)
+    }
+}
+
+impl Key for (DefId, DefId) {
+    fn map_crate(&self) -> CrateNum {
+        self.0.krate
+    }
+    fn default_span(&self, tcx: TyCtxt) -> Span {
+        self.1.default_span(tcx)
+    }
+}
+
+impl Key for (CrateNum, DefId) {
+    fn map_crate(&self) -> CrateNum {
+        self.0
+    }
+    fn default_span(&self, tcx: TyCtxt) -> Span {
+        self.1.default_span(tcx)
+    }
+}
+
+trait Value<'tcx>: Sized {
+    fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
+}
+
+impl<'tcx, T> Value<'tcx> for T {
+    default fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> T {
+        tcx.sess.abort_if_errors();
+        bug!("Value::from_cycle_error called without errors");
+    }
+}
+
+impl<'tcx, T: Default> Value<'tcx> for T {
+    default fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> T {
+        T::default()
+    }
+}
+
+impl<'tcx> Value<'tcx> for Ty<'tcx> {
+    fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
+        tcx.types.err
+    }
+}
+
+pub struct CycleError<'a> {
+    span: Span,
+    cycle: RefMut<'a, [(Span, Query)]>
+}
+
+impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
+    pub fn report_cycle(self, CycleError { span, cycle }: CycleError) {
+        assert!(!cycle.is_empty());
+
+        let mut err = struct_span_err!(self.sess, span, E0391,
+            "unsupported cyclic reference between types/traits detected");
+        err.span_label(span, &format!("cyclic reference"));
+
+        err.span_note(cycle[0].0, &format!("the cycle begins when {}...",
+                                           cycle[0].1.describe(self)));
+
+        for &(span, ref query) in &cycle[1..] {
+            err.span_note(span, &format!("...which then requires {}...",
+                                         query.describe(self)));
+        }
+
+        err.note(&format!("...which then again requires {}, completing the cycle.",
+                          cycle[0].1.describe(self)));
+
+        err.emit();
+    }
+
+    fn cycle_check<F, R>(self, span: Span, query: Query, compute: F)
+                         -> Result<R, CycleError<'a>>
+        where F: FnOnce() -> R
+    {
+        {
+            let mut stack = self.maps.query_stack.borrow_mut();
+            if let Some((i, _)) = stack.iter().enumerate().rev()
+                                       .find(|&(_, &(_, ref q))| *q == query) {
+                return Err(CycleError {
+                    span: span,
+                    cycle: RefMut::map(stack, |stack| &mut stack[i..])
+                });
+            }
+            stack.push((span, query));
+        }
+
+        let result = compute();
+
+        self.maps.query_stack.borrow_mut().pop();
+
+        Ok(result)
+    }
+}
+
+trait QueryDescription: DepTrackingMapConfig {
+    fn describe(tcx: TyCtxt, key: Self::Key) -> String;
+}
+
+impl<M: DepTrackingMapConfig<Key=DefId>> QueryDescription for M {
+    default fn describe(tcx: TyCtxt, def_id: DefId) -> String {
+        format!("processing `{}`", tcx.item_path_str(def_id))
+    }
+}
+
+impl<'tcx> QueryDescription for queries::super_predicates<'tcx> {
+    fn describe(tcx: TyCtxt, def_id: DefId) -> String {
+        format!("computing the supertraits of `{}`",
+                tcx.item_path_str(def_id))
+    }
+}
+
+impl<'tcx> QueryDescription for queries::type_param_predicates<'tcx> {
+    fn describe(tcx: TyCtxt, (_, def_id): (DefId, DefId)) -> String {
+        let id = tcx.hir.as_local_node_id(def_id).unwrap();
+        format!("computing the bounds for type parameter `{}`",
+                tcx.hir.ty_param_name(id))
+    }
+}
+
+impl<'tcx> QueryDescription for queries::coherent_trait<'tcx> {
+    fn describe(tcx: TyCtxt, (_, def_id): (CrateNum, DefId)) -> String {
+        format!("coherence checking all impls of trait `{}`",
+                tcx.item_path_str(def_id))
+    }
+}
+
+impl<'tcx> QueryDescription for queries::coherent_inherent_impls<'tcx> {
+    fn describe(_: TyCtxt, _: CrateNum) -> String {
+        format!("coherence checking all inherent impls")
+    }
+}
+
+macro_rules! define_maps {
+    (<$tcx:tt>
+     $($(#[$attr:meta])*
+       pub $name:ident: $node:ident($K:ty) -> $V:ty),*) => {
+        pub struct Maps<$tcx> {
+            providers: IndexVec<CrateNum, Providers<$tcx>>,
+            query_stack: RefCell<Vec<(Span, Query)>>,
+            $($(#[$attr])* pub $name: RefCell<DepTrackingMap<queries::$name<$tcx>>>),*
+        }
+
+        impl<$tcx> Maps<$tcx> {
+            pub fn new(dep_graph: DepGraph,
+                       providers: IndexVec<CrateNum, Providers<$tcx>>)
+                       -> Self {
+                Maps {
+                    providers,
+                    query_stack: RefCell::new(vec![]),
+                    $($name: RefCell::new(DepTrackingMap::new(dep_graph.clone()))),*
+                }
+            }
+        }
+
+        #[allow(bad_style)]
+        #[derive(Copy, Clone, Debug, PartialEq, Eq)]
+        pub enum Query {
+            $($(#[$attr])* $name($K)),*
+        }
+
+        impl Query {
+            pub fn describe(&self, tcx: TyCtxt) -> String {
+                match *self {
+                    $(Query::$name(key) => queries::$name::describe(tcx, key)),*
+                }
+            }
+        }
+
+        pub mod queries {
+            use std::marker::PhantomData;
+
+            $(#[allow(bad_style)]
+            pub struct $name<$tcx> {
+                data: PhantomData<&$tcx ()>
+            })*
+        }
+
+        $(impl<$tcx> DepTrackingMapConfig for queries::$name<$tcx> {
+            type Key = $K;
+            type Value = $V;
+
+            #[allow(unused)]
+            fn to_dep_node(key: &$K) -> DepNode<DefId> {
+                use dep_graph::DepNode::*;
+
+                $node(*key)
+            }
+        }
+        impl<'a, $tcx, 'lcx> queries::$name<$tcx> {
+            fn try_get_with<F, R>(tcx: TyCtxt<'a, $tcx, 'lcx>,
+                                  mut span: Span,
+                                  key: $K,
+                                  f: F)
+                                  -> Result<R, CycleError<'a>>
+                where F: FnOnce(&$V) -> R
+            {
+                if let Some(result) = tcx.maps.$name.borrow().get(&key) {
+                    return Ok(f(result));
+                }
+
+                // FIXME(eddyb) Get more valid Span's on queries.
+                if span == DUMMY_SP {
+                    span = key.default_span(tcx);
+                }
+
+                let _task = tcx.dep_graph.in_task(Self::to_dep_node(&key));
+
+                let result = tcx.cycle_check(span, Query::$name(key), || {
+                    let provider = tcx.maps.providers[key.map_crate()].$name;
+                    provider(tcx.global_tcx(), key)
+                })?;
+
+                Ok(f(&tcx.maps.$name.borrow_mut().entry(key).or_insert(result)))
+            }
+
+            pub fn try_get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K)
+                           -> Result<$V, CycleError<'a>> {
+                Self::try_get_with(tcx, span, key, Clone::clone)
+            }
+
+            $(#[$attr])*
+            pub fn get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) -> $V {
+                Self::try_get(tcx, span, key).unwrap_or_else(|e| {
+                    tcx.report_cycle(e);
+                    Value::from_cycle_error(tcx.global_tcx())
+                })
+            }
+
+            pub fn force(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) {
+                // FIXME(eddyb) Move away from using `DepTrackingMap`
+                // so we don't have to explicitly ignore a false edge:
+                // we can't observe a value dependency, only side-effects,
+                // through `force`, and once everything has been updated,
+                // perhaps only diagnostics, if those, will remain.
+                let _ignore = tcx.dep_graph.in_ignore();
+                match Self::try_get_with(tcx, span, key, |_| ()) {
+                    Ok(()) => {}
+                    Err(e) => tcx.report_cycle(e)
+                }
+            }
+        })*
+
+        pub struct Providers<$tcx> {
+            $(pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $V),*
+        }
+
+        impl<$tcx> Copy for Providers<$tcx> {}
+        impl<$tcx> Clone for Providers<$tcx> {
+            fn clone(&self) -> Self { *self }
+        }
+
+        impl<$tcx> Default for Providers<$tcx> {
+            fn default() -> Self {
+                $(fn $name<'a, $tcx>(_: TyCtxt<'a, $tcx, $tcx>, key: $K) -> $V {
+                    bug!("tcx.maps.{}({:?}) unsupported by its crate",
+                         stringify!($name), key);
+                })*
+                Providers { $($name),* }
+            }
+        }
+    }
+}
+
+// Each of these maps also corresponds to a method on a
+// `Provider` trait for requesting a value of that type,
+// and a method on `Maps` itself for doing that in a
+// a way that memoizes and does dep-graph tracking,
+// wrapping around the actual chain of providers that
+// the driver creates (using several `rustc_*` crates).
+define_maps! { <'tcx>
+    /// Records the type of every item.
+    pub ty: ItemSignature(DefId) -> Ty<'tcx>,
+
+    /// Maps from the def-id of an item (trait/struct/enum/fn) to its
+    /// associated generics and predicates.
+    pub generics: ItemSignature(DefId) -> &'tcx ty::Generics,
+    pub predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>,
+
+    /// Maps from the def-id of a trait to the list of
+    /// super-predicates. This is a subset of the full list of
+    /// predicates. We store these in a separate map because we must
+    /// evaluate them even during type conversion, often before the
+    /// full predicates are available (note that supertraits have
+    /// additional acyclicity requirements).
+    pub super_predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>,
+
+    /// To avoid cycles within the predicates of a single item we compute
+    /// per-type-parameter predicates for resolving `T::AssocTy`.
+    pub type_param_predicates: TypeParamPredicates((DefId, DefId))
+        -> ty::GenericPredicates<'tcx>,
+
+    pub trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef,
+    pub adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef,
+    pub adt_sized_constraint: SizedConstraint(DefId) -> Ty<'tcx>,
+
+    /// Maps from def-id of a type or region parameter to its
+    /// (inferred) variance.
+    pub variances: ItemSignature(DefId) -> Rc<Vec<ty::Variance>>,
+
+    /// Maps from an impl/trait def-id to a list of the def-ids of its items
+    pub associated_item_def_ids: AssociatedItemDefIds(DefId) -> Rc<Vec<DefId>>,
+
+    /// Maps from a trait item to the trait item "descriptor"
+    pub associated_item: AssociatedItems(DefId) -> ty::AssociatedItem,
+
+    pub impl_trait_ref: ItemSignature(DefId) -> Option<ty::TraitRef<'tcx>>,
+
+    /// Maps a DefId of a type to a list of its inherent impls.
+    /// Contains implementations of methods that are inherent to a type.
+    /// Methods in these implementations don't need to be exported.
+    pub inherent_impls: InherentImpls(DefId) -> Vec<DefId>,
+
+    /// Maps from the def-id of a function/method or const/static
+    /// to its MIR. Mutation is done at an item granularity to
+    /// allow MIR optimization passes to function and still
+    /// access cross-crate MIR (e.g. inlining or const eval).
+    ///
+    /// Note that cross-crate MIR appears to be always borrowed
+    /// (in the `RefCell` sense) to prevent accidental mutation.
+    pub mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>>,
+
+    /// Maps DefId's that have an associated Mir to the result
+    /// of the MIR qualify_consts pass. The actual meaning of
+    /// the value isn't known except to the pass itself.
+    pub mir_const_qualif: Mir(DefId) -> u8,
+
+    /// Records the type of each closure. The def ID is the ID of the
+    /// expression defining the closure.
+    pub closure_kind: ItemSignature(DefId) -> ty::ClosureKind,
+
+    /// Records the type of each closure. The def ID is the ID of the
+    /// expression defining the closure.
+    pub closure_type: ItemSignature(DefId) -> ty::PolyFnSig<'tcx>,
+
+    /// Caches CoerceUnsized kinds for impls on custom types.
+    pub custom_coerce_unsized_kind: ItemSignature(DefId)
+        -> ty::adjustment::CustomCoerceUnsized,
+
+    pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>,
+
+    pub coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (),
+
+    pub coherent_inherent_impls: coherent_inherent_impls_dep_node(CrateNum) -> (),
+
+    /// Results of evaluating monomorphic constants embedded in
+    /// other items, such as enum variant explicit discriminants.
+    pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result<ConstVal<'tcx>, ()>
+}
+
+fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
+    DepNode::CoherenceCheckTrait(def_id)
+}
+
+fn coherent_inherent_impls_dep_node(_: CrateNum) -> DepNode<DefId> {
+    DepNode::Coherence
+}
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 7937d2ccfe4..656d0ddf09a 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -19,20 +19,24 @@ use dep_graph::{self, DepNode};
 use hir::{map as hir_map, FreevarMap, TraitMap};
 use middle;
 use hir::def::{Def, CtorKind, ExportMap};
-use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
+use middle::const_val::ConstVal;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::region::{CodeExtent, ROOT_CODE_EXTENT};
+use middle::resolve_lifetime::ObjectLifetimeDefault;
 use mir::Mir;
 use traits;
 use ty;
 use ty::subst::{Subst, Substs};
+use ty::util::IntTypeExt;
 use ty::walk::TypeWalker;
 use util::common::MemoizationMap;
-use util::nodemap::{NodeSet, NodeMap, FxHashMap};
+use util::nodemap::{NodeSet, FxHashMap};
 
 use serialize::{self, Encodable, Encoder};
 use std::borrow::Cow;
 use std::cell::{Cell, RefCell, Ref};
+use std::collections::BTreeMap;
 use std::hash::{Hash, Hasher};
 use std::ops::Deref;
 use std::rc::Rc;
@@ -43,6 +47,7 @@ use syntax::ast::{self, Name, NodeId};
 use syntax::attr;
 use syntax::symbol::{Symbol, InternedString};
 use syntax_pos::{DUMMY_SP, Span};
+use rustc_const_math::ConstInt;
 
 use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
 
@@ -50,8 +55,8 @@ use hir;
 use hir::itemlikevisit::ItemLikeVisitor;
 
 pub use self::sty::{Binder, DebruijnIndex};
-pub use self::sty::{BareFnTy, FnSig, PolyFnSig};
-pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
+pub use self::sty::{FnSig, PolyFnSig};
+pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
 pub use self::sty::{ClosureSubsts, TypeAndMut};
 pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef};
 pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
@@ -70,6 +75,8 @@ pub use self::context::{Lift, TypeckTables};
 
 pub use self::trait_def::{TraitDef, TraitFlags};
 
+pub use self::maps::queries;
+
 pub mod adjustment;
 pub mod cast;
 pub mod error;
@@ -94,20 +101,17 @@ mod flags;
 mod structural_impls;
 mod sty;
 
-pub type Disr = u128;
-
 // Data types
 
 /// The complete set of all analyses described in this module. This is
 /// produced by the driver and fed to trans and later passes.
 #[derive(Clone)]
-pub struct CrateAnalysis<'tcx> {
+pub struct CrateAnalysis {
     pub export_map: ExportMap,
     pub access_levels: middle::privacy::AccessLevels,
     pub reachable: NodeSet,
     pub name: String,
     pub glob_map: Option<hir::GlobMap>,
-    pub hir_ty_to_ty: NodeMap<Ty<'tcx>>,
 }
 
 #[derive(Clone)]
@@ -585,13 +589,13 @@ pub enum IntVarValue {
     UintType(ast::UintTy),
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable)]
-pub struct TypeParameterDef<'tcx> {
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
+pub struct TypeParameterDef {
     pub name: Name,
     pub def_id: DefId,
     pub index: u32,
-    pub default_def_id: DefId, // for use in error reporing about defaults
-    pub default: Option<Ty<'tcx>>,
+    pub has_default: bool,
+    pub object_lifetime_default: ObjectLifetimeDefault,
 
     /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
     /// on generic parameter `T`, asserts data behind the parameter
@@ -628,16 +632,21 @@ impl RegionParameterDef {
 /// Information about the formal type/lifetime parameters associated
 /// with an item or method. Analogous to hir::Generics.
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
-pub struct Generics<'tcx> {
+pub struct Generics {
     pub parent: Option<DefId>,
     pub parent_regions: u32,
     pub parent_types: u32,
     pub regions: Vec<RegionParameterDef>,
-    pub types: Vec<TypeParameterDef<'tcx>>,
+    pub types: Vec<TypeParameterDef>,
+
+    /// Reverse map to each `TypeParameterDef`'s `index` field, from
+    /// `def_id.index` (`def_id.krate` is the same as the item's).
+    pub type_param_to_index: BTreeMap<DefIndex, u32>,
+
     pub has_self: bool,
 }
 
-impl<'tcx> Generics<'tcx> {
+impl Generics {
     pub fn parent_count(&self) -> usize {
         self.parent_regions as usize + self.parent_types as usize
     }
@@ -651,16 +660,18 @@ impl<'tcx> Generics<'tcx> {
     }
 
     pub fn region_param(&self, param: &EarlyBoundRegion) -> &RegionParameterDef {
+        assert_eq!(self.parent_count(), 0);
         &self.regions[param.index as usize - self.has_self as usize]
     }
 
-    pub fn type_param(&self, param: &ParamTy) -> &TypeParameterDef<'tcx> {
+    pub fn type_param(&self, param: &ParamTy) -> &TypeParameterDef {
+        assert_eq!(self.parent_count(), 0);
         &self.types[param.idx as usize - self.has_self as usize - self.regions.len()]
     }
 }
 
 /// Bounds on generics.
-#[derive(Clone)]
+#[derive(Clone, Default)]
 pub struct GenericPredicates<'tcx> {
     pub parent: Option<DefId>,
     pub predicates: Vec<Predicate<'tcx>>,
@@ -1086,24 +1097,6 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
     }
 }
 
-impl<'tcx> TraitRef<'tcx> {
-    pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> TraitRef<'tcx> {
-        TraitRef { def_id: def_id, substs: substs }
-    }
-
-    pub fn self_ty(&self) -> Ty<'tcx> {
-        self.substs.type_at(0)
-    }
-
-    pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
-        // Select only the "input types" from a trait-reference. For
-        // now this is all the types that appear in the
-        // trait-reference, but it should eventually exclude
-        // associated types.
-        self.substs.types()
-    }
-}
-
 /// When type checking, we use the `ParameterEnvironment` to track
 /// details about the type/lifetime parameters that are in scope.
 /// It primarily stores the bounds information.
@@ -1287,10 +1280,10 @@ bitflags! {
         const IS_DTORCK           = 1 << 1, // is this a dtorck type?
         const IS_DTORCK_VALID     = 1 << 2,
         const IS_PHANTOM_DATA     = 1 << 3,
-        const IS_SIMD             = 1 << 4,
-        const IS_FUNDAMENTAL      = 1 << 5,
-        const IS_UNION            = 1 << 6,
-        const IS_BOX              = 1 << 7,
+        const IS_FUNDAMENTAL      = 1 << 4,
+        const IS_UNION            = 1 << 5,
+        const IS_BOX              = 1 << 6,
+        const IS_DTOR_VALID       = 1 << 7,
     }
 }
 
@@ -1300,11 +1293,24 @@ pub struct VariantDef {
     /// this is the DefId of the struct's ctor.
     pub did: DefId,
     pub name: Name, // struct's name if this is a struct
-    pub disr_val: Disr,
+    pub discr: VariantDiscr,
     pub fields: Vec<FieldDef>,
     pub ctor_kind: CtorKind,
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
+pub enum VariantDiscr {
+    /// Explicit value for this variant, i.e. `X = 123`.
+    /// The `DefId` corresponds to the embedded constant.
+    Explicit(DefId),
+
+    /// The previous variant's discriminant plus one.
+    /// For efficiency reasons, the distance from the
+    /// last `Explicit` discriminant is being stored,
+    /// or `0` for the first variant, if it has none.
+    Relative(usize),
+}
+
 #[derive(Debug)]
 pub struct FieldDef {
     pub did: DefId,
@@ -1318,12 +1324,6 @@ pub struct FieldDef {
 /// table.
 pub struct AdtDef {
     pub did: DefId,
-    /// Type of the discriminant
-    ///
-    /// Note, that this is the type specified in `repr()` or a default type of some sort, and might
-    /// not match the actual type that layout algorithm decides to use when translating this type
-    /// into LLVM. That being said, layout algorithm may not use a type larger than specified here.
-    pub discr_ty: attr::IntType,
     pub variants: Vec<VariantDef>,
     destructor: Cell<Option<DefId>>,
     flags: Cell<AdtFlags>,
@@ -1366,27 +1366,37 @@ pub struct ReprOptions {
 }
 
 impl ReprOptions {
-    pub fn new<'a, 'gcx, 'tcx>(tcx: &TyCtxt<'a, 'gcx, 'tcx>, did: DefId) -> ReprOptions {
+    pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions {
         let mut ret = ReprOptions::default();
-        let attrs = tcx.lookup_repr_hints(did);
-        for r in attrs.iter() {
-            match *r {
-                attr::ReprExtern => ret.c = true,
-                attr::ReprPacked => ret.packed = true,
-                attr::ReprSimd => ret.simd = true,
-                attr::ReprInt(i) => ret.int = Some(i),
-                attr::ReprAny => (),
+
+        for attr in tcx.get_attrs(did).iter() {
+            for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) {
+                match r {
+                    attr::ReprExtern => ret.c = true,
+                    attr::ReprPacked => ret.packed = true,
+                    attr::ReprSimd => ret.simd = true,
+                    attr::ReprInt(i) => ret.int = Some(i),
+                }
             }
         }
+
+        // FIXME(eddyb) This is deprecated and should be removed.
+        if tcx.has_attr(did, "simd") {
+            ret.simd = true;
+        }
+
         ret
     }
+
+    pub fn discr_type(&self) -> attr::IntType {
+        self.int.unwrap_or(attr::SignedInt(ast::IntTy::Is))
+    }
 }
 
 impl<'a, 'gcx, 'tcx> AdtDef {
-    fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+    fn new(tcx: TyCtxt,
            did: DefId,
            kind: AdtKind,
-           discr_ty: attr::IntType,
            variants: Vec<VariantDef>,
            repr: ReprOptions) -> Self {
         let mut flags = AdtFlags::NO_ADT_FLAGS;
@@ -1394,9 +1404,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         if attr::contains_name(&attrs, "fundamental") {
             flags = flags | AdtFlags::IS_FUNDAMENTAL;
         }
-        if tcx.lookup_simd(did) {
-            flags = flags | AdtFlags::IS_SIMD;
-        }
         if Some(did) == tcx.lang_items.phantom_data() {
             flags = flags | AdtFlags::IS_PHANTOM_DATA;
         }
@@ -1410,7 +1417,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         }
         AdtDef {
             did: did,
-            discr_ty: discr_ty,
             variants: variants,
             flags: Cell::new(flags),
             destructor: Cell::new(None),
@@ -1486,11 +1492,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         self.flags.get().intersects(AdtFlags::IS_FUNDAMENTAL)
     }
 
-    #[inline]
-    pub fn is_simd(&self) -> bool {
-        self.flags.get().intersects(AdtFlags::IS_SIMD)
-    }
-
     /// Returns true if this is PhantomData<T>.
     #[inline]
     pub fn is_phantom_data(&self) -> bool {
@@ -1504,8 +1505,8 @@ impl<'a, 'gcx, 'tcx> AdtDef {
     }
 
     /// Returns whether this type has a destructor.
-    pub fn has_dtor(&self) -> bool {
-        self.destructor.get().is_some()
+    pub fn has_dtor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
+        self.destructor(tcx).is_some()
     }
 
     /// Asserts this is a struct and returns the struct's unique
@@ -1560,12 +1561,57 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         }
     }
 
-    pub fn destructor(&self) -> Option<DefId> {
-        self.destructor.get()
+    pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
+        if self.flags.get().intersects(AdtFlags::IS_DTOR_VALID) {
+            return self.destructor.get();
+        }
+
+        let dtor = self.destructor_uncached(tcx);
+        self.destructor.set(dtor);
+        self.flags.set(self.flags.get() | AdtFlags::IS_DTOR_VALID);
+
+        dtor
     }
 
-    pub fn set_destructor(&self, dtor: DefId) {
-        self.destructor.set(Some(dtor));
+    fn destructor_uncached(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
+        let drop_trait = if let Some(def_id) = tcx.lang_items.drop_trait() {
+            def_id
+        } else {
+            return None;
+        };
+
+        queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, drop_trait));
+
+        let mut dtor = None;
+        let ty = tcx.item_type(self.did);
+        tcx.lookup_trait_def(drop_trait).for_each_relevant_impl(tcx, ty, |def_id| {
+            if let Some(item) = tcx.associated_items(def_id).next() {
+                dtor = Some(item.def_id);
+            }
+        });
+
+        dtor
+    }
+
+    pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
+                         -> impl Iterator<Item=ConstInt> + 'a {
+        let repr_type = self.repr.discr_type();
+        let initial = repr_type.initial_discriminant(tcx.global_tcx());
+        let mut prev_discr = None::<ConstInt>;
+        self.variants.iter().map(move |v| {
+            let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr());
+            if let VariantDiscr::Explicit(expr_did) = v.discr {
+                match tcx.maps.monomorphic_const_eval.borrow()[&expr_did] {
+                    Ok(ConstVal::Integral(v)) => {
+                        discr = v;
+                    }
+                    _ => {}
+                }
+            }
+            prev_discr = Some(discr);
+
+            discr
+        })
     }
 
     /// Returns a simpler type such that `Self: Sized` if and only
@@ -1609,7 +1655,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
                                         stack: &mut Vec<DefId>)
                                         -> Ty<'tcx>
     {
-        if let Some(ty) = tcx.adt_sized_constraint.borrow().get(&self.did) {
+        if let Some(ty) = tcx.maps.adt_sized_constraint.borrow().get(&self.did) {
             return ty;
         }
 
@@ -1623,7 +1669,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
             //
             // Consider the type as Sized in the meanwhile to avoid
             // further errors.
-            tcx.adt_sized_constraint.borrow_mut().insert(self.did, tcx.types.err);
+            tcx.maps.adt_sized_constraint.borrow_mut().insert(self.did, tcx.types.err);
             return tcx.types.err;
         }
 
@@ -1647,7 +1693,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
             _ => tcx.intern_tup(&tys[..], false)
         };
 
-        let old = tcx.adt_sized_constraint.borrow().get(&self.did).cloned();
+        let old = tcx.maps.adt_sized_constraint.borrow().get(&self.did).cloned();
         match old {
             Some(old_ty) => {
                 debug!("calculate_sized_constraint: {:?} recurred", self);
@@ -1656,7 +1702,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
             }
             None => {
                 debug!("calculate_sized_constraint: {:?} => {:?}", self, ty);
-                tcx.adt_sized_constraint.borrow_mut().insert(self.did, ty);
+                tcx.maps.adt_sized_constraint.borrow_mut().insert(self.did, ty);
                 ty
             }
         }
@@ -1871,28 +1917,6 @@ impl LvaluePreference {
     }
 }
 
-/// Helper for looking things up in the various maps that are populated during
-/// typeck::collect (e.g., `tcx.associated_items`, `tcx.types`, etc).  All of
-/// these share the pattern that if the id is local, it should have been loaded
-/// into the map by the `typeck::collect` phase.  If the def-id is external,
-/// then we have to go consult the crate loading code (and cache the result for
-/// the future).
-fn lookup_locally_or_in_crate_store<M, F>(descr: &str,
-                                          def_id: DefId,
-                                          map: &M,
-                                          load_external: F)
-                                          -> M::Value where
-    M: MemoizationMap<Key=DefId>,
-    F: FnOnce() -> M::Value,
-{
-    map.memoize(def_id, || {
-        if def_id.is_local() {
-            bug!("No def'n found for {:?} in tcx.{}", def_id, descr);
-        }
-        load_external()
-    })
-}
-
 impl BorrowKind {
     pub fn from_mutbl(m: hir::Mutability) -> BorrowKind {
         match m {
@@ -1932,25 +1956,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn item_tables(self, def_id: DefId) -> &'gcx TypeckTables<'gcx> {
-        self.tables.memoize(def_id, || {
-            if def_id.is_local() {
-                // Closures' tables come from their outermost function,
-                // as they are part of the same "inference environment".
-                let outer_def_id = self.closure_base_def_id(def_id);
-                if outer_def_id != def_id {
-                    return self.item_tables(outer_def_id);
-                }
-
-                bug!("No def'n found for {:?} in tcx.tables", def_id);
-            }
-
-            // Cross-crate side-tables only exist alongside serialized HIR.
-            self.sess.cstore.maybe_get_item_body(self.global_tcx(), def_id).map(|_| {
-                self.tables.borrow()[&def_id]
-            }).unwrap_or_else(|| {
-                bug!("tcx.item_tables({:?}): missing from metadata", def_id)
-            })
-        })
+        queries::typeck_tables::get(self, DUMMY_SP, def_id)
     }
 
     pub fn expr_span(self, id: NodeId) -> Span {
@@ -2058,31 +2064,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn custom_coerce_unsized_kind(self, did: DefId) -> adjustment::CustomCoerceUnsized {
-        self.custom_coerce_unsized_kinds.memoize(did, || {
-            let (kind, src) = if did.krate != LOCAL_CRATE {
-                (self.sess.cstore.custom_coerce_unsized_kind(did), "external")
-            } else {
-                (None, "local")
-            };
-
-            match kind {
-                Some(kind) => kind,
-                None => {
-                    bug!("custom_coerce_unsized_kind: \
-                          {} impl `{}` is missing its kind",
-                          src, self.item_path_str(did));
-                }
-            }
-        })
+        queries::custom_coerce_unsized_kind::get(self, DUMMY_SP, did)
     }
 
     pub fn associated_item(self, def_id: DefId) -> AssociatedItem {
-        self.associated_items.memoize(def_id, || {
-            if !def_id.is_local() {
-                return self.sess.cstore.associated_item(def_id)
-                           .expect("missing AssociatedItem in metadata");
-            }
+        if !def_id.is_local() {
+            return queries::associated_item::get(self, DUMMY_SP, def_id);
+        }
 
+        self.maps.associated_item.memoize(def_id, || {
             // When the user asks for a given associated item, we
             // always go ahead and convert all the associated items in
             // the container. Note that we are also careful only to
@@ -2104,7 +2094,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                             self.associated_item_from_impl_item_ref(parent_def_id,
                                                                     impl_trait_ref.is_some(),
                                                                     impl_item_ref);
-                        self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item);
+                        self.maps.associated_item.borrow_mut()
+                            .insert(assoc_item.def_id, assoc_item);
                     }
                 }
 
@@ -2112,7 +2103,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                     for trait_item_ref in trait_item_refs {
                         let assoc_item =
                             self.associated_item_from_trait_item_ref(parent_def_id, trait_item_ref);
-                        self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item);
+                        self.maps.associated_item.borrow_mut()
+                            .insert(assoc_item.def_id, assoc_item);
                     }
                 }
 
@@ -2123,7 +2115,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
             // memoize wants us to return something, so return
             // the one we generated for this def-id
-            *self.associated_items.borrow().get(&def_id).unwrap()
+            *self.maps.associated_item.borrow().get(&def_id).unwrap()
         })
     }
 
@@ -2181,11 +2173,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn associated_item_def_ids(self, def_id: DefId) -> Rc<Vec<DefId>> {
-        self.associated_item_def_ids.memoize(def_id, || {
-            if !def_id.is_local() {
-                return Rc::new(self.sess.cstore.associated_item_def_ids(def_id));
-            }
+        if !def_id.is_local() {
+            return queries::associated_item_def_ids::get(self, DUMMY_SP, def_id);
+        }
 
+        self.maps.associated_item_def_ids.memoize(def_id, || {
             let id = self.hir.as_local_node_id(def_id).unwrap();
             let item = self.hir.expect_item(id);
             let vec: Vec<_> = match item.node {
@@ -2217,9 +2209,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Returns the trait-ref corresponding to a given impl, or None if it is
     /// an inherent impl.
     pub fn impl_trait_ref(self, id: DefId) -> Option<TraitRef<'gcx>> {
-        lookup_locally_or_in_crate_store(
-            "impl_trait_refs", id, &self.impl_trait_refs,
-            || self.sess.cstore.impl_trait_ref(self.global_tcx(), id))
+        queries::impl_trait_ref::get(self, DUMMY_SP, id)
     }
 
     // Returns `ty::VariantDef` if `def` refers to a struct,
@@ -2298,58 +2288,37 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     // If the given item is in an external crate, looks up its type and adds it to
     // the type cache. Returns the type parameters and type.
     pub fn item_type(self, did: DefId) -> Ty<'gcx> {
-        lookup_locally_or_in_crate_store(
-            "item_types", did, &self.item_types,
-            || self.sess.cstore.item_type(self.global_tcx(), did))
+        queries::ty::get(self, DUMMY_SP, did)
     }
 
     /// Given the did of a trait, returns its canonical trait ref.
     pub fn lookup_trait_def(self, did: DefId) -> &'gcx TraitDef {
-        lookup_locally_or_in_crate_store(
-            "trait_defs", did, &self.trait_defs,
-            || self.alloc_trait_def(self.sess.cstore.trait_def(self.global_tcx(), did))
-        )
+        queries::trait_def::get(self, DUMMY_SP, did)
     }
 
     /// Given the did of an ADT, return a reference to its definition.
     pub fn lookup_adt_def(self, did: DefId) -> &'gcx AdtDef {
-        lookup_locally_or_in_crate_store(
-            "adt_defs", did, &self.adt_defs,
-            || self.sess.cstore.adt_def(self.global_tcx(), did))
+        queries::adt_def::get(self, DUMMY_SP, did)
     }
 
     /// Given the did of an item, returns its generics.
-    pub fn item_generics(self, did: DefId) -> &'gcx Generics<'gcx> {
-        lookup_locally_or_in_crate_store(
-            "generics", did, &self.generics,
-            || self.alloc_generics(self.sess.cstore.item_generics(self.global_tcx(), did)))
+    pub fn item_generics(self, did: DefId) -> &'gcx Generics {
+        queries::generics::get(self, DUMMY_SP, did)
     }
 
     /// Given the did of an item, returns its full set of predicates.
     pub fn item_predicates(self, did: DefId) -> GenericPredicates<'gcx> {
-        lookup_locally_or_in_crate_store(
-            "predicates", did, &self.predicates,
-            || self.sess.cstore.item_predicates(self.global_tcx(), did))
+        queries::predicates::get(self, DUMMY_SP, did)
     }
 
     /// Given the did of a trait, returns its superpredicates.
     pub fn item_super_predicates(self, did: DefId) -> GenericPredicates<'gcx> {
-        lookup_locally_or_in_crate_store(
-            "super_predicates", did, &self.super_predicates,
-            || self.sess.cstore.item_super_predicates(self.global_tcx(), did))
+        queries::super_predicates::get(self, DUMMY_SP, did)
     }
 
     /// Given the did of an item, returns its MIR, borrowed immutably.
     pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> {
-        lookup_locally_or_in_crate_store("mir_map", did, &self.mir_map, || {
-            let mir = self.sess.cstore.get_item_mir(self.global_tcx(), did);
-            let mir = self.alloc_mir(mir);
-
-            // Perma-borrow MIR from extern crates to prevent mutation.
-            mem::forget(mir.borrow());
-
-            mir
-        }).borrow()
+        queries::mir::get(self, DUMMY_SP, did).borrow()
     }
 
     /// If `type_needs_drop` returns true, then `ty` is definitely
@@ -2400,41 +2369,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.get_attrs(did).iter().any(|item| item.check_name(attr))
     }
 
-    /// Determine whether an item is annotated with `#[repr(packed)]`
-    pub fn lookup_packed(self, did: DefId) -> bool {
-        self.lookup_repr_hints(did).contains(&attr::ReprPacked)
-    }
-
-    /// Determine whether an item is annotated with `#[simd]`
-    pub fn lookup_simd(self, did: DefId) -> bool {
-        self.has_attr(did, "simd")
-            || self.lookup_repr_hints(did).contains(&attr::ReprSimd)
-    }
-
     pub fn item_variances(self, item_id: DefId) -> Rc<Vec<ty::Variance>> {
-        lookup_locally_or_in_crate_store(
-            "item_variance_map", item_id, &self.item_variance_map,
-            || Rc::new(self.sess.cstore.item_variances(item_id)))
+        queries::variances::get(self, DUMMY_SP, item_id)
     }
 
     pub fn trait_has_default_impl(self, trait_def_id: DefId) -> bool {
-        self.populate_implementations_for_trait_if_necessary(trait_def_id);
-
         let def = self.lookup_trait_def(trait_def_id);
         def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL)
     }
 
-    /// Records a trait-to-implementation mapping.
-    pub fn record_trait_has_default_impl(self, trait_def_id: DefId) {
-        let def = self.lookup_trait_def(trait_def_id);
-        def.flags.set(def.flags.get() | TraitFlags::HAS_DEFAULT_IMPL)
-    }
-
     /// Populates the type context with all the inherent implementations for
     /// the given type if necessary.
     pub fn populate_inherent_implementations_for_type_if_necessary(self,
+                                                                   span: Span,
                                                                    type_id: DefId) {
         if type_id.is_local() {
+            // Make sure coherence of inherent impls ran already.
+            ty::queries::coherent_inherent_impls::force(self, span, LOCAL_CRATE);
             return
         }
 
@@ -2451,7 +2402,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
         let inherent_impls = self.sess.cstore.inherent_implementations_for_type(type_id);
 
-        self.inherent_impls.borrow_mut().insert(type_id, inherent_impls);
+        self.maps.inherent_impls.borrow_mut().insert(type_id, inherent_impls);
         self.populated_external_types.borrow_mut().insert(type_id);
     }
 
@@ -2467,16 +2418,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         let _ignore = self.dep_graph.in_ignore();
 
         let def = self.lookup_trait_def(trait_id);
-        if def.flags.get().intersects(TraitFlags::IMPLS_VALID) {
+        if def.flags.get().intersects(TraitFlags::HAS_REMOTE_IMPLS) {
             return;
         }
 
         debug!("populate_implementations_for_trait_if_necessary: searching for {:?}", def);
 
-        if self.sess.cstore.is_defaulted_trait(trait_id) {
-            self.record_trait_has_default_impl(trait_id);
-        }
-
         for impl_def_id in self.sess.cstore.implementations_of_trait(Some(trait_id)) {
             let trait_ref = self.impl_trait_ref(impl_def_id).unwrap();
 
@@ -2485,37 +2432,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             def.record_remote_impl(self, impl_def_id, trait_ref, parent);
         }
 
-        def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID);
+        def.flags.set(def.flags.get() | TraitFlags::HAS_REMOTE_IMPLS);
     }
 
     pub fn closure_kind(self, def_id: DefId) -> ty::ClosureKind {
-        // If this is a local def-id, it should be inserted into the
-        // tables by typeck; else, it will be retreived from
-        // the external crate metadata.
-        if let Some(&kind) = self.closure_kinds.borrow().get(&def_id) {
-            return kind;
-        }
-
-        let kind = self.sess.cstore.closure_kind(def_id);
-        self.closure_kinds.borrow_mut().insert(def_id, kind);
-        kind
+        queries::closure_kind::get(self, DUMMY_SP, def_id)
     }
 
-    pub fn closure_type(self,
-                        def_id: DefId,
-                        substs: ClosureSubsts<'tcx>)
-                        -> ty::ClosureTy<'tcx>
-    {
-        // If this is a local def-id, it should be inserted into the
-        // tables by typeck; else, it will be retreived from
-        // the external crate metadata.
-        if let Some(ty) = self.closure_tys.borrow().get(&def_id) {
-            return ty.subst(self, substs.substs);
-        }
-
-        let ty = self.sess.cstore.closure_ty(self.global_tcx(), def_id);
-        self.closure_tys.borrow_mut().insert(def_id, ty.clone());
-        ty.subst(self, substs.substs)
+    pub fn closure_type(self, def_id: DefId) -> ty::PolyFnSig<'tcx> {
+        queries::closure_type::get(self, DUMMY_SP, def_id)
     }
 
     /// Given the def_id of an impl, return the def_id of the trait it implements.
@@ -2527,15 +2452,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// If the given def ID describes a method belonging to an impl, return the
     /// ID of the impl that the method belongs to. Otherwise, return `None`.
     pub fn impl_of_method(self, def_id: DefId) -> Option<DefId> {
-        if def_id.krate != LOCAL_CRATE {
-            return self.sess.cstore.associated_item(def_id).and_then(|item| {
-                match item.container {
-                    TraitContainer(_) => None,
-                    ImplContainer(def_id) => Some(def_id),
-                }
-            });
-        }
-        match self.associated_items.borrow().get(&def_id).cloned() {
+        let item = if def_id.krate != LOCAL_CRATE {
+            if let Some(Def::Method(_)) = self.sess.cstore.describe_def(def_id) {
+                Some(self.associated_item(def_id))
+            } else {
+                None
+            }
+        } else {
+            self.maps.associated_item.borrow().get(&def_id).cloned()
+        };
+
+        match item {
             Some(trait_item) => {
                 match trait_item.container {
                     TraitContainer(_) => None,
@@ -2553,7 +2480,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         if def_id.krate != LOCAL_CRATE {
             return self.sess.cstore.trait_of_item(def_id);
         }
-        match self.associated_items.borrow().get(&def_id) {
+        match self.maps.associated_item.borrow().get(&def_id) {
             Some(associated_item) => {
                 match associated_item.container {
                     TraitContainer(def_id) => Some(def_id),
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 2e3009b4ed6..cef24d44d68 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -157,24 +157,6 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
     Ok(tcx.mk_substs(params)?)
 }
 
-impl<'tcx> Relate<'tcx> for &'tcx ty::BareFnTy<'tcx> {
-    fn relate<'a, 'gcx, R>(relation: &mut R,
-                           a: &&'tcx ty::BareFnTy<'tcx>,
-                           b: &&'tcx ty::BareFnTy<'tcx>)
-                           -> RelateResult<'tcx, &'tcx ty::BareFnTy<'tcx>>
-        where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
-    {
-        let unsafety = relation.relate(&a.unsafety, &b.unsafety)?;
-        let abi = relation.relate(&a.abi, &b.abi)?;
-        let sig = relation.relate(&a.sig, &b.sig)?;
-        Ok(relation.tcx().mk_bare_fn(ty::BareFnTy {
-            unsafety: unsafety,
-            abi: abi,
-            sig: sig
-        }))
-    }
-}
-
 impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
     fn relate<'a, 'gcx, R>(relation: &mut R,
                            a: &ty::FnSig<'tcx>,
@@ -186,6 +168,8 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
             return Err(TypeError::VariadicMismatch(
                 expected_found(relation, &a.variadic, &b.variadic)));
         }
+        let unsafety = relation.relate(&a.unsafety, &b.unsafety)?;
+        let abi = relation.relate(&a.abi, &b.abi)?;
 
         if a.inputs().len() != b.inputs().len() {
             return Err(TypeError::ArgCount);
@@ -204,7 +188,9 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
             }).collect::<Result<AccumulateVec<[_; 8]>, _>>()?;
         Ok(ty::FnSig {
             inputs_and_output: relation.tcx().intern_type_list(&inputs_and_output),
-            variadic: a.variadic
+            variadic: a.variadic,
+            unsafety: unsafety,
+            abi: abi
         })
     }
 }
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index aa74e7cc0d0..48f6fcd11b8 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -235,20 +235,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::FnSig<'a> {
         tcx.lift(&self.inputs_and_output).map(|x| {
             ty::FnSig {
                 inputs_and_output: x,
-                variadic: self.variadic
-            }
-        })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::ClosureTy<'a> {
-    type Lifted = ty::ClosureTy<'tcx>;
-    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.sig).map(|sig| {
-            ty::ClosureTy {
-                sig: sig,
+                variadic: self.variadic,
                 unsafety: self.unsafety,
-                abi: self.abi
+                abi: self.abi,
             }
         })
     }
@@ -353,7 +342,7 @@ macro_rules! CopyImpls {
     }
 }
 
-CopyImpls! { (), hir::Unsafety, abi::Abi, ty::RegionParameterDef }
+CopyImpls! { (), hir::Unsafety, abi::Abi }
 
 impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> (T, U) {
@@ -531,43 +520,6 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::BareFnTy<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        let fty = ty::BareFnTy {
-            sig: self.sig.fold_with(folder),
-            abi: self.abi,
-            unsafety: self.unsafety
-        };
-        folder.tcx().mk_bare_fn(fty)
-    }
-
-    fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_bare_fn_ty(self)
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.sig.visit_with(visitor)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ClosureTy<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-       ty::ClosureTy {
-            sig: self.sig.fold_with(folder),
-            unsafety: self.unsafety,
-            abi: self.abi,
-        }
-    }
-
-    fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_closure_ty(self)
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.sig.visit_with(visitor)
-    }
-}
-
 impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         ty::TypeAndMut { ty: self.ty.fold_with(folder), mutbl: self.mutbl }
@@ -588,6 +540,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
         ty::FnSig {
             inputs_and_output: folder.tcx().intern_type_list(&inputs_and_output),
             variadic: self.variadic,
+            unsafety: self.unsafety,
+            abi: self.abi,
         }
     }
 
@@ -716,40 +670,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoBorrow<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::TypeParameterDef {
-            name: self.name,
-            def_id: self.def_id,
-            index: self.index,
-            default: self.default.fold_with(folder),
-            default_def_id: self.default_def_id,
-            pure_wrt_drop: self.pure_wrt_drop,
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.default.visit_with(visitor)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::Generics {
-            parent: self.parent,
-            parent_regions: self.parent_regions,
-            parent_types: self.parent_types,
-            regions: self.regions.fold_with(folder),
-            types: self.types.fold_with(folder),
-            has_self: self.has_self,
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.regions.visit_with(visitor) || self.types.visit_with(visitor)
-    }
-}
-
 impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         ty::GenericPredicates {
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 862bc15c052..e686d620191 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -128,12 +128,12 @@ pub enum TypeVariants<'tcx> {
 
     /// The anonymous type of a function declaration/definition. Each
     /// function has a unique type.
-    TyFnDef(DefId, &'tcx Substs<'tcx>, &'tcx BareFnTy<'tcx>),
+    TyFnDef(DefId, &'tcx Substs<'tcx>, PolyFnSig<'tcx>),
 
     /// A pointer to a function.  Written as `fn() -> i32`.
     /// FIXME: This is currently also used to represent the callee of a method;
     /// see ty::MethodCallee etc.
-    TyFnPtr(&'tcx BareFnTy<'tcx>),
+    TyFnPtr(PolyFnSig<'tcx>),
 
     /// A trait, defined with `trait`.
     TyDynamic(Binder<&'tcx Slice<ExistentialPredicate<'tcx>>>, &'tcx ty::Region),
@@ -389,6 +389,24 @@ pub struct TraitRef<'tcx> {
     pub substs: &'tcx Substs<'tcx>,
 }
 
+impl<'tcx> TraitRef<'tcx> {
+    pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> TraitRef<'tcx> {
+        TraitRef { def_id: def_id, substs: substs }
+    }
+
+    pub fn self_ty(&self) -> Ty<'tcx> {
+        self.substs.type_at(0)
+    }
+
+    pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
+        // Select only the "input types" from a trait-reference. For
+        // now this is all the types that appear in the
+        // trait-reference, but it should eventually exclude
+        // associated types.
+        self.substs.types()
+    }
+}
+
 pub type PolyTraitRef<'tcx> = Binder<TraitRef<'tcx>>;
 
 impl<'tcx> PolyTraitRef<'tcx> {
@@ -531,38 +549,22 @@ pub struct ProjectionTy<'tcx> {
     /// The name `N` of the associated type.
     pub item_name: Name,
 }
-
-#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
-pub struct BareFnTy<'tcx> {
-    pub unsafety: hir::Unsafety,
-    pub abi: abi::Abi,
-    /// Signature (inputs and output) of this function type.
-    pub sig: PolyFnSig<'tcx>,
-}
-
-impl<'tcx> serialize::UseSpecializedDecodable for &'tcx BareFnTy<'tcx> {}
-
-#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
-pub struct ClosureTy<'tcx> {
-    pub unsafety: hir::Unsafety,
-    pub abi: abi::Abi,
-    pub sig: PolyFnSig<'tcx>,
-}
-
 /// Signature of a function type, which I have arbitrarily
 /// decided to use to refer to the input/output types.
 ///
 /// - `inputs` is the list of arguments and their modes.
 /// - `output` is the return type.
 /// - `variadic` indicates whether this is a variadic function. (only true for foreign fns)
-#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct FnSig<'tcx> {
     pub inputs_and_output: &'tcx Slice<Ty<'tcx>>,
-    pub variadic: bool
+    pub variadic: bool,
+    pub unsafety: hir::Unsafety,
+    pub abi: abi::Abi,
 }
 
 impl<'tcx> FnSig<'tcx> {
-    pub fn inputs(&self) -> &[Ty<'tcx>] {
+    pub fn inputs(&self) -> &'tcx [Ty<'tcx>] {
         &self.inputs_and_output[..self.inputs_and_output.len() - 1]
     }
 
@@ -574,7 +576,7 @@ impl<'tcx> FnSig<'tcx> {
 pub type PolyFnSig<'tcx> = Binder<FnSig<'tcx>>;
 
 impl<'tcx> PolyFnSig<'tcx> {
-    pub fn inputs(&self) -> Binder<&[Ty<'tcx>]> {
+    pub fn inputs(&self) -> Binder<&'tcx [Ty<'tcx>]> {
         Binder(self.skip_binder().inputs())
     }
     pub fn input(&self, index: usize) -> ty::Binder<Ty<'tcx>> {
@@ -586,6 +588,12 @@ impl<'tcx> PolyFnSig<'tcx> {
     pub fn variadic(&self) -> bool {
         self.skip_binder().variadic
     }
+    pub fn unsafety(&self) -> hir::Unsafety {
+        self.skip_binder().unsafety
+    }
+    pub fn abi(&self) -> abi::Abi {
+        self.skip_binder().abi
+    }
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
@@ -1087,7 +1095,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
     #[inline]
     pub fn is_simd(&self) -> bool {
         match self.sty {
-            TyAdt(def, _) => def.is_simd(),
+            TyAdt(def, _) => def.repr.simd,
             _ => false
         }
     }
@@ -1280,23 +1288,15 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
         }
     }
 
-    pub fn fn_sig(&self) -> &'tcx PolyFnSig<'tcx> {
+    pub fn fn_sig(&self) -> PolyFnSig<'tcx> {
         match self.sty {
-            TyFnDef(.., ref f) | TyFnPtr(ref f) => &f.sig,
+            TyFnDef(.., f) | TyFnPtr(f) => f,
             _ => bug!("Ty::fn_sig() called on non-fn type: {:?}", self)
         }
     }
 
-    /// Returns the ABI of the given function.
-    pub fn fn_abi(&self) -> abi::Abi {
-        match self.sty {
-            TyFnDef(.., ref f) | TyFnPtr(ref f) => f.abi,
-            _ => bug!("Ty::fn_abi() called on non-fn type"),
-        }
-    }
-
     // Type accessors for substructures of types
-    pub fn fn_args(&self) -> ty::Binder<&[Ty<'tcx>]> {
+    pub fn fn_args(&self) -> ty::Binder<&'tcx [Ty<'tcx>]> {
         self.fn_sig().inputs()
     }
 
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index c0a529b936b..0a2cc1c30f4 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -184,7 +184,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
                             mut mk_type: FT)
                             -> &'tcx Substs<'tcx>
     where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
-          FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> {
+          FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
         let defs = tcx.item_generics(def_id);
         let mut substs = Vec::with_capacity(defs.count());
         Substs::fill_item(&mut substs, tcx, defs, &mut mk_region, &mut mk_type);
@@ -198,7 +198,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
                              mut mk_type: FT)
                              -> &'tcx Substs<'tcx>
     where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
-          FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx>
+          FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx>
     {
         let defs = tcx.item_generics(def_id);
         let mut result = Vec::with_capacity(defs.count());
@@ -209,11 +209,11 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
 
     fn fill_item<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
                          tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                         defs: &ty::Generics<'tcx>,
+                         defs: &ty::Generics,
                          mk_region: &mut FR,
                          mk_type: &mut FT)
     where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
-          FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> {
+          FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
 
         if let Some(def_id) = defs.parent {
             let parent_defs = tcx.item_generics(def_id);
@@ -223,11 +223,11 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
     }
 
     fn fill_single<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
-                           defs: &ty::Generics<'tcx>,
+                           defs: &ty::Generics,
                            mk_region: &mut FR,
                            mk_type: &mut FT)
     where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
-          FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> {
+          FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
         // Handle Self first, before all regions.
         let mut types = defs.types.iter();
         if defs.parent.is_none() && defs.has_self {
@@ -301,7 +301,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
         tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned())
     }
 
-    pub fn truncate_to(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, generics: &ty::Generics<'tcx>)
+    pub fn truncate_to(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, generics: &ty::Generics)
                        -> &'tcx Substs<'tcx> {
         tcx.mk_substs(self.iter().take(generics.count()).cloned())
     }
diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs
index 1dc494ca277..097b596c5eb 100644
--- a/src/librustc/ty/trait_def.rs
+++ b/src/librustc/ty/trait_def.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use dep_graph::DepNode;
-use hir::def_id::DefId;
+use hir::def_id::{DefId, LOCAL_CRATE};
 use traits::{self, specialization_graph};
 use ty;
 use ty::fast_reject;
@@ -18,6 +18,9 @@ use std::cell::{Cell, RefCell};
 use hir;
 use util::nodemap::FxHashMap;
 
+use syntax::ast;
+use syntax_pos::DUMMY_SP;
+
 /// A trait's definition with type information.
 pub struct TraitDef {
     pub def_id: DefId,
@@ -60,6 +63,11 @@ pub struct TraitDef {
     /// Various flags
     pub flags: Cell<TraitFlags>,
 
+    /// The number of impls we've added from the local crate.
+    /// When this number matches up the list in the HIR map,
+    /// we're done, and the specialization graph is correct.
+    local_impl_count: Cell<usize>,
+
     /// The ICH of this trait's DefPath, cached here so it doesn't have to be
     /// recomputed all the time.
     pub def_path_hash: u64,
@@ -78,6 +86,7 @@ impl<'a, 'gcx, 'tcx> TraitDef {
             nonblanket_impls: RefCell::new(FxHashMap()),
             blanket_impls: RefCell::new(vec![]),
             flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS),
+            local_impl_count: Cell::new(0),
             specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()),
             def_path_hash: def_path_hash,
         }
@@ -155,6 +164,13 @@ impl<'a, 'gcx, 'tcx> TraitDef {
         assert!(impl_def_id.is_local());
         let was_new = self.record_impl(tcx, impl_def_id, impl_trait_ref);
         assert!(was_new);
+
+        self.local_impl_count.set(self.local_impl_count.get() + 1);
+    }
+
+    /// Records a trait-to-implementation mapping.
+    pub fn record_has_default_impl(&self) {
+        self.flags.set(self.flags.get() | TraitFlags::HAS_DEFAULT_IMPL);
     }
 
     /// Records a trait-to-implementation mapping for a non-local impl.
@@ -194,10 +210,51 @@ impl<'a, 'gcx, 'tcx> TraitDef {
         specialization_graph::ancestors(self, of_impl)
     }
 
+    /// Whether the impl set and specialization graphs are complete.
+    pub fn is_complete(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
+        tcx.populate_implementations_for_trait_if_necessary(self.def_id);
+        ty::queries::coherent_trait::try_get(tcx, DUMMY_SP, (LOCAL_CRATE, self.def_id)).is_ok()
+    }
+
+    /// If any local impls haven't been added yet, returns
+    /// Some(list of local impls for this trait).
+    fn missing_local_impls(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
+                           -> Option<&'gcx [ast::NodeId]> {
+        if self.flags.get().intersects(TraitFlags::HAS_LOCAL_IMPLS) {
+            return None;
+        }
+
+        if self.is_complete(tcx) {
+            self.flags.set(self.flags.get() | TraitFlags::HAS_LOCAL_IMPLS);
+            return None;
+        }
+
+        let impls = tcx.hir.trait_impls(self.def_id);
+        assert!(self.local_impl_count.get() <= impls.len());
+        if self.local_impl_count.get() == impls.len() {
+            self.flags.set(self.flags.get() | TraitFlags::HAS_LOCAL_IMPLS);
+            return None;
+        }
+
+        Some(impls)
+    }
+
     pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, mut f: F) {
         self.read_trait_impls(tcx);
         tcx.populate_implementations_for_trait_if_necessary(self.def_id);
 
+        let local_impls = self.missing_local_impls(tcx);
+        if let Some(impls) = local_impls {
+            for &id in impls {
+                f(tcx.hir.local_def_id(id));
+            }
+        }
+        let mut f = |def_id: DefId| {
+            if !(local_impls.is_some() && def_id.is_local()) {
+                f(def_id);
+            }
+        };
+
         for &impl_def_id in self.blanket_impls.borrow().iter() {
             f(impl_def_id);
         }
@@ -217,9 +274,20 @@ impl<'a, 'gcx, 'tcx> TraitDef {
                                                    mut f: F)
     {
         self.read_trait_impls(tcx);
-
         tcx.populate_implementations_for_trait_if_necessary(self.def_id);
 
+        let local_impls = self.missing_local_impls(tcx);
+        if let Some(impls) = local_impls {
+            for &id in impls {
+                f(tcx.hir.local_def_id(id));
+            }
+        }
+        let mut f = |def_id: DefId| {
+            if !(local_impls.is_some() && def_id.is_local()) {
+                f(def_id);
+            }
+        };
+
         for &impl_def_id in self.blanket_impls.borrow().iter() {
             f(impl_def_id);
         }
@@ -258,6 +326,7 @@ bitflags! {
         const HAS_DEFAULT_IMPL      = 1 << 0,
         const IS_OBJECT_SAFE        = 1 << 1,
         const OBJECT_SAFETY_VALID   = 1 << 2,
-        const IMPLS_VALID           = 1 << 3,
+        const HAS_REMOTE_IMPLS      = 1 << 3,
+        const HAS_LOCAL_IMPLS       = 1 << 4,
     }
 }
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 16492de6c3d..49c25d25c60 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -16,13 +16,14 @@ use infer::InferCtxt;
 use hir::map as hir_map;
 use traits::{self, Reveal};
 use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
-use ty::{Disr, ParameterEnvironment};
+use ty::{ParameterEnvironment};
 use ty::fold::TypeVisitor;
 use ty::layout::{Layout, LayoutError};
 use ty::TypeVariants::*;
 use util::nodemap::FxHashMap;
 use middle::lang_items;
 
+use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
 use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult};
 
 use std::cell::RefCell;
@@ -35,21 +36,94 @@ use syntax_pos::Span;
 
 use hir;
 
-pub trait IntTypeExt {
-    fn to_ty<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
-    fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr;
+type Disr = ConstInt;
+
+ pub trait IntTypeExt {
+    fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
+    fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>)
+                           -> Option<Disr>;
+    fn assert_ty_matches(&self, val: Disr);
+    fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr;
+ }
+
+
+macro_rules! typed_literal {
+    ($tcx:expr, $ty:expr, $lit:expr) => {
+        match $ty {
+            SignedInt(ast::IntTy::I8)    => ConstInt::I8($lit),
+            SignedInt(ast::IntTy::I16)   => ConstInt::I16($lit),
+            SignedInt(ast::IntTy::I32)   => ConstInt::I32($lit),
+            SignedInt(ast::IntTy::I64)   => ConstInt::I64($lit),
+            SignedInt(ast::IntTy::I128)   => ConstInt::I128($lit),
+            SignedInt(ast::IntTy::Is) => match $tcx.sess.target.int_type {
+                ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16($lit)),
+                ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32($lit)),
+                ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64($lit)),
+                _ => bug!(),
+            },
+            UnsignedInt(ast::UintTy::U8)  => ConstInt::U8($lit),
+            UnsignedInt(ast::UintTy::U16) => ConstInt::U16($lit),
+            UnsignedInt(ast::UintTy::U32) => ConstInt::U32($lit),
+            UnsignedInt(ast::UintTy::U64) => ConstInt::U64($lit),
+            UnsignedInt(ast::UintTy::U128) => ConstInt::U128($lit),
+            UnsignedInt(ast::UintTy::Us) => match $tcx.sess.target.uint_type {
+                ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16($lit)),
+                ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32($lit)),
+                ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64($lit)),
+                _ => bug!(),
+            },
+        }
+    }
 }
 
 impl IntTypeExt for attr::IntType {
-    fn to_ty<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
-        match self {
-            SignedInt(i) => tcx.mk_mach_int(i),
-            UnsignedInt(i) => tcx.mk_mach_uint(i),
+    fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
+        match *self {
+            SignedInt(ast::IntTy::I8)      => tcx.types.i8,
+            SignedInt(ast::IntTy::I16)     => tcx.types.i16,
+            SignedInt(ast::IntTy::I32)     => tcx.types.i32,
+            SignedInt(ast::IntTy::I64)     => tcx.types.i64,
+            SignedInt(ast::IntTy::I128)     => tcx.types.i128,
+            SignedInt(ast::IntTy::Is)   => tcx.types.isize,
+            UnsignedInt(ast::UintTy::U8)    => tcx.types.u8,
+            UnsignedInt(ast::UintTy::U16)   => tcx.types.u16,
+            UnsignedInt(ast::UintTy::U32)   => tcx.types.u32,
+            UnsignedInt(ast::UintTy::U64)   => tcx.types.u64,
+            UnsignedInt(ast::UintTy::U128)   => tcx.types.u128,
+            UnsignedInt(ast::UintTy::Us) => tcx.types.usize,
         }
     }
 
-    fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr {
-        0
+    fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr {
+        typed_literal!(tcx, *self, 0)
+    }
+
+    fn assert_ty_matches(&self, val: Disr) {
+        match (*self, val) {
+            (SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => {},
+            (SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => {},
+            (SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => {},
+            (SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => {},
+            (SignedInt(ast::IntTy::I128), ConstInt::I128(_)) => {},
+            (SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => {},
+            (UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => {},
+            (UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => {},
+            (UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => {},
+            (UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => {},
+            (UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) => {},
+            (UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => {},
+            _ => bug!("disr type mismatch: {:?} vs {:?}", self, val),
+        }
+    }
+
+    fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>)
+                           -> Option<Disr> {
+        if let Some(val) = val {
+            self.assert_ty_matches(val);
+            (val + typed_literal!(tcx, *self, 1)).ok()
+        } else {
+            Some(self.initial_discriminant(tcx))
+        }
     }
 }
 
@@ -81,7 +155,7 @@ impl<'tcx> ParameterEnvironment<'tcx> {
                                        self_type: Ty<'tcx>, span: Span)
                                        -> Result<(), CopyImplementationError> {
         // FIXME: (@jroesch) float this code up
-        tcx.infer_ctxt(self.clone(), Reveal::NotSpecializable).enter(|infcx| {
+        tcx.infer_ctxt(self.clone(), Reveal::UserFacing).enter(|infcx| {
             let (adt, substs) = match self_type.sty {
                 ty::TyAdt(adt, substs) => (adt, substs),
                 _ => return Err(CopyImplementationError::NotAnAdt)
@@ -103,7 +177,7 @@ impl<'tcx> ParameterEnvironment<'tcx> {
                 }
             }
 
-            if adt.has_dtor() {
+            if adt.has_dtor(tcx) {
                 return Err(CopyImplementationError::HasDestructor);
             }
 
@@ -164,21 +238,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    /// Returns the IntType representation.
-    /// This used to ensure `int_ty` doesn't contain `usize` and `isize`
-    /// by converting them to their actual types. That doesn't happen anymore.
-    pub fn enum_repr_type(self, opt_hint: Option<&attr::ReprAttr>) -> attr::IntType {
-        match opt_hint {
-            // Feed in the given type
-            Some(&attr::ReprInt(int_t)) => int_t,
-            // ... but provide sensible default if none provided
-            //
-            // NB. Historically `fn enum_variants` generate i64 here, while
-            // rustc_typeck::check would generate isize.
-            _ => SignedInt(ast::IntTy::Is),
-        }
-    }
-
     /// Returns the deeply last field of nested structures, or the same type,
     /// if not a structure at all. Corresponds to the only possible unsized
     /// field, and its type can be used to determine unsizing strategy.
@@ -300,7 +359,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// (This allows programs to make cyclic structures without
     /// resorting to unasfe means; see RFCs 769 and 1238).
     pub fn is_adt_dtorck(self, adt: &ty::AdtDef) -> bool {
-        let dtor_method = match adt.destructor() {
+        let dtor_method = match adt.destructor(self) {
             Some(dtor) => dtor,
             None => return false
         };
@@ -388,10 +447,10 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
             TyFnDef(def_id, ..) => self.def_id(def_id),
             TyAdt(d, _) => self.def_id(d.did),
             TyFnPtr(f) => {
-                self.hash(f.unsafety);
-                self.hash(f.abi);
-                self.hash(f.sig.variadic());
-                self.hash(f.sig.skip_binder().inputs().len());
+                self.hash(f.unsafety());
+                self.hash(f.abi());
+                self.hash(f.variadic());
+                self.hash(f.inputs().skip_binder().len());
             }
             TyDynamic(ref data, ..) => {
                 if let Some(p) = data.principal() {
@@ -471,7 +530,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
             }
         }
         let result =
-            tcx.infer_ctxt(param_env.clone(), Reveal::ExactMatch)
+            tcx.infer_ctxt(param_env.clone(), Reveal::UserFacing)
             .enter(|infcx| {
                 traits::type_known_to_meet_bound(&infcx, self, def_id, span)
             });
diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs
index 01f31e5024c..d7954953aba 100644
--- a/src/librustc/ty/walk.rs
+++ b/src/librustc/ty/walk.rs
@@ -115,17 +115,17 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
         ty::TyTuple(ts, _) => {
             stack.extend(ts.iter().cloned().rev());
         }
-        ty::TyFnDef(_, substs, ref ft) => {
+        ty::TyFnDef(_, substs, ft) => {
             stack.extend(substs.types().rev());
-            push_sig_subtypes(stack, &ft.sig);
+            push_sig_subtypes(stack, ft);
         }
-        ty::TyFnPtr(ref ft) => {
-            push_sig_subtypes(stack, &ft.sig);
+        ty::TyFnPtr(ft) => {
+            push_sig_subtypes(stack, ft);
         }
     }
 }
 
-fn push_sig_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, sig: &ty::PolyFnSig<'tcx>) {
+fn push_sig_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, sig: ty::PolyFnSig<'tcx>) {
     stack.push(sig.skip_binder().output());
     stack.extend(sig.skip_binder().inputs().iter().cloned().rev());
 }
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index a45c43235eb..6323f1dc0d4 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -137,11 +137,14 @@ pub fn parameterized(f: &mut fmt::Formatter,
         }
 
         if !verbose {
-            if generics.types.last().map_or(false, |def| def.default.is_some()) {
+            if generics.types.last().map_or(false, |def| def.has_default) {
                 if let Some(substs) = tcx.lift(&substs) {
                     let tps = substs.types().rev().skip(child_types);
                     for (def, actual) in generics.types.iter().rev().zip(tps) {
-                        if def.default.subst(tcx, substs) != Some(actual) {
+                        if !def.has_default {
+                            break;
+                        }
+                        if tcx.item_type(def.def_id).subst(tcx, substs) != actual {
                             break;
                         }
                         num_supplied_defaults += 1;
@@ -326,7 +329,7 @@ impl<'tcx> fmt::Display for &'tcx ty::Slice<ty::ExistentialPredicate<'tcx>> {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::TypeParameterDef<'tcx> {
+impl fmt::Debug for ty::TypeParameterDef {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "TypeParameterDef({}, {:?}, {})",
                self.name,
@@ -492,15 +495,6 @@ impl fmt::Debug for ty::Region {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::ClosureTy<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "ClosureTy({},{:?},{})",
-               self.unsafety,
-               self.sig,
-               self.abi)
-    }
-}
-
 impl<'tcx> fmt::Debug for ty::ClosureUpvar<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "ClosureUpvar({:?},{:?})",
@@ -582,6 +576,14 @@ impl<'tcx> fmt::Debug for ty::InstantiatedPredicates<'tcx> {
 
 impl<'tcx> fmt::Display for ty::FnSig<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if self.unsafety == hir::Unsafety::Unsafe {
+            write!(f, "unsafe ")?;
+        }
+
+        if self.abi != Abi::Rust {
+            write!(f, "extern {} ", self.abi)?;
+        }
+
         write!(f, "fn")?;
         fn_sig(f, self.inputs(), self.variadic, self.output())
     }
@@ -738,42 +740,17 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
                 write!(f, ")")
             }
             TyFnDef(def_id, substs, ref bare_fn) => {
-                if bare_fn.unsafety == hir::Unsafety::Unsafe {
-                    write!(f, "unsafe ")?;
-                }
-
-                if bare_fn.abi != Abi::Rust {
-                    write!(f, "extern {} ", bare_fn.abi)?;
-                }
-
-                write!(f, "{} {{", bare_fn.sig.0)?;
+                write!(f, "{} {{", bare_fn.0)?;
                 parameterized(f, substs, def_id, &[])?;
                 write!(f, "}}")
             }
             TyFnPtr(ref bare_fn) => {
-                if bare_fn.unsafety == hir::Unsafety::Unsafe {
-                    write!(f, "unsafe ")?;
-                }
-
-                if bare_fn.abi != Abi::Rust {
-                    write!(f, "extern {} ", bare_fn.abi)?;
-                }
-
-                write!(f, "{}", bare_fn.sig.0)
+                write!(f, "{}", bare_fn.0)
             }
             TyInfer(infer_ty) => write!(f, "{}", infer_ty),
             TyError => write!(f, "[type error]"),
             TyParam(ref param_ty) => write!(f, "{}", param_ty),
-            TyAdt(def, substs) => {
-                ty::tls::with(|tcx| {
-                    if def.did.is_local() &&
-                          !tcx.item_types.borrow().contains_key(&def.did) {
-                        write!(f, "{}<..>", tcx.item_path_str(def.did))
-                    } else {
-                        parameterized(f, substs, def.did, &[])
-                    }
-                })
-            }
+            TyAdt(def, substs) => parameterized(f, substs, def.did, &[]),
             TyDynamic(data, r) => {
                 write!(f, "{}", data)?;
                 let r = r.to_string();
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index 1d5d1e3ab2f..0c179469448 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -200,6 +200,7 @@ supported_targets! {
     ("armv7s-apple-ios", armv7s_apple_ios),
 
     ("x86_64-sun-solaris", x86_64_sun_solaris),
+    ("sparcv9-sun-solaris", sparcv9_sun_solaris),
 
     ("x86_64-pc-windows-gnu", x86_64_pc_windows_gnu),
     ("i686-pc-windows-gnu", i686_pc_windows_gnu),
diff --git a/src/librustc_back/target/sparcv9_sun_solaris.rs b/src/librustc_back/target/sparcv9_sun_solaris.rs
new file mode 100644
index 00000000000..c88e5a402f2
--- /dev/null
+++ b/src/librustc_back/target/sparcv9_sun_solaris.rs
@@ -0,0 +1,35 @@
+// 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 target::{Target, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::solaris_base::opts();
+    base.pre_link_args.push("-m64".to_string());
+    // llvm calls this "v9"
+    base.cpu = "v9".to_string();
+    base.max_atomic_width = Some(64);
+
+    Ok(Target {
+        llvm_target: "sparcv9-sun-solaris".to_string(),
+        target_endian: "big".to_string(),
+        target_pointer_width: "64".to_string(),
+        data_layout: "E-m:e-i64:64-n32:64-S128".to_string(),
+        // Use "sparc64" instead of "sparcv9" here, since the former is already
+        // used widely in the source base.  If we ever needed ABI
+        // differentiation from the sparc64, we could, but that would probably
+        // just be confusing.
+        arch: "sparc64".to_string(),
+        target_os: "solaris".to_string(),
+        target_env: "".to_string(),
+        target_vendor: "sun".to_string(),
+        options: base,
+    })
+}
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index e3dec97472a..3ce31882b86 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -783,7 +783,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
             }
             LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => {
                 match lp_base.to_type().sty {
-                    ty::TyAdt(def, _) if def.has_dtor() => {
+                    ty::TyAdt(def, _) if def.has_dtor(self.tcx()) => {
                         // In the case where the owner implements drop, then
                         // the path must be initialized to prevent a case of
                         // partial reinitialization
diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
index c33ced52e2b..0577ba7f45a 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
@@ -177,7 +177,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => {
             match b.ty.sty {
                 ty::TyAdt(def, _) => {
-                    if def.has_dtor() {
+                    if def.has_dtor(bccx.tcx) {
                         Some(cmt.clone())
                     } else {
                         check_and_get_illegal_move_origin(bccx, b)
diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
index 47f8d978704..3678c2e55c1 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
@@ -150,7 +150,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         Categorization::Downcast(ref b, _) |
         Categorization::Interior(ref b, mc::InteriorField(_)) => {
             match b.ty.sty {
-                ty::TyAdt(def, _) if def.has_dtor() => {
+                ty::TyAdt(def, _) if def.has_dtor(bccx.tcx) => {
                     let mut err = struct_span_err!(bccx, move_from.span, E0509,
                                                    "cannot move out of type `{}`, \
                                                    which implements the `Drop` trait",
diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs
index 940dd5433a0..44e3b38ea38 100644
--- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs
+++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs
@@ -164,8 +164,9 @@ fn is_rustc_peek<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         {
             if let mir::Operand::Constant(ref func) = *oper
             {
-                if let ty::TyFnDef(def_id, _, &ty::BareFnTy { abi, .. }) = func.ty.sty
+                if let ty::TyFnDef(def_id, _, sig) = func.ty.sty
                 {
+                    let abi = sig.abi();
                     let name = tcx.item_name(def_id);
                     if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
                         if name == "rustc_peek" {
diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
index 5899c9f31d1..13f898219bc 100644
--- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
+++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
@@ -20,7 +20,7 @@ use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::ty::util::IntTypeExt;
 use rustc::mir::*;
 use rustc::mir::transform::{Pass, MirPass, MirSource};
-use rustc::middle::const_val::{ConstVal, ConstInt};
+use rustc::middle::const_val::ConstVal;
 use rustc::middle::lang_items;
 use rustc::util::nodemap::FxHashMap;
 use rustc_data_structures::indexed_set::IdxSetBuf;
@@ -639,10 +639,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                 let mut values = Vec::with_capacity(adt.variants.len());
                 let mut blocks = Vec::with_capacity(adt.variants.len());
                 let mut otherwise = None;
-                for (variant_index, variant) in adt.variants.iter().enumerate() {
-                    let discr = ConstInt::new_inttype(variant.disr_val, adt.discr_ty,
-                                                      self.tcx.sess.target.uint_type,
-                                                      self.tcx.sess.target.int_type).unwrap();
+                for (variant_index, discr) in adt.discriminants(self.tcx).enumerate() {
                     let subpath = super::move_path_children_matching(
                         self.move_data(), c.path, |proj| match proj {
                             &Projection {
@@ -680,7 +677,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                 // Additionally, we do not want to switch on the
                 // discriminant after it is free-ed, because that
                 // way lies only trouble.
-                let discr_ty = adt.discr_ty.to_ty(self.tcx);
+                let discr_ty = adt.repr.discr_type().to_ty(self.tcx);
                 let discr = Lvalue::Local(self.patch.new_temp(discr_ty));
                 let switch_block = self.patch.new_block(BasicBlockData {
                     statements: vec![
@@ -901,7 +898,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
 
         match ty.sty {
             ty::TyAdt(def, _) => {
-                if def.has_dtor() && !def.is_box() {
+                if def.has_dtor(self.tcx) && !def.is_box() {
                     self.tcx.sess.span_warn(
                         c.source_info.span,
                         &format!("dataflow bug??? moving out of type with dtor {:?}",
diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs
index 35ace6628cf..8d866676dbd 100644
--- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs
+++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs
@@ -289,7 +289,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
             // error: can't move out of borrowed content
             ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove),
             // error: can't move out of struct with destructor
-            ty::TyAdt(adt, _) if adt.has_dtor() && !adt.is_box() =>
+            ty::TyAdt(adt, _) if adt.has_dtor(self.tcx) && !adt.is_box() =>
                 return Err(MovePathError::IllegalMove),
             // move out of union - always move the entire union
             ty::TyAdt(adt, _) if adt.is_union() =>
diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs
index d9283e7037f..1c9ee335699 100644
--- a/src/librustc_borrowck/borrowck/mir/mod.rs
+++ b/src/librustc_borrowck/borrowck/mir/mod.rs
@@ -248,7 +248,7 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
                    lv, ty);
             true
         }
-        ty::TyAdt(def, _) if (def.has_dtor() && !def.is_box()) || def.is_union() => {
+        ty::TyAdt(def, _) if (def.has_dtor(tcx) && !def.is_box()) || def.is_union() => {
             debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => true",
                    lv, ty);
             true
diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs
index 78c4027aa43..53a7e872928 100644
--- a/src/librustc_const_eval/_match.rs
+++ b/src/librustc_const_eval/_match.rs
@@ -196,24 +196,46 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
             }
         }).clone()
     }
+
+    fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
+        if self.tcx.sess.features.borrow().never_type {
+            ty.is_uninhabited_from(self.module, self.tcx)
+        } else {
+            false
+        }
+    }
+
+    fn is_variant_uninhabited(&self,
+                              variant: &'tcx ty::VariantDef,
+                              substs: &'tcx ty::subst::Substs<'tcx>) -> bool
+    {
+        if self.tcx.sess.features.borrow().never_type {
+            let forest = variant.uninhabited_from(
+                &mut FxHashMap::default(), self.tcx, substs, AdtKind::Enum
+            );
+            forest.contains(self.tcx, self.module)
+        } else {
+            false
+        }
+    }
 }
 
 #[derive(Clone, Debug, PartialEq)]
-pub enum Constructor {
+pub enum Constructor<'tcx> {
     /// The constructor of all patterns that don't vary by constructor,
     /// e.g. struct patterns and fixed-length arrays.
     Single,
     /// Enum variants.
     Variant(DefId),
     /// Literal values.
-    ConstantValue(ConstVal),
+    ConstantValue(ConstVal<'tcx>),
     /// Ranges of literal values (`2...5` and `2..5`).
-    ConstantRange(ConstVal, ConstVal, RangeEnd),
+    ConstantRange(ConstVal<'tcx>, ConstVal<'tcx>, RangeEnd),
     /// Array patterns of length n.
     Slice(usize),
 }
 
-impl<'tcx> Constructor {
+impl<'tcx> Constructor<'tcx> {
     fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> usize {
         match self {
             &Variant(vid) => adt.variant_index_with_id(vid),
@@ -267,7 +289,7 @@ impl<'tcx> Witness<'tcx> {
     fn push_wild_constructor<'a>(
         mut self,
         cx: &MatchCheckCtxt<'a, 'tcx>,
-        ctor: &Constructor,
+        ctor: &Constructor<'tcx>,
         ty: Ty<'tcx>)
         -> Self
     {
@@ -299,7 +321,7 @@ impl<'tcx> Witness<'tcx> {
     fn apply_constructor<'a>(
         mut self,
         cx: &MatchCheckCtxt<'a,'tcx>,
-        ctor: &Constructor,
+        ctor: &Constructor<'tcx>,
         ty: Ty<'tcx>)
         -> Self
     {
@@ -377,50 +399,35 @@ impl<'tcx> Witness<'tcx> {
 /// We make sure to omit constructors that are statically impossible. eg for
 /// Option<!> we do not include Some(_) in the returned list of constructors.
 fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
-                                  pcx: PatternContext<'tcx>) -> Vec<Constructor>
+                                  pcx: PatternContext<'tcx>)
+                                  -> Vec<Constructor<'tcx>>
 {
-    let check_inhabited = cx.tcx.sess.features.borrow().never_type;
     debug!("all_constructors({:?})", pcx.ty);
     match pcx.ty.sty {
         ty::TyBool =>
             [true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(),
         ty::TySlice(ref sub_ty) => {
-            if sub_ty.is_uninhabited_from(cx.module, cx.tcx)
-                && check_inhabited
-            {
+            if cx.is_uninhabited(sub_ty) {
                 vec![Slice(0)]
             } else {
                 (0..pcx.max_slice_length+1).map(|length| Slice(length)).collect()
             }
         }
         ty::TyArray(ref sub_ty, length) => {
-            if length == 0 || !(sub_ty.is_uninhabited_from(cx.module, cx.tcx)
-                                && check_inhabited)
-            {
-                vec![Slice(length)]
-            } else {
+            if length > 0 && cx.is_uninhabited(sub_ty) {
                 vec![]
+            } else {
+                vec![Slice(length)]
             }
         }
         ty::TyAdt(def, substs) if def.is_enum() && def.variants.len() != 1 => {
-            def.variants.iter().filter_map(|v| {
-                let mut visited = FxHashMap::default();
-                let forest = v.uninhabited_from(&mut visited,
-                                                cx.tcx, substs,
-                                                AdtKind::Enum);
-                if forest.contains(cx.tcx, cx.module)
-                    && check_inhabited
-                {
-                    None
-                } else {
-                    Some(Variant(v.did))
-                }
-            }).collect()
+            def.variants.iter()
+                .filter(|v| !cx.is_variant_uninhabited(v, substs))
+                .map(|v| Variant(v.did))
+                .collect()
         }
         _ => {
-            if pcx.ty.is_uninhabited_from(cx.module, cx.tcx)
-                    && check_inhabited
-            {
+            if cx.is_uninhabited(pcx.ty) {
                 vec![]
             } else {
                 vec![Single]
@@ -564,7 +571,6 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
 
     assert!(rows.iter().all(|r| r.len() == v.len()));
 
-
     let pcx = PatternContext {
         ty: rows.iter().map(|r| r[0].ty).find(|ty| !ty.references_error())
             .unwrap_or(v[0].ty),
@@ -590,7 +596,6 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
         let missing_ctors: Vec<Constructor> = all_ctors.iter().filter(|c| {
             !used_ctors.contains(*c)
         }).cloned().collect();
-        debug!("missing_ctors = {:?}", missing_ctors);
 
         // `missing_ctors` is the set of constructors from the same type as the
         // first column of `matrix` that are matched only by wildcard patterns
@@ -599,8 +604,23 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
         // Therefore, if there is some pattern that is unmatched by `matrix`,
         // it will still be unmatched if the first constructor is replaced by
         // any of the constructors in `missing_ctors`
-
-        if missing_ctors.is_empty() {
+        //
+        // However, if our scrutinee is *privately* an empty enum, we
+        // must treat it as though it had an "unknown" constructor (in
+        // that case, all other patterns obviously can't be variants)
+        // to avoid exposing its emptyness. See the `match_privately_empty`
+        // test for details.
+        //
+        // FIXME: currently the only way I know of something can
+        // be a privately-empty enum is when the never_type
+        // feature flag is not present, so this is only
+        // needed for that case.
+
+        let is_privately_empty =
+            all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
+        debug!("missing_ctors={:?} is_privately_empty={:?}", missing_ctors,
+               is_privately_empty);
+        if missing_ctors.is_empty() && !is_privately_empty {
             all_ctors.into_iter().map(|c| {
                 is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
             }).find(|result| result.is_useful()).unwrap_or(NotUseful)
@@ -645,10 +665,11 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
     cx: &mut MatchCheckCtxt<'a, 'tcx>,
     &Matrix(ref m): &Matrix<'p, 'tcx>,
     v: &[&'p Pattern<'tcx>],
-    ctor: Constructor,
+    ctor: Constructor<'tcx>,
     lty: Ty<'tcx>,
     witness: WitnessPreference) -> Usefulness<'tcx>
 {
+    debug!("is_useful_specialized({:?}, {:?}, {:?})", v, ctor, lty);
     let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty);
     let wild_patterns_owned: Vec<_> = sub_pat_tys.iter().map(|ty| {
         Pattern {
@@ -682,10 +703,10 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
 /// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
 ///
 /// Returns None in case of a catch-all, which can't be specialized.
-fn pat_constructors(_cx: &mut MatchCheckCtxt,
-                    pat: &Pattern,
-                    pcx: PatternContext)
-                    -> Option<Vec<Constructor>>
+fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
+                          pat: &Pattern<'tcx>,
+                          pcx: PatternContext)
+                          -> Option<Vec<Constructor<'tcx>>>
 {
     match *pat.kind {
         PatternKind::Binding { .. } | PatternKind::Wild =>
@@ -754,7 +775,19 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
         ty::TyRef(_, ref ty_and_mut) => vec![ty_and_mut.ty],
         ty::TyAdt(adt, substs) => {
             adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| {
-                field.ty(cx.tcx, substs)
+                let is_visible = adt.is_enum()
+                    || field.vis.is_accessible_from(cx.module, cx.tcx);
+                if is_visible {
+                    field.ty(cx.tcx, substs)
+                } else {
+                    // Treat all non-visible fields as nil. They
+                    // can't appear in any other pattern from
+                    // this match (because they are private),
+                    // so their type does not matter - but
+                    // we don't want to know they are
+                    // uninhabited.
+                    cx.tcx.mk_nil()
+                }
             }).collect()
         }
         _ => vec![],
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 6f33b4fad76..e2b9f174ff0 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -124,7 +124,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
                               "statics cannot be referenced in patterns");
                 }
                 PatternError::ConstEval(err) => {
-                    report_const_eval_err(self.tcx, &err, pat_span, "pattern").emit();
+                    report_const_eval_err(self.tcx, &err, pat_span, "pattern");
                 }
             }
         }
@@ -177,6 +177,31 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
             // Fourth, check for unreachable arms.
             check_arms(cx, &inlined_arms, source);
 
+            // Then, if the match has no arms, check whether the scrutinee
+            // is uninhabited.
+            let pat_ty = self.tables.node_id_to_type(scrut.id);
+            let module = self.tcx.hir.local_def_id(self.tcx.hir.get_module_parent(scrut.id));
+            if inlined_arms.is_empty() {
+                let scrutinee_is_uninhabited = if self.tcx.sess.features.borrow().never_type {
+                    pat_ty.is_uninhabited_from(module, self.tcx)
+                } else {
+                    self.conservative_is_uninhabited(pat_ty)
+                };
+                if !scrutinee_is_uninhabited {
+                    // We know the type is inhabited, so this must be wrong
+                    let mut err = create_e0004(self.tcx.sess, scrut.span,
+                                               format!("non-exhaustive patterns: type {} \
+                                                        is non-empty",
+                                                       pat_ty));
+                    span_help!(&mut err, scrut.span,
+                               "Please ensure that all possible cases are being handled; \
+                                possibly adding wildcards or more match arms.");
+                    err.emit();
+                }
+                // If the type *is* uninhabited, it's vacuously exhaustive
+                return;
+            }
+
             let matrix: Matrix = inlined_arms
                 .iter()
                 .filter(|&&(_, guard)| guard.is_none())
@@ -188,6 +213,15 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
         })
     }
 
+    fn conservative_is_uninhabited(&self, scrutinee_ty: Ty<'tcx>) -> bool {
+        // "rustc-1.0-style" uncontentious uninhabitableness check
+        match scrutinee_ty.sty {
+            ty::TyNever => true,
+            ty::TyAdt(def, _) => def.variants.is_empty(),
+            _ => false
+        }
+    }
+
     fn check_irrefutable(&self, pat: &Pat, is_fn_arg: bool) {
         let origin = if is_fn_arg {
             "function argument"
@@ -482,7 +516,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
 ///
 /// FIXME: this should be done by borrowck.
 fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) {
-    cx.tcx.infer_ctxt((cx.tables, cx.param_env.clone()), Reveal::NotSpecializable).enter(|infcx| {
+    cx.tcx.infer_ctxt((cx.tables, cx.param_env.clone()), Reveal::UserFacing).enter(|infcx| {
         let mut checker = MutationChecker {
             cx: cx,
         };
diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs
index 8c8b2b5da36..9937cbbf8e1 100644
--- a/src/librustc_const_eval/diagnostics.rs
+++ b/src/librustc_const_eval/diagnostics.rs
@@ -576,22 +576,6 @@ integer type:
 https://doc.rust-lang.org/reference.html#ffi-attributes
 "##,
 
-
-E0306: r##"
-In an array type `[T; N]`, `N` is the number of elements in the array. This
-must be an unsigned integer. Erroneous code example:
-
-```compile_fail,E0306
-const X: [i32; true] = [0]; // error: expected `usize` for array length,
-                            //        found boolean
-```
-
-Working example:
-
-```
-const X: [i32; 1] = [0];
-```
-"##,
 }
 
 
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index af4f63a0561..c5d577ce571 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -11,7 +11,6 @@
 use rustc::middle::const_val::ConstVal::*;
 use rustc::middle::const_val::ConstVal;
 use self::ErrKind::*;
-use self::EvalHint::*;
 
 use rustc::hir::map as hir_map;
 use rustc::hir::map::blocks::FnLikeNode;
@@ -20,7 +19,7 @@ use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::util::IntTypeExt;
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::{Substs, Subst};
 use rustc::traits::Reveal;
 use rustc::util::common::ErrorReported;
 use rustc::util::nodemap::DefIdMap;
@@ -28,8 +27,7 @@ use rustc::util::nodemap::DefIdMap;
 use graphviz::IntoCow;
 use syntax::ast;
 use rustc::hir::{self, Expr};
-use syntax::attr::IntType;
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
 
 use std::borrow::Cow;
 use std::cmp::Ordering;
@@ -37,18 +35,24 @@ use std::cmp::Ordering;
 use rustc_const_math::*;
 use rustc_errors::DiagnosticBuilder;
 
+macro_rules! signal {
+    ($e:expr, $exn:expr) => {
+        return Err(ConstEvalErr { span: $e.span, kind: $exn })
+    }
+}
+
 macro_rules! math {
     ($e:expr, $op:expr) => {
         match $op {
             Ok(val) => val,
-            Err(e) => signal!($e, Math(e)),
+            Err(e) => signal!($e, ErrKind::from(e)),
         }
     }
 }
 
 fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   variant_def: DefId)
-                                  -> Option<(&'tcx Expr, Option<&'a ty::TypeckTables<'tcx>>)> {
+                                  -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> {
     if let Some(variant_node_id) = tcx.hir.as_local_node_id(variant_def) {
         let enum_node_id = tcx.hir.get_parent(variant_node_id);
         if let Some(hir_map::NodeItem(it)) = tcx.hir.find(enum_node_id) {
@@ -58,7 +62,7 @@ fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         return variant.node.disr_expr.map(|e| {
                             let def_id = tcx.hir.body_owner_def_id(e);
                             (&tcx.hir.body(e).value,
-                             tcx.tables.borrow().get(&def_id).cloned())
+                             tcx.item_tables(def_id))
                         });
                     }
                 }
@@ -75,55 +79,41 @@ fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 /// This generally happens in late/trans const evaluation.
 pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         def_id: DefId,
-                                        substs: Option<&'tcx Substs<'tcx>>)
+                                        substs: &'tcx Substs<'tcx>)
                                         -> Option<(&'tcx Expr,
-                                                   Option<&'a ty::TypeckTables<'tcx>>,
-                                                   Option<ty::Ty<'tcx>>)> {
+                                                   &'a ty::TypeckTables<'tcx>)> {
     if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
         match tcx.hir.find(node_id) {
             None => None,
             Some(hir_map::NodeItem(&hir::Item {
-                node: hir::ItemConst(ref ty, body), ..
+                node: hir::ItemConst(_, body), ..
             })) |
             Some(hir_map::NodeImplItem(&hir::ImplItem {
-                node: hir::ImplItemKind::Const(ref ty, body), ..
+                node: hir::ImplItemKind::Const(_, body), ..
             })) => {
                 Some((&tcx.hir.body(body).value,
-                      tcx.tables.borrow().get(&def_id).cloned(),
-                      tcx.ast_ty_to_prim_ty(ty)))
+                      tcx.item_tables(def_id)))
             }
             Some(hir_map::NodeTraitItem(ti)) => match ti.node {
-                hir::TraitItemKind::Const(ref ty, default) => {
-                    if let Some(substs) = substs {
-                        // If we have a trait item and the substitutions for it,
-                        // `resolve_trait_associated_const` will select an impl
-                        // or the default.
-                        let trait_id = tcx.hir.get_parent(node_id);
-                        let trait_id = tcx.hir.local_def_id(trait_id);
-                        let default_value = default.map(|body| {
-                            (&tcx.hir.body(body).value,
-                             tcx.tables.borrow().get(&def_id).cloned(),
-                             tcx.ast_ty_to_prim_ty(ty))
-                        });
-                        resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
-                    } else {
-                        // Technically, without knowing anything about the
-                        // expression that generates the obligation, we could
-                        // still return the default if there is one. However,
-                        // it's safer to return `None` than to return some value
-                        // that may differ from what you would get from
-                        // correctly selecting an impl.
-                        None
-                    }
+                hir::TraitItemKind::Const(_, default) => {
+                    // If we have a trait item and the substitutions for it,
+                    // `resolve_trait_associated_const` will select an impl
+                    // or the default.
+                    let trait_id = tcx.hir.get_parent(node_id);
+                    let trait_id = tcx.hir.local_def_id(trait_id);
+                    let default_value = default.map(|body| {
+                        (&tcx.hir.body(body).value,
+                            tcx.item_tables(def_id))
+                    });
+                    resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
                 }
                 _ => None
             },
             Some(_) => None
         }
     } else {
-        let expr_tables_ty = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
-            (&body.value, Some(tcx.item_tables(def_id)),
-             Some(tcx.sess.cstore.item_type(tcx, def_id)))
+        let expr_and_tables = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
+            (&body.value, tcx.item_tables(def_id))
         });
         match tcx.sess.cstore.describe_def(def_id) {
             Some(Def::AssociatedConst(_)) => {
@@ -133,30 +123,26 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 // trait-associated const if the caller gives us the
                 // substitutions for the reference to it.
                 if let Some(trait_id) = trait_id {
-                    if let Some(substs) = substs {
-                        resolve_trait_associated_const(tcx, def_id, expr_tables_ty,
-                                                       trait_id, substs)
-                    } else {
-                        None
-                    }
+                    resolve_trait_associated_const(tcx, def_id, expr_and_tables,
+                                                   trait_id, substs)
                 } else {
-                    expr_tables_ty
+                    expr_and_tables
                 }
             },
-            Some(Def::Const(..)) => expr_tables_ty,
+            Some(Def::Const(..)) => expr_and_tables,
             _ => None
         }
     }
 }
 
 fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-                                   -> Option<(&'tcx hir::Body, Option<&'a ty::TypeckTables<'tcx>>)>
+                                   -> Option<(&'tcx hir::Body, &'a ty::TypeckTables<'tcx>)>
 {
     if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
         FnLikeNode::from_node(tcx.hir.get(node_id)).and_then(|fn_like| {
             if fn_like.constness() == hir::Constness::Const {
                 Some((tcx.hir.body(fn_like.body()),
-                      tcx.tables.borrow().get(&def_id).cloned()))
+                      tcx.item_tables(def_id)))
             } else {
                 None
             }
@@ -164,7 +150,7 @@ fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
     } else {
         if tcx.sess.cstore.is_const_fn(def_id) {
             tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
-                (body, Some(tcx.item_tables(def_id)))
+                (body, tcx.item_tables(def_id))
             })
         } else {
             None
@@ -172,7 +158,7 @@ fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
     }
 }
 
-pub fn report_const_eval_err<'a, 'tcx>(
+fn build_const_eval_err<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     err: &ConstEvalErr,
     primary_span: Span,
@@ -189,6 +175,18 @@ pub fn report_const_eval_err<'a, 'tcx>(
     diag
 }
 
+pub fn report_const_eval_err<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    err: &ConstEvalErr,
+    primary_span: Span,
+    primary_kind: &str)
+{
+    if let TypeckError = err.kind {
+        return;
+    }
+    build_const_eval_err(tcx, err, primary_span, primary_kind).emit();
+}
+
 pub fn fatal_const_eval_err<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     err: &ConstEvalErr,
@@ -196,7 +194,7 @@ pub fn fatal_const_eval_err<'a, 'tcx>(
     primary_kind: &str)
     -> !
 {
-    report_const_eval_err(tcx, err, primary_span, primary_kind).emit();
+    report_const_eval_err(tcx, err, primary_span, primary_kind);
     tcx.sess.abort_if_errors();
     unreachable!()
 }
@@ -222,69 +220,58 @@ pub fn note_const_eval_err<'a, 'tcx>(
 
 pub struct ConstContext<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    tables: Option<&'a ty::TypeckTables<'tcx>>,
-    fn_args: Option<DefIdMap<ConstVal>>
+    tables: &'a ty::TypeckTables<'tcx>,
+    substs: &'tcx Substs<'tcx>,
+    fn_args: Option<DefIdMap<ConstVal<'tcx>>>
 }
 
 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
     pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, body: hir::BodyId) -> Self {
         let def_id = tcx.hir.body_owner_def_id(body);
-        ConstContext {
-            tcx: tcx,
-            tables: tcx.tables.borrow().get(&def_id).cloned(),
-            fn_args: None
-        }
+        ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id);
+        ConstContext::with_tables(tcx, tcx.item_tables(def_id))
     }
 
     pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>) -> Self {
         ConstContext {
             tcx: tcx,
-            tables: Some(tables),
+            tables: tables,
+            substs: tcx.intern_substs(&[]),
             fn_args: None
         }
     }
 
     /// Evaluate a constant expression in a context where the expression isn't
-    /// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked,
-    /// but a few places need to evaluate constants during type-checking, like
-    /// computing the length of an array. (See also the FIXME above EvalHint.)
-    pub fn eval(&self, e: &Expr, ty_hint: EvalHint<'tcx>) -> EvalResult {
-        eval_const_expr_partial(self, e, ty_hint)
+    /// guaranteed to be evaluatable.
+    pub fn eval(&self, e: &Expr) -> EvalResult<'tcx> {
+        if self.tables.tainted_by_errors {
+            signal!(e, TypeckError);
+        }
+        eval_const_expr_partial(self, e)
     }
 }
 
 #[derive(Clone, Debug)]
-pub struct ConstEvalErr {
+pub struct ConstEvalErr<'tcx> {
     pub span: Span,
-    pub kind: ErrKind,
+    pub kind: ErrKind<'tcx>,
 }
 
 #[derive(Clone, Debug)]
-pub enum ErrKind {
+pub enum ErrKind<'tcx> {
     CannotCast,
-    CannotCastTo(&'static str),
-    InvalidOpForInts(hir::BinOp_),
-    InvalidOpForBools(hir::BinOp_),
-    InvalidOpForFloats(hir::BinOp_),
-    InvalidOpForIntUint(hir::BinOp_),
-    InvalidOpForUintInt(hir::BinOp_),
-    NegateOn(ConstVal),
-    NotOn(ConstVal),
-    CallOn(ConstVal),
-
     MissingStructField,
+    NegateOn(ConstVal<'tcx>),
+    NotOn(ConstVal<'tcx>),
+    CallOn(ConstVal<'tcx>),
+
     NonConstPath,
     UnimplementedConstVal(&'static str),
-    UnresolvedPath,
     ExpectedConstTuple,
     ExpectedConstStruct,
-    TupleIndexOutOfBounds,
     IndexedNonVec,
-    IndexNegative,
-    IndexNotInt,
+    IndexNotUsize,
     IndexOutOfBounds { len: u64, index: u64 },
-    RepeatCountNotNatural,
-    RepeatCountNotInt,
 
     MiscBinaryOp,
     MiscCatchAll,
@@ -292,18 +279,17 @@ pub enum ErrKind {
     IndexOpFeatureGated,
     Math(ConstMathErr),
 
-    IntermediateUnsignedNegative,
-    /// Expected, Got
-    TypeMismatch(String, ConstInt),
+    ErroneousReferencedConstant(Box<ConstEvalErr<'tcx>>),
 
-    BadType(ConstVal),
-    ErroneousReferencedConstant(Box<ConstEvalErr>),
-    CharCast(ConstInt),
+    TypeckError
 }
 
-impl From<ConstMathErr> for ErrKind {
-    fn from(err: ConstMathErr) -> ErrKind {
-        Math(err)
+impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
+    fn from(err: ConstMathErr) -> ErrKind<'tcx> {
+        match err {
+            ConstMathErr::UnsignedNegation => TypeckError,
+            _ => Math(err)
+        }
     }
 }
 
@@ -321,7 +307,7 @@ impl<'a> ConstEvalErrDescription<'a> {
     }
 }
 
-impl ConstEvalErr {
+impl<'tcx> ConstEvalErr<'tcx> {
     pub fn description(&self) -> ConstEvalErrDescription {
         use self::ErrKind::*;
         use self::ConstEvalErrDescription::*;
@@ -335,12 +321,6 @@ impl ConstEvalErr {
 
         match self.kind {
             CannotCast => simple!("can't cast this type"),
-            CannotCastTo(s) => simple!("can't cast this type to {}", s),
-            InvalidOpForInts(_) =>  simple!("can't do this op on integrals"),
-            InvalidOpForBools(_) =>  simple!("can't do this op on bools"),
-            InvalidOpForFloats(_) => simple!("can't do this op on floats"),
-            InvalidOpForIntUint(..) => simple!("can't do this op on an isize and usize"),
-            InvalidOpForUintInt(..) => simple!("can't do this op on a usize and isize"),
             NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
             NotOn(ref const_val) => simple!("not on {}", const_val.description()),
             CallOn(ref const_val) => simple!("call on {}", const_val.description()),
@@ -349,111 +329,42 @@ impl ConstEvalErr {
             NonConstPath        => simple!("non-constant path in constant expression"),
             UnimplementedConstVal(what) =>
                 simple!("unimplemented constant expression: {}", what),
-            UnresolvedPath => simple!("unresolved path in constant expression"),
             ExpectedConstTuple => simple!("expected constant tuple"),
             ExpectedConstStruct => simple!("expected constant struct"),
-            TupleIndexOutOfBounds => simple!("tuple index out of bounds"),
             IndexedNonVec => simple!("indexing is only supported for arrays"),
-            IndexNegative => simple!("indices must be non-negative integers"),
-            IndexNotInt => simple!("indices must be integers"),
+            IndexNotUsize => simple!("indices must be of type `usize`"),
             IndexOutOfBounds { len, index } => {
                 simple!("index out of bounds: the len is {} but the index is {}",
                         len, index)
             }
-            RepeatCountNotNatural => simple!("repeat count must be a natural number"),
-            RepeatCountNotInt => simple!("repeat count must be integers"),
 
             MiscBinaryOp => simple!("bad operands for binary"),
             MiscCatchAll => simple!("unsupported constant expr"),
             IndexOpFeatureGated => simple!("the index operation on const values is unstable"),
             Math(ref err) => Simple(err.description().into_cow()),
 
-            IntermediateUnsignedNegative => simple!(
-                "during the computation of an unsigned a negative \
-                 number was encountered. This is most likely a bug in\
-                 the constant evaluator"),
-
-            TypeMismatch(ref expected, ref got) => {
-                simple!("expected {}, found {}", expected, got.description())
-            },
-            BadType(ref i) => simple!("value of wrong type: {:?}", i),
             ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
-            CharCast(ref got) => {
-                simple!("only `u8` can be cast as `char`, not `{}`", got.description())
-            },
-        }
-    }
-}
-
-pub type EvalResult = Result<ConstVal, ConstEvalErr>;
-pub type CastResult = Result<ConstVal, ErrKind>;
-
-// FIXME: Long-term, this enum should go away: trying to evaluate
-// an expression which hasn't been type-checked is a recipe for
-// disaster.  That said, it's not clear how to fix ast_ty_to_ty
-// to avoid the ordering issue.
-
-/// Hint to determine how to evaluate constant expressions which
-/// might not be type-checked.
-#[derive(Copy, Clone, Debug)]
-pub enum EvalHint<'tcx> {
-    /// We have a type-checked expression.
-    ExprTypeChecked,
-    /// We have an expression which hasn't been type-checked, but we have
-    /// an idea of what the type will be because of the context. For example,
-    /// the length of an array is always `usize`. (This is referred to as
-    /// a hint because it isn't guaranteed to be consistent with what
-    /// type-checking would compute.)
-    UncheckedExprHint(Ty<'tcx>),
-    /// We have an expression which has not yet been type-checked, and
-    /// and we have no clue what the type will be.
-    UncheckedExprNoHint,
-}
 
-impl<'tcx> EvalHint<'tcx> {
-    fn erase_hint(&self) -> EvalHint<'tcx> {
-        match *self {
-            ExprTypeChecked => ExprTypeChecked,
-            UncheckedExprHint(_) | UncheckedExprNoHint => UncheckedExprNoHint,
-        }
-    }
-    fn checked_or(&self, ty: Ty<'tcx>) -> EvalHint<'tcx> {
-        match *self {
-            ExprTypeChecked => ExprTypeChecked,
-            _ => UncheckedExprHint(ty),
+            TypeckError => simple!("type-checking failed"),
         }
     }
 }
 
-macro_rules! signal {
-    ($e:expr, $exn:expr) => {
-        return Err(ConstEvalErr { span: $e.span, kind: $exn })
-    }
-}
+pub type EvalResult<'tcx> = Result<ConstVal<'tcx>, ConstEvalErr<'tcx>>;
+pub type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
 
 fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
-                                     e: &Expr,
-                                     ty_hint: EvalHint<'tcx>) -> EvalResult {
+                                     e: &Expr) -> EvalResult<'tcx> {
     let tcx = cx.tcx;
-    // Try to compute the type of the expression based on the EvalHint.
-    // (See also the definition of EvalHint, and the FIXME above EvalHint.)
-    let ety = match ty_hint {
-        ExprTypeChecked => {
-            // After type-checking, expr_ty is guaranteed to succeed.
-            cx.tables.map(|tables| tables.expr_ty(e))
-        }
-        UncheckedExprHint(ty) => {
-            // Use the type hint; it's not guaranteed to be right, but it's
-            // usually good enough.
-            Some(ty)
-        }
-        UncheckedExprNoHint => {
-            // This expression might not be type-checked, and we have no hint.
-            // Try to query the context for a type anyway; we might get lucky
-            // (for example, if the expression was imported from another crate).
-            cx.tables.and_then(|tables| tables.expr_ty_opt(e))
-        }
+    let ety = cx.tables.expr_ty(e);
+
+    // Avoid applying substitutions if they're empty, that'd ICE.
+    let ety = if cx.substs.is_empty() {
+        ety
+    } else {
+        ety.subst(tcx, cx.substs)
     };
+
     let result = match e.node {
       hir::ExprUnary(hir::UnNeg, ref inner) => {
         // unary neg literals already got their sign during creation
@@ -465,28 +376,28 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
             const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
             const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
             const I128_OVERFLOW: u128 = i128::min_value() as u128;
-            match (&lit.node, ety.map(|t| &t.sty)) {
-                (&LitKind::Int(I8_OVERFLOW, _), Some(&ty::TyInt(IntTy::I8))) |
+            match (&lit.node, &ety.sty) {
+                (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) |
                 (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
                     return Ok(Integral(I8(i8::min_value())))
                 },
-                (&LitKind::Int(I16_OVERFLOW, _), Some(&ty::TyInt(IntTy::I16))) |
+                (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) |
                 (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
                     return Ok(Integral(I16(i16::min_value())))
                 },
-                (&LitKind::Int(I32_OVERFLOW, _), Some(&ty::TyInt(IntTy::I32))) |
+                (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) |
                 (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
                     return Ok(Integral(I32(i32::min_value())))
                 },
-                (&LitKind::Int(I64_OVERFLOW, _), Some(&ty::TyInt(IntTy::I64))) |
+                (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) |
                 (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
                     return Ok(Integral(I64(i64::min_value())))
                 },
-                (&LitKind::Int(I128_OVERFLOW, _), Some(&ty::TyInt(IntTy::I128))) |
+                (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) |
                 (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => {
                     return Ok(Integral(I128(i128::min_value())))
                 },
-                (&LitKind::Int(n, _), Some(&ty::TyInt(IntTy::Is))) |
+                (&LitKind::Int(n, _), &ty::TyInt(IntTy::Is)) |
                 (&LitKind::Int(n, Signed(IntTy::Is)), _) => {
                     match tcx.sess.target.int_type {
                         IntTy::I16 => if n == I16_OVERFLOW {
@@ -498,20 +409,20 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                         IntTy::I64 => if n == I64_OVERFLOW {
                             return Ok(Integral(Isize(Is64(i64::min_value()))));
                         },
-                        _ => bug!(),
+                        _ => span_bug!(e.span, "typeck error")
                     }
                 },
                 _ => {},
             }
         }
-        match cx.eval(inner, ty_hint)? {
+        match cx.eval(inner)? {
           Float(f) => Float(-f),
           Integral(i) => Integral(math!(e, -i)),
           const_val => signal!(e, NegateOn(const_val)),
         }
       }
       hir::ExprUnary(hir::UnNot, ref inner) => {
-        match cx.eval(inner, ty_hint)? {
+        match cx.eval(inner)? {
           Integral(i) => Integral(math!(e, !i)),
           Bool(b) => Bool(!b),
           const_val => signal!(e, NotOn(const_val)),
@@ -519,16 +430,11 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
       }
       hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")),
       hir::ExprBinary(op, ref a, ref b) => {
-        let b_ty = match op.node {
-            hir::BiShl | hir::BiShr => ty_hint.erase_hint(),
-            _ => ty_hint
-        };
         // technically, if we don't have type hints, but integral eval
         // gives us a type through a type-suffix, cast or const def type
         // we need to re-eval the other value of the BinOp if it was
         // not inferred
-        match (cx.eval(a, ty_hint)?,
-               cx.eval(b, b_ty)?) {
+        match (cx.eval(a)?, cx.eval(b)?) {
           (Float(a), Float(b)) => {
             use std::cmp::Ordering::*;
             match op.node {
@@ -543,7 +449,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
               hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
               hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
               hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
-              _ => signal!(e, InvalidOpForFloats(op.node)),
+              _ => span_bug!(e.span, "typeck error"),
             }
           }
           (Integral(a), Integral(b)) => {
@@ -565,7 +471,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
               hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
               hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
               hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
-              _ => signal!(e, InvalidOpForInts(op.node)),
+              _ => span_bug!(e.span, "typeck error"),
             }
           }
           (Bool(a), Bool(b)) => {
@@ -581,90 +487,57 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
               hir::BiLe => a <= b,
               hir::BiGe => a >= b,
               hir::BiGt => a > b,
-              _ => signal!(e, InvalidOpForBools(op.node)),
+              _ => span_bug!(e.span, "typeck error"),
              })
           }
 
           _ => signal!(e, MiscBinaryOp),
         }
       }
-      hir::ExprCast(ref base, ref target_ty) => {
-        let ety = tcx.ast_ty_to_prim_ty(&target_ty).or(ety)
-                .unwrap_or_else(|| {
-                    tcx.sess.span_fatal(target_ty.span,
-                                        "target type not found for const cast")
-                });
-
-        let base_hint = if let ExprTypeChecked = ty_hint {
-            ExprTypeChecked
-        } else {
-            match cx.tables.and_then(|tables| tables.expr_ty_opt(&base)) {
-                Some(t) => UncheckedExprHint(t),
-                None => ty_hint
-            }
-        };
-
-        let val = match cx.eval(base, base_hint) {
-            Ok(val) => val,
-            Err(ConstEvalErr { kind: ErroneousReferencedConstant(
-                box ConstEvalErr { kind: TypeMismatch(_, val), .. }), .. }) |
-            Err(ConstEvalErr { kind: TypeMismatch(_, val), .. }) => {
-                // Something like `5i8 as usize` doesn't need a type hint for the base
-                // instead take the type hint from the inner value
-                let hint = match val.int_type() {
-                    Some(IntType::UnsignedInt(ty)) => ty_hint.checked_or(tcx.mk_mach_uint(ty)),
-                    Some(IntType::SignedInt(ty)) => ty_hint.checked_or(tcx.mk_mach_int(ty)),
-                    // we had a type hint, so we can't have an unknown type
-                    None => bug!(),
-                };
-                cx.eval(base, hint)?
-            },
-            Err(e) => return Err(e),
-        };
-        match cast_const(tcx, val, ety) {
+      hir::ExprCast(ref base, _) => {
+        match cast_const(tcx, cx.eval(base)?, ety) {
             Ok(val) => val,
             Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
         }
       }
       hir::ExprPath(ref qpath) => {
-          let def = cx.tables.map(|tables| tables.qpath_def(qpath, e.id)).unwrap_or_else(|| {
-            // There are no tables so we can only handle already-resolved HIR.
-            match *qpath {
-                hir::QPath::Resolved(_, ref path) => path.def,
-                hir::QPath::TypeRelative(..) => Def::Err
-            }
-          });
-          match def {
+        let substs = cx.tables.node_id_item_substs(e.id)
+            .unwrap_or_else(|| tcx.intern_substs(&[]));
+
+        // Avoid applying substitutions if they're empty, that'd ICE.
+        let substs = if cx.substs.is_empty() {
+            substs
+        } else {
+            substs.subst(tcx, cx.substs)
+        };
+
+          match cx.tables.qpath_def(qpath, e.id) {
               Def::Const(def_id) |
               Def::AssociatedConst(def_id) => {
-                  let substs = if let ExprTypeChecked = ty_hint {
-                      Some(cx.tables.and_then(|tables| tables.node_id_item_substs(e.id))
-                        .unwrap_or_else(|| tcx.intern_substs(&[])))
-                  } else {
-                      None
-                  };
-                  if let Some((expr, tables, ty)) = lookup_const_by_id(tcx, def_id, substs) {
-                      let item_hint = match ty {
-                          Some(ty) => ty_hint.checked_or(ty),
-                          None => ty_hint,
-                      };
-                      let cx = ConstContext { tcx: tcx, tables: tables, fn_args: None };
-                      match cx.eval(expr, item_hint) {
+                  if let Some((expr, tables)) = lookup_const_by_id(tcx, def_id, substs) {
+                      let cx = ConstContext::with_tables(tcx, tables);
+                      match cx.eval(expr) {
                           Ok(val) => val,
+                          Err(ConstEvalErr { kind: TypeckError, .. }) => {
+                              signal!(e, TypeckError);
+                          }
                           Err(err) => {
                               debug!("bad reference: {:?}, {:?}", err.description(), err.span);
                               signal!(e, ErroneousReferencedConstant(box err))
                           },
                       }
                   } else {
-                      signal!(e, NonConstPath);
+                      signal!(e, TypeckError);
                   }
               },
               Def::VariantCtor(variant_def, ..) => {
                   if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) {
-                      let cx = ConstContext { tcx: tcx, tables: tables, fn_args: None };
-                      match cx.eval(expr, ty_hint) {
+                      let cx = ConstContext::with_tables(tcx, tables);
+                      match cx.eval(expr) {
                           Ok(val) => val,
+                          Err(ConstEvalErr { kind: TypeckError, .. }) => {
+                              signal!(e, TypeckError);
+                          }
                           Err(err) => {
                               debug!("bad reference: {:?}, {:?}", err.description(), err.span);
                               signal!(e, ErroneousReferencedConstant(box err))
@@ -685,16 +558,14 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                       signal!(e, NonConstPath);
                   }
               },
-              Def::Method(id) | Def::Fn(id) => Function(id),
-              Def::Err => signal!(e, UnresolvedPath),
+              Def::Method(id) | Def::Fn(id) => Function(id, substs),
+              Def::Err => span_bug!(e.span, "typeck error"),
               _ => signal!(e, NonConstPath),
           }
       }
       hir::ExprCall(ref callee, ref args) => {
-          let sub_ty_hint = ty_hint.erase_hint();
-          let callee_val = cx.eval(callee, sub_ty_hint)?;
-          let did = match callee_val {
-              Function(did) => did,
+          let (did, substs) = match cx.eval(callee)? {
+              Function(did, substs) => (did, substs),
               Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
               callee => signal!(e, CallOn(callee)),
           };
@@ -711,8 +582,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
 
           let mut call_args = DefIdMap();
           for (arg, arg_expr) in arg_defs.into_iter().zip(args.iter()) {
-              let arg_hint = ty_hint.erase_hint();
-              let arg_val = cx.eval(arg_expr, arg_hint)?;
+              let arg_val = cx.eval(arg_expr)?;
               debug!("const call arg: {:?}", arg);
               if let Some(def_id) = arg {
                 assert!(call_args.insert(def_id, arg_val).is_none());
@@ -722,9 +592,10 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
           let callee_cx = ConstContext {
             tcx: tcx,
             tables: tables,
+            substs: substs,
             fn_args: Some(call_args)
           };
-          callee_cx.eval(&body.value, ty_hint)?
+          callee_cx.eval(&body.value)?
       },
       hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
           Ok(val) => val,
@@ -732,32 +603,27 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
       },
       hir::ExprBlock(ref block) => {
         match block.expr {
-            Some(ref expr) => cx.eval(expr, ty_hint)?,
-            None => signal!(e, UnimplementedConstVal("empty block")),
+            Some(ref expr) => cx.eval(expr)?,
+            None => Tuple(vec![]),
         }
       }
-      hir::ExprType(ref e, _) => cx.eval(e, ty_hint)?,
+      hir::ExprType(ref e, _) => cx.eval(e)?,
       hir::ExprTup(ref fields) => {
-        let field_hint = ty_hint.erase_hint();
-        Tuple(fields.iter().map(|e| cx.eval(e, field_hint)).collect::<Result<_, _>>()?)
+        Tuple(fields.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
       }
       hir::ExprStruct(_, ref fields, _) => {
-        let field_hint = ty_hint.erase_hint();
         Struct(fields.iter().map(|f| {
-            cx.eval(&f.expr, field_hint).map(|v| (f.name.node, v))
+            cx.eval(&f.expr).map(|v| (f.name.node, v))
         }).collect::<Result<_, _>>()?)
       }
       hir::ExprIndex(ref arr, ref idx) => {
         if !tcx.sess.features.borrow().const_indexing {
             signal!(e, IndexOpFeatureGated);
         }
-        let arr_hint = ty_hint.erase_hint();
-        let arr = cx.eval(arr, arr_hint)?;
-        let idx_hint = ty_hint.checked_or(tcx.types.usize);
-        let idx = match cx.eval(idx, idx_hint)? {
+        let arr = cx.eval(arr)?;
+        let idx = match cx.eval(idx)? {
             Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
-            Integral(_) => bug!(),
-            _ => signal!(idx, IndexNotInt),
+            _ => signal!(idx, IndexNotUsize),
         };
         assert_eq!(idx as usize as u64, idx);
         match arr {
@@ -787,45 +653,25 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
         }
       }
       hir::ExprArray(ref v) => {
-        let elem_hint = ty_hint.erase_hint();
-        Array(v.iter().map(|e| cx.eval(e, elem_hint)).collect::<Result<_, _>>()?)
+        Array(v.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
       }
-      hir::ExprRepeat(ref elem, count) => {
-          let elem_hint = ty_hint.erase_hint();
-          let len_hint = ty_hint.checked_or(tcx.types.usize);
-          let n = if let Some(ty) = ety {
-            // For cross-crate constants, we have the type already,
-            // but not the body for `count`, so use the type.
-            match ty.sty {
-                ty::TyArray(_, n) => n as u64,
-                _ => bug!()
-            }
-          } else {
-            let n = &tcx.hir.body(count).value;
-            match ConstContext::new(tcx, count).eval(n, len_hint)? {
-                Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
-                Integral(_) => signal!(e, RepeatCountNotNatural),
-                _ => signal!(e, RepeatCountNotInt),
-            }
+      hir::ExprRepeat(ref elem, _) => {
+          let n = match ety.sty {
+            ty::TyArray(_, n) => n as u64,
+            _ => span_bug!(e.span, "typeck error")
           };
-          Repeat(Box::new(cx.eval(elem, elem_hint)?), n)
+          Repeat(Box::new(cx.eval(elem)?), n)
       },
       hir::ExprTupField(ref base, index) => {
-        let base_hint = ty_hint.erase_hint();
-        let c = cx.eval(base, base_hint)?;
+        let c = cx.eval(base)?;
         if let Tuple(ref fields) = c {
-            if let Some(elem) = fields.get(index.node) {
-                elem.clone()
-            } else {
-                signal!(e, TupleIndexOutOfBounds);
-            }
+            fields[index.node].clone()
         } else {
             signal!(base, ExpectedConstTuple);
         }
       }
       hir::ExprField(ref base, field_name) => {
-        let base_hint = ty_hint.erase_hint();
-        let c = cx.eval(base, base_hint)?;
+        let c = cx.eval(base)?;
         if let Struct(ref fields) = c {
             if let Some(f) = fields.get(&field_name.node) {
                 f.clone()
@@ -840,90 +686,23 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
       _ => signal!(e, MiscCatchAll)
     };
 
-    match (ety.map(|t| &t.sty), result) {
-        (Some(ref ty_hint), Integral(i)) => match infer(i, tcx, ty_hint) {
-            Ok(inferred) => Ok(Integral(inferred)),
-            Err(err) => signal!(e, err),
-        },
-        (_, result) => Ok(result),
-    }
-}
-
-fn infer<'a, 'tcx>(i: ConstInt,
-                   tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                   ty_hint: &ty::TypeVariants<'tcx>)
-                   -> Result<ConstInt, ErrKind> {
-    use syntax::ast::*;
-
-    match (ty_hint, i) {
-        (&ty::TyInt(IntTy::I8), result @ I8(_)) => Ok(result),
-        (&ty::TyInt(IntTy::I16), result @ I16(_)) => Ok(result),
-        (&ty::TyInt(IntTy::I32), result @ I32(_)) => Ok(result),
-        (&ty::TyInt(IntTy::I64), result @ I64(_)) => Ok(result),
-        (&ty::TyInt(IntTy::I128), result @ I128(_)) => Ok(result),
-        (&ty::TyInt(IntTy::Is), result @ Isize(_)) => Ok(result),
-
-        (&ty::TyUint(UintTy::U8), result @ U8(_)) => Ok(result),
-        (&ty::TyUint(UintTy::U16), result @ U16(_)) => Ok(result),
-        (&ty::TyUint(UintTy::U32), result @ U32(_)) => Ok(result),
-        (&ty::TyUint(UintTy::U64), result @ U64(_)) => Ok(result),
-        (&ty::TyUint(UintTy::U128), result @ U128(_)) => Ok(result),
-        (&ty::TyUint(UintTy::Us), result @ Usize(_)) => Ok(result),
-
-        (&ty::TyInt(IntTy::I8), Infer(i)) => Ok(I8(i as i128 as i8)),
-        (&ty::TyInt(IntTy::I16), Infer(i)) => Ok(I16(i as i128 as i16)),
-        (&ty::TyInt(IntTy::I32), Infer(i)) => Ok(I32(i as i128 as i32)),
-        (&ty::TyInt(IntTy::I64), Infer(i)) => Ok(I64(i as i128 as i64)),
-        (&ty::TyInt(IntTy::I128), Infer(i)) => Ok(I128(i as i128)),
-        (&ty::TyInt(IntTy::Is), Infer(i)) => {
-            Ok(Isize(ConstIsize::new_truncating(i as i128, tcx.sess.target.int_type)))
-        },
-
-        (&ty::TyInt(IntTy::I8), InferSigned(i)) => Ok(I8(i as i8)),
-        (&ty::TyInt(IntTy::I16), InferSigned(i)) => Ok(I16(i as i16)),
-        (&ty::TyInt(IntTy::I32), InferSigned(i)) => Ok(I32(i as i32)),
-        (&ty::TyInt(IntTy::I64), InferSigned(i)) => Ok(I64(i as i64)),
-        (&ty::TyInt(IntTy::I128), InferSigned(i)) => Ok(I128(i)),
-        (&ty::TyInt(IntTy::Is), InferSigned(i)) => {
-            Ok(Isize(ConstIsize::new_truncating(i, tcx.sess.target.int_type)))
-        },
-
-        (&ty::TyUint(UintTy::U8), Infer(i)) => Ok(U8(i as u8)),
-        (&ty::TyUint(UintTy::U16), Infer(i)) => Ok(U16(i as u16)),
-        (&ty::TyUint(UintTy::U32), Infer(i)) => Ok(U32(i as u32)),
-        (&ty::TyUint(UintTy::U64), Infer(i)) => Ok(U64(i as u64)),
-        (&ty::TyUint(UintTy::U128), Infer(i)) => Ok(U128(i)),
-        (&ty::TyUint(UintTy::Us), Infer(i)) => {
-            Ok(Usize(ConstUsize::new_truncating(i, tcx.sess.target.uint_type)))
-        },
-        (&ty::TyUint(_), InferSigned(_)) => Err(IntermediateUnsignedNegative),
-
-        (&ty::TyInt(ity), i) => Err(TypeMismatch(ity.to_string(), i)),
-        (&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)),
-
-        (&ty::TyAdt(adt, _), i) if adt.is_enum() => {
-            let hints = tcx.lookup_repr_hints(adt.did);
-            let int_ty = tcx.enum_repr_type(hints.iter().next());
-            infer(i, tcx, &int_ty.to_ty(tcx).sty)
-        },
-        (_, i) => Err(BadType(ConstVal::Integral(i))),
-    }
+    Ok(result)
 }
 
 fn resolve_trait_associated_const<'a, 'tcx: 'a>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     trait_item_id: DefId,
-    default_value: Option<(&'tcx Expr, Option<&'a ty::TypeckTables<'tcx>>, Option<ty::Ty<'tcx>>)>,
+    default_value: Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>,
     trait_id: DefId,
     rcvr_substs: &'tcx Substs<'tcx>
-) -> Option<(&'tcx Expr, Option<&'a ty::TypeckTables<'tcx>>, Option<ty::Ty<'tcx>>)>
+) -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>
 {
     let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs));
     debug!("resolve_trait_associated_const: trait_ref={:?}",
            trait_ref);
 
     tcx.populate_implementations_for_trait_if_necessary(trait_id);
-    tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
+    tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
         let mut selcx = traits::SelectionContext::new(&infcx);
         let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
                                                  trait_ref.to_poly_trait_predicate());
@@ -951,7 +730,7 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(
                 let ac = tcx.associated_items(impl_data.impl_def_id)
                     .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
                 match ac {
-                    Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
+                    Some(ic) => lookup_const_by_id(tcx, ic.def_id, Substs::empty()),
                     None => default_value,
                 }
             }
@@ -962,7 +741,10 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(
     })
 }
 
-fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstInt, ty: ty::Ty) -> CastResult {
+fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                            val: ConstInt,
+                            ty: Ty<'tcx>)
+                            -> CastResult<'tcx> {
     let v = val.to_u128_unchecked();
     match ty.sty {
         ty::TyBool if v == 0 => Ok(Bool(false)),
@@ -983,42 +765,31 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstInt, ty: ty::
         ty::TyUint(ast::UintTy::Us) => {
             Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type))))
         },
-        ty::TyFloat(ast::FloatTy::F64) => match val.erase_type() {
-            Infer(u) => Ok(Float(F64(u as f64))),
-            InferSigned(i) => Ok(Float(F64(i as f64))),
-            _ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"),
-        },
-        ty::TyFloat(ast::FloatTy::F32) => match val.erase_type() {
-            Infer(u) => Ok(Float(F32(u as f32))),
-            InferSigned(i) => Ok(Float(F32(i as f32))),
-            _ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"),
-        },
+        ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(val.to_f64()))),
+        ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(val.to_f32()))),
         ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
-        ty::TyChar => match infer(val, tcx, &ty::TyUint(ast::UintTy::U8)) {
-            Ok(U8(u)) => Ok(Char(u as char)),
-            // can only occur before typeck, typeck blocks `T as char` for `T` != `u8`
-            _ => Err(CharCast(val)),
+        ty::TyChar => match val {
+            U8(u) => Ok(Char(u as char)),
+            _ => bug!(),
         },
-        _ => Err(CannotCast),
+        _ => bug!(),
     }
 }
 
 fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                               val: ConstFloat,
-                              ty: ty::Ty) -> CastResult {
+                              ty: Ty<'tcx>) -> CastResult<'tcx> {
     match ty.sty {
         ty::TyInt(_) | ty::TyUint(_) => {
             let i = match val {
-                F32(f) if f >= 0.0 => Infer(f as u128),
-                FInfer { f64: f, .. } |
-                F64(f) if f >= 0.0 => Infer(f as u128),
+                F32(f) if f >= 0.0 => U128(f as u128),
+                F64(f) if f >= 0.0 => U128(f as u128),
 
-                F32(f) => InferSigned(f as i128),
-                FInfer { f64: f, .. } |
-                F64(f) => InferSigned(f as i128)
+                F32(f) => I128(f as i128),
+                F64(f) => I128(f as i128)
             };
 
-            if let (InferSigned(_), &ty::TyUint(_)) = (i, &ty.sty) {
+            if let (I128(_), &ty::TyUint(_)) = (i, &ty.sty) {
                 return Err(CannotCast);
             }
 
@@ -1026,23 +797,26 @@ fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
         ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(match val {
             F32(f) => f as f64,
-            FInfer { f64: f, .. } | F64(f) => f
+            F64(f) => f
         }))),
         ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(match val {
             F64(f) => f as f32,
-            FInfer { f32: f, .. } | F32(f) => f
+            F32(f) => f
         }))),
         _ => Err(CannotCast),
     }
 }
 
-fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstVal, ty: ty::Ty) -> CastResult {
+fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                        val: ConstVal<'tcx>,
+                        ty: Ty<'tcx>)
+                        -> CastResult<'tcx> {
     match val {
         Integral(i) => cast_const_int(tcx, i, ty),
-        Bool(b) => cast_const_int(tcx, Infer(b as u128), ty),
+        Bool(b) => cast_const_int(tcx, U8(b as u8), ty),
         Float(f) => cast_const_float(tcx, f, ty),
-        Char(c) => cast_const_int(tcx, Infer(c as u128), ty),
-        Function(_) => Err(UnimplementedConstVal("casting fn pointers")),
+        Char(c) => cast_const_int(tcx, U32(c as u32), ty),
+        Function(..) => Err(UnimplementedConstVal("casting fn pointers")),
         ByteStr(b) => match ty.sty {
             ty::TyRawPtr(_) => {
                 Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
@@ -1070,67 +844,56 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstVal, ty: ty::Ty)
 
 fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          ty_hint: Option<Ty<'tcx>>)
-                          -> Result<ConstVal, ErrKind> {
+                          mut ty: Ty<'tcx>)
+                          -> Result<ConstVal<'tcx>, ErrKind<'tcx>> {
     use syntax::ast::*;
     use syntax::ast::LitIntType::*;
+
+    if let ty::TyAdt(adt, _) = ty.sty {
+        if adt.is_enum() {
+            ty = adt.repr.discr_type().to_ty(tcx)
+        }
+    }
+
     match *lit {
         LitKind::Str(ref s, _) => Ok(Str(s.as_str())),
         LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())),
         LitKind::Byte(n) => Ok(Integral(U8(n))),
-        LitKind::Int(n, Signed(ity)) => {
-            infer(InferSigned(n as i128), tcx, &ty::TyInt(ity)).map(Integral)
-        },
-
-        // FIXME: this should become u128.
-        LitKind::Int(n, Unsuffixed) => {
-            match ty_hint.map(|t| &t.sty) {
-                Some(&ty::TyInt(ity)) => {
-                    infer(InferSigned(n as i128), tcx, &ty::TyInt(ity)).map(Integral)
-                },
-                Some(&ty::TyUint(uty)) => {
-                    infer(Infer(n as u128), tcx, &ty::TyUint(uty)).map(Integral)
-                },
-                None => Ok(Integral(Infer(n as u128))),
-                Some(&ty::TyAdt(adt, _)) => {
-                    let hints = tcx.lookup_repr_hints(adt.did);
-                    let int_ty = tcx.enum_repr_type(hints.iter().next());
-                    infer(Infer(n as u128), tcx, &int_ty.to_ty(tcx).sty).map(Integral)
-                },
-                Some(ty_hint) => bug!("bad ty_hint: {:?}, {:?}", ty_hint, lit),
+        LitKind::Int(n, hint) => {
+            match (&ty.sty, hint) {
+                (&ty::TyInt(ity), _) |
+                (_, Signed(ity)) => {
+                    Ok(Integral(ConstInt::new_signed_truncating(n as i128,
+                        ity, tcx.sess.target.int_type)))
+                }
+                (&ty::TyUint(uty), _) |
+                (_, Unsigned(uty)) => {
+                    Ok(Integral(ConstInt::new_unsigned_truncating(n as u128,
+                        uty, tcx.sess.target.uint_type)))
+                }
+                _ => bug!()
             }
-        },
-        LitKind::Int(n, Unsigned(ity)) => {
-            infer(Infer(n as u128), tcx, &ty::TyUint(ity)).map(Integral)
-        },
-
+        }
         LitKind::Float(n, fty) => {
-            parse_float(&n.as_str(), Some(fty)).map(Float)
+            parse_float(&n.as_str(), fty).map(Float)
         }
         LitKind::FloatUnsuffixed(n) => {
-            let fty_hint = match ty_hint.map(|t| &t.sty) {
-                Some(&ty::TyFloat(fty)) => Some(fty),
-                _ => None
+            let fty = match ty.sty {
+                ty::TyFloat(fty) => fty,
+                _ => bug!()
             };
-            parse_float(&n.as_str(), fty_hint).map(Float)
+            parse_float(&n.as_str(), fty).map(Float)
         }
         LitKind::Bool(b) => Ok(Bool(b)),
         LitKind::Char(c) => Ok(Char(c)),
     }
 }
 
-fn parse_float(num: &str, fty_hint: Option<ast::FloatTy>)
-               -> Result<ConstFloat, ErrKind> {
-    let val = match fty_hint {
-        Some(ast::FloatTy::F32) => num.parse::<f32>().map(F32),
-        Some(ast::FloatTy::F64) => num.parse::<f64>().map(F64),
-        None => {
-            num.parse::<f32>().and_then(|f32| {
-                num.parse::<f64>().map(|f64| {
-                    FInfer { f32: f32, f64: f64 }
-                })
-            })
-        }
+fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
+                     -> Result<ConstFloat, ErrKind<'tcx>> {
+    let val = match fty {
+        ast::FloatTy::F32 => num.parse::<f32>().map(F32),
+        ast::FloatTy::F64 => num.parse::<f64>().map(F64)
     };
     val.map_err(|_| {
         // FIXME(#31407) this is only necessary because float parsing is buggy
@@ -1170,17 +933,17 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> {
                              a: &Expr,
                              b: &Expr) -> Result<Ordering, ErrorReported> {
         let tcx = self.tcx;
-        let a = match self.eval(a, ExprTypeChecked) {
+        let a = match self.eval(a) {
             Ok(a) => a,
             Err(e) => {
-                report_const_eval_err(tcx, &e, a.span, "expression").emit();
+                report_const_eval_err(tcx, &e, a.span, "expression");
                 return Err(ErrorReported);
             }
         };
-        let b = match self.eval(b, ExprTypeChecked) {
+        let b = match self.eval(b) {
             Ok(b) => b,
             Err(e) => {
-                report_const_eval_err(tcx, &e, b.span, "expression").emit();
+                report_const_eval_err(tcx, &e, b.span, "expression");
                 return Err(ErrorReported);
             }
         };
@@ -1195,26 +958,17 @@ pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              reason: &str)
                              -> Result<usize, ErrorReported>
 {
-    let hint = UncheckedExprHint(tcx.types.usize);
     let count_expr = &tcx.hir.body(count).value;
-    match ConstContext::new(tcx, count).eval(count_expr, hint) {
+    match ConstContext::new(tcx, count).eval(count_expr) {
         Ok(Integral(Usize(count))) => {
             let val = count.as_u64(tcx.sess.target.uint_type);
             assert_eq!(val as usize as u64, val);
             Ok(val as usize)
         },
-        Ok(const_val) => {
-            struct_span_err!(tcx.sess, count_expr.span, E0306,
-                             "expected `usize` for {}, found {}",
-                             reason,
-                             const_val.description())
-                .span_label(count_expr.span, &format!("expected `usize`"))
-                .emit();
-
-            Err(ErrorReported)
-        }
+        Ok(_) |
+        Err(ConstEvalErr { kind: TypeckError, .. }) => Err(ErrorReported),
         Err(err) => {
-            let mut diag = report_const_eval_err(
+            let mut diag = build_const_eval_err(
                 tcx, &err, count_expr.span, reason);
 
             if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node {
diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs
index 198e49daabc..4434a901f94 100644
--- a/src/librustc_const_eval/lib.rs
+++ b/src/librustc_const_eval/lib.rs
@@ -21,6 +21,7 @@
 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![deny(warnings)]
 
 #![feature(rustc_private)]
 #![feature(staged_api)]
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index 609fb3e39d6..72a47c00281 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -27,9 +27,9 @@ use syntax::ptr::P;
 use syntax_pos::Span;
 
 #[derive(Clone, Debug)]
-pub enum PatternError {
+pub enum PatternError<'tcx> {
     StaticInPattern(Span),
-    ConstEval(eval::ConstEvalErr),
+    ConstEval(eval::ConstEvalErr<'tcx>),
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -84,12 +84,12 @@ pub enum PatternKind<'tcx> {
     },
 
     Constant {
-        value: ConstVal,
+        value: ConstVal<'tcx>,
     },
 
     Range {
-        lo: ConstVal,
-        hi: ConstVal,
+        lo: ConstVal<'tcx>,
+        hi: ConstVal<'tcx>,
         end: RangeEnd,
     },
 
@@ -118,7 +118,7 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
         ConstVal::Char(c) => write!(f, "{:?}", c),
         ConstVal::Struct(_) |
         ConstVal::Tuple(_) |
-        ConstVal::Function(_) |
+        ConstVal::Function(..) |
         ConstVal::Array(..) |
         ConstVal::Repeat(..) => bug!("{:?} not printable in a pattern", value)
     }
@@ -265,7 +265,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
 pub struct PatternContext<'a, 'gcx: 'tcx, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
     pub tables: &'a ty::TypeckTables<'gcx>,
-    pub errors: Vec<PatternError>,
+    pub errors: Vec<PatternError<'tcx>>,
 }
 
 impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
@@ -582,11 +582,11 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
                 let tcx = self.tcx.global_tcx();
                 let substs = self.tables.node_id_item_substs(id)
                     .unwrap_or_else(|| tcx.intern_substs(&[]));
-                match eval::lookup_const_by_id(tcx, def_id, Some(substs)) {
-                    Some((const_expr, const_tables, _const_ty)) => {
+                match eval::lookup_const_by_id(tcx, def_id, substs) {
+                    Some((const_expr, const_tables)) => {
                         // Enter the inlined constant's tables temporarily.
                         let old_tables = self.tables;
-                        self.tables = const_tables.expect("missing tables after typeck");
+                        self.tables = const_tables;
                         let pat = self.lower_const_expr(const_expr, pat_id, span);
                         self.tables = old_tables;
                         return pat;
@@ -609,7 +609,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
 
     fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> {
         let const_cx = eval::ConstContext::with_tables(self.tcx.global_tcx(), self.tables);
-        match const_cx.eval(expr, eval::EvalHint::ExprTypeChecked) {
+        match const_cx.eval(expr) {
             Ok(value) => {
                 PatternKind::Constant { value: value }
             }
@@ -796,7 +796,7 @@ macro_rules! CloneImpls {
 }
 
 CloneImpls!{ <'tcx>
-    Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal, Region,
+    Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal<'tcx>, Region,
     Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
     &'tcx Substs<'tcx>, &'tcx Kind<'tcx>
 }
diff --git a/src/librustc_const_math/float.rs b/src/librustc_const_math/float.rs
index 4610c183e1b..f557edffbda 100644
--- a/src/librustc_const_math/float.rs
+++ b/src/librustc_const_math/float.rs
@@ -17,13 +17,7 @@ use super::err::*;
 #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
 pub enum ConstFloat {
     F32(f32),
-    F64(f64),
-
-    // When the type isn't known, we have to operate on both possibilities.
-    FInfer {
-        f32: f32,
-        f64: f64
-    }
+    F64(f64)
 }
 pub use self::ConstFloat::*;
 
@@ -31,7 +25,6 @@ impl ConstFloat {
     /// Description of the type, not the value
     pub fn description(&self) -> &'static str {
         match *self {
-            FInfer {..} => "float",
             F32(_) => "f32",
             F64(_) => "f64",
         }
@@ -41,17 +34,13 @@ impl ConstFloat {
         match *self {
             F32(f) => f.is_nan(),
             F64(f) => f.is_nan(),
-            FInfer { f32, f64 } => f32.is_nan() || f64.is_nan()
         }
     }
 
     /// Compares the values if they are of the same type
     pub fn try_cmp(self, rhs: Self) -> Result<Ordering, ConstMathErr> {
         match (self, rhs) {
-            (F64(a), F64(b)) |
-            (F64(a), FInfer { f64: b, .. }) |
-            (FInfer { f64: a, .. }, F64(b)) |
-            (FInfer { f64: a, .. }, FInfer { f64: b, .. })  => {
+            (F64(a), F64(b))  => {
                 // This is pretty bad but it is the existing behavior.
                 Ok(if a == b {
                     Ordering::Equal
@@ -62,9 +51,7 @@ impl ConstFloat {
                 })
             }
 
-            (F32(a), F32(b)) |
-            (F32(a), FInfer { f32: b, .. }) |
-            (FInfer { f32: a, .. }, F32(b)) => {
+            (F32(a), F32(b)) => {
                 Ok(if a == b {
                     Ordering::Equal
                 } else if a < b {
@@ -86,10 +73,7 @@ impl ConstFloat {
 impl PartialEq for ConstFloat {
     fn eq(&self, other: &Self) -> bool {
         match (*self, *other) {
-            (F64(a), F64(b)) |
-            (F64(a), FInfer { f64: b, .. }) |
-            (FInfer { f64: a, .. }, F64(b)) |
-            (FInfer { f64: a, .. }, FInfer { f64: b, .. }) => {
+            (F64(a), F64(b)) => {
                 unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)}
             }
             (F32(a), F32(b)) => {
@@ -105,7 +89,7 @@ impl Eq for ConstFloat {}
 impl hash::Hash for ConstFloat {
     fn hash<H: hash::Hasher>(&self, state: &mut H) {
         match *self {
-            F64(a) | FInfer { f64: a, .. } => {
+            F64(a) => {
                 unsafe { transmute::<_,u64>(a) }.hash(state)
             }
             F32(a) => {
@@ -118,7 +102,6 @@ impl hash::Hash for ConstFloat {
 impl ::std::fmt::Display for ConstFloat {
     fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
         match *self {
-            FInfer { f64, .. } => write!(fmt, "{}", f64),
             F32(f) => write!(fmt, "{}f32", f),
             F64(f) => write!(fmt, "{}f64", f),
         }
@@ -131,20 +114,8 @@ macro_rules! derive_binop {
             type Output = Result<Self, ConstMathErr>;
             fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
                 match (self, rhs) {
-                    (F32(a), F32(b)) |
-                    (F32(a), FInfer { f32: b, .. }) |
-                    (FInfer { f32: a, .. }, F32(b)) => Ok(F32(a.$func(b))),
-
-                    (F64(a), F64(b)) |
-                    (FInfer { f64: a, .. }, F64(b)) |
-                    (F64(a), FInfer { f64: b, .. }) => Ok(F64(a.$func(b))),
-
-                    (FInfer { f32: a32, f64: a64 },
-                     FInfer { f32: b32, f64: b64 }) => Ok(FInfer {
-                        f32: a32.$func(b32),
-                        f64: a64.$func(b64)
-                    }),
-
+                    (F32(a), F32(b)) => Ok(F32(a.$func(b))),
+                    (F64(a), F64(b)) => Ok(F64(a.$func(b))),
                     _ => Err(UnequalTypes(Op::$op)),
                 }
             }
@@ -164,10 +135,6 @@ impl ::std::ops::Neg for ConstFloat {
         match self {
             F32(f) => F32(-f),
             F64(f) => F64(-f),
-            FInfer { f32, f64 } => FInfer {
-                f32: -f32,
-                f64: -f64
-            }
         }
     }
 }
diff --git a/src/librustc_const_math/int.rs b/src/librustc_const_math/int.rs
index bc3809db1c6..d97276da9bf 100644
--- a/src/librustc_const_math/int.rs
+++ b/src/librustc_const_math/int.rs
@@ -30,8 +30,6 @@ pub enum ConstInt {
     U64(u64),
     U128(u128),
     Usize(ConstUsize),
-    Infer(u128),
-    InferSigned(i128),
 }
 pub use self::ConstInt::*;
 
@@ -77,14 +75,6 @@ mod ibounds {
 }
 
 impl ConstInt {
-    pub fn new_inttype(val: u128, ty: IntType, usize_ty: UintTy, isize_ty: IntTy)
-    -> Option<ConstInt> {
-        match ty {
-            IntType::SignedInt(i) => ConstInt::new_signed(val as i128, i, isize_ty),
-            IntType::UnsignedInt(i) => ConstInt::new_unsigned(val, i, usize_ty),
-        }
-    }
-
     /// Creates a new unsigned ConstInt with matching type while also checking that overflow does
     /// not happen.
     pub fn new_unsigned(val: u128, ty: UintTy, usize_ty: UintTy) -> Option<ConstInt> {
@@ -100,7 +90,7 @@ impl ConstInt {
         }
     }
 
-    /// Creates a new unsigned ConstInt with matching type while also checking that overflow does
+    /// Creates a new signed ConstInt with matching type while also checking that overflow does
     /// not happen.
     pub fn new_signed(val: i128, ty: IntTy, isize_ty: IntTy) -> Option<ConstInt> {
         match ty {
@@ -115,103 +105,33 @@ impl ConstInt {
         }
     }
 
-    /// If either value is `Infer` or `InferSigned`, try to turn the value into the type of
-    /// the other value. If both values have no type, don't do anything
-    pub fn infer(self, other: Self) -> Result<(Self, Self), ConstMathErr> {
-        let inferred = match (self, other) {
-            (InferSigned(_), InferSigned(_))
-            | (Infer(_), Infer(_)) => self, // no inference possible
-            // kindof wrong, you could have had values > I64MAX during computation of a
-            (Infer(a @ 0...ubounds::I64MAX), InferSigned(_)) => InferSigned(a as i128),
-            (Infer(_), InferSigned(_)) => return Err(ConstMathErr::NotInRange),
-            (_, InferSigned(_))
-            | (_, Infer(_)) => return other.infer(self).map(|(b, a)| (a, b)),
-
-            (Infer(a @ 0...ubounds::I8MAX), I8(_)) => I8(a as i64 as i8),
-            (Infer(a @ 0...ubounds::I16MAX), I16(_)) => I16(a as i64 as i16),
-            (Infer(a @ 0...ubounds::I32MAX), I32(_)) => I32(a as i64 as i32),
-            (Infer(a @ 0...ubounds::I64MAX), I64(_)) => I64(a as i64),
-            (Infer(a @ 0...ubounds::I128MAX), I128(_)) => I128(a as i128),
-            (Infer(a @ 0...ubounds::I16MAX), Isize(Is16(_))) => Isize(Is16(a as i64 as i16)),
-            (Infer(a @ 0...ubounds::I32MAX), Isize(Is32(_))) => Isize(Is32(a as i64 as i32)),
-            (Infer(a @ 0...ubounds::I64MAX), Isize(Is64(_))) => Isize(Is64(a as i64)),
-            (Infer(a @ 0...ubounds::U8MAX), U8(_)) => U8(a as u8),
-            (Infer(a @ 0...ubounds::U16MAX), U16(_)) => U16(a as u16),
-            (Infer(a @ 0...ubounds::U32MAX), U32(_)) => U32(a as u32),
-            (Infer(a @ 0...ubounds::U64MAX), U64(_)) => U64(a as u64),
-            (Infer(a @ 0...ubounds::U128MAX), U128(_)) => U128(a as u128),
-            (Infer(a @ 0...ubounds::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)),
-            (Infer(a @ 0...ubounds::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)),
-            (Infer(a @ 0...ubounds::U64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)),
-
-            (Infer(_), _) => return Err(ConstMathErr::NotInRange),
-
-            (InferSigned(a @ ibounds::I8MIN...ibounds::I8MAX), I8(_)) => I8(a as i8),
-            (InferSigned(a @ ibounds::I16MIN...ibounds::I16MAX), I16(_)) => I16(a as i16),
-            (InferSigned(a @ ibounds::I32MIN...ibounds::I32MAX), I32(_)) => I32(a as i32),
-            (InferSigned(a @ ibounds::I64MIN...ibounds::I64MAX), I64(_)) => I64(a as i64),
-            (InferSigned(a @ ibounds::I128MIN...ibounds::I128MAX), I128(_)) => I128(a as i128),
-            (InferSigned(a @ ibounds::I16MIN...ibounds::I16MAX), Isize(Is16(_))) => {
-                Isize(Is16(a as i16))
-            },
-            (InferSigned(a @ ibounds::I32MIN...ibounds::I32MAX), Isize(Is32(_))) => {
-                Isize(Is32(a as i32))
-            },
-            (InferSigned(a @ ibounds::I64MIN...ibounds::I64MAX), Isize(Is64(_))) => {
-                Isize(Is64(a as i64))
-            },
-            (InferSigned(a @ 0...ibounds::U8MAX), U8(_)) => U8(a as u8),
-            (InferSigned(a @ 0...ibounds::U16MAX), U16(_)) => U16(a as u16),
-            (InferSigned(a @ 0...ibounds::U32MAX), U32(_)) => U32(a as u32),
-            (InferSigned(a @ 0...ibounds::U64MAX), U64(_)) => U64(a as u64),
-            (InferSigned(a @ 0...ibounds::I128MAX), U128(_)) => U128(a as u128),
-            (InferSigned(a @ 0...ibounds::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)),
-            (InferSigned(a @ 0...ibounds::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)),
-            (InferSigned(a @ 0...ibounds::U64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)),
-            (InferSigned(_), _) => return Err(ConstMathErr::NotInRange),
-            _ => self, // already known types
-        };
-        Ok((inferred, other))
+    /// Creates a new unsigned ConstInt with matching type.
+    pub fn new_unsigned_truncating(val: u128, ty: UintTy, usize_ty: UintTy) -> ConstInt {
+        match ty {
+            UintTy::U8 => U8(val as u8),
+            UintTy::U16 => U16(val as u16),
+            UintTy::U32 => U32(val as u32),
+            UintTy::U64 => U64(val as u64),
+            UintTy::Us => Usize(ConstUsize::new_truncating(val, usize_ty)),
+            UintTy::U128 => U128(val)
+        }
     }
 
-    /// Turn this value into an `Infer` or an `InferSigned`
-    pub fn erase_type(self) -> Self {
-        match self {
-            Infer(i) => Infer(i),
-            InferSigned(i) if i < 0 => InferSigned(i),
-            I8(i) if i < 0 => InferSigned(i as i128),
-            I16(i) if i < 0 => InferSigned(i as i128),
-            I32(i) if i < 0 => InferSigned(i as i128),
-            I64(i) if i < 0 => InferSigned(i as i128),
-            I128(i) if i < 0 => InferSigned(i as i128),
-            Isize(Is16(i)) if i < 0 => InferSigned(i as i128),
-            Isize(Is32(i)) if i < 0 => InferSigned(i as i128),
-            Isize(Is64(i)) if i < 0 => InferSigned(i as i128),
-            InferSigned(i) => Infer(i as u128),
-            I8(i) => Infer(i as u128),
-            I16(i) => Infer(i as u128),
-            I32(i) => Infer(i as u128),
-            I64(i) => Infer(i as u128),
-            I128(i) => Infer(i as u128),
-            Isize(Is16(i)) => Infer(i as u128),
-            Isize(Is32(i)) => Infer(i as u128),
-            Isize(Is64(i)) => Infer(i as u128),
-            U8(i) => Infer(i as u128),
-            U16(i) => Infer(i as u128),
-            U32(i) => Infer(i as u128),
-            U64(i) => Infer(i as u128),
-            U128(i) => Infer(i as u128),
-            Usize(Us16(i)) => Infer(i as u128),
-            Usize(Us32(i)) => Infer(i as u128),
-            Usize(Us64(i)) => Infer(i as u128),
+    /// Creates a new signed ConstInt with matching type.
+    pub fn new_signed_truncating(val: i128, ty: IntTy, isize_ty: IntTy) -> ConstInt {
+        match ty {
+            IntTy::I8 => I8(val as i8),
+            IntTy::I16 => I16(val as i16),
+            IntTy::I32 => I32(val as i32),
+            IntTy::I64 => I64(val as i64),
+            IntTy::Is => Isize(ConstIsize::new_truncating(val, isize_ty)),
+            IntTy::I128 => I128(val)
         }
     }
 
     /// Description of the type, not the value
     pub fn description(&self) -> &'static str {
         match *self {
-            Infer(_) => "not yet inferred integral",
-            InferSigned(_) => "not yet inferred signed integral",
             I8(_) => "i8",
             I16(_) => "i16",
             I32(_) => "i32",
@@ -230,10 +150,23 @@ impl ConstInt {
     /// Erases the type and returns a u128.
     /// This is not the same as `-5i8 as u128` but as `-5i8 as i128 as u128`
     pub fn to_u128_unchecked(self) -> u128 {
-        match self.erase_type() {
-            ConstInt::Infer(i) => i,
-            ConstInt::InferSigned(i) => i as u128,
-            _ => unreachable!(),
+        match self {
+            I8(i) => i as i128 as u128,
+            I16(i) => i as i128 as u128,
+            I32(i) => i as i128 as u128,
+            I64(i) => i as i128 as u128,
+            I128(i) => i as i128 as u128,
+            Isize(Is16(i)) => i as i128 as u128,
+            Isize(Is32(i)) => i as i128 as u128,
+            Isize(Is64(i)) => i as i128 as u128,
+            U8(i) => i as u128,
+            U16(i) => i as u128,
+            U32(i) => i as u128,
+            U64(i) => i as u128,
+            U128(i) => i as u128,
+            Usize(Us16(i)) => i as u128,
+            Usize(Us32(i)) => i as u128,
+            Usize(Us64(i)) => i as u128,
         }
     }
 
@@ -258,8 +191,6 @@ impl ConstInt {
     /// Converts the value to a `u128` if it's in the range 0...std::u128::MAX
     pub fn to_u128(&self) -> Option<u128> {
         match *self {
-            Infer(v) => Some(v),
-            InferSigned(v) if v >= 0 => Some(v as u128),
             I8(v) if v >= 0 => Some(v as u128),
             I16(v) if v >= 0 => Some(v as u128),
             I32(v) if v >= 0 => Some(v as u128),
@@ -280,6 +211,48 @@ impl ConstInt {
         }
     }
 
+    pub fn to_f32(self) -> f32 {
+        match self {
+            I8(i) => i as f32,
+            I16(i) => i as f32,
+            I32(i) => i as f32,
+            I64(i) => i as f32,
+            I128(i) => i as f32,
+            Isize(Is16(i)) => i as f32,
+            Isize(Is32(i)) => i as f32,
+            Isize(Is64(i)) => i as f32,
+            U8(i) => i as f32,
+            U16(i) => i as f32,
+            U32(i) => i as f32,
+            U64(i) => i as f32,
+            U128(i) => i as f32,
+            Usize(Us16(i)) => i as f32,
+            Usize(Us32(i)) => i as f32,
+            Usize(Us64(i)) => i as f32,
+        }
+    }
+
+    pub fn to_f64(self) -> f64 {
+        match self {
+            I8(i) => i as f64,
+            I16(i) => i as f64,
+            I32(i) => i as f64,
+            I64(i) => i as f64,
+            I128(i) => i as f64,
+            Isize(Is16(i)) => i as f64,
+            Isize(Is32(i)) => i as f64,
+            Isize(Is64(i)) => i as f64,
+            U8(i) => i as f64,
+            U16(i) => i as f64,
+            U32(i) => i as f64,
+            U64(i) => i as f64,
+            U128(i) => i as f64,
+            Usize(Us16(i)) => i as f64,
+            Usize(Us32(i)) => i as f64,
+            Usize(Us64(i)) => i as f64,
+        }
+    }
+
     pub fn is_negative(&self) -> bool {
         match *self {
             I8(v) => v < 0,
@@ -290,14 +263,13 @@ impl ConstInt {
             Isize(Is16(v)) => v < 0,
             Isize(Is32(v)) => v < 0,
             Isize(Is64(v)) => v < 0,
-            InferSigned(v) => v < 0,
             _ => false,
         }
     }
 
     /// Compares the values if they are of the same type
     pub fn try_cmp(self, rhs: Self) -> Result<::std::cmp::Ordering, ConstMathErr> {
-        match self.infer(rhs)? {
+        match (self, rhs) {
             (I8(a), I8(b)) => Ok(a.cmp(&b)),
             (I16(a), I16(b)) => Ok(a.cmp(&b)),
             (I32(a), I32(b)) => Ok(a.cmp(&b)),
@@ -314,8 +286,6 @@ impl ConstInt {
             (Usize(Us16(a)), Usize(Us16(b))) => Ok(a.cmp(&b)),
             (Usize(Us32(a)), Usize(Us32(b))) => Ok(a.cmp(&b)),
             (Usize(Us64(a)), Usize(Us64(b))) => Ok(a.cmp(&b)),
-            (Infer(a), Infer(b)) => Ok(a.cmp(&b)),
-            (InferSigned(a), InferSigned(b)) => Ok(a.cmp(&b)),
             _ => Err(CmpBetweenUnequalTypes),
         }
     }
@@ -342,25 +312,23 @@ impl ConstInt {
             ConstInt::Usize(ConstUsize::Us16(i)) => ConstInt::Usize(ConstUsize::Us16(add1!(i))),
             ConstInt::Usize(ConstUsize::Us32(i)) => ConstInt::Usize(ConstUsize::Us32(add1!(i))),
             ConstInt::Usize(ConstUsize::Us64(i)) => ConstInt::Usize(ConstUsize::Us64(add1!(i))),
-            ConstInt::Infer(_) | ConstInt::InferSigned(_) => panic!("no type info for const int"),
         }
     }
 
-    pub fn int_type(self) -> Option<IntType> {
+    pub fn int_type(self) -> IntType {
         match self {
-            ConstInt::I8(_) => Some(IntType::SignedInt(IntTy::I8)),
-            ConstInt::I16(_) => Some(IntType::SignedInt(IntTy::I16)),
-            ConstInt::I32(_) => Some(IntType::SignedInt(IntTy::I32)),
-            ConstInt::I64(_) => Some(IntType::SignedInt(IntTy::I64)),
-            ConstInt::I128(_) => Some(IntType::SignedInt(IntTy::I128)),
-            ConstInt::Isize(_) => Some(IntType::SignedInt(IntTy::Is)),
-            ConstInt::U8(_) => Some(IntType::UnsignedInt(UintTy::U8)),
-            ConstInt::U16(_) => Some(IntType::UnsignedInt(UintTy::U16)),
-            ConstInt::U32(_) => Some(IntType::UnsignedInt(UintTy::U32)),
-            ConstInt::U64(_) => Some(IntType::UnsignedInt(UintTy::U64)),
-            ConstInt::U128(_) => Some(IntType::UnsignedInt(UintTy::U128)),
-            ConstInt::Usize(_) => Some(IntType::UnsignedInt(UintTy::Us)),
-            _ => None,
+            ConstInt::I8(_) => IntType::SignedInt(IntTy::I8),
+            ConstInt::I16(_) => IntType::SignedInt(IntTy::I16),
+            ConstInt::I32(_) => IntType::SignedInt(IntTy::I32),
+            ConstInt::I64(_) => IntType::SignedInt(IntTy::I64),
+            ConstInt::I128(_) => IntType::SignedInt(IntTy::I128),
+            ConstInt::Isize(_) => IntType::SignedInt(IntTy::Is),
+            ConstInt::U8(_) => IntType::UnsignedInt(UintTy::U8),
+            ConstInt::U16(_) => IntType::UnsignedInt(UintTy::U16),
+            ConstInt::U32(_) => IntType::UnsignedInt(UintTy::U32),
+            ConstInt::U64(_) => IntType::UnsignedInt(UintTy::U64),
+            ConstInt::U128(_) => IntType::UnsignedInt(UintTy::U128),
+            ConstInt::Usize(_) => IntType::UnsignedInt(UintTy::Us),
         }
     }
 }
@@ -380,8 +348,6 @@ impl ::std::cmp::Ord for ConstInt {
 impl ::std::fmt::Display for ConstInt {
     fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
         match *self {
-            Infer(i) => write!(fmt, "{}", i),
-            InferSigned(i) => write!(fmt, "{}", i),
             I8(i) => write!(fmt, "{}i8", i),
             I16(i) => write!(fmt, "{}i16", i),
             I32(i) => write!(fmt, "{}i32", i),
@@ -417,7 +383,7 @@ macro_rules! impl_binop {
         impl ::std::ops::$op for ConstInt {
             type Output = Result<Self, ConstMathErr>;
             fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
-                match self.infer(rhs)? {
+                match (self, rhs) {
                     (I8(a), I8(b)) => a.$checked_func(b).map(I8),
                     (I16(a), I16(b)) => a.$checked_func(b).map(I16),
                     (I32(a), I32(b)) => a.$checked_func(b).map(I32),
@@ -434,8 +400,6 @@ macro_rules! impl_binop {
                     (Usize(Us16(a)), Usize(Us16(b))) => a.$checked_func(b).map(Us16).map(Usize),
                     (Usize(Us32(a)), Usize(Us32(b))) => a.$checked_func(b).map(Us32).map(Usize),
                     (Usize(Us64(a)), Usize(Us64(b))) => a.$checked_func(b).map(Us64).map(Usize),
-                    (Infer(a), Infer(b)) => a.$checked_func(b).map(Infer),
-                    (InferSigned(a), InferSigned(b)) => a.$checked_func(b).map(InferSigned),
                     _ => return Err(UnequalTypes(Op::$op)),
                 }.ok_or(Overflow(Op::$op))
             }
@@ -448,7 +412,7 @@ macro_rules! derive_binop {
         impl ::std::ops::$op for ConstInt {
             type Output = Result<Self, ConstMathErr>;
             fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
-                match self.infer(rhs)? {
+                match (self, rhs) {
                     (I8(a), I8(b)) => Ok(I8(a.$func(b))),
                     (I16(a), I16(b)) => Ok(I16(a.$func(b))),
                     (I32(a), I32(b)) => Ok(I32(a.$func(b))),
@@ -465,8 +429,6 @@ macro_rules! derive_binop {
                     (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a.$func(b)))),
                     (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a.$func(b)))),
                     (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a.$func(b)))),
-                    (Infer(a), Infer(b)) => Ok(Infer(a.$func(b))),
-                    (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a.$func(b))),
                     _ => Err(UnequalTypes(Op::$op)),
                 }
             }
@@ -498,7 +460,6 @@ fn check_division(
         (Isize(_), Isize(Is16(0))) => Err(zerr),
         (Isize(_), Isize(Is32(0))) => Err(zerr),
         (Isize(_), Isize(Is64(0))) => Err(zerr),
-        (InferSigned(_), InferSigned(0)) => Err(zerr),
 
         (U8(_), U8(0)) => Err(zerr),
         (U16(_), U16(0)) => Err(zerr),
@@ -508,7 +469,6 @@ fn check_division(
         (Usize(_), Usize(Us16(0))) => Err(zerr),
         (Usize(_), Usize(Us32(0))) => Err(zerr),
         (Usize(_), Usize(Us64(0))) => Err(zerr),
-        (Infer(_), Infer(0)) => Err(zerr),
 
         (I8(::std::i8::MIN), I8(-1)) => Err(Overflow(op)),
         (I16(::std::i16::MIN), I16(-1)) => Err(Overflow(op)),
@@ -518,7 +478,6 @@ fn check_division(
         (Isize(Is16(::std::i16::MIN)), Isize(Is16(-1))) => Err(Overflow(op)),
         (Isize(Is32(::std::i32::MIN)), Isize(Is32(-1))) => Err(Overflow(op)),
         (Isize(Is64(::std::i64::MIN)), Isize(Is64(-1))) => Err(Overflow(op)),
-        (InferSigned(I128_MIN), InferSigned(-1)) => Err(Overflow(op)),
 
         _ => Ok(()),
     }
@@ -527,7 +486,7 @@ fn check_division(
 impl ::std::ops::Div for ConstInt {
     type Output = Result<Self, ConstMathErr>;
     fn div(self, rhs: Self) -> Result<Self, ConstMathErr> {
-        let (lhs, rhs) = self.infer(rhs)?;
+        let (lhs, rhs) = (self, rhs);
         check_division(lhs, rhs, Op::Div, DivisionByZero)?;
         match (lhs, rhs) {
             (I8(a), I8(b)) => Ok(I8(a/b)),
@@ -538,7 +497,6 @@ impl ::std::ops::Div for ConstInt {
             (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a/b))),
             (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a/b))),
             (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a/b))),
-            (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a/b)),
 
             (U8(a), U8(b)) => Ok(U8(a/b)),
             (U16(a), U16(b)) => Ok(U16(a/b)),
@@ -548,7 +506,6 @@ impl ::std::ops::Div for ConstInt {
             (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a/b))),
             (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a/b))),
             (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a/b))),
-            (Infer(a), Infer(b)) => Ok(Infer(a/b)),
 
             _ => Err(UnequalTypes(Op::Div)),
         }
@@ -558,7 +515,7 @@ impl ::std::ops::Div for ConstInt {
 impl ::std::ops::Rem for ConstInt {
     type Output = Result<Self, ConstMathErr>;
     fn rem(self, rhs: Self) -> Result<Self, ConstMathErr> {
-        let (lhs, rhs) = self.infer(rhs)?;
+        let (lhs, rhs) = (self, rhs);
         // should INT_MIN%-1 be zero or an error?
         check_division(lhs, rhs, Op::Rem, RemainderByZero)?;
         match (lhs, rhs) {
@@ -570,7 +527,6 @@ impl ::std::ops::Rem for ConstInt {
             (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a%b))),
             (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a%b))),
             (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a%b))),
-            (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a%b)),
 
             (U8(a), U8(b)) => Ok(U8(a%b)),
             (U16(a), U16(b)) => Ok(U16(a%b)),
@@ -580,7 +536,6 @@ impl ::std::ops::Rem for ConstInt {
             (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a%b))),
             (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a%b))),
             (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a%b))),
-            (Infer(a), Infer(b)) => Ok(Infer(a%b)),
 
             _ => Err(UnequalTypes(Op::Rem)),
         }
@@ -608,8 +563,6 @@ impl ::std::ops::Shl<ConstInt> for ConstInt {
             Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shl(b), Op::Shl)))),
             Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
             Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
-            Infer(a) => Ok(Infer(overflowing!(a.overflowing_shl(b), Op::Shl))),
-            InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shl(b), Op::Shl))),
         }
     }
 }
@@ -635,8 +588,6 @@ impl ::std::ops::Shr<ConstInt> for ConstInt {
             Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shr(b), Op::Shr)))),
             Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
             Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
-            Infer(a) => Ok(Infer(overflowing!(a.overflowing_shr(b), Op::Shr))),
-            InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shr(b), Op::Shr))),
         }
     }
 }
@@ -656,9 +607,6 @@ impl ::std::ops::Neg for ConstInt {
             a@U8(0) | a@U16(0) | a@U32(0) | a@U64(0) | a@U128(0) |
             a@Usize(Us16(0)) | a@Usize(Us32(0)) | a@Usize(Us64(0)) => Ok(a),
             U8(_) | U16(_) | U32(_) | U64(_) | U128(_) | Usize(_) => Err(UnsignedNegation),
-            Infer(a @ 0...ubounds::I128MAX) => Ok(InferSigned(-(a as i128))),
-            Infer(_) => Err(Overflow(Op::Neg)),
-            InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_neg(), Op::Neg))),
         }
     }
 }
@@ -683,8 +631,6 @@ impl ::std::ops::Not for ConstInt {
             Usize(Us16(a)) => Ok(Usize(Us16(!a))),
             Usize(Us32(a)) => Ok(Usize(Us32(!a))),
             Usize(Us64(a)) => Ok(Usize(Us64(!a))),
-            Infer(a) => Ok(Infer(!a)),
-            InferSigned(a) => Ok(InferSigned(!a)),
         }
     }
 }
diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs
index 13764ce5bbb..b7833a54403 100644
--- a/src/librustc_const_math/lib.rs
+++ b/src/librustc_const_math/lib.rs
@@ -21,7 +21,7 @@
 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]
-
+#![deny(warnings)]
 
 #![feature(rustc_private)]
 #![feature(staged_api)]
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index de789d5686f..ddf09f5cfe0 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -21,14 +21,14 @@ use rustc::middle::{self, dependency_format, stability, reachable};
 use rustc::middle::privacy::AccessLevels;
 use rustc::ty::{self, TyCtxt, Resolutions, GlobalArenas};
 use rustc::util::common::time;
-use rustc::util::nodemap::{NodeSet, NodeMap};
+use rustc::util::nodemap::NodeSet;
 use rustc::util::fs::rename_or_copy_remove;
 use rustc_borrowck as borrowck;
 use rustc_incremental::{self, IncrementalHashesMap};
 use rustc_incremental::ich::Fingerprint;
 use rustc_resolve::{MakeGlobMap, Resolver};
 use rustc_metadata::creader::CrateLoader;
-use rustc_metadata::cstore::CStore;
+use rustc_metadata::cstore::{self, CStore};
 use rustc_trans::back::{link, write};
 use rustc_trans as trans;
 use rustc_typeck as typeck;
@@ -343,7 +343,7 @@ pub struct CompileState<'a, 'tcx: 'a> {
     pub hir_crate: Option<&'a hir::Crate>,
     pub hir_map: Option<&'a hir_map::Map<'tcx>>,
     pub resolutions: Option<&'a Resolutions>,
-    pub analysis: Option<&'a ty::CrateAnalysis<'tcx>>,
+    pub analysis: Option<&'a ty::CrateAnalysis>,
     pub tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>,
     pub trans: Option<&'a trans::CrateTranslation>,
 }
@@ -417,7 +417,7 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> {
                                 arenas: &'tcx GlobalArenas<'tcx>,
                                 cstore: &'a CStore,
                                 hir_map: &'a hir_map::Map<'tcx>,
-                                analysis: &'a ty::CrateAnalysis<'static>,
+                                analysis: &'a ty::CrateAnalysis,
                                 resolutions: &'a Resolutions,
                                 krate: &'a ast::Crate,
                                 hir_crate: &'a hir::Crate,
@@ -444,7 +444,7 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> {
                             out_file: &'a Option<PathBuf>,
                             krate: Option<&'a ast::Crate>,
                             hir_crate: &'a hir::Crate,
-                            analysis: &'a ty::CrateAnalysis<'tcx>,
+                            analysis: &'a ty::CrateAnalysis,
                             tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             crate_name: &'a str)
                             -> Self {
@@ -534,7 +534,7 @@ fn count_nodes(krate: &ast::Crate) -> usize {
 pub struct ExpansionResult {
     pub expanded_crate: ast::Crate,
     pub defs: hir_map::Definitions,
-    pub analysis: ty::CrateAnalysis<'static>,
+    pub analysis: ty::CrateAnalysis,
     pub resolutions: Resolutions,
     pub hir_forest: hir_map::Forest,
 }
@@ -797,7 +797,6 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
             reachable: NodeSet(),
             name: crate_name.to_string(),
             glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None },
-            hir_ty_to_ty: NodeMap(),
         },
         resolutions: Resolutions {
             freevars: resolver.freevars,
@@ -813,7 +812,7 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
 /// structures carrying the results of the analysis.
 pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
                                                hir_map: hir_map::Map<'tcx>,
-                                               mut analysis: ty::CrateAnalysis<'tcx>,
+                                               mut analysis: ty::CrateAnalysis,
                                                resolutions: Resolutions,
                                                arena: &'tcx DroplessArena,
                                                arenas: &'tcx GlobalArenas<'tcx>,
@@ -821,7 +820,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
                                                f: F)
                                                -> Result<R, usize>
     where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>,
-                            ty::CrateAnalysis<'tcx>,
+                            ty::CrateAnalysis,
                             IncrementalHashesMap,
                             CompileResult) -> R
 {
@@ -872,7 +871,16 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
 
     let index = stability::Index::new(&hir_map);
 
+    let mut local_providers = ty::maps::Providers::default();
+    mir::provide(&mut local_providers);
+    typeck::provide(&mut local_providers);
+
+    let mut extern_providers = ty::maps::Providers::default();
+    cstore::provide(&mut extern_providers);
+
     TyCtxt::create_and_enter(sess,
+                             local_providers,
+                             extern_providers,
                              arenas,
                              arena,
                              resolutions,
@@ -900,8 +908,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
              || stability::check_unstable_api_usage(tcx));
 
         // passes are timed inside typeck
-        analysis.hir_ty_to_ty =
-            try_with_f!(typeck::check_crate(tcx), (tcx, analysis, incremental_hashes_map));
+        try_with_f!(typeck::check_crate(tcx), (tcx, analysis, incremental_hashes_map));
 
         time(time_passes,
              "const checking",
@@ -951,8 +958,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
             // in stage 4 below.
             passes.push_hook(box mir::transform::dump_mir::DumpMir);
             passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("initial"));
-            passes.push_pass(
-                box mir::transform::qualify_consts::QualifyAndPromoteConstants::default());
+            passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants);
             passes.push_pass(box mir::transform::type_check::TypeckMir);
             passes.push_pass(
                 box mir::transform::simplify_branches::SimplifyBranches::new("initial"));
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 21fe13997b7..064c4982ef0 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -201,7 +201,7 @@ impl PpSourceMode {
     fn call_with_pp_support_hir<'tcx, A, B, F>(&self,
                                                sess: &'tcx Session,
                                                hir_map: &hir_map::Map<'tcx>,
-                                               analysis: &ty::CrateAnalysis<'tcx>,
+                                               analysis: &ty::CrateAnalysis,
                                                resolutions: &Resolutions,
                                                arena: &'tcx DroplessArena,
                                                arenas: &'tcx GlobalArenas<'tcx>,
@@ -838,7 +838,7 @@ pub fn print_after_parsing(sess: &Session,
 
 pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
                                                 hir_map: &hir_map::Map<'tcx>,
-                                                analysis: &ty::CrateAnalysis<'tcx>,
+                                                analysis: &ty::CrateAnalysis,
                                                 resolutions: &Resolutions,
                                                 input: &Input,
                                                 krate: &ast::Crate,
@@ -958,7 +958,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
 // Instead, we call that function ourselves.
 fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
                                        hir_map: &hir_map::Map<'tcx>,
-                                       analysis: &ty::CrateAnalysis<'tcx>,
+                                       analysis: &ty::CrateAnalysis,
                                        resolutions: &Resolutions,
                                        crate_name: &str,
                                        arena: &'tcx DroplessArena,
@@ -996,11 +996,13 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
                 } else {
                     match ppm {
                         PpmMir => {
-                            write_mir_pretty(tcx, tcx.mir_map.borrow().keys().into_iter(), &mut out)
+                            write_mir_pretty(tcx,
+                                             tcx.maps.mir.borrow().keys().into_iter(),
+                                             &mut out)
                         }
                         PpmMirCFG => {
                             write_mir_graphviz(tcx,
-                                               tcx.mir_map.borrow().keys().into_iter(),
+                                               tcx.maps.mir.borrow().keys().into_iter(),
                                                &mut out)
                         }
                         _ => unreachable!(),
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 5481de1811d..9568cc3d6de 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -139,6 +139,8 @@ fn test_env<F>(source_string: &str,
     let region_map = region::resolve_crate(&sess, &hir_map);
     let index = stability::Index::new(&hir_map);
     TyCtxt::create_and_enter(&sess,
+                             ty::maps::Providers::default(),
+                             ty::maps::Providers::default(),
                              &arenas,
                              &arena,
                              resolutions,
@@ -149,7 +151,7 @@ fn test_env<F>(source_string: &str,
                              index,
                              "test_crate",
                              |tcx| {
-        tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
+        tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
 
             body(Env { infcx: &infcx });
             let free_regions = FreeRegionMap::new();
@@ -268,11 +270,13 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
     }
 
     pub fn t_fn(&self, input_tys: &[Ty<'tcx>], output_ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.infcx.tcx.mk_fn_ptr(self.infcx.tcx.mk_bare_fn(ty::BareFnTy {
-            unsafety: hir::Unsafety::Normal,
-            abi: Abi::Rust,
-            sig: ty::Binder(self.infcx.tcx.mk_fn_sig(input_tys.iter().cloned(), output_ty, false)),
-        }))
+        self.infcx.tcx.mk_fn_ptr(ty::Binder(self.infcx.tcx.mk_fn_sig(
+            input_tys.iter().cloned(),
+            output_ty,
+            false,
+            hir::Unsafety::Normal,
+            Abi::Rust
+        )))
     }
 
     pub fn t_nil(&self) -> Ty<'tcx> {
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index c7512f2971b..150a2c39db7 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -63,8 +63,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
                hash_spans: bool,
                hash_bodies: bool)
                -> Self {
-        let check_overflow = tcx.sess.opts.debugging_opts.force_overflow_checks
-            .unwrap_or(tcx.sess.opts.debug_assertions);
+        let check_overflow = tcx.sess.overflow_checks();
 
         StrictVersionHashVisitor {
             st: st,
@@ -338,8 +337,10 @@ fn saw_expr<'a>(node: &'a Expr_,
         ExprIndex(..)            => (SawExprIndex, true),
         ExprPath(_)              => (SawExprPath, false),
         ExprAddrOf(m, _)         => (SawExprAddrOf(m), false),
-        ExprBreak(label, _)      => (SawExprBreak(label.map(|l| l.name.as_str())), false),
-        ExprAgain(label)         => (SawExprAgain(label.map(|l| l.name.as_str())), false),
+        ExprBreak(label, _)      => (SawExprBreak(label.ident.map(|i|
+                                                    i.node.name.as_str())), false),
+        ExprAgain(label)         => (SawExprAgain(label.ident.map(|i|
+                                                    i.node.name.as_str())), false),
         ExprRet(..)              => (SawExprRet, false),
         ExprInlineAsm(ref a,..)  => (SawExprInlineAsm(StableInlineAsm(a)), false),
         ExprStruct(..)           => (SawExprStruct, false),
@@ -1166,6 +1167,9 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
             trait_items: _,
             impl_items: _,
             bodies: _,
+
+            trait_impls: _,
+            trait_default_impl: _,
         } = *krate;
 
         visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);
diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs
index 60f24b71de2..673f1ae1084 100644
--- a/src/librustc_incremental/persist/data.rs
+++ b/src/librustc_incremental/persist/data.rs
@@ -23,6 +23,11 @@ use super::directory::DefPathIndex;
 pub struct SerializedDepGraph {
     pub edges: Vec<SerializedEdgeSet>,
 
+    /// These are output nodes that have no incoming edges. We track
+    /// these separately so that when we reload all edges, we don't
+    /// lose track of these nodes.
+    pub bootstrap_outputs: Vec<DepNode<DefPathIndex>>,
+
     /// These are hashes of two things:
     /// - the HIR nodes in this crate
     /// - the metadata nodes from dependent crates we use
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index a0bcb54af32..156f8b9e7c4 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -257,6 +257,12 @@ pub struct DirtyCleanMetadataVisitor<'a, 'tcx:'a, 'm> {
 impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         self.check_item(item.id, item.span);
+
+        if let hir::ItemEnum(ref def, _) = item.node {
+            for v in &def.variants {
+                self.check_item(v.node.data.id(), v.span);
+            }
+        }
     }
 
     fn visit_trait_item(&mut self, item: &hir::TraitItem) {
diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs
index 7724658a9d6..03411e01a57 100644
--- a/src/librustc_incremental/persist/load.rs
+++ b/src/librustc_incremental/persist/load.rs
@@ -184,6 +184,18 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
     }
 
+    // Recreate bootstrap outputs, which are outputs that have no incoming edges (and hence cannot
+    // be dirty).
+    for bootstrap_output in &serialized_dep_graph.bootstrap_outputs {
+        if let Some(n) = retraced.map(bootstrap_output) {
+            if let DepNode::WorkProduct(ref wp) = n {
+                clean_work_products.insert(wp.clone());
+            }
+
+            tcx.dep_graph.with_task(n, || ()); // create the node with no inputs
+        }
+    }
+
     // Subtle. Sometimes we have intermediate nodes that we can't recreate in the new graph.
     // This is pretty unusual but it arises in a scenario like this:
     //
diff --git a/src/librustc_incremental/persist/preds/mod.rs b/src/librustc_incremental/persist/preds/mod.rs
index a80620fbde6..f6a37c7a122 100644
--- a/src/librustc_incremental/persist/preds/mod.rs
+++ b/src/librustc_incremental/persist/preds/mod.rs
@@ -11,7 +11,7 @@
 use rustc::dep_graph::{DepGraphQuery, DepNode};
 use rustc::hir::def_id::DefId;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::graph::Graph;
+use rustc_data_structures::graph::{Graph, NodeIndex};
 
 use super::hash::*;
 use ich::Fingerprint;
@@ -28,6 +28,14 @@ pub struct Predecessors<'query> {
     // of the graph down.
     pub reduced_graph: Graph<&'query DepNode<DefId>, ()>,
 
+    // These are output nodes that have no incoming edges. We have to
+    // track these specially because, when we load the data back up
+    // again, we want to make sure and recreate these nodes (we want
+    // to recreate the nodes where all incoming edges are clean; but
+    // since we ordinarily just serialize edges, we wind up just
+    // forgetting that bootstrap outputs even exist in that case.)
+    pub bootstrap_outputs: Vec<&'query DepNode<DefId>>,
+
     // For the inputs (hir/foreign-metadata), we include hashes.
     pub hashes: FxHashMap<&'query DepNode<DefId>, Fingerprint>,
 }
@@ -57,7 +65,7 @@ impl<'q> Predecessors<'q> {
 
         // Reduce the graph to the most important nodes.
         let compress::Reduction { graph, input_nodes } =
-            compress::reduce_graph(&query.graph, HashContext::is_hashable, is_output);
+            compress::reduce_graph(&query.graph, HashContext::is_hashable, |n| is_output(n));
 
         let mut hashes = FxHashMap();
         for input_index in input_nodes {
@@ -67,8 +75,17 @@ impl<'q> Predecessors<'q> {
                   .or_insert_with(|| hcx.hash(input).unwrap());
         }
 
+        let bootstrap_outputs: Vec<&'q DepNode<DefId>> =
+            (0 .. graph.len_nodes())
+            .map(NodeIndex)
+            .filter(|&n| graph.incoming_edges(n).next().is_none())
+            .map(|n| *graph.node_data(n))
+            .filter(|n| is_output(n))
+            .collect();
+
         Predecessors {
             reduced_graph: graph,
+            bootstrap_outputs: bootstrap_outputs,
             hashes: hashes,
         }
     }
diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs
index 34bb125ef3f..dfa6bf6bbb5 100644
--- a/src/librustc_incremental/persist/save.rs
+++ b/src/librustc_incremental/persist/save.rs
@@ -204,11 +204,15 @@ pub fn encode_dep_graph(preds: &Predecessors,
     }
 
     // Create the serialized dep-graph.
+    let bootstrap_outputs = preds.bootstrap_outputs.iter()
+                                                   .map(|n| builder.map(n))
+                                                   .collect();
     let edges = edges.into_iter()
                      .map(|(k, v)| SerializedEdgeSet { source: k, targets: v })
                      .collect();
     let graph = SerializedDepGraph {
-        edges: edges,
+        bootstrap_outputs,
+        edges,
         hashes: preds.hashes
             .iter()
             .map(|(&dep_node, &hash)| {
@@ -221,6 +225,7 @@ pub fn encode_dep_graph(preds: &Predecessors,
     };
 
     if tcx.sess.opts.debugging_opts.incremental_info {
+        println!("incremental: {} nodes in reduced dep-graph", preds.reduced_graph.len_nodes());
         println!("incremental: {} edges in serialized dep-graph", graph.edges.len());
         println!("incremental: {} hashes in serialized dep-graph", graph.hashes.len());
     }
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index 0c86eb42e7a..353b86820c4 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -29,7 +29,7 @@ pub enum MethodLateContext {
 
 pub fn method_context(cx: &LateContext, id: ast::NodeId, span: Span) -> MethodLateContext {
     let def_id = cx.tcx.hir.local_def_id(id);
-    match cx.tcx.associated_items.borrow().get(&def_id) {
+    match cx.tcx.maps.associated_item.borrow().get(&def_id) {
         None => span_bug!(span, "missing method descriptor?!"),
         Some(item) => {
             match item.container {
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 1592d178176..b3f09c28277 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -523,7 +523,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations {
             }
             _ => return,
         };
-        if def.has_dtor() {
+        if def.has_dtor(cx.tcx) {
             return;
         }
         let parameter_environment = cx.tcx.empty_parameter_environment();
@@ -882,7 +882,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
                     let node_id = tcx.hir.as_local_node_id(method.def_id).unwrap();
 
                     let param_env = ty::ParameterEnvironment::for_item(tcx, node_id);
-                    tcx.infer_ctxt(param_env, Reveal::NotSpecializable).enter(|infcx| {
+                    tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
                         let mut selcx = traits::SelectionContext::new(&infcx);
                         match selcx.select(&obligation) {
                             // The method comes from a `T: Trait` bound.
@@ -1082,9 +1082,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes {
                 }
                 let typ = cx.tables.node_id_to_type(expr.id);
                 match typ.sty {
-                    ty::TyFnDef(.., ref bare_fn) if bare_fn.abi == RustIntrinsic => {
-                        let from = bare_fn.sig.skip_binder().inputs()[0];
-                        let to = bare_fn.sig.skip_binder().output();
+                    ty::TyFnDef(.., bare_fn) if bare_fn.abi() == RustIntrinsic => {
+                        let from = bare_fn.inputs().skip_binder()[0];
+                        let to = *bare_fn.output().skip_binder();
                         return Some((&from.sty, &to.sty));
                     }
                     _ => (),
@@ -1095,7 +1095,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes {
 
         fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool {
             match cx.tcx.item_type(def_id).sty {
-                ty::TyFnDef(.., ref bfty) if bfty.abi == RustIntrinsic => (),
+                ty::TyFnDef(.., bfty) if bfty.abi() == RustIntrinsic => (),
                 _ => return false,
             }
             cx.tcx.item_name(def_id) == "transmute"
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 8feb07953db..529afe0215e 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -17,7 +17,6 @@ use rustc::ty::layout::{Layout, Primitive};
 use rustc::traits::Reveal;
 use middle::const_val::ConstVal;
 use rustc_const_eval::ConstContext;
-use rustc_const_eval::EvalHint::ExprTypeChecked;
 use util::nodemap::FxHashSet;
 use lint::{LateContext, LintContext, LintArray};
 use lint::{LintPass, LateLintPass};
@@ -109,7 +108,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
                             }
                         } else {
                             let const_cx = ConstContext::with_tables(cx.tcx, cx.tables);
-                            match const_cx.eval(&r, ExprTypeChecked) {
+                            match const_cx.eval(&r) {
                                 Ok(ConstVal::Integral(i)) => {
                                     i.is_negative() ||
                                     i.to_u64()
@@ -381,6 +380,17 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     false
 }
 
+fn is_ffi_safe(ty: attr::IntType) -> bool {
+    match ty {
+        attr::SignedInt(ast::IntTy::I8) | attr::UnsignedInt(ast::UintTy::U8) |
+        attr::SignedInt(ast::IntTy::I16) | attr::UnsignedInt(ast::UintTy::U16) |
+        attr::SignedInt(ast::IntTy::I32) | attr::UnsignedInt(ast::UintTy::U32) |
+        attr::SignedInt(ast::IntTy::I64) | attr::UnsignedInt(ast::UintTy::U64) |
+        attr::SignedInt(ast::IntTy::I128) | attr::UnsignedInt(ast::UintTy::U128) => true,
+        attr::SignedInt(ast::IntTy::Is) | attr::UnsignedInt(ast::UintTy::Us) => false
+    }
+}
+
 impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     /// Check if the given type is "ffi-safe" (has a stable, well-defined
     /// representation which can be exported to C code).
@@ -406,7 +416,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 }
                 match def.adt_kind() {
                     AdtKind::Struct => {
-                        if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
+                        if !def.repr.c {
                             return FfiUnsafe("found struct without foreign-function-safe \
                                               representation annotation in foreign module, \
                                               consider adding a #[repr(C)] attribute to the type");
@@ -440,7 +450,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         if all_phantom { FfiPhantom } else { FfiSafe }
                     }
                     AdtKind::Union => {
-                        if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
+                        if !def.repr.c {
                             return FfiUnsafe("found union without foreign-function-safe \
                                               representation annotation in foreign module, \
                                               consider adding a #[repr(C)] attribute to the type");
@@ -479,35 +489,28 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
                         // Check for a repr() attribute to specify the size of the
                         // discriminant.
-                        let repr_hints = cx.lookup_repr_hints(def.did);
-                        match &repr_hints[..] {
-                            &[] => {
-                                // Special-case types like `Option<extern fn()>`.
-                                if !is_repr_nullable_ptr(cx, def, substs) {
-                                    return FfiUnsafe("found enum without foreign-function-safe \
-                                                      representation annotation in foreign \
-                                                      module, consider adding a #[repr(...)] \
-                                                      attribute to the type");
-                                }
+                        if !def.repr.c && def.repr.int.is_none() {
+                            // Special-case types like `Option<extern fn()>`.
+                            if !is_repr_nullable_ptr(cx, def, substs) {
+                                return FfiUnsafe("found enum without foreign-function-safe \
+                                                  representation annotation in foreign \
+                                                  module, consider adding a #[repr(...)] \
+                                                  attribute to the type");
                             }
-                            &[ref hint] => {
-                                if !hint.is_ffi_safe() {
-                                    // FIXME: This shouldn't be reachable: we should check
-                                    // this earlier.
-                                    return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
-                                }
-
-                                // Enum with an explicitly sized discriminant; either
-                                // a C-style enum or a discriminated union.
+                        }
 
-                                // The layout of enum variants is implicitly repr(C).
-                                // FIXME: Is that correct?
-                            }
-                            _ => {
+                        if let Some(int_ty) = def.repr.int {
+                            if !is_ffi_safe(int_ty) {
                                 // FIXME: This shouldn't be reachable: we should check
                                 // this earlier.
-                                return FfiUnsafe("enum has too many #[repr(...)] attributes");
+                                return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
                             }
+
+                            // Enum with an explicitly sized discriminant; either
+                            // a C-style enum or a discriminated union.
+
+                            // The layout of enum variants is implicitly repr(C).
+                            // FIXME: Is that correct?
                         }
 
                         // Check the contained variants.
@@ -568,8 +571,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
             ty::TyArray(ty, _) => self.check_type_for_ffi(cache, ty),
 
-            ty::TyFnPtr(bare_fn) => {
-                match bare_fn.abi {
+            ty::TyFnPtr(sig) => {
+                match sig.abi() {
                     Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
                         return FfiUnsafe("found function pointer with Rust calling convention in \
                                           foreign module; consider using an `extern` function \
@@ -578,7 +581,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                     _ => {}
                 }
 
-                let sig = cx.erase_late_bound_regions(&bare_fn.sig);
+                let sig = cx.erase_late_bound_regions(&sig);
                 if !sig.output().is_nil() {
                     let r = self.check_type_for_ffi(cache, sig.output());
                     match r {
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 104d76b1f60..4477488f6cb 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -1077,10 +1077,20 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
             let mut found = false;
             for lib in self.cstore.get_used_libraries().borrow_mut().iter_mut() {
                 if lib.name == name as &str {
-                    lib.kind = kind;
+                    let mut changed = false;
+                    if let Some(k) = kind {
+                        lib.kind = k;
+                        changed = true;
+                    }
                     if let &Some(ref new_name) = new_name {
                         lib.name = Symbol::intern(new_name);
+                        changed = true;
+                    }
+                    if !changed {
+                        self.sess.warn(&format!("redundant linker flag specified for library `{}`",
+                                                name));
                     }
+
                     found = true;
                 }
             }
@@ -1089,7 +1099,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
                 let new_name = new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
                 let lib = NativeLibrary {
                     name: Symbol::intern(new_name.unwrap_or(name)),
-                    kind: kind,
+                    kind: if let Some(k) = kind { k } else { cstore::NativeUnknown },
                     cfg: None,
                     foreign_items: Vec::new(),
                 };
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index 4709ca6101c..bb30245df5f 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -35,6 +35,8 @@ pub use rustc::middle::cstore::{NativeLibrary, NativeLibraryKind, LinkagePrefere
 pub use rustc::middle::cstore::NativeLibraryKind::*;
 pub use rustc::middle::cstore::{CrateSource, LinkMeta, LibSource};
 
+pub use cstore_impl::provide;
+
 // A map from external crate numbers (as decoded from some crate file) to
 // local crate numbers (as generated during this session). Each external
 // crate may refer to types in other external crates, and each has their
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 7b0177bfd23..7b02280ef90 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -13,21 +13,25 @@ use encoder;
 use locator;
 use schema;
 
+use rustc::dep_graph::DepTrackingMapConfig;
 use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, ExternCrate};
 use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro};
 use rustc::hir::def::{self, Def};
 use rustc::middle::lang_items;
-use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
 use rustc::session::Session;
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{self, TyCtxt};
+use rustc::ty::maps::Providers;
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
 
 use rustc::dep_graph::DepNode;
 use rustc::hir::map::{DefKey, DefPath, DisambiguatedDefPathData};
-use rustc::mir::Mir;
 use rustc::util::nodemap::{NodeSet, DefIdMap};
 use rustc_back::PanicStrategy;
 
+use std::any::Any;
+use std::mem;
+use std::rc::Rc;
+
 use syntax::ast;
 use syntax::attr;
 use syntax::parse::filemap_to_tts;
@@ -39,87 +43,103 @@ use rustc::hir;
 
 use std::collections::BTreeMap;
 
-impl<'tcx> CrateStore<'tcx> for cstore::CStore {
-    fn describe_def(&self, def: DefId) -> Option<Def> {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_def(def.index)
-    }
-
-    fn def_span(&self, sess: &Session, def: DefId) -> Span {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_span(def.index, sess)
-    }
-
-    fn stability(&self, def: DefId) -> Option<attr::Stability> {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_stability(def.index)
+macro_rules! provide {
+    (<$lt:tt> $tcx:ident, $def_id:ident, $cdata:ident $($name:ident => $compute:block)*) => {
+        pub fn provide<$lt>(providers: &mut Providers<$lt>) {
+            $(fn $name<'a, $lt:$lt>($tcx: TyCtxt<'a, $lt, $lt>, $def_id: DefId)
+                                    -> <ty::queries::$name<$lt> as
+                                        DepTrackingMapConfig>::Value {
+                assert!(!$def_id.is_local());
+
+                $tcx.dep_graph.read(DepNode::MetaData($def_id));
+
+                let $cdata = $tcx.sess.cstore.crate_data_as_rc_any($def_id.krate);
+                let $cdata = $cdata.downcast_ref::<cstore::CrateMetadata>()
+                    .expect("CrateStore crated ata is not a CrateMetadata");
+                $compute
+            })*
+
+            *providers = Providers {
+                $($name,)*
+                ..*providers
+            };
+        }
     }
+}
 
-    fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_deprecation(def.index)
+provide! { <'tcx> tcx, def_id, cdata
+    ty => { cdata.get_type(def_id.index, tcx) }
+    generics => { tcx.alloc_generics(cdata.get_generics(def_id.index)) }
+    predicates => { cdata.get_predicates(def_id.index, tcx) }
+    super_predicates => { cdata.get_super_predicates(def_id.index, tcx) }
+    trait_def => {
+        tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx))
+    }
+    adt_def => { cdata.get_adt_def(def_id.index, tcx) }
+    variances => { Rc::new(cdata.get_item_variances(def_id.index)) }
+    associated_item_def_ids => {
+        let mut result = vec![];
+        cdata.each_child_of_item(def_id.index, |child| result.push(child.def.def_id()));
+        Rc::new(result)
+    }
+    associated_item => { cdata.get_associated_item(def_id.index) }
+    impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
+    custom_coerce_unsized_kind => {
+        cdata.get_custom_coerce_unsized_kind(def_id.index).unwrap_or_else(|| {
+            bug!("custom_coerce_unsized_kind: `{:?}` is missing its kind", def_id);
+        })
     }
+    mir => {
+        let mir = cdata.maybe_get_item_mir(tcx, def_id.index).unwrap_or_else(|| {
+            bug!("get_item_mir: missing MIR for `{:?}`", def_id)
+        });
 
-    fn visibility(&self, def: DefId) -> ty::Visibility {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_visibility(def.index)
-    }
+        let mir = tcx.alloc_mir(mir);
 
-    fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind
-    {
-        assert!(!def_id.is_local());
-        self.dep_graph.read(DepNode::MetaData(def_id));
-        self.get_crate_data(def_id.krate).closure_kind(def_id.index)
-    }
+        // Perma-borrow MIR from extern crates to prevent mutation.
+        mem::forget(mir.borrow());
 
-    fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> {
-        assert!(!def_id.is_local());
-        self.dep_graph.read(DepNode::MetaData(def_id));
-        self.get_crate_data(def_id.krate).closure_ty(def_id.index, tcx)
+        mir
     }
+    mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
+    typeck_tables => { cdata.item_body_tables(def_id.index, tcx) }
+    closure_kind => { cdata.closure_kind(def_id.index) }
+    closure_type => { cdata.closure_ty(def_id.index, tcx) }
+}
 
-    fn item_variances(&self, def: DefId) -> Vec<ty::Variance> {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_item_variances(def.index)
+impl CrateStore for cstore::CStore {
+    fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc<Any> {
+        self.get_crate_data(krate)
     }
 
-    fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                     -> Ty<'tcx>
-    {
+    fn describe_def(&self, def: DefId) -> Option<Def> {
         self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_type(def.index, tcx)
+        self.get_crate_data(def.krate).get_def(def.index)
     }
 
-    fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                           -> ty::GenericPredicates<'tcx>
-    {
+    fn def_span(&self, sess: &Session, def: DefId) -> Span {
         self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_predicates(def.index, tcx)
+        self.get_crate_data(def.krate).get_span(def.index, sess)
     }
 
-    fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                                 -> ty::GenericPredicates<'tcx>
-    {
+    fn stability(&self, def: DefId) -> Option<attr::Stability> {
         self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_super_predicates(def.index, tcx)
+        self.get_crate_data(def.krate).get_stability(def.index)
     }
 
-    fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                         -> ty::Generics<'tcx>
-    {
+    fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> {
         self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_generics(def.index, tcx)
+        self.get_crate_data(def.krate).get_deprecation(def.index)
     }
 
-    fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize) {
+    fn visibility(&self, def: DefId) -> ty::Visibility {
         self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).generics_own_param_counts(def.index)
+        self.get_crate_data(def.krate).get_visibility(def.index)
     }
 
-    fn item_generics_object_lifetime_defaults(&self, def: DefId)
-                                              -> Vec<ObjectLifetimeDefault> {
+    fn item_generics_cloned(&self, def: DefId) -> ty::Generics {
         self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).generics_object_lifetime_defaults(def.index)
+        self.get_crate_data(def.krate).get_generics(def.index)
     }
 
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>
@@ -128,18 +148,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         self.get_crate_data(def_id.krate).get_item_attrs(def_id.index)
     }
 
-    fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::TraitDef
-    {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_trait_def(def.index, tcx)
-    }
-
-    fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> &'tcx ty::AdtDef
-    {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_adt_def(def.index, tcx)
-    }
-
     fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>
     {
         // FIXME(#38501) We've skipped a `read` on the `HirBody` of
@@ -168,34 +176,12 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         result
     }
 
-    fn associated_item_def_ids(&self, def_id: DefId) -> Vec<DefId> {
-        self.dep_graph.read(DepNode::MetaData(def_id));
-        let mut result = vec![];
-        self.get_crate_data(def_id.krate)
-            .each_child_of_item(def_id.index, |child| result.push(child.def.def_id()));
-        result
-    }
-
     fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity
     {
         self.dep_graph.read(DepNode::MetaData(def));
         self.get_crate_data(def.krate).get_impl_polarity(def.index)
     }
 
-    fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                          -> Option<ty::TraitRef<'tcx>>
-    {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_impl_trait(def.index, tcx)
-    }
-
-    fn custom_coerce_unsized_kind(&self, def: DefId)
-                                  -> Option<ty::adjustment::CustomCoerceUnsized>
-    {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_custom_coerce_unsized_kind(def.index)
-    }
-
     fn impl_parent(&self, impl_def: DefId) -> Option<DefId> {
         self.dep_graph.read(DepNode::MetaData(impl_def));
         self.get_crate_data(impl_def.krate).get_parent_impl(impl_def.index)
@@ -206,7 +192,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         self.get_crate_data(def_id.krate).get_trait_of_item(def_id.index)
     }
 
-    fn associated_item(&self, def: DefId) -> Option<ty::AssociatedItem>
+    fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem
     {
         self.dep_graph.read(DepNode::MetaData(def));
         self.get_crate_data(def.krate).get_associated_item(def.index)
@@ -218,12 +204,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         self.get_crate_data(did.krate).is_const_fn(did.index)
     }
 
-    fn is_defaulted_trait(&self, trait_def_id: DefId) -> bool
-    {
-        self.dep_graph.read(DepNode::MetaData(trait_def_id));
-        self.get_crate_data(trait_def_id.krate).is_defaulted_trait(trait_def_id.index)
-    }
-
     fn is_default_impl(&self, impl_did: DefId) -> bool {
         self.dep_graph.read(DepNode::MetaData(impl_did));
         self.get_crate_data(impl_did.krate).is_default_impl(impl_did.index)
@@ -439,10 +419,10 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         })
     }
 
-    fn maybe_get_item_body<'a>(&'tcx self,
-                               tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                               def_id: DefId)
-                               -> Option<&'tcx hir::Body>
+    fn maybe_get_item_body<'a, 'tcx>(&self,
+                                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                     def_id: DefId)
+                                     -> Option<&'tcx hir::Body>
     {
         if let Some(cached) = tcx.hir.get_inlined_body(def_id) {
             return Some(cached);
@@ -464,13 +444,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         self.get_crate_data(def.krate).const_is_rvalue_promotable_to_static(def.index)
     }
 
-    fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx> {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).maybe_get_item_mir(tcx, def.index).unwrap_or_else(|| {
-            bug!("get_item_mir: missing MIR for {}", tcx.item_path_str(def))
-        })
-    }
-
     fn is_item_mir_available(&self, def: DefId) -> bool {
         self.dep_graph.read(DepNode::MetaData(def));
         self.get_crate_data(def.krate).is_item_mir_available(def.index)
@@ -518,10 +491,10 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         self.do_extern_mod_stmt_cnum(emod_id)
     }
 
-    fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                           reexports: &def::ExportMap,
-                           link_meta: &LinkMeta,
-                           reachable: &NodeSet) -> Vec<u8>
+    fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                 reexports: &def::ExportMap,
+                                 link_meta: &LinkMeta,
+                                 reachable: &NodeSet) -> Vec<u8>
     {
         encoder::encode_metadata(tcx, self, reexports, link_meta, reachable)
     }
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index abc3ffcf86b..b4b9966cbe4 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -20,7 +20,6 @@ use rustc::middle::cstore::LinkagePreference;
 use rustc::hir::def::{self, Def, CtorKind};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc::middle::lang_items;
-use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
 use rustc::session::Session;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::Substs;
@@ -39,6 +38,7 @@ use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque};
 use syntax::attr;
 use syntax::ast;
 use syntax::codemap;
+use syntax::ext::base::MacroKind;
 use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP};
 
 pub struct DecodeContext<'a, 'tcx: 'a> {
@@ -363,12 +363,6 @@ impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice<Ty<'tcx>>> for DecodeContext<'
     }
 }
 
-impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::BareFnTy<'tcx>> for DecodeContext<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<&'tcx ty::BareFnTy<'tcx>, Self::Error> {
-        Ok(self.tcx().mk_bare_fn(Decodable::decode(self)?))
-    }
-}
-
 impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::AdtDef> for DecodeContext<'a, 'tcx> {
     fn specialized_decode(&mut self) -> Result<&'tcx ty::AdtDef, Self::Error> {
         let def_id = DefId::decode(self)?;
@@ -417,8 +411,8 @@ impl<'a, 'tcx> MetadataBlob {
 impl<'tcx> EntryKind<'tcx> {
     fn to_def(&self, did: DefId) -> Option<Def> {
         Some(match *self {
-            EntryKind::Const => Def::Const(did),
-            EntryKind::AssociatedConst(_) => Def::AssociatedConst(did),
+            EntryKind::Const(_) => Def::Const(did),
+            EntryKind::AssociatedConst(..) => Def::AssociatedConst(did),
             EntryKind::ImmStatic |
             EntryKind::ForeignImmStatic => Def::Static(did, false),
             EntryKind::MutStatic |
@@ -434,7 +428,7 @@ impl<'tcx> EntryKind<'tcx> {
             EntryKind::Variant(_) => Def::Variant(did),
             EntryKind::Trait(_) => Def::Trait(did),
             EntryKind::Enum(..) => Def::Enum(did),
-            EntryKind::MacroDef(_) => Def::Macro(did),
+            EntryKind::MacroDef(_) => Def::Macro(did, MacroKind::Bang),
 
             EntryKind::ForeignMod |
             EntryKind::Impl(_) |
@@ -483,9 +477,11 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
     pub fn get_def(&self, index: DefIndex) -> Option<Def> {
-        match self.is_proc_macro(index) {
-            true => Some(Def::Macro(self.local_def_id(index))),
-            false => self.entry(index).kind.to_def(self.local_def_id(index)),
+        if !self.is_proc_macro(index) {
+            self.entry(index).kind.to_def(self.local_def_id(index))
+        } else {
+            let kind = self.proc_macros.as_ref().unwrap()[index.as_usize() - 1].1.kind();
+            Some(Def::Macro(self.local_def_id(index), kind))
         }
     }
 
@@ -505,15 +501,22 @@ impl<'a, 'tcx> CrateMetadata {
             _ => bug!(),
         };
 
-        ty::TraitDef::new(self.local_def_id(item_id),
-                          data.unsafety,
-                          data.paren_sugar,
-                          self.def_path(item_id).deterministic_hash(tcx))
+        let def = ty::TraitDef::new(self.local_def_id(item_id),
+                                    data.unsafety,
+                                    data.paren_sugar,
+                                    self.def_path(item_id).deterministic_hash(tcx));
+
+        if data.has_default_impl {
+            def.record_has_default_impl();
+        }
+
+        def
     }
 
     fn get_variant(&self,
                    item: &Entry<'tcx>,
-                   index: DefIndex)
+                   index: DefIndex,
+                   tcx: TyCtxt<'a, 'tcx, 'tcx>)
                    -> (ty::VariantDef, Option<DefIndex>) {
         let data = match item.kind {
             EntryKind::Variant(data) |
@@ -522,6 +525,11 @@ impl<'a, 'tcx> CrateMetadata {
             _ => bug!(),
         };
 
+        if let ty::VariantDiscr::Explicit(def_id) = data.discr {
+            let result = data.evaluated_discr.map_or(Err(()), Ok);
+            tcx.maps.monomorphic_const_eval.borrow_mut().insert(def_id, result);
+        }
+
         (ty::VariantDef {
             did: self.local_def_id(data.struct_ctor.unwrap_or(index)),
             name: self.item_name(index),
@@ -533,7 +541,7 @@ impl<'a, 'tcx> CrateMetadata {
                     vis: f.visibility.decode(self)
                 }
             }).collect(),
-            disr_val: data.disr,
+            discr: data.discr,
             ctor_kind: data.ctor_kind,
         }, data.struct_ctor)
     }
@@ -544,10 +552,10 @@ impl<'a, 'tcx> CrateMetadata {
                        -> &'tcx ty::AdtDef {
         let item = self.entry(item_id);
         let did = self.local_def_id(item_id);
-        let (kind, ty) = match item.kind {
-            EntryKind::Enum(dt, _) => (ty::AdtKind::Enum, Some(dt.decode(self))),
-            EntryKind::Struct(_, _) => (ty::AdtKind::Struct, None),
-            EntryKind::Union(_, _) => (ty::AdtKind::Union, None),
+        let kind = match item.kind {
+            EntryKind::Enum(_) => ty::AdtKind::Enum,
+            EntryKind::Struct(_, _) => ty::AdtKind::Struct,
+            EntryKind::Union(_, _) => ty::AdtKind::Union,
             _ => bug!("get_adt_def called on a non-ADT {:?}", did),
         };
         let mut ctor_index = None;
@@ -555,27 +563,28 @@ impl<'a, 'tcx> CrateMetadata {
             item.children
                 .decode(self)
                 .map(|index| {
-                    let (variant, struct_ctor) = self.get_variant(&self.entry(index), index);
+                    let (variant, struct_ctor) =
+                        self.get_variant(&self.entry(index), index, tcx);
                     assert_eq!(struct_ctor, None);
                     variant
                 })
                 .collect()
         } else {
-            let (variant, struct_ctor) = self.get_variant(&item, item_id);
+            let (variant, struct_ctor) = self.get_variant(&item, item_id, tcx);
             ctor_index = struct_ctor;
             vec![variant]
         };
         let (kind, repr) = match item.kind {
-            EntryKind::Enum(_, repr) => (ty::AdtKind::Enum, repr),
+            EntryKind::Enum(repr) => (ty::AdtKind::Enum, repr),
             EntryKind::Struct(_, repr) => (ty::AdtKind::Struct, repr),
             EntryKind::Union(_, repr) => (ty::AdtKind::Union, repr),
             _ => bug!("get_adt_def called on a non-ADT {:?}", did),
         };
 
-        let adt = tcx.alloc_adt_def(did, kind, ty, variants, repr);
+        let adt = tcx.alloc_adt_def(did, kind, variants, repr);
         if let Some(ctor_index) = ctor_index {
             // Make adt definition available through constructor id as well.
-            tcx.adt_defs.borrow_mut().insert(self.local_def_id(ctor_index), adt);
+            tcx.maps.adt_def.borrow_mut().insert(self.local_def_id(ctor_index), adt);
         }
 
         adt
@@ -598,30 +607,8 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn get_generics(&self,
-                        item_id: DefIndex,
-                        tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                        -> ty::Generics<'tcx> {
-        let g = self.entry(item_id).generics.unwrap().decode(self);
-        ty::Generics {
-            parent: g.parent,
-            parent_regions: g.parent_regions,
-            parent_types: g.parent_types,
-            regions: g.regions.decode((self, tcx)).collect(),
-            types: g.types.decode((self, tcx)).collect(),
-            has_self: g.has_self,
-        }
-    }
-
-    pub fn generics_own_param_counts(&self, item_id: DefIndex) -> (usize, usize) {
-        let g = self.entry(item_id).generics.unwrap().decode(self);
-        (g.regions.len, g.types.len)
-    }
-
-    pub fn generics_object_lifetime_defaults(&self, item_id: DefIndex)
-                                             -> Vec<ObjectLifetimeDefault> {
+    pub fn get_generics(&self, item_id: DefIndex) -> ty::Generics {
         self.entry(item_id).generics.unwrap().decode(self)
-                           .object_lifetime_defaults.decode(self).collect()
     }
 
     pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
@@ -688,8 +675,14 @@ impl<'a, 'tcx> CrateMetadata {
     {
         if let Some(ref proc_macros) = self.proc_macros {
             if id == CRATE_DEF_INDEX {
-                for (id, &(name, _)) in proc_macros.iter().enumerate() {
-                    let def = Def::Macro(DefId { krate: self.cnum, index: DefIndex::new(id + 1) });
+                for (id, &(name, ref ext)) in proc_macros.iter().enumerate() {
+                    let def = Def::Macro(
+                        DefId {
+                            krate: self.cnum,
+                            index: DefIndex::new(id + 1)
+                        },
+                        ext.kind()
+                    );
                     callback(def::Export { name: name, def: def });
                 }
             }
@@ -793,16 +786,19 @@ impl<'a, 'tcx> CrateMetadata {
         if self.is_proc_macro(id) { return None; }
         self.entry(id).ast.map(|ast| {
             let def_id = self.local_def_id(id);
-            let ast = ast.decode(self);
-
-            let tables = ast.tables.decode((self, tcx));
-            tcx.tables.borrow_mut().insert(def_id, tcx.alloc_tables(tables));
-
-            let body = ast.body.decode((self, tcx));
+            let body = ast.decode(self).body.decode(self);
             tcx.hir.intern_inlined_body(def_id, body)
         })
     }
 
+    pub fn item_body_tables(&self,
+                            id: DefIndex,
+                            tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                            -> &'tcx ty::TypeckTables<'tcx> {
+        let ast = self.entry(id).ast.unwrap().decode(self);
+        tcx.alloc_tables(ast.tables.decode((self, tcx)))
+    }
+
     pub fn item_body_nested_bodies(&self, id: DefIndex) -> BTreeMap<hir::BodyId, hir::Body> {
         self.entry(id).ast.into_iter().flat_map(|ast| {
             ast.decode(self).nested_bodies.decode(self).map(|body| (body.id(), body))
@@ -829,54 +825,46 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn get_associated_item(&self, id: DefIndex) -> Option<ty::AssociatedItem> {
+    pub fn mir_const_qualif(&self, id: DefIndex) -> u8 {
+        match self.entry(id).kind {
+            EntryKind::Const(qualif) |
+            EntryKind::AssociatedConst(AssociatedContainer::ImplDefault, qualif) |
+            EntryKind::AssociatedConst(AssociatedContainer::ImplFinal, qualif) => {
+                qualif
+            }
+            _ => bug!(),
+        }
+    }
+
+    pub fn get_associated_item(&self, id: DefIndex) -> ty::AssociatedItem {
         let item = self.entry(id);
-        let parent_and_name = || {
-            let def_key = self.def_key(id);
-            (self.local_def_id(def_key.parent.unwrap()),
-             def_key.disambiguated_data.data.get_opt_name().unwrap())
-        };
+        let def_key = self.def_key(id);
+        let parent = self.local_def_id(def_key.parent.unwrap());
+        let name = def_key.disambiguated_data.data.get_opt_name().unwrap();
 
-        Some(match item.kind {
-            EntryKind::AssociatedConst(container) => {
-                let (parent, name) = parent_and_name();
-                ty::AssociatedItem {
-                    name: name,
-                    kind: ty::AssociatedKind::Const,
-                    vis: item.visibility.decode(self),
-                    defaultness: container.defaultness(),
-                    def_id: self.local_def_id(id),
-                    container: container.with_def_id(parent),
-                    method_has_self_argument: false
-                }
+        let (kind, container, has_self) = match item.kind {
+            EntryKind::AssociatedConst(container, _) => {
+                (ty::AssociatedKind::Const, container, false)
             }
             EntryKind::Method(data) => {
-                let (parent, name) = parent_and_name();
                 let data = data.decode(self);
-                ty::AssociatedItem {
-                    name: name,
-                    kind: ty::AssociatedKind::Method,
-                    vis: item.visibility.decode(self),
-                    defaultness: data.container.defaultness(),
-                    def_id: self.local_def_id(id),
-                    container: data.container.with_def_id(parent),
-                    method_has_self_argument: data.has_self
-                }
+                (ty::AssociatedKind::Method, data.container, data.has_self)
             }
             EntryKind::AssociatedType(container) => {
-                let (parent, name) = parent_and_name();
-                ty::AssociatedItem {
-                    name: name,
-                    kind: ty::AssociatedKind::Type,
-                    vis: item.visibility.decode(self),
-                    defaultness: container.defaultness(),
-                    def_id: self.local_def_id(id),
-                    container: container.with_def_id(parent),
-                    method_has_self_argument: false
-                }
+                (ty::AssociatedKind::Type, container, false)
             }
-            _ => return None,
-        })
+            _ => bug!()
+        };
+
+        ty::AssociatedItem {
+            name: name,
+            kind: kind,
+            vis: item.visibility.decode(self),
+            defaultness: container.defaultness(),
+            def_id: self.local_def_id(id),
+            container: container.with_def_id(parent),
+            method_has_self_argument: has_self
+        }
     }
 
     pub fn get_item_variances(&self, id: DefIndex) -> Vec<ty::Variance> {
@@ -1056,13 +1044,6 @@ impl<'a, 'tcx> CrateMetadata {
         self.dllimport_foreign_items.contains(&id)
     }
 
-    pub fn is_defaulted_trait(&self, trait_id: DefIndex) -> bool {
-        match self.entry(trait_id).kind {
-            EntryKind::Trait(data) => data.decode(self).has_default_impl,
-            _ => bug!(),
-        }
-    }
-
     pub fn is_default_impl(&self, impl_id: DefIndex) -> bool {
         match self.entry(impl_id).kind {
             EntryKind::DefaultImpl(_) => true,
@@ -1080,7 +1061,7 @@ impl<'a, 'tcx> CrateMetadata {
     pub fn closure_ty(&self,
                       closure_id: DefIndex,
                       tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                      -> ty::ClosureTy<'tcx> {
+                      -> ty::PolyFnSig<'tcx> {
         match self.entry(closure_id).kind {
             EntryKind::Closure(data) => data.decode(self).ty.decode((self, tcx)),
             _ => bug!(),
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 0f9491aaf15..af0edab7a83 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -36,7 +36,7 @@ use syntax::ast::{self, CRATE_NODE_ID};
 use syntax::codemap::Spanned;
 use syntax::attr;
 use syntax::symbol::Symbol;
-use syntax_pos;
+use syntax_pos::{self, DUMMY_SP};
 
 use rustc::hir::{self, PatKind};
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
@@ -261,7 +261,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         let data = VariantData {
             ctor_kind: variant.ctor_kind,
-            disr: variant.disr_val,
+            discr: variant.discr,
+            evaluated_discr: match variant.discr {
+                ty::VariantDiscr::Explicit(def_id) => {
+                    ty::queries::monomorphic_const_eval::get(tcx, DUMMY_SP, def_id).ok()
+                }
+                ty::VariantDiscr::Relative(_) => None
+            },
             struct_ctor: None,
         };
 
@@ -388,7 +394,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         let data = VariantData {
             ctor_kind: variant.ctor_kind,
-            disr: variant.disr_val,
+            discr: variant.discr,
+            evaluated_discr: None,
             struct_ctor: Some(def_id.index),
         };
 
@@ -423,26 +430,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
     }
 
-    fn encode_generics(&mut self, def_id: DefId) -> Lazy<Generics<'tcx>> {
+    fn encode_generics(&mut self, def_id: DefId) -> Lazy<ty::Generics> {
         let tcx = self.tcx;
-        let g = tcx.item_generics(def_id);
-        let regions = self.lazy_seq_ref(&g.regions);
-        let types = self.lazy_seq_ref(&g.types);
-        let mut object_lifetime_defaults = LazySeq::empty();
-        if let Some(id) = tcx.hir.as_local_node_id(def_id) {
-            if let Some(o) = tcx.named_region_map.object_lifetime_defaults.get(&id) {
-                object_lifetime_defaults = self.lazy_seq_ref(o);
-            }
-        }
-        self.lazy(&Generics {
-            parent: g.parent,
-            parent_regions: g.parent_regions,
-            parent_types: g.parent_types,
-            regions: regions,
-            types: types,
-            has_self: g.has_self,
-            object_lifetime_defaults: object_lifetime_defaults,
-        })
+        self.lazy(tcx.item_generics(def_id))
     }
 
     fn encode_predicates(&mut self, def_id: DefId) -> Lazy<ty::GenericPredicates<'tcx>> {
@@ -467,7 +457,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         };
 
         let kind = match trait_item.kind {
-            ty::AssociatedKind::Const => EntryKind::AssociatedConst(container),
+            ty::AssociatedKind::Const => {
+                EntryKind::AssociatedConst(container, 0)
+            }
             ty::AssociatedKind::Method => {
                 let fn_data = if let hir::TraitItemKind::Method(_, ref m) = ast_item.node {
                     let arg_names = match *m {
@@ -543,7 +535,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         };
 
         let kind = match impl_item.kind {
-            ty::AssociatedKind::Const => EntryKind::AssociatedConst(container),
+            ty::AssociatedKind::Const => {
+                EntryKind::AssociatedConst(container,
+                    ty::queries::mir_const_qualif::get(self.tcx, ast_item.span, def_id))
+            }
             ty::AssociatedKind::Method => {
                 let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
                     FnData {
@@ -614,12 +609,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 
     fn encode_mir(&mut self, def_id: DefId) -> Option<Lazy<mir::Mir<'tcx>>> {
-        self.tcx.mir_map.borrow().get(&def_id).map(|mir| self.lazy(&*mir.borrow()))
+        self.tcx.maps.mir.borrow().get(&def_id).map(|mir| self.lazy(&*mir.borrow()))
     }
 
     // Encodes the inherent implementations of a structure, enumeration, or trait.
     fn encode_inherent_implementations(&mut self, def_id: DefId) -> LazySeq<DefIndex> {
-        match self.tcx.inherent_impls.borrow().get(&def_id) {
+        match self.tcx.maps.inherent_impls.borrow().get(&def_id) {
             None => LazySeq::empty(),
             Some(implementations) => {
                 self.lazy_seq(implementations.iter().map(|&def_id| {
@@ -647,7 +642,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let kind = match item.node {
             hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic,
             hir::ItemStatic(_, hir::MutImmutable, _) => EntryKind::ImmStatic,
-            hir::ItemConst(..) => EntryKind::Const,
+            hir::ItemConst(..) => {
+                EntryKind::Const(ty::queries::mir_const_qualif::get(tcx, item.span, def_id))
+            }
             hir::ItemFn(_, _, constness, .., body) => {
                 let data = FnData {
                     constness: constness,
@@ -661,8 +658,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
             hir::ItemForeignMod(_) => EntryKind::ForeignMod,
             hir::ItemTy(..) => EntryKind::Type,
-            hir::ItemEnum(..) => EntryKind::Enum(self.lazy(&tcx.lookup_adt_def(def_id).discr_ty),
-                                                 get_repr_options(&tcx, def_id)),
+            hir::ItemEnum(..) => EntryKind::Enum(get_repr_options(&tcx, def_id)),
             hir::ItemStruct(ref struct_def, _) => {
                 let variant = tcx.lookup_adt_def(def_id).struct_variant();
 
@@ -679,7 +675,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
                 EntryKind::Struct(self.lazy(&VariantData {
                     ctor_kind: variant.ctor_kind,
-                    disr: variant.disr_val,
+                    discr: variant.discr,
+                    evaluated_discr: None,
                     struct_ctor: struct_ctor,
                 }), repr_options)
             }
@@ -689,7 +686,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
                 EntryKind::Union(self.lazy(&VariantData {
                     ctor_kind: variant.ctor_kind,
-                    disr: variant.disr_val,
+                    discr: variant.discr,
+                    evaluated_discr: None,
                     struct_ctor: None,
                 }), repr_options)
             }
@@ -720,7 +718,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 let data = ImplData {
                     polarity: polarity,
                     parent_impl: parent,
-                    coerce_unsized_kind: tcx.custom_coerce_unsized_kinds
+                    coerce_unsized_kind: tcx.maps.custom_coerce_unsized_kind
                         .borrow()
                         .get(&def_id)
                         .cloned(),
@@ -1008,6 +1006,10 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> {
                           EncodeContext::encode_info_for_foreign_item,
                           (def_id, ni));
     }
+    fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
+        intravisit::walk_generics(self, generics);
+        self.index.encode_info_for_generics(generics);
+    }
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
         intravisit::walk_ty(self, ty);
         self.index.encode_info_for_ty(ty);
@@ -1019,6 +1021,14 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> {
 }
 
 impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
+    fn encode_info_for_generics(&mut self, generics: &hir::Generics) {
+        for ty_param in &generics.ty_params {
+            let def_id = self.tcx.hir.local_def_id(ty_param.id);
+            let has_default = Untracked(ty_param.default.is_some());
+            self.record(def_id, EncodeContext::encode_info_for_ty_param, (def_id, has_default));
+        }
+    }
+
     fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
         if let hir::TyImplTrait(_) = ty.node {
             let def_id = self.tcx.hir.local_def_id(ty.id);
@@ -1038,6 +1048,34 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
 }
 
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+    fn encode_info_for_ty_param(&mut self,
+                                (def_id, Untracked(has_default)): (DefId, Untracked<bool>))
+                                -> Entry<'tcx> {
+        let tcx = self.tcx;
+        Entry {
+            kind: EntryKind::Type,
+            visibility: self.lazy(&ty::Visibility::Public),
+            span: self.lazy(&tcx.def_span(def_id)),
+            attributes: LazySeq::empty(),
+            children: LazySeq::empty(),
+            stability: None,
+            deprecation: None,
+
+            ty: if has_default {
+                Some(self.encode_item_type(def_id))
+            } else {
+                None
+            },
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: None,
+            predicates: None,
+
+            ast: None,
+            mir: None,
+        }
+    }
+
     fn encode_info_for_anon_ty(&mut self, def_id: DefId) -> Entry<'tcx> {
         let tcx = self.tcx;
         Entry {
@@ -1065,7 +1103,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         let data = ClosureData {
             kind: tcx.closure_kind(def_id),
-            ty: self.lazy(&tcx.closure_tys.borrow()[&def_id]),
+            ty: self.lazy(&tcx.closure_type(def_id)),
         };
 
         Entry {
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index 2fbdb8c0de6..0ce886ce9e9 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -20,6 +20,7 @@
 #![feature(box_patterns)]
 #![feature(conservative_impl_trait)]
 #![feature(core_intrinsics)]
+#![cfg_attr(stage0, feature(field_init_shorthand))]
 #![feature(i128_type)]
 #![feature(proc_macro_internals)]
 #![feature(quote)]
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index 777af02772e..4a20913d0b3 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -14,9 +14,9 @@ use index;
 use rustc::hir;
 use rustc::hir::def::{self, CtorKind};
 use rustc::hir::def_id::{DefIndex, DefId};
+use rustc::middle::const_val::ConstVal;
 use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary};
 use rustc::middle::lang_items;
-use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
 use rustc::mir;
 use rustc::ty::{self, Ty, ReprOptions};
 use rustc_back::PanicStrategy;
@@ -212,7 +212,7 @@ pub struct Entry<'tcx> {
     pub ty: Option<Lazy<Ty<'tcx>>>,
     pub inherent_impls: LazySeq<DefIndex>,
     pub variances: LazySeq<ty::Variance>,
-    pub generics: Option<Lazy<Generics<'tcx>>>,
+    pub generics: Option<Lazy<ty::Generics>>,
     pub predicates: Option<Lazy<ty::GenericPredicates<'tcx>>>,
 
     pub ast: Option<Lazy<astencode::Ast<'tcx>>>,
@@ -221,18 +221,18 @@ pub struct Entry<'tcx> {
 
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
 pub enum EntryKind<'tcx> {
-    Const,
+    Const(u8),
     ImmStatic,
     MutStatic,
     ForeignImmStatic,
     ForeignMutStatic,
     ForeignMod,
     Type,
-    Enum(Lazy<attr::IntType>, ReprOptions),
+    Enum(ReprOptions),
     Field,
-    Variant(Lazy<VariantData>),
-    Struct(Lazy<VariantData>, ReprOptions),
-    Union(Lazy<VariantData>, ReprOptions),
+    Variant(Lazy<VariantData<'tcx>>),
+    Struct(Lazy<VariantData<'tcx>>, ReprOptions),
+    Union(Lazy<VariantData<'tcx>>, ReprOptions),
     Fn(Lazy<FnData>),
     ForeignFn(Lazy<FnData>),
     Mod(Lazy<ModData>),
@@ -243,21 +243,7 @@ pub enum EntryKind<'tcx> {
     DefaultImpl(Lazy<ImplData<'tcx>>),
     Method(Lazy<MethodData>),
     AssociatedType(AssociatedContainer),
-    AssociatedConst(AssociatedContainer),
-}
-
-/// A copy of `ty::Generics` which allows lazy decoding of
-/// `regions` and `types` (e.g. knowing the number of type
-/// and lifetime parameters before `TyCtxt` is created).
-#[derive(RustcEncodable, RustcDecodable)]
-pub struct Generics<'tcx> {
-    pub parent: Option<DefId>,
-    pub parent_regions: u32,
-    pub parent_types: u32,
-    pub regions: LazySeq<ty::RegionParameterDef>,
-    pub types: LazySeq<ty::TypeParameterDef<'tcx>>,
-    pub has_self: bool,
-    pub object_lifetime_defaults: LazySeq<ObjectLifetimeDefault>,
+    AssociatedConst(AssociatedContainer, u8),
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
@@ -277,9 +263,10 @@ pub struct FnData {
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct VariantData {
+pub struct VariantData<'tcx> {
     pub ctor_kind: CtorKind,
-    pub disr: u128,
+    pub discr: ty::VariantDiscr,
+    pub evaluated_discr: Option<ConstVal<'tcx>>,
 
     /// If this is a struct's only variant, this
     /// is the index of the "struct ctor" item.
@@ -350,5 +337,5 @@ pub struct MethodData {
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct ClosureData<'tcx> {
     pub kind: ty::ClosureKind,
-    pub ty: Lazy<ty::ClosureTy<'tcx>>,
+    pub ty: Lazy<ty::PolyFnSig<'tcx>>,
 }
diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs
index 0487e277a33..5abfe084f22 100644
--- a/src/librustc_mir/build/expr/as_lvalue.rs
+++ b/src/librustc_mir/build/expr/as_lvalue.rs
@@ -99,6 +99,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             ExprKind::Use { .. } |
             ExprKind::NeverToAny { .. } |
             ExprKind::ReifyFnPointer { .. } |
+            ExprKind::ClosureFnPointer { .. } |
             ExprKind::UnsafeFnPointer { .. } |
             ExprKind::Unsize { .. } |
             ExprKind::Repeat { .. } |
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 7adcc0e730b..7f5d9c36ece 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -112,6 +112,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let source = unpack!(block = this.as_operand(block, source));
                 block.and(Rvalue::Cast(CastKind::UnsafeFnPointer, source, expr.ty))
             }
+            ExprKind::ClosureFnPointer { source } => {
+                let source = unpack!(block = this.as_operand(block, source));
+                block.and(Rvalue::Cast(CastKind::ClosureFnPointer, source, expr.ty))
+            }
             ExprKind::Unsize { source } => {
                 let source = unpack!(block = this.as_operand(block, source));
                 block.and(Rvalue::Cast(CastKind::Unsize, source, expr.ty))
diff --git a/src/librustc_mir/build/expr/category.rs b/src/librustc_mir/build/expr/category.rs
index 6e57c10964c..35173bb598c 100644
--- a/src/librustc_mir/build/expr/category.rs
+++ b/src/librustc_mir/build/expr/category.rs
@@ -70,6 +70,7 @@ impl Category {
             ExprKind::Cast { .. } |
             ExprKind::Use { .. } |
             ExprKind::ReifyFnPointer { .. } |
+            ExprKind::ClosureFnPointer { .. } |
             ExprKind::UnsafeFnPointer { .. } |
             ExprKind::Unsize { .. } |
             ExprKind::Repeat { .. } |
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index e66f2b4e2bf..ae51951b519 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -202,7 +202,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let diverges = match ty.sty {
                     ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
                         // FIXME(canndrew): This is_never should probably be an is_uninhabited
-                        f.sig.skip_binder().output().is_never()
+                        f.output().skip_binder().is_never()
                     }
                     _ => false
                 };
@@ -244,6 +244,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             ExprKind::Cast { .. } |
             ExprKind::Use { .. } |
             ExprKind::ReifyFnPointer { .. } |
+            ExprKind::ClosureFnPointer { .. } |
             ExprKind::UnsafeFnPointer { .. } |
             ExprKind::Unsize { .. } |
             ExprKind::Repeat { .. } |
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index a28bc5d6ce3..6b6acb054b1 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -309,13 +309,13 @@ enum TestKind<'tcx> {
     // test the branches of enum
     SwitchInt {
         switch_ty: Ty<'tcx>,
-        options: Vec<ConstVal>,
-        indices: FxHashMap<ConstVal, usize>,
+        options: Vec<ConstVal<'tcx>>,
+        indices: FxHashMap<ConstVal<'tcx>, usize>,
     },
 
     // test for equality
     Eq {
-        value: ConstVal,
+        value: ConstVal<'tcx>,
         ty: Ty<'tcx>,
     },
 
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 01c0433112b..f4fdf8ade90 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -20,7 +20,7 @@ use build::matches::{Candidate, MatchPair, Test, TestKind};
 use hair::*;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::bitvec::BitVector;
-use rustc::middle::const_val::{ConstVal, ConstInt};
+use rustc::middle::const_val::ConstVal;
 use rustc::ty::{self, Ty};
 use rustc::ty::util::IntTypeExt;
 use rustc::mir::*;
@@ -112,8 +112,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                      test_lvalue: &Lvalue<'tcx>,
                                      candidate: &Candidate<'pat, 'tcx>,
                                      switch_ty: Ty<'tcx>,
-                                     options: &mut Vec<ConstVal>,
-                                     indices: &mut FxHashMap<ConstVal, usize>)
+                                     options: &mut Vec<ConstVal<'tcx>>,
+                                     indices: &mut FxHashMap<ConstVal<'tcx>, usize>)
                                      -> bool
     {
         let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) {
@@ -191,11 +191,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let mut targets = Vec::with_capacity(used_variants + 1);
                 let mut values = Vec::with_capacity(used_variants);
                 let tcx = self.hir.tcx();
-                for (idx, variant) in adt_def.variants.iter().enumerate() {
+                for (idx, discr) in adt_def.discriminants(tcx).enumerate() {
                     target_blocks.place_back() <- if variants.contains(idx) {
-                        let discr = ConstInt::new_inttype(variant.disr_val, adt_def.discr_ty,
-                                                          tcx.sess.target.uint_type,
-                                                          tcx.sess.target.int_type).unwrap();
                         values.push(discr);
                         *(targets.place_back() <- self.cfg.start_new_block())
                     } else {
@@ -212,7 +209,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 }
                 debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
                        num_enum_variants, values, variants);
-                let discr_ty = adt_def.discr_ty.to_ty(tcx);
+                let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
                 let discr = self.temp(discr_ty);
                 self.cfg.push_assign(block, source_info, &discr,
                                      Rvalue::Discriminant(lvalue.clone()));
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index ecdc58ba55d..41374a00123 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -223,6 +223,17 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
     builder.finish(vec![], ty)
 }
 
+pub fn construct_error<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
+                                       body_id: hir::BodyId)
+                                       -> Mir<'tcx> {
+    let span = hir.tcx().hir.span(hir.tcx().hir.body_owner(body_id));
+    let ty = hir.tcx().types.err;
+    let mut builder = Builder::new(hir, span, 0, ty);
+    let source_info = builder.source_info(span);
+    builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
+    builder.finish(vec![], ty)
+}
+
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     fn new(hir: Cx<'a, 'gcx, 'tcx>,
            span: Span,
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index c702a142fab..282361fc13e 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -385,22 +385,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// resolving `break` and `continue`.
     pub fn find_loop_scope(&mut self,
                            span: Span,
-                           label: Option<CodeExtent>)
+                           label: CodeExtent)
                            -> &mut LoopScope<'tcx> {
-        let loop_scopes = &mut self.loop_scopes;
-        match label {
-            None => {
-                // no label? return the innermost loop scope
-                loop_scopes.iter_mut().rev().next()
-            }
-            Some(label) => {
-                // otherwise, find the loop-scope with the correct id
-                loop_scopes.iter_mut()
-                           .rev()
-                           .filter(|loop_scope| loop_scope.extent == label)
-                           .next()
-            }
-        }.unwrap_or_else(|| span_bug!(span, "no enclosing loop scope found?"))
+        // find the loop-scope with the correct id
+        self.loop_scopes.iter_mut()
+            .rev()
+            .filter(|loop_scope| loop_scope.extent == label)
+            .next()
+            .unwrap_or_else(|| span_bug!(span, "no enclosing loop scope found?"))
     }
 
     /// Given a span and the current visibility scope, make a SourceInfo.
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 7eaf1fe1398..f2b89309e4a 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -17,7 +17,7 @@ use hair::cx::to_ref::ToRef;
 use rustc::hir::map;
 use rustc::hir::def::{Def, CtorKind};
 use rustc::middle::const_val::ConstVal;
-use rustc_const_eval::{ConstContext, EvalHint, fatal_const_eval_err};
+use rustc_const_eval::{ConstContext, fatal_const_eval_err};
 use rustc::ty::{self, AdtKind, VariantDef, Ty};
 use rustc::ty::cast::CastKind as TyCastKind;
 use rustc::hir;
@@ -60,6 +60,15 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                     kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() },
                 };
             }
+            Some((ty::adjustment::Adjust::ClosureFnPointer, adjusted_ty)) => {
+                expr = Expr {
+                    temp_lifetime: temp_lifetime,
+                    temp_lifetime_was_shrunk: was_shrunk,
+                    ty: adjusted_ty,
+                    span: self.span,
+                    kind: ExprKind::ClosureFnPointer { source: expr.to_ref() },
+                };
+            }
             Some((ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => {
                 expr = Expr {
                     temp_lifetime: temp_lifetime,
@@ -258,13 +267,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
                 let method = method_callee(cx, expr, ty::MethodCall::expr(expr.id));
 
-                let sig = match method.ty.sty {
-                    ty::TyFnDef(.., fn_ty) => &fn_ty.sig,
-                    _ => span_bug!(expr.span, "type of method is not an fn"),
-                };
+                let sig = method.ty.fn_sig();
 
                 let sig = cx.tcx
-                    .no_late_bound_regions(sig)
+                    .no_late_bound_regions(&sig)
                     .unwrap_or_else(|| span_bug!(expr.span, "method call has late-bound regions"));
 
                 assert_eq!(sig.inputs().len(), 2);
@@ -588,7 +594,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         hir::ExprRepeat(ref v, count) => {
             let tcx = cx.tcx.global_tcx();
             let c = &cx.tcx.hir.body(count).value;
-            let count = match ConstContext::new(tcx, count).eval(c, EvalHint::ExprTypeChecked) {
+            let count = match ConstContext::new(tcx, count).eval(c) {
                 Ok(ConstVal::Integral(ConstInt::Usize(u))) => u,
                 Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
                 Err(s) => fatal_const_eval_err(tcx, &s, c.span, "expression")
@@ -605,14 +611,21 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
         hir::ExprRet(ref v) => ExprKind::Return { value: v.to_ref() },
         hir::ExprBreak(label, ref value) => {
-            ExprKind::Break {
-                label: label.map(|label| cx.tcx.region_maps.node_extent(label.loop_id)),
-                value: value.to_ref(),
+            match label.loop_id.into() {
+                Ok(loop_id) => ExprKind::Break {
+                    label: cx.tcx.region_maps.node_extent(loop_id),
+                    value: value.to_ref(),
+                },
+                Err(err) => bug!("invalid loop id for break: {}", err)
             }
+
         }
         hir::ExprAgain(label) => {
-            ExprKind::Continue {
-                label: label.map(|label| cx.tcx.region_maps.node_extent(label.loop_id)),
+            match label.loop_id.into() {
+                Ok(loop_id) => ExprKind::Continue {
+                    label: cx.tcx.region_maps.node_extent(loop_id),
+                },
+                Err(err) => bug!("invalid loop id for continue: {}", err)
             }
         }
         hir::ExprMatch(ref discr, ref arms, _) => {
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 5b3297cb694..c555ce1ab9c 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -18,7 +18,7 @@ use hair::*;
 use rustc::mir::transform::MirSource;
 
 use rustc::middle::const_val::ConstVal;
-use rustc_const_eval::{ConstContext, EvalHint, fatal_const_eval_err};
+use rustc_const_eval::{ConstContext, fatal_const_eval_err};
 use rustc_data_structures::indexed_vec::Idx;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::blocks::FnLikeNode;
@@ -59,13 +59,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         let mut check_overflow = attrs.iter()
             .any(|item| item.check_name("rustc_inherit_overflow_checks"));
 
-        // Respect -Z force-overflow-checks=on and -C debug-assertions.
-        check_overflow |= infcx.tcx
-            .sess
-            .opts
-            .debugging_opts
-            .force_overflow_checks
-            .unwrap_or(infcx.tcx.sess.opts.debug_assertions);
+        // Respect -C overflow-checks.
+        check_overflow |= infcx.tcx.sess.overflow_checks();
 
         // Constants and const fn's always need overflow checks.
         check_overflow |= constness == hir::Constness::Const;
@@ -118,7 +113,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
 
     pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> {
         let tcx = self.tcx.global_tcx();
-        match ConstContext::with_tables(tcx, self.tables()).eval(e, EvalHint::ExprTypeChecked) {
+        match ConstContext::with_tables(tcx, self.tables()).eval(e) {
             Ok(value) => Literal::Value { value: value },
             Err(s) => fatal_const_eval_err(tcx, &s, e.span, "expression")
         }
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 4ac67cfb2fc..9c7ee6a9ce8 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -152,6 +152,9 @@ pub enum ExprKind<'tcx> {
     ReifyFnPointer {
         source: ExprRef<'tcx>,
     },
+    ClosureFnPointer {
+        source: ExprRef<'tcx>,
+    },
     UnsafeFnPointer {
         source: ExprRef<'tcx>,
     },
@@ -205,11 +208,11 @@ pub enum ExprKind<'tcx> {
         arg: ExprRef<'tcx>,
     },
     Break {
-        label: Option<CodeExtent>,
+        label: CodeExtent,
         value: Option<ExprRef<'tcx>>,
     },
     Continue {
-        label: Option<CodeExtent>,
+        label: CodeExtent,
     },
     Return {
         value: Option<ExprRef<'tcx>>,
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 9a8fb1099d0..a97495a0ebc 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -53,3 +53,9 @@ pub mod mir_map;
 pub mod pretty;
 pub mod transform;
 
+use rustc::ty::maps::Providers;
+
+pub fn provide(providers: &mut Providers) {
+    mir_map::provide(providers);
+    transform::qualify_consts::provide(providers);
+}
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index b7f90682c7c..e0eb09fbf5d 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -17,6 +17,7 @@
 //! - `#[rustc_mir(pretty="file.mir")]`
 
 use build;
+use rustc::hir::def_id::DefId;
 use rustc::dep_graph::DepNode;
 use rustc::mir::Mir;
 use rustc::mir::transform::MirSource;
@@ -24,9 +25,9 @@ use rustc::mir::visit::MutVisitor;
 use pretty;
 use hair::cx::Cx;
 
-use rustc::infer::InferCtxt;
 use rustc::traits::Reveal;
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::maps::Providers;
 use rustc::ty::subst::Substs;
 use rustc::hir;
 use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
@@ -34,6 +35,7 @@ use syntax::abi::Abi;
 use syntax::ast;
 use syntax_pos::Span;
 
+use std::cell::RefCell;
 use std::mem;
 
 pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
@@ -42,6 +44,109 @@ pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     }.as_deep_visitor());
 }
 
+pub fn provide(providers: &mut Providers) {
+    providers.mir = build_mir;
+}
+
+fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
+                       -> &'tcx RefCell<Mir<'tcx>> {
+    let id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let unsupported = || {
+        span_bug!(tcx.hir.span(id), "can't build MIR for {:?}", def_id);
+    };
+
+    // Figure out what primary body this item has.
+    let body_id = match tcx.hir.get(id) {
+        hir::map::NodeItem(item) => {
+            match item.node {
+                hir::ItemConst(_, body) |
+                hir::ItemStatic(_, _, body) |
+                hir::ItemFn(.., body) => body,
+                _ => unsupported()
+            }
+        }
+        hir::map::NodeTraitItem(item) => {
+            match item.node {
+                hir::TraitItemKind::Const(_, Some(body)) |
+                hir::TraitItemKind::Method(_,
+                    hir::TraitMethod::Provided(body)) => body,
+                _ => unsupported()
+            }
+        }
+        hir::map::NodeImplItem(item) => {
+            match item.node {
+                hir::ImplItemKind::Const(_, body) |
+                hir::ImplItemKind::Method(_, body) => body,
+                _ => unsupported()
+            }
+        }
+        hir::map::NodeExpr(expr) => {
+            // FIXME(eddyb) Closures should have separate
+            // function definition IDs and expression IDs.
+            // Type-checking should not let closures get
+            // this far in a constant position.
+            // Assume that everything other than closures
+            // is a constant "initializer" expression.
+            match expr.node {
+                hir::ExprClosure(_, _, body, _) => body,
+                _ => hir::BodyId { node_id: expr.id }
+            }
+        }
+        _ => unsupported()
+    };
+
+    let src = MirSource::from_node(tcx, id);
+    tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
+        let cx = Cx::new(&infcx, src);
+        let mut mir = if cx.tables().tainted_by_errors {
+            build::construct_error(cx, body_id)
+        } else if let MirSource::Fn(id) = src {
+            // fetch the fully liberated fn signature (that is, all bound
+            // types/lifetimes replaced)
+            let fn_sig = cx.tables().liberated_fn_sigs[&id].clone();
+
+            let ty = tcx.item_type(tcx.hir.local_def_id(id));
+            let mut abi = fn_sig.abi;
+            let implicit_argument = if let ty::TyClosure(..) = ty.sty {
+                // HACK(eddyb) Avoid having RustCall on closures,
+                // as it adds unnecessary (and wrong) auto-tupling.
+                abi = Abi::Rust;
+                Some((closure_self_ty(tcx, id, body_id), None))
+            } else {
+                None
+            };
+
+            let body = tcx.hir.body(body_id);
+            let explicit_arguments =
+                body.arguments
+                    .iter()
+                    .enumerate()
+                    .map(|(index, arg)| {
+                        (fn_sig.inputs()[index], Some(&*arg.pat))
+                    });
+
+            let arguments = implicit_argument.into_iter().chain(explicit_arguments);
+            build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body)
+        } else {
+            build::construct_const(cx, body_id)
+        };
+
+        // Convert the Mir to global types.
+        let mut globalizer = GlobalizeMir {
+            tcx: tcx,
+            span: mir.span
+        };
+        globalizer.visit_mir(&mut mir);
+        let mir = unsafe {
+            mem::transmute::<Mir, Mir<'tcx>>(mir)
+        };
+
+        pretty::dump_mir(tcx, "mir_map", &0, src, &mir);
+
+        tcx.alloc_mir(mir)
+    })
+}
+
 /// A pass to lift all the types and substitutions in a Mir
 /// to the global tcx. Sadly, we don't have a "folder" that
 /// can change 'tcx so we have to transmute afterwards.
@@ -79,68 +184,13 @@ struct BuildMir<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>
 }
 
-fn build<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                         body_id: hir::BodyId)
-                         -> (Mir<'tcx>, MirSource) {
-    let tcx = infcx.tcx.global_tcx();
-
-    let item_id = tcx.hir.body_owner(body_id);
-    let src = MirSource::from_node(tcx, item_id);
-    let cx = Cx::new(infcx, src);
-    if let MirSource::Fn(id) = src {
-        // fetch the fully liberated fn signature (that is, all bound
-        // types/lifetimes replaced)
-        let fn_sig = cx.tables().liberated_fn_sigs[&id].clone();
-
-        let ty = tcx.item_type(tcx.hir.local_def_id(id));
-        let (abi, implicit_argument) = if let ty::TyClosure(..) = ty.sty {
-            (Abi::Rust, Some((closure_self_ty(tcx, id, body_id), None)))
-        } else {
-            (ty.fn_abi(), None)
-        };
-
-        let body = tcx.hir.body(body_id);
-        let explicit_arguments =
-            body.arguments
-                .iter()
-                .enumerate()
-                .map(|(index, arg)| {
-                    (fn_sig.inputs()[index], Some(&*arg.pat))
-                });
-
-        let arguments = implicit_argument.into_iter().chain(explicit_arguments);
-        (build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body), src)
-    } else {
-        (build::construct_const(cx, body_id), src)
-    }
-}
-
 impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
         NestedVisitorMap::None
     }
 
     fn visit_nested_body(&mut self, body_id: hir::BodyId) {
-        self.tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| {
-            let (mut mir, src) = build(&infcx, body_id);
-
-            // Convert the Mir to global types.
-            let tcx = infcx.tcx.global_tcx();
-            let mut globalizer = GlobalizeMir {
-                tcx: tcx,
-                span: mir.span
-            };
-            globalizer.visit_mir(&mut mir);
-            let mir = unsafe {
-                mem::transmute::<Mir, Mir<'tcx>>(mir)
-            };
-
-            pretty::dump_mir(tcx, "mir_map", &0, src, &mir);
-
-            let mir = tcx.alloc_mir(mir);
-            let def_id = tcx.hir.local_def_id(src.item_id());
-            tcx.mir_map.borrow_mut().insert(def_id, mir);
-        });
+        self.tcx.item_mir(self.tcx.hir.body_owner_def_id(body_id));
 
         let body = self.tcx.hir.body(body_id);
         self.visit_body(body);
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 4459142cfb2..441a9add883 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -16,24 +16,24 @@
 
 use rustc_data_structures::bitvec::BitVector;
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::map as hir_map;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::traits::{self, Reveal};
-use rustc::ty::{self, TyCtxt, Ty};
+use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
 use rustc::ty::cast::CastTy;
+use rustc::ty::maps::Providers;
 use rustc::mir::*;
 use rustc::mir::traversal::ReversePostorder;
-use rustc::mir::transform::{Pass, MirPass, MirSource};
+use rustc::mir::transform::{Pass, MirMapPass, MirPassHook, MirSource};
 use rustc::mir::visit::{LvalueContext, Visitor};
-use rustc::util::nodemap::DefIdMap;
 use rustc::middle::lang_items;
 use syntax::abi::Abi;
 use syntax::feature_gate::UnstableFeatures;
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
 
-use std::collections::hash_map::Entry;
 use std::fmt;
 use std::usize;
 
@@ -41,36 +41,32 @@ use super::promote_consts::{self, Candidate, TempState};
 
 bitflags! {
     flags Qualif: u8 {
-        // Const item's qualification while recursing.
-        // Recursive consts are an error.
-        const RECURSIVE         = 1 << 0,
-
         // Constant containing interior mutability (UnsafeCell).
-        const MUTABLE_INTERIOR  = 1 << 1,
+        const MUTABLE_INTERIOR  = 1 << 0,
 
         // Constant containing an ADT that implements Drop.
-        const NEEDS_DROP        = 1 << 2,
+        const NEEDS_DROP        = 1 << 1,
 
         // Function argument.
-        const FN_ARGUMENT       = 1 << 3,
+        const FN_ARGUMENT       = 1 << 2,
 
         // Static lvalue or move from a static.
-        const STATIC            = 1 << 4,
+        const STATIC            = 1 << 3,
 
         // Reference to a static.
-        const STATIC_REF        = 1 << 5,
+        const STATIC_REF        = 1 << 4,
 
         // Not constant at all - non-`const fn` calls, asm!,
         // pointer comparisons, ptr-to-int casts, etc.
-        const NOT_CONST         = 1 << 6,
+        const NOT_CONST         = 1 << 5,
 
         // Refers to temporaries which cannot be promoted as
         // promote_consts decided they weren't simple enough.
-        const NOT_PROMOTABLE    = 1 << 7,
+        const NOT_PROMOTABLE    = 1 << 6,
 
         // Borrows of temporaries can be promoted only
         // if they have none of the above qualifications.
-        const NEVER_PROMOTE     = !0,
+        const NEVER_PROMOTE     = 0b111_1111,
 
         // Const items can only have MUTABLE_INTERIOR
         // and NOT_PROMOTABLE without producing an error.
@@ -134,7 +130,6 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     rpo: ReversePostorder<'a, 'tcx>,
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     param_env: ty::ParameterEnvironment<'tcx>,
-    qualif_map: &'a mut DefIdMap<Qualif>,
     temp_qualif: IndexVec<Local, Option<Qualif>>,
     return_qualif: Option<Qualif>,
     qualif: Qualif,
@@ -146,7 +141,6 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
     fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
            param_env: ty::ParameterEnvironment<'tcx>,
-           qualif_map: &'a mut DefIdMap<Qualif>,
            def_id: DefId,
            mir: &'a Mir<'tcx>,
            mode: Mode)
@@ -162,7 +156,6 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
             rpo: rpo,
             tcx: tcx,
             param_env: param_env,
-            qualif_map: qualif_map,
             temp_qualif: IndexVec::from_elem(None, &mir.local_decls),
             return_qualif: None,
             qualif: Qualif::empty(),
@@ -585,17 +578,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                     if substs.types().next().is_some() {
                         self.add_type(constant.ty);
                     } else {
-                        let qualif = qualify_const_item_cached(self.tcx,
-                                                               self.qualif_map,
-                                                               def_id);
-                        self.add(qualif);
-                    }
+                        let bits = ty::queries::mir_const_qualif::get(self.tcx,
+                                                                      constant.span,
+                                                                      def_id);
 
-                    // FIXME(eddyb) check recursive constants here,
-                    // instead of rustc_passes::static_recursion.
-                    if self.qualif.intersects(Qualif::RECURSIVE) {
-                        span_bug!(constant.span,
-                                  "recursive constant wasn't caught earlier");
+                        let qualif = Qualif::from_bits(bits).expect("invalid mir_const_qualif");
+                        self.add(qualif);
                     }
 
                     // Let `const fn` transitively have destructors,
@@ -619,6 +607,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
             Rvalue::CheckedBinaryOp(..) |
             Rvalue::Cast(CastKind::ReifyFnPointer, ..) |
             Rvalue::Cast(CastKind::UnsafeFnPointer, ..) |
+            Rvalue::Cast(CastKind::ClosureFnPointer, ..) |
             Rvalue::Cast(CastKind::Unsize, ..) => {}
 
             Rvalue::Len(_) => {
@@ -757,7 +746,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
 
             Rvalue::Aggregate(ref kind, _) => {
                 if let AggregateKind::Adt(def, ..) = *kind {
-                    if def.has_dtor() {
+                    if def.has_dtor(self.tcx) {
                         self.add(Qualif::NEEDS_DROP);
                         self.deny_drop();
                     }
@@ -787,7 +776,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
             let fn_ty = func.ty(self.mir, self.tcx);
             let (is_shuffle, is_const_fn) = match fn_ty.sty {
                 ty::TyFnDef(def_id, _, f) => {
-                    (f.abi == Abi::PlatformIntrinsic &&
+                    (f.abi() == Abi::PlatformIntrinsic &&
                      self.tcx.item_name(def_id).as_str().starts_with("simd_shuffle"),
                      is_const_fn(self.tcx, def_id))
                 }
@@ -943,41 +932,64 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
     }
 }
 
-fn qualify_const_item_cached<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                       qualif_map: &mut DefIdMap<Qualif>,
-                                       def_id: DefId)
-                                       -> Qualif {
-    match qualif_map.entry(def_id) {
-        Entry::Occupied(entry) => return *entry.get(),
-        Entry::Vacant(entry) => {
-            // Guard against `const` recursion.
-            entry.insert(Qualif::RECURSIVE);
-        }
+pub fn provide(providers: &mut Providers) {
+    providers.mir_const_qualif = qualify_const_item;
+}
+
+fn qualify_const_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                def_id: DefId)
+                                -> u8 {
+    let mir = &tcx.item_mir(def_id);
+    if mir.return_ty.references_error() {
+        return Qualif::NOT_CONST.bits();
     }
 
-    let param_env = if def_id.is_local() {
-        let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
-        ty::ParameterEnvironment::for_item(tcx, node_id)
-    } else {
-        // These should only be monomorphic constants.
-        tcx.empty_parameter_environment()
-    };
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let param_env = ty::ParameterEnvironment::for_item(tcx, node_id);
 
-    let mir = &tcx.item_mir(def_id);
-    let mut qualifier = Qualifier::new(tcx, param_env, qualif_map, def_id, mir, Mode::Const);
-    let qualif = qualifier.qualify_const();
-    qualifier.qualif_map.insert(def_id, qualif);
-    qualif
+    let mut qualifier = Qualifier::new(tcx, param_env, def_id, mir, Mode::Const);
+    qualifier.qualify_const().bits()
 }
 
-#[derive(Default)]
-pub struct QualifyAndPromoteConstants {
-    qualif_map: DefIdMap<Qualif>
-}
+pub struct QualifyAndPromoteConstants;
 
 impl Pass for QualifyAndPromoteConstants {}
 
-impl<'tcx> MirPass<'tcx> for QualifyAndPromoteConstants {
+impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants {
+    fn run_pass<'a>(&mut self,
+                    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                    hooks: &mut [Box<for<'s> MirPassHook<'s>>])
+    {
+        let def_ids = tcx.maps.mir.borrow().keys();
+        for def_id in def_ids {
+            if !def_id.is_local() {
+                continue;
+            }
+
+            let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
+            let id = tcx.hir.as_local_node_id(def_id).unwrap();
+            let src = MirSource::from_node(tcx, id);
+
+            if let MirSource::Const(_) = src {
+                ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id);
+                continue;
+            }
+
+            let mir = &mut tcx.maps.mir.borrow()[&def_id].borrow_mut();
+            tcx.dep_graph.write(DepNode::Mir(def_id));
+
+            for hook in &mut *hooks {
+                hook.on_mir_pass(tcx, src, mir, self, false);
+            }
+            self.run_pass(tcx, src, mir);
+            for hook in &mut *hooks {
+                hook.on_mir_pass(tcx, src, mir, self, true);
+            }
+        }
+    }
+}
+
+impl<'tcx> QualifyAndPromoteConstants {
     fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     src: MirSource, mir: &mut Mir<'tcx>) {
         let id = src.item_id();
@@ -990,18 +1002,9 @@ impl<'tcx> MirPass<'tcx> for QualifyAndPromoteConstants {
                     Mode::Fn
                 }
             }
-            MirSource::Const(_) => {
-                match self.qualif_map.entry(def_id) {
-                    Entry::Occupied(_) => return,
-                    Entry::Vacant(entry) => {
-                        // Guard against `const` recursion.
-                        entry.insert(Qualif::RECURSIVE);
-                        Mode::Const
-                    }
-                }
-            }
             MirSource::Static(_, hir::MutImmutable) => Mode::Static,
             MirSource::Static(_, hir::MutMutable) => Mode::StaticMut,
+            MirSource::Const(_) |
             MirSource::Promoted(..) => return
         };
         let param_env = ty::ParameterEnvironment::for_item(tcx, id);
@@ -1011,7 +1014,6 @@ impl<'tcx> MirPass<'tcx> for QualifyAndPromoteConstants {
             // which can't be mutated until its scope ends.
             let (temps, candidates) = {
                 let mut qualifier = Qualifier::new(tcx, param_env,
-                                                   &mut self.qualif_map,
                                                    def_id, mir, mode);
                 if mode == Mode::ConstFn {
                     // Enforce a constant-like CFG for `const fn`.
@@ -1028,20 +1030,14 @@ impl<'tcx> MirPass<'tcx> for QualifyAndPromoteConstants {
             // Do the actual promotion, now that we know what's viable.
             promote_consts::promote_candidates(mir, tcx, temps, candidates);
         } else {
-            let mut qualifier = Qualifier::new(tcx, param_env,
-                                               &mut self.qualif_map,
-                                               def_id, mir, mode);
-            let qualif = qualifier.qualify_const();
-
-            if mode == Mode::Const {
-                qualifier.qualif_map.insert(def_id, qualif);
-            }
+            let mut qualifier = Qualifier::new(tcx, param_env, def_id, mir, mode);
+            qualifier.qualify_const();
         }
 
         // Statics must be Sync.
         if mode == Mode::Static {
             let ty = mir.return_ty;
-            tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
+            tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
                 let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
                 let mut fulfillment_cx = traits::FulfillmentContext::new();
                 fulfillment_cx.register_bound(&infcx, ty,
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 8d108815e0f..af4a4a53905 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -440,14 +440,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
                 let func_ty = func.ty(mir, tcx);
                 debug!("check_terminator: call, func_ty={:?}", func_ty);
-                let func_ty = match func_ty.sty {
-                    ty::TyFnDef(.., func_ty) | ty::TyFnPtr(func_ty) => func_ty,
+                let sig = match func_ty.sty {
+                    ty::TyFnDef(.., sig) | ty::TyFnPtr(sig) => sig,
                     _ => {
                         span_mirbug!(self, term, "call to non-function {:?}", func_ty);
                         return;
                     }
                 };
-                let sig = tcx.erase_late_bound_regions(&func_ty.sig);
+                let sig = tcx.erase_late_bound_regions(&sig);
                 let sig = self.normalize(&sig);
                 self.check_call_dest(mir, term, &sig, destination);
 
@@ -699,7 +699,7 @@ impl<'tcx> MirPass<'tcx> for TypeckMir {
             return;
         }
         let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
-        tcx.infer_ctxt(param_env, Reveal::NotSpecializable).enter(|infcx| {
+        tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
             let mut checker = TypeChecker::new(&infcx, src.item_id());
             {
                 let mut verifier = TypeVerifier::new(&mut checker, mir);
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 0b55513f831..930a13e36bd 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -28,9 +28,8 @@ use rustc::dep_graph::DepNode;
 use rustc::ty::cast::CastKind;
 use rustc_const_eval::{ConstEvalErr, ConstContext};
 use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math};
-use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath, BadType};
-use rustc_const_eval::ErrKind::UnresolvedPath;
-use rustc_const_eval::EvalHint::ExprTypeChecked;
+use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
+use rustc_const_eval::ErrKind::{TypeckError};
 use rustc_const_math::{ConstMathErr, Op};
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
@@ -66,12 +65,12 @@ struct CheckCrateVisitor<'a, 'tcx: 'a> {
 impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
     fn check_const_eval(&self, expr: &'gcx hir::Expr) {
         let const_cx = ConstContext::with_tables(self.tcx, self.tables);
-        if let Err(err) = const_cx.eval(expr, ExprTypeChecked) {
+        if let Err(err) = const_cx.eval(expr) {
             match err.kind {
                 UnimplementedConstVal(_) => {}
                 IndexOpFeatureGated => {}
                 ErroneousReferencedConstant(_) => {}
-                BadType(_) => {}
+                TypeckError => {}
                 _ => {
                     self.tcx.sess.add_lint(CONST_ERR,
                                            expr.id,
@@ -138,7 +137,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
             self.check_const_eval(&body.value);
         }
 
-        let outer_penv = self.tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| {
+        let outer_penv = self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
             let param_env = infcx.parameter_environment.clone();
             let outer_penv = mem::replace(&mut self.param_env, param_env);
             euv::ExprUseVisitor::new(self, &infcx).consume_body(body);
@@ -240,18 +239,17 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
 
         if self.in_fn && self.promotable {
             let const_cx = ConstContext::with_tables(self.tcx, self.tables);
-            match const_cx.eval(ex, ExprTypeChecked) {
+            match const_cx.eval(ex) {
                 Ok(_) => {}
                 Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) |
                 Err(ConstEvalErr { kind: MiscCatchAll, .. }) |
                 Err(ConstEvalErr { kind: MiscBinaryOp, .. }) |
                 Err(ConstEvalErr { kind: NonConstPath, .. }) |
-                Err(ConstEvalErr { kind: UnresolvedPath, .. }) |
                 Err(ConstEvalErr { kind: ErroneousReferencedConstant(_), .. }) |
                 Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shr)), .. }) |
                 Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shl)), .. }) |
                 Err(ConstEvalErr { kind: IndexOpFeatureGated, .. }) => {}
-                Err(ConstEvalErr { kind: BadType(_), .. }) => {}
+                Err(ConstEvalErr { kind: TypeckError, .. }) => {}
                 Err(msg) => {
                     self.tcx.sess.add_lint(CONST_ERR,
                                            ex.id,
@@ -274,7 +272,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
 /// instead of producing errors.
 fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) {
     match node_ty.sty {
-        ty::TyAdt(def, _) if def.has_dtor() => {
+        ty::TyAdt(def, _) if def.has_dtor(v.tcx) => {
             v.promotable = false;
         }
         _ => {}
@@ -447,6 +445,7 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp
         Some(Adjust::NeverToAny) |
         Some(Adjust::ReifyFnPointer) |
         Some(Adjust::UnsafeFnPointer) |
+        Some(Adjust::ClosureFnPointer) |
         Some(Adjust::MutToConstPointer) => {}
 
         Some(Adjust::DerefRef { autoderefs, .. }) => {
diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs
index ef871959176..5f06eadb84a 100644
--- a/src/librustc_passes/diagnostics.rs
+++ b/src/librustc_passes/diagnostics.rs
@@ -241,6 +241,22 @@ match 5u32 {
 }
 ```
 "##,
+
+E0590: r##"
+`break` or `continue` must include a label when used in the condition of a
+`while` loop.
+
+Example of erroneous code:
+
+```compile_fail
+while break {}
+```
+
+To fix this, add a label specifying which loop is being broken out of:
+```
+`foo: while break `foo {}
+```
+"##
 }
 
 register_diagnostics! {
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index a5bd69fff01..b2d51be5bf7 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -87,23 +87,26 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                 self.with_context(Closure, |v| v.visit_nested_body(b));
             }
             hir::ExprBreak(label, ref opt_expr) => {
+                let loop_id = match label.loop_id.into() {
+                    Ok(loop_id) => loop_id,
+                    Err(hir::LoopIdError::OutsideLoopScope) => ast::DUMMY_NODE_ID,
+                    Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
+                        self.emit_unlabled_cf_in_while_condition(e.span, "break");
+                        ast::DUMMY_NODE_ID
+                    },
+                    Err(hir::LoopIdError::UnresolvedLabel) => ast::DUMMY_NODE_ID,
+                };
+
                 if opt_expr.is_some() {
-                    let loop_kind = if let Some(label) = label {
-                        if label.loop_id == ast::DUMMY_NODE_ID {
-                            None
-                        } else {
-                            Some(match self.hir_map.expect_expr(label.loop_id).node {
-                                hir::ExprWhile(..) => LoopKind::WhileLoop,
-                                hir::ExprLoop(_, _, source) => LoopKind::Loop(source),
-                                ref r => span_bug!(e.span,
-                                                   "break label resolved to a non-loop: {:?}", r),
-                            })
-                        }
-                    } else if let Loop(kind) = self.cx {
-                        Some(kind)
-                    } else {
-                        // `break` outside a loop - caught below
+                    let loop_kind = if loop_id == ast::DUMMY_NODE_ID {
                         None
+                    } else {
+                        Some(match self.hir_map.expect_expr(loop_id).node {
+                            hir::ExprWhile(..) => LoopKind::WhileLoop,
+                            hir::ExprLoop(_, _, source) => LoopKind::Loop(source),
+                            ref r => span_bug!(e.span,
+                                               "break label resolved to a non-loop: {:?}", r),
+                        })
                     };
                     match loop_kind {
                         None | Some(LoopKind::Loop(hir::LoopSource::Loop)) => (),
@@ -117,9 +120,15 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                         }
                     }
                 }
+
                 self.require_loop("break", e.span);
             }
-            hir::ExprAgain(_) => self.require_loop("continue", e.span),
+            hir::ExprAgain(label) => {
+                if let Err(hir::LoopIdError::UnlabeledCfInWhileCondition) = label.loop_id.into() {
+                    self.emit_unlabled_cf_in_while_condition(e.span, "continue");
+                }
+                self.require_loop("continue", e.span)
+            },
             _ => intravisit::walk_expr(self, e),
         }
     }
@@ -150,4 +159,12 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
             }
         }
     }
+
+    fn emit_unlabled_cf_in_while_condition(&mut self, span: Span, cf_type: &str) {
+        struct_span_err!(self.sess, span, E0590,
+                         "`break` or `continue` with no label in the condition of a `while` loop")
+            .span_label(span,
+                        &format!("unlabeled `{}` in the condition of a `while` loop", cf_type))
+            .emit();
+    }
 }
diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs
index 33b7089c382..ad20c535dec 100644
--- a/src/librustc_passes/mir_stats.rs
+++ b/src/librustc_passes/mir_stats.rs
@@ -44,7 +44,7 @@ pub fn print_mir_stats<'tcx, 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, title: &str) {
     // For debugging instrumentation like this, we don't need to worry
     // about maintaining the dep graph.
     let _ignore = tcx.dep_graph.in_ignore();
-    let mir_map = tcx.mir_map.borrow();
+    let mir_map = tcx.maps.mir.borrow();
     for def_id in mir_map.keys() {
         let mir = mir_map.get(&def_id).unwrap();
         collector.visit_mir(&mir.borrow());
diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs
index 9de5ff541a5..c367e71fcd2 100644
--- a/src/librustc_passes/rvalues.rs
+++ b/src/librustc_passes/rvalues.rs
@@ -38,7 +38,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> {
 
     fn visit_nested_body(&mut self, body_id: hir::BodyId) {
         let body = self.tcx.hir.body(body_id);
-        self.tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| {
+        self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
             let mut delegate = RvalueContextDelegate {
                 tcx: infcx.tcx,
                 param_env: &infcx.parameter_environment
diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs
index 1ef8a5b0080..fc05471ead3 100644
--- a/src/librustc_passes/static_recursion.rs
+++ b/src/librustc_passes/static_recursion.rs
@@ -18,7 +18,6 @@ use rustc::hir::def::{Def, CtorKind};
 use rustc::util::nodemap::{NodeMap, NodeSet};
 
 use syntax::ast;
-use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax_pos::Span;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir;
@@ -43,7 +42,7 @@ impl<'a, 'hir: 'a> Visitor<'hir> for CheckCrateVisitor<'a, 'hir> {
         match it.node {
             hir::ItemStatic(..) |
             hir::ItemConst(..) => {
-                let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &it.span);
+                let mut recursion_visitor = CheckItemRecursionVisitor::new(self);
                 recursion_visitor.visit_item(it);
             }
             hir::ItemEnum(ref enum_def, ref generics) => {
@@ -52,8 +51,7 @@ impl<'a, 'hir: 'a> Visitor<'hir> for CheckCrateVisitor<'a, 'hir> {
                 // less redundant output.
                 for variant in &enum_def.variants {
                     if let Some(_) = variant.node.disr_expr {
-                        let mut recursion_visitor = CheckItemRecursionVisitor::new(self,
-                                                                                   &variant.span);
+                        let mut recursion_visitor = CheckItemRecursionVisitor::new(self);
                         recursion_visitor.populate_enum_discriminants(enum_def);
                         recursion_visitor.visit_variant(variant, generics, it.id);
                     }
@@ -68,7 +66,7 @@ impl<'a, 'hir: 'a> Visitor<'hir> for CheckCrateVisitor<'a, 'hir> {
         match ti.node {
             hir::TraitItemKind::Const(_, ref default) => {
                 if let Some(_) = *default {
-                    let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &ti.span);
+                    let mut recursion_visitor = CheckItemRecursionVisitor::new(self);
                     recursion_visitor.visit_trait_item(ti);
                 }
             }
@@ -80,7 +78,7 @@ impl<'a, 'hir: 'a> Visitor<'hir> for CheckCrateVisitor<'a, 'hir> {
     fn visit_impl_item(&mut self, ii: &'hir hir::ImplItem) {
         match ii.node {
             hir::ImplItemKind::Const(..) => {
-                let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &ii.span);
+                let mut recursion_visitor = CheckItemRecursionVisitor::new(self);
                 recursion_visitor.visit_impl_item(ii);
             }
             _ => {}
@@ -105,7 +103,6 @@ pub fn check_crate<'hir>(sess: &Session, hir_map: &hir_map::Map<'hir>) -> Compil
 }
 
 struct CheckItemRecursionVisitor<'a, 'b: 'a, 'hir: 'b> {
-    root_span: &'b Span,
     sess: &'b Session,
     hir_map: &'b hir_map::Map<'hir>,
     discriminant_map: &'a mut NodeMap<Option<hir::BodyId>>,
@@ -114,9 +111,8 @@ struct CheckItemRecursionVisitor<'a, 'b: 'a, 'hir: 'b> {
 }
 
 impl<'a, 'b: 'a, 'hir: 'b> CheckItemRecursionVisitor<'a, 'b, 'hir> {
-    fn new(v: &'a mut CheckCrateVisitor<'b, 'hir>, span: &'b Span) -> Self {
+    fn new(v: &'a mut CheckCrateVisitor<'b, 'hir>) -> Self {
         CheckItemRecursionVisitor {
-            root_span: span,
             sess: v.sess,
             hir_map: v.hir_map,
             discriminant_map: &mut v.discriminant_map,
@@ -143,15 +139,7 @@ impl<'a, 'b: 'a, 'hir: 'b> CheckItemRecursionVisitor<'a, 'b, 'hir> {
                     false
                 }
             });
-            if any_static {
-                if !self.sess.features.borrow().static_recursion {
-                    emit_feature_err(&self.sess.parse_sess,
-                                     "static_recursion",
-                                     *self.root_span,
-                                     GateIssue::Language,
-                                     "recursive static");
-                }
-            } else {
+            if !any_static {
                 struct_span_err!(self.sess, span, E0265, "recursive constant")
                     .span_label(span, &format!("recursion not allowed in constant"))
                     .emit();
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 9dc94745cff..72347f1616e 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -334,7 +334,11 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
 
 impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
     fn generics(&mut self) -> &mut Self {
-        self.ev.tcx.item_generics(self.item_def_id).visit_with(self);
+        for def in &self.ev.tcx.item_generics(self.item_def_id).types {
+            if def.has_default {
+                self.ev.tcx.item_type(def.def_id).visit_with(self);
+            }
+        }
         self
     }
 
@@ -892,7 +896,11 @@ struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
     fn generics(&mut self) -> &mut Self {
-        self.tcx.item_generics(self.item_def_id).visit_with(self);
+        for def in &self.tcx.item_generics(self.item_def_id).types {
+            if def.has_default {
+                self.tcx.item_type(def.def_id).visit_with(self);
+            }
+        }
         self
     }
 
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 4679b6be88b..89cff39c59e 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -462,8 +462,8 @@ impl<'a> Resolver<'a> {
                     self.define(module, ident, ns, (child.def, ty::Visibility::Public,
                                                     DUMMY_SP, Mark::root()));
 
-                    let has_self = self.session.cstore.associated_item(child.def.def_id())
-                                       .map_or(false, |item| item.method_has_self_argument);
+                    let has_self = self.session.cstore.associated_item_cloned(child.def.def_id())
+                                       .method_has_self_argument;
                     self.trait_item_map.insert((def_id, child.name, ns), (child.def, has_self));
                 }
                 module.populated.set(true);
@@ -495,7 +495,7 @@ impl<'a> Resolver<'a> {
 
     pub fn get_macro(&mut self, def: Def) -> Rc<SyntaxExtension> {
         let def_id = match def {
-            Def::Macro(def_id) => def_id,
+            Def::Macro(def_id, ..) => def_id,
             _ => panic!("Expected Def::Macro(..)"),
         };
         if let Some(ext) = self.macro_map.get(&def_id) {
@@ -537,7 +537,6 @@ impl<'a> Resolver<'a> {
                            binding: &'a NameBinding<'a>,
                            span: Span,
                            allow_shadowing: bool) {
-        self.macro_names.insert(name);
         if self.builtin_macros.insert(name, binding).is_some() && !allow_shadowing {
             let msg = format!("`{}` is already in scope", name);
             let note =
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index 2fada8a9ec2..8f6b1b8971e 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -15,6 +15,33 @@
 // use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
 register_long_diagnostics! {
 
+E0128: r##"
+Type parameter defaults can only use parameters that occur before them.
+Erroneous code example:
+
+```compile_fail,E0128
+struct Foo<T=U, U=()> {
+    field1: T,
+    filed2: U,
+}
+// error: type parameters with a default cannot use forward declared
+// identifiers
+```
+
+Since type parameters are evaluated in-order, you may be able to fix this issue
+by doing:
+
+```
+struct Foo<U=(), T=U> {
+    field1: T,
+    filed2: U,
+}
+```
+
+Please also verify that this wasn't because of a name-clash and rename the type
+parameter if so.
+"##,
+
 E0154: r##"
 ## Note: this error code is no longer emitted by the compiler.
 
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index c9e870188aa..0565db28ec5 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -136,6 +136,8 @@ enum ResolutionError<'a> {
     AttemptToUseNonConstantValueInConstant,
     /// error E0530: X bindings cannot shadow Ys
     BindingShadowsSomethingUnacceptable(&'a str, Name, &'a NameBinding<'a>),
+    /// error E0128: type parameters with a default cannot use forward declared identifiers
+    ForwardDeclaredTyParam,
 }
 
 fn resolve_error<'sess, 'a>(resolver: &'sess Resolver,
@@ -322,6 +324,14 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
             err.span_label(binding.span, msg);
             err
         }
+        ResolutionError::ForwardDeclaredTyParam => {
+            let mut err = struct_span_err!(resolver.session, span, E0128,
+                                           "type parameters with a default cannot use \
+                                            forward declared identifiers");
+            err.span_label(span, &format!("defaulted type parameters \
+                                           cannot be forward declared"));
+            err
+        }
     }
 }
 
@@ -674,6 +684,32 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
         self.label_ribs.pop();
         self.ribs[ValueNS].pop();
     }
+    fn visit_generics(&mut self, generics: &'tcx Generics) {
+        // For type parameter defaults, we have to ban access
+        // to following type parameters, as the Substs can only
+        // provide previous type parameters as they're built.
+        let mut default_ban_rib = Rib::new(ForwardTyParamBanRibKind);
+        default_ban_rib.bindings.extend(generics.ty_params.iter()
+            .skip_while(|p| p.default.is_none())
+            .map(|p| (Ident::with_empty_ctxt(p.ident.name), Def::Err)));
+
+        for param in &generics.ty_params {
+            for bound in &param.bounds {
+                self.visit_ty_param_bound(bound);
+            }
+
+            if let Some(ref ty) = param.default {
+                self.ribs[TypeNS].push(default_ban_rib);
+                self.visit_ty(ty);
+                default_ban_rib = self.ribs[TypeNS].pop().unwrap();
+            }
+
+            // Allow all following defaults to refer to this type parameter.
+            default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name));
+        }
+        for lt in &generics.lifetimes { self.visit_lifetime_def(lt); }
+        for p in &generics.where_clause.predicates { self.visit_where_predicate(p); }
+    }
 }
 
 pub type ErrorMessage = Option<(Span, String)>;
@@ -718,6 +754,11 @@ enum RibKind<'a> {
 
     // We passed through a `macro_rules!` statement with the given expansion
     MacroDefinition(Mark),
+
+    // All bindings in this rib are type parameters that can't be used
+    // from the default of a type parameter because they're not declared
+    // before said type parameter. Also see the `visit_generics` override.
+    ForwardTyParamBanRibKind,
 }
 
 /// One local scope.
@@ -736,13 +777,6 @@ impl<'a> Rib<'a> {
     }
 }
 
-/// A definition along with the index of the rib it was found on
-#[derive(Copy, Clone, Debug)]
-struct LocalDef {
-    ribs: Option<(Namespace, usize)>,
-    def: Def,
-}
-
 enum LexicalScopeBinding<'a> {
     Item(&'a NameBinding<'a>),
     Def(Def),
@@ -1265,7 +1299,7 @@ impl<'a> Resolver<'a> {
             ribs: PerNS {
                 value_ns: vec![Rib::new(ModuleRibKind(graph_root))],
                 type_ns: vec![Rib::new(ModuleRibKind(graph_root))],
-                macro_ns: None,
+                macro_ns: Some(vec![Rib::new(ModuleRibKind(graph_root))]),
             },
             label_ribs: Vec::new(),
 
@@ -1428,7 +1462,7 @@ impl<'a> Resolver<'a> {
             if let Some(def) = self.ribs[ns][i].bindings.get(&ident).cloned() {
                 // The ident resolves to a type parameter or local variable.
                 return Some(LexicalScopeBinding::Def(
-                    self.adjust_local_def(LocalDef { ribs: Some((ns, i)), def: def }, record_used)
+                    self.adjust_local_def(ns, i, def, record_used)
                 ));
             }
 
@@ -2328,10 +2362,13 @@ impl<'a> Resolver<'a> {
                 };
             }
         }
-        if primary_ns != MacroNS && path.len() == 1 &&
-                self.macro_names.contains(&path[0].name) {
+        let is_builtin = self.builtin_macros.get(&path[0].name).cloned()
+            .map(|binding| binding.get_macro(self).kind() == MacroKind::Bang).unwrap_or(false);
+        if primary_ns != MacroNS && (is_builtin || self.macro_names.contains(&path[0].name)) {
             // Return some dummy definition, it's enough for error reporting.
-            return Some(PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX))));
+            return Some(
+                PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang))
+            );
         }
         fin_res
     }
@@ -2524,12 +2561,23 @@ impl<'a> Resolver<'a> {
     }
 
     // Resolve a local definition, potentially adjusting for closures.
-    fn adjust_local_def(&mut self, local_def: LocalDef, record_used: Option<Span>) -> Def {
-        let ribs = match local_def.ribs {
-            Some((ns, i)) => &self.ribs[ns][i + 1..],
-            None => &[] as &[_],
-        };
-        let mut def = local_def.def;
+    fn adjust_local_def(&mut self,
+                        ns: Namespace,
+                        rib_index: usize,
+                        mut def: Def,
+                        record_used: Option<Span>) -> Def {
+        let ribs = &self.ribs[ns][rib_index + 1..];
+
+        // An invalid forward use of a type parameter from a previous default.
+        if let ForwardTyParamBanRibKind = self.ribs[ns][rib_index].kind {
+            if let Some(span) = record_used {
+                resolve_error(self, span,
+                        ResolutionError::ForwardDeclaredTyParam);
+            }
+            assert_eq!(def, Def::Err);
+            return Def::Err;
+        }
+
         match def {
             Def::Upvar(..) => {
                 span_bug!(record_used.unwrap_or(DUMMY_SP), "unexpected {:?} in bindings", def)
@@ -2537,7 +2585,8 @@ impl<'a> Resolver<'a> {
             Def::Local(def_id) => {
                 for rib in ribs {
                     match rib.kind {
-                        NormalRibKind | ModuleRibKind(..) | MacroDefinition(..) => {
+                        NormalRibKind | ModuleRibKind(..) | MacroDefinition(..) |
+                        ForwardTyParamBanRibKind => {
                             // Nothing to do. Continue.
                         }
                         ClosureRibKind(function_id) => {
@@ -2590,7 +2639,7 @@ impl<'a> Resolver<'a> {
                 for rib in ribs {
                     match rib.kind {
                         NormalRibKind | MethodRibKind(_) | ClosureRibKind(..) |
-                        ModuleRibKind(..) | MacroDefinition(..) => {
+                        ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind => {
                             // Nothing to do. Continue.
                         }
                         ItemRibKind => {
@@ -2768,18 +2817,24 @@ impl<'a> Resolver<'a> {
         }
     }
 
-    fn resolve_labeled_block(&mut self, label: Option<SpannedIdent>, id: NodeId, block: &Block) {
+    fn with_resolved_label<F>(&mut self, label: Option<SpannedIdent>, id: NodeId, f: F)
+        where F: FnOnce(&mut Resolver)
+    {
         if let Some(label) = label {
             let def = Def::Label(id);
             self.with_label_rib(|this| {
                 this.label_ribs.last_mut().unwrap().bindings.insert(label.node, def);
-                this.visit_block(block);
+                f(this);
             });
         } else {
-            self.visit_block(block);
+            f(self);
         }
     }
 
+    fn resolve_labeled_block(&mut self, label: Option<SpannedIdent>, id: NodeId, block: &Block) {
+        self.with_resolved_label(label, id, |this| this.visit_block(block));
+    }
+
     fn resolve_expr(&mut self, expr: &Expr, parent: Option<&ExprKind>) {
         // First, record candidate traits for this expression if it could
         // result in the invocation of a method call.
@@ -2833,18 +2888,18 @@ impl<'a> Resolver<'a> {
             ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block),
 
             ExprKind::While(ref subexpression, ref block, label) => {
-                self.visit_expr(subexpression);
-                self.resolve_labeled_block(label, expr.id, &block);
+                self.with_resolved_label(label, expr.id, |this| {
+                    this.visit_expr(subexpression);
+                    this.visit_block(block);
+                });
             }
 
             ExprKind::WhileLet(ref pattern, ref subexpression, ref block, label) => {
-                self.visit_expr(subexpression);
-                self.ribs[ValueNS].push(Rib::new(NormalRibKind));
-                self.resolve_pattern(pattern, PatternSource::WhileLet, &mut FxHashMap());
-
-                self.resolve_labeled_block(label, expr.id, block);
-
-                self.ribs[ValueNS].pop();
+                self.with_resolved_label(label, expr.id, |this| {
+                    this.visit_expr(subexpression);
+                    this.resolve_pattern(pattern, PatternSource::WhileLet, &mut FxHashMap());
+                    this.visit_block(block);
+                });
             }
 
             ExprKind::ForLoop(ref pattern, ref subexpression, ref block, label) => {
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 8d563d20549..b7068f4b09f 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -23,7 +23,7 @@ use syntax::ast::{self, Name, Ident};
 use syntax::attr;
 use syntax::errors::DiagnosticBuilder;
 use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator};
-use syntax::ext::base::{NormalTT, Resolver as SyntaxResolver, SyntaxExtension};
+use syntax::ext::base::{Resolver as SyntaxResolver, SyntaxExtension};
 use syntax::ext::base::MacroKind;
 use syntax::ext::expand::{Expansion, mark_tts};
 use syntax::ext::hygiene::Mark;
@@ -152,16 +152,14 @@ impl<'a> base::Resolver for Resolver<'a> {
     }
 
     fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
-        if let NormalTT(..) = *ext {
-            self.macro_names.insert(ident.name);
-        }
         let def_id = DefId {
             krate: BUILTIN_MACROS_CRATE,
             index: DefIndex::new(self.macro_map.len()),
         };
+        let kind = ext.kind();
         self.macro_map.insert(def_id, ext);
         let binding = self.arenas.alloc_name_binding(NameBinding {
-            kind: NameBindingKind::Def(Def::Macro(def_id)),
+            kind: NameBindingKind::Def(Def::Macro(def_id, kind)),
             span: DUMMY_SP,
             vis: ty::Visibility::Invisible,
             expansion: Mark::root(),
@@ -181,6 +179,11 @@ impl<'a> base::Resolver for Resolver<'a> {
     fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>)
                               -> Option<ast::Attribute> {
         for i in 0..attrs.len() {
+            if self.session.plugin_attributes.borrow().iter()
+                    .any(|&(ref attr_nm, _)| attrs[i].name() == &**attr_nm) {
+                attr::mark_known(&attrs[i]);
+            }
+
             match self.builtin_macros.get(&attrs[i].name()).cloned() {
                 Some(binding) => match *binding.get_macro(self) {
                     MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
@@ -465,24 +468,40 @@ impl<'a> Resolver<'a> {
 
     fn suggest_macro_name(&mut self, name: &str, kind: MacroKind,
                           err: &mut DiagnosticBuilder<'a>) {
-        let suggestion = match kind {
-            MacroKind::Bang =>
-                find_best_match_for_name(self.macro_names.iter(), name, None),
-            MacroKind::Attr |
-            MacroKind::Derive => {
-                // Find a suggestion from the legacy namespace.
-                // FIXME: get_macro needs an &mut Resolver, can we do it without cloning?
-                let builtin_macros = self.builtin_macros.clone();
-                let names = builtin_macros.iter().filter_map(|(name, binding)| {
-                    if binding.get_macro(self).kind() == kind {
-                        Some(name)
-                    } else {
-                        None
-                    }
-                });
-                find_best_match_for_name(names, name, None)
+        // First check if this is a locally-defined bang macro.
+        let suggestion = if let MacroKind::Bang = kind {
+            find_best_match_for_name(self.macro_names.iter(), name, None)
+        } else {
+            None
+        // Then check builtin macros.
+        }.or_else(|| {
+            // FIXME: get_macro needs an &mut Resolver, can we do it without cloning?
+            let builtin_macros = self.builtin_macros.clone();
+            let names = builtin_macros.iter().filter_map(|(name, binding)| {
+                if binding.get_macro(self).kind() == kind {
+                    Some(name)
+                } else {
+                    None
+                }
+            });
+            find_best_match_for_name(names, name, None)
+        // Then check modules.
+        }).or_else(|| {
+            if !self.use_extern_macros {
+                return None;
             }
-        };
+            let is_macro = |def| {
+                if let Def::Macro(_, def_kind) = def {
+                    def_kind == kind
+                } else {
+                    false
+                }
+            };
+            let ident = Ident::from_str(name);
+            self.lookup_typo_candidate(&vec![ident], MacroNS, is_macro)
+                .as_ref().map(|s| Symbol::intern(s))
+        });
+
         if let Some(suggestion) = suggestion {
             if suggestion != name {
                 if let MacroKind::Bang = kind {
@@ -561,7 +580,7 @@ impl<'a> Resolver<'a> {
             });
             self.macro_exports.push(Export {
                 name: def.ident.name,
-                def: Def::Macro(self.definitions.local_def_id(def.id)),
+                def: Def::Macro(self.definitions.local_def_id(def.id), MacroKind::Bang),
             });
             self.exported_macros.push(def);
         }
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 292f1eb1366..3c275e0996d 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -112,7 +112,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, D>)
     {
         let item_def_id = self.tcx.hir.local_def_id(item_id);
-        match self.tcx.tables.borrow().get(&item_def_id) {
+        match self.tcx.maps.typeck_tables.borrow().get(&item_def_id) {
             Some(tables) => {
                 let old_tables = self.save_ctxt.tables;
                 self.save_ctxt.tables = tables;
@@ -336,7 +336,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             Def::AssociatedTy(..) |
             Def::AssociatedConst(..) |
             Def::PrimTy(_) |
-            Def::Macro(_) |
+            Def::Macro(..) |
             Def::Err => {
                span_bug!(span,
                          "process_def_kind for unexpected item: {:?}",
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index ddc60fe5f81..b1e435dcc75 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -85,7 +85,7 @@ pub mod recorder {
 pub struct SaveContext<'l, 'tcx: 'l> {
     tcx: TyCtxt<'l, 'tcx, 'tcx>,
     tables: &'l ty::TypeckTables<'tcx>,
-    analysis: &'l ty::CrateAnalysis<'tcx>,
+    analysis: &'l ty::CrateAnalysis,
     span_utils: SpanUtils<'tcx>,
 }
 
@@ -550,7 +550,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 match *qpath {
                     hir::QPath::Resolved(_, ref path) => path.def,
                     hir::QPath::TypeRelative(..) => {
-                        if let Some(ty) = self.analysis.hir_ty_to_ty.get(&id) {
+                        if let Some(ty) = self.tcx.ast_ty_to_ty_cache.borrow().get(&id) {
                             if let ty::TyProjection(proj) = ty.sty {
                                 for item in self.tcx.associated_items(proj.trait_ref.def_id) {
                                     if item.kind == ty::AssociatedKind::Type {
@@ -854,7 +854,7 @@ impl Format {
 
 pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>,
                                krate: &ast::Crate,
-                               analysis: &'l ty::CrateAnalysis<'tcx>,
+                               analysis: &'l ty::CrateAnalysis,
                                cratename: &str,
                                odir: Option<&Path>,
                                format: Format) {
diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs
index 89525b27ed3..b5add6404fc 100644
--- a/src/librustc_save_analysis/span_utils.rs
+++ b/src/librustc_save_analysis/span_utils.rs
@@ -17,7 +17,6 @@ use std::env;
 use std::path::Path;
 
 use syntax::ast;
-use syntax::parse::filemap_to_tts;
 use syntax::parse::lexer::{self, StringReader};
 use syntax::parse::token::{self, Token};
 use syntax::symbol::keywords;
@@ -49,23 +48,6 @@ impl<'a> SpanUtils<'a> {
         }
     }
 
-    // sub_span starts at span.lo, so we need to adjust the positions etc.
-    // If sub_span is None, we don't need to adjust.
-    pub fn make_sub_span(&self, span: Span, sub_span: Option<Span>) -> Option<Span> {
-        match sub_span {
-            None => None,
-            Some(sub) => {
-                let FileMapAndBytePos {fm, pos} = self.sess.codemap().lookup_byte_offset(span.lo);
-                let base = pos + fm.start_pos;
-                Some(Span {
-                    lo: base + self.sess.codemap().lookup_byte_offset(sub.lo).pos,
-                    hi: base + self.sess.codemap().lookup_byte_offset(sub.hi).pos,
-                    expn_id: span.expn_id,
-                })
-            }
-        }
-    }
-
     pub fn snippet(&self, span: Span) -> String {
         match self.sess.codemap().span_to_snippet(span) {
             Ok(s) => s,
@@ -74,24 +56,7 @@ impl<'a> SpanUtils<'a> {
     }
 
     pub fn retokenise_span(&self, span: Span) -> StringReader<'a> {
-        // sadness - we don't have spans for sub-expressions nor access to the tokens
-        // so in order to get extents for the function name itself (which dxr expects)
-        // we need to re-tokenise the fn definition
-
-        // Note: this is a bit awful - it adds the contents of span to the end of
-        // the codemap as a new filemap. This is mostly OK, but means we should
-        // not iterate over the codemap. Also, any spans over the new filemap
-        // are incompatible with spans over other filemaps.
-        let filemap = self.sess
-                          .codemap()
-                          .new_filemap(String::from("<anon-dxr>"), None, self.snippet(span));
-        lexer::StringReader::new(&self.sess.parse_sess, filemap)
-    }
-
-    fn span_to_tts(&self, span: Span) -> Vec<TokenTree> {
-        let filename = String::from("<anon-dxr>");
-        let filemap = self.sess.codemap().new_filemap(filename, None, self.snippet(span));
-        filemap_to_tts(&self.sess.parse_sess, filemap)
+        lexer::StringReader::retokenize(&self.sess.parse_sess, span)
     }
 
     // Re-parses a path and returns the span for the last identifier in the path
@@ -103,7 +68,7 @@ impl<'a> SpanUtils<'a> {
         loop {
             let ts = toks.real_token();
             if ts.tok == token::Eof {
-                return self.make_sub_span(span, result)
+                return result
             }
             if bracket_count == 0 && (ts.tok.is_ident() || ts.tok.is_keyword(keywords::SelfValue)) {
                 result = Some(ts.sp);
@@ -128,7 +93,7 @@ impl<'a> SpanUtils<'a> {
                 return None;
             }
             if bracket_count == 0 && (ts.tok.is_ident() || ts.tok.is_keyword(keywords::SelfValue)) {
-                return self.make_sub_span(span, Some(ts.sp));
+                return Some(ts.sp);
             }
 
             bracket_count += match ts.tok {
@@ -178,10 +143,7 @@ impl<'a> SpanUtils<'a> {
             }
             prev = next;
         }
-        if result.is_none() && prev_span.is_some() {
-            return self.make_sub_span(span, prev_span);
-        }
-        return self.make_sub_span(span, result);
+        result.or(prev_span)
     }
 
     // Return the span for the last ident before a `<` and outside any
@@ -241,9 +203,9 @@ impl<'a> SpanUtils<'a> {
                       loc.line);
         }
         if result.is_none() && prev.tok.is_ident() && angle_count == 0 {
-            return self.make_sub_span(span, Some(prev.sp));
+            return Some(prev.sp);
         }
-        self.make_sub_span(span, result)
+        result
     }
 
     // Reparse span and return an owned vector of sub spans of the first limit
@@ -310,7 +272,7 @@ impl<'a> SpanUtils<'a> {
                 angle_count += 1;
             }
             if ts.tok.is_ident() && angle_count == nesting {
-                result.push(self.make_sub_span(span, Some(ts.sp)).unwrap());
+                result.push(ts.sp);
             }
         }
     }
@@ -320,8 +282,11 @@ impl<'a> SpanUtils<'a> {
     /// end of the 'signature' part, that is up to, but not including an opening
     /// brace or semicolon.
     pub fn signature_string_for_span(&self, span: Span) -> String {
-        let mut toks = self.span_to_tts(span).into_iter();
+        let mut toks = self.retokenise_span(span);
+        toks.real_token();
+        let mut toks = toks.parse_all_token_trees().unwrap().into_iter();
         let mut prev = toks.next().unwrap();
+
         let first_span = prev.get_span();
         let mut angle_count = 0;
         for tok in toks {
@@ -360,7 +325,7 @@ impl<'a> SpanUtils<'a> {
             }
             let next = toks.real_token();
             if next.tok == tok {
-                return self.make_sub_span(span, Some(prev.sp));
+                return Some(prev.sp);
             }
             prev = next;
         }
@@ -374,7 +339,7 @@ impl<'a> SpanUtils<'a> {
                 return None;
             }
             if next.tok == tok {
-                return self.make_sub_span(span, Some(next.sp));
+                return Some(next.sp);
             }
         }
     }
@@ -399,7 +364,7 @@ impl<'a> SpanUtils<'a> {
                 if ts.tok == token::Eof {
                     return None
                 } else {
-                    return self.make_sub_span(span, Some(ts.sp));
+                    return Some(ts.sp);
                 }
             }
         }
@@ -444,7 +409,7 @@ impl<'a> SpanUtils<'a> {
             if ts.tok == token::Not {
                 let ts = toks.real_token();
                 if ts.tok.is_ident() {
-                    return self.make_sub_span(span, Some(ts.sp));
+                    return Some(ts.sp);
                 } else {
                     return None;
                 }
@@ -463,7 +428,7 @@ impl<'a> SpanUtils<'a> {
             let ts = toks.real_token();
             if ts.tok == token::Not {
                 if prev.tok.is_ident() {
-                    return self.make_sub_span(span, Some(prev.sp));
+                    return Some(prev.sp);
                 } else {
                     return None;
                 }
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index a476b1d29e5..b44cd20e440 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -327,20 +327,18 @@ pub struct FnType {
 
 impl FnType {
     pub fn new<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                         abi: Abi,
-                         sig: &ty::FnSig<'tcx>,
+                         sig: ty::FnSig<'tcx>,
                          extra_args: &[Ty<'tcx>]) -> FnType {
-        let mut fn_ty = FnType::unadjusted(ccx, abi, sig, extra_args);
-        fn_ty.adjust_for_abi(ccx, abi, sig);
+        let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args);
+        fn_ty.adjust_for_abi(ccx, sig);
         fn_ty
     }
 
     pub fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                abi: Abi,
-                                sig: &ty::FnSig<'tcx>,
+                                sig: ty::FnSig<'tcx>,
                                 extra_args: &[Ty<'tcx>]) -> FnType {
         use self::Abi::*;
-        let cconv = match ccx.sess().target.target.adjust_abi(abi) {
+        let cconv = match ccx.sess().target.target.adjust_abi(sig.abi) {
             RustIntrinsic | PlatformIntrinsic |
             Rust | RustCall => llvm::CCallConv,
 
@@ -363,7 +361,7 @@ impl FnType {
         };
 
         let mut inputs = sig.inputs();
-        let extra_args = if abi == RustCall {
+        let extra_args = if sig.abi == RustCall {
             assert!(!sig.variadic && extra_args.is_empty());
 
             match sig.inputs().last().unwrap().sty {
@@ -388,7 +386,7 @@ impl FnType {
         let linux_s390x = target.target_os == "linux"
                        && target.arch == "s390x"
                        && target.target_env == "gnu";
-        let rust_abi = match abi {
+        let rust_abi = match sig.abi {
             RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true,
             _ => false
         };
@@ -506,7 +504,11 @@ impl FnType {
                 if let Some(inner) = rust_ptr_attrs(ty, &mut data) {
                     data.attrs.set(ArgAttribute::NonNull);
                     if ccx.tcx().struct_tail(inner).is_trait() {
+                        // vtables can be safely marked non-null, readonly
+                        // and noalias.
                         info.attrs.set(ArgAttribute::NonNull);
+                        info.attrs.set(ArgAttribute::ReadOnly);
+                        info.attrs.set(ArgAttribute::NoAlias);
                     }
                 }
                 args.push(data);
@@ -531,8 +533,8 @@ impl FnType {
 
     pub fn adjust_for_abi<'a, 'tcx>(&mut self,
                                     ccx: &CrateContext<'a, 'tcx>,
-                                    abi: Abi,
-                                    sig: &ty::FnSig<'tcx>) {
+                                    sig: ty::FnSig<'tcx>) {
+        let abi = sig.abi;
         if abi == Abi::Unadjusted { return }
 
         if abi == Abi::Rust || abi == Abi::RustCall ||
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 41c0eaa52a7..8125f432ff5 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -47,7 +47,7 @@ use rustc::util::common::time;
 use session::config::{self, NoDebugInfo};
 use rustc_incremental::IncrementalHashesMap;
 use session::{self, DataTypeKind, Session};
-use abi::{self, Abi, FnType};
+use abi::{self, FnType};
 use mir::lvalue::LvalueRef;
 use adt;
 use attributes;
@@ -472,8 +472,15 @@ pub fn load_fat_ptr<'a, 'tcx>(
         b.load(ptr, alignment.to_align())
     };
 
-    // FIXME: emit metadata on `meta`.
-    let meta = b.load(get_meta(b, src), alignment.to_align());
+    let meta = get_meta(b, src);
+    let meta_ty = val_ty(meta);
+    // If the 'meta' field is a pointer, it's a vtable, so use load_nonnull
+    // instead
+    let meta = if meta_ty.element_type().kind() == llvm::TypeKind::Pointer {
+        b.load_nonnull(meta, None)
+    } else {
+        b.load(meta, None)
+    };
 
     (ptr, meta)
 }
@@ -593,8 +600,8 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
     let fn_ty = ccx.tcx().erase_regions(&fn_ty);
     let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty);
 
-    let ty::BareFnTy { abi, ref sig, .. } = *common::ty_fn_ty(ccx, fn_ty);
-    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(sig);
+    let sig = common::ty_fn_sig(ccx, fn_ty);
+    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig);
 
     let lldecl = match ccx.instances().borrow().get(&instance) {
         Some(&val) => val,
@@ -607,10 +614,8 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
         attributes::emit_uwtable(lldecl, true);
     }
 
-    let fn_ty = FnType::new(ccx, abi, &sig, &[]);
-
     let mir = ccx.tcx().item_mir(instance.def);
-    mir::trans_mir(ccx, lldecl, fn_ty, &mir, instance, &sig, abi);
+    mir::trans_mir(ccx, lldecl, &mir, instance, sig);
 }
 
 pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
@@ -625,7 +630,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let ctor_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &ctor_ty);
 
     let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&ctor_ty.fn_sig());
-    let fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
+    let fn_ty = FnType::new(ccx, sig, &[]);
 
     let bcx = Builder::new_block(ccx, llfn, "entry-block");
     if !fn_ty.ret.is_ignore() {
@@ -1132,11 +1137,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let ty::CrateAnalysis { export_map, reachable, name, .. } = analysis;
     let exported_symbols = find_exported_symbols(tcx, reachable);
 
-    let check_overflow = if let Some(v) = tcx.sess.opts.debugging_opts.force_overflow_checks {
-        v
-    } else {
-        tcx.sess.opts.debug_assertions
-    };
+    let check_overflow = tcx.sess.overflow_checks();
 
     let link_meta = link::build_link_meta(incremental_hashes_map, &name);
 
diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs
index f64e581c177..a62f07042a7 100644
--- a/src/librustc_trans/builder.rs
+++ b/src/librustc_trans/builder.rs
@@ -1149,6 +1149,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
     }
 
+    pub fn set_invariant_load(&self, load: ValueRef) {
+        unsafe {
+            llvm::LLVMSetMetadata(load, llvm::MD_invariant_load as c_uint,
+                                  llvm::LLVMMDNodeInContext(self.ccx.llcx(), ptr::null(), 0));
+        }
+    }
+
     /// Returns the ptr value that should be used for storing `val`.
     fn check_store<'b>(&self,
                        val: ValueRef,
@@ -1181,7 +1188,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
 
         assert!(fn_ty.kind() == llvm::TypeKind::Function,
-                "builder::{} not passed a function", typ);
+                "builder::{} not passed a function, but {:?}", typ, fn_ty);
 
         let param_tys = fn_ty.func_params();
 
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index 4a8658dd2e3..4925c9d547e 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -18,7 +18,7 @@ pub use self::CalleeData::*;
 
 use llvm::{self, ValueRef, get_params};
 use rustc::hir::def_id::DefId;
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::{Substs, Subst};
 use rustc::traits;
 use abi::{Abi, FnType};
 use attributes;
@@ -83,7 +83,7 @@ impl<'tcx> Callee<'tcx> {
 
         let fn_ty = def_ty(ccx.shared(), def_id, substs);
         if let ty::TyFnDef(.., f) = fn_ty.sty {
-            if f.abi == Abi::RustIntrinsic || f.abi == Abi::PlatformIntrinsic {
+            if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
                 return Callee {
                     data: Intrinsic,
                     ty: fn_ty
@@ -93,9 +93,9 @@ impl<'tcx> Callee<'tcx> {
 
         // FIXME(eddyb) Detect ADT constructors more efficiently.
         if let Some(adt_def) = fn_ty.fn_ret().skip_binder().ty_adt_def() {
-            if let Some(v) = adt_def.variants.iter().find(|v| def_id == v.did) {
+            if let Some(i) = adt_def.variants.iter().position(|v| def_id == v.did) {
                 return Callee {
-                    data: NamedTupleConstructor(Disr::from(v.disr_val)),
+                    data: NamedTupleConstructor(Disr::for_variant(tcx, adt_def, i)),
                     ty: fn_ty
                 };
             }
@@ -169,14 +169,13 @@ impl<'tcx> Callee<'tcx> {
     /// The extra argument types are for variadic (extern "C") functions.
     pub fn direct_fn_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
                               extra_args: &[Ty<'tcx>]) -> FnType {
-        let abi = self.ty.fn_abi();
-        let sig = ccx.tcx().erase_late_bound_regions_and_normalize(self.ty.fn_sig());
-        let mut fn_ty = FnType::unadjusted(ccx, abi, &sig, extra_args);
+        let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&self.ty.fn_sig());
+        let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args);
         if let Virtual(_) = self.data {
             // Don't pass the vtable, it's not an argument of the virtual fn.
             fn_ty.args[1].ignore();
         }
-        fn_ty.adjust_for_abi(ccx, abi, &sig);
+        fn_ty.adjust_for_abi(ccx, sig);
         fn_ty
     }
 
@@ -307,38 +306,32 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty);
 
     // Make a version with the type of by-ref closure.
-    let ty::ClosureTy { unsafety, abi, mut sig } = tcx.closure_type(def_id, substs);
-    sig.0 = tcx.mk_fn_sig(
-        iter::once(ref_closure_ty).chain(sig.0.inputs().iter().cloned()),
-        sig.0.output(),
-        sig.0.variadic
-    );
-    let llref_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
-        unsafety: unsafety,
-        abi: abi,
-        sig: sig.clone()
-    }));
+    let sig = tcx.closure_type(def_id).subst(tcx, substs.substs);
+    let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
+    assert_eq!(sig.abi, Abi::RustCall);
+    let llref_fn_ty = tcx.mk_fn_ptr(ty::Binder(tcx.mk_fn_sig(
+        iter::once(ref_closure_ty).chain(sig.inputs().iter().cloned()),
+        sig.output(),
+        sig.variadic,
+        sig.unsafety,
+        Abi::RustCall
+    )));
     debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}",
            llref_fn_ty);
 
 
     // Make a version of the closure type with the same arguments, but
     // with argument #0 being by value.
-    assert_eq!(abi, Abi::RustCall);
-    sig.0 = tcx.mk_fn_sig(
-        iter::once(closure_ty).chain(sig.0.inputs().iter().skip(1).cloned()),
-        sig.0.output(),
-        sig.0.variadic
+    let sig = tcx.mk_fn_sig(
+        iter::once(closure_ty).chain(sig.inputs().iter().cloned()),
+        sig.output(),
+        sig.variadic,
+        sig.unsafety,
+        Abi::RustCall
     );
 
-    let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
-    let fn_ty = FnType::new(ccx, abi, &sig, &[]);
-
-    let llonce_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
-        unsafety: unsafety,
-        abi: abi,
-        sig: ty::Binder(sig)
-    }));
+    let fn_ty = FnType::new(ccx, sig, &[]);
+    let llonce_fn_ty = tcx.mk_fn_ptr(ty::Binder(sig));
 
     // Create the by-value helper.
     let function_name = method_instance.symbol_name(ccx.shared());
@@ -470,33 +463,20 @@ fn trans_fn_pointer_shim<'a, 'tcx>(
 
     // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
     // which is the fn pointer, and `args`, which is the arguments tuple.
-    let sig = match bare_fn_ty.sty {
-        ty::TyFnDef(..,
-                    &ty::BareFnTy { unsafety: hir::Unsafety::Normal,
-                                    abi: Abi::Rust,
-                                    ref sig }) |
-        ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal,
-                                    abi: Abi::Rust,
-                                    ref sig }) => sig,
-
-        _ => {
-            bug!("trans_fn_pointer_shim invoked on invalid type: {}",
-                 bare_fn_ty);
-        }
-    };
-    let sig = tcx.erase_late_bound_regions_and_normalize(sig);
+    let sig = bare_fn_ty.fn_sig();
+    let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
+    assert_eq!(sig.unsafety, hir::Unsafety::Normal);
+    assert_eq!(sig.abi, Abi::Rust);
     let tuple_input_ty = tcx.intern_tup(sig.inputs(), false);
     let sig = tcx.mk_fn_sig(
         [bare_fn_ty_maybe_ref, tuple_input_ty].iter().cloned(),
         sig.output(),
-        false
+        false,
+        hir::Unsafety::Normal,
+        Abi::RustCall
     );
-    let fn_ty = FnType::new(ccx, Abi::RustCall, &sig, &[]);
-    let tuple_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
-        unsafety: hir::Unsafety::Normal,
-        abi: Abi::RustCall,
-        sig: ty::Binder(sig)
-    }));
+    let fn_ty = FnType::new(ccx, sig, &[]);
+    let tuple_fn_ty = tcx.mk_fn_ptr(ty::Binder(sig));
     debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
 
     //
@@ -600,7 +580,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // other weird situations. Annoying.
 
     // Create a fn pointer with the substituted signature.
-    let fn_ptr_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(common::ty_fn_ty(ccx, fn_ty).into_owned()));
+    let fn_ptr_ty = tcx.mk_fn_ptr(common::ty_fn_sig(ccx, fn_ty));
     let llptrty = type_of::type_of(ccx, fn_ptr_ty);
 
     let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index b5f948442b7..b12c1220b2b 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -489,6 +489,20 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                                                           self.output);
                 }
             }
+            mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => {
+                let source_ty = operand.ty(self.mir, self.scx.tcx());
+                match source_ty.sty {
+                    ty::TyClosure(def_id, substs) => {
+                        let closure_trans_item =
+                            create_fn_trans_item(self.scx,
+                                                 def_id,
+                                                 substs.substs,
+                                                 self.param_substs);
+                        self.output.push(closure_trans_item);
+                    }
+                    _ => bug!(),
+                }
+            }
             mir::Rvalue::Box(..) => {
                 let exchange_malloc_fn_def_id =
                     self.scx
@@ -615,19 +629,13 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                                               def_id: DefId)
                                               -> bool {
             match tcx.item_type(def_id).sty {
-                ty::TyFnDef(def_id, _, f) => {
+                ty::TyFnDef(def_id, _, _) => {
                     // Some constructors also have type TyFnDef but they are
                     // always instantiated inline and don't result in a
                     // translation item. Same for FFI functions.
                     if let Some(hir_map::NodeForeignItem(_)) = tcx.hir.get_if_local(def_id) {
                         return false;
                     }
-
-                    if let Some(adt_def) = f.sig.output().skip_binder().ty_adt_def() {
-                        if adt_def.variants.iter().any(|v| def_id == v.did) {
-                            return false;
-                        }
-                    }
                 }
                 ty::TyClosure(..) => {}
                 _ => return false
@@ -674,10 +682,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
 
         fn is_drop_in_place_intrinsic<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                 def_id: DefId,
-                                                bare_fn_ty: &ty::BareFnTy<'tcx>)
+                                                bare_fn_ty: ty::PolyFnSig<'tcx>)
                                                 -> bool {
-            (bare_fn_ty.abi == Abi::RustIntrinsic ||
-             bare_fn_ty.abi == Abi::PlatformIntrinsic) &&
+            (bare_fn_ty.abi() == Abi::RustIntrinsic ||
+             bare_fn_ty.abi() == Abi::PlatformIntrinsic) &&
             tcx.item_name(def_id) == "drop_in_place"
         }
     }
@@ -689,6 +697,16 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
 fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   def_id: DefId)
                                   -> bool {
+    if let ty::TyFnDef(_, _, sig) = tcx.item_type(def_id).sty {
+        if let Some(adt_def) = sig.output().skip_binder().ty_adt_def() {
+            if adt_def.variants.iter().any(|v| def_id == v.did) {
+                // HACK: ADT constructors are translated in-place and
+                // do not have a trans-item.
+                return false;
+            }
+        }
+    }
+
     if def_id.is_local() {
         true
     } else {
@@ -736,7 +754,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
     // If the type implements Drop, also add a translation item for the
     // monomorphized Drop::drop() implementation.
     let destructor_did = match ty.sty {
-        ty::TyAdt(def, _) => def.destructor(),
+        ty::TyAdt(def, _) => def.destructor(scx.tcx()),
         _ => None
     };
 
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 64100ed4191..1032da7ef75 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -29,11 +29,11 @@ use type_::Type;
 use value::Value;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::layout::Layout;
+use rustc::ty::subst::Subst;
 use rustc::traits::{self, SelectionContext, Reveal};
 use rustc::hir;
 
 use libc::{c_uint, c_char};
-use std::borrow::Cow;
 use std::iter;
 
 use syntax::ast;
@@ -570,17 +570,17 @@ pub fn shift_mask_val<'a, 'tcx>(
     }
 }
 
-pub fn ty_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                          ty: Ty<'tcx>)
-                          -> Cow<'tcx, ty::BareFnTy<'tcx>>
+pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                           ty: Ty<'tcx>)
+                           -> ty::PolyFnSig<'tcx>
 {
     match ty.sty {
-        ty::TyFnDef(_, _, fty) => Cow::Borrowed(fty),
+        ty::TyFnDef(_, _, sig) => sig,
         // Shims currently have type TyFnPtr. Not sure this should remain.
-        ty::TyFnPtr(fty) => Cow::Borrowed(fty),
+        ty::TyFnPtr(sig) => sig,
         ty::TyClosure(def_id, substs) => {
             let tcx = ccx.tcx();
-            let ty::ClosureTy { unsafety, abi, sig } = tcx.closure_type(def_id, substs);
+            let sig = tcx.closure_type(def_id).subst(tcx, substs.substs);
 
             let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv);
             let env_ty = match tcx.closure_kind(def_id) {
@@ -589,12 +589,13 @@ pub fn ty_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                 ty::ClosureKind::FnOnce => ty,
             };
 
-            let sig = sig.map_bound(|sig| tcx.mk_fn_sig(
+            sig.map_bound(|sig| tcx.mk_fn_sig(
                 iter::once(env_ty).chain(sig.inputs().iter().cloned()),
                 sig.output(),
-                sig.variadic
-            ));
-            Cow::Owned(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: sig })
+                sig.variadic,
+                sig.unsafety,
+                sig.abi
+            ))
         }
         _ => bug!("unexpected type {:?} to ty_fn_sig", ty)
     }
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index b68de7b46c8..011f7748f2c 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -213,11 +213,11 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
     g
 }
 
-pub fn trans_static(ccx: &CrateContext,
-                    m: hir::Mutability,
-                    id: ast::NodeId,
-                    attrs: &[ast::Attribute])
-                    -> Result<ValueRef, ConstEvalErr> {
+pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                              m: hir::Mutability,
+                              id: ast::NodeId,
+                              attrs: &[ast::Attribute])
+                              -> Result<ValueRef, ConstEvalErr<'tcx>> {
     unsafe {
         let def_id = ccx.tcx().hir.local_def_id(id);
         let g = get_static(ccx, def_id);
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 799f502aadb..d5f7549ece0 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -959,15 +959,13 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
             return llfn;
         }
 
-        let ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
-            unsafety: hir::Unsafety::Unsafe,
-            abi: Abi::C,
-            sig: ty::Binder(tcx.mk_fn_sig(
-                iter::once(tcx.mk_mut_ptr(tcx.types.u8)),
-                tcx.types.never,
-                false
-            )),
-        }));
+        let ty = tcx.mk_fn_ptr(ty::Binder(tcx.mk_fn_sig(
+            iter::once(tcx.mk_mut_ptr(tcx.types.u8)),
+            tcx.types.never,
+            false,
+            hir::Unsafety::Unsafe,
+            Abi::C
+        )));
 
         let llfn = declare::declare_fn(self, "rust_eh_unwind_resume", ty);
         attributes::unwind(llfn, true);
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 11c0bf852f7..f6cdd883850 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -373,11 +373,11 @@ fn vec_slice_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
 fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                       unique_type_id: UniqueTypeId,
-                                      signature: &ty::PolyFnSig<'tcx>,
+                                      signature: ty::PolyFnSig<'tcx>,
                                       span: Span)
                                       -> MetadataCreationResult
 {
-    let signature = cx.tcx().erase_late_bound_regions(signature);
+    let signature = cx.tcx().erase_late_bound_regions(&signature);
 
     let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs().len() + 1);
 
@@ -558,10 +558,10 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 Err(metadata) => return metadata,
             }
         }
-        ty::TyFnDef(.., ref barefnty) | ty::TyFnPtr(ref barefnty) => {
+        ty::TyFnDef(.., sig) | ty::TyFnPtr(sig) => {
             let fn_metadata = subroutine_type_metadata(cx,
                                                        unique_type_id,
-                                                       &barefnty.sig,
+                                                       sig,
                                                        usage_site_span).metadata;
             match debug_context(cx).type_map
                                    .borrow()
@@ -1465,10 +1465,10 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     // <unknown>
     let file_metadata = unknown_file_metadata(cx);
 
-    let variants = &enum_type.ty_adt_def().unwrap().variants;
-    let enumerators_metadata: Vec<DIDescriptor> = variants
-        .iter()
-        .map(|v| {
+    let def = enum_type.ty_adt_def().unwrap();
+    let enumerators_metadata: Vec<DIDescriptor> = def.discriminants(cx.tcx())
+        .zip(&def.variants)
+        .map(|(discr, v)| {
             let token = v.name.as_str();
             let name = CString::new(token.as_bytes()).unwrap();
             unsafe {
@@ -1476,7 +1476,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                     DIB(cx),
                     name.as_ptr(),
                     // FIXME: what if enumeration has i128 discriminant?
-                    v.disr_val as u64)
+                    discr.to_u128_unchecked() as u64)
             }
         })
         .collect();
diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs
index e9b592ec8fd..d5f04542d02 100644
--- a/src/librustc_trans/debuginfo/mod.rs
+++ b/src/librustc_trans/debuginfo/mod.rs
@@ -198,8 +198,7 @@ pub fn finalize(cx: &CrateContext) {
 /// for the function.
 pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                                instance: Instance<'tcx>,
-                                               sig: &ty::FnSig<'tcx>,
-                                               abi: Abi,
+                                               sig: ty::FnSig<'tcx>,
                                                llfn: ValueRef,
                                                mir: &mir::Mir) -> FunctionDebugContext {
     if cx.sess().opts.debuginfo == NoDebugInfo {
@@ -225,7 +224,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     let file_metadata = file_metadata(cx, &loc.file.name, &loc.file.abs_path);
 
     let function_type_metadata = unsafe {
-        let fn_signature = get_function_signature(cx, sig, abi);
+        let fn_signature = get_function_signature(cx, sig);
         llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature)
     };
 
@@ -295,8 +294,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     return FunctionDebugContext::RegularContext(fn_debug_context);
 
     fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
-                                        sig: &ty::FnSig<'tcx>,
-                                        abi: Abi) -> DIArray {
+                                        sig: ty::FnSig<'tcx>) -> DIArray {
         if cx.sess().opts.debuginfo == LimitedDebugInfo {
             return create_DIArray(DIB(cx), &[]);
         }
@@ -309,7 +307,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             _ => type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP)
         });
 
-        let inputs = if abi == Abi::RustCall {
+        let inputs = if sig.abi == Abi::RustCall {
             &sig.inputs()[..sig.inputs().len() - 1]
         } else {
             sig.inputs()
@@ -320,7 +318,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP));
         }
 
-        if abi == Abi::RustCall && !sig.inputs().is_empty() {
+        if sig.abi == Abi::RustCall && !sig.inputs().is_empty() {
             if let ty::TyTuple(args, _) = sig.inputs()[sig.inputs().len() - 1].sty {
                 for &argument_type in args {
                     signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP));
@@ -332,7 +330,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     }
 
     fn get_template_parameters<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
-                                         generics: &ty::Generics<'tcx>,
+                                         generics: &ty::Generics,
                                          substs: &Substs<'tcx>,
                                          file_metadata: DIFile,
                                          name_to_append_suffix_to: &mut String)
@@ -382,9 +380,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         return create_DIArray(DIB(cx), &template_params[..]);
     }
 
-    fn get_type_parameter_names<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
-                                          generics: &ty::Generics<'tcx>)
-                                          -> Vec<ast::Name> {
+    fn get_type_parameter_names(cx: &CrateContext, generics: &ty::Generics) -> Vec<ast::Name> {
         let mut names = generics.parent.map_or(vec![], |def_id| {
             get_type_parameter_names(cx, cx.tcx().item_generics(def_id))
         });
diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs
index 018bbb6e97d..13ff6646e66 100644
--- a/src/librustc_trans/debuginfo/type_names.rs
+++ b/src/librustc_trans/debuginfo/type_names.rs
@@ -96,12 +96,13 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 push_type_params(cx, principal.substs, output);
             }
         },
-        ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) |
-        ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
-            if unsafety == hir::Unsafety::Unsafe {
+        ty::TyFnDef(.., sig) |
+        ty::TyFnPtr(sig) => {
+            if sig.unsafety() == hir::Unsafety::Unsafe {
                 output.push_str("unsafe ");
             }
 
+            let abi = sig.abi();
             if abi != ::abi::Abi::Rust {
                 output.push_str("extern \"");
                 output.push_str(abi.name());
@@ -110,7 +111,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
             output.push_str("fn(");
 
-            let sig = cx.tcx().erase_late_bound_regions_and_normalize(sig);
+            let sig = cx.tcx().erase_late_bound_regions_and_normalize(&sig);
             if !sig.inputs().is_empty() {
                 for &parameter_type in sig.inputs() {
                     push_debuginfo_type_name(cx, parameter_type, true, output);
diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs
index 15a1c990aad..ceff96a39b2 100644
--- a/src/librustc_trans/debuginfo/utils.rs
+++ b/src/librustc_trans/debuginfo/utils.rs
@@ -14,6 +14,7 @@ use super::{CrateDebugContext};
 use super::namespace::item_namespace;
 
 use rustc::hir::def_id::DefId;
+use rustc::ty::DefIdTree;
 
 use llvm;
 use llvm::debuginfo::{DIScope, DIBuilderRef, DIDescriptor, DIArray};
@@ -74,11 +75,8 @@ pub fn DIB(cx: &CrateContext) -> DIBuilderRef {
 
 pub fn get_namespace_and_span_for_item(cx: &CrateContext, def_id: DefId)
                                    -> (DIScope, Span) {
-    let containing_scope = item_namespace(cx, DefId {
-        krate: def_id.krate,
-        index: cx.tcx().def_key(def_id).parent
-                 .expect("get_namespace_and_span_for_item: missing parent?")
-    });
+    let containing_scope = item_namespace(cx, cx.tcx().parent(def_id)
+        .expect("get_namespace_and_span_for_item: missing parent?"));
 
     // Try to get some span information, if we have an inlined item.
     let definition_span = cx.tcx().def_span(def_id);
diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs
index 7ac482459ee..2787812f962 100644
--- a/src/librustc_trans/declare.rs
+++ b/src/librustc_trans/declare.rs
@@ -132,11 +132,11 @@ pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type) -> ValueRef {
 pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
                             fn_type: ty::Ty<'tcx>) -> ValueRef {
     debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type);
-    let ty::BareFnTy { abi, ref sig, .. } = *common::ty_fn_ty(ccx, fn_type);
-    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(sig);
+    let sig = common::ty_fn_sig(ccx, fn_type);
+    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig);
     debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
 
-    let fty = FnType::new(ccx, abi, &sig, &[]);
+    let fty = FnType::new(ccx, sig, &[]);
     let llfn = declare_raw_fn(ccx, name, fty.cconv, fty.llvm_type(ccx));
 
     // FIXME(canndrew): This is_never should really be an is_uninhabited
@@ -144,7 +144,7 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
         llvm::Attribute::NoReturn.apply_llfn(Function, llfn);
     }
 
-    if abi != Abi::Rust && abi != Abi::RustCall {
+    if sig.abi != Abi::Rust && sig.abi != Abi::RustCall {
         attributes::unwind(llfn, false);
     }
 
diff --git a/src/librustc_trans/disr.rs b/src/librustc_trans/disr.rs
index f3a62bc85b8..a940faac838 100644
--- a/src/librustc_trans/disr.rs
+++ b/src/librustc_trans/disr.rs
@@ -8,10 +8,42 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use rustc::middle::const_val::ConstVal;
+use rustc::ty::{self, TyCtxt};
+use rustc_const_math::ConstInt;
+
 #[derive(Debug, Eq, PartialEq, Copy, Clone)]
 pub struct Disr(pub u64);
 
 impl Disr {
+    pub fn for_variant(tcx: TyCtxt,
+                       def: &ty::AdtDef,
+                       variant_index: usize) -> Self {
+        let mut explicit_index = variant_index;
+        let mut explicit_value = Disr(0);
+        loop {
+            match def.variants[explicit_index].discr {
+                ty::VariantDiscr::Relative(0) => break,
+                ty::VariantDiscr::Relative(distance) => {
+                    explicit_index -= distance;
+                }
+                ty::VariantDiscr::Explicit(expr_did) => {
+                    match tcx.maps.monomorphic_const_eval.borrow()[&expr_did] {
+                        Ok(ConstVal::Integral(v)) => {
+                            explicit_value = Disr::from(v);
+                            break;
+                        }
+                        _ => {
+                            explicit_index -= 1;
+                        }
+                    }
+                }
+            }
+        }
+        let distance = variant_index - explicit_index;
+        explicit_value.wrapping_add(Disr::from(distance))
+    }
+
     pub fn wrapping_add(self, other: Self) -> Self {
         Disr(self.0.wrapping_add(other.0))
     }
@@ -24,10 +56,10 @@ impl ::std::ops::BitAnd for Disr {
     }
 }
 
-impl From<::rustc::ty::Disr> for Disr {
-    fn from(i: ::rustc::ty::Disr) -> Disr {
+impl From<ConstInt> for Disr {
+    fn from(i: ConstInt) -> Disr {
         // FIXME: what if discr has 128 bit discr?
-        Disr(i as u64)
+        Disr(i.to_u128_unchecked() as u64)
     }
 }
 
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index d66ea4d650f..32fc3d5af24 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -237,7 +237,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
             bcx.call(dtor, &[ptr.llval], None);
             bcx
         }
-        ty::TyAdt(def, ..) if def.has_dtor() && !skip_dtor => {
+        ty::TyAdt(def, ..) if def.has_dtor(bcx.tcx()) && !skip_dtor => {
             let shallow_drop = def.is_union();
             let tcx = bcx.tcx();
 
@@ -265,7 +265,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
                 traits::VtableImpl(data) => data,
                 _ => bug!("dtor for {:?} is not an impl???", t)
             };
-            let dtor_did = def.destructor().unwrap();
+            let dtor_did = def.destructor(tcx).unwrap();
             let callee = Callee::def(bcx.ccx, dtor_did, vtbl.substs);
             let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
             let llret;
@@ -386,7 +386,15 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
             let info = bcx.pointercast(info, Type::int(bcx.ccx).ptr_to());
             let size_ptr = bcx.gepi(info, &[1]);
             let align_ptr = bcx.gepi(info, &[2]);
-            (bcx.load(size_ptr, None), bcx.load(align_ptr, None))
+
+            let size = bcx.load(size_ptr, None);
+            let align = bcx.load(align_ptr, None);
+
+            // Vtable loads are invariant
+            bcx.set_invariant_load(size);
+            bcx.set_invariant_load(align);
+
+            (size, align)
         }
         ty::TySlice(_) | ty::TyStr => {
             let unit_ty = t.sequence_element_type(bcx.tcx());
@@ -513,11 +521,10 @@ fn drop_structural_ty<'a, 'tcx>(
                         let llswitch = cx.switch(lldiscrim_a, ret_void_cx.llbb(), n_variants);
                         let next_cx = cx.build_sibling_block("enum-iter-next");
 
-                        for (i, variant) in adt.variants.iter().enumerate() {
-                            let variant_cx_name = format!("enum-iter-variant-{}",
-                                &variant.disr_val.to_string());
+                        for (i, discr) in adt.discriminants(cx.tcx()).enumerate() {
+                            let variant_cx_name = format!("enum-iter-variant-{}", i);
                             let variant_cx = cx.build_sibling_block(&variant_cx_name);
-                            let case_val = adt::trans_case(&cx, t, Disr::from(variant.disr_val));
+                            let case_val = adt::trans_case(&cx, t, Disr::from(discr));
                             variant_cx.add_case(llswitch, case_val, variant_cx.llbb());
                             ptr.ty = LvalueTy::Downcast {
                                 adt_def: adt,
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index 333a0802ee6..b7aedb742db 100644
--- a/src/librustc_trans/intrinsic.rs
+++ b/src/librustc_trans/intrinsic.rs
@@ -97,12 +97,12 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
     let ccx = bcx.ccx;
     let tcx = ccx.tcx();
 
-    let (def_id, substs, fty) = match callee_ty.sty {
-        ty::TyFnDef(def_id, substs, ref fty) => (def_id, substs, fty),
+    let (def_id, substs, sig) = match callee_ty.sty {
+        ty::TyFnDef(def_id, substs, sig) => (def_id, substs, sig),
         _ => bug!("expected fn item type, found {}", callee_ty)
     };
 
-    let sig = tcx.erase_late_bound_regions_and_normalize(&fty.sig);
+    let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
     let arg_tys = sig.inputs();
     let ret_ty = sig.output();
     let name = &*tcx.item_name(def_id).as_str();
@@ -878,13 +878,13 @@ fn gen_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                     output: Ty<'tcx>,
                     trans: &mut for<'b> FnMut(Builder<'b, 'tcx>))
                     -> ValueRef {
-    let sig = ccx.tcx().mk_fn_sig(inputs.into_iter(), output, false);
-
-    let rust_fn_ty = ccx.tcx().mk_fn_ptr(ccx.tcx().mk_bare_fn(ty::BareFnTy {
-        unsafety: hir::Unsafety::Unsafe,
-        abi: Abi::Rust,
-        sig: ty::Binder(sig)
-    }));
+    let rust_fn_ty = ccx.tcx().mk_fn_ptr(ty::Binder(ccx.tcx().mk_fn_sig(
+        inputs.into_iter(),
+        output,
+        false,
+        hir::Unsafety::Unsafe,
+        Abi::Rust
+    )));
     let llfn = declare::define_internal_fn(ccx, name, rust_fn_ty);
     let bcx = Builder::new_block(ccx, llfn, "entry-block");
     trans(bcx);
@@ -905,11 +905,13 @@ fn get_rust_try_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // Define the type up front for the signature of the rust_try function.
     let tcx = ccx.tcx();
     let i8p = tcx.mk_mut_ptr(tcx.types.i8);
-    let fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
-        unsafety: hir::Unsafety::Unsafe,
-        abi: Abi::Rust,
-        sig: ty::Binder(tcx.mk_fn_sig(iter::once(i8p), tcx.mk_nil(), false)),
-    }));
+    let fn_ty = tcx.mk_fn_ptr(ty::Binder(tcx.mk_fn_sig(
+        iter::once(i8p),
+        tcx.mk_nil(),
+        false,
+        hir::Unsafety::Unsafe,
+        Abi::Rust
+    )));
     let output = tcx.types.i32;
     let rust_try = gen_fn(ccx, "__rust_try", vec![fn_ty, i8p, i8p], output, trans);
     ccx.rust_try_fn().set(Some(rust_try));
@@ -959,7 +961,7 @@ fn generic_simd_intrinsic<'a, 'tcx>(
 
 
     let tcx = bcx.tcx();
-    let sig = tcx.erase_late_bound_regions_and_normalize(callee_ty.fn_sig());
+    let sig = tcx.erase_late_bound_regions_and_normalize(&callee_ty.fn_sig());
     let arg_tys = sig.inputs();
 
     // every intrinsic takes a SIMD vector as its first argument
diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs
index 3033ae61d20..a3f4168e96f 100644
--- a/src/librustc_trans/meth.rs
+++ b/src/librustc_trans/meth.rs
@@ -30,13 +30,15 @@ const VTABLE_OFFSET: usize = 3;
 /// Extracts a method from a trait object's vtable, at the specified index.
 pub fn get_virtual_method<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                                     llvtable: ValueRef,
-                                    vtable_index: usize)
-                                    -> ValueRef {
+                                    vtable_index: usize) -> ValueRef {
     // Load the data pointer from the object.
     debug!("get_virtual_method(vtable_index={}, llvtable={:?})",
            vtable_index, Value(llvtable));
 
-    bcx.load(bcx.gepi(llvtable, &[vtable_index + VTABLE_OFFSET]), None)
+    let ptr = bcx.load_nonnull(bcx.gepi(llvtable, &[vtable_index + VTABLE_OFFSET]), None);
+    // Vtable loads are invariant
+    bcx.set_invariant_load(ptr);
+    ptr
 }
 
 /// Generate a shim function that allows an object type like `SomeTrait` to
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index 651d0066b12..3cad2bc1d84 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -139,7 +139,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                 if switch_ty == bcx.tcx().types.bool {
                     let lltrue = llblock(self, targets[0]);
                     let llfalse = llblock(self, targets[1]);
-                    if let [ConstInt::Infer(0)] = values[..] {
+                    if let [ConstInt::U8(0)] = values[..] {
                         bcx.cond_br(discr.immediate(), llfalse, lltrue);
                     } else {
                         bcx.cond_br(discr.immediate(), lltrue, llfalse);
@@ -365,20 +365,21 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                 // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
                 let callee = self.trans_operand(&bcx, func);
 
-                let (mut callee, abi, sig) = match callee.ty.sty {
-                    ty::TyFnDef(def_id, substs, f) => {
-                        (Callee::def(bcx.ccx, def_id, substs), f.abi, &f.sig)
+                let (mut callee, sig) = match callee.ty.sty {
+                    ty::TyFnDef(def_id, substs, sig) => {
+                        (Callee::def(bcx.ccx, def_id, substs), sig)
                     }
-                    ty::TyFnPtr(f) => {
+                    ty::TyFnPtr(sig) => {
                         (Callee {
                             data: Fn(callee.immediate()),
                             ty: callee.ty
-                        }, f.abi, &f.sig)
+                        }, sig)
                     }
                     _ => bug!("{} is not callable", callee.ty)
                 };
 
-                let sig = bcx.tcx().erase_late_bound_regions_and_normalize(sig);
+                let sig = bcx.tcx().erase_late_bound_regions_and_normalize(&sig);
+                let abi = sig.abi;
 
                 // Handle intrinsics old trans wants Expr's for, ourselves.
                 let intrinsic = match (&callee.ty.sty, &callee.data) {
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 7e17ae5f1d3..771a5b7f366 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -20,7 +20,7 @@ use rustc::mir;
 use rustc::mir::tcx::LvalueTy;
 use rustc::ty::{self, layout, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::cast::{CastTy, IntTy};
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::{Kind, Substs, Subst};
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use {abi, adt, base, Disr, machine};
 use callee::Callee;
@@ -83,7 +83,6 @@ impl<'tcx> Const<'tcx> {
                 let u = v.as_u64(ccx.tcx().sess.target.uint_type);
                 (C_integral(Type::int(ccx), u, false), tcx.types.usize)
             },
-            Infer(_) | InferSigned(_) => bug!("MIR must not use `{:?}`", ci),
         };
         Const { llval: llval, ty: ty }
     }
@@ -97,14 +96,13 @@ impl<'tcx> Const<'tcx> {
         let val = match cv {
             ConstVal::Float(F32(v)) => C_floating_f64(v as f64, llty),
             ConstVal::Float(F64(v)) => C_floating_f64(v, llty),
-            ConstVal::Float(FInfer {..}) => bug!("MIR must not use `{:?}`", cv),
             ConstVal::Bool(v) => C_bool(ccx, v),
             ConstVal::Integral(ref i) => return Const::from_constint(ccx, i),
             ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
             ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
             ConstVal::Struct(_) | ConstVal::Tuple(_) |
             ConstVal::Array(..) | ConstVal::Repeat(..) |
-            ConstVal::Function(_) => {
+            ConstVal::Function(..) => {
                 bug!("MIR must not use `{:?}` (which refers to a local ID)", cv)
             }
             ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
@@ -249,7 +247,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
     fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
                  instance: Instance<'tcx>,
                  args: IndexVec<mir::Local, Const<'tcx>>)
-                 -> Result<Const<'tcx>, ConstEvalErr> {
+                 -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
         let instance = instance.resolve_const(ccx.shared());
         let mir = ccx.tcx().item_mir(instance.def);
         MirConstContext::new(ccx, &mir, instance.substs, args).trans()
@@ -263,7 +261,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                                          value)
     }
 
-    fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr> {
+    fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
         let tcx = self.ccx.tcx();
         let mut bb = mir::START_BLOCK;
 
@@ -325,7 +323,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                         };
 
                         let err = ConstEvalErr{ span: span, kind: err };
-                        report_const_eval_err(tcx, &err, span, "expression").emit();
+                        report_const_eval_err(tcx, &err, span, "expression");
                         failure = Err(err);
                     }
                     target
@@ -373,7 +371,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
     }
 
     fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
-                    -> Result<ConstLvalue<'tcx>, ConstEvalErr> {
+                    -> Result<ConstLvalue<'tcx>, ConstEvalErr<'tcx>> {
         let tcx = self.ccx.tcx();
 
         if let mir::Lvalue::Local(index) = *lvalue {
@@ -468,7 +466,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
     }
 
     fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span)
-                     -> Result<Const<'tcx>, ConstEvalErr> {
+                     -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
         debug!("const_operand({:?} @ {:?})", operand, span);
         let result = match *operand {
             mir::Operand::Consume(ref lvalue) => {
@@ -523,7 +521,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
 
     fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
                     dest_ty: Ty<'tcx>, span: Span)
-                    -> Result<Const<'tcx>, ConstEvalErr> {
+                    -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
         let tcx = self.ccx.tcx();
         debug!("const_rvalue({:?}: {:?} @ {:?})", rvalue, dest_ty, span);
         let val = match *rvalue {
@@ -578,6 +576,28 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                             }
                         }
                     }
+                    mir::CastKind::ClosureFnPointer => {
+                        match operand.ty.sty {
+                            ty::TyClosure(def_id, substs) => {
+                                // Get the def_id for FnOnce::call_once
+                                let fn_once = tcx.lang_items.fn_once_trait().unwrap();
+                                let call_once = tcx
+                                    .global_tcx().associated_items(fn_once)
+                                    .find(|it| it.kind == ty::AssociatedKind::Method)
+                                    .unwrap().def_id;
+                                // Now create its substs [Closure, Tuple]
+                                let input = tcx.closure_type(def_id)
+                                    .subst(tcx, substs.substs).input(0);
+                                let substs = tcx.mk_substs([operand.ty, input.skip_binder()]
+                                    .iter().cloned().map(Kind::from));
+                                Callee::def(self.ccx, call_once, substs)
+                                    .reify(self.ccx)
+                            }
+                            _ => {
+                                bug!("{} cannot be cast to a fn ptr", operand.ty)
+                            }
+                        }
+                    }
                     mir::CastKind::UnsafeFnPointer => {
                         // this is a no-op at the LLVM level
                         operand.llval
@@ -939,8 +959,11 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
 }
 
 
-pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId)
-                                -> Result<ValueRef, ConstEvalErr> {
+pub fn trans_static_initializer<'a, 'tcx>(
+    ccx: &CrateContext<'a, 'tcx>,
+    def_id: DefId)
+    -> Result<ValueRef, ConstEvalErr<'tcx>>
+{
     let instance = Instance::mono(ccx.shared(), def_id);
     MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval)
 }
@@ -980,7 +1003,7 @@ fn trans_const<'a, 'tcx>(
         layout::CEnum { discr: d, min, max, .. } => {
             let discr = match *kind {
                 mir::AggregateKind::Adt(adt_def, _, _, _) => {
-                    Disr::from(adt_def.variants[variant_index].disr_val)
+                    Disr::for_variant(ccx.tcx(), adt_def, variant_index)
                 },
                 _ => Disr(0),
             };
diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs
index 0cfc2c8d163..6419f41f86b 100644
--- a/src/librustc_trans/mir/mod.rs
+++ b/src/librustc_trans/mir/mod.rs
@@ -28,7 +28,6 @@ use type_of;
 
 use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, Span};
 use syntax::symbol::keywords;
-use syntax::abi::Abi;
 
 use std::iter;
 
@@ -134,17 +133,14 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
         } else {
             let cm = self.ccx.sess().codemap();
             // Walk up the macro expansion chain until we reach a non-expanded span.
+            // We also stop at the function body level because no line stepping can occurr
+            // at the level above that.
             let mut span = source_info.span;
-            while span.expn_id != NO_EXPANSION && span.expn_id != COMMAND_LINE_EXPN {
+            while span.expn_id != NO_EXPANSION &&
+                  span.expn_id != COMMAND_LINE_EXPN &&
+                  span.expn_id != self.mir.span.expn_id {
                 if let Some(callsite_span) = cm.with_expn_info(span.expn_id,
                                                     |ei| ei.map(|ei| ei.call_site.clone())) {
-                    // When the current function itself is a result of macro expansion,
-                    // we stop at the function body level because no line stepping can occurr
-                    // at the level above that.
-                    if self.mir.span.expn_id != NO_EXPANSION &&
-                       span.expn_id == self.mir.span.expn_id {
-                        break;
-                    }
                     span = callsite_span;
                 } else {
                     break;
@@ -208,15 +204,14 @@ impl<'tcx> LocalRef<'tcx> {
 pub fn trans_mir<'a, 'tcx: 'a>(
     ccx: &'a CrateContext<'a, 'tcx>,
     llfn: ValueRef,
-    fn_ty: FnType,
     mir: &'a Mir<'tcx>,
     instance: Instance<'tcx>,
-    sig: &ty::FnSig<'tcx>,
-    abi: Abi,
+    sig: ty::FnSig<'tcx>,
 ) {
+    let fn_ty = FnType::new(ccx, sig, &[]);
     debug!("fn_ty: {:?}", fn_ty);
     let debug_context =
-        debuginfo::create_function_debug_context(ccx, instance, sig, abi, llfn, mir);
+        debuginfo::create_function_debug_context(ccx, instance, sig, llfn, mir);
     let bcx = Builder::new_block(ccx, llfn, "entry-block");
 
     let cleanup_kinds = analyze::cleanup_kinds(&mir);
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index 7d4f542addb..037c771c97b 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -12,6 +12,7 @@ use llvm::{self, ValueRef};
 use rustc::ty::{self, Ty};
 use rustc::ty::cast::{CastTy, IntTy};
 use rustc::ty::layout::Layout;
+use rustc::ty::subst::{Kind, Subst};
 use rustc::mir::tcx::LvalueTy;
 use rustc::mir;
 use middle::lang_items::ExchangeMallocFnLangItem;
@@ -105,9 +106,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
             mir::Rvalue::Aggregate(ref kind, ref operands) => {
                 match *kind {
                     mir::AggregateKind::Adt(adt_def, variant_index, substs, active_field_index) => {
-                        let disr = Disr::from(adt_def.variants[variant_index].disr_val);
+                        let disr = Disr::for_variant(bcx.tcx(), adt_def, variant_index);
                         let dest_ty = dest.ty.to_ty(bcx.tcx());
-                        adt::trans_set_discr(&bcx, dest_ty, dest.llval, Disr::from(disr));
+                        adt::trans_set_discr(&bcx, dest_ty, dest.llval, disr);
                         for (i, operand) in operands.iter().enumerate() {
                             let op = self.trans_operand(&bcx, operand);
                             // Do not generate stores and GEPis for zero-sized fields.
@@ -118,7 +119,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                                 val.ty = LvalueTy::Downcast {
                                     adt_def: adt_def,
                                     substs: self.monomorphize(&substs),
-                                    variant_index: disr.0 as usize,
+                                    variant_index: variant_index,
                                 };
                                 let (lldest_i, align) = val.trans_field_ptr(&bcx, field_index);
                                 self.store_operand(&bcx, lldest_i, align.to_align(), op);
@@ -190,6 +191,29 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                             }
                         }
                     }
+                    mir::CastKind::ClosureFnPointer => {
+                        match operand.ty.sty {
+                            ty::TyClosure(def_id, substs) => {
+                                // Get the def_id for FnOnce::call_once
+                                let fn_once = bcx.tcx().lang_items.fn_once_trait().unwrap();
+                                let call_once = bcx.tcx()
+                                    .global_tcx().associated_items(fn_once)
+                                    .find(|it| it.kind == ty::AssociatedKind::Method)
+                                    .unwrap().def_id;
+                                // Now create its substs [Closure, Tuple]
+                                let input = bcx.tcx().closure_type(def_id)
+                                    .subst(bcx.tcx(), substs.substs).input(0);
+                                let substs = bcx.tcx().mk_substs([operand.ty, input.skip_binder()]
+                                    .iter().cloned().map(Kind::from));
+                                OperandValue::Immediate(
+                                    Callee::def(bcx.ccx, call_once, substs)
+                                        .reify(bcx.ccx))
+                            }
+                            _ => {
+                                bug!("{} cannot be cast to a fn ptr", operand.ty)
+                            }
+                        }
+                    }
                     mir::CastKind::UnsafeFnPointer => {
                         // this is a no-op at the LLVM level
                         operand.val
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 04a6cb27501..d691fa6aadf 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -199,11 +199,17 @@ impl<'a, 'tcx> TransItem<'tcx> {
         assert_eq!(dg.ty(), glue::get_drop_glue_type(ccx.shared(), dg.ty()));
         let t = dg.ty();
 
-        let sig = tcx.mk_fn_sig(iter::once(tcx.mk_mut_ptr(t)), tcx.mk_nil(), false);
+        let sig = tcx.mk_fn_sig(
+            iter::once(tcx.mk_mut_ptr(t)),
+            tcx.mk_nil(),
+            false,
+            hir::Unsafety::Normal,
+            Abi::Rust
+        );
 
         debug!("predefine_drop_glue: sig={}", sig);
 
-        let fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
+        let fn_ty = FnType::new(ccx, sig, &[]);
         let llfnty = fn_ty.llvm_type(ccx);
 
         assert!(declare::get_defined_value(ccx, symbol_name).is_none());
@@ -457,12 +463,13 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
                         output);
                 }
             },
-            ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) |
-            ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
-                if unsafety == hir::Unsafety::Unsafe {
+            ty::TyFnDef(.., sig) |
+            ty::TyFnPtr(sig) => {
+                if sig.unsafety() == hir::Unsafety::Unsafe {
                     output.push_str("unsafe ");
                 }
 
+                let abi = sig.abi();
                 if abi != ::abi::Abi::Rust {
                     output.push_str("extern \"");
                     output.push_str(abi.name());
@@ -471,7 +478,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
 
                 output.push_str("fn(");
 
-                let sig = self.tcx.erase_late_bound_regions_and_normalize(sig);
+                let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig);
 
                 if !sig.inputs().is_empty() {
                     for &parameter_type in sig.inputs() {
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index 87af3b6c5e1..a5722e6e520 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -272,9 +272,9 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
       ty::TyStr | ty::TyDynamic(..) => Type::i8(cx),
 
       ty::TyFnDef(..) => Type::nil(cx),
-      ty::TyFnPtr(f) => {
-        let sig = cx.tcx().erase_late_bound_regions_and_normalize(&f.sig);
-        FnType::new(cx, f.abi, &sig, &[]).llvm_type(cx).ptr_to()
+      ty::TyFnPtr(sig) => {
+        let sig = cx.tcx().erase_late_bound_regions_and_normalize(&sig);
+        FnType::new(cx, sig, &[]).llvm_type(cx).ptr_to()
       }
       ty::TyTuple(ref tys, _) if tys.is_empty() => Type::nil(cx),
       ty::TyTuple(..) => {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index ab1897101eb..577fe31eab0 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -11,17 +11,6 @@
 //! Conversion from AST representation of types to the ty.rs
 //! representation.  The main routine here is `ast_ty_to_ty()`: each use
 //! is parameterized by an instance of `AstConv`.
-//!
-//! The parameterization of `ast_ty_to_ty()` is because it behaves
-//! somewhat differently during the collect and check phases,
-//! particularly with respect to looking up the types of top-level
-//! items.  In the collect phase, the crate context is used as the
-//! `AstConv` instance; in this phase, the `get_item_type()`
-//! function triggers a recursive call to `type_of_item()`
-//! (note that `ast_ty_to_ty()` will detect recursive types and report
-//! an error).  In the check phase, when the FnCtxt is used as the
-//! `AstConv`, `get_item_type()` just looks up the item type in
-//! `tcx.types` (using `TyCtxt::item_type`).
 
 use rustc_const_eval::eval_length;
 use rustc_data_structures::accumulate_vec::AccumulateVec;
@@ -42,7 +31,7 @@ use std::cell::RefCell;
 use std::iter;
 use syntax::{abi, ast};
 use syntax::feature_gate::{GateIssue, emit_feature_err};
-use syntax::symbol::{Symbol, keywords};
+use syntax::symbol::Symbol;
 use syntax_pos::Span;
 
 pub trait AstConv<'gcx, 'tcx> {
@@ -51,28 +40,10 @@ pub trait AstConv<'gcx, 'tcx> {
     /// A cache used for the result of `ast_ty_to_ty_cache`
     fn ast_ty_to_ty_cache(&self) -> &RefCell<NodeMap<Ty<'tcx>>>;
 
-    /// Returns the generic type and lifetime parameters for an item.
-    fn get_generics(&self, span: Span, id: DefId)
-                    -> Result<&'tcx ty::Generics<'tcx>, ErrorReported>;
-
-    /// Identify the type for an item, like a type alias, fn, or struct.
-    fn get_item_type(&self, span: Span, id: DefId) -> Result<Ty<'tcx>, ErrorReported>;
-
-    /// Returns the `TraitDef` for a given trait. This allows you to
-    /// figure out the set of type parameters defined on the trait.
-    fn get_trait_def(&self, span: Span, id: DefId)
-                     -> Result<&'tcx ty::TraitDef, ErrorReported>;
-
-    /// Ensure that the super-predicates for the trait with the given
-    /// id are available and also for the transitive set of
-    /// super-predicates.
-    fn ensure_super_predicates(&self, span: Span, id: DefId)
-                               -> Result<(), ErrorReported>;
-
     /// Returns the set of bounds in scope for the type parameter with
     /// the given id.
-    fn get_type_parameter_bounds(&self, span: Span, def_id: ast::NodeId)
-                                 -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>;
+    fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
+                                 -> ty::GenericPredicates<'tcx>;
 
     /// Return an (optional) substitution to convert bound type parameters that
     /// are in scope into free ones. This function should only return Some
@@ -89,7 +60,7 @@ pub trait AstConv<'gcx, 'tcx> {
 
     /// Same as ty_infer, but with a known type parameter definition.
     fn ty_infer_for_def(&self,
-                        _def: &ty::TypeParameterDef<'tcx>,
+                        _def: &ty::TypeParameterDef,
                         _substs: &[Kind<'tcx>],
                         span: Span) -> Ty<'tcx> {
         self.ty_infer(span)
@@ -218,7 +189,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                             &item_segment.parameters,
                                             None);
 
-        assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span));
+        assoc_bindings.first().map(|b| self.prohibit_projection(b.span));
 
         substs
     }
@@ -251,14 +222,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         // If the type is parameterized by this region, then replace this
         // region with the current anon region binding (in other words,
         // whatever & would get replaced with).
-        let decl_generics = match self.get_generics(span, def_id) {
-            Ok(generics) => generics,
-            Err(ErrorReported) => {
-                // No convenient way to recover from a cycle here. Just bail. Sorry!
-                self.tcx().sess.abort_if_errors();
-                bug!("ErrorReported returned, but no errors reports?")
-            }
-        };
+        let decl_generics = tcx.item_generics(def_id);
         let expected_num_region_params = decl_generics.regions.len();
         let supplied_num_region_params = lifetimes.len();
         if expected_num_region_params != supplied_num_region_params {
@@ -277,9 +241,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         }
 
         let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF);
-        let default_needs_object_self = |p: &ty::TypeParameterDef<'tcx>| {
-            if let Some(ref default) = p.default {
-                if is_object && default.has_self_ty() {
+        let default_needs_object_self = |p: &ty::TypeParameterDef| {
+            if is_object && p.has_default {
+                if ty::queries::ty::get(tcx, span, p.def_id).has_self_ty() {
                     // There is no suitable inference default for a type parameter
                     // that references self, in an object type.
                     return true;
@@ -327,7 +291,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     self.ty_infer(span)
                 };
                 ty_var
-            } else if let Some(default) = def.default {
+            } else if def.has_default {
                 // No type parameter provided, but a default exists.
 
                 // If we are converting an object type, then the
@@ -346,7 +310,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     tcx.types.err
                 } else {
                     // This is a default type parameter.
-                    default.subst_spanned(tcx, substs, Some(span))
+                    ty::queries::ty::get(tcx, span, def.def_id)
+                        .subst_spanned(tcx, substs, Some(span))
                 }
             } else {
                 // We've already errored above about the mismatch.
@@ -481,7 +446,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                                  trait_def_id,
                                                  self_ty,
                                                  trait_segment);
-        assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span));
+        assoc_bindings.first().map(|b| self.prohibit_projection(b.span));
         ty::TraitRef::new(trait_def_id, substs)
     }
 
@@ -495,14 +460,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         debug!("create_substs_for_ast_trait_ref(trait_segment={:?})",
                trait_segment);
 
-        let trait_def = match self.get_trait_def(span, trait_def_id) {
-            Ok(trait_def) => trait_def,
-            Err(ErrorReported) => {
-                // No convenient way to recover from a cycle here. Just bail. Sorry!
-                self.tcx().sess.abort_if_errors();
-                bug!("ErrorReported returned, but no errors reports?")
-            }
-        };
+        let trait_def = self.tcx().lookup_trait_def(trait_def_id);
 
         match trait_segment.parameters {
             hir::AngleBracketedParameters(_) => {
@@ -615,8 +573,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         // Otherwise, we have to walk through the supertraits to find
         // those that do.
-        self.ensure_super_predicates(binding.span, trait_ref.def_id())?;
-
         let candidates =
             traits::supertraits(tcx, trait_ref.clone())
             .filter(|r| self.trait_defines_associated_type_named(r.def_id(), binding.item_name));
@@ -643,16 +599,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         item_segment: &hir::PathSegment)
         -> Ty<'tcx>
     {
-        let tcx = self.tcx();
-        let decl_ty = match self.get_item_type(span, did) {
-            Ok(ty) => ty,
-            Err(ErrorReported) => {
-                return tcx.types.err;
-            }
-        };
-
         let substs = self.ast_path_substs_for_ty(span, did, item_segment);
-        decl_ty.subst(self.tcx(), substs)
+        ty::queries::ty::get(self.tcx(), span, did).subst(self.tcx(), substs)
     }
 
     /// Transform a PolyTraitRef into a PolyExistentialTraitRef by
@@ -709,11 +657,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             })
         });
 
-        // ensure the super predicates and stop if we encountered an error
-        if self.ensure_super_predicates(span, principal.def_id()).is_err() {
-            return tcx.types.err;
-        }
-
         // check that there are no gross object safety violations,
         // most importantly, that the supertraits don't contain Self,
         // to avoid ICE-s.
@@ -798,30 +741,19 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     }
 
     // Search for a bound on a type parameter which includes the associated item
-    // given by assoc_name. ty_param_node_id is the node id for the type parameter
-    // (which might be `Self`, but only if it is the `Self` of a trait, not an
-    // impl). This function will fail if there are no suitable bounds or there is
+    // given by `assoc_name`. `ty_param_def_id` is the `DefId` for the type parameter
+    // This function will fail if there are no suitable bounds or there is
     // any ambiguity.
     fn find_bound_for_assoc_item(&self,
-                                 ty_param_node_id: ast::NodeId,
-                                 ty_param_name: ast::Name,
+                                 ty_param_def_id: DefId,
                                  assoc_name: ast::Name,
                                  span: Span)
                                  -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
     {
         let tcx = self.tcx();
 
-        let bounds = match self.get_type_parameter_bounds(span, ty_param_node_id) {
-            Ok(v) => v,
-            Err(ErrorReported) => {
-                return Err(ErrorReported);
-            }
-        };
-
-        // Ensure the super predicates and stop if we encountered an error.
-        if bounds.iter().any(|b| self.ensure_super_predicates(span, b.def_id()).is_err()) {
-            return Err(ErrorReported);
-        }
+        let bounds: Vec<_> = self.get_type_parameter_bounds(span, ty_param_def_id)
+            .predicates.into_iter().filter_map(|p| p.to_opt_poly_trait_ref()).collect();
 
         // Check that there is exactly one way to find an associated type with the
         // correct name.
@@ -829,8 +761,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             traits::transitive_bounds(tcx, &bounds)
             .filter(|b| self.trait_defines_associated_type_named(b.def_id(), assoc_name));
 
+        let param_node_id = tcx.hir.as_local_node_id(ty_param_def_id).unwrap();
+        let param_name = tcx.hir.ty_param_name(param_node_id);
         self.one_bound_for_assoc_type(suitable_bounds,
-                                      &ty_param_name.as_str(),
+                                      &param_name.as_str(),
                                       &assoc_name.as_str(),
                                       span)
     }
@@ -910,7 +844,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         debug!("associated_path_def_to_ty: {:?}::{}", ty, assoc_name);
 
-        tcx.prohibit_type_params(slice::ref_slice(item_segment));
+        self.prohibit_type_params(slice::ref_slice(item_segment));
 
         // Find the type of the associated item, and the trait where the associated
         // item is declared.
@@ -918,29 +852,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             (_, Def::SelfTy(Some(_), Some(impl_def_id))) => {
                 // `Self` in an impl of a trait - we have a concrete self type and a
                 // trait reference.
-                // FIXME: Self type is not always computed when we are here because type parameter
-                // bounds may affect Self type and have to be converted before it.
-                let trait_ref = if impl_def_id.is_local() {
-                    tcx.impl_trait_refs.borrow().get(&impl_def_id).cloned().and_then(|x| x)
-                } else {
-                    tcx.impl_trait_ref(impl_def_id)
-                };
-                let trait_ref = if let Some(trait_ref) = trait_ref {
-                    trait_ref
-                } else {
-                    tcx.sess.span_err(span, "`Self` type is used before it's determined");
-                    return (tcx.types.err, Def::Err);
+                let trait_ref = match tcx.impl_trait_ref(impl_def_id) {
+                    Some(trait_ref) => trait_ref,
+                    None => {
+                        // A cycle error occurred, most likely.
+                        return (tcx.types.err, Def::Err);
+                    }
                 };
+
                 let trait_ref = if let Some(free_substs) = self.get_free_substs() {
                     trait_ref.subst(tcx, free_substs)
                 } else {
                     trait_ref
                 };
 
-                if self.ensure_super_predicates(span, trait_ref.def_id).is_err() {
-                    return (tcx.types.err, Def::Err);
-                }
-
                 let candidates =
                     traits::supertraits(tcx, ty::Binder(trait_ref))
                     .filter(|r| self.trait_defines_associated_type_named(r.def_id(),
@@ -954,23 +879,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     Err(ErrorReported) => return (tcx.types.err, Def::Err),
                 }
             }
-            (&ty::TyParam(_), Def::SelfTy(Some(trait_did), None)) => {
-                let trait_node_id = tcx.hir.as_local_node_id(trait_did).unwrap();
-                match self.find_bound_for_assoc_item(trait_node_id,
-                                                     keywords::SelfType.name(),
-                                                     assoc_name,
-                                                     span) {
-                    Ok(bound) => bound,
-                    Err(ErrorReported) => return (tcx.types.err, Def::Err),
-                }
-            }
+            (&ty::TyParam(_), Def::SelfTy(Some(param_did), None)) |
             (&ty::TyParam(_), Def::TyParam(param_did)) => {
-                let param_node_id = tcx.hir.as_local_node_id(param_did).unwrap();
-                let param_name = tcx.type_parameter_def(param_node_id).name;
-                match self.find_bound_for_assoc_item(param_node_id,
-                                                     param_name,
-                                                     assoc_name,
-                                                     span) {
+                match self.find_bound_for_assoc_item(param_did, assoc_name, span) {
                     Ok(bound) => bound,
                     Err(ErrorReported) => return (tcx.types.err, Def::Err),
                 }
@@ -1006,7 +917,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     {
         let tcx = self.tcx();
 
-        tcx.prohibit_type_params(slice::ref_slice(item_segment));
+        self.prohibit_type_params(slice::ref_slice(item_segment));
 
         let self_ty = if let Some(ty) = opt_self_ty {
             ty
@@ -1031,6 +942,36 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         self.projected_ty(span, trait_ref, item_segment.name)
     }
 
+    pub fn prohibit_type_params(&self, segments: &[hir::PathSegment]) {
+        for segment in segments {
+            for typ in segment.parameters.types() {
+                struct_span_err!(self.tcx().sess, typ.span, E0109,
+                                 "type parameters are not allowed on this type")
+                    .span_label(typ.span, &format!("type parameter not allowed"))
+                    .emit();
+                break;
+            }
+            for lifetime in segment.parameters.lifetimes() {
+                struct_span_err!(self.tcx().sess, lifetime.span, E0110,
+                                 "lifetime parameters are not allowed on this type")
+                    .span_label(lifetime.span,
+                                &format!("lifetime parameter not allowed on this type"))
+                    .emit();
+                break;
+            }
+            for binding in segment.parameters.bindings() {
+                self.prohibit_projection(binding.span);
+                break;
+            }
+        }
+    }
+
+    pub fn prohibit_projection(&self, span: Span) {
+        let mut err = struct_span_err!(self.tcx().sess, span, E0229,
+                                       "associated type bindings are not allowed here");
+        err.span_label(span, &format!("associate type not allowed here")).emit();
+    }
+
     // Check a type Path and convert it to a Ty.
     pub fn def_to_ty(&self,
                      opt_self_ty: Option<Ty<'tcx>>,
@@ -1046,71 +987,50 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         match path.def {
             Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => {
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(path.segments.split_last().unwrap().1);
+                self.prohibit_type_params(path.segments.split_last().unwrap().1);
                 self.ast_path_to_ty(span, did, path.segments.last().unwrap())
             }
             Def::Variant(did) if permit_variants => {
                 // Convert "variant type" as if it were a real type.
                 // The resulting `Ty` is type of the variant's enum for now.
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(path.segments.split_last().unwrap().1);
+                self.prohibit_type_params(path.segments.split_last().unwrap().1);
                 self.ast_path_to_ty(span,
                                     tcx.parent_def_id(did).unwrap(),
                                     path.segments.last().unwrap())
             }
             Def::TyParam(did) => {
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(&path.segments);
+                self.prohibit_type_params(&path.segments);
 
                 let node_id = tcx.hir.as_local_node_id(did).unwrap();
-                let param = tcx.ty_param_defs.borrow().get(&node_id)
-                               .map(ty::ParamTy::for_def);
-                if let Some(p) = param {
-                    p.to_ty(tcx)
-                } else {
-                    // Only while computing defaults of earlier type
-                    // parameters can a type parameter be missing its def.
-                    struct_span_err!(tcx.sess, span, E0128,
-                                     "type parameters with a default cannot use \
-                                      forward declared identifiers")
-                        .span_label(span, &format!("defaulted type parameters \
-                                                    cannot be forward declared"))
-                        .emit();
-                    tcx.types.err
-                }
+                let item_id = tcx.hir.get_parent_node(node_id);
+                let item_def_id = tcx.hir.local_def_id(item_id);
+                let generics = tcx.item_generics(item_def_id);
+                let index = generics.type_param_to_index[&tcx.hir.local_def_id(node_id).index];
+                tcx.mk_param(index, tcx.hir.name(node_id))
             }
             Def::SelfTy(_, Some(def_id)) => {
                 // Self in impl (we know the concrete type).
 
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(&path.segments);
+                self.prohibit_type_params(&path.segments);
 
-                // FIXME: Self type is not always computed when we are here because type parameter
-                // bounds may affect Self type and have to be converted before it.
-                let ty = if def_id.is_local() {
-                    tcx.item_types.borrow().get(&def_id).cloned()
+                let ty = ty::queries::ty::get(tcx, span, def_id);
+                if let Some(free_substs) = self.get_free_substs() {
+                    ty.subst(tcx, free_substs)
                 } else {
-                    Some(tcx.item_type(def_id))
-                };
-                if let Some(ty) = ty {
-                    if let Some(free_substs) = self.get_free_substs() {
-                        ty.subst(tcx, free_substs)
-                    } else {
-                        ty
-                    }
-                } else {
-                    tcx.sess.span_err(span, "`Self` type is used before it's determined");
-                    tcx.types.err
+                    ty
                 }
             }
             Def::SelfTy(Some(_), None) => {
                 // Self in trait.
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(&path.segments);
+                self.prohibit_type_params(&path.segments);
                 tcx.mk_self_type()
             }
             Def::AssociatedTy(def_id) => {
-                tcx.prohibit_type_params(&path.segments[..path.segments.len()-2]);
+                self.prohibit_type_params(&path.segments[..path.segments.len()-2]);
                 let trait_did = tcx.parent_def_id(def_id).unwrap();
                 self.qpath_to_ty(span,
                                  opt_self_ty,
@@ -1120,7 +1040,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             }
             Def::PrimTy(prim_ty) => {
                 assert_eq!(opt_self_ty, None);
-                tcx.prim_ty_to_ty(&path.segments, prim_ty)
+                self.prohibit_type_params(&path.segments);
+                match prim_ty {
+                    hir::TyBool => tcx.types.bool,
+                    hir::TyChar => tcx.types.char,
+                    hir::TyInt(it) => tcx.mk_mach_int(it),
+                    hir::TyUint(uit) => tcx.mk_mach_uint(uit),
+                    hir::TyFloat(ft) => tcx.mk_mach_float(ft),
+                    hir::TyStr => tcx.mk_str()
+                }
             }
             Def::Err => {
                 self.set_tainted_by_errors();
@@ -1183,10 +1111,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 // warning then. (Once we fix #32330, the regions we are
                 // checking for here would be considered early bound
                 // anyway.)
-                let inputs = bare_fn_ty.sig.inputs();
+                let inputs = bare_fn_ty.inputs();
                 let late_bound_in_args = tcx.collect_constrained_late_bound_regions(
                     &inputs.map_bound(|i| i.to_owned()));
-                let output = bare_fn_ty.sig.output();
+                let output = bare_fn_ty.output();
                 let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output);
                 for br in late_bound_in_ret.difference(&late_bound_in_args) {
                     let br_name = match *br {
@@ -1211,9 +1139,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             hir::TyTraitObject(ref bounds, ref lifetime) => {
                 self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime)
             }
-            hir::TyImplTrait(ref bounds) => {
-                use collect::{compute_bounds, SizedByDefault};
-
+            hir::TyImplTrait(_) => {
                 // Figure out if we can allow an `impl Trait` here, by walking up
                 // to a `fn` or inherent `impl` method, going only through `Ty`
                 // or `TraitRef` nodes (as nothing else should be in types) and
@@ -1253,24 +1179,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 // Create the anonymized type.
                 if allow {
                     let def_id = tcx.hir.local_def_id(ast_ty.id);
-                    if let Err(ErrorReported) = self.get_generics(ast_ty.span, def_id) {
-                        return tcx.types.err;
-                    }
-                    let substs = Substs::identity_for_item(tcx, def_id);
-                    let ty = tcx.mk_anon(tcx.hir.local_def_id(ast_ty.id), substs);
-
-                    // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
-                    let bounds = compute_bounds(self, ty, bounds,
-                                                SizedByDefault::Yes,
-                                                ast_ty.span);
-                    let predicates = bounds.predicates(tcx, ty);
-                    let predicates = tcx.lift_to_global(&predicates).unwrap();
-                    tcx.predicates.borrow_mut().insert(def_id, ty::GenericPredicates {
-                        parent: None,
-                        predicates: predicates
-                    });
-
-                    ty
+                    tcx.mk_anon(def_id, Substs::identity_for_item(tcx, def_id))
                 } else {
                     span_err!(tcx.sess, ast_ty.span, E0562,
                               "`impl Trait` not allowed outside of function \
@@ -1341,7 +1250,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     unsafety: hir::Unsafety,
                     abi: abi::Abi,
                     decl: &hir::FnDecl)
-                    -> &'tcx ty::BareFnTy<'tcx> {
+                    -> ty::PolyFnSig<'tcx> {
         debug!("ty_of_fn");
 
         let input_tys: Vec<Ty> =
@@ -1354,15 +1263,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         debug!("ty_of_fn: output_ty={:?}", output_ty);
 
-        self.tcx().mk_bare_fn(ty::BareFnTy {
-            unsafety: unsafety,
-            abi: abi,
-            sig: ty::Binder(self.tcx().mk_fn_sig(
-                input_tys.into_iter(),
-                output_ty,
-                decl.variadic
-            )),
-        })
+        ty::Binder(self.tcx().mk_fn_sig(
+            input_tys.into_iter(),
+            output_ty,
+            decl.variadic,
+            unsafety,
+            abi
+        ))
     }
 
     pub fn ty_of_closure(&self,
@@ -1370,7 +1277,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         decl: &hir::FnDecl,
         abi: abi::Abi,
         expected_sig: Option<ty::FnSig<'tcx>>)
-        -> ty::ClosureTy<'tcx>
+        -> ty::PolyFnSig<'tcx>
     {
         debug!("ty_of_closure(expected_sig={:?})",
                expected_sig);
@@ -1407,11 +1314,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         debug!("ty_of_closure: output_ty={:?}", output_ty);
 
-        ty::ClosureTy {
-            unsafety: unsafety,
-            abi: abi,
-            sig: ty::Binder(self.tcx().mk_fn_sig(input_tys, output_ty, decl.variadic)),
-        }
+        ty::Binder(self.tcx().mk_fn_sig(
+            input_tys,
+            output_ty,
+            decl.variadic,
+            unsafety,
+            abi
+        ))
     }
 
     /// Given the bounds on an object, determines what single region bound (if any) we can
@@ -1429,12 +1338,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         debug!("compute_opt_region_bound(existential_predicates={:?})",
                existential_predicates);
 
-        if let Some(principal) = existential_predicates.principal() {
-            if let Err(ErrorReported) = self.ensure_super_predicates(span, principal.def_id()) {
-                return Some(tcx.mk_region(ty::ReStatic));
-            }
-        }
-
         // No explicit region bound specified. Therefore, examine trait
         // bounds and see if we can derive region bounds from those.
         let derived_region_bounds =
@@ -1510,7 +1413,7 @@ fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize,
                              ty_param_defs: &[ty::TypeParameterDef]) {
     let accepted = ty_param_defs.len();
-    let required = ty_param_defs.iter().take_while(|x| x.default.is_none()) .count();
+    let required = ty_param_defs.iter().take_while(|x| !x.has_default).count();
     if supplied < required {
         let expected = if required < accepted {
             "expected at least"
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 3a980c8e764..4b88f5acf42 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -10,11 +10,12 @@
 
 use super::{DeferredCallResolution, Expectation, FnCtxt, TupleArgumentsFlag};
 
-use CrateCtxt;
 use hir::def::Def;
 use hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::{infer, traits};
-use rustc::ty::{self, LvaluePreference, Ty};
+use rustc::ty::{self, TyCtxt, LvaluePreference, Ty};
+use rustc::ty::subst::Subst;
+use syntax::abi;
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
 
@@ -23,12 +24,9 @@ use rustc::hir;
 /// Check that it is legal to call methods of the trait corresponding
 /// to `trait_id` (this only cares about the trait, not the specific
 /// method that is called)
-pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: DefId) {
-    if ccx.tcx.lang_items.drop_trait() == Some(trait_id) {
-        struct_span_err!(ccx.tcx.sess,
-                         span,
-                         E0040,
-                         "explicit use of destructor method")
+pub fn check_legal_trait_for_method_call(tcx: TyCtxt, span: Span, trait_id: DefId) {
+    if tcx.lang_items.drop_trait() == Some(trait_id) {
+        struct_span_err!(tcx.sess, span, E0040, "explicit use of destructor method")
             .span_label(span, &format!("explicit destructor calls not allowed"))
             .emit();
     }
@@ -113,10 +111,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // haven't yet decided on whether the closure is fn vs
                 // fnmut vs fnonce. If so, we have to defer further processing.
                 if self.closure_kind(def_id).is_none() {
-                    let closure_ty = self.closure_type(def_id, substs);
+                    let closure_ty = self.closure_type(def_id).subst(self.tcx, substs.substs);
                     let fn_sig = self.replace_late_bound_regions_with_fresh_var(call_expr.span,
                                                                    infer::FnCall,
-                                                                   &closure_ty.sig)
+                                                                   &closure_ty)
                         .0;
                     self.record_deferred_call_resolution(def_id,
                                                          Box::new(CallResolution {
@@ -190,13 +188,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             arg_exprs: &'gcx [hir::Expr],
                             expected: Expectation<'tcx>)
                             -> Ty<'tcx> {
-        let error_fn_sig;
-
         let (fn_sig, def_span) = match callee_ty.sty {
-            ty::TyFnDef(def_id, .., &ty::BareFnTy {ref sig, ..}) => {
+            ty::TyFnDef(def_id, .., sig) => {
                 (sig, self.tcx.hir.span_if_local(def_id))
             }
-            ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => (sig, None),
+            ty::TyFnPtr(sig) => (sig, None),
             ref t => {
                 let mut unit_variant = None;
                 if let &ty::TyAdt(adt_def, ..) = t {
@@ -236,13 +232,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // This is the "default" function signature, used in case of error.
                 // In that case, we check each argument against "error" in order to
                 // set up all the node type bindings.
-                error_fn_sig = ty::Binder(self.tcx.mk_fn_sig(
+                (ty::Binder(self.tcx.mk_fn_sig(
                     self.err_args(arg_exprs.len()).into_iter(),
                     self.tcx.types.err,
                     false,
-                ));
-
-                (&error_fn_sig, None)
+                    hir::Unsafety::Normal,
+                    abi::Abi::Rust
+                )), None)
             }
         };
 
@@ -252,7 +248,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // previously appeared within a `Binder<>` and hence would not
         // have been normalized before.
         let fn_sig =
-            self.replace_late_bound_regions_with_fresh_var(call_expr.span, infer::FnCall, fn_sig)
+            self.replace_late_bound_regions_with_fresh_var(call_expr.span, infer::FnCall, &fn_sig)
                 .0;
         let fn_sig = self.normalize_associated_types_in(call_expr.span, &fn_sig);
 
@@ -359,7 +355,7 @@ impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tc
                 // (This always bites me, should find a way to
                 // refactor it.)
                 let method_sig = fcx.tcx
-                    .no_late_bound_regions(method_callee.ty.fn_sig())
+                    .no_late_bound_regions(&method_callee.ty.fn_sig())
                     .unwrap();
 
                 debug!("attempt_resolution: method_callee={:?}", method_callee);
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 7979edbf5e2..51fbc5aab6c 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -55,11 +55,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                expected_sig);
 
         let expr_def_id = self.tcx.hir.local_def_id(expr.id);
-        let mut fn_ty = AstConv::ty_of_closure(self,
-                                               hir::Unsafety::Normal,
-                                               decl,
-                                               Abi::RustCall,
-                                               expected_sig);
+        let sig = AstConv::ty_of_closure(self,
+                                         hir::Unsafety::Normal,
+                                         decl,
+                                         Abi::RustCall,
+                                         expected_sig);
 
         // Create type variables (for now) to represent the transformed
         // types of upvars. These will be unified during the upvar
@@ -74,32 +74,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type);
 
         let extent = self.tcx.region_maps.call_site_extent(expr.id, body.value.id);
-        let fn_sig = self.tcx.liberate_late_bound_regions(extent, &fn_ty.sig);
+        let fn_sig = self.tcx.liberate_late_bound_regions(extent, &sig);
         let fn_sig = self.inh.normalize_associated_types_in(body.value.span,
                                                             body.value.id, &fn_sig);
 
-        check_fn(self,
-                 hir::Unsafety::Normal,
-                 expr.id,
-                 &fn_sig,
-                 decl,
-                 expr.id,
-                 body);
+        check_fn(self, fn_sig, decl, expr.id, body);
 
         // Tuple up the arguments and insert the resulting function type into
         // the `closures` table.
-        fn_ty.sig.0 = self.tcx.mk_fn_sig(
-            iter::once(self.tcx.intern_tup(fn_ty.sig.skip_binder().inputs(), false)),
-            fn_ty.sig.skip_binder().output(),
-            fn_ty.sig.variadic()
-        );
+        let sig = sig.map_bound(|sig| self.tcx.mk_fn_sig(
+            iter::once(self.tcx.intern_tup(sig.inputs(), false)),
+            sig.output(),
+            sig.variadic,
+            sig.unsafety,
+            sig.abi
+        ));
 
         debug!("closure for {:?} --> sig={:?} opt_kind={:?}",
                expr_def_id,
-               fn_ty.sig,
+               sig,
                opt_kind);
 
-        self.tables.borrow_mut().closure_tys.insert(expr.id, fn_ty);
+        self.tables.borrow_mut().closure_tys.insert(expr.id, sig);
         match opt_kind {
             Some(kind) => {
                 self.tables.borrow_mut().closure_kinds.insert(expr.id, kind);
@@ -228,7 +224,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty);
         debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty);
 
-        let fn_sig = self.tcx.mk_fn_sig(input_tys.cloned(), ret_param_ty, false);
+        let fn_sig = self.tcx.mk_fn_sig(
+            input_tys.cloned(),
+            ret_param_ty,
+            false,
+            hir::Unsafety::Normal,
+            Abi::Rust
+        );
         debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);
 
         Some(fn_sig)
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 718c273785a..53759cc115d 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -63,13 +63,18 @@
 use check::FnCtxt;
 
 use rustc::hir;
+use rustc::hir::def_id::DefId;
 use rustc::infer::{Coercion, InferOk, TypeTrace};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode};
 use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
-use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty};
+use rustc::ty::{self, LvaluePreference, TypeAndMut,
+                Ty, ClosureSubsts};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::error::TypeError;
 use rustc::ty::relate::RelateResult;
+use rustc::ty::subst::Subst;
+use syntax::abi;
+use syntax::feature_gate;
 use util::common::indent;
 
 use std::cell::RefCell;
@@ -196,6 +201,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
                 // unsafe qualifier.
                 self.coerce_from_fn_pointer(a, a_f, b)
             }
+            ty::TyClosure(def_id_a, substs_a) => {
+                // Non-capturing closures are coercible to
+                // function pointers
+                self.coerce_closure_to_fn(a, def_id_a, substs_a, b)
+            }
             _ => {
                 // Otherwise, just use unification rules.
                 self.unify_and_identity(a, b)
@@ -498,11 +508,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
 
     fn coerce_from_safe_fn(&self,
                            a: Ty<'tcx>,
-                           fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
+                           fn_ty_a: ty::PolyFnSig<'tcx>,
                            b: Ty<'tcx>)
                            -> CoerceResult<'tcx> {
         if let ty::TyFnPtr(fn_ty_b) = b.sty {
-            match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
+            match (fn_ty_a.unsafety(), fn_ty_b.unsafety()) {
                 (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
                     let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
                     return self.unify_and_identity(unsafe_a, b)
@@ -516,7 +526,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
 
     fn coerce_from_fn_pointer(&self,
                               a: Ty<'tcx>,
-                              fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
+                              fn_ty_a: ty::PolyFnSig<'tcx>,
                               b: Ty<'tcx>)
                               -> CoerceResult<'tcx> {
         //! Attempts to coerce from the type of a Rust function item
@@ -531,7 +541,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
 
     fn coerce_from_fn_item(&self,
                            a: Ty<'tcx>,
-                           fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
+                           fn_ty_a: ty::PolyFnSig<'tcx>,
                            b: Ty<'tcx>)
                            -> CoerceResult<'tcx> {
         //! Attempts to coerce from the type of a Rust function item
@@ -551,6 +561,59 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
         }
     }
 
+    fn coerce_closure_to_fn(&self,
+                           a: Ty<'tcx>,
+                           def_id_a: DefId,
+                           substs_a: ClosureSubsts<'tcx>,
+                           b: Ty<'tcx>)
+                           -> CoerceResult<'tcx> {
+        //! Attempts to coerce from the type of a non-capturing closure
+        //! into a function pointer.
+        //!
+
+        let b = self.shallow_resolve(b);
+
+        let node_id_a = self.tcx.hir.as_local_node_id(def_id_a).unwrap();
+        match b.sty {
+            ty::TyFnPtr(_) if self.tcx.with_freevars(node_id_a, |v| v.is_empty()) => {
+                if !self.tcx.sess.features.borrow().closure_to_fn_coercion {
+                    feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
+                                                   "closure_to_fn_coercion",
+                                                   self.cause.span,
+                                                   feature_gate::GateIssue::Language,
+                                                   feature_gate::CLOSURE_TO_FN_COERCION);
+                    return self.unify_and_identity(a, b);
+                }
+                // We coerce the closure, which has fn type
+                //     `extern "rust-call" fn((arg0,arg1,...)) -> _`
+                // to
+                //     `fn(arg0,arg1,...) -> _`
+                let sig = self.closure_type(def_id_a).subst(self.tcx, substs_a.substs);
+                let converted_sig = sig.map_bound(|s| {
+                    let params_iter = match s.inputs()[0].sty {
+                        ty::TyTuple(params, _) => {
+                            params.into_iter().cloned()
+                        }
+                        _ => bug!(),
+                    };
+                    self.tcx.mk_fn_sig(
+                        params_iter,
+                        s.output(),
+                        s.variadic,
+                        hir::Unsafety::Normal,
+                        abi::Abi::Rust
+                    )
+                });
+                let pointer_ty = self.tcx.mk_fn_ptr(converted_sig);
+                debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})",
+                       a, b, pointer_ty);
+                self.unify_and_identity(pointer_ty, b)
+                    .map(|(ty, _)| (ty, Adjust::ClosureFnPointer))
+            }
+            _ => self.unify_and_identity(a, b),
+        }
+    }
+
     fn coerce_unsafe_ptr(&self,
                          a: Ty<'tcx>,
                          b: Ty<'tcx>,
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index d110c16cf33..0e9abaf1cf9 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -11,7 +11,7 @@
 use rustc::hir::{self, ImplItemKind, TraitItemKind};
 use rustc::infer::{self, InferOk};
 use rustc::middle::free_region::FreeRegionMap;
-use rustc::ty;
+use rustc::ty::{self, TyCtxt};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 use rustc::ty::error::{ExpectedFound, TypeError};
 use rustc::ty::subst::{Subst, Substs};
@@ -20,7 +20,6 @@ use rustc::util::common::ErrorReported;
 use syntax::ast;
 use syntax_pos::Span;
 
-use CrateCtxt;
 use super::assoc;
 use super::{Inherited, FnCtxt};
 use astconv::ExplicitSelf;
@@ -36,7 +35,7 @@ use astconv::ExplicitSelf;
 /// - trait_m: the method in the trait
 /// - impl_trait_ref: the TraitRef corresponding to the trait implementation
 
-pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                      impl_m: &ty::AssociatedItem,
                                      impl_m_span: Span,
                                      impl_m_body_id: ast::NodeId,
@@ -47,7 +46,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     debug!("compare_impl_method(impl_trait_ref={:?})",
            impl_trait_ref);
 
-    if let Err(ErrorReported) = compare_self_type(ccx,
+    if let Err(ErrorReported) = compare_self_type(tcx,
                                                   impl_m,
                                                   impl_m_span,
                                                   trait_m,
@@ -55,7 +54,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         return;
     }
 
-    if let Err(ErrorReported) = compare_number_of_generics(ccx,
+    if let Err(ErrorReported) = compare_number_of_generics(tcx,
                                                            impl_m,
                                                            impl_m_span,
                                                            trait_m,
@@ -63,7 +62,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         return;
     }
 
-    if let Err(ErrorReported) = compare_number_of_method_arguments(ccx,
+    if let Err(ErrorReported) = compare_number_of_method_arguments(tcx,
                                                                    impl_m,
                                                                    impl_m_span,
                                                                    trait_m,
@@ -71,7 +70,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         return;
     }
 
-    if let Err(ErrorReported) = compare_predicate_entailment(ccx,
+    if let Err(ErrorReported) = compare_predicate_entailment(tcx,
                                                              impl_m,
                                                              impl_m_span,
                                                              impl_m_body_id,
@@ -82,7 +81,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                           impl_m: &ty::AssociatedItem,
                                           impl_m_span: Span,
                                           impl_m_body_id: ast::NodeId,
@@ -90,8 +89,6 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                           impl_trait_ref: ty::TraitRef<'tcx>,
                                           old_broken_mode: bool)
                                           -> Result<(), ErrorReported> {
-    let tcx = ccx.tcx;
-
     let trait_to_impl_substs = impl_trait_ref.substs;
 
     let cause = ObligationCause {
@@ -190,7 +187,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let trait_m_predicates = tcx.item_predicates(trait_m.def_id);
 
     // Check region bounds.
-    check_region_bounds_on_impl_method(ccx,
+    check_region_bounds_on_impl_method(tcx,
                                        impl_m_span,
                                        impl_m,
                                        &trait_m_generics,
@@ -227,8 +224,8 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                                                trait_param_env,
                                                                normalize_cause.clone());
 
-    tcx.infer_ctxt(trait_param_env, Reveal::NotSpecializable).enter(|infcx| {
-        let inh = Inherited::new(ccx, infcx);
+    tcx.infer_ctxt(trait_param_env, Reveal::UserFacing).enter(|infcx| {
+        let inh = Inherited::new(infcx);
         let infcx = &inh.infcx;
         let fulfillment_cx = &inh.fulfillment_cx;
 
@@ -266,19 +263,17 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         // Compute skolemized form of impl and trait method tys.
         let tcx = infcx.tcx;
 
-        let m_fty = |method: &ty::AssociatedItem| {
+        let m_sig = |method: &ty::AssociatedItem| {
             match tcx.item_type(method.def_id).sty {
                 ty::TyFnDef(_, _, f) => f,
                 _ => bug!()
             }
         };
-        let impl_m_fty = m_fty(impl_m);
-        let trait_m_fty = m_fty(trait_m);
 
         let (impl_sig, _) =
             infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
                                                             infer::HigherRankedType,
-                                                            &impl_m_fty.sig);
+                                                            &m_sig(impl_m));
         let impl_sig =
             impl_sig.subst(tcx, impl_to_skol_substs);
         let impl_sig =
@@ -287,16 +282,12 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                                  impl_m_span,
                                                  impl_m_body_id,
                                                  &impl_sig);
-        let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
-            unsafety: impl_m_fty.unsafety,
-            abi: impl_m_fty.abi,
-            sig: ty::Binder(impl_sig.clone()),
-        }));
+        let impl_fty = tcx.mk_fn_ptr(ty::Binder(impl_sig));
         debug!("compare_impl_method: impl_fty={:?}", impl_fty);
 
         let trait_sig = tcx.liberate_late_bound_regions(
             infcx.parameter_environment.free_id_outlive,
-            &trait_m_fty.sig);
+            &m_sig(trait_m));
         let trait_sig =
             trait_sig.subst(tcx, trait_to_skol_substs);
         let trait_sig =
@@ -305,11 +296,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                                  impl_m_span,
                                                  impl_m_body_id,
                                                  &trait_sig);
-        let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
-            unsafety: trait_m_fty.unsafety,
-            abi: trait_m_fty.abi,
-            sig: ty::Binder(trait_sig.clone()),
-        }));
+        let trait_fty = tcx.mk_fn_ptr(ty::Binder(trait_sig));
 
         debug!("compare_impl_method: trait_fty={:?}", trait_fty);
 
@@ -383,11 +370,11 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     })
 }
 
-fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                 span: Span,
                                                 impl_m: &ty::AssociatedItem,
-                                                trait_generics: &ty::Generics<'tcx>,
-                                                impl_generics: &ty::Generics<'tcx>,
+                                                trait_generics: &ty::Generics,
+                                                impl_generics: &ty::Generics,
                                                 trait_to_skol_substs: &Substs<'tcx>,
                                                 impl_to_skol_substs: &Substs<'tcx>)
                                                 -> Result<(), ErrorReported> {
@@ -414,7 +401,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     // are zero. Since I don't quite know how to phrase things at
     // the moment, give a kind of vague error message.
     if trait_params.len() != impl_params.len() {
-        struct_span_err!(ccx.tcx.sess,
+        struct_span_err!(tcx.sess,
                          span,
                          E0195,
                          "lifetime parameters or bounds on method `{}` do not match the \
@@ -510,14 +497,13 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
     }
 }
 
-fn compare_self_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                impl_m: &ty::AssociatedItem,
                                impl_m_span: Span,
                                trait_m: &ty::AssociatedItem,
                                impl_trait_ref: ty::TraitRef<'tcx>)
                                -> Result<(), ErrorReported>
 {
-    let tcx = ccx.tcx;
     // Try to give more informative error messages about self typing
     // mismatches.  Note that any mismatch will also be detected
     // below, where we construct a canonical function type that
@@ -583,13 +569,12 @@ fn compare_self_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     Ok(())
 }
 
-fn compare_number_of_generics<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn compare_number_of_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         impl_m: &ty::AssociatedItem,
                                         impl_m_span: Span,
                                         trait_m: &ty::AssociatedItem,
                                         trait_item_span: Option<Span>)
                                         -> Result<(), ErrorReported> {
-    let tcx = ccx.tcx;
     let impl_m_generics = tcx.item_generics(impl_m.def_id);
     let trait_m_generics = tcx.item_generics(trait_m.def_id);
     let num_impl_m_type_params = impl_m_generics.types.len();
@@ -653,13 +638,12 @@ fn compare_number_of_generics<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     Ok(())
 }
 
-fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                 impl_m: &ty::AssociatedItem,
                                                 impl_m_span: Span,
                                                 trait_m: &ty::AssociatedItem,
                                                 trait_item_span: Option<Span>)
                                                 -> Result<(), ErrorReported> {
-    let tcx = ccx.tcx;
     let m_fty = |method: &ty::AssociatedItem| {
         match tcx.item_type(method.def_id).sty {
             ty::TyFnDef(_, _, f) => f,
@@ -668,8 +652,8 @@ fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     };
     let impl_m_fty = m_fty(impl_m);
     let trait_m_fty = m_fty(trait_m);
-    let trait_number_args = trait_m_fty.sig.inputs().skip_binder().len();
-    let impl_number_args = impl_m_fty.sig.inputs().skip_binder().len();
+    let trait_number_args = trait_m_fty.inputs().skip_binder().len();
+    let impl_number_args = impl_m_fty.inputs().skip_binder().len();
     if trait_number_args != impl_number_args {
         let trait_m_node_id = tcx.hir.as_local_node_id(trait_m.def_id);
         let trait_span = if let Some(trait_id) = trait_m_node_id {
@@ -739,15 +723,14 @@ fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     Ok(())
 }
 
-pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     impl_c: &ty::AssociatedItem,
                                     impl_c_span: Span,
                                     trait_c: &ty::AssociatedItem,
                                     impl_trait_ref: ty::TraitRef<'tcx>) {
     debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
 
-    let tcx = ccx.tcx;
-    tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
+    tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
         let mut fulfillment_cx = traits::FulfillmentContext::new();
 
         // The below is for the most part highly similar to the procedure
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index a77887cd221..232c4c4db7c 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -123,8 +123,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         match method.def() {
             Def::Method(def_id) => {
                 match self.tcx.item_type(def_id).sty {
-                    ty::TypeVariants::TyFnDef(_, _, fty) => {
-                        fty.sig.skip_binder().inputs().len() == 1
+                    ty::TypeVariants::TyFnDef(_, _, sig) => {
+                        sig.inputs().skip_binder().len() == 1
                     }
                     _ => false,
                 }
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index f701bc32208..07cc35ed67b 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use CrateCtxt;
 use check::regionck::RegionCtxt;
 
 use hir::def_id::DefId;
@@ -40,17 +39,18 @@ use syntax_pos::Span;
 ///    struct/enum definition for the nominal type itself (i.e.
 ///    cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
 ///
-pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()> {
-    let dtor_self_type = ccx.tcx.item_type(drop_impl_did);
-    let dtor_predicates = ccx.tcx.item_predicates(drop_impl_did);
+pub fn check_drop_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                 drop_impl_did: DefId) -> Result<(), ()> {
+    let dtor_self_type = tcx.item_type(drop_impl_did);
+    let dtor_predicates = tcx.item_predicates(drop_impl_did);
     match dtor_self_type.sty {
         ty::TyAdt(adt_def, self_to_impl_substs) => {
-            ensure_drop_params_and_item_params_correspond(ccx,
+            ensure_drop_params_and_item_params_correspond(tcx,
                                                           drop_impl_did,
                                                           dtor_self_type,
                                                           adt_def.did)?;
 
-            ensure_drop_predicates_are_implied_by_item_defn(ccx,
+            ensure_drop_predicates_are_implied_by_item_defn(tcx,
                                                             drop_impl_did,
                                                             &dtor_predicates,
                                                             adt_def.did,
@@ -59,7 +59,7 @@ pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()>
         _ => {
             // Destructors only work on nominal types.  This was
             // already checked by coherence, so we can panic here.
-            let span = ccx.tcx.def_span(drop_impl_did);
+            let span = tcx.def_span(drop_impl_did);
             span_bug!(span,
                       "should have been rejected by coherence check: {}",
                       dtor_self_type);
@@ -68,20 +68,19 @@ pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()>
 }
 
 fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
-    ccx: &CrateCtxt<'a, 'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
     drop_impl_did: DefId,
     drop_impl_ty: Ty<'tcx>,
     self_type_did: DefId)
     -> Result<(), ()>
 {
-    let tcx = ccx.tcx;
     let drop_impl_node_id = tcx.hir.as_local_node_id(drop_impl_did).unwrap();
     let self_type_node_id = tcx.hir.as_local_node_id(self_type_did).unwrap();
 
     // check that the impl type can be made to match the trait type.
 
     let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id);
-    tcx.infer_ctxt(impl_param_env, Reveal::NotSpecializable).enter(|infcx| {
+    tcx.infer_ctxt(impl_param_env, Reveal::UserFacing).enter(|infcx| {
         let tcx = infcx.tcx;
         let mut fulfillment_cx = traits::FulfillmentContext::new();
 
@@ -126,7 +125,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
 /// Confirms that every predicate imposed by dtor_predicates is
 /// implied by assuming the predicates attached to self_type_did.
 fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
-    ccx: &CrateCtxt<'a, 'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
     drop_impl_did: DefId,
     dtor_predicates: &ty::GenericPredicates<'tcx>,
     self_type_did: DefId,
@@ -169,8 +168,6 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
     // absent. So we report an error that the Drop impl injected a
     // predicate that is not present on the struct definition.
 
-    let tcx = ccx.tcx;
-
     let self_type_node_id = tcx.hir.as_local_node_id(self_type_did).unwrap();
 
     let drop_impl_span = tcx.def_span(drop_impl_did);
@@ -557,7 +554,7 @@ fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 
             // Find the `impl<..> Drop for _` to inspect any
             // attributes attached to the impl's generics.
-            let dtor_method = adt_def.destructor()
+            let dtor_method = adt_def.destructor(tcx)
                 .expect("dtorck type without destructor impossible");
             let method = tcx.associated_item(dtor_method);
             let impl_def_id = method.container.id();
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index cb4e85e842c..28996b40cfd 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -14,9 +14,9 @@
 use intrinsics;
 use rustc::traits::{ObligationCause, ObligationCauseCode};
 use rustc::ty::subst::Substs;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, TyCtxt, Ty};
 use rustc::util::nodemap::FxHashMap;
-use {CrateCtxt, require_same_types};
+use require_same_types;
 
 use syntax::abi::Abi;
 use syntax::ast;
@@ -27,24 +27,25 @@ use rustc::hir;
 
 use std::iter;
 
-fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                    it: &hir::ForeignItem,
                                    n_tps: usize,
                                    abi: Abi,
                                    inputs: Vec<Ty<'tcx>>,
                                    output: Ty<'tcx>) {
-    let tcx = ccx.tcx;
     let def_id = tcx.hir.local_def_id(it.id);
 
     let substs = Substs::for_item(tcx, def_id,
                                   |_, _| tcx.mk_region(ty::ReErased),
                                   |def, _| tcx.mk_param_from_def(def));
 
-    let fty = tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy {
-        unsafety: hir::Unsafety::Unsafe,
-        abi: abi,
-        sig: ty::Binder(tcx.mk_fn_sig(inputs.into_iter(), output, false)),
-    }));
+    let fty = tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig(
+        inputs.into_iter(),
+        output,
+        false,
+        hir::Unsafety::Unsafe,
+        abi
+    )));
     let i_n_tps = tcx.item_generics(def_id).types.len();
     if i_n_tps != n_tps {
         let span = match it.node {
@@ -59,7 +60,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             .span_label(span, &format!("expected {} type parameter", n_tps))
             .emit();
     } else {
-        require_same_types(ccx,
+        require_same_types(tcx,
                            &ObligationCause::new(it.span,
                                                  it.id,
                                                  ObligationCauseCode::IntrinsicType),
@@ -70,13 +71,9 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
 /// Remember to add all intrinsics here, in librustc_trans/trans/intrinsic.rs,
 /// and in libcore/intrinsics.rs
-pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
-    fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
-        let name = Symbol::intern(&format!("P{}", n));
-        ccx.tcx.mk_param(n, name)
-    }
-
-    let tcx = ccx.tcx;
+pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                      it: &hir::ForeignItem) {
+    let param = |n| tcx.mk_param(n, Symbol::intern(&format!("P{}", n)));
     let name = it.name.as_str();
     let (n_tps, inputs, output) = if name.starts_with("atomic_") {
         let split : Vec<&str> = name.split('_').collect();
@@ -84,19 +81,19 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
 
         //We only care about the operation here
         let (n_tps, inputs, output) = match split[1] {
-            "cxchg" | "cxchgweak" => (1, vec![tcx.mk_mut_ptr(param(ccx, 0)),
-                                              param(ccx, 0),
-                                              param(ccx, 0)],
-                                      tcx.intern_tup(&[param(ccx, 0), tcx.types.bool], false)),
-            "load" => (1, vec![tcx.mk_imm_ptr(param(ccx, 0))],
-                       param(ccx, 0)),
-            "store" => (1, vec![tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)],
+            "cxchg" | "cxchgweak" => (1, vec![tcx.mk_mut_ptr(param(0)),
+                                              param(0),
+                                              param(0)],
+                                      tcx.intern_tup(&[param(0), tcx.types.bool], false)),
+            "load" => (1, vec![tcx.mk_imm_ptr(param(0))],
+                       param(0)),
+            "store" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)],
                         tcx.mk_nil()),
 
             "xchg" | "xadd" | "xsub" | "and"  | "nand" | "or" | "xor" | "max" |
             "min"  | "umax" | "umin" => {
-                (1, vec![tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)],
-                 param(ccx, 0))
+                (1, vec![tcx.mk_mut_ptr(param(0)), param(0)],
+                 param(0))
             }
             "fence" | "singlethreadfence" => {
                 (0, Vec::new(), tcx.mk_nil())
@@ -116,45 +113,45 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
         let (n_tps, inputs, output) = match &name[..] {
             "breakpoint" => (0, Vec::new(), tcx.mk_nil()),
             "size_of" |
-            "pref_align_of" | "min_align_of" => (1, Vec::new(), ccx.tcx.types.usize),
+            "pref_align_of" | "min_align_of" => (1, Vec::new(), tcx.types.usize),
             "size_of_val" |  "min_align_of_val" => {
                 (1, vec![
                     tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1),
                                                                   ty::BrAnon(0))),
-                                    param(ccx, 0))
-                 ], ccx.tcx.types.usize)
+                                    param(0))
+                 ], tcx.types.usize)
             }
-            "rustc_peek" => (1, vec![param(ccx, 0)], param(ccx, 0)),
-            "init" => (1, Vec::new(), param(ccx, 0)),
-            "uninit" => (1, Vec::new(), param(ccx, 0)),
-            "forget" => (1, vec![ param(ccx, 0) ], tcx.mk_nil()),
-            "transmute" => (2, vec![ param(ccx, 0) ], param(ccx, 1)),
+            "rustc_peek" => (1, vec![param(0)], param(0)),
+            "init" => (1, Vec::new(), param(0)),
+            "uninit" => (1, Vec::new(), param(0)),
+            "forget" => (1, vec![ param(0) ], tcx.mk_nil()),
+            "transmute" => (2, vec![ param(0) ], param(1)),
             "move_val_init" => {
                 (1,
                  vec![
-                    tcx.mk_mut_ptr(param(ccx, 0)),
-                    param(ccx, 0)
+                    tcx.mk_mut_ptr(param(0)),
+                    param(0)
                   ],
                tcx.mk_nil())
             }
             "drop_in_place" => {
-                (1, vec![tcx.mk_mut_ptr(param(ccx, 0))], tcx.mk_nil())
+                (1, vec![tcx.mk_mut_ptr(param(0))], tcx.mk_nil())
             }
-            "needs_drop" => (1, Vec::new(), ccx.tcx.types.bool),
+            "needs_drop" => (1, Vec::new(), tcx.types.bool),
 
             "type_name" => (1, Vec::new(), tcx.mk_static_str()),
-            "type_id" => (1, Vec::new(), ccx.tcx.types.u64),
+            "type_id" => (1, Vec::new(), tcx.types.u64),
             "offset" | "arith_offset" => {
               (1,
                vec![
                   tcx.mk_ptr(ty::TypeAndMut {
-                      ty: param(ccx, 0),
+                      ty: param(0),
                       mutbl: hir::MutImmutable
                   }),
-                  ccx.tcx.types.isize
+                  tcx.types.isize
                ],
                tcx.mk_ptr(ty::TypeAndMut {
-                   ty: param(ccx, 0),
+                   ty: param(0),
                    mutbl: hir::MutImmutable
                }))
             }
@@ -162,11 +159,11 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
               (1,
                vec![
                   tcx.mk_ptr(ty::TypeAndMut {
-                      ty: param(ccx, 0),
+                      ty: param(0),
                       mutbl: hir::MutImmutable
                   }),
                   tcx.mk_ptr(ty::TypeAndMut {
-                      ty: param(ccx, 0),
+                      ty: param(0),
                       mutbl: hir::MutMutable
                   }),
                   tcx.types.usize,
@@ -177,11 +174,11 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
               (1,
                vec![
                   tcx.mk_ptr(ty::TypeAndMut {
-                      ty: param(ccx, 0),
+                      ty: param(0),
                       mutbl: hir::MutMutable
                   }),
                   tcx.mk_ptr(ty::TypeAndMut {
-                      ty: param(ccx, 0),
+                      ty: param(0),
                       mutbl: hir::MutImmutable
                   }),
                   tcx.types.usize,
@@ -192,7 +189,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
               (1,
                vec![
                   tcx.mk_ptr(ty::TypeAndMut {
-                      ty: param(ccx, 0),
+                      ty: param(0),
                       mutbl: hir::MutMutable
                   }),
                   tcx.types.u8,
@@ -264,23 +261,23 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
             "roundf64"     => (0, vec![ tcx.types.f64 ], tcx.types.f64),
 
             "volatile_load" =>
-                (1, vec![ tcx.mk_imm_ptr(param(ccx, 0)) ], param(ccx, 0)),
+                (1, vec![ tcx.mk_imm_ptr(param(0)) ], param(0)),
             "volatile_store" =>
-                (1, vec![ tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0) ], tcx.mk_nil()),
+                (1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_nil()),
 
-            "ctpop" | "ctlz" | "cttz" | "bswap" => (1, vec![param(ccx, 0)], param(ccx, 0)),
+            "ctpop" | "ctlz" | "cttz" | "bswap" => (1, vec![param(0)], param(0)),
 
             "add_with_overflow" | "sub_with_overflow"  | "mul_with_overflow" =>
-                (1, vec![param(ccx, 0), param(ccx, 0)],
-                tcx.intern_tup(&[param(ccx, 0), tcx.types.bool], false)),
+                (1, vec![param(0), param(0)],
+                tcx.intern_tup(&[param(0), tcx.types.bool], false)),
 
             "unchecked_div" | "unchecked_rem" =>
-                (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)),
+                (1, vec![param(0), param(0)], param(0)),
 
             "overflowing_add" | "overflowing_sub" | "overflowing_mul" =>
-                (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)),
+                (1, vec![param(0), param(0)], param(0)),
             "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" =>
-                (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)),
+                (1, vec![param(0), param(0)], param(0)),
 
             "assume" => (0, vec![tcx.types.bool], tcx.mk_nil()),
             "likely" => (0, vec![tcx.types.bool], tcx.types.bool),
@@ -289,15 +286,17 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
             "discriminant_value" => (1, vec![
                     tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1),
                                                                   ty::BrAnon(0))),
-                                   param(ccx, 0))], tcx.types.u64),
+                                   param(0))], tcx.types.u64),
 
             "try" => {
                 let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8);
-                let fn_ty = tcx.mk_bare_fn(ty::BareFnTy {
-                    unsafety: hir::Unsafety::Normal,
-                    abi: Abi::Rust,
-                    sig: ty::Binder(tcx.mk_fn_sig(iter::once(mut_u8), tcx.mk_nil(), false)),
-                });
+                let fn_ty = ty::Binder(tcx.mk_fn_sig(
+                    iter::once(mut_u8),
+                    tcx.mk_nil(),
+                    false,
+                    hir::Unsafety::Normal,
+                    Abi::Rust,
+                ));
                 (0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32)
             }
 
@@ -312,18 +311,17 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
         };
         (n_tps, inputs, output)
     };
-    equate_intrinsic_type(ccx, it, n_tps, Abi::RustIntrinsic, inputs, output)
+    equate_intrinsic_type(tcx, it, n_tps, Abi::RustIntrinsic, inputs, output)
 }
 
 /// Type-check `extern "platform-intrinsic" { ... }` functions.
-pub fn check_platform_intrinsic_type(ccx: &CrateCtxt,
-                                     it: &hir::ForeignItem) {
+pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                               it: &hir::ForeignItem) {
     let param = |n| {
         let name = Symbol::intern(&format!("P{}", n));
-        ccx.tcx.mk_param(n, name)
+        tcx.mk_param(n, name)
     };
 
-    let tcx = ccx.tcx;
     let def_id = tcx.hir.local_def_id(it.id);
     let i_n_tps = tcx.item_generics(def_id).types.len();
     let name = it.name.as_str();
@@ -369,7 +367,7 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt,
                     let mut structural_to_nomimal = FxHashMap();
 
                     let sig = tcx.item_type(def_id).fn_sig();
-                    let sig = tcx.no_late_bound_regions(sig).unwrap();
+                    let sig = tcx.no_late_bound_regions(&sig).unwrap();
                     if intr.inputs.len() != sig.inputs().len() {
                         span_err!(tcx.sess, it.span, E0444,
                                   "platform-specific intrinsic has invalid number of \
@@ -379,10 +377,10 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt,
                     }
                     let input_pairs = intr.inputs.iter().zip(sig.inputs());
                     for (i, (expected_arg, arg)) in input_pairs.enumerate() {
-                        match_intrinsic_type_to_type(ccx, &format!("argument {}", i + 1), it.span,
+                        match_intrinsic_type_to_type(tcx, &format!("argument {}", i + 1), it.span,
                                                      &mut structural_to_nomimal, expected_arg, arg);
                     }
-                    match_intrinsic_type_to_type(ccx, "return value", it.span,
+                    match_intrinsic_type_to_type(tcx, "return value", it.span,
                                                  &mut structural_to_nomimal,
                                                  &intr.output, sig.output());
                     return
@@ -396,15 +394,15 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt,
         }
     };
 
-    equate_intrinsic_type(ccx, it, n_tps, Abi::PlatformIntrinsic,
+    equate_intrinsic_type(tcx, it, n_tps, Abi::PlatformIntrinsic,
                           inputs, output)
 }
 
 // walk the expected type and the actual type in lock step, checking they're
 // the same, in a kinda-structural way, i.e. `Vector`s have to be simd structs with
 // exactly the right element type
-fn match_intrinsic_type_to_type<'tcx, 'a>(
-        ccx: &CrateCtxt<'a, 'tcx>,
+fn match_intrinsic_type_to_type<'a, 'tcx>(
+        tcx: TyCtxt<'a, 'tcx, 'tcx>,
         position: &str,
         span: Span,
         structural_to_nominal: &mut FxHashMap<&'a intrinsics::Type, ty::Ty<'tcx>>,
@@ -413,7 +411,7 @@ fn match_intrinsic_type_to_type<'tcx, 'a>(
     use intrinsics::Type::*;
 
     let simple_error = |real: &str, expected: &str| {
-        span_err!(ccx.tcx.sess, span, E0442,
+        span_err!(tcx.sess, span, E0442,
                   "intrinsic {} has wrong type: found {}, expected {}",
                   position, real, expected)
     };
@@ -453,7 +451,7 @@ fn match_intrinsic_type_to_type<'tcx, 'a>(
                         simple_error(&format!("`{}`", t),
                                      if const_ {"const pointer"} else {"mut pointer"})
                     }
-                    match_intrinsic_type_to_type(ccx, position, span, structural_to_nominal,
+                    match_intrinsic_type_to_type(tcx, position, span, structural_to_nominal,
                                                  inner_expected, ty)
                 }
                 _ => simple_error(&format!("`{}`", t), "raw pointer"),
@@ -464,19 +462,19 @@ fn match_intrinsic_type_to_type<'tcx, 'a>(
                 simple_error(&format!("non-simd type `{}`", t), "simd type");
                 return;
             }
-            let t_len = t.simd_size(ccx.tcx);
+            let t_len = t.simd_size(tcx);
             if len as usize != t_len {
                 simple_error(&format!("vector with length {}", t_len),
                              &format!("length {}", len));
                 return;
             }
-            let t_ty = t.simd_type(ccx.tcx);
+            let t_ty = t.simd_type(tcx);
             {
                 // check that a given structural type always has the same an intrinsic definition
                 let previous = structural_to_nominal.entry(expected).or_insert(t);
                 if *previous != t {
                     // this gets its own error code because it is non-trivial
-                    span_err!(ccx.tcx.sess, span, E0443,
+                    span_err!(tcx.sess, span, E0443,
                               "intrinsic {} has wrong type: found `{}`, expected `{}` which \
                                was used for this vector type previously in this signature",
                               position,
@@ -485,7 +483,7 @@ fn match_intrinsic_type_to_type<'tcx, 'a>(
                     return;
                 }
             }
-            match_intrinsic_type_to_type(ccx,
+            match_intrinsic_type_to_type(tcx,
                                          position,
                                          span,
                                          structural_to_nominal,
@@ -501,7 +499,7 @@ fn match_intrinsic_type_to_type<'tcx, 'a>(
                         return
                     }
                     for (e, c) in expected_contents.iter().zip(contents) {
-                        match_intrinsic_type_to_type(ccx, position, span, structural_to_nominal,
+                        match_intrinsic_type_to_type(tcx, position, span, structural_to_nominal,
                                                      e, c)
                     }
                 }
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 2d90394025d..e6e4b577bd5 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -365,10 +365,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
 
         debug!("method_predicates after subst = {:?}", method_predicates);
 
-        let fty = match self.tcx.item_type(def_id).sty {
-            ty::TyFnDef(_, _, f) => f,
-            _ => bug!()
-        };
+        let sig = self.tcx.item_type(def_id).fn_sig();
 
         // Instantiate late-bound regions and substitute the trait
         // parameters into the method type to get the actual method type.
@@ -376,21 +373,15 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         // NB: Instantiate late-bound regions first so that
         // `instantiate_type_scheme` can normalize associated types that
         // may reference those regions.
-        let method_sig = self.replace_late_bound_regions_with_fresh_var(&fty.sig);
+        let method_sig = self.replace_late_bound_regions_with_fresh_var(&sig);
         debug!("late-bound lifetimes from method instantiated, method_sig={:?}",
                method_sig);
 
         let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig);
         debug!("type scheme substituted, method_sig={:?}", method_sig);
 
-        let method_ty = self.tcx.mk_fn_def(def_id, all_substs,
-                                           self.tcx.mk_bare_fn(ty::BareFnTy {
-            sig: ty::Binder(method_sig),
-            unsafety: fty.unsafety,
-            abi: fty.abi,
-        }));
-
-        (method_ty, method_predicates)
+        (self.tcx.mk_fn_def(def_id, all_substs, ty::Binder(method_sig)),
+         method_predicates)
     }
 
     fn add_obligations(&mut self,
@@ -566,7 +557,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         // Disallow calls to the method `drop` defined in the `Drop` trait.
         match pick.item.container {
             ty::TraitContainer(trait_def_id) => {
-                callee::check_legal_trait_for_method_call(self.ccx, self.span, trait_def_id)
+                callee::check_legal_trait_for_method_call(self.tcx, self.span, trait_def_id)
             }
             ty::ImplContainer(..) => {}
         }
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index eae8989bd34..4085a171bbe 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -139,7 +139,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         if let Some(import_id) = pick.import_id {
             let import_def_id = self.tcx.hir.local_def_id(import_id);
             debug!("used_trait_import: {:?}", import_def_id);
-            self.used_trait_imports.borrow_mut().insert(import_def_id);
+            self.tables.borrow_mut().used_trait_imports.insert(import_def_id);
         }
 
         self.tcx.check_stability(pick.item.def_id, call_expr.id, span);
@@ -244,21 +244,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // `instantiate_type_scheme` can normalize associated types that
         // may reference those regions.
         let original_method_ty = tcx.item_type(def_id);
-        let fty = match original_method_ty.sty {
-            ty::TyFnDef(_, _, f) => f,
-            _ => bug!()
-        };
+        let fn_sig = original_method_ty.fn_sig();
         let fn_sig = self.replace_late_bound_regions_with_fresh_var(span,
                                                                     infer::FnCall,
-                                                                    &fty.sig).0;
+                                                                    &fn_sig).0;
         let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig);
         let transformed_self_ty = fn_sig.inputs()[0];
         let method_ty = tcx.mk_fn_def(def_id, trait_ref.substs,
-                                      tcx.mk_bare_fn(ty::BareFnTy {
-            sig: ty::Binder(fn_sig),
-            unsafety: fty.unsafety,
-            abi: fty.abi
-        }));
+                                     ty::Binder(fn_sig));
 
         debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
                method_ty,
@@ -340,7 +333,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         if let Some(import_id) = pick.import_id {
             let import_def_id = self.tcx.hir.local_def_id(import_id);
             debug!("used_trait_import: {:?}", import_def_id);
-            self.used_trait_imports.borrow_mut().insert(import_def_id);
+            self.tables.borrow_mut().used_trait_imports.insert(import_def_id);
         }
 
         let def = pick.item.def();
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index fd29ff0be43..dfa7ababca0 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -481,9 +481,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) {
         // Read the inherent implementation candidates for this type from the
         // metadata if necessary.
-        self.tcx.populate_inherent_implementations_for_type_if_necessary(def_id);
+        self.tcx.populate_inherent_implementations_for_type_if_necessary(self.span, def_id);
 
-        if let Some(impl_infos) = self.tcx.inherent_impls.borrow().get(&def_id) {
+        if let Some(impl_infos) = self.tcx.maps.inherent_impls.borrow().get(&def_id) {
             for &impl_def_id in impl_infos.iter() {
                 self.assemble_inherent_impl_probe(impl_def_id);
             }
@@ -653,7 +653,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
     fn assemble_extension_candidates_for_all_traits(&mut self) -> Result<(), MethodError<'tcx>> {
         let mut duplicates = FxHashSet();
-        for trait_info in suggest::all_traits(self.ccx) {
+        for trait_info in suggest::all_traits(self.tcx) {
             if duplicates.insert(trait_info.def_id) {
                 self.assemble_extension_candidates_for_trait(None, trait_info.def_id)?;
             }
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index f6345e6e262..6ce50d91124 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -11,11 +11,9 @@
 //! Give useful errors and suggestions to users when an item can't be
 //! found or is otherwise invalid.
 
-use CrateCtxt;
-
 use check::FnCtxt;
 use rustc::hir::map as hir_map;
-use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable};
+use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable};
 use hir::def::Def;
 use hir::def_id::{CRATE_DEF_INDEX, DefId};
 use middle::lang_items::FnOnceTraitLangItem;
@@ -343,7 +341,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // there's no implemented traits, so lets suggest some traits to
         // implement, by finding ones that have the item name, and are
         // legal to implement.
-        let mut candidates = all_traits(self.ccx)
+        let mut candidates = all_traits(self.tcx)
             .filter(|info| {
                 // we approximate the coherence rules to only suggest
                 // traits that are legal to implement by requiring that
@@ -423,7 +421,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
-pub type AllTraitsVec = Vec<TraitInfo>;
+pub type AllTraitsVec = Vec<DefId>;
 
 #[derive(Copy, Clone)]
 pub struct TraitInfo {
@@ -458,8 +456,8 @@ impl Ord for TraitInfo {
 }
 
 /// Retrieve all traits in this crate and any dependent crates.
-pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
-    if ccx.all_traits.borrow().is_none() {
+pub fn all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> AllTraits<'a> {
+    if tcx.all_traits.borrow().is_none() {
         use rustc::hir::itemlikevisit;
 
         let mut traits = vec![];
@@ -476,7 +474,7 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
                 match i.node {
                     hir::ItemTrait(..) => {
                         let def_id = self.map.local_def_id(i.id);
-                        self.traits.push(TraitInfo::new(def_id));
+                        self.traits.push(def_id);
                     }
                     _ => {}
                 }
@@ -488,45 +486,45 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
             fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
             }
         }
-        ccx.tcx.hir.krate().visit_all_item_likes(&mut Visitor {
-            map: &ccx.tcx.hir,
+        tcx.hir.krate().visit_all_item_likes(&mut Visitor {
+            map: &tcx.hir,
             traits: &mut traits,
         });
 
         // Cross-crate:
         let mut external_mods = FxHashSet();
-        fn handle_external_def(ccx: &CrateCtxt,
+        fn handle_external_def(tcx: TyCtxt,
                                traits: &mut AllTraitsVec,
                                external_mods: &mut FxHashSet<DefId>,
                                def: Def) {
             let def_id = def.def_id();
             match def {
                 Def::Trait(..) => {
-                    traits.push(TraitInfo::new(def_id));
+                    traits.push(def_id);
                 }
                 Def::Mod(..) => {
                     if !external_mods.insert(def_id) {
                         return;
                     }
-                    for child in ccx.tcx.sess.cstore.item_children(def_id) {
-                        handle_external_def(ccx, traits, external_mods, child.def)
+                    for child in tcx.sess.cstore.item_children(def_id) {
+                        handle_external_def(tcx, traits, external_mods, child.def)
                     }
                 }
                 _ => {}
             }
         }
-        for cnum in ccx.tcx.sess.cstore.crates() {
+        for cnum in tcx.sess.cstore.crates() {
             let def_id = DefId {
                 krate: cnum,
                 index: CRATE_DEF_INDEX,
             };
-            handle_external_def(ccx, &mut traits, &mut external_mods, Def::Mod(def_id));
+            handle_external_def(tcx, &mut traits, &mut external_mods, Def::Mod(def_id));
         }
 
-        *ccx.all_traits.borrow_mut() = Some(traits);
+        *tcx.all_traits.borrow_mut() = Some(traits);
     }
 
-    let borrow = ccx.all_traits.borrow();
+    let borrow = tcx.all_traits.borrow();
     assert!(borrow.is_some());
     AllTraits {
         borrow: borrow,
@@ -547,7 +545,7 @@ impl<'a> Iterator for AllTraits<'a> {
         // ugh.
         borrow.as_ref().unwrap().get(*idx).map(|info| {
             *idx += 1;
-            *info
+            TraitInfo::new(*info)
         })
     }
 }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 9d963226caf..0337727dcba 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -56,7 +56,7 @@ stored in `fcx.node_types` and `fcx.item_substs`.  These types
 may contain unresolved type variables.  After type checking is
 complete, the functions in the writeback module are used to take the
 types from this table, resolve them, and then write them into their
-permanent home in the type context `ccx.tcx`.
+permanent home in the type context `tcx`.
 
 This means that during inferencing you should use `fcx.write_ty()`
 and `fcx.expr_ty()` / `fcx.node_ty()` to write/obtain the types of
@@ -91,18 +91,18 @@ use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 use rustc::ty::{ParamTy, ParameterEnvironment};
 use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
-use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, Visibility};
+use rustc::ty::{self, Ty, TyCtxt, Visibility};
 use rustc::ty::{MethodCall, MethodCallee};
 use rustc::ty::adjustment;
 use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
+use rustc::ty::maps::Providers;
 use rustc::ty::util::{Representability, IntTypeExt};
 use require_c_abi_if_variadic;
 use session::{Session, CompileResult};
-use CrateCtxt;
 use TypeAndSubsts;
 use lint;
 use util::common::{ErrorReported, indenter};
-use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, FxHashSet, NodeMap};
+use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap};
 
 use std::cell::{Cell, RefCell};
 use std::cmp;
@@ -110,7 +110,6 @@ use std::mem::replace;
 use std::ops::{self, Deref};
 use syntax::abi::Abi;
 use syntax::ast;
-use syntax::attr;
 use syntax::codemap::{self, original_sp, Spanned};
 use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax::ptr::P;
@@ -124,6 +123,7 @@ use rustc::hir::{self, PatKind};
 use rustc::middle::lang_items;
 use rustc_back::slice;
 use rustc_const_eval::eval_length;
+use rustc_const_math::ConstInt;
 
 mod assoc;
 mod autoderef;
@@ -153,8 +153,8 @@ mod op;
 /// `bar()` will each have their own `FnCtxt`, but they will
 /// share the inherited fields.
 pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    ccx: &'a CrateCtxt<'a, 'gcx>,
     infcx: InferCtxt<'a, 'gcx, 'tcx>,
+
     locals: RefCell<NodeMap<Ty<'tcx>>>,
 
     fulfillment_cx: RefCell<traits::FulfillmentContext<'tcx>>,
@@ -174,16 +174,7 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     // associated fresh inference variable. Writeback resolves these
     // variables to get the concrete type, which can be used to
     // deanonymize TyAnon, after typeck is done with all functions.
-    anon_types: RefCell<DefIdMap<Ty<'tcx>>>,
-
-    // Obligations which will have to be checked at the end of
-    // type-checking, after all functions have been inferred.
-    deferred_obligations: RefCell<Vec<traits::DeferredObligation<'tcx>>>,
-
-    // a set of trait import def-ids that we use during method
-    // resolution; during writeback, this is written into
-    // `tcx.used_trait_imports` for this item def-id
-    used_trait_imports: RefCell<FxHashSet<DefId>>,
+    anon_types: RefCell<NodeMap<Ty<'tcx>>>,
 }
 
 impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
@@ -425,15 +416,12 @@ pub struct EnclosingLoops<'gcx, 'tcx> {
 }
 
 impl<'gcx, 'tcx> EnclosingLoops<'gcx, 'tcx> {
-    fn find_loop(&mut self, id: Option<ast::NodeId>) -> Option<&mut LoopCtxt<'gcx, 'tcx>> {
-        if let Some(id) = id {
-            if let Some(ix) = self.by_id.get(&id).cloned() {
-                Some(&mut self.stack[ix])
-            } else {
-                None
-            }
+    fn find_loop(&mut self, id: hir::LoopIdResult) -> Option<&mut LoopCtxt<'gcx, 'tcx>> {
+        let id_res: Result<_,_> = id.into();
+        if let Some(ix) = id_res.ok().and_then(|id| self.by_id.get(&id).cloned()) {
+            Some(&mut self.stack[ix])
         } else {
-            self.stack.last_mut()
+            None
         }
     }
 }
@@ -444,10 +432,6 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 
     body_id: ast::NodeId,
 
-    // This flag is set to true if, during the writeback phase, we encounter
-    // a type error in this function.
-    writeback_errors: Cell<bool>,
-
     // Number of errors that had been reported when we started
     // checking this function. On exit, if we find that *more* errors
     // have been reported, we will skip regionck and other work that
@@ -476,22 +460,20 @@ impl<'a, 'gcx, 'tcx> Deref for FnCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
-/// Helper type of a temporary returned by ccx.inherited(...).
+/// Helper type of a temporary returned by Inherited::build(...).
 /// Necessary because we can't write the following bound:
 /// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(Inherited<'b, 'gcx, 'tcx>).
 pub struct InheritedBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    ccx: &'a CrateCtxt<'a, 'gcx>,
     infcx: infer::InferCtxtBuilder<'a, 'gcx, 'tcx>
 }
 
-impl<'a, 'gcx, 'tcx> CrateCtxt<'a, 'gcx> {
-    pub fn inherited(&'a self, id: ast::NodeId)
-                     -> InheritedBuilder<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
+    pub fn build(tcx: TyCtxt<'a, 'gcx, 'gcx>, id: ast::NodeId)
+                 -> InheritedBuilder<'a, 'gcx, 'tcx> {
         let tables = ty::TypeckTables::empty();
-        let param_env = ParameterEnvironment::for_item(self.tcx, id);
+        let param_env = ParameterEnvironment::for_item(tcx, id);
         InheritedBuilder {
-            ccx: self,
-            infcx: self.tcx.infer_ctxt((tables, param_env), Reveal::NotSpecializable)
+            infcx: tcx.infer_ctxt((tables, param_env), Reveal::UserFacing)
         }
     }
 }
@@ -500,25 +482,19 @@ impl<'a, 'gcx, 'tcx> InheritedBuilder<'a, 'gcx, 'tcx> {
     fn enter<F, R>(&'tcx mut self, f: F) -> R
         where F: for<'b> FnOnce(Inherited<'b, 'gcx, 'tcx>) -> R
     {
-        let ccx = self.ccx;
-        self.infcx.enter(|infcx| f(Inherited::new(ccx, infcx)))
+        self.infcx.enter(|infcx| f(Inherited::new(infcx)))
     }
 }
 
 impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
-    pub fn new(ccx: &'a CrateCtxt<'a, 'gcx>,
-               infcx: InferCtxt<'a, 'gcx, 'tcx>)
-               -> Self {
+    pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self {
         Inherited {
-            ccx: ccx,
             infcx: infcx,
             fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
             locals: RefCell::new(NodeMap()),
             deferred_call_resolutions: RefCell::new(DefIdMap()),
             deferred_cast_checks: RefCell::new(Vec::new()),
-            anon_types: RefCell::new(DefIdMap()),
-            deferred_obligations: RefCell::new(Vec::new()),
-            used_trait_imports: RefCell::new(DefIdSet()),
+            anon_types: RefCell::new(NodeMap()),
         }
     }
 
@@ -538,23 +514,23 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
 
 }
 
-struct CheckItemTypesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
-struct CheckItemBodiesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
+struct CheckItemTypesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
+struct CheckItemBodiesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
 
 impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.ccx.tcx.hir)
+        NestedVisitorMap::OnlyBodies(&self.tcx.hir)
     }
 
     fn visit_item(&mut self, i: &'tcx hir::Item) {
-        check_item_type(self.ccx, i);
+        check_item_type(self.tcx, i);
         intravisit::walk_item(self, i);
     }
 
     fn visit_ty(&mut self, t: &'tcx hir::Ty) {
         match t.node {
             hir::TyArray(_, length) => {
-                check_const_with_type(self.ccx, length, self.ccx.tcx.types.usize, length.node_id);
+                self.tcx.item_tables(self.tcx.hir.local_def_id(length.node_id));
             }
             _ => {}
         }
@@ -565,7 +541,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, e: &'tcx hir::Expr) {
         match e.node {
             hir::ExprRepeat(_, count) => {
-                check_const_with_type(self.ccx, count, self.ccx.tcx.types.usize, count.node_id);
+                self.tcx.item_tables(self.tcx.hir.local_def_id(count.node_id));
             }
             _ => {}
         }
@@ -577,8 +553,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
 impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         match item.node {
-            hir::ItemFn(ref decl, .., body_id) => {
-                check_bare_fn(self.ccx, &decl, body_id, item.id, item.span);
+            hir::ItemFn(..) => {
+                self.tcx.item_tables(self.tcx.hir.local_def_id(item.id));
             }
             _ => { }
         }
@@ -586,11 +562,9 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
         match trait_item.node {
-            hir::TraitItemKind::Const(_, Some(expr)) => {
-                check_const(self.ccx, expr, trait_item.id)
-            }
-            hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body_id)) => {
-                check_bare_fn(self.ccx, &sig.decl, body_id, trait_item.id, trait_item.span);
+            hir::TraitItemKind::Const(_, Some(_)) |
+            hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => {
+                self.tcx.item_tables(self.tcx.hir.local_def_id(trait_item.id));
             }
             hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
             hir::TraitItemKind::Const(_, None) |
@@ -602,11 +576,9 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
         match impl_item.node {
-            hir::ImplItemKind::Const(_, expr) => {
-                check_const(self.ccx, expr, impl_item.id)
-            }
-            hir::ImplItemKind::Method(ref sig, body_id) => {
-                check_bare_fn(self.ccx, &sig.decl, body_id, impl_item.id, impl_item.span);
+            hir::ImplItemKind::Const(..) |
+            hir::ImplItemKind::Method(..) => {
+                self.tcx.item_tables(self.tcx.hir.local_def_id(impl_item.id));
             }
             hir::ImplItemKind::Type(_) => {
                 // Nothing to do here.
@@ -615,61 +587,41 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
     }
 }
 
-pub fn check_wf_new(ccx: &CrateCtxt) -> CompileResult {
-    ccx.tcx.sess.track_errors(|| {
-        let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(ccx);
-        ccx.tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut visit.as_deep_visitor());
+pub fn check_wf_new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
+    tcx.sess.track_errors(|| {
+        let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx);
+        tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut visit.as_deep_visitor());
     })
 }
 
-pub fn check_item_types(ccx: &CrateCtxt) -> CompileResult {
-    ccx.tcx.sess.track_errors(|| {
-        let mut visit = CheckItemTypesVisitor { ccx: ccx };
-        ccx.tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemType,
+pub fn check_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
+    tcx.sess.track_errors(|| {
+        let mut visit = CheckItemTypesVisitor { tcx: tcx };
+        tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemType,
                                               &mut visit.as_deep_visitor());
     })
 }
 
-pub fn check_item_bodies(ccx: &CrateCtxt) -> CompileResult {
-    ccx.tcx.sess.track_errors(|| {
-        let mut visit = CheckItemBodiesVisitor { ccx: ccx };
-        ccx.tcx.visit_all_item_likes_in_krate(DepNode::TypeckTables, &mut visit);
-
-        // Process deferred obligations, now that all functions
-        // bodies have been fully inferred.
-        for (&item_id, obligations) in ccx.deferred_obligations.borrow().iter() {
-            // Use the same DepNode as for the body of the original function/item.
-            let def_id = ccx.tcx.hir.local_def_id(item_id);
-            let _task = ccx.tcx.dep_graph.in_task(DepNode::TypeckTables(def_id));
-
-            let param_env = ParameterEnvironment::for_item(ccx.tcx, item_id);
-            ccx.tcx.infer_ctxt(param_env, Reveal::NotSpecializable).enter(|infcx| {
-                let mut fulfillment_cx = traits::FulfillmentContext::new();
-                for obligation in obligations.iter().map(|o| o.to_obligation()) {
-                    fulfillment_cx.register_predicate_obligation(&infcx, obligation);
-                }
-
-                if let Err(errors) = fulfillment_cx.select_all_or_error(&infcx) {
-                    infcx.report_fulfillment_errors(&errors);
-                }
-            });
-        }
+pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
+    tcx.sess.track_errors(|| {
+        let mut visit = CheckItemBodiesVisitor { tcx: tcx };
+        tcx.visit_all_item_likes_in_krate(DepNode::TypeckTables, &mut visit);
     })
 }
 
-pub fn check_drop_impls(ccx: &CrateCtxt) -> CompileResult {
-    ccx.tcx.sess.track_errors(|| {
-        let _task = ccx.tcx.dep_graph.in_task(DepNode::Dropck);
-        let drop_trait = match ccx.tcx.lang_items.drop_trait() {
-            Some(id) => ccx.tcx.lookup_trait_def(id), None => { return }
+pub fn check_drop_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
+    tcx.sess.track_errors(|| {
+        let _task = tcx.dep_graph.in_task(DepNode::Dropck);
+        let drop_trait = match tcx.lang_items.drop_trait() {
+            Some(id) => tcx.lookup_trait_def(id), None => { return }
         };
-        drop_trait.for_each_impl(ccx.tcx, |drop_impl_did| {
-            let _task = ccx.tcx.dep_graph.in_task(DepNode::DropckImpl(drop_impl_did));
+        drop_trait.for_each_impl(tcx, |drop_impl_did| {
+            let _task = tcx.dep_graph.in_task(DepNode::DropckImpl(drop_impl_did));
             if drop_impl_did.is_local() {
-                match dropck::check_drop_impl(ccx, drop_impl_did) {
+                match dropck::check_drop_impl(tcx, drop_impl_did) {
                     Ok(()) => {}
                     Err(()) => {
-                        assert!(ccx.tcx.sess.has_errors());
+                        assert!(tcx.sess.has_errors());
                     }
                 }
             }
@@ -677,47 +629,150 @@ pub fn check_drop_impls(ccx: &CrateCtxt) -> CompileResult {
     })
 }
 
-fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                           decl: &'tcx hir::FnDecl,
-                           body_id: hir::BodyId,
-                           fn_id: ast::NodeId,
-                           span: Span) {
-    let body = ccx.tcx.hir.body(body_id);
-
-    let raw_fty = ccx.tcx.item_type(ccx.tcx.hir.local_def_id(fn_id));
-    let fn_ty = match raw_fty.sty {
-        ty::TyFnDef(.., f) => f,
-        _ => span_bug!(body.value.span, "check_bare_fn: function type expected")
+pub fn provide(providers: &mut Providers) {
+    *providers = Providers {
+        typeck_tables,
+        closure_type,
+        closure_kind,
+        ..*providers
     };
+}
 
-    check_abi(ccx, span, fn_ty.abi);
+fn closure_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          def_id: DefId)
+                          -> ty::PolyFnSig<'tcx> {
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    tcx.item_tables(def_id).closure_tys[&node_id]
+}
 
-    ccx.inherited(fn_id).enter(|inh| {
-        // Compute the fty from point of view of inside fn.
-        let fn_scope = inh.tcx.region_maps.call_site_extent(fn_id, body_id.node_id);
-        let fn_sig =
-            fn_ty.sig.subst(inh.tcx, &inh.parameter_environment.free_substs);
-        let fn_sig =
-            inh.tcx.liberate_late_bound_regions(fn_scope, &fn_sig);
-        let fn_sig =
-            inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
+fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          def_id: DefId)
+                          -> ty::ClosureKind {
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    tcx.item_tables(def_id).closure_kinds[&node_id]
+}
+
+fn typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                           def_id: DefId)
+                           -> &'tcx ty::TypeckTables<'tcx> {
+    // Closures' tables come from their outermost function,
+    // as they are part of the same "inference environment".
+    let outer_def_id = tcx.closure_base_def_id(def_id);
+    if outer_def_id != def_id {
+        return tcx.item_tables(outer_def_id);
+    }
+
+    let id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let span = tcx.hir.span(id);
+    let unsupported = || {
+        span_bug!(span, "can't type-check body of {:?}", def_id);
+    };
 
-        let fcx = check_fn(&inh, fn_ty.unsafety, fn_id, &fn_sig, decl, fn_id, body);
+    // Figure out what primary body this item has.
+    let mut fn_decl = None;
+    let body_id = match tcx.hir.get(id) {
+        hir::map::NodeItem(item) => {
+            match item.node {
+                hir::ItemConst(_, body) |
+                hir::ItemStatic(_, _, body) => body,
+                hir::ItemFn(ref decl, .., body) => {
+                    fn_decl = Some(decl);
+                    body
+                }
+                _ => unsupported()
+            }
+        }
+        hir::map::NodeTraitItem(item) => {
+            match item.node {
+                hir::TraitItemKind::Const(_, Some(body)) => body,
+                hir::TraitItemKind::Method(ref sig,
+                    hir::TraitMethod::Provided(body)) => {
+                        fn_decl = Some(&sig.decl);
+                        body
+                    }
+                _ => unsupported()
+            }
+        }
+        hir::map::NodeImplItem(item) => {
+            match item.node {
+                hir::ImplItemKind::Const(_, body) => body,
+                hir::ImplItemKind::Method(ref sig, body) => {
+                    fn_decl = Some(&sig.decl);
+                    body
+                }
+                _ => unsupported()
+            }
+        }
+        hir::map::NodeExpr(expr) => {
+            // FIXME(eddyb) Closures should have separate
+            // function definition IDs and expression IDs.
+            // Type-checking should not let closures get
+            // this far in a constant position.
+            // Assume that everything other than closures
+            // is a constant "initializer" expression.
+            match expr.node {
+                hir::ExprClosure(..) => {
+                    // We should've bailed out above for closures.
+                    span_bug!(expr.span, "unexpected closure")
+                }
+                _ => hir::BodyId { node_id: expr.id }
+            }
+        }
+        _ => unsupported()
+    };
+    let body = tcx.hir.body(body_id);
+
+    Inherited::build(tcx, id).enter(|inh| {
+        let fcx = if let Some(decl) = fn_decl {
+            let fn_sig = tcx.item_type(def_id).fn_sig();
+
+            check_abi(tcx, span, fn_sig.abi());
+
+            // Compute the fty from point of view of inside fn.
+            let fn_scope = inh.tcx.region_maps.call_site_extent(id, body_id.node_id);
+            let fn_sig =
+                fn_sig.subst(inh.tcx, &inh.parameter_environment.free_substs);
+            let fn_sig =
+                inh.tcx.liberate_late_bound_regions(fn_scope, &fn_sig);
+            let fn_sig =
+                inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
+
+            check_fn(&inh, fn_sig, decl, id, body)
+        } else {
+            let expected_type = tcx.item_type(def_id);
+            let fcx = FnCtxt::new(&inh, None, body.value.id);
+            fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
+
+            // Gather locals in statics (because of block expressions).
+            // This is technically unnecessary because locals in static items are forbidden,
+            // but prevents type checking from blowing up before const checking can properly
+            // emit an error.
+            GatherLocalsVisitor { fcx: &fcx }.visit_body(body);
+
+            fcx.check_expr_coercable_to_type(&body.value, expected_type);
+
+            fcx
+        };
 
         fcx.select_all_obligations_and_apply_defaults();
         fcx.closure_analyze(body);
         fcx.select_obligations_where_possible();
         fcx.check_casts();
-        fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
+        fcx.select_all_obligations_or_error();
+
+        if fn_decl.is_some() {
+            fcx.regionck_fn(id, body);
+        } else {
+            fcx.regionck_expr(body);
+        }
 
-        fcx.regionck_fn(fn_id, body);
-        fcx.resolve_type_vars_in_body(body);
-    });
+        fcx.resolve_type_vars_in_body(body)
+    })
 }
 
-fn check_abi<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, abi: Abi) {
-    if !ccx.tcx.sess.target.target.is_abi_supported(abi) {
-        struct_span_err!(ccx.tcx.sess, span, E0570,
+fn check_abi<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, abi: Abi) {
+    if !tcx.sess.target.target.is_abi_supported(abi) {
+        struct_span_err!(tcx.sess, span, E0570,
             "The ABI `{}` is not supported for the current target", abi).emit()
     }
 }
@@ -785,16 +840,14 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
                 _: hir::BodyId, _: Span, _: ast::NodeId) { }
 }
 
-/// Helper used by check_bare_fn and check_expr_fn. Does the grungy work of checking a function
+/// Helper used for fns and closures. Does the grungy work of checking a function
 /// body and returns the function context used for that purpose, since in the case of a fn item
 /// there is still a bit more to do.
 ///
 /// * ...
 /// * inherited: other fields inherited from the enclosing fn (if any)
 fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
-                            unsafety: hir::Unsafety,
-                            unsafety_id: ast::NodeId,
-                            fn_sig: &ty::FnSig<'tcx>,
+                            fn_sig: ty::FnSig<'tcx>,
                             decl: &'gcx hir::FnDecl,
                             fn_id: ast::NodeId,
                             body: &'gcx hir::Body)
@@ -808,12 +861,17 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     // in the case of function expressions, based on the outer context.
     let mut fcx = FnCtxt::new(inherited, None, body.value.id);
     let ret_ty = fn_sig.output();
-    *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);
+    *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id);
 
     fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
     fcx.ret_ty = fcx.instantiate_anon_types(&Some(ret_ty));
-    fn_sig = fcx.tcx.mk_fn_sig(fn_sig.inputs().iter().cloned(), &fcx.ret_ty.unwrap(),
-                               fn_sig.variadic);
+    fn_sig = fcx.tcx.mk_fn_sig(
+        fn_sig.inputs().iter().cloned(),
+        fcx.ret_ty.unwrap(),
+        fn_sig.variadic,
+        fn_sig.unsafety,
+        fn_sig.abi
+    );
 
     GatherLocalsVisitor { fcx: &fcx, }.visit_body(body);
 
@@ -839,30 +897,36 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     fcx
 }
 
-fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
-    let def_id = ccx.tcx.hir.local_def_id(id);
-    check_representable(ccx.tcx, span, def_id);
+fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          id: ast::NodeId,
+                          span: Span) {
+    let def_id = tcx.hir.local_def_id(id);
+    check_representable(tcx, span, def_id);
 
-    if ccx.tcx.lookup_simd(def_id) {
-        check_simd(ccx.tcx, span, def_id);
+    if tcx.lookup_adt_def(def_id).repr.simd {
+        check_simd(tcx, span, def_id);
     }
 }
 
-fn check_union(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
-    check_representable(ccx.tcx, span, ccx.tcx.hir.local_def_id(id));
+fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                         id: ast::NodeId,
+                         span: Span) {
+    check_representable(tcx, span, tcx.hir.local_def_id(id));
 }
 
-pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
+pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) {
     debug!("check_item_type(it.id={}, it.name={})",
            it.id,
-           ccx.tcx.item_path_str(ccx.tcx.hir.local_def_id(it.id)));
+           tcx.item_path_str(tcx.hir.local_def_id(it.id)));
     let _indenter = indenter();
     match it.node {
       // Consts can play a role in type-checking, so they are included here.
-      hir::ItemStatic(.., e) |
-      hir::ItemConst(_, e) => check_const(ccx, e, it.id),
+      hir::ItemStatic(..) |
+      hir::ItemConst(..) => {
+        tcx.item_tables(tcx.hir.local_def_id(it.id));
+      }
       hir::ItemEnum(ref enum_definition, _) => {
-        check_enum_variants(ccx,
+        check_enum_variants(tcx,
                             it.span,
                             &enum_definition.variants,
                             it.id);
@@ -870,48 +934,48 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
       hir::ItemFn(..) => {} // entirely within check_item_body
       hir::ItemImpl(.., ref impl_item_refs) => {
           debug!("ItemImpl {} with id {}", it.name, it.id);
-          let impl_def_id = ccx.tcx.hir.local_def_id(it.id);
-          if let Some(impl_trait_ref) = ccx.tcx.impl_trait_ref(impl_def_id) {
-              check_impl_items_against_trait(ccx,
+          let impl_def_id = tcx.hir.local_def_id(it.id);
+          if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) {
+              check_impl_items_against_trait(tcx,
                                              it.span,
                                              impl_def_id,
                                              impl_trait_ref,
                                              impl_item_refs);
               let trait_def_id = impl_trait_ref.def_id;
-              check_on_unimplemented(ccx, trait_def_id, it);
+              check_on_unimplemented(tcx, trait_def_id, it);
           }
       }
       hir::ItemTrait(..) => {
-        let def_id = ccx.tcx.hir.local_def_id(it.id);
-        check_on_unimplemented(ccx, def_id, it);
+        let def_id = tcx.hir.local_def_id(it.id);
+        check_on_unimplemented(tcx, def_id, it);
       }
       hir::ItemStruct(..) => {
-        check_struct(ccx, it.id, it.span);
+        check_struct(tcx, it.id, it.span);
       }
       hir::ItemUnion(..) => {
-        check_union(ccx, it.id, it.span);
+        check_union(tcx, it.id, it.span);
       }
       hir::ItemTy(_, ref generics) => {
-        let def_id = ccx.tcx.hir.local_def_id(it.id);
-        let pty_ty = ccx.tcx.item_type(def_id);
-        check_bounds_are_used(ccx, generics, pty_ty);
+        let def_id = tcx.hir.local_def_id(it.id);
+        let pty_ty = tcx.item_type(def_id);
+        check_bounds_are_used(tcx, generics, pty_ty);
       }
       hir::ItemForeignMod(ref m) => {
-        check_abi(ccx, it.span, m.abi);
+        check_abi(tcx, it.span, m.abi);
 
         if m.abi == Abi::RustIntrinsic {
             for item in &m.items {
-                intrinsic::check_intrinsic_type(ccx, item);
+                intrinsic::check_intrinsic_type(tcx, item);
             }
         } else if m.abi == Abi::PlatformIntrinsic {
             for item in &m.items {
-                intrinsic::check_platform_intrinsic_type(ccx, item);
+                intrinsic::check_platform_intrinsic_type(tcx, item);
             }
         } else {
             for item in &m.items {
-                let generics = ccx.tcx.item_generics(ccx.tcx.hir.local_def_id(item.id));
+                let generics = tcx.item_generics(tcx.hir.local_def_id(item.id));
                 if !generics.types.is_empty() {
-                    let mut err = struct_span_err!(ccx.tcx.sess, item.span, E0044,
+                    let mut err = struct_span_err!(tcx.sess, item.span, E0044,
                         "foreign items may not have type parameters");
                     span_help!(&mut err, item.span,
                         "consider using specialization instead of \
@@ -920,7 +984,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
                 }
 
                 if let hir::ForeignItemFn(ref fn_decl, _, _) = item.node {
-                    require_c_abi_if_variadic(ccx.tcx, fn_decl, m.abi, item.span);
+                    require_c_abi_if_variadic(tcx, fn_decl, m.abi, item.span);
                 }
             }
         }
@@ -929,10 +993,10 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
     }
 }
 
-fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn check_on_unimplemented<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     def_id: DefId,
                                     item: &hir::Item) {
-    let generics = ccx.tcx.item_generics(def_id);
+    let generics = tcx.item_generics(def_id);
     if let Some(ref attr) = item.attrs.iter().find(|a| {
         a.check_name("rustc_on_unimplemented")
     }) {
@@ -952,8 +1016,8 @@ fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                         }) {
                             Some(_) => (),
                             None => {
-                                let name = ccx.tcx.item_name(def_id);
-                                span_err!(ccx.tcx.sess, attr.span, E0230,
+                                let name = tcx.item_name(def_id);
+                                span_err!(tcx.sess, attr.span, E0230,
                                                  "there is no type parameter \
                                                           {} on trait {}",
                                                            s, name);
@@ -961,7 +1025,7 @@ fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                         },
                         // `{:1}` and `{}` are not to be used
                         Position::ArgumentIs(_) => {
-                            span_err!(ccx.tcx.sess, attr.span, E0231,
+                            span_err!(tcx.sess, attr.span, E0231,
                                                   "only named substitution \
                                                    parameters are allowed");
                         }
@@ -970,7 +1034,7 @@ fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             }
         } else {
             struct_span_err!(
-                ccx.tcx.sess, attr.span, E0232,
+                tcx.sess, attr.span, E0232,
                 "this attribute must have a value")
                 .span_label(attr.span, &format!("attribute requires a value"))
                 .note(&format!("eg `#[rustc_on_unimplemented = \"foo\"]`"))
@@ -1028,7 +1092,7 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
 }
 
-fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                             impl_span: Span,
                                             impl_id: DefId,
                                             impl_trait_ref: ty::TraitRef<'tcx>,
@@ -1039,11 +1103,10 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     if impl_trait_ref.references_error() { return; }
 
     // Locate trait definition and items
-    let tcx = ccx.tcx;
     let trait_def = tcx.lookup_trait_def(impl_trait_ref.def_id);
     let mut overridden_associated_type = None;
 
-    let impl_items = || impl_item_refs.iter().map(|iiref| ccx.tcx.hir.impl_item(iiref.id));
+    let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir.impl_item(iiref.id));
 
     // Check existing impl methods to see if they are both present in trait
     // and compatible with trait signature
@@ -1058,7 +1121,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 hir::ImplItemKind::Const(..) => {
                     // Find associated const definition.
                     if ty_trait_item.kind == ty::AssociatedKind::Const {
-                        compare_const_impl(ccx,
+                        compare_const_impl(tcx,
                                            &ty_impl_item,
                                            impl_item.span,
                                            &ty_trait_item,
@@ -1082,7 +1145,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                     let trait_span = tcx.hir.span_if_local(ty_trait_item.def_id);
                     if ty_trait_item.kind == ty::AssociatedKind::Method {
                         let err_count = tcx.sess.err_count();
-                        compare_impl_method(ccx,
+                        compare_impl_method(tcx,
                                             &ty_impl_item,
                                             impl_item.span,
                                             body_id.node_id,
@@ -1092,7 +1155,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                             true); // start with old-broken-mode
                         if err_count == tcx.sess.err_count() {
                             // old broken mode did not report an error. Try with the new mode.
-                            compare_impl_method(ccx,
+                            compare_impl_method(tcx,
                                                 &ty_impl_item,
                                                 impl_item.span,
                                                 body_id.node_id,
@@ -1204,42 +1267,6 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-/// Checks a constant with a given type.
-fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
-                                   body: hir::BodyId,
-                                   expected_type: Ty<'tcx>,
-                                   id: ast::NodeId) {
-    let body = ccx.tcx.hir.body(body);
-    ccx.inherited(id).enter(|inh| {
-        let fcx = FnCtxt::new(&inh, None, body.value.id);
-        fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
-
-        // Gather locals in statics (because of block expressions).
-        // This is technically unnecessary because locals in static items are forbidden,
-        // but prevents type checking from blowing up before const checking can properly
-        // emit an error.
-        GatherLocalsVisitor { fcx: &fcx }.visit_body(body);
-
-        fcx.check_expr_coercable_to_type(&body.value, expected_type);
-
-        fcx.select_all_obligations_and_apply_defaults();
-        fcx.closure_analyze(body);
-        fcx.select_obligations_where_possible();
-        fcx.check_casts();
-        fcx.select_all_obligations_or_error();
-
-        fcx.regionck_expr(body);
-        fcx.resolve_type_vars_in_body(body);
-    });
-}
-
-fn check_const<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                         body: hir::BodyId,
-                         id: ast::NodeId) {
-    let decl_ty = ccx.tcx.item_type(ccx.tcx.hir.local_def_id(id));
-    check_const_with_type(ccx, body, decl_ty, id);
-}
-
 /// Checks whether a type can be represented in memory. In particular, it
 /// identifies types that contain themselves without indirection through a
 /// pointer, which would mean their size is unbounded.
@@ -1295,64 +1322,59 @@ pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId
 }
 
 #[allow(trivial_numeric_casts)]
-pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                                    sp: Span,
-                                    vs: &'tcx [hir::Variant],
-                                    id: ast::NodeId) {
-    let def_id = ccx.tcx.hir.local_def_id(id);
-    let hint = *ccx.tcx.lookup_repr_hints(def_id).get(0).unwrap_or(&attr::ReprAny);
-
-    if hint != attr::ReprAny && vs.is_empty() {
+pub fn check_enum_variants<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                     sp: Span,
+                                     vs: &'tcx [hir::Variant],
+                                     id: ast::NodeId) {
+    let def_id = tcx.hir.local_def_id(id);
+    let def = tcx.lookup_adt_def(def_id);
+
+    if vs.is_empty() && tcx.has_attr(def_id, "repr") {
         struct_span_err!(
-            ccx.tcx.sess, sp, E0084,
+            tcx.sess, sp, E0084,
             "unsupported representation for zero-variant enum")
             .span_label(sp, &format!("unsupported enum representation"))
             .emit();
     }
 
-    let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx);
-    if repr_type_ty == ccx.tcx.types.i128 || repr_type_ty == ccx.tcx.types.u128 {
-        if !ccx.tcx.sess.features.borrow().i128_type {
-            emit_feature_err(&ccx.tcx.sess.parse_sess,
+    let repr_type_ty = def.repr.discr_type().to_ty(tcx);
+    if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
+        if !tcx.sess.features.borrow().i128_type {
+            emit_feature_err(&tcx.sess.parse_sess,
                              "i128_type", sp, GateIssue::Language, "128-bit type is unstable");
         }
     }
 
     for v in vs {
         if let Some(e) = v.node.disr_expr {
-            check_const_with_type(ccx, e, repr_type_ty, e.node_id);
+            tcx.item_tables(tcx.hir.local_def_id(e.node_id));
         }
     }
 
-    let def_id = ccx.tcx.hir.local_def_id(id);
-
-    let variants = &ccx.tcx.lookup_adt_def(def_id).variants;
-    let mut disr_vals: Vec<ty::Disr> = Vec::new();
-    for (v, variant) in vs.iter().zip(variants.iter()) {
-        let current_disr_val = variant.disr_val;
-
+    let mut disr_vals: Vec<ConstInt> = Vec::new();
+    for (discr, v) in def.discriminants(tcx).zip(vs) {
         // Check for duplicate discriminant values
-        if let Some(i) = disr_vals.iter().position(|&x| x == current_disr_val) {
-            let variant_i_node_id = ccx.tcx.hir.as_local_node_id(variants[i].did).unwrap();
-            let variant_i = ccx.tcx.hir.expect_variant(variant_i_node_id);
+        if let Some(i) = disr_vals.iter().position(|&x| x == discr) {
+            let variant_i_node_id = tcx.hir.as_local_node_id(def.variants[i].did).unwrap();
+            let variant_i = tcx.hir.expect_variant(variant_i_node_id);
             let i_span = match variant_i.node.disr_expr {
-                Some(expr) => ccx.tcx.hir.span(expr.node_id),
-                None => ccx.tcx.hir.span(variant_i_node_id)
+                Some(expr) => tcx.hir.span(expr.node_id),
+                None => tcx.hir.span(variant_i_node_id)
             };
             let span = match v.node.disr_expr {
-                Some(expr) => ccx.tcx.hir.span(expr.node_id),
+                Some(expr) => tcx.hir.span(expr.node_id),
                 None => v.span
             };
-            struct_span_err!(ccx.tcx.sess, span, E0081,
+            struct_span_err!(tcx.sess, span, E0081,
                              "discriminant value `{}` already exists", disr_vals[i])
                 .span_label(i_span, &format!("first use of `{}`", disr_vals[i]))
                 .span_label(span , &format!("enum already has `{}`", disr_vals[i]))
                 .emit();
         }
-        disr_vals.push(current_disr_val);
+        disr_vals.push(discr);
     }
 
-    check_representable(ccx.tcx, sp, def_id);
+    check_representable(tcx, sp, def_id);
 }
 
 impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
@@ -1362,57 +1384,30 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
         &self.ast_ty_to_ty_cache
     }
 
-    fn get_generics(&self, _: Span, id: DefId)
-                    -> Result<&'tcx ty::Generics<'tcx>, ErrorReported>
-    {
-        Ok(self.tcx().item_generics(id))
-    }
-
-    fn get_item_type(&self, _: Span, id: DefId) -> Result<Ty<'tcx>, ErrorReported>
-    {
-        Ok(self.tcx().item_type(id))
-    }
-
-    fn get_trait_def(&self, _: Span, id: DefId)
-                     -> Result<&'tcx ty::TraitDef, ErrorReported>
-    {
-        Ok(self.tcx().lookup_trait_def(id))
-    }
-
-    fn ensure_super_predicates(&self, _: Span, _: DefId) -> Result<(), ErrorReported> {
-        // all super predicates are ensured during collect pass
-        Ok(())
-    }
-
     fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
         Some(&self.parameter_environment.free_substs)
     }
 
-    fn get_type_parameter_bounds(&self,
-                                 _: Span,
-                                 node_id: ast::NodeId)
-                                 -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>
+    fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
+                                 -> ty::GenericPredicates<'tcx>
     {
-        let def = self.tcx.type_parameter_def(node_id);
-        let r = self.parameter_environment
-                                  .caller_bounds
-                                  .iter()
-                                  .filter_map(|predicate| {
-                                      match *predicate {
-                                          ty::Predicate::Trait(ref data) => {
-                                              if data.0.self_ty().is_param(def.index) {
-                                                  Some(data.to_poly_trait_ref())
-                                              } else {
-                                                  None
-                                              }
-                                          }
-                                          _ => {
-                                              None
-                                          }
-                                      }
-                                  })
-                                  .collect();
-        Ok(r)
+        let tcx = self.tcx;
+        let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+        let item_id = tcx.hir.ty_param_owner(node_id);
+        let item_def_id = tcx.hir.local_def_id(item_id);
+        let generics = tcx.item_generics(item_def_id);
+        let index = generics.type_param_to_index[&def_id.index];
+        ty::GenericPredicates {
+            parent: None,
+            predicates: self.parameter_environment.caller_bounds.iter().filter(|predicate| {
+                match **predicate {
+                    ty::Predicate::Trait(ref data) => {
+                        data.0.self_ty().is_param(index)
+                    }
+                    _ => false
+                }
+            }).cloned().collect()
+        }
     }
 
     fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>)
@@ -1429,7 +1424,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn ty_infer_for_def(&self,
-                        ty_param_def: &ty::TypeParameterDef<'tcx>,
+                        ty_param_def: &ty::TypeParameterDef,
                         substs: &[Kind<'tcx>],
                         span: Span) -> Ty<'tcx> {
         self.type_var_for_def(span, ty_param_def, substs)
@@ -1494,7 +1489,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         FnCtxt {
             ast_ty_to_ty_cache: RefCell::new(NodeMap()),
             body_id: body_id,
-            writeback_errors: Cell::new(false),
             err_count_on_creation: inh.tcx.sess.err_count(),
             ret_ty: rty,
             ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal,
@@ -1509,10 +1503,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn param_env(&self) -> &ty::ParameterEnvironment<'gcx> {
-        &self.parameter_environment
-    }
-
     pub fn sess(&self) -> &Session {
         &self.tcx.sess
     }
@@ -1614,6 +1604,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         if ty.references_error() {
             self.has_errors.set(true);
+            self.set_tainted_by_errors();
         }
 
         // FIXME(canndrew): This is_never should probably be an is_uninhabited
@@ -1701,12 +1692,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             if let ty::TyAnon(def_id, substs) = ty.sty {
                 // Use the same type variable if the exact same TyAnon appears more
                 // than once in the return type (e.g. if it's pased to a type alias).
-                if let Some(ty_var) = self.anon_types.borrow().get(&def_id) {
+                let id = self.tcx.hir.as_local_node_id(def_id).unwrap();
+                if let Some(ty_var) = self.anon_types.borrow().get(&id) {
                     return ty_var;
                 }
                 let span = self.tcx.def_span(def_id);
                 let ty_var = self.next_ty_var(TypeVariableOrigin::TypeInference(span));
-                self.anon_types.borrow_mut().insert(def_id, ty_var);
+                self.anon_types.borrow_mut().insert(id, ty_var);
 
                 let item_predicates = self.tcx.item_predicates(def_id);
                 let bounds = item_predicates.instantiate(self.tcx, substs);
@@ -1759,10 +1751,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.write_ty(node_id, self.tcx.mk_nil());
     }
 
-    pub fn write_never(&self, node_id: ast::NodeId) {
-        self.write_ty(node_id, self.tcx.types.never);
-    }
-
     pub fn write_error(&self, node_id: ast::NodeId) {
         self.write_ty(node_id, self.tcx.types.err);
     }
@@ -2245,11 +2233,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
 
-        // Steal the deferred obligations before the fulfillment
-        // context can turn all of them into errors.
-        let obligations = fulfillment_cx.take_deferred_obligations();
-        self.deferred_obligations.borrow_mut().extend(obligations);
-
         match fulfillment_cx.select_all_or_error(self) {
             Ok(()) => { }
             Err(errors) => { self.report_fulfillment_errors(&errors); }
@@ -2423,13 +2406,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     let expected_arg_tys = self.expected_types_for_fn_args(
                         sp,
                         expected,
-                        fty.sig.0.output(),
-                        &fty.sig.0.inputs()[1..]
+                        fty.0.output(),
+                        &fty.0.inputs()[1..]
                     );
-                    self.check_argument_types(sp, &fty.sig.0.inputs()[1..], &expected_arg_tys[..],
-                                              args_no_rcvr, fty.sig.0.variadic, tuple_arguments,
+                    self.check_argument_types(sp, &fty.0.inputs()[1..], &expected_arg_tys[..],
+                                              args_no_rcvr, fty.0.variadic, tuple_arguments,
                                               self.tcx.hir.span_if_local(def_id));
-                    fty.sig.0.output()
+                    fty.0.output()
                 }
                 _ => {
                     span_bug!(callee_expr.span, "method without bare fn type");
@@ -3596,10 +3579,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               tcx.mk_nil()
           }
           hir::ExprBreak(label, ref expr_opt) => {
-            let loop_id = label.map(|l| l.loop_id);
             let coerce_to = {
                 let mut enclosing_loops = self.enclosing_loops.borrow_mut();
-                enclosing_loops.find_loop(loop_id).map(|ctxt| ctxt.coerce_to)
+                enclosing_loops.find_loop(label.loop_id).map(|ctxt| ctxt.coerce_to)
             };
             if let Some(coerce_to) = coerce_to {
                 let e_ty;
@@ -3614,8 +3596,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     e_ty = tcx.mk_nil();
                     cause = self.misc(expr.span);
                 }
+
                 let mut enclosing_loops = self.enclosing_loops.borrow_mut();
-                let ctxt = enclosing_loops.find_loop(loop_id).unwrap();
+                let ctxt = enclosing_loops.find_loop(label.loop_id).unwrap();
 
                 let result = if let Some(ref e) = *expr_opt {
                     // Special-case the first element, as it has no "previous expressions".
@@ -4308,7 +4291,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 let container = self.tcx.associated_item(def_id).container;
                 match container {
                     ty::TraitContainer(trait_did) => {
-                        callee::check_legal_trait_for_method_call(self.ccx, span, trait_did)
+                        callee::check_legal_trait_for_method_call(self.tcx, span, trait_did)
                     }
                     ty::ImplContainer(_) => {}
                 }
@@ -4339,7 +4322,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // errors if type parameters are provided in an inappropriate place.
         let poly_segments = type_segment.is_some() as usize +
                             fn_segment.is_some() as usize;
-        self.tcx.prohibit_type_params(&segments[..segments.len() - poly_segments]);
+        AstConv::prohibit_type_params(self, &segments[..segments.len() - poly_segments]);
 
         match def {
             Def::Local(def_id) | Def::Upvar(def_id, ..) => {
@@ -4426,8 +4409,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             if let Some(ast_ty) = types.get(i) {
                 // A provided type parameter.
                 self.to_ty(ast_ty)
-            } else if let (false, Some(default)) = (infer_types, def.default) {
+            } else if !infer_types && def.has_default {
                 // No type parameter provided, but a default exists.
+                let default = self.tcx.item_type(def.def_id);
                 default.subst_spanned(self.tcx, substs, Some(span))
             } else {
                 // No type parameters were provided, we can infer all.
@@ -4540,9 +4524,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 &generics.types
             }
         });
-        let required_len = type_defs.iter()
-                                    .take_while(|d| d.default.is_none())
-                                    .count();
+        let required_len = type_defs.iter().take_while(|d| !d.has_default).count();
         if types.len() > type_defs.len() {
             let span = types[type_defs.len()].span;
             let expected_text = count_type_params(type_defs.len());
@@ -4630,7 +4612,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
-pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                        generics: &hir::Generics,
                                        ty: Ty<'tcx>) {
     debug!("check_bounds_are_used(n_tps={}, ty={:?})",
@@ -4649,7 +4631,7 @@ pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     for (&used, param) in tps_used.iter().zip(&generics.ty_params) {
         if !used {
-            struct_span_err!(ccx.tcx.sess, param.span, E0091,
+            struct_span_err!(tcx.sess, param.span, E0091,
                 "type parameter `{}` is unused",
                 param.name)
                 .span_label(param.span, &format!("unused type parameter"))
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index d84e9d3fd37..e1067d299fa 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -102,8 +102,6 @@ use syntax_pos::Span;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::{self, PatKind};
 
-use self::SubjectNode::Subject;
-
 // a variation on try that just returns unit
 macro_rules! ignore_err {
     ($e:expr) => (match $e { Ok(e) => e, Err(_) => return () })
@@ -183,7 +181,7 @@ pub struct RegionCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     repeating_scope: ast::NodeId,
 
     // id of AST node being analyzed (the subject of the analysis).
-    subject: SubjectNode,
+    subject: ast::NodeId,
 
 }
 
@@ -195,14 +193,13 @@ impl<'a, 'gcx, 'tcx> Deref for RegionCtxt<'a, 'gcx, 'tcx> {
 }
 
 pub struct RepeatingScope(ast::NodeId);
-pub enum SubjectNode { Subject(ast::NodeId), None }
+pub struct Subject(ast::NodeId);
 
 impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     pub fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
-               initial_repeating_scope: RepeatingScope,
+               RepeatingScope(initial_repeating_scope): RepeatingScope,
                initial_body_id: ast::NodeId,
-               subject: SubjectNode) -> RegionCtxt<'a, 'gcx, 'tcx> {
-        let RepeatingScope(initial_repeating_scope) = initial_repeating_scope;
+               Subject(subject): Subject) -> RegionCtxt<'a, 'gcx, 'tcx> {
         RegionCtxt {
             fcx: fcx,
             repeating_scope: initial_repeating_scope,
@@ -416,13 +413,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn resolve_regions_and_report_errors(&self) {
-        let subject_node_id = match self.subject {
-            Subject(s) => s,
-            SubjectNode::None => {
-                bug!("cannot resolve_regions_and_report_errors \
-                      without subject node");
-            }
-        };
+        let subject_node_id = self.subject;
 
         self.fcx.resolve_regions_and_report_errors(&self.free_region_map,
                                                    subject_node_id);
@@ -936,7 +927,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                     // was applied on the base type, as that is always the case.
                     let fn_sig = method.ty.fn_sig();
                     let fn_sig = // late-bound regions should have been instantiated
-                        self.tcx.no_late_bound_regions(fn_sig).unwrap();
+                        self.tcx.no_late_bound_regions(&fn_sig).unwrap();
                     let self_ty = fn_sig.inputs()[0];
                     let (m, r) = match self_ty.sty {
                         ty::TyRef(r, ref m) => (m.mutbl, r),
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index c2f64b1bd79..7b146842671 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -208,9 +208,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
 
         // If we are also inferred the closure kind here, update the
         // main table and process any deferred resolutions.
-        let closure_def_id = self.fcx.tcx.hir.local_def_id(id);
         if let Some(&kind) = self.temp_closure_kinds.get(&id) {
             self.fcx.tables.borrow_mut().closure_kinds.insert(id, kind);
+            let closure_def_id = self.fcx.tcx.hir.local_def_id(id);
             debug!("closure_kind({:?}) = {:?}", closure_def_id, kind);
 
             let mut deferred_call_resolutions =
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index cef6a75e58d..a4cb4071b4d 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -9,9 +9,8 @@
 // except according to those terms.
 
 use astconv::ExplicitSelf;
-use check::FnCtxt;
+use check::{Inherited, FnCtxt};
 use constrained_type_params::{identify_constrained_type_params, Parameter};
-use CrateCtxt;
 
 use hir::def_id::DefId;
 use middle::region::{CodeExtent};
@@ -27,8 +26,8 @@ use errors::DiagnosticBuilder;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir;
 
-pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> {
-    ccx: &'ccx CrateCtxt<'ccx, 'tcx>,
+pub struct CheckTypeWellFormedVisitor<'a, 'tcx:'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
     code: ObligationCauseCode<'tcx>,
 }
 
@@ -51,9 +50,9 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
         let id = self.id;
         let span = self.span;
         self.inherited.enter(|inh| {
-            let fcx = FnCtxt::new(&inh, Some(inh.ccx.tcx.types.never), id);
+            let fcx = FnCtxt::new(&inh, None, id);
             let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor {
-                ccx: fcx.ccx,
+                tcx: fcx.tcx.global_tcx(),
                 code: code
             });
             fcx.select_all_obligations_or_error();
@@ -62,19 +61,15 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
     }
 }
 
-impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
-    pub fn new(ccx: &'ccx CrateCtxt<'ccx, 'gcx>)
-               -> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
+impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
+    pub fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>)
+               -> CheckTypeWellFormedVisitor<'a, 'gcx> {
         CheckTypeWellFormedVisitor {
-            ccx: ccx,
+            tcx: tcx,
             code: ObligationCauseCode::MiscObligation
         }
     }
 
-    fn tcx(&self) -> TyCtxt<'ccx, 'gcx, 'gcx> {
-        self.ccx.tcx
-    }
-
     /// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are
     /// well-formed, meaning that they do not require any constraints not declared in the struct
     /// definition itself. For example, this definition would be illegal:
@@ -87,10 +82,10 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
     /// not included it frequently leads to confusing errors in fn bodies. So it's better to check
     /// the types first.
     fn check_item_well_formed(&mut self, item: &hir::Item) {
-        let ccx = self.ccx;
+        let tcx = self.tcx;
         debug!("check_item_well_formed(it.id={}, it.name={})",
                item.id,
-               ccx.tcx.item_path_str(ccx.tcx.hir.local_def_id(item.id)));
+               tcx.item_path_str(tcx.hir.local_def_id(item.id)));
 
         match item.node {
             /// Right now we check that every default trait implementation
@@ -117,9 +112,9 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
             hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), ..) => {
                 // FIXME(#27579) what amount of WF checking do we need for neg impls?
 
-                let trait_ref = ccx.tcx.impl_trait_ref(ccx.tcx.hir.local_def_id(item.id)).unwrap();
-                if !ccx.tcx.trait_has_default_impl(trait_ref.def_id) {
-                    error_192(ccx, item.span);
+                let trait_ref = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id)).unwrap();
+                if !tcx.trait_has_default_impl(trait_ref.def_id) {
+                    error_192(tcx, item.span);
                 }
             }
             hir::ItemFn(.., body_id) => {
@@ -187,11 +182,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                     let method_ty = fcx.tcx.item_type(item.def_id);
                     let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method_ty);
                     let predicates = fcx.instantiate_bounds(span, item.def_id, free_substs);
-                    let fty = match method_ty.sty {
-                        ty::TyFnDef(_, _, f) => f,
-                        _ => bug!()
-                    };
-                    this.check_fn_or_method(fcx, span, fty, &predicates,
+                    let sig = method_ty.fn_sig();
+                    this.check_fn_or_method(fcx, span, sig, &predicates,
                                             free_id_outlive, &mut implied_bounds);
                     let sig_if_method = sig_if_method.expect("bad signature for method");
                     this.check_method_receiver(fcx, sig_if_method, &item,
@@ -211,14 +203,14 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
     }
 
     fn for_item<'tcx>(&self, item: &hir::Item)
-                      -> CheckWfFcxBuilder<'ccx, 'gcx, 'tcx> {
+                      -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
         self.for_id(item.id, item.span)
     }
 
     fn for_id<'tcx>(&self, id: ast::NodeId, span: Span)
-                    -> CheckWfFcxBuilder<'ccx, 'gcx, 'tcx> {
+                    -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
         CheckWfFcxBuilder {
-            inherited: self.ccx.inherited(id),
+            inherited: Inherited::build(self.tcx, id),
             code: self.code.clone(),
             id: id,
             span: span
@@ -270,7 +262,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
         //
         // 3) that the trait definition does not have any type parameters
 
-        let predicates = self.tcx().item_predicates(trait_def_id);
+        let predicates = self.tcx.item_predicates(trait_def_id);
 
         // We must exclude the Self : Trait predicate contained by all
         // traits.
@@ -285,7 +277,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                 }
             });
 
-        let has_ty_params = self.tcx().item_generics(trait_def_id).types.len() > 1;
+        let has_ty_params = self.tcx.item_generics(trait_def_id).types.len() > 1;
 
         // We use an if-else here, since the generics will also trigger
         // an extraneous error message when we find predicates like
@@ -296,14 +288,14 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
         // extraneous predicates created by things like
         // an associated type inside the trait.
         let mut err = None;
-        if !self.tcx().associated_item_def_ids(trait_def_id).is_empty() {
-            error_380(self.ccx, span);
+        if !self.tcx.associated_item_def_ids(trait_def_id).is_empty() {
+            error_380(self.tcx, span);
         } else if has_ty_params {
-            err = Some(struct_span_err!(self.tcx().sess, span, E0567,
+            err = Some(struct_span_err!(self.tcx.sess, span, E0567,
                 "traits with auto impls (`e.g. impl \
                     Trait for ..`) can not have type parameters"));
         } else if has_predicates {
-            err = Some(struct_span_err!(self.tcx().sess, span, E0568,
+            err = Some(struct_span_err!(self.tcx.sess, span, E0568,
                 "traits with auto impls (`e.g. impl \
                     Trait for ..`) cannot have predicates"));
         }
@@ -321,9 +313,9 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
     }
 
     fn check_trait(&mut self, item: &hir::Item) {
-        let trait_def_id = self.tcx().hir.local_def_id(item.id);
+        let trait_def_id = self.tcx.hir.local_def_id(item.id);
 
-        if self.tcx().trait_has_default_impl(trait_def_id) {
+        if self.tcx.trait_has_default_impl(trait_def_id) {
             self.check_auto_trait(trait_def_id, item.span);
         }
 
@@ -344,18 +336,13 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
             let def_id = fcx.tcx.hir.local_def_id(item.id);
             let ty = fcx.tcx.item_type(def_id);
             let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &ty);
-            let bare_fn_ty = match item_ty.sty {
-                ty::TyFnDef(.., ref bare_fn_ty) => bare_fn_ty,
-                _ => {
-                    span_bug!(item.span, "Fn item without fn type");
-                }
-            };
+            let sig = item_ty.fn_sig();
 
             let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs);
 
             let mut implied_bounds = vec![];
             let free_id_outlive = fcx.tcx.region_maps.call_site_extent(item.id, body_id.node_id);
-            this.check_fn_or_method(fcx, item.span, bare_fn_ty, &predicates,
+            this.check_fn_or_method(fcx, item.span, sig, &predicates,
                                     free_id_outlive, &mut implied_bounds);
             implied_bounds
         })
@@ -440,14 +427,14 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
     fn check_fn_or_method<'fcx, 'tcx>(&mut self,
                                       fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
                                       span: Span,
-                                      fty: &'tcx ty::BareFnTy<'tcx>,
+                                      sig: ty::PolyFnSig<'tcx>,
                                       predicates: &ty::InstantiatedPredicates<'tcx>,
                                       free_id_outlive: CodeExtent,
                                       implied_bounds: &mut Vec<Ty<'tcx>>)
     {
         let free_substs = &fcx.parameter_environment.free_substs;
-        let fty = fcx.instantiate_type_scheme(span, free_substs, &fty);
-        let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig);
+        let sig = fcx.instantiate_type_scheme(span, free_substs, &sig);
+        let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &sig);
 
         for input_ty in sig.inputs() {
             fcx.register_wf_obligation(&input_ty, span, self.code.clone());
@@ -514,15 +501,15 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                                      item: &hir::Item,
                                      ast_generics: &hir::Generics)
     {
-        let item_def_id = self.tcx().hir.local_def_id(item.id);
-        let ty = self.tcx().item_type(item_def_id);
-        if self.tcx().has_error_field(ty) {
+        let item_def_id = self.tcx.hir.local_def_id(item.id);
+        let ty = self.tcx.item_type(item_def_id);
+        if self.tcx.has_error_field(ty) {
             return;
         }
 
-        let ty_predicates = self.tcx().item_predicates(item_def_id);
+        let ty_predicates = self.tcx.item_predicates(item_def_id);
         assert_eq!(ty_predicates.parent, None);
-        let variances = self.tcx().item_variances(item_def_id);
+        let variances = self.tcx.item_variances(item_def_id);
 
         let mut constrained_parameters: FxHashSet<_> =
             variances.iter().enumerate()
@@ -555,15 +542,15 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                          span: Span,
                          param_name: ast::Name)
     {
-        let mut err = error_392(self.ccx, span, param_name);
+        let mut err = error_392(self.tcx, span, param_name);
 
-        let suggested_marker_id = self.tcx().lang_items.phantom_data();
+        let suggested_marker_id = self.tcx.lang_items.phantom_data();
         match suggested_marker_id {
             Some(def_id) => {
                 err.help(
                     &format!("consider removing `{}` or using a marker such as `{}`",
                              param_name,
-                             self.tcx().item_path_str(def_id)));
+                             self.tcx.item_path_str(def_id)));
             }
             None => {
                 // no lang items, no help!
@@ -595,7 +582,7 @@ fn reject_shadowing_type_parameters(tcx: TyCtxt, def_id: DefId) {
     }
 }
 
-impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
+impl<'a, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
         NestedVisitorMap::None
     }
@@ -681,21 +668,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
-fn error_192(ccx: &CrateCtxt, span: Span) {
-    span_err!(ccx.tcx.sess, span, E0192,
+fn error_192(tcx: TyCtxt, span: Span) {
+    span_err!(tcx.sess, span, E0192,
               "negative impls are only allowed for traits with \
                default impls (e.g., `Send` and `Sync`)")
 }
 
-fn error_380(ccx: &CrateCtxt, span: Span) {
-    span_err!(ccx.tcx.sess, span, E0380,
+fn error_380(tcx: TyCtxt, span: Span) {
+    span_err!(tcx.sess, span, E0380,
               "traits with default impls (`e.g. impl \
                Trait for ..`) must have no methods or associated items")
 }
 
-fn error_392<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, param_name: ast::Name)
+fn error_392<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, param_name: ast::Name)
                        -> DiagnosticBuilder<'tcx> {
-    let mut err = struct_span_err!(ccx.tcx.sess, span, E0392,
+    let mut err = struct_span_err!(tcx.sess, span, E0392,
                   "parameter `{}` is never used", param_name);
     err.span_label(span, &format!("unused type parameter"));
     err
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index a2922270583..1382ab34ca5 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -14,14 +14,12 @@
 use self::ResolveReason::*;
 
 use check::FnCtxt;
-use hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee};
 use rustc::ty::adjustment;
 use rustc::ty::fold::{TypeFolder,TypeFoldable};
 use rustc::infer::{InferCtxt, FixupError};
 use rustc::util::nodemap::{DefIdMap, DefIdSet};
 
-use std::cell::Cell;
 use std::mem;
 
 use syntax::ast;
@@ -34,9 +32,8 @@ use rustc::hir;
 // Entry point
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body) {
-        assert_eq!(self.writeback_errors.get(), false);
-
+    pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body)
+                                     -> &'gcx ty::TypeckTables<'gcx> {
         let item_id = self.tcx.hir.body_owner(body.id());
         let item_def_id = self.tcx.hir.local_def_id(item_id);
 
@@ -50,18 +47,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         wbcx.visit_liberated_fn_sigs();
         wbcx.visit_fru_field_types();
         wbcx.visit_anon_types();
-        wbcx.visit_deferred_obligations(item_id);
         wbcx.visit_type_nodes();
         wbcx.visit_cast_types();
         wbcx.visit_lints();
 
-        let tables = self.tcx.alloc_tables(wbcx.tables);
-        self.tcx.tables.borrow_mut().insert(item_def_id, tables);
-
-        let used_trait_imports = mem::replace(&mut *self.used_trait_imports.borrow_mut(),
+        let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports,
                                               DefIdSet());
         debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
-        self.tcx.used_trait_imports.borrow_mut().insert(item_def_id, used_trait_imports);
+        wbcx.tables.used_trait_imports = used_trait_imports;
+
+        wbcx.tables.tainted_by_errors = self.is_tainted_by_errors();
+
+        self.tcx.alloc_tables(wbcx.tables)
     }
 }
 
@@ -197,19 +194,11 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
     }
 
     fn visit_stmt(&mut self, s: &'gcx hir::Stmt) {
-        if self.fcx.writeback_errors.get() {
-            return;
-        }
-
         self.visit_node_id(ResolvingExpr(s.span), s.node.id());
         intravisit::walk_stmt(self, s);
     }
 
     fn visit_expr(&mut self, e: &'gcx hir::Expr) {
-        if self.fcx.writeback_errors.get() {
-            return;
-        }
-
         self.fix_scalar_builtin_expr(e);
 
         self.visit_node_id(ResolvingExpr(e.span), e.id);
@@ -229,29 +218,16 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
     }
 
     fn visit_block(&mut self, b: &'gcx hir::Block) {
-        if self.fcx.writeback_errors.get() {
-            return;
-        }
-
         self.visit_node_id(ResolvingExpr(b.span), b.id);
         intravisit::walk_block(self, b);
     }
 
     fn visit_pat(&mut self, p: &'gcx hir::Pat) {
-        if self.fcx.writeback_errors.get() {
-            return;
-        }
-
         self.visit_node_id(ResolvingPattern(p.span), p.id);
-
         intravisit::walk_pat(self, p);
     }
 
     fn visit_local(&mut self, l: &'gcx hir::Local) {
-        if self.fcx.writeback_errors.get() {
-            return;
-        }
-
         let var_ty = self.fcx.local_ty(l.span, l.id);
         let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span));
         self.write_ty_to_tables(l.id, var_ty);
@@ -261,10 +237,6 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
 
 impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
     fn visit_upvar_borrow_map(&mut self) {
-        if self.fcx.writeback_errors.get() {
-            return;
-        }
-
         for (upvar_id, upvar_capture) in self.fcx.tables.borrow().upvar_capture_map.iter() {
             let new_upvar_capture = match *upvar_capture {
                 ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue,
@@ -282,48 +254,30 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
         }
     }
 
-    fn visit_closures(&self) {
-        if self.fcx.writeback_errors.get() {
-            return
-        }
-
+    fn visit_closures(&mut self) {
         for (&id, closure_ty) in self.fcx.tables.borrow().closure_tys.iter() {
             let closure_ty = self.resolve(closure_ty, ResolvingClosure(id));
-            let def_id = self.tcx().hir.local_def_id(id);
-            self.tcx().closure_tys.borrow_mut().insert(def_id, closure_ty);
+            self.tables.closure_tys.insert(id, closure_ty);
         }
 
         for (&id, &closure_kind) in self.fcx.tables.borrow().closure_kinds.iter() {
-            let def_id = self.tcx().hir.local_def_id(id);
-            self.tcx().closure_kinds.borrow_mut().insert(def_id, closure_kind);
+            self.tables.closure_kinds.insert(id, closure_kind);
         }
     }
 
     fn visit_cast_types(&mut self) {
-        if self.fcx.writeback_errors.get() {
-            return
-        }
-
         self.tables.cast_kinds.extend(
             self.fcx.tables.borrow().cast_kinds.iter().map(|(&key, &value)| (key, value)));
     }
 
     fn visit_lints(&mut self) {
-        if self.fcx.writeback_errors.get() {
-            return
-        }
-
         self.fcx.tables.borrow_mut().lints.transfer(&mut self.tables.lints);
     }
 
-    fn visit_anon_types(&self) {
-        if self.fcx.writeback_errors.get() {
-            return
-        }
-
+    fn visit_anon_types(&mut self) {
         let gcx = self.tcx().global_tcx();
-        for (&def_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
-            let reason = ResolvingAnonTy(def_id);
+        for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
+            let reason = ResolvingAnonTy(node_id);
             let inside_ty = self.resolve(&concrete_ty, reason);
 
             // Convert the type from the function into a type valid outside
@@ -361,7 +315,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
                 }
             });
 
-            gcx.item_types.borrow_mut().insert(def_id, outside_ty);
+            self.tables.node_types.insert(node_id, outside_ty);
         }
     }
 
@@ -412,6 +366,10 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
                         adjustment::Adjust::MutToConstPointer
                     }
 
+                    adjustment::Adjust::ClosureFnPointer => {
+                        adjustment::Adjust::ClosureFnPointer
+                    }
+
                     adjustment::Adjust::UnsafeFnPointer => {
                         adjustment::Adjust::UnsafeFnPointer
                     }
@@ -479,23 +437,10 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
         }
     }
 
-    fn visit_deferred_obligations(&mut self, item_id: ast::NodeId) {
-        let deferred_obligations = self.fcx.deferred_obligations.borrow();
-        let obligations: Vec<_> = deferred_obligations.iter().map(|obligation| {
-            let reason = ResolvingDeferredObligation(obligation.cause.span);
-            self.resolve(obligation, reason)
-        }).collect();
-
-        if !obligations.is_empty() {
-            assert!(self.fcx.ccx.deferred_obligations.borrow_mut()
-                                .insert(item_id, obligations).is_none());
-        }
-    }
-
     fn visit_type_nodes(&self) {
         for (&id, ty) in self.fcx.ast_ty_to_ty_cache.borrow().iter() {
             let ty = self.resolve(ty, ResolvingTyNode(id));
-            self.fcx.ccx.ast_ty_to_ty_cache.borrow_mut().insert(id, ty);
+            self.fcx.tcx.ast_ty_to_ty_cache.borrow_mut().insert(id, ty);
         }
     }
 
@@ -524,8 +469,7 @@ enum ResolveReason {
     ResolvingClosure(ast::NodeId),
     ResolvingFnSig(ast::NodeId),
     ResolvingFieldTypes(ast::NodeId),
-    ResolvingAnonTy(DefId),
-    ResolvingDeferredObligation(Span),
+    ResolvingAnonTy(ast::NodeId),
     ResolvingTyNode(ast::NodeId),
 }
 
@@ -541,13 +485,10 @@ impl<'a, 'gcx, 'tcx> ResolveReason {
             ResolvingClosure(id) |
             ResolvingFnSig(id) |
             ResolvingFieldTypes(id) |
-            ResolvingTyNode(id) => {
+            ResolvingTyNode(id) |
+            ResolvingAnonTy(id) => {
                 tcx.hir.span(id)
             }
-            ResolvingAnonTy(did) => {
-                tcx.def_span(did)
-            }
-            ResolvingDeferredObligation(span) => span
         }
     }
 }
@@ -559,7 +500,6 @@ impl<'a, 'gcx, 'tcx> ResolveReason {
 struct Resolver<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
     tcx: TyCtxt<'cx, 'gcx, 'tcx>,
     infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
-    writeback_errors: &'cx Cell<bool>,
     reason: ResolveReason,
 }
 
@@ -568,22 +508,19 @@ impl<'cx, 'gcx, 'tcx> Resolver<'cx, 'gcx, 'tcx> {
            reason: ResolveReason)
            -> Resolver<'cx, 'gcx, 'tcx>
     {
-        Resolver::from_infcx(fcx, &fcx.writeback_errors, reason)
+        Resolver::from_infcx(fcx, reason)
     }
 
     fn from_infcx(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
-                  writeback_errors: &'cx Cell<bool>,
                   reason: ResolveReason)
                   -> Resolver<'cx, 'gcx, 'tcx>
     {
         Resolver { infcx: infcx,
                    tcx: infcx.tcx,
-                   writeback_errors: writeback_errors,
                    reason: reason }
     }
 
     fn report_error(&self, e: FixupError) {
-        self.writeback_errors.set(true);
         if !self.tcx.sess.has_errors() {
             match self.reason {
                 ResolvingExpr(span) => {
@@ -622,7 +559,6 @@ impl<'cx, 'gcx, 'tcx> Resolver<'cx, 'gcx, 'tcx> {
 
                 ResolvingFnSig(_) |
                 ResolvingFieldTypes(_) |
-                ResolvingDeferredObligation(_) |
                 ResolvingTyNode(_) => {
                     // any failures here should also fail when
                     // resolving the patterns, closure types, or
diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs
index 6dff6d57e4f..3791079dc81 100644
--- a/src/librustc_typeck/check_unused.rs
+++ b/src/librustc_typeck/check_unused.rs
@@ -70,7 +70,8 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         let item_def_id = tcx.hir.local_def_id(item_id);
 
         // this will have been written by the main typeck pass
-        if let Some(imports) = tcx.used_trait_imports.borrow().get(&item_def_id) {
+        if let Some(tables) = tcx.maps.typeck_tables.borrow().get(&item_def_id) {
+            let imports = &tables.used_trait_imports;
             debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports);
             used_trait_imports.extend(imports);
         } else {
diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs
index 96875fce468..3cdf9fc93ae 100644
--- a/src/librustc_typeck/coherence/builtin.rs
+++ b/src/librustc_typeck/coherence/builtin.rs
@@ -26,47 +26,38 @@ use rustc::hir::def_id::DefId;
 use rustc::hir::map as hir_map;
 use rustc::hir::{self, ItemImpl};
 
-pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    check_trait(tcx, tcx.lang_items.drop_trait(), visit_implementation_of_drop);
-    check_trait(tcx, tcx.lang_items.copy_trait(), visit_implementation_of_copy);
-    check_trait(
-        tcx,
-        tcx.lang_items.coerce_unsized_trait(),
-        visit_implementation_of_coerce_unsized);
+pub fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_def_id: DefId) {
+    Checker { tcx, trait_def_id }
+        .check(tcx.lang_items.drop_trait(), visit_implementation_of_drop)
+        .check(tcx.lang_items.copy_trait(), visit_implementation_of_copy)
+        .check(tcx.lang_items.coerce_unsized_trait(),
+               visit_implementation_of_coerce_unsized);
 }
 
-fn check_trait<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                            trait_def_id: Option<DefId>,
-                            mut f: F)
-    where F: FnMut(TyCtxt<'a, 'tcx, 'tcx>, DefId, DefId)
-{
-    if let Some(trait_def_id) = trait_def_id {
-        let mut impls = vec![];
-        tcx.lookup_trait_def(trait_def_id).for_each_impl(tcx, |did| {
-            impls.push(did);
-        });
-        impls.sort();
-        for impl_def_id in impls {
-            f(tcx, trait_def_id, impl_def_id);
+struct Checker<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    trait_def_id: DefId
+}
+
+impl<'a, 'tcx> Checker<'a, 'tcx> {
+    fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> &Self
+        where F: FnMut(TyCtxt<'a, 'tcx, 'tcx>, DefId, DefId)
+    {
+        if Some(self.trait_def_id) == trait_def_id {
+            for &impl_id in self.tcx.hir.trait_impls(self.trait_def_id) {
+                let impl_def_id = self.tcx.hir.local_def_id(impl_id);
+                f(self.tcx, self.trait_def_id, impl_def_id);
+            }
         }
+        self
     }
 }
 
 fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                           _drop_did: DefId,
                                           impl_did: DefId) {
-    let items = tcx.associated_item_def_ids(impl_did);
-    if items.is_empty() {
-        // We'll error out later. For now, just don't ICE.
-        return;
-    }
-    let method_def_id = items[0];
-
-    let self_type = tcx.item_type(impl_did);
-    match self_type.sty {
-        ty::TyAdt(type_def, _) => {
-            type_def.set_destructor(method_def_id);
-        }
+    match tcx.item_type(impl_did).sty {
+        ty::TyAdt(..) => {}
         _ => {
             // Destructors only work on nominal types.
             if let Some(impl_node_id) = tcx.hir.as_local_node_id(impl_did) {
@@ -205,7 +196,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
            source,
            target);
 
-    tcx.infer_ctxt(param_env, Reveal::ExactMatch).enter(|infcx| {
+    tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
         let cause = ObligationCause::misc(span, impl_node_id);
         let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
                            mt_b: ty::TypeAndMut<'tcx>,
@@ -341,7 +332,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
 
         if let Some(kind) = kind {
-            tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind);
+            tcx.maps.custom_coerce_unsized_kind.borrow_mut().insert(impl_did, kind);
         }
     });
 }
diff --git a/src/librustc_typeck/coherence/inherent.rs b/src/librustc_typeck/coherence/inherent.rs
new file mode 100644
index 00000000000..e3b4ba9eb1b
--- /dev/null
+++ b/src/librustc_typeck/coherence/inherent.rs
@@ -0,0 +1,356 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::dep_graph::DepNode;
+use rustc::hir::def_id::DefId;
+use rustc::hir;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::lint;
+use rustc::traits::{self, Reveal};
+use rustc::ty::{self, TyCtxt};
+
+use syntax::ast;
+use syntax_pos::Span;
+
+struct InherentCollect<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>
+}
+
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
+    fn visit_item(&mut self, item: &hir::Item) {
+        let (unsafety, ty) = match item.node {
+            hir::ItemImpl(unsafety, .., None, ref ty, _) => (unsafety, ty),
+            _ => return
+        };
+
+        match unsafety {
+            hir::Unsafety::Normal => {
+                // OK
+            }
+            hir::Unsafety::Unsafe => {
+                span_err!(self.tcx.sess,
+                          item.span,
+                          E0197,
+                          "inherent impls cannot be declared as unsafe");
+            }
+        }
+
+        let def_id = self.tcx.hir.local_def_id(item.id);
+        let self_ty = self.tcx.item_type(def_id);
+        match self_ty.sty {
+            ty::TyAdt(def, _) => {
+                self.check_def_id(item, def.did);
+            }
+            ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
+                self.check_def_id(item, data.principal().unwrap().def_id());
+            }
+            ty::TyChar => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.char_impl(),
+                                          "char",
+                                          "char",
+                                          item.span);
+            }
+            ty::TyStr => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.str_impl(),
+                                          "str",
+                                          "str",
+                                          item.span);
+            }
+            ty::TySlice(_) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.slice_impl(),
+                                          "slice",
+                                          "[T]",
+                                          item.span);
+            }
+            ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.const_ptr_impl(),
+                                          "const_ptr",
+                                          "*const T",
+                                          item.span);
+            }
+            ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.mut_ptr_impl(),
+                                          "mut_ptr",
+                                          "*mut T",
+                                          item.span);
+            }
+            ty::TyInt(ast::IntTy::I8) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.i8_impl(),
+                                          "i8",
+                                          "i8",
+                                          item.span);
+            }
+            ty::TyInt(ast::IntTy::I16) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.i16_impl(),
+                                          "i16",
+                                          "i16",
+                                          item.span);
+            }
+            ty::TyInt(ast::IntTy::I32) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.i32_impl(),
+                                          "i32",
+                                          "i32",
+                                          item.span);
+            }
+            ty::TyInt(ast::IntTy::I64) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.i64_impl(),
+                                          "i64",
+                                          "i64",
+                                          item.span);
+            }
+            ty::TyInt(ast::IntTy::I128) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.i128_impl(),
+                                          "i128",
+                                          "i128",
+                                          item.span);
+            }
+            ty::TyInt(ast::IntTy::Is) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.isize_impl(),
+                                          "isize",
+                                          "isize",
+                                          item.span);
+            }
+            ty::TyUint(ast::UintTy::U8) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.u8_impl(),
+                                          "u8",
+                                          "u8",
+                                          item.span);
+            }
+            ty::TyUint(ast::UintTy::U16) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.u16_impl(),
+                                          "u16",
+                                          "u16",
+                                          item.span);
+            }
+            ty::TyUint(ast::UintTy::U32) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.u32_impl(),
+                                          "u32",
+                                          "u32",
+                                          item.span);
+            }
+            ty::TyUint(ast::UintTy::U64) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.u64_impl(),
+                                          "u64",
+                                          "u64",
+                                          item.span);
+            }
+            ty::TyUint(ast::UintTy::U128) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.u128_impl(),
+                                          "u128",
+                                          "u128",
+                                          item.span);
+            }
+            ty::TyUint(ast::UintTy::Us) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.usize_impl(),
+                                          "usize",
+                                          "usize",
+                                          item.span);
+            }
+            ty::TyFloat(ast::FloatTy::F32) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.f32_impl(),
+                                          "f32",
+                                          "f32",
+                                          item.span);
+            }
+            ty::TyFloat(ast::FloatTy::F64) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.f64_impl(),
+                                          "f64",
+                                          "f64",
+                                          item.span);
+            }
+            ty::TyError => {
+                return;
+            }
+            _ => {
+                struct_span_err!(self.tcx.sess,
+                                 ty.span,
+                                 E0118,
+                                 "no base type found for inherent implementation")
+                    .span_label(ty.span, &format!("impl requires a base type"))
+                    .note(&format!("either implement a trait on it or create a newtype \
+                                    to wrap it instead"))
+                    .emit();
+                return;
+            }
+        }
+    }
+
+    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+    }
+
+    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+    }
+}
+
+impl<'a, 'tcx> InherentCollect<'a, 'tcx> {
+    fn check_def_id(&self, item: &hir::Item, def_id: DefId) {
+        if def_id.is_local() {
+            // Add the implementation to the mapping from implementation to base
+            // type def ID, if there is a base type for this implementation and
+            // the implementation does not have any associated traits.
+            let impl_def_id = self.tcx.hir.local_def_id(item.id);
+
+            // Subtle: it'd be better to collect these into a local map
+            // and then write the vector only once all items are known,
+            // but that leads to degenerate dep-graphs. The problem is
+            // that the write of that big vector winds up having reads
+            // from *all* impls in the krate, since we've lost the
+            // precision basically.  This would be ok in the firewall
+            // model so once we've made progess towards that we can modify
+            // the strategy here. In the meantime, using `push` is ok
+            // because we are doing this as a pre-pass before anyone
+            // actually reads from `inherent_impls` -- and we know this is
+            // true beacuse we hold the refcell lock.
+            self.tcx.maps.inherent_impls.borrow_mut().push(def_id, impl_def_id);
+        } else {
+            struct_span_err!(self.tcx.sess,
+                             item.span,
+                             E0116,
+                             "cannot define inherent `impl` for a type outside of the crate \
+                              where the type is defined")
+                .span_label(item.span,
+                            &format!("impl for type defined outside of crate."))
+                .note("define and implement a trait or new type instead")
+                .emit();
+        }
+    }
+
+    fn check_primitive_impl(&self,
+                            impl_def_id: DefId,
+                            lang_def_id: Option<DefId>,
+                            lang: &str,
+                            ty: &str,
+                            span: Span) {
+        match lang_def_id {
+            Some(lang_def_id) if lang_def_id == impl_def_id => {
+                // OK
+            }
+            _ => {
+                struct_span_err!(self.tcx.sess,
+                                 span,
+                                 E0390,
+                                 "only a single inherent implementation marked with `#[lang = \
+                                  \"{}\"]` is allowed for the `{}` primitive",
+                                 lang,
+                                 ty)
+                    .span_help(span, "consider using a trait to implement these methods")
+                    .emit();
+            }
+        }
+    }
+}
+
+struct InherentOverlapChecker<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>
+}
+
+impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
+    fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
+        #[derive(Copy, Clone, PartialEq)]
+        enum Namespace {
+            Type,
+            Value,
+        }
+
+        let name_and_namespace = |def_id| {
+            let item = self.tcx.associated_item(def_id);
+            (item.name, match item.kind {
+                ty::AssociatedKind::Type => Namespace::Type,
+                ty::AssociatedKind::Const |
+                ty::AssociatedKind::Method => Namespace::Value,
+            })
+        };
+
+        let impl_items1 = self.tcx.associated_item_def_ids(impl1);
+        let impl_items2 = self.tcx.associated_item_def_ids(impl2);
+
+        for &item1 in &impl_items1[..] {
+            let (name, namespace) = name_and_namespace(item1);
+
+            for &item2 in &impl_items2[..] {
+                if (name, namespace) == name_and_namespace(item2) {
+                    let msg = format!("duplicate definitions with name `{}`", name);
+                    let node_id = self.tcx.hir.as_local_node_id(item1).unwrap();
+                    self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
+                                           node_id,
+                                           self.tcx.span_of_impl(item1).unwrap(),
+                                           msg);
+                }
+            }
+        }
+    }
+
+    fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
+        let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id));
+
+        let inherent_impls = self.tcx.maps.inherent_impls.borrow();
+        let impls = match inherent_impls.get(&ty_def_id) {
+            Some(impls) => impls,
+            None => return,
+        };
+
+        for (i, &impl1_def_id) in impls.iter().enumerate() {
+            for &impl2_def_id in &impls[(i + 1)..] {
+                self.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
+                    if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
+                        self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
+                    }
+                });
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> {
+    fn visit_item(&mut self, item: &'v hir::Item) {
+        match item.node {
+            hir::ItemEnum(..) |
+            hir::ItemStruct(..) |
+            hir::ItemTrait(..) |
+            hir::ItemUnion(..) => {
+                let type_def_id = self.tcx.hir.local_def_id(item.id);
+                self.check_for_overlapping_inherent_impls(type_def_id);
+            }
+            _ => {}
+        }
+    }
+
+    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+    }
+
+    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+    }
+}
+
+pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl,
+                                      &mut InherentCollect { tcx });
+    tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial,
+                                      &mut InherentOverlapChecker { tcx });
+}
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index b6a863fd2ed..9ecf42daeaa 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -15,147 +15,72 @@
 // done by the orphan and overlap modules. Then we build up various
 // mappings. That mapping code resides here.
 
-use dep_graph::DepTrackingMap;
-use hir::def_id::DefId;
-use rustc::ty::{self, maps, TyCtxt, TypeFoldable};
-use rustc::ty::{Ty, TyBool, TyChar, TyError};
-use rustc::ty::{TyParam, TyRawPtr};
-use rustc::ty::{TyRef, TyAdt, TyDynamic, TyNever, TyTuple};
-use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
-use rustc::ty::{TyUint, TyClosure, TyFnDef, TyFnPtr};
-use rustc::ty::{TyProjection, TyAnon};
-use CrateCtxt;
-use syntax_pos::Span;
+use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use rustc::ty::{self, TyCtxt, TypeFoldable};
+use rustc::ty::maps::Providers;
 use rustc::dep_graph::DepNode;
-use rustc::hir::itemlikevisit::ItemLikeVisitor;
-use rustc::hir::{Item, ItemImpl};
-use rustc::hir;
-use std::cell::RefMut;
+
+use syntax::ast;
+use syntax_pos::DUMMY_SP;
 
 mod builtin;
+mod inherent;
 mod orphan;
 mod overlap;
 mod unsafety;
 
-struct CoherenceCollect<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    inherent_impls: RefMut<'a, DepTrackingMap<maps::InherentImpls<'tcx>>>,
-}
-
-impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCollect<'a, 'tcx> {
-    fn visit_item(&mut self, item: &Item) {
-        if let ItemImpl(..) = item.node {
-            self.check_implementation(item)
-        }
-    }
-
-    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
-    }
+fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) {
+    let impl_def_id = tcx.hir.local_def_id(node_id);
 
-    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
-    }
-}
+    // If there are no traits, then this implementation must have a
+    // base type.
 
-impl<'a, 'tcx> CoherenceCollect<'a, 'tcx> {
-    fn check(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-        let inherent_impls = tcx.inherent_impls.borrow_mut();
-        let mut this = &mut CoherenceCollect { tcx, inherent_impls };
+    if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) {
+        debug!("(checking implementation) adding impl for trait '{:?}', item '{}'",
+                trait_ref,
+                tcx.item_path_str(impl_def_id));
 
-        // Check implementations and traits. This populates the tables
-        // containing the inherent methods and extension methods. It also
-        // builds up the trait inheritance table.
-        tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl, this);
-    }
-
-    // Returns the def ID of the base type, if there is one.
-    fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
-        match ty.sty {
-            TyAdt(def, _) => Some(def.did),
-
-            TyDynamic(ref t, ..) => t.principal().map(|p| p.def_id()),
-
-            TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyStr | TyArray(..) |
-            TySlice(..) | TyFnDef(..) | TyFnPtr(_) | TyTuple(..) | TyParam(..) | TyError |
-            TyNever | TyRawPtr(_) | TyRef(..) | TyProjection(..) => None,
-
-            TyInfer(..) | TyClosure(..) | TyAnon(..) => {
-                // `ty` comes from a user declaration so we should only expect types
-                // that the user can type
-                span_bug!(span,
-                          "coherence encountered unexpected type searching for base type: {}",
-                          ty);
-            }
+        // Skip impls where one of the self type is an error type.
+        // This occurs with e.g. resolve failures (#30589).
+        if trait_ref.references_error() {
+            return;
         }
-    }
 
-    fn check_implementation(&mut self, item: &Item) {
-        let tcx = self.tcx;
-        let impl_did = tcx.hir.local_def_id(item.id);
-        let self_type = tcx.item_type(impl_did);
-
-        // If there are no traits, then this implementation must have a
-        // base type.
-
-        if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
-            debug!("(checking implementation) adding impl for trait '{:?}', item '{}'",
-                   trait_ref,
-                   item.name);
-
-            // Skip impls where one of the self type is an error type.
-            // This occurs with e.g. resolve failures (#30589).
-            if trait_ref.references_error() {
-                return;
-            }
-
-            enforce_trait_manually_implementable(self.tcx, item.span, trait_ref.def_id);
-            self.add_trait_impl(trait_ref, impl_did);
-        } else {
-            // Skip inherent impls where the self type is an error
-            // type. This occurs with e.g. resolve failures (#30589).
-            if self_type.references_error() {
-                return;
-            }
-
-            // Add the implementation to the mapping from implementation to base
-            // type def ID, if there is a base type for this implementation and
-            // the implementation does not have any associated traits.
-            if let Some(base_def_id) = self.get_base_type_def_id(item.span, self_type) {
-                self.add_inherent_impl(base_def_id, impl_did);
-            }
-        }
+        enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id);
+        let trait_def = tcx.lookup_trait_def(trait_ref.def_id);
+        trait_def.record_local_impl(tcx, impl_def_id, trait_ref);
     }
+}
 
-    fn add_inherent_impl(&mut self, base_def_id: DefId, impl_def_id: DefId) {
-        // Subtle: it'd be better to collect these into a local map
-        // and then write the vector only once all items are known,
-        // but that leads to degenerate dep-graphs. The problem is
-        // that the write of that big vector winds up having reads
-        // from *all* impls in the krate, since we've lost the
-        // precision basically.  This would be ok in the firewall
-        // model so once we've made progess towards that we can modify
-        // the strategy here. In the meantime, using `push` is ok
-        // because we are doing this as a pre-pass before anyone
-        // actually reads from `inherent_impls` -- and we know this is
-        // true beacuse we hold the refcell lock.
-        self.inherent_impls.push(base_def_id, impl_def_id);
+fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_def_id: DefId) {
+    let did = Some(trait_def_id);
+    let li = &tcx.lang_items;
+
+    // Disallow *all* explicit impls of `Sized` and `Unsize` for now.
+    if did == li.sized_trait() {
+        let span = tcx.span_of_impl(impl_def_id).unwrap();
+        struct_span_err!(tcx.sess,
+                         span,
+                         E0322,
+                         "explicit impls for the `Sized` trait are not permitted")
+            .span_label(span, &format!("impl of 'Sized' not allowed"))
+            .emit();
+        return;
     }
 
-    fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'tcx>, impl_def_id: DefId) {
-        debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}",
-               impl_trait_ref,
-               impl_def_id);
-        let trait_def = self.tcx.lookup_trait_def(impl_trait_ref.def_id);
-        trait_def.record_local_impl(self.tcx, impl_def_id, impl_trait_ref);
+    if did == li.unsize_trait() {
+        let span = tcx.span_of_impl(impl_def_id).unwrap();
+        span_err!(tcx.sess,
+                  span,
+                  E0328,
+                  "explicit impls for the `Unsize` trait are not permitted");
+        return;
     }
-}
 
-fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: DefId) {
     if tcx.sess.features.borrow().unboxed_closures {
-        // the feature gate allows all of them
+        // the feature gate allows all Fn traits
         return;
     }
-    let did = Some(trait_def_id);
-    let li = &tcx.lang_items;
 
     let trait_name = if did == li.fn_trait() {
         "Fn"
@@ -167,7 +92,7 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def
         return; // everything OK
     };
     let mut err = struct_span_err!(tcx.sess,
-                                   sp,
+                                   tcx.span_of_impl(impl_def_id).unwrap(),
                                    E0183,
                                    "manual implementations of `{}` are experimental",
                                    trait_name);
@@ -176,12 +101,41 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def
     err.emit();
 }
 
-pub fn check_coherence(ccx: &CrateCtxt) {
-    CoherenceCollect::check(ccx.tcx);
+pub fn provide(providers: &mut Providers) {
+    *providers = Providers {
+        coherent_trait,
+        coherent_inherent_impls,
+        ..*providers
+    };
+}
+
+fn coherent_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                            (_, def_id): (CrateNum, DefId)) {
+    tcx.populate_implementations_for_trait_if_necessary(def_id);
+
+    let impls = tcx.hir.trait_impls(def_id);
+    for &impl_id in impls {
+        check_impl(tcx, impl_id);
+    }
+    for &impl_id in impls {
+        overlap::check_impl(tcx, impl_id);
+    }
+    builtin::check_trait(tcx, def_id);
+}
+
+fn coherent_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _: CrateNum) {
+    inherent::check(tcx);
+}
+
+pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    let _task = tcx.dep_graph.in_task(DepNode::Coherence);
+    for &trait_def_id in tcx.hir.krate().trait_impls.keys() {
+        ty::queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, trait_def_id));
+    }
+
+    unsafety::check(tcx);
+    orphan::check(tcx);
+    overlap::check_default_impls(tcx);
 
-    let _task = ccx.tcx.dep_graph.in_task(DepNode::Coherence);
-    unsafety::check(ccx.tcx);
-    orphan::check(ccx.tcx);
-    overlap::check(ccx.tcx);
-    builtin::check(ccx.tcx);
+    ty::queries::coherent_inherent_impls::get(tcx, DUMMY_SP, LOCAL_CRATE);
 }
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index 9ef231499df..ee361ab6073 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -11,11 +11,8 @@
 //! Orphan checker: every impl either implements a trait defined in this
 //! crate or pertains to a type defined in this crate.
 
-use hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::traits;
 use rustc::ty::{self, TyCtxt};
-use syntax::ast;
-use syntax_pos::Span;
 use rustc::dep_graph::DepNode;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir;
@@ -29,46 +26,6 @@ struct OrphanChecker<'cx, 'tcx: 'cx> {
     tcx: TyCtxt<'cx, 'tcx, 'tcx>,
 }
 
-impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
-    fn check_def_id(&self, item: &hir::Item, def_id: DefId) {
-        if def_id.krate != LOCAL_CRATE {
-            struct_span_err!(self.tcx.sess,
-                             item.span,
-                             E0116,
-                             "cannot define inherent `impl` for a type outside of the crate \
-                              where the type is defined")
-                .span_label(item.span,
-                            &format!("impl for type defined outside of crate."))
-                .note("define and implement a trait or new type instead")
-                .emit();
-        }
-    }
-
-    fn check_primitive_impl(&self,
-                            impl_def_id: DefId,
-                            lang_def_id: Option<DefId>,
-                            lang: &str,
-                            ty: &str,
-                            span: Span) {
-        match lang_def_id {
-            Some(lang_def_id) if lang_def_id == impl_def_id => {
-                // OK
-            }
-            _ => {
-                struct_span_err!(self.tcx.sess,
-                                 span,
-                                 E0390,
-                                 "only a single inherent implementation marked with `#[lang = \
-                                  \"{}\"]` is allowed for the `{}` primitive",
-                                 lang,
-                                 ty)
-                    .span_help(span, "consider using a trait to implement these methods")
-                    .emit();
-            }
-        }
-    }
-}
-
 impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
     /// Checks exactly one impl for orphan rules and other such
     /// restrictions.  In this fn, it can happen that multiple errors
@@ -78,168 +35,6 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         let def_id = self.tcx.hir.local_def_id(item.id);
         match item.node {
-            hir::ItemImpl(.., None, ref ty, _) => {
-                // For inherent impls, self type must be a nominal type
-                // defined in this crate.
-                debug!("coherence2::orphan check: inherent impl {}",
-                       self.tcx.hir.node_to_string(item.id));
-                let self_ty = self.tcx.item_type(def_id);
-                match self_ty.sty {
-                    ty::TyAdt(def, _) => {
-                        self.check_def_id(item, def.did);
-                    }
-                    ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
-                        self.check_def_id(item, data.principal().unwrap().def_id());
-                    }
-                    ty::TyChar => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.char_impl(),
-                                                  "char",
-                                                  "char",
-                                                  item.span);
-                    }
-                    ty::TyStr => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.str_impl(),
-                                                  "str",
-                                                  "str",
-                                                  item.span);
-                    }
-                    ty::TySlice(_) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.slice_impl(),
-                                                  "slice",
-                                                  "[T]",
-                                                  item.span);
-                    }
-                    ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.const_ptr_impl(),
-                                                  "const_ptr",
-                                                  "*const T",
-                                                  item.span);
-                    }
-                    ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.mut_ptr_impl(),
-                                                  "mut_ptr",
-                                                  "*mut T",
-                                                  item.span);
-                    }
-                    ty::TyInt(ast::IntTy::I8) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.i8_impl(),
-                                                  "i8",
-                                                  "i8",
-                                                  item.span);
-                    }
-                    ty::TyInt(ast::IntTy::I16) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.i16_impl(),
-                                                  "i16",
-                                                  "i16",
-                                                  item.span);
-                    }
-                    ty::TyInt(ast::IntTy::I32) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.i32_impl(),
-                                                  "i32",
-                                                  "i32",
-                                                  item.span);
-                    }
-                    ty::TyInt(ast::IntTy::I64) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.i64_impl(),
-                                                  "i64",
-                                                  "i64",
-                                                  item.span);
-                    }
-                    ty::TyInt(ast::IntTy::I128) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.i128_impl(),
-                                                  "i128",
-                                                  "i128",
-                                                  item.span);
-                    }
-                    ty::TyInt(ast::IntTy::Is) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.isize_impl(),
-                                                  "isize",
-                                                  "isize",
-                                                  item.span);
-                    }
-                    ty::TyUint(ast::UintTy::U8) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.u8_impl(),
-                                                  "u8",
-                                                  "u8",
-                                                  item.span);
-                    }
-                    ty::TyUint(ast::UintTy::U16) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.u16_impl(),
-                                                  "u16",
-                                                  "u16",
-                                                  item.span);
-                    }
-                    ty::TyUint(ast::UintTy::U32) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.u32_impl(),
-                                                  "u32",
-                                                  "u32",
-                                                  item.span);
-                    }
-                    ty::TyUint(ast::UintTy::U64) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.u64_impl(),
-                                                  "u64",
-                                                  "u64",
-                                                  item.span);
-                    }
-                    ty::TyUint(ast::UintTy::U128) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.u128_impl(),
-                                                  "u128",
-                                                  "u128",
-                                                  item.span);
-                    }
-                    ty::TyUint(ast::UintTy::Us) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.usize_impl(),
-                                                  "usize",
-                                                  "usize",
-                                                  item.span);
-                    }
-                    ty::TyFloat(ast::FloatTy::F32) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.f32_impl(),
-                                                  "f32",
-                                                  "f32",
-                                                  item.span);
-                    }
-                    ty::TyFloat(ast::FloatTy::F64) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.f64_impl(),
-                                                  "f64",
-                                                  "f64",
-                                                  item.span);
-                    }
-                    ty::TyError => {
-                        return;
-                    }
-                    _ => {
-                        struct_span_err!(self.tcx.sess,
-                                         ty.span,
-                                         E0118,
-                                         "no base type found for inherent implementation")
-                            .span_label(ty.span, &format!("impl requires a base type"))
-                            .note(&format!("either implement a trait on it or create a newtype \
-                                            to wrap it instead"))
-                            .emit();
-                        return;
-                    }
-                }
-            }
             hir::ItemImpl(.., Some(_), _, _) => {
                 // "Trait" impl
                 debug!("coherence2::orphan check: trait impl {}",
@@ -311,7 +106,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
                        trait_def_id,
                        self.tcx.trait_has_default_impl(trait_def_id));
                 if self.tcx.trait_has_default_impl(trait_def_id) &&
-                   trait_def_id.krate != LOCAL_CRATE {
+                   !trait_def_id.is_local() {
                     let self_ty = trait_ref.self_ty();
                     let opt_self_def_id = match self_ty.sty {
                         ty::TyAdt(self_def, _) => Some(self_def.did),
@@ -346,31 +141,13 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
                         return;
                     }
                 }
-
-                // Disallow *all* explicit impls of `Sized` and `Unsize` for now.
-                if Some(trait_def_id) == self.tcx.lang_items.sized_trait() {
-                    struct_span_err!(self.tcx.sess,
-                                     item.span,
-                                     E0322,
-                                     "explicit impls for the `Sized` trait are not permitted")
-                        .span_label(item.span, &format!("impl of 'Sized' not allowed"))
-                        .emit();
-                    return;
-                }
-                if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() {
-                    span_err!(self.tcx.sess,
-                              item.span,
-                              E0328,
-                              "explicit impls for the `Unsize` trait are not permitted");
-                    return;
-                }
             }
             hir::ItemDefaultImpl(_, ref item_trait_ref) => {
                 // "Trait" impl
                 debug!("coherence2::orphan check: default trait impl {}",
                        self.tcx.hir.node_to_string(item.id));
                 let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
-                if trait_ref.def_id.krate != LOCAL_CRATE {
+                if !trait_ref.def_id.is_local() {
                     struct_span_err!(self.tcx.sess,
                                      item_trait_ref.path.span,
                                      E0318,
diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs
index 56c17dc2f6e..d334d0c4338 100644
--- a/src/librustc_typeck/coherence/overlap.rs
+++ b/src/librustc_typeck/coherence/overlap.rs
@@ -12,102 +12,101 @@
 //! same type. Likewise, no two inherent impls for a given type
 //! constructor provide a method with the same name.
 
-use hir::def_id::DefId;
-use rustc::traits::{self, Reveal};
+use rustc::traits;
 use rustc::ty::{self, TyCtxt, TypeFoldable};
 use syntax::ast;
 use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
-use util::nodemap::DefIdMap;
-use lint;
 
-pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    let mut overlap = OverlapChecker {
-        tcx: tcx,
-        default_impls: DefIdMap(),
-    };
+pub fn check_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    let mut overlap = OverlapChecker { tcx };
 
     // this secondary walk specifically checks for some other cases,
     // like defaulted traits, for which additional overlap rules exist
     tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
 }
 
-struct OverlapChecker<'cx, 'tcx: 'cx> {
-    tcx: TyCtxt<'cx, 'tcx, 'tcx>,
-
-    // maps from a trait def-id to an impl id
-    default_impls: DefIdMap<ast::NodeId>,
-}
+pub fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) {
+    let impl_def_id = tcx.hir.local_def_id(node_id);
+    let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+    let trait_def_id = trait_ref.def_id;
 
-impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
-    fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
-        #[derive(Copy, Clone, PartialEq)]
-        enum Namespace {
-            Type,
-            Value,
-        }
+    if trait_ref.references_error() {
+        debug!("coherence: skipping impl {:?} with error {:?}",
+               impl_def_id, trait_ref);
+        return
+    }
 
-        let name_and_namespace = |def_id| {
-            let item = self.tcx.associated_item(def_id);
-            (item.name, match item.kind {
-                ty::AssociatedKind::Type => Namespace::Type,
-                ty::AssociatedKind::Const |
-                ty::AssociatedKind::Method => Namespace::Value,
-            })
-        };
-
-        let impl_items1 = self.tcx.associated_item_def_ids(impl1);
-        let impl_items2 = self.tcx.associated_item_def_ids(impl2);
-
-        for &item1 in &impl_items1[..] {
-            let (name, namespace) = name_and_namespace(item1);
-
-            for &item2 in &impl_items2[..] {
-                if (name, namespace) == name_and_namespace(item2) {
-                    let msg = format!("duplicate definitions with name `{}`", name);
-                    let node_id = self.tcx.hir.as_local_node_id(item1).unwrap();
-                    self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
-                                           node_id,
-                                           self.tcx.span_of_impl(item1).unwrap(),
-                                           msg);
-                }
+    let _task =
+        tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
+
+    let def = tcx.lookup_trait_def(trait_def_id);
+
+    // attempt to insert into the specialization graph
+    let insert_result = def.add_impl_for_specialization(tcx, impl_def_id);
+
+    // insertion failed due to overlap
+    if let Err(overlap) = insert_result {
+        let mut err = struct_span_err!(tcx.sess,
+                                       tcx.span_of_impl(impl_def_id).unwrap(),
+                                       E0119,
+                                       "conflicting implementations of trait `{}`{}:",
+                                       overlap.trait_desc,
+                                       overlap.self_desc.clone().map_or(String::new(),
+                                                                        |ty| {
+            format!(" for type `{}`", ty)
+        }));
+
+        match tcx.span_of_impl(overlap.with_impl) {
+            Ok(span) => {
+                err.span_label(span, &format!("first implementation here"));
+                err.span_label(tcx.span_of_impl(impl_def_id).unwrap(),
+                               &format!("conflicting implementation{}",
+                                        overlap.self_desc
+                                            .map_or(String::new(),
+                                                    |ty| format!(" for `{}`", ty))));
+            }
+            Err(cname) => {
+                err.note(&format!("conflicting implementation in crate `{}`", cname));
             }
         }
+
+        err.emit();
     }
 
-    fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
-        let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id));
-
-        let inherent_impls = self.tcx.inherent_impls.borrow();
-        let impls = match inherent_impls.get(&ty_def_id) {
-            Some(impls) => impls,
-            None => return,
-        };
-
-        for (i, &impl1_def_id) in impls.iter().enumerate() {
-            for &impl2_def_id in &impls[(i + 1)..] {
-                self.tcx.infer_ctxt((), Reveal::ExactMatch).enter(|infcx| {
-                    if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
-                        self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
-                    }
-                });
+    // check for overlap with the automatic `impl Trait for Trait`
+    if let ty::TyDynamic(ref data, ..) = trait_ref.self_ty().sty {
+        // This is something like impl Trait1 for Trait2. Illegal
+        // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
+
+        if data.principal().map_or(true, |p| !tcx.is_object_safe(p.def_id())) {
+            // This is an error, but it will be reported by wfcheck.  Ignore it here.
+            // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
+        } else {
+            let mut supertrait_def_ids =
+                traits::supertrait_def_ids(tcx,
+                                           data.principal().unwrap().def_id());
+            if supertrait_def_ids.any(|d| d == trait_def_id) {
+                span_err!(tcx.sess,
+                          tcx.span_of_impl(impl_def_id).unwrap(),
+                          E0371,
+                          "the object type `{}` automatically \
+                           implements the trait `{}`",
+                          trait_ref.self_ty(),
+                          tcx.item_path_str(trait_def_id));
             }
         }
     }
 }
 
+struct OverlapChecker<'cx, 'tcx: 'cx> {
+    tcx: TyCtxt<'cx, 'tcx, 'tcx>,
+}
+
 impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &'v hir::Item) {
         match item.node {
-            hir::ItemEnum(..) |
-            hir::ItemStruct(..) |
-            hir::ItemTrait(..) |
-            hir::ItemUnion(..) => {
-                let type_def_id = self.tcx.hir.local_def_id(item.id);
-                self.check_for_overlapping_inherent_impls(type_def_id);
-            }
-
             hir::ItemDefaultImpl(..) => {
                 // look for another default impl; note that due to the
                 // general orphan/coherence rules, it must always be
@@ -115,8 +114,8 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
                 let impl_def_id = self.tcx.hir.local_def_id(item.id);
                 let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
 
-                let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
-                if let Some(prev_id) = prev_default_impl {
+                let prev_id = self.tcx.hir.trait_default_impl(trait_ref.def_id).unwrap();
+                if prev_id != item.id {
                     let mut err = struct_span_err!(self.tcx.sess,
                                                    self.tcx.span_of_impl(impl_def_id).unwrap(),
                                                    E0521,
@@ -131,76 +130,6 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
                 }
             }
             hir::ItemImpl(.., Some(_), _, _) => {
-                let impl_def_id = self.tcx.hir.local_def_id(item.id);
-                let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
-                let trait_def_id = trait_ref.def_id;
-
-                if trait_ref.references_error() {
-                    debug!("coherence: skipping impl {:?} with error {:?}",
-                           impl_def_id, trait_ref);
-                    return
-                }
-
-                let _task =
-                    self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
-
-                let def = self.tcx.lookup_trait_def(trait_def_id);
-
-                // attempt to insert into the specialization graph
-                let insert_result = def.add_impl_for_specialization(self.tcx, impl_def_id);
-
-                // insertion failed due to overlap
-                if let Err(overlap) = insert_result {
-                    let mut err = struct_span_err!(self.tcx.sess,
-                                                   self.tcx.span_of_impl(impl_def_id).unwrap(),
-                                                   E0119,
-                                                   "conflicting implementations of trait `{}`{}:",
-                                                   overlap.trait_desc,
-                                                   overlap.self_desc.clone().map_or(String::new(),
-                                                                                    |ty| {
-                        format!(" for type `{}`", ty)
-                    }));
-
-                    match self.tcx.span_of_impl(overlap.with_impl) {
-                        Ok(span) => {
-                            err.span_label(span, &format!("first implementation here"));
-                            err.span_label(self.tcx.span_of_impl(impl_def_id).unwrap(),
-                                           &format!("conflicting implementation{}",
-                                                    overlap.self_desc
-                                                        .map_or(String::new(),
-                                                                |ty| format!(" for `{}`", ty))));
-                        }
-                        Err(cname) => {
-                            err.note(&format!("conflicting implementation in crate `{}`", cname));
-                        }
-                    }
-
-                    err.emit();
-                }
-
-                // check for overlap with the automatic `impl Trait for Trait`
-                if let ty::TyDynamic(ref data, ..) = trait_ref.self_ty().sty {
-                    // This is something like impl Trait1 for Trait2. Illegal
-                    // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
-
-                    if data.principal().map_or(true, |p| !self.tcx.is_object_safe(p.def_id())) {
-                        // This is an error, but it will be reported by wfcheck.  Ignore it here.
-                        // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
-                    } else {
-                        let mut supertrait_def_ids =
-                            traits::supertrait_def_ids(self.tcx,
-                                                       data.principal().unwrap().def_id());
-                        if supertrait_def_ids.any(|d| d == trait_def_id) {
-                            span_err!(self.tcx.sess,
-                                      item.span,
-                                      E0371,
-                                      "the object type `{}` automatically \
-                                       implements the trait `{}`",
-                                      trait_ref.self_ty(),
-                                      self.tcx.item_path_str(trait_def_id));
-                        }
-                    }
-                }
             }
             _ => {}
         }
diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs
index 8c98e2952eb..22247d2531a 100644
--- a/src/librustc_typeck/coherence/unsafety.rs
+++ b/src/librustc_typeck/coherence/unsafety.rs
@@ -31,20 +31,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
                                 unsafety: hir::Unsafety,
                                 polarity: hir::ImplPolarity) {
         match self.tcx.impl_trait_ref(self.tcx.hir.local_def_id(item.id)) {
-            None => {
-                // Inherent impl.
-                match unsafety {
-                    hir::Unsafety::Normal => {
-                        // OK
-                    }
-                    hir::Unsafety::Unsafe => {
-                        span_err!(self.tcx.sess,
-                                  item.span,
-                                  E0197,
-                                  "inherent impls cannot be declared as unsafe");
-                    }
-                }
-            }
+            None => {}
 
             Some(trait_ref) => {
                 let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id);
@@ -100,7 +87,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> {
             hir::ItemDefaultImpl(unsafety, _) => {
                 self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive);
             }
-            hir::ItemImpl(unsafety, polarity, ref generics, ..) => {
+            hir::ItemImpl(unsafety, polarity, ref generics, Some(_), _, _) => {
                 self.check_unsafety_coherence(item, Some(generics), unsafety, polarity);
             }
             _ => {}
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 217405a81ec..7f413a0dfc3 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -47,10 +47,6 @@ item, we may need to compute the *type scheme* or *trait definition*
 for other items.
 
 There are some shortcomings in this design:
-
-- Before walking the set of supertraits for a given trait, you must
-  call `ensure_super_predicates` on that trait def-id. Otherwise,
-  `item_super_predicates` will result in ICEs.
 - Because the item generics include defaults, cycles through type
   parameter defaults are illegal even if those defaults are never
   employed. This is not necessarily a bug.
@@ -62,24 +58,26 @@ use lint;
 use constrained_type_params as ctp;
 use middle::lang_items::SizedTraitLangItem;
 use middle::const_val::ConstVal;
-use rustc_const_eval::EvalHint::UncheckedExprHint;
+use middle::resolve_lifetime as rl;
 use rustc_const_eval::{ConstContext, report_const_eval_err};
 use rustc::ty::subst::Substs;
-use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer, ReprOptions};
+use rustc::ty::{ToPredicate, ReprOptions};
 use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
+use rustc::ty::maps::Providers;
 use rustc::ty::util::IntTypeExt;
 use rustc::dep_graph::DepNode;
-use util::common::{ErrorReported, MemoizationMap};
+use util::common::MemoizationMap;
 use util::nodemap::{NodeMap, FxHashMap};
-use CrateCtxt;
 
 use rustc_const_math::ConstInt;
 
 use std::cell::RefCell;
+use std::collections::BTreeMap;
 
-use syntax::{abi, ast, attr};
+use syntax::{abi, ast};
+use syntax::codemap::Spanned;
 use syntax::symbol::{Symbol, keywords};
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
 
 use rustc::hir::{self, map as hir_map};
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
@@ -89,9 +87,23 @@ use rustc::hir::def_id::DefId;
 ///////////////////////////////////////////////////////////////////////////
 // Main entry point
 
-pub fn collect_item_types(ccx: &CrateCtxt) {
-    let mut visitor = CollectItemTypesVisitor { ccx: ccx };
-    ccx.tcx.visit_all_item_likes_in_krate(DepNode::CollectItem, &mut visitor.as_deep_visitor());
+pub fn collect_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    let mut visitor = CollectItemTypesVisitor { tcx: tcx };
+    tcx.visit_all_item_likes_in_krate(DepNode::CollectItem, &mut visitor.as_deep_visitor());
+}
+
+pub fn provide(providers: &mut Providers) {
+    *providers = Providers {
+        ty,
+        generics,
+        predicates,
+        super_predicates,
+        type_param_predicates,
+        trait_def,
+        adt_def,
+        impl_trait_ref,
+        ..*providers
+    };
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -102,29 +114,18 @@ pub fn collect_item_types(ccx: &CrateCtxt) {
 /// available in various different forms at various points in the
 /// process. So we can't just store a pointer to e.g. the AST or the
 /// parsed ty form, we have to be more flexible. To this end, the
-/// `ItemCtxt` is parameterized by a `GetTypeParameterBounds` object
-/// that it uses to satisfy `get_type_parameter_bounds` requests.
-/// This object might draw the information from the AST
-/// (`hir::Generics`) or it might draw from a `ty::GenericPredicates`
-/// or both (a tuple).
+/// `ItemCtxt` is parameterized by a `DefId` that it uses to satisfy
+/// `get_type_parameter_bounds` requests, drawing the information from
+/// the AST (`hir::Generics`), recursively.
 struct ItemCtxt<'a,'tcx:'a> {
-    ccx: &'a CrateCtxt<'a,'tcx>,
-    param_bounds: &'a (GetTypeParameterBounds<'tcx>+'a),
-}
-
-#[derive(Copy, Clone, PartialEq, Eq)]
-pub enum AstConvRequest {
-    GetGenerics(DefId),
-    GetItemTypeScheme(DefId),
-    GetTraitDef(DefId),
-    EnsureSuperPredicates(DefId),
-    GetTypeParameterBounds(ast::NodeId),
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    item_def_id: DefId,
 }
 
 ///////////////////////////////////////////////////////////////////////////
 
 struct CollectItemTypesVisitor<'a, 'tcx: 'a> {
-    ccx: &'a CrateCtxt<'a, 'tcx>
+    tcx: TyCtxt<'a, 'tcx, 'tcx>
 }
 
 impl<'a, 'tcx> CollectItemTypesVisitor<'a, 'tcx> {
@@ -168,9 +169,9 @@ impl<'a, 'tcx> CollectItemTypesVisitor<'a, 'tcx> {
     fn with_collect_item_sig<OP>(&self, id: ast::NodeId, op: OP)
         where OP: FnOnce()
     {
-        let def_id = self.ccx.tcx.hir.local_def_id(id);
-        self.ccx.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), || {
-            self.ccx.tcx.hir.read(id);
+        let def_id = self.tcx.hir.local_def_id(id);
+        self.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), || {
+            self.tcx.hir.read(id);
             op();
         });
     }
@@ -178,41 +179,52 @@ impl<'a, 'tcx> CollectItemTypesVisitor<'a, 'tcx> {
 
 impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.ccx.tcx.hir)
+        NestedVisitorMap::OnlyBodies(&self.tcx.hir)
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item) {
-        self.with_collect_item_sig(item.id, || convert_item(self.ccx, item));
+        self.with_collect_item_sig(item.id, || convert_item(self.tcx, item));
         intravisit::walk_item(self, item);
     }
 
+    fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
+        for param in &generics.ty_params {
+            if param.default.is_some() {
+                let def_id = self.tcx.hir.local_def_id(param.id);
+                self.tcx.item_type(def_id);
+            }
+        }
+        intravisit::walk_generics(self, generics);
+    }
+
     fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         if let hir::ExprClosure(..) = expr.node {
-            let def_id = self.ccx.tcx.hir.local_def_id(expr.id);
-            generics_of_def_id(self.ccx, def_id);
-            type_of_def_id(self.ccx, def_id);
+            let def_id = self.tcx.hir.local_def_id(expr.id);
+            self.tcx.item_generics(def_id);
+            self.tcx.item_type(def_id);
         }
         intravisit::walk_expr(self, expr);
     }
 
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
         if let hir::TyImplTrait(..) = ty.node {
-            let def_id = self.ccx.tcx.hir.local_def_id(ty.id);
-            generics_of_def_id(self.ccx, def_id);
+            let def_id = self.tcx.hir.local_def_id(ty.id);
+            self.tcx.item_generics(def_id);
+            self.tcx.item_predicates(def_id);
         }
         intravisit::walk_ty(self, ty);
     }
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
         self.with_collect_item_sig(trait_item.id, || {
-            convert_trait_item(self.ccx, trait_item)
+            convert_trait_item(self.tcx, trait_item)
         });
         intravisit::walk_trait_item(self, trait_item);
     }
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
         self.with_collect_item_sig(impl_item.id, || {
-            convert_impl_item(self.ccx, impl_item)
+            convert_impl_item(self.tcx, impl_item)
         });
         intravisit::walk_impl_item(self, impl_item);
     }
@@ -221,153 +233,13 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 // Utility types and common code for the above passes.
 
-impl<'a,'tcx> CrateCtxt<'a,'tcx> {
-    fn icx(&'a self, param_bounds: &'a GetTypeParameterBounds<'tcx>) -> ItemCtxt<'a,'tcx> {
+impl<'a, 'tcx> ItemCtxt<'a, 'tcx> {
+    fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId)
+           -> ItemCtxt<'a,'tcx> {
         ItemCtxt {
-            ccx: self,
-            param_bounds: param_bounds,
-        }
-    }
-
-    fn cycle_check<F,R>(&self,
-                        span: Span,
-                        request: AstConvRequest,
-                        code: F)
-                        -> Result<R,ErrorReported>
-        where F: FnOnce() -> Result<R,ErrorReported>
-    {
-        {
-            let mut stack = self.stack.borrow_mut();
-            if let Some((i, _)) = stack.iter().enumerate().rev().find(|&(_, r)| *r == request) {
-                let cycle = &stack[i..];
-                self.report_cycle(span, cycle);
-                return Err(ErrorReported);
-            }
-            stack.push(request);
+            tcx: tcx,
+            item_def_id: item_def_id,
         }
-
-        let result = code();
-
-        self.stack.borrow_mut().pop();
-        result
-    }
-
-    fn report_cycle(&self,
-                    span: Span,
-                    cycle: &[AstConvRequest])
-    {
-        assert!(!cycle.is_empty());
-        let tcx = self.tcx;
-
-        let mut err = struct_span_err!(tcx.sess, span, E0391,
-            "unsupported cyclic reference between types/traits detected");
-        err.span_label(span, &format!("cyclic reference"));
-
-        match cycle[0] {
-            AstConvRequest::GetGenerics(def_id) |
-            AstConvRequest::GetItemTypeScheme(def_id) |
-            AstConvRequest::GetTraitDef(def_id) => {
-                err.note(
-                    &format!("the cycle begins when processing `{}`...",
-                             tcx.item_path_str(def_id)));
-            }
-            AstConvRequest::EnsureSuperPredicates(def_id) => {
-                err.note(
-                    &format!("the cycle begins when computing the supertraits of `{}`...",
-                             tcx.item_path_str(def_id)));
-            }
-            AstConvRequest::GetTypeParameterBounds(id) => {
-                let def = tcx.type_parameter_def(id);
-                err.note(
-                    &format!("the cycle begins when computing the bounds \
-                              for type parameter `{}`...",
-                             def.name));
-            }
-        }
-
-        for request in &cycle[1..] {
-            match *request {
-                AstConvRequest::GetGenerics(def_id) |
-                AstConvRequest::GetItemTypeScheme(def_id) |
-                AstConvRequest::GetTraitDef(def_id) => {
-                    err.note(
-                        &format!("...which then requires processing `{}`...",
-                                 tcx.item_path_str(def_id)));
-                }
-                AstConvRequest::EnsureSuperPredicates(def_id) => {
-                    err.note(
-                        &format!("...which then requires computing the supertraits of `{}`...",
-                                 tcx.item_path_str(def_id)));
-                }
-                AstConvRequest::GetTypeParameterBounds(id) => {
-                    let def = tcx.type_parameter_def(id);
-                    err.note(
-                        &format!("...which then requires computing the bounds \
-                                  for type parameter `{}`...",
-                                 def.name));
-                }
-            }
-        }
-
-        match cycle[0] {
-            AstConvRequest::GetGenerics(def_id) |
-            AstConvRequest::GetItemTypeScheme(def_id) |
-            AstConvRequest::GetTraitDef(def_id) => {
-                err.note(
-                    &format!("...which then again requires processing `{}`, completing the cycle.",
-                             tcx.item_path_str(def_id)));
-            }
-            AstConvRequest::EnsureSuperPredicates(def_id) => {
-                err.note(
-                    &format!("...which then again requires computing the supertraits of `{}`, \
-                              completing the cycle.",
-                             tcx.item_path_str(def_id)));
-            }
-            AstConvRequest::GetTypeParameterBounds(id) => {
-                let def = tcx.type_parameter_def(id);
-                err.note(
-                    &format!("...which then again requires computing the bounds \
-                              for type parameter `{}`, completing the cycle.",
-                             def.name));
-            }
-        }
-        err.emit();
-    }
-
-    /// Loads the trait def for a given trait, returning ErrorReported if a cycle arises.
-    fn get_trait_def(&self, def_id: DefId)
-                     -> &'tcx ty::TraitDef
-    {
-        let tcx = self.tcx;
-
-        if let Some(trait_id) = tcx.hir.as_local_node_id(def_id) {
-            let item = match tcx.hir.get(trait_id) {
-                hir_map::NodeItem(item) => item,
-                _ => bug!("get_trait_def({:?}): not an item", trait_id)
-            };
-
-            generics_of_def_id(self, def_id);
-            trait_def_of_item(self, &item)
-        } else {
-            tcx.lookup_trait_def(def_id)
-        }
-    }
-
-    /// Ensure that the (transitive) super predicates for
-    /// `trait_def_id` are available. This will report a cycle error
-    /// if a trait `X` (transitively) extends itself in some form.
-    fn ensure_super_predicates(&self, span: Span, trait_def_id: DefId)
-                               -> Result<(), ErrorReported>
-    {
-        self.cycle_check(span, AstConvRequest::EnsureSuperPredicates(trait_def_id), || {
-            let def_ids = ensure_super_predicates_step(self, trait_def_id);
-
-            for def_id in def_ids {
-                self.ensure_super_predicates(span, def_id)?;
-            }
-
-            Ok(())
-        })
     }
 }
 
@@ -378,58 +250,18 @@ impl<'a,'tcx> ItemCtxt<'a,'tcx> {
 }
 
 impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { self.ccx.tcx }
+    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { self.tcx }
 
     fn ast_ty_to_ty_cache(&self) -> &RefCell<NodeMap<Ty<'tcx>>> {
-        &self.ccx.ast_ty_to_ty_cache
-    }
-
-    fn get_generics(&self, span: Span, id: DefId)
-                    -> Result<&'tcx ty::Generics<'tcx>, ErrorReported>
-    {
-        self.ccx.cycle_check(span, AstConvRequest::GetGenerics(id), || {
-            Ok(generics_of_def_id(self.ccx, id))
-        })
-    }
-
-    fn get_item_type(&self, span: Span, id: DefId) -> Result<Ty<'tcx>, ErrorReported> {
-        self.ccx.cycle_check(span, AstConvRequest::GetItemTypeScheme(id), || {
-            Ok(type_of_def_id(self.ccx, id))
-        })
-    }
-
-    fn get_trait_def(&self, span: Span, id: DefId)
-                     -> Result<&'tcx ty::TraitDef, ErrorReported>
-    {
-        self.ccx.cycle_check(span, AstConvRequest::GetTraitDef(id), || {
-            Ok(self.ccx.get_trait_def(id))
-        })
+        &self.tcx.ast_ty_to_ty_cache
     }
 
-    fn ensure_super_predicates(&self,
-                               span: Span,
-                               trait_def_id: DefId)
-                               -> Result<(), ErrorReported>
-    {
-        debug!("ensure_super_predicates(trait_def_id={:?})",
-               trait_def_id);
-
-        self.ccx.ensure_super_predicates(span, trait_def_id)
-    }
-
-
     fn get_type_parameter_bounds(&self,
                                  span: Span,
-                                 node_id: ast::NodeId)
-                                 -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>
+                                 def_id: DefId)
+                                 -> ty::GenericPredicates<'tcx>
     {
-        self.ccx.cycle_check(span, AstConvRequest::GetTypeParameterBounds(node_id), || {
-            let v = self.param_bounds.get_type_parameter_bounds(self, span, node_id)
-                                     .into_iter()
-                                     .filter_map(|p| p.to_opt_poly_trait_ref())
-                                     .collect();
-            Ok(v)
-        })
+        ty::queries::type_param_predicates::get(self.tcx, span, (self.item_def_id, def_id))
     }
 
     fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
@@ -483,120 +315,121 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
     }
 }
 
-/// Interface used to find the bounds on a type parameter from within
-/// an `ItemCtxt`. This allows us to use multiple kinds of sources.
-trait GetTypeParameterBounds<'tcx> {
-    fn get_type_parameter_bounds(&self,
-                                 astconv: &AstConv<'tcx, 'tcx>,
-                                 span: Span,
-                                 node_id: ast::NodeId)
-                                 -> Vec<ty::Predicate<'tcx>>;
-}
-
-/// Find bounds from both elements of the tuple.
-impl<'a,'b,'tcx,A,B> GetTypeParameterBounds<'tcx> for (&'a A,&'b B)
-    where A : GetTypeParameterBounds<'tcx>, B : GetTypeParameterBounds<'tcx>
-{
-    fn get_type_parameter_bounds(&self,
-                                 astconv: &AstConv<'tcx, 'tcx>,
-                                 span: Span,
-                                 node_id: ast::NodeId)
-                                 -> Vec<ty::Predicate<'tcx>>
-    {
-        let mut v = self.0.get_type_parameter_bounds(astconv, span, node_id);
-        v.extend(self.1.get_type_parameter_bounds(astconv, span, node_id));
-        v
-    }
-}
+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
+    // written inline like `<T:Foo>` or in a where clause like
+    // `where T:Foo`.
+
+    let param_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let param_owner = tcx.hir.ty_param_owner(param_id);
+    let param_owner_def_id = tcx.hir.local_def_id(param_owner);
+    let generics = tcx.item_generics(param_owner_def_id);
+    let index = generics.type_param_to_index[&def_id.index];
+    let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id));
+
+    // Don't look for bounds where the type parameter isn't in scope.
+    let parent = if item_def_id == param_owner_def_id {
+        None
+    } else {
+        tcx.item_generics(item_def_id).parent
+    };
 
-/// Empty set of bounds.
-impl<'tcx> GetTypeParameterBounds<'tcx> for () {
-    fn get_type_parameter_bounds(&self,
-                                 _astconv: &AstConv<'tcx, 'tcx>,
-                                 _span: Span,
-                                 _node_id: ast::NodeId)
-                                 -> Vec<ty::Predicate<'tcx>>
-    {
-        Vec::new()
-    }
-}
+    let mut result = parent.map_or(ty::GenericPredicates {
+        parent: None,
+        predicates: vec![]
+    }, |parent| {
+        let icx = ItemCtxt::new(tcx, parent);
+        icx.get_type_parameter_bounds(DUMMY_SP, def_id)
+    });
 
-/// Find bounds from the parsed and converted predicates.  This is
-/// used when converting methods, because by that time the predicates
-/// from the trait/impl have been fully converted.
-impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> {
-    fn get_type_parameter_bounds(&self,
-                                 astconv: &AstConv<'tcx, 'tcx>,
-                                 span: Span,
-                                 node_id: ast::NodeId)
-                                 -> Vec<ty::Predicate<'tcx>>
-    {
-        let def = astconv.tcx().type_parameter_def(node_id);
+    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) => {
+            match item.node {
+                TraitItemKind::Method(ref sig, _) => &sig.generics,
+                _ => return result
+            }
+        }
 
-        let mut results = self.parent.map_or(vec![], |def_id| {
-            let parent = astconv.tcx().item_predicates(def_id);
-            parent.get_type_parameter_bounds(astconv, span, node_id)
-        });
+        NodeImplItem(item) => {
+            match item.node {
+                ImplItemKind::Method(ref sig, _) => &sig.generics,
+                _ => return result
+            }
+        }
 
-        results.extend(self.predicates.iter().filter(|predicate| {
-            match **predicate {
-                ty::Predicate::Trait(ref data) => {
-                    data.skip_binder().self_ty().is_param(def.index)
-                }
-                ty::Predicate::TypeOutlives(ref data) => {
-                    data.skip_binder().0.is_param(def.index)
-                }
-                ty::Predicate::Equate(..) |
-                ty::Predicate::RegionOutlives(..) |
-                ty::Predicate::WellFormed(..) |
-                ty::Predicate::ObjectSafe(..) |
-                ty::Predicate::ClosureKind(..) |
-                ty::Predicate::Projection(..) => {
-                    false
+        NodeItem(item) => {
+            match item.node {
+                ItemFn(.., ref generics, _) |
+                ItemImpl(_, _, ref generics, ..) |
+                ItemTy(_, ref generics) |
+                ItemEnum(_, ref generics) |
+                ItemStruct(_, ref generics) |
+                ItemUnion(_, ref generics) => generics,
+                ItemTrait(_, ref generics, ..) => {
+                    // Implied `Self: Trait` and supertrait bounds.
+                    if param_id == item_node_id {
+                        result.predicates.push(ty::TraitRef {
+                            def_id: item_def_id,
+                            substs: Substs::identity_for_item(tcx, item_def_id)
+                        }.to_predicate());
+                    }
+                    generics
                 }
+                _ => return result
             }
-        }).cloned());
+        }
 
-        results
-    }
-}
+        NodeForeignItem(item) => {
+            match item.node {
+                ForeignItemFn(_, _, ref generics) => generics,
+                _ => return result
+            }
+        }
 
-/// Find bounds from hir::Generics. This requires scanning through the
-/// AST. We do this to avoid having to convert *all* the bounds, which
-/// would create artificial cycles. Instead we can only convert the
-/// bounds for a type parameter `X` if `X::Foo` is used.
-impl<'tcx> GetTypeParameterBounds<'tcx> for hir::Generics {
-    fn get_type_parameter_bounds(&self,
-                                 astconv: &AstConv<'tcx, 'tcx>,
-                                 _: Span,
-                                 node_id: ast::NodeId)
-                                 -> Vec<ty::Predicate<'tcx>>
-    {
-        // In the AST, bounds can derive from two places. Either
-        // written inline like `<T:Foo>` or in a where clause like
-        // `where T:Foo`.
+        _ => return result
+    };
 
-        let def = astconv.tcx().type_parameter_def(node_id);
-        let ty = astconv.tcx().mk_param_from_def(&def);
+    let icx = ItemCtxt::new(tcx, item_def_id);
+    result.predicates.extend(
+        icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty));
+    result
+}
 
+impl<'a, 'tcx> ItemCtxt<'a, 'tcx> {
+    /// Find bounds from hir::Generics. This requires scanning through the
+    /// AST. We do this to avoid having to convert *all* the bounds, which
+    /// would create artificial cycles. Instead we can only convert the
+    /// bounds for a type parameter `X` if `X::Foo` is used.
+    fn type_parameter_bounds_in_generics(&self,
+                                         ast_generics: &hir::Generics,
+                                         param_id: ast::NodeId,
+                                         ty: Ty<'tcx>)
+                                         -> Vec<ty::Predicate<'tcx>>
+    {
         let from_ty_params =
-            self.ty_params
+            ast_generics.ty_params
                 .iter()
-                .filter(|p| p.id == node_id)
+                .filter(|p| p.id == param_id)
                 .flat_map(|p| p.bounds.iter())
-                .flat_map(|b| predicates_from_bound(astconv, ty, b));
+                .flat_map(|b| predicates_from_bound(self, ty, b));
 
         let from_where_clauses =
-            self.where_clause
+            ast_generics.where_clause
                 .predicates
                 .iter()
                 .filter_map(|wp| match *wp {
                     hir::WherePredicate::BoundPredicate(ref bp) => Some(bp),
                     _ => None
                 })
-                .filter(|bp| is_param(astconv.tcx(), &bp.bounded_ty, node_id))
+                .filter(|bp| is_param(self.tcx, &bp.bounded_ty, param_id))
                 .flat_map(|bp| bp.bounds.iter())
-                .flat_map(|b| predicates_from_bound(astconv, ty, b));
+                .flat_map(|b| predicates_from_bound(self, ty, b));
 
         from_ty_params.chain(from_where_clauses).collect()
     }
@@ -624,76 +457,10 @@ fn is_param<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
-fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                           struct_generics: &'tcx ty::Generics<'tcx>,
-                           struct_predicates: &ty::GenericPredicates<'tcx>,
-                           field: &hir::StructField,
-                           ty_f: &'tcx ty::FieldDef)
-{
-    let tt = ccx.icx(struct_predicates).to_ty(&field.ty);
-    ccx.tcx.item_types.borrow_mut().insert(ty_f.did, tt);
-
-    let def_id = ccx.tcx.hir.local_def_id(field.id);
-    assert_eq!(def_id, ty_f.did);
-    ccx.tcx.generics.borrow_mut().insert(def_id, struct_generics);
-    ccx.tcx.predicates.borrow_mut().insert(def_id, struct_predicates.clone());
-}
-
-fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                            id: ast::NodeId,
-                            sig: &hir::MethodSig,
-                            rcvr_ty_predicates: &ty::GenericPredicates<'tcx>,) {
-    let def_id = ccx.tcx.hir.local_def_id(id);
-    let ty_generics = generics_of_def_id(ccx, def_id);
-
-    let ty_generic_predicates =
-        ty_generic_predicates(ccx, &sig.generics, ty_generics.parent, vec![], false);
-
-    let fty = AstConv::ty_of_fn(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
-                                sig.unsafety, sig.abi, &sig.decl);
-
-    let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
-                                ccx.tcx.hir.span(id), def_id);
-    let fty = ccx.tcx.mk_fn_def(def_id, substs, fty);
-    ccx.tcx.item_types.borrow_mut().insert(def_id, fty);
-    ccx.tcx.predicates.borrow_mut().insert(def_id, ty_generic_predicates);
-}
-
-fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                      container: AssociatedItemContainer,
-                                      id: ast::NodeId,
-                                      ty: ty::Ty<'tcx>)
-{
-    let predicates = ty::GenericPredicates {
-        parent: Some(container.id()),
-        predicates: vec![]
-    };
-    let def_id = ccx.tcx.hir.local_def_id(id);
-    ccx.tcx.predicates.borrow_mut().insert(def_id, predicates);
-    ccx.tcx.item_types.borrow_mut().insert(def_id, ty);
-}
-
-fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                     container: AssociatedItemContainer,
-                                     id: ast::NodeId,
-                                     ty: Option<Ty<'tcx>>)
-{
-    let predicates = ty::GenericPredicates {
-        parent: Some(container.id()),
-        predicates: vec![]
-    };
-    let def_id = ccx.tcx.hir.local_def_id(id);
-    ccx.tcx.predicates.borrow_mut().insert(def_id, predicates);
-
-    if let Some(ty) = ty {
-        ccx.tcx.item_types.borrow_mut().insert(def_id, ty);
-    }
-}
-
-fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
-                                 span: Span,
-                                 generics: &hir::Generics,
-                                 thing: &'static str) {
+fn ensure_no_ty_param_bounds(tcx: TyCtxt,
+                             span: Span,
+                             generics: &hir::Generics,
+                             thing: &'static str) {
     let mut warn = false;
 
     for ty_param in generics.ty_params.iter() {
@@ -722,256 +489,183 @@ fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
         // eventually accept these, but it will not be
         // part of this PR. Still, convert to warning to
         // make bootstrapping easier.
-        span_warn!(ccx.tcx.sess, span, E0122,
+        span_warn!(tcx.sess, span, E0122,
                    "trait bounds are not (yet) enforced \
                    in {} definitions",
                    thing);
     }
 }
 
-fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
-    let tcx = ccx.tcx;
+fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) {
     debug!("convert: item {} with id {}", it.name, it.id);
-    let def_id = ccx.tcx.hir.local_def_id(it.id);
+    let def_id = tcx.hir.local_def_id(it.id);
     match it.node {
         // These don't define types.
         hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemMod(_) => {
         }
         hir::ItemForeignMod(ref foreign_mod) => {
             for item in &foreign_mod.items {
-                convert_foreign_item(ccx, item);
+                let def_id = tcx.hir.local_def_id(item.id);
+                tcx.item_generics(def_id);
+                tcx.item_type(def_id);
+                tcx.item_predicates(def_id);
             }
         }
         hir::ItemEnum(ref enum_definition, _) => {
-            let ty = type_of_def_id(ccx, def_id);
-            let generics = generics_of_def_id(ccx, def_id);
-            let predicates = predicates_of_item(ccx, it);
-            convert_enum_variant_types(ccx,
-                                       tcx.lookup_adt_def(ccx.tcx.hir.local_def_id(it.id)),
-                                       ty,
-                                       generics,
-                                       predicates,
-                                       &enum_definition.variants);
+            tcx.item_generics(def_id);
+            tcx.item_type(def_id);
+            tcx.item_predicates(def_id);
+            convert_enum_variant_types(tcx, def_id, &enum_definition.variants);
         },
-        hir::ItemDefaultImpl(_, ref ast_trait_ref) => {
-            let trait_ref =
-                AstConv::instantiate_mono_trait_ref(&ccx.icx(&()),
-                                                    ast_trait_ref,
-                                                    tcx.mk_self_type());
-
-            tcx.record_trait_has_default_impl(trait_ref.def_id);
-
-            tcx.impl_trait_refs.borrow_mut().insert(ccx.tcx.hir.local_def_id(it.id),
-                                                    Some(trait_ref));
+        hir::ItemDefaultImpl(..) => {
+            tcx.impl_trait_ref(def_id);
         }
-        hir::ItemImpl(..,
-                      ref generics,
-                      ref opt_trait_ref,
-                      ref selfty,
-                      _) => {
-            // Create generics from the generics specified in the impl head.
-            debug!("convert: ast_generics={:?}", generics);
-            generics_of_def_id(ccx, def_id);
-            let mut ty_predicates =
-                ty_generic_predicates(ccx, generics, None, vec![], false);
-
-            debug!("convert: impl_bounds={:?}", ty_predicates);
-
-            let selfty = ccx.icx(&ty_predicates).to_ty(&selfty);
-            tcx.item_types.borrow_mut().insert(def_id, selfty);
-
-            let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| {
-                AstConv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
-                                                    ast_trait_ref,
-                                                    selfty)
-            });
-            tcx.impl_trait_refs.borrow_mut().insert(def_id, trait_ref);
-
-            // Subtle: before we store the predicates into the tcx, we
-            // sort them so that predicates like `T: Foo<Item=U>` come
-            // before uses of `U`.  This avoids false ambiguity errors
-            // in trait checking. See `setup_constraining_predicates`
-            // for details.
-            ctp::setup_constraining_predicates(&mut ty_predicates.predicates,
-                                               trait_ref,
-                                               &mut ctp::parameters_for_impl(selfty, trait_ref));
-
-            tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone());
+        hir::ItemImpl(..) => {
+            tcx.item_generics(def_id);
+            tcx.item_type(def_id);
+            tcx.impl_trait_ref(def_id);
+            tcx.item_predicates(def_id);
         },
         hir::ItemTrait(..) => {
-            generics_of_def_id(ccx, def_id);
-            trait_def_of_item(ccx, it);
-            let _: Result<(), ErrorReported> = // any error is already reported, can ignore
-                ccx.ensure_super_predicates(it.span, def_id);
-            convert_trait_predicates(ccx, it);
+            tcx.item_generics(def_id);
+            tcx.lookup_trait_def(def_id);
+            ty::queries::super_predicates::get(tcx, it.span, def_id);
+            tcx.item_predicates(def_id);
         },
         hir::ItemStruct(ref struct_def, _) |
         hir::ItemUnion(ref struct_def, _) => {
-            let ty = type_of_def_id(ccx, def_id);
-            let generics = generics_of_def_id(ccx, def_id);
-            let predicates = predicates_of_item(ccx, it);
-
-            let variant = tcx.lookup_adt_def(def_id).struct_variant();
-
-            for (f, ty_f) in struct_def.fields().iter().zip(variant.fields.iter()) {
-                convert_field(ccx, generics, &predicates, f, ty_f)
+            tcx.item_generics(def_id);
+            tcx.item_type(def_id);
+            tcx.item_predicates(def_id);
+
+            for f in struct_def.fields() {
+                let def_id = tcx.hir.local_def_id(f.id);
+                tcx.item_generics(def_id);
+                tcx.item_type(def_id);
+                tcx.item_predicates(def_id);
             }
 
             if !struct_def.is_struct() {
-                convert_variant_ctor(ccx, struct_def.id(), variant, ty, predicates);
+                convert_variant_ctor(tcx, struct_def.id());
             }
         },
         hir::ItemTy(_, ref generics) => {
-            ensure_no_ty_param_bounds(ccx, it.span, generics, "type");
-            type_of_def_id(ccx, def_id);
-            generics_of_def_id(ccx, def_id);
-            predicates_of_item(ccx, it);
+            ensure_no_ty_param_bounds(tcx, it.span, generics, "type");
+            tcx.item_generics(def_id);
+            tcx.item_type(def_id);
+            tcx.item_predicates(def_id);
         },
         _ => {
-            type_of_def_id(ccx, def_id);
-            generics_of_def_id(ccx, def_id);
-            predicates_of_item(ccx, it);
+            tcx.item_generics(def_id);
+            tcx.item_type(def_id);
+            tcx.item_predicates(def_id);
         },
     }
 }
 
-fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) {
-    let tcx = ccx.tcx;
-
-    // we can lookup details about the trait because items are visited
-    // before trait-items
-    let trait_def_id = tcx.hir.get_parent_did(trait_item.id);
-    let trait_predicates = tcx.item_predicates(trait_def_id);
+fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &hir::TraitItem) {
+    let def_id = tcx.hir.local_def_id(trait_item.id);
+    tcx.item_generics(def_id);
 
     match trait_item.node {
-        hir::TraitItemKind::Const(ref ty, _) => {
-            let const_def_id = ccx.tcx.hir.local_def_id(trait_item.id);
-            generics_of_def_id(ccx, const_def_id);
-            let ty = ccx.icx(&trait_predicates).to_ty(&ty);
-            convert_associated_const(ccx,
-                                     TraitContainer(trait_def_id),
-                                     trait_item.id,
-                                     ty);
+        hir::TraitItemKind::Const(..) |
+        hir::TraitItemKind::Type(_, Some(_)) |
+        hir::TraitItemKind::Method(..) => {
+            tcx.item_type(def_id);
         }
 
-        hir::TraitItemKind::Type(_, ref opt_ty) => {
-            let type_def_id = ccx.tcx.hir.local_def_id(trait_item.id);
-            generics_of_def_id(ccx, type_def_id);
-
-            let typ = opt_ty.as_ref().map({
-                |ty| ccx.icx(&trait_predicates).to_ty(&ty)
-            });
-
-            convert_associated_type(ccx, TraitContainer(trait_def_id), trait_item.id, typ);
-        }
+        hir::TraitItemKind::Type(_, None) => {}
+    };
 
-        hir::TraitItemKind::Method(ref sig, _) => {
-            convert_method(ccx, trait_item.id, sig, &trait_predicates);
-        }
-    }
+    tcx.item_predicates(def_id);
 }
 
-fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) {
-    let tcx = ccx.tcx;
-
-    // we can lookup details about the impl because items are visited
-    // before impl-items
-    let impl_def_id = tcx.hir.get_parent_did(impl_item.id);
-    let impl_predicates = tcx.item_predicates(impl_def_id);
-    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
-
-    match impl_item.node {
-        hir::ImplItemKind::Const(ref ty, _) => {
-            let const_def_id = ccx.tcx.hir.local_def_id(impl_item.id);
-            generics_of_def_id(ccx, const_def_id);
-            let ty = ccx.icx(&impl_predicates).to_ty(&ty);
-            convert_associated_const(ccx,
-                                     ImplContainer(impl_def_id),
-                                     impl_item.id,
-                                     ty);
-        }
-
-        hir::ImplItemKind::Type(ref ty) => {
-            let type_def_id = ccx.tcx.hir.local_def_id(impl_item.id);
-            generics_of_def_id(ccx, type_def_id);
-
-            if impl_trait_ref.is_none() {
-                span_err!(tcx.sess, impl_item.span, E0202,
-                          "associated types are not allowed in inherent impls");
-            }
-
-            let typ = ccx.icx(&impl_predicates).to_ty(ty);
-
-            convert_associated_type(ccx, ImplContainer(impl_def_id), impl_item.id, Some(typ));
-        }
-
-        hir::ImplItemKind::Method(ref sig, _) => {
-            convert_method(ccx, impl_item.id, sig, &impl_predicates);
-        }
-    }
+fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item: &hir::ImplItem) {
+    let def_id = tcx.hir.local_def_id(impl_item.id);
+    tcx.item_generics(def_id);
+    tcx.item_type(def_id);
+    tcx.item_predicates(def_id);
 }
 
-fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                  ctor_id: ast::NodeId,
-                                  variant: &'tcx ty::VariantDef,
-                                  ty: Ty<'tcx>,
-                                  predicates: ty::GenericPredicates<'tcx>) {
-    let tcx = ccx.tcx;
+fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                  ctor_id: ast::NodeId) {
     let def_id = tcx.hir.local_def_id(ctor_id);
-    generics_of_def_id(ccx, def_id);
-    let ctor_ty = match variant.ctor_kind {
-        CtorKind::Fictive | CtorKind::Const => ty,
-        CtorKind::Fn => {
-            let inputs = variant.fields.iter().map(|field| tcx.item_type(field.did));
-            let substs = mk_item_substs(&ccx.icx(&predicates), ccx.tcx.hir.span(ctor_id), def_id);
-            tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy {
-                unsafety: hir::Unsafety::Normal,
-                abi: abi::Abi::Rust,
-                sig: ty::Binder(ccx.tcx.mk_fn_sig(inputs, ty, false))
-            }))
-        }
-    };
-    tcx.item_types.borrow_mut().insert(def_id, ctor_ty);
-    tcx.predicates.borrow_mut().insert(tcx.hir.local_def_id(ctor_id), predicates);
+    tcx.item_generics(def_id);
+    tcx.item_type(def_id);
+    tcx.item_predicates(def_id);
 }
 
-fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                        def: &'tcx ty::AdtDef,
-                                        ty: Ty<'tcx>,
-                                        generics: &'tcx ty::Generics<'tcx>,
-                                        predicates: ty::GenericPredicates<'tcx>,
+fn evaluate_disr_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                body: hir::BodyId)
+                                -> Result<ConstVal<'tcx>, ()> {
+    let e = &tcx.hir.body(body).value;
+    ConstContext::new(tcx, body).eval(e).map_err(|err| {
+        // enum variant evaluation happens before the global constant check
+        // so we need to report the real error
+        report_const_eval_err(tcx, &err, e.span, "enum discriminant");
+    })
+}
+
+fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                        def_id: DefId,
                                         variants: &[hir::Variant]) {
-    // fill the field types
-    for (variant, ty_variant) in variants.iter().zip(def.variants.iter()) {
-        for (f, ty_f) in variant.node.data.fields().iter().zip(ty_variant.fields.iter()) {
-            convert_field(ccx, generics, &predicates, f, ty_f)
+    let def = tcx.lookup_adt_def(def_id);
+    let repr_type = def.repr.discr_type();
+    let initial = repr_type.initial_discriminant(tcx);
+    let mut prev_discr = None::<ConstInt>;
+
+    // fill the discriminant values and field types
+    for variant in variants {
+        let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr());
+        prev_discr = Some(if let Some(e) = variant.node.disr_expr {
+            let expr_did = tcx.hir.local_def_id(e.node_id);
+            let result = tcx.maps.monomorphic_const_eval.memoize(expr_did, || {
+                evaluate_disr_expr(tcx, e)
+            });
+
+            match result {
+                Ok(ConstVal::Integral(x)) => Some(x),
+                _ => None
+            }
+        } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {
+            Some(discr)
+        } else {
+            struct_span_err!(tcx.sess, variant.span, E0370,
+                             "enum discriminant overflowed")
+                .span_label(variant.span, &format!("overflowed on value after {}",
+                                                   prev_discr.unwrap()))
+                .note(&format!("explicitly set `{} = {}` if that is desired outcome",
+                               variant.node.name, wrapped_discr))
+                .emit();
+            None
+        }.unwrap_or(wrapped_discr));
+
+        for f in variant.node.data.fields() {
+            let def_id = tcx.hir.local_def_id(f.id);
+            tcx.item_generics(def_id);
+            tcx.item_type(def_id);
+            tcx.item_predicates(def_id);
         }
 
         // Convert the ctor, if any. This also registers the variant as
         // an item.
-        convert_variant_ctor(
-            ccx,
-            variant.node.data.id(),
-            ty_variant,
-            ty,
-            predicates.clone()
-        );
+        convert_variant_ctor(tcx, variant.node.data.id());
     }
 }
 
-fn convert_struct_variant<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn convert_struct_variant<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     did: DefId,
                                     name: ast::Name,
-                                    disr_val: ty::Disr,
+                                    discr: ty::VariantDiscr,
                                     def: &hir::VariantData)
                                     -> ty::VariantDef {
     let mut seen_fields: FxHashMap<ast::Name, Span> = FxHashMap();
-    let node_id = ccx.tcx.hir.as_local_node_id(did).unwrap();
+    let node_id = tcx.hir.as_local_node_id(did).unwrap();
     let fields = def.fields().iter().map(|f| {
-        let fid = ccx.tcx.hir.local_def_id(f.id);
+        let fid = tcx.hir.local_def_id(f.id);
         let dup_span = seen_fields.get(&f.name).cloned();
         if let Some(prev_span) = dup_span {
-            struct_span_err!(ccx.tcx.sess, f.span, E0124,
+            struct_span_err!(tcx.sess, f.span, E0124,
                              "field `{}` is already declared",
                              f.name)
                 .span_label(f.span, &"field already declared")
@@ -984,647 +678,524 @@ fn convert_struct_variant<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         ty::FieldDef {
             did: fid,
             name: f.name,
-            vis: ty::Visibility::from_hir(&f.vis, node_id, ccx.tcx)
+            vis: ty::Visibility::from_hir(&f.vis, node_id, tcx)
         }
     }).collect();
     ty::VariantDef {
         did: did,
         name: name,
-        disr_val: disr_val,
+        discr: discr,
         fields: fields,
         ctor_kind: CtorKind::from_hir(def),
     }
 }
 
-fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                it: &hir::Item,
-                                def: &hir::VariantData)
-                                -> &'tcx ty::AdtDef
-{
-    let did = ccx.tcx.hir.local_def_id(it.id);
-    // Use separate constructor id for unit/tuple structs and reuse did for braced structs.
-    let ctor_id = if !def.is_struct() { Some(ccx.tcx.hir.local_def_id(def.id())) } else { None };
-    let variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name, 0, def)];
-    let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Struct, None, variants,
-        ReprOptions::new(&ccx.tcx, did));
-    if let Some(ctor_id) = ctor_id {
-        // Make adt definition available through constructor id as well.
-        ccx.tcx.adt_defs.borrow_mut().insert(ctor_id, adt);
-    }
+fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                     def_id: DefId)
+                     -> &'tcx ty::AdtDef {
+    use rustc::hir::map::*;
+    use rustc::hir::*;
 
-    ccx.tcx.adt_defs.borrow_mut().insert(did, adt);
-    adt
-}
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let item = match tcx.hir.get(node_id) {
+        NodeItem(item) => item,
 
-fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                it: &hir::Item,
-                                def: &hir::VariantData)
-                                -> &'tcx ty::AdtDef
-{
-    let did = ccx.tcx.hir.local_def_id(it.id);
-    let variants = vec![convert_struct_variant(ccx, did, it.name, 0, def)];
-    let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, None, variants,
-                                    ReprOptions::new(&ccx.tcx, did));
-    ccx.tcx.adt_defs.borrow_mut().insert(did, adt);
-    adt
-}
+        // Make adt definition available through constructor id as well.
+        NodeStructCtor(_) => {
+            return tcx.lookup_adt_def(tcx.hir.get_parent_did(node_id));
+        }
 
-fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, body: hir::BodyId)
-                      -> Option<ConstInt> {
-    let e = &ccx.tcx.hir.body(body).value;
-    debug!("disr expr, checking {}", ccx.tcx.hir.node_to_pretty_string(e.id));
-
-    let ty_hint = repr_ty.to_ty(ccx.tcx);
-    let print_err = |cv: ConstVal| {
-        struct_span_err!(ccx.tcx.sess, e.span, E0079, "mismatched types")
-            .note_expected_found(&"type", &ty_hint, &format!("{}", cv.description()))
-            .span_label(e.span, &format!("expected '{}' type", ty_hint))
-            .emit();
+        _ => bug!()
     };
 
-    let hint = UncheckedExprHint(ty_hint);
-    match ConstContext::new(ccx.tcx, body).eval(e, hint) {
-        Ok(ConstVal::Integral(i)) => {
-            // FIXME: eval should return an error if the hint does not match the type of the body.
-            // i.e. eventually the match below would not exist.
-            match (repr_ty, i) {
-                (attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) |
-                (attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) |
-                (attr::SignedInt(ast::IntTy::I32), ConstInt::I32(_)) |
-                (attr::SignedInt(ast::IntTy::I64), ConstInt::I64(_)) |
-                (attr::SignedInt(ast::IntTy::I128), ConstInt::I128(_)) |
-                (attr::SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) |
-                (attr::UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) |
-                (attr::UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) |
-                (attr::UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) |
-                (attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) |
-                (attr::UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) |
-                (attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) =>
-                    Some(i),
-                (_, i) => {
-                    print_err(ConstVal::Integral(i));
-                    None
-                },
-            }
-        },
-        Ok(cv) => {
-            print_err(cv);
-            None
-        },
-        // enum variant evaluation happens before the global constant check
-        // so we need to report the real error
-        Err(err) => {
-            let mut diag = report_const_eval_err(
-                ccx.tcx, &err, e.span, "enum discriminant");
-            diag.emit();
-            None
+    let repr = ReprOptions::new(tcx, def_id);
+    let (kind, variants) = match item.node {
+        ItemEnum(ref def, _) => {
+            let mut distance_from_explicit = 0;
+            (AdtKind::Enum, def.variants.iter().map(|v| {
+                let did = tcx.hir.local_def_id(v.node.data.id());
+                let discr = if let Some(e) = v.node.disr_expr {
+                    distance_from_explicit = 0;
+                    ty::VariantDiscr::Explicit(tcx.hir.local_def_id(e.node_id))
+                } else {
+                    ty::VariantDiscr::Relative(distance_from_explicit)
+                };
+                distance_from_explicit += 1;
+
+                convert_struct_variant(tcx, did, v.node.name, discr, &v.node.data)
+            }).collect())
         }
-    }
-}
-
-fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                              it: &hir::Item,
-                              def: &hir::EnumDef)
-                              -> &'tcx ty::AdtDef
-{
-    let tcx = ccx.tcx;
-    let did = tcx.hir.local_def_id(it.id);
-    let repr_hints = tcx.lookup_repr_hints(did);
-    let repr_type = tcx.enum_repr_type(repr_hints.get(0));
-    let initial = ConstInt::new_inttype(repr_type.initial_discriminant(tcx), repr_type,
-                                        tcx.sess.target.uint_type, tcx.sess.target.int_type)
-        .unwrap();
-    let mut prev_disr = None::<ConstInt>;
-    let variants = def.variants.iter().map(|v| {
-        let wrapped_disr = prev_disr.map_or(initial, |d| d.wrap_incr());
-        let disr = if let Some(e) = v.node.disr_expr {
-            // FIXME: i128 discriminants
-            evaluate_disr_expr(ccx, repr_type, e)
-        } else if let Some(disr) = prev_disr.map_or(Some(initial),
-                                                    |v| (v + ConstInt::Infer(1)).ok()) {
-            Some(disr)
-        } else {
-            struct_span_err!(tcx.sess, v.span, E0370,
-                             "enum discriminant overflowed")
-                .span_label(v.span, &format!("overflowed on value after {}", prev_disr.unwrap()))
-                .note(&format!("explicitly set `{} = {}` if that is desired outcome",
-                               v.node.name, wrapped_disr))
-                .emit();
-            None
-        }.unwrap_or(wrapped_disr);
-        prev_disr = Some(disr);
-        let did = tcx.hir.local_def_id(v.node.data.id());
-        convert_struct_variant(ccx, did, v.node.name, disr.to_u128_unchecked(), &v.node.data)
-    }).collect();
-    let adt = tcx.alloc_adt_def(did, AdtKind::Enum, Some(repr_type), variants,
-                                ReprOptions::new(&ccx.tcx, did));
-    tcx.adt_defs.borrow_mut().insert(did, adt);
-    adt
+        ItemStruct(ref def, _) => {
+            // Use separate constructor id for unit/tuple structs and reuse did for braced structs.
+            let ctor_id = if !def.is_struct() {
+                Some(tcx.hir.local_def_id(def.id()))
+            } else {
+                None
+            };
+            (AdtKind::Struct, vec![
+                convert_struct_variant(tcx, ctor_id.unwrap_or(def_id), item.name,
+                                       ty::VariantDiscr::Relative(0), def)
+            ])
+        }
+        ItemUnion(ref def, _) => {
+            (AdtKind::Union, vec![
+                convert_struct_variant(tcx, def_id, item.name,
+                                       ty::VariantDiscr::Relative(0), def)
+            ])
+        }
+        _ => bug!()
+    };
+    tcx.alloc_adt_def(def_id, kind, variants, repr)
 }
 
 /// Ensures that the super-predicates of the trait with def-id
-/// trait_def_id are converted and stored. This does NOT ensure that
-/// the transitive super-predicates are converted; that is the job of
-/// the `ensure_super_predicates()` method in the `AstConv` impl
-/// above. Returns a list of trait def-ids that must be ensured as
-/// well to guarantee that the transitive superpredicates are
-/// converted.
-fn ensure_super_predicates_step(ccx: &CrateCtxt,
-                                trait_def_id: DefId)
-                                -> Vec<DefId>
-{
-    let tcx = ccx.tcx;
-
-    debug!("ensure_super_predicates_step(trait_def_id={:?})", trait_def_id);
+/// trait_def_id are converted and stored. This also ensures that
+/// the transitive super-predicates are converted;
+fn super_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                              trait_def_id: DefId)
+                              -> ty::GenericPredicates<'tcx> {
+    debug!("super_predicates(trait_def_id={:?})", trait_def_id);
+    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,
+        _ => bug!("trait_node_id {} is not an item", trait_node_id)
+    };
 
-    let trait_node_id = if let Some(n) = tcx.hir.as_local_node_id(trait_def_id) {
-        n
-    } else {
-        // If this trait comes from an external crate, then all of the
-        // supertraits it may depend on also must come from external
-        // crates, and hence all of them already have their
-        // super-predicates "converted" (and available from crate
-        // meta-data), so there is no need to transitively test them.
-        return Vec::new();
+    let (generics, bounds) = match item.node {
+        hir::ItemTrait(_, ref generics, ref supertraits, _) => (generics, supertraits),
+        _ => span_bug!(item.span,
+                       "super_predicates invoked on non-trait"),
     };
 
-    let superpredicates = tcx.super_predicates.borrow().get(&trait_def_id).cloned();
-    let superpredicates = superpredicates.unwrap_or_else(|| {
-        let item = match ccx.tcx.hir.get(trait_node_id) {
-            hir_map::NodeItem(item) => item,
-            _ => bug!("trait_node_id {} is not an item", trait_node_id)
-        };
+    let icx = ItemCtxt::new(tcx, trait_def_id);
 
-        let (generics, bounds) = match item.node {
-            hir::ItemTrait(_, ref generics, ref supertraits, _) => (generics, supertraits),
-            _ => span_bug!(item.span,
-                           "ensure_super_predicates_step invoked on non-trait"),
-        };
+    // Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`.
+    let self_param_ty = tcx.mk_self_type();
+    let superbounds1 = compute_bounds(&icx,
+                                      self_param_ty,
+                                      bounds,
+                                      SizedByDefault::No,
+                                      item.span);
 
-        // In-scope when converting the superbounds for `Trait` are
-        // that `Self:Trait` as well as any bounds that appear on the
-        // generic types:
-        generics_of_def_id(ccx, trait_def_id);
-        trait_def_of_item(ccx, item);
-        let trait_ref = ty::TraitRef {
-            def_id: trait_def_id,
-            substs: Substs::identity_for_item(tcx, trait_def_id)
-        };
-        let self_predicate = ty::GenericPredicates {
-            parent: None,
-            predicates: vec![trait_ref.to_predicate()]
-        };
-        let scope = &(generics, &self_predicate);
-
-        // Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`.
-        let self_param_ty = tcx.mk_self_type();
-        let superbounds1 = compute_bounds(&ccx.icx(scope),
-                                          self_param_ty,
-                                          bounds,
-                                          SizedByDefault::No,
-                                          item.span);
-
-        let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
-
-        // Convert any explicit superbounds in the where clause,
-        // e.g. `trait Foo where Self : Bar`:
-        let superbounds2 = generics.get_type_parameter_bounds(&ccx.icx(scope), item.span, item.id);
-
-        // Combine the two lists to form the complete set of superbounds:
-        let superbounds = superbounds1.into_iter().chain(superbounds2).collect();
-        let superpredicates = ty::GenericPredicates {
-            parent: None,
-            predicates: superbounds
-        };
-        debug!("superpredicates for trait {:?} = {:?}",
-               tcx.hir.local_def_id(item.id),
-               superpredicates);
+    let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
 
-        tcx.super_predicates.borrow_mut().insert(trait_def_id, superpredicates.clone());
+    // Convert any explicit superbounds in the where clause,
+    // e.g. `trait Foo where Self : Bar`:
+    let superbounds2 = icx.type_parameter_bounds_in_generics(generics, item.id, self_param_ty);
 
-        superpredicates
-    });
+    // Combine the two lists to form the complete set of superbounds:
+    let superbounds: Vec<_> = superbounds1.into_iter().chain(superbounds2).collect();
+
+    // Now require that immediate supertraits are converted,
+    // which will, in turn, reach indirect supertraits.
+    for bound in superbounds.iter().filter_map(|p| p.to_opt_poly_trait_ref()) {
+        ty::queries::super_predicates::get(tcx, item.span, bound.def_id());
+    }
+
+    ty::GenericPredicates {
+        parent: None,
+        predicates: superbounds
+    }
+}
+
+fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                       def_id: DefId)
+                       -> &'tcx ty::TraitDef {
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let item = tcx.hir.expect_item(node_id);
+
+    let unsafety = match item.node {
+        hir::ItemTrait(unsafety, ..) => unsafety,
+        _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
+    };
+
+    let paren_sugar = tcx.has_attr(def_id, "rustc_paren_sugar");
+    if paren_sugar && !tcx.sess.features.borrow().unboxed_closures {
+        let mut err = tcx.sess.struct_span_err(
+            item.span,
+            "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \
+             which traits can use parenthetical notation");
+        help!(&mut err,
+            "add `#![feature(unboxed_closures)]` to \
+             the crate attributes to use it");
+        err.emit();
+    }
 
-    let def_ids: Vec<_> = superpredicates.predicates
-                                         .iter()
-                                         .filter_map(|p| p.to_opt_poly_trait_ref())
-                                         .map(|tr| tr.def_id())
-                                         .collect();
+    let def_path_hash = tcx.def_path(def_id).deterministic_hash(tcx);
+    let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, def_path_hash);
 
-    debug!("ensure_super_predicates_step: def_ids={:?}", def_ids);
+    if tcx.hir.trait_is_auto(def_id) {
+        def.record_has_default_impl();
+    }
 
-    def_ids
+    tcx.alloc_trait_def(def)
 }
 
-fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) -> &'tcx ty::TraitDef {
-    let def_id = ccx.tcx.hir.local_def_id(it.id);
-    let tcx = ccx.tcx;
+fn generics<'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(_) => {
+            let parent_id = tcx.hir.get_parent(node_id);
+            Some(tcx.hir.local_def_id(parent_id))
+        }
+        NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
+            Some(tcx.closure_base_def_id(def_id))
+        }
+        NodeTy(&hir::Ty { node: hir::TyImplTrait(..), .. }) => {
+            let mut parent_id = node_id;
+            loop {
+                match tcx.hir.get(parent_id) {
+                    NodeItem(_) | NodeImplItem(_) | NodeTraitItem(_) => break,
+                    _ => {
+                        parent_id = tcx.hir.get_parent_node(parent_id);
+                    }
+                }
+            }
+            Some(tcx.hir.local_def_id(parent_id))
+        }
+        _ => None
+    };
 
-    tcx.trait_defs.memoize(def_id, || {
-        let unsafety = match it.node {
-            hir::ItemTrait(unsafety, ..) => unsafety,
-            _ => span_bug!(it.span, "trait_def_of_item invoked on non-trait"),
-        };
+    let mut opt_self = None;
+    let mut allow_defaults = false;
 
-        let paren_sugar = tcx.has_attr(def_id, "rustc_paren_sugar");
-        if paren_sugar && !ccx.tcx.sess.features.borrow().unboxed_closures {
-            let mut err = ccx.tcx.sess.struct_span_err(
-                it.span,
-                "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \
-                which traits can use parenthetical notation");
-            help!(&mut err,
-                "add `#![feature(unboxed_closures)]` to \
-                the crate attributes to use it");
-            err.emit();
+    let no_generics = hir::Generics::empty();
+    let ast_generics = match node {
+        NodeTraitItem(item) => {
+            match item.node {
+                TraitItemKind::Method(ref sig, _) => &sig.generics,
+                _ => &no_generics
+            }
         }
 
-        let def_path_hash = tcx.def_path(def_id).deterministic_hash(tcx);
-        tcx.alloc_trait_def(ty::TraitDef::new(def_id, unsafety, paren_sugar, def_path_hash))
-    })
-}
+        NodeImplItem(item) => {
+            match item.node {
+                ImplItemKind::Method(ref sig, _) => &sig.generics,
+                _ => &no_generics
+            }
+        }
 
-fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) {
-    let tcx = ccx.tcx;
+        NodeItem(item) => {
+            match item.node {
+                ItemFn(.., ref generics, _) |
+                ItemImpl(_, _, ref generics, ..) => generics,
+
+                ItemTy(_, ref generics) |
+                ItemEnum(_, ref generics) |
+                ItemStruct(_, ref generics) |
+                ItemUnion(_, ref generics) => {
+                    allow_defaults = true;
+                    generics
+                }
 
-    let def_id = ccx.tcx.hir.local_def_id(it.id);
+                ItemTrait(_, ref generics, ..) => {
+                    // Add in the self type parameter.
+                    //
+                    // Something of a hack: use the node id for the trait, also as
+                    // the node id for the Self type parameter.
+                    let param_id = item.id;
+
+                    opt_self = Some(ty::TypeParameterDef {
+                        index: 0,
+                        name: keywords::SelfType.name(),
+                        def_id: tcx.hir.local_def_id(param_id),
+                        has_default: false,
+                        object_lifetime_default: rl::Set1::Empty,
+                        pure_wrt_drop: false,
+                    });
+
+                    allow_defaults = true;
+                    generics
+                }
 
-    generics_of_def_id(ccx, def_id);
-    trait_def_of_item(ccx, it);
+                _ => &no_generics
+            }
+        }
 
-    let (generics, items) = match it.node {
-        hir::ItemTrait(_, ref generics, _, ref items) => (generics, items),
-        ref s => {
-            span_bug!(
-                it.span,
-                "trait_def_of_item invoked on {:?}",
-                s);
+        NodeForeignItem(item) => {
+            match item.node {
+                ForeignItemStatic(..) => &no_generics,
+                ForeignItemFn(_, _, ref generics) => generics
+            }
         }
+
+        _ => &no_generics
     };
 
-    let super_predicates = ccx.tcx.item_super_predicates(def_id);
+    let has_self = opt_self.is_some();
+    let mut parent_has_self = false;
+    let mut own_start = has_self as u32;
+    let (parent_regions, parent_types) = parent_def_id.map_or((0, 0), |def_id| {
+        let generics = tcx.item_generics(def_id);
+        assert_eq!(has_self, false);
+        parent_has_self = generics.has_self;
+        own_start = generics.count() as u32;
+        (generics.parent_regions + generics.regions.len() as u32,
+            generics.parent_types + generics.types.len() as u32)
+    });
 
-    // `ty_generic_predicates` below will consider the bounds on the type
-    // parameters (including `Self`) and the explicit where-clauses,
-    // but to get the full set of predicates on a trait we need to add
-    // in the supertrait bounds and anything declared on the
-    // associated types.
-    let mut base_predicates = super_predicates.predicates;
+    let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
+    let regions = early_lifetimes.enumerate().map(|(i, l)| {
+        let issue_32330 = tcx.named_region_map.issue_32330.get(&l.lifetime.id).cloned();
+        ty::RegionParameterDef {
+            name: l.lifetime.name,
+            index: own_start + i as u32,
+            def_id: tcx.hir.local_def_id(l.lifetime.id),
+            pure_wrt_drop: l.pure_wrt_drop,
+            issue_32330: issue_32330,
+        }
+    }).collect::<Vec<_>>();
 
-    // Add in a predicate that `Self:Trait` (where `Trait` is the
-    // current trait).  This is needed for builtin bounds.
-    let trait_ref = ty::TraitRef {
-        def_id: def_id,
-        substs: Substs::identity_for_item(tcx, def_id)
-    };
-    let self_predicate = trait_ref.to_poly_trait_ref().to_predicate();
-    base_predicates.push(self_predicate);
-
-    // add in the explicit where-clauses
-    let mut trait_predicates =
-        ty_generic_predicates(ccx, generics, None, base_predicates, true);
-
-    let assoc_predicates = predicates_for_associated_types(ccx,
-                                                           generics,
-                                                           &trait_predicates,
-                                                           trait_ref,
-                                                           items);
-    trait_predicates.predicates.extend(assoc_predicates);
-
-    tcx.predicates.borrow_mut().insert(def_id, trait_predicates);
-    return;
-
-    fn predicates_for_associated_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                                 ast_generics: &hir::Generics,
-                                                 trait_predicates: &ty::GenericPredicates<'tcx>,
-                                                 self_trait_ref: ty::TraitRef<'tcx>,
-                                                 trait_item_refs: &[hir::TraitItemRef])
-                                                 -> Vec<ty::Predicate<'tcx>>
-    {
-        trait_item_refs.iter().flat_map(|trait_item_ref| {
-            let trait_item = ccx.tcx.hir.trait_item(trait_item_ref.id);
-            let bounds = match trait_item.node {
-                hir::TraitItemKind::Type(ref bounds, _) => bounds,
-                _ => {
-                    return vec![].into_iter();
-                }
-            };
+    let object_lifetime_defaults =
+        tcx.named_region_map.object_lifetime_defaults.get(&node_id);
 
-            let assoc_ty = ccx.tcx.mk_projection(self_trait_ref,
-                                                 trait_item.name);
+    // Now create the real type parameters.
+    let type_start = own_start + regions.len() as u32;
+    let types = ast_generics.ty_params.iter().enumerate().map(|(i, p)| {
+        if p.name == keywords::SelfType.name() {
+            span_bug!(p.span, "`Self` should not be the name of a regular parameter");
+        }
 
-            let bounds = compute_bounds(&ccx.icx(&(ast_generics, trait_predicates)),
-                                        assoc_ty,
-                                        bounds,
-                                        SizedByDefault::Yes,
-                                        trait_item.span);
+        if !allow_defaults && p.default.is_some() {
+            if !tcx.sess.features.borrow().default_type_parameter_fallback {
+                tcx.sess.add_lint(
+                    lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
+                    p.id,
+                    p.span,
+                    format!("defaults for type parameters are only allowed in `struct`, \
+                             `enum`, `type`, or `trait` definitions."));
+            }
+        }
 
-            bounds.predicates(ccx.tcx, assoc_ty).into_iter()
-        }).collect()
+        ty::TypeParameterDef {
+            index: type_start + i as u32,
+            name: p.name,
+            def_id: tcx.hir.local_def_id(p.id),
+            has_default: p.default.is_some(),
+            object_lifetime_default:
+                object_lifetime_defaults.map_or(rl::Set1::Empty, |o| o[i]),
+            pure_wrt_drop: p.pure_wrt_drop,
+        }
+    });
+    let mut types: Vec<_> = opt_self.into_iter().chain(types).collect();
+
+    // 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 { node: hir::ExprClosure(..), .. }) = node {
+        tcx.with_freevars(node_id, |fv| {
+            types.extend(fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef {
+                index: type_start + i as u32,
+                name: Symbol::intern("<upvar>"),
+                def_id: def_id,
+                has_default: false,
+                object_lifetime_default: rl::Set1::Empty,
+                pure_wrt_drop: false,
+            }));
+        });
     }
+
+    let mut type_param_to_index = BTreeMap::new();
+    for param in &types {
+        type_param_to_index.insert(param.def_id.index, param.index);
+    }
+
+    tcx.alloc_generics(ty::Generics {
+        parent: parent_def_id,
+        parent_regions: parent_regions,
+        parent_types: parent_types,
+        regions: regions,
+        types: types,
+        type_param_to_index: type_param_to_index,
+        has_self: has_self || parent_has_self
+    })
 }
 
-fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                def_id: DefId)
-                                -> &'tcx ty::Generics<'tcx> {
-    let tcx = ccx.tcx;
-    let node_id = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
-        id
-    } else {
-        return tcx.item_generics(def_id);
-    };
-    tcx.generics.memoize(def_id, || {
-        use rustc::hir::map::*;
-        use rustc::hir::*;
-
-        let node = tcx.hir.get(node_id);
-        let parent_def_id = match node {
-            NodeImplItem(_) |
-            NodeTraitItem(_) |
-            NodeVariant(_) |
-            NodeStructCtor(_) => {
-                let parent_id = tcx.hir.get_parent(node_id);
-                Some(tcx.hir.local_def_id(parent_id))
-            }
-            NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
-                Some(tcx.closure_base_def_id(def_id))
-            }
-            NodeTy(&hir::Ty { node: hir::TyImplTrait(..), .. }) => {
-                let mut parent_id = node_id;
-                loop {
-                    match tcx.hir.get(parent_id) {
-                        NodeItem(_) | NodeImplItem(_) | NodeTraitItem(_) => break,
-                        _ => {
-                            parent_id = tcx.hir.get_parent_node(parent_id);
-                        }
-                    }
-                }
-                Some(tcx.hir.local_def_id(parent_id))
-            }
-            _ => None
-        };
+fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                def_id: DefId)
+                -> Ty<'tcx> {
+    use rustc::hir::map::*;
+    use rustc::hir::*;
 
-        let mut opt_self = None;
-        let mut allow_defaults = false;
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
 
-        let no_generics = hir::Generics::empty();
-        let ast_generics = match node {
-            NodeTraitItem(item) => {
-                match item.node {
-                    TraitItemKind::Method(ref sig, _) => &sig.generics,
-                    _ => &no_generics
-                }
-            }
+    let icx = ItemCtxt::new(tcx, def_id);
 
-            NodeImplItem(item) => {
-                match item.node {
-                    ImplItemKind::Method(ref sig, _) => &sig.generics,
-                    _ => &no_generics
+    match tcx.hir.get(node_id) {
+        NodeTraitItem(item) => {
+            match item.node {
+                TraitItemKind::Method(ref sig, _) => {
+                    let fty = AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl);
+                    let substs = Substs::identity_for_item(tcx, def_id);
+                    tcx.mk_fn_def(def_id, substs, fty)
+                }
+                TraitItemKind::Const(ref ty, _) |
+                TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
+                TraitItemKind::Type(_, None) => {
+                    span_bug!(item.span, "associated type missing default");
                 }
             }
+        }
 
-            NodeItem(item) => {
-                match item.node {
-                    ItemFn(.., ref generics, _) |
-                    ItemImpl(_, _, ref generics, ..) => generics,
-
-                    ItemTy(_, ref generics) |
-                    ItemEnum(_, ref generics) |
-                    ItemStruct(_, ref generics) |
-                    ItemUnion(_, ref generics) => {
-                        allow_defaults = true;
-                        generics
-                    }
-
-                    ItemTrait(_, ref generics, ..) => {
-                        // Add in the self type parameter.
-                        //
-                        // Something of a hack: use the node id for the trait, also as
-                        // the node id for the Self type parameter.
-                        let param_id = item.id;
-
-                        let parent = ccx.tcx.hir.get_parent(param_id);
-
-                        let def = ty::TypeParameterDef {
-                            index: 0,
-                            name: keywords::SelfType.name(),
-                            def_id: tcx.hir.local_def_id(param_id),
-                            default_def_id: tcx.hir.local_def_id(parent),
-                            default: None,
-                            pure_wrt_drop: false,
-                        };
-                        tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone());
-                        opt_self = Some(def);
-
-                        allow_defaults = true;
-                        generics
+        NodeImplItem(item) => {
+            match item.node {
+                ImplItemKind::Method(ref sig, _) => {
+                    let fty = AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl);
+                    let substs = Substs::identity_for_item(tcx, def_id);
+                    tcx.mk_fn_def(def_id, substs, fty)
+                }
+                ImplItemKind::Const(ref ty, _) => icx.to_ty(ty),
+                ImplItemKind::Type(ref ty) => {
+                    if tcx.impl_trait_ref(tcx.hir.get_parent_did(node_id)).is_none() {
+                        span_err!(tcx.sess, item.span, E0202,
+                                  "associated types are not allowed in inherent impls");
                     }
 
-                    _ => &no_generics
+                    icx.to_ty(ty)
                 }
             }
+        }
 
-            NodeForeignItem(item) => {
-                match item.node {
-                    ForeignItemStatic(..) => &no_generics,
-                    ForeignItemFn(_, _, ref generics) => generics
+        NodeItem(item) => {
+            match item.node {
+                ItemStatic(ref t, ..) | ItemConst(ref t, _) |
+                ItemTy(ref t, _) | ItemImpl(.., ref t, _) => {
+                    icx.to_ty(t)
+                }
+                ItemFn(ref decl, unsafety, _, abi, _, _) => {
+                    let tofd = AstConv::ty_of_fn(&icx, unsafety, abi, &decl);
+                    let substs = Substs::identity_for_item(tcx, def_id);
+                    tcx.mk_fn_def(def_id, substs, tofd)
+                }
+                ItemEnum(..) |
+                ItemStruct(..) |
+                ItemUnion(..) => {
+                    let def = tcx.lookup_adt_def(def_id);
+                    let substs = Substs::identity_for_item(tcx, def_id);
+                    tcx.mk_adt(def, substs)
+                }
+                ItemDefaultImpl(..) |
+                ItemTrait(..) |
+                ItemMod(..) |
+                ItemForeignMod(..) |
+                ItemExternCrate(..) |
+                ItemUse(..) => {
+                    span_bug!(
+                        item.span,
+                        "compute_type_of_item: unexpected item type: {:?}",
+                        item.node);
                 }
             }
+        }
 
-            _ => &no_generics
-        };
+        NodeForeignItem(foreign_item) => {
+            let abi = tcx.hir.get_foreign_abi(node_id);
 
-        let has_self = opt_self.is_some();
-        let mut parent_has_self = false;
-        let mut own_start = has_self as u32;
-        let (parent_regions, parent_types) = parent_def_id.map_or((0, 0), |def_id| {
-            let generics = generics_of_def_id(ccx, def_id);
-            assert_eq!(has_self, false);
-            parent_has_self = generics.has_self;
-            own_start = generics.count() as u32;
-            (generics.parent_regions + generics.regions.len() as u32,
-             generics.parent_types + generics.types.len() as u32)
-        });
+            match foreign_item.node {
+                ForeignItemFn(ref fn_decl, _, _) => {
+                    compute_type_of_foreign_fn_decl(tcx, def_id, fn_decl, abi)
+                }
+                ForeignItemStatic(ref t, _) => icx.to_ty(t)
+            }
+        }
 
-        let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics);
-        let regions = early_lifetimes.iter().enumerate().map(|(i, l)| {
-            let issue_32330 = ccx.tcx.named_region_map.issue_32330
-                                                      .get(&l.lifetime.id)
-                                                      .cloned();
-            ty::RegionParameterDef {
-                name: l.lifetime.name,
-                index: own_start + i as u32,
-                def_id: tcx.hir.local_def_id(l.lifetime.id),
-                pure_wrt_drop: l.pure_wrt_drop,
-                issue_32330: issue_32330,
+        NodeStructCtor(&ref def) |
+        NodeVariant(&Spanned { node: hir::Variant_ { data: ref def, .. }, .. }) => {
+            let ty = tcx.item_type(tcx.hir.get_parent_did(node_id));
+            match *def {
+                VariantData::Unit(..) | VariantData::Struct(..) => ty,
+                VariantData::Tuple(ref fields, _) => {
+                    let inputs = fields.iter().map(|f| {
+                        tcx.item_type(tcx.hir.local_def_id(f.id))
+                    });
+                    let substs = Substs::identity_for_item(tcx, def_id);
+                    tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig(
+                        inputs,
+                        ty,
+                        false,
+                        hir::Unsafety::Normal,
+                        abi::Abi::Rust
+                    )))
+                }
             }
-        }).collect::<Vec<_>>();
+        }
 
-        // Now create the real type parameters.
-        let type_start = own_start + regions.len() as u32;
-        let types = ast_generics.ty_params.iter().enumerate().map(|(i, p)| {
-            let i = type_start + i as u32;
-            get_or_create_type_parameter_def(ccx, i, p, allow_defaults)
-        });
-        let mut types: Vec<_> = opt_self.into_iter().chain(types).collect();
-
-        // 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 { node: hir::ExprClosure(..), .. }) = node {
-            tcx.with_freevars(node_id, |fv| {
-                types.extend(fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef {
-                    index: type_start + i as u32,
-                    name: Symbol::intern("<upvar>"),
-                    def_id: def_id,
-                    default_def_id: parent_def_id.unwrap(),
-                    default: None,
-                    pure_wrt_drop: false,
-               }));
-            });
+        NodeField(field) => icx.to_ty(&field.ty),
+
+        NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
+            tcx.mk_closure(def_id, Substs::for_item(
+                tcx, def_id,
+                |def, _| {
+                    let region = def.to_early_bound_region_data();
+                    tcx.mk_region(ty::ReEarlyBound(region))
+                },
+                |def, _| tcx.mk_param_from_def(def)
+            ))
         }
 
-        tcx.alloc_generics(ty::Generics {
-            parent: parent_def_id,
-            parent_regions: parent_regions,
-            parent_types: parent_types,
-            regions: regions,
-            types: types,
-            has_self: has_self || parent_has_self
-        })
-    })
-}
+        NodeExpr(_) => match tcx.hir.get(tcx.hir.get_parent_node(node_id)) {
+            NodeTy(&hir::Ty { node: TyArray(_, body), .. }) |
+            NodeExpr(&hir::Expr { node: ExprRepeat(_, body), .. })
+                if body.node_id == node_id => tcx.types.usize,
 
-fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                            def_id: DefId)
-                            -> Ty<'tcx> {
-    let node_id = if let Some(id) = ccx.tcx.hir.as_local_node_id(def_id) {
-        id
-    } else {
-        return ccx.tcx.item_type(def_id);
-    };
-    ccx.tcx.item_types.memoize(def_id, || {
-        use rustc::hir::map::*;
-        use rustc::hir::*;
-
-        // Alway bring in generics, as computing the type needs them.
-        generics_of_def_id(ccx, def_id);
-
-        let ty = match ccx.tcx.hir.get(node_id) {
-            NodeItem(item) => {
-                match item.node {
-                    ItemStatic(ref t, ..) | ItemConst(ref t, _) => {
-                        ccx.icx(&()).to_ty(&t)
-                    }
-                    ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
-                        let tofd = AstConv::ty_of_fn(&ccx.icx(generics), unsafety, abi, &decl);
-                        let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
-                        ccx.tcx.mk_fn_def(def_id, substs, tofd)
-                    }
-                    ItemTy(ref t, ref generics) => {
-                        ccx.icx(generics).to_ty(&t)
-                    }
-                    ItemEnum(ref ei, ref generics) => {
-                        let def = convert_enum_def(ccx, item, ei);
-                        let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
-                        ccx.tcx.mk_adt(def, substs)
-                    }
-                    ItemStruct(ref si, ref generics) => {
-                        let def = convert_struct_def(ccx, item, si);
-                        let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
-                        ccx.tcx.mk_adt(def, substs)
-                    }
-                    ItemUnion(ref un, ref generics) => {
-                        let def = convert_union_def(ccx, item, un);
-                        let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
-                        ccx.tcx.mk_adt(def, substs)
-                    }
-                    ItemDefaultImpl(..) |
-                    ItemTrait(..) |
-                    ItemImpl(..) |
-                    ItemMod(..) |
-                    ItemForeignMod(..) |
-                    ItemExternCrate(..) |
-                    ItemUse(..) => {
-                        span_bug!(
-                            item.span,
-                            "compute_type_of_item: unexpected item type: {:?}",
-                            item.node);
-                    }
+            NodeVariant(&Spanned { node: Variant_ { disr_expr: Some(e), .. }, .. })
+                if e.node_id == node_id => {
+                    tcx.lookup_adt_def(tcx.hir.get_parent_did(node_id))
+                        .repr.discr_type().to_ty(tcx)
                 }
-            }
-            NodeForeignItem(foreign_item) => {
-                let abi = ccx.tcx.hir.get_foreign_abi(node_id);
-
-                match foreign_item.node {
-                    ForeignItemFn(ref fn_decl, _, ref generics) => {
-                        compute_type_of_foreign_fn_decl(
-                            ccx, ccx.tcx.hir.local_def_id(foreign_item.id),
-                            fn_decl, generics, abi)
-                    }
-                    ForeignItemStatic(ref t, _) => {
-                        ccx.icx(&()).to_ty(t)
-                    }
-                }
-            }
-            NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
-                ccx.tcx.mk_closure(def_id, Substs::for_item(
-                    ccx.tcx, def_id,
-                    |def, _| {
-                        let region = def.to_early_bound_region_data();
-                        ccx.tcx.mk_region(ty::ReEarlyBound(region))
-                    },
-                    |def, _| ccx.tcx.mk_param_from_def(def)
-                ))
-            }
+
             x => {
-                bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
+                bug!("unexpected expr parent in type_of_def_id(): {:?}", x);
             }
-        };
-
-        ty
-    })
-}
-
-fn predicates_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                it: &hir::Item)
-                                -> ty::GenericPredicates<'tcx> {
-    let def_id = ccx.tcx.hir.local_def_id(it.id);
+        },
 
-    let no_generics = hir::Generics::empty();
-    let generics = match it.node {
-        hir::ItemFn(.., ref generics, _) |
-        hir::ItemTy(_, ref generics) |
-        hir::ItemEnum(_, ref generics) |
-        hir::ItemStruct(_, ref generics) |
-        hir::ItemUnion(_, ref generics) => generics,
-        _ => &no_generics
-    };
+        NodeTyParam(&hir::TyParam { default: Some(ref ty), .. }) => {
+            icx.to_ty(ty)
+        }
 
-    let predicates = ty_generic_predicates(ccx, generics, None, vec![], false);
-    ccx.tcx.predicates.borrow_mut().insert(def_id, predicates.clone());
+        NodeTy(&hir::Ty { node: TyImplTrait(..), .. }) => {
+            let owner = tcx.hir.get_parent_did(node_id);
+            tcx.item_tables(owner).node_id_to_type(node_id)
+        }
 
-    predicates
+        x => {
+            bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
+        }
+    }
 }
 
-fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                  it: &hir::ForeignItem)
-{
-    // For reasons I cannot fully articulate, I do so hate the AST
-    // map, and I regard each time that I use it as a personal and
-    // moral failing, but at the moment it seems like the only
-    // convenient way to extract the ABI. - ndm
-    let def_id = ccx.tcx.hir.local_def_id(it.id);
-    type_of_def_id(ccx, def_id);
-    generics_of_def_id(ccx, def_id);
-
-    let no_generics = hir::Generics::empty();
-    let generics = match it.node {
-        hir::ForeignItemFn(_, _, ref generics) => generics,
-        hir::ForeignItemStatic(..) => &no_generics
-    };
+fn impl_trait_ref<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                            def_id: DefId)
+                            -> Option<ty::TraitRef<'tcx>> {
+    let icx = ItemCtxt::new(tcx, def_id);
 
-    let predicates = ty_generic_predicates(ccx, generics, None, vec![], false);
-    ccx.tcx.predicates.borrow_mut().insert(def_id, predicates);
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    match tcx.hir.expect_item(node_id).node {
+        hir::ItemDefaultImpl(_, ref ast_trait_ref) => {
+            Some(AstConv::instantiate_mono_trait_ref(&icx,
+                                                     ast_trait_ref,
+                                                     tcx.mk_self_type()))
+        }
+        hir::ItemImpl(.., ref opt_trait_ref, _, _) => {
+            opt_trait_ref.as_ref().map(|ast_trait_ref| {
+                let selfty = tcx.item_type(def_id);
+                AstConv::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty)
+            })
+        }
+        _ => bug!()
+    }
 }
 
 // Is it marked with ?Sized
@@ -1676,60 +1247,123 @@ fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
 /// the lifetimes that are declared. For fns or methods, we have to
 /// screen out those that do not appear in any where-clauses etc using
 /// `resolve_lifetime::early_bound_lifetimes`.
-fn early_bound_lifetimes_from_generics<'a, 'tcx, 'hir>(
-    ccx: &CrateCtxt<'a, 'tcx>,
-    ast_generics: &'hir hir::Generics)
-    -> Vec<&'hir hir::LifetimeDef>
+fn early_bound_lifetimes_from_generics<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    ast_generics: &'a hir::Generics)
+    -> impl Iterator<Item=&'a hir::LifetimeDef>
 {
     ast_generics
         .lifetimes
         .iter()
-        .filter(|l| !ccx.tcx.named_region_map.late_bound.contains(&l.lifetime.id))
-        .collect()
+        .filter(move |l| !tcx.named_region_map.late_bound.contains(&l.lifetime.id))
 }
 
-fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                                  ast_generics: &hir::Generics,
-                                  parent: Option<DefId>,
-                                  super_predicates: Vec<ty::Predicate<'tcx>>,
-                                  has_self: bool)
-                                  -> ty::GenericPredicates<'tcx>
-{
-    let tcx = ccx.tcx;
-    let parent_count = parent.map_or(0, |def_id| {
-        let generics = generics_of_def_id(ccx, def_id);
-        assert_eq!(generics.parent, None);
-        assert_eq!(generics.parent_regions, 0);
-        assert_eq!(generics.parent_types, 0);
-        generics.count() as u32
-    });
-    let ref base_predicates = match parent {
-        Some(def_id) => {
-            assert_eq!(super_predicates, vec![]);
-            tcx.item_predicates(def_id)
+fn predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                        def_id: DefId)
+                        -> ty::GenericPredicates<'tcx> {
+    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 mut is_trait = None;
+
+    let icx = ItemCtxt::new(tcx, def_id);
+    let no_generics = hir::Generics::empty();
+    let ast_generics = match node {
+        NodeTraitItem(item) => {
+            match item.node {
+                TraitItemKind::Method(ref sig, _) => &sig.generics,
+                _ => &no_generics
+            }
         }
-        None => {
-            ty::GenericPredicates {
-                parent: None,
-                predicates: super_predicates.clone()
+
+        NodeImplItem(item) => {
+            match item.node {
+                ImplItemKind::Method(ref sig, _) => &sig.generics,
+                _ => &no_generics
+            }
+        }
+
+        NodeItem(item) => {
+            match item.node {
+                ItemFn(.., ref generics, _) |
+                ItemImpl(_, _, ref generics, ..) |
+                ItemTy(_, ref generics) |
+                ItemEnum(_, ref generics) |
+                ItemStruct(_, ref generics) |
+                ItemUnion(_, ref generics) => {
+                    generics
+                }
+
+                ItemTrait(_, ref generics, .., ref items) => {
+                    is_trait = Some((ty::TraitRef {
+                        def_id: def_id,
+                        substs: Substs::identity_for_item(tcx, def_id)
+                    }, items));
+                    generics
+                }
+
+                _ => &no_generics
             }
         }
+
+        NodeForeignItem(item) => {
+            match item.node {
+                ForeignItemStatic(..) => &no_generics,
+                ForeignItemFn(_, _, ref generics) => generics
+            }
+        }
+
+        NodeTy(&Ty { node: TyImplTrait(ref bounds), span, .. }) => {
+            let substs = Substs::identity_for_item(tcx, def_id);
+            let anon_ty = tcx.mk_anon(def_id, substs);
+
+            // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
+            let bounds = compute_bounds(&icx, anon_ty, bounds,
+                                        SizedByDefault::Yes,
+                                        span);
+            return ty::GenericPredicates {
+                parent: None,
+                predicates: bounds.predicates(tcx, anon_ty)
+            };
+        }
+
+        _ => &no_generics
     };
-    let mut predicates = super_predicates;
+
+    let generics = tcx.item_generics(def_id);
+    let parent_count = generics.parent_count() as u32;
+    let has_own_self = generics.has_self && parent_count == 0;
+
+    let mut predicates = vec![];
+
+    // Below we'll consider the bounds on the type parameters (including `Self`)
+    // and the explicit where-clauses, but to get the full set of predicates
+    // on a trait we need to add in the supertrait bounds and bounds found on
+    // associated types.
+    if let Some((trait_ref, _)) = is_trait {
+        predicates = tcx.item_super_predicates(def_id).predicates;
+
+        // Add in a predicate that `Self:Trait` (where `Trait` is the
+        // current trait).  This is needed for builtin bounds.
+        predicates.push(trait_ref.to_poly_trait_ref().to_predicate());
+    }
 
     // Collect the region predicates that were declared inline as
     // well. In the case of parameters declared on a fn or method, we
     // have to be careful to only iterate over early-bound regions.
-    let own_start = parent_count + has_self as u32;
-    let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics);
-    for (index, param) in early_lifetimes.iter().enumerate() {
-        let index = own_start + index as u32;
-        let region = ccx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
+    let mut index = parent_count + has_own_self as u32;
+    for param in early_bound_lifetimes_from_generics(tcx, ast_generics) {
+        let region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
             index: index,
             name: param.lifetime.name
         }));
+        index += 1;
+
         for bound in &param.bounds {
-            let bound_region = AstConv::ast_region_to_region(&ccx.icx(&()), bound, None);
+            let bound_region = AstConv::ast_region_to_region(&icx, bound, None);
             let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region));
             predicates.push(outlives.to_predicate());
         }
@@ -1737,16 +1371,16 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
 
     // Collect the predicates that were written inline by the user on each
     // type parameter (e.g., `<T:Foo>`).
-    let type_start = own_start + early_lifetimes.len() as u32;
-    for (index, param) in ast_generics.ty_params.iter().enumerate() {
-        let index = type_start + index as u32;
-        let param_ty = ty::ParamTy::new(index, param.name).to_ty(ccx.tcx);
-        let bounds = compute_bounds(&ccx.icx(&(base_predicates, ast_generics)),
+    for param in &ast_generics.ty_params {
+        let param_ty = ty::ParamTy::new(index, param.name).to_ty(tcx);
+        index += 1;
+
+        let bounds = compute_bounds(&icx,
                                     param_ty,
                                     &param.bounds,
                                     SizedByDefault::Yes,
                                     param.span);
-        predicates.extend(bounds.predicates(ccx.tcx, param_ty));
+        predicates.extend(bounds.predicates(tcx, param_ty));
     }
 
     // Add in the bounds that appear in the where-clause
@@ -1754,8 +1388,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
     for predicate in &where_clause.predicates {
         match predicate {
             &hir::WherePredicate::BoundPredicate(ref bound_pred) => {
-                let ty = AstConv::ast_ty_to_ty(&ccx.icx(&(base_predicates, ast_generics)),
-                                               &bound_pred.bounded_ty);
+                let ty = icx.to_ty(&bound_pred.bounded_ty);
 
                 for bound in bound_pred.bounds.iter() {
                     match bound {
@@ -1763,8 +1396,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                             let mut projections = Vec::new();
 
                             let trait_ref =
-                                AstConv::instantiate_poly_trait_ref(&ccx.icx(&(base_predicates,
-                                                                               ast_generics)),
+                                AstConv::instantiate_poly_trait_ref(&icx,
                                                                     poly_trait_ref,
                                                                     ty,
                                                                     &mut projections);
@@ -1777,7 +1409,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                         }
 
                         &hir::TyParamBound::RegionTyParamBound(ref lifetime) => {
-                            let region = AstConv::ast_region_to_region(&ccx.icx(&()),
+                            let region = AstConv::ast_region_to_region(&icx,
                                                                        lifetime,
                                                                        None);
                             let pred = ty::Binder(ty::OutlivesPredicate(ty, region));
@@ -1788,9 +1420,9 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
             }
 
             &hir::WherePredicate::RegionPredicate(ref region_pred) => {
-                let r1 = AstConv::ast_region_to_region(&ccx.icx(&()), &region_pred.lifetime, None);
+                let r1 = AstConv::ast_region_to_region(&icx, &region_pred.lifetime, None);
                 for bound in &region_pred.bounds {
-                    let r2 = AstConv::ast_region_to_region(&ccx.icx(&()), bound, None);
+                    let r2 = AstConv::ast_region_to_region(&icx, bound, None);
                     let pred = ty::Binder(ty::OutlivesPredicate(r1, r2));
                     predicates.push(ty::Predicate::RegionOutlives(pred))
                 }
@@ -1802,58 +1434,46 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
         }
     }
 
-    ty::GenericPredicates {
-        parent: parent,
-        predicates: predicates
-    }
-}
-
-fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                                             index: u32,
-                                             param: &hir::TyParam,
-                                             allow_defaults: bool)
-                                             -> ty::TypeParameterDef<'tcx>
-{
-    let tcx = ccx.tcx;
-    match tcx.ty_param_defs.borrow().get(&param.id) {
-        Some(d) => { return d.clone(); }
-        None => { }
-    }
+    // Add predicates from associated type bounds.
+    if let Some((self_trait_ref, trait_items)) = is_trait {
+        predicates.extend(trait_items.iter().flat_map(|trait_item_ref| {
+            let trait_item = tcx.hir.trait_item(trait_item_ref.id);
+            let bounds = match trait_item.node {
+                hir::TraitItemKind::Type(ref bounds, _) => bounds,
+                _ => {
+                    return vec![].into_iter();
+                }
+            };
 
-    let default =
-        param.default.as_ref().map(|def| ccx.icx(&()).to_ty(def));
+            let assoc_ty = tcx.mk_projection(self_trait_ref, trait_item.name);
 
-    let parent = tcx.hir.get_parent(param.id);
+            let bounds = compute_bounds(&ItemCtxt::new(tcx, def_id),
+                                        assoc_ty,
+                                        bounds,
+                                        SizedByDefault::Yes,
+                                        trait_item.span);
 
-    if !allow_defaults && default.is_some() {
-        if !tcx.sess.features.borrow().default_type_parameter_fallback {
-            tcx.sess.add_lint(
-                lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
-                param.id,
-                param.span,
-                format!("defaults for type parameters are only allowed in `struct`, \
-                         `enum`, `type`, or `trait` definitions."));
-        }
+            bounds.predicates(tcx, assoc_ty).into_iter()
+        }))
     }
 
-    let def = ty::TypeParameterDef {
-        index: index,
-        name: param.name,
-        def_id: ccx.tcx.hir.local_def_id(param.id),
-        default_def_id: ccx.tcx.hir.local_def_id(parent),
-        default: default,
-        pure_wrt_drop: param.pure_wrt_drop,
-    };
-
-    if def.name == keywords::SelfType.name() {
-        span_bug!(param.span, "`Self` should not be the name of a regular parameter");
+    // Subtle: before we store the predicates into the tcx, we
+    // sort them so that predicates like `T: Foo<Item=U>` come
+    // before uses of `U`.  This avoids false ambiguity errors
+    // in trait checking. See `setup_constraining_predicates`
+    // for details.
+    if let NodeItem(&Item { node: ItemImpl(..), .. }) = node {
+        let self_ty = tcx.item_type(def_id);
+        let trait_ref = tcx.impl_trait_ref(def_id);
+        ctp::setup_constraining_predicates(&mut predicates,
+                                           trait_ref,
+                                           &mut ctp::parameters_for_impl(self_ty, trait_ref));
     }
 
-    tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone());
-
-    debug!("get_or_create_type_parameter_def: def for type param: {:?}", def);
-
-    def
+    ty::GenericPredicates {
+        parent: generics.parent,
+        predicates: predicates
+    }
 }
 
 pub enum SizedByDefault { Yes, No, }
@@ -1943,53 +1563,36 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
 }
 
 fn compute_type_of_foreign_fn_decl<'a, 'tcx>(
-    ccx: &CrateCtxt<'a, 'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
     def_id: DefId,
     decl: &hir::FnDecl,
-    ast_generics: &hir::Generics,
     abi: abi::Abi)
     -> Ty<'tcx>
 {
-    let fty = AstConv::ty_of_fn(&ccx.icx(ast_generics), hir::Unsafety::Unsafe, abi, decl);
+    let fty = AstConv::ty_of_fn(&ItemCtxt::new(tcx, def_id), hir::Unsafety::Unsafe, abi, decl);
 
     // feature gate SIMD types in FFI, since I (huonw) am not sure the
     // ABIs are handled at all correctly.
     if abi != abi::Abi::RustIntrinsic && abi != abi::Abi::PlatformIntrinsic
-            && !ccx.tcx.sess.features.borrow().simd_ffi {
+            && !tcx.sess.features.borrow().simd_ffi {
         let check = |ast_ty: &hir::Ty, ty: ty::Ty| {
             if ty.is_simd() {
-                ccx.tcx.sess.struct_span_err(ast_ty.span,
+                tcx.sess.struct_span_err(ast_ty.span,
                               &format!("use of SIMD type `{}` in FFI is highly experimental and \
                                         may result in invalid code",
-                                       ccx.tcx.hir.node_to_pretty_string(ast_ty.id)))
+                                       tcx.hir.node_to_pretty_string(ast_ty.id)))
                     .help("add #![feature(simd_ffi)] to the crate attributes to enable")
                     .emit();
             }
         };
-        for (input, ty) in decl.inputs.iter().zip(*fty.sig.inputs().skip_binder()) {
+        for (input, ty) in decl.inputs.iter().zip(*fty.inputs().skip_binder()) {
             check(&input, ty)
         }
         if let hir::Return(ref ty) = decl.output {
-            check(&ty, *fty.sig.output().skip_binder())
+            check(&ty, *fty.output().skip_binder())
         }
     }
 
-    let id = ccx.tcx.hir.as_local_node_id(def_id).unwrap();
-    let substs = mk_item_substs(&ccx.icx(ast_generics), ccx.tcx.hir.span(id), def_id);
-    ccx.tcx.mk_fn_def(def_id, substs, fty)
-}
-
-fn mk_item_substs<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
-                        span: Span,
-                        def_id: DefId)
-                        -> &'tcx Substs<'tcx> {
-    let tcx = astconv.tcx();
-    // FIXME(eddyb) Do this request from Substs::for_item in librustc.
-    if let Err(ErrorReported) = astconv.get_generics(span, def_id) {
-        // No convenient way to recover from a cycle here. Just bail. Sorry!
-        tcx.sess.abort_if_errors();
-        bug!("ErrorReported returned, but no errors reports?")
-    }
-
-    Substs::identity_for_item(tcx, def_id)
+    let substs = Substs::identity_for_item(tcx, def_id);
+    tcx.mk_fn_def(def_id, substs, fty)
 }
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 5bfc3a934af..644e323a8db 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -1039,45 +1039,6 @@ struct Good(u32, u32, u32);
 ```
 "##,
 
-E0079: r##"
-Enum variants which contain no data can be given a custom integer
-representation. This error indicates that the value provided is not an integer
-literal and is therefore invalid.
-
-For example, in the following code:
-
-```compile_fail,E0079
-enum Foo {
-    Q = "32",
-}
-```
-
-We try to set the representation to a string.
-
-There's no general fix for this; if you can work with an integer then just set
-it to one:
-
-```
-enum Foo {
-    Q = 32,
-}
-```
-
-However if you actually wanted a mapping between variants and non-integer
-objects, it may be preferable to use a method with a match instead:
-
-```
-enum Foo { Q }
-impl Foo {
-    fn get_str(&self) -> &'static str {
-        match *self {
-            Foo::Q => "32",
-        }
-    }
-}
-```
-"##,
-
 E0081: r##"
 Enum discriminants are used to differentiate enum variants stored in memory.
 This error indicates that the same value was used for two or more variants,
@@ -1427,6 +1388,44 @@ struct Baz<'a> {
 ```
 "##,
 
+E0109: r##"
+You tried to give a type parameter to a type which doesn't need it. Erroneous
+code example:
+
+```compile_fail,E0109
+type X = u32<i32>; // error: type parameters are not allowed on this type
+```
+
+Please check that you used the correct type and recheck its definition. Perhaps
+it doesn't need the type parameter.
+
+Example:
+
+```
+type X = u32; // this compiles
+```
+
+Note that type parameters for enum-variant constructors go after the variant,
+not after the enum (Option::None::<u32>, not Option::<u32>::None).
+"##,
+
+E0110: r##"
+You tried to give a lifetime parameter to a type which doesn't need it.
+Erroneous code example:
+
+```compile_fail,E0110
+type X = u32<'static>; // error: lifetime parameters are not allowed on
+                       //        this type
+```
+
+Please check that the correct type was used and recheck its definition; perhaps
+it doesn't need the lifetime parameter. Example:
+
+```
+type X = u32; // ok!
+```
+"##,
+
 E0116: r##"
 You can only define an inherent implementation for a type in the same crate
 where the type was defined. For example, an `impl` block as below is not allowed
@@ -1701,33 +1700,6 @@ struct Foo {
 ```
 "##,
 
-E0128: r##"
-Type parameter defaults can only use parameters that occur before them.
-Erroneous code example:
-
-```compile_fail,E0128
-struct Foo<T=U, U=()> {
-    field1: T,
-    filed2: U,
-}
-// error: type parameters with a default cannot use forward declared
-// identifiers
-```
-
-Since type parameters are evaluated in-order, you may be able to fix this issue
-by doing:
-
-```
-struct Foo<U=(), T=U> {
-    field1: T,
-    filed2: U,
-}
-```
-
-Please also verify that this wasn't because of a name-clash and rename the type
-parameter if so.
-"##,
-
 E0131: r##"
 It is not possible to define `main` with type parameters, or even with function
 parameters. When `main` is present, it must take no arguments and return `()`.
@@ -2676,6 +2648,41 @@ fn main() {
 ```
 "##,
 
+E0229: r##"
+An associated type binding was done outside of the type parameter declaration
+and `where` clause. Erroneous code example:
+
+```compile_fail,E0229
+pub trait Foo {
+    type A;
+    fn boo(&self) -> <Self as Foo>::A;
+}
+
+struct Bar;
+
+impl Foo for isize {
+    type A = usize;
+    fn boo(&self) -> usize { 42 }
+}
+
+fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
+// error: associated type bindings are not allowed here
+```
+
+To solve this error, please move the type bindings in the type parameter
+declaration:
+
+```ignore
+fn baz<I: Foo<A=Bar>>(x: &<I as Foo>::A) {} // ok!
+```
+
+Or in the `where` clause:
+
+```ignore
+fn baz<I>(x: &<I as Foo>::A) where I: Foo<A=Bar> {}
+```
+"##,
+
 E0230: r##"
 The trait has more type parameters specified than appear in its definition.
 
@@ -3444,23 +3451,6 @@ impl Bar for *mut Foo {
 ```
 "##,
 
-E0391: r##"
-This error indicates that some types or traits depend on each other
-and therefore cannot be constructed.
-
-The following example contains a circular dependency between two traits:
-
-```compile_fail,E0391
-trait FirstTrait : SecondTrait {
-
-}
-
-trait SecondTrait : FirstTrait {
-
-}
-```
-"##,
-
 E0392: r##"
 This error indicates that a type or lifetime parameter has been declared
 but not actually used. Here is an example that demonstrates the error:
diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs
index 3a19b3579d5..3df25825a71 100644
--- a/src/librustc_typeck/impl_wf_check.rs
+++ b/src/librustc_typeck/impl_wf_check.rs
@@ -23,14 +23,12 @@ use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::def_id::DefId;
-use rustc::ty;
+use rustc::ty::{self, TyCtxt};
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 
 use syntax_pos::Span;
 
-use CrateCtxt;
-
 /// Checks that all the type/lifetime parameters on an impl also
 /// appear in the trait ref or self-type (or are constrained by a
 /// where-clause). These rules are needed to ensure that, given a
@@ -61,27 +59,27 @@ use CrateCtxt;
 /// impl<'a> Trait<Foo> for Bar { type X = &'a i32; }
 ///      ^ 'a is unused and appears in assoc type, error
 /// ```
-pub fn impl_wf_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>) {
+pub fn impl_wf_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     // We will tag this as part of the WF check -- logically, it is,
     // but it's one that we must perform earlier than the rest of
     // WfCheck.
-    ccx.tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut ImplWfCheck { ccx: ccx });
+    tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut ImplWfCheck { tcx: tcx });
 }
 
 struct ImplWfCheck<'a, 'tcx: 'a> {
-    ccx: &'a CrateCtxt<'a, 'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
 impl<'a, 'tcx> ItemLikeVisitor<'tcx> for ImplWfCheck<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         match item.node {
             hir::ItemImpl(.., ref generics, _, _, ref impl_item_refs) => {
-                let impl_def_id = self.ccx.tcx.hir.local_def_id(item.id);
-                enforce_impl_params_are_constrained(self.ccx,
+                let impl_def_id = self.tcx.hir.local_def_id(item.id);
+                enforce_impl_params_are_constrained(self.tcx,
                                                     generics,
                                                     impl_def_id,
                                                     impl_item_refs);
-                enforce_impl_items_are_distinct(self.ccx, impl_item_refs);
+                enforce_impl_items_are_distinct(self.tcx, impl_item_refs);
             }
             _ => { }
         }
@@ -92,16 +90,16 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for ImplWfCheck<'a, 'tcx> {
     fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) { }
 }
 
-fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                  impl_hir_generics: &hir::Generics,
                                                  impl_def_id: DefId,
                                                  impl_item_refs: &[hir::ImplItemRef])
 {
     // Every lifetime used in an associated type must be constrained.
-    let impl_self_ty = ccx.tcx.item_type(impl_def_id);
-    let impl_generics = ccx.tcx.item_generics(impl_def_id);
-    let impl_predicates = ccx.tcx.item_predicates(impl_def_id);
-    let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id);
+    let impl_self_ty = tcx.item_type(impl_def_id);
+    let impl_generics = tcx.item_generics(impl_def_id);
+    let impl_predicates = tcx.item_predicates(impl_def_id);
+    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
 
     let mut input_parameters = ctp::parameters_for_impl(impl_self_ty, impl_trait_ref);
     ctp::identify_constrained_type_params(
@@ -111,19 +109,19 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     for (ty_param, param) in impl_generics.types.iter().zip(&impl_hir_generics.ty_params) {
         let param_ty = ty::ParamTy::for_def(ty_param);
         if !input_parameters.contains(&ctp::Parameter::from(param_ty)) {
-            report_unused_parameter(ccx, param.span, "type", &param_ty.to_string());
+            report_unused_parameter(tcx, param.span, "type", &param_ty.to_string());
         }
     }
 
     // Disallow unconstrained lifetimes, but only if they appear in assoc types.
     let lifetimes_in_associated_types: FxHashSet<_> = impl_item_refs.iter()
-        .map(|item_ref|  ccx.tcx.hir.local_def_id(item_ref.id.node_id))
+        .map(|item_ref|  tcx.hir.local_def_id(item_ref.id.node_id))
         .filter(|&def_id| {
-            let item = ccx.tcx.associated_item(def_id);
+            let item = tcx.associated_item(def_id);
             item.kind == ty::AssociatedKind::Type && item.defaultness.has_value()
         })
         .flat_map(|def_id| {
-            ctp::parameters_for(&ccx.tcx.item_type(def_id), true)
+            ctp::parameters_for(&tcx.item_type(def_id), true)
         }).collect();
     for (ty_lifetime, lifetime) in impl_generics.regions.iter()
         .zip(&impl_hir_generics.lifetimes)
@@ -134,7 +132,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             lifetimes_in_associated_types.contains(&param) && // (*)
             !input_parameters.contains(&param)
         {
-            report_unused_parameter(ccx, lifetime.lifetime.span,
+            report_unused_parameter(tcx, lifetime.lifetime.span,
                                     "lifetime", &lifetime.lifetime.name.to_string());
         }
     }
@@ -159,13 +157,13 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     // used elsewhere are not projected back out.
 }
 
-fn report_unused_parameter(ccx: &CrateCtxt,
+fn report_unused_parameter(tcx: TyCtxt,
                            span: Span,
                            kind: &str,
                            name: &str)
 {
     struct_span_err!(
-        ccx.tcx.sess, span, E0207,
+        tcx.sess, span, E0207,
         "the {} parameter `{}` is not constrained by the \
         impl trait, self type, or predicates",
         kind, name)
@@ -174,10 +172,9 @@ fn report_unused_parameter(ccx: &CrateCtxt,
 }
 
 /// Enforce that we do not have two items in an impl with the same name.
-fn enforce_impl_items_are_distinct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn enforce_impl_items_are_distinct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                              impl_item_refs: &[hir::ImplItemRef])
 {
-    let tcx = ccx.tcx;
     let mut seen_type_items = FxHashMap();
     let mut seen_value_items = FxHashMap();
     for impl_item_ref in impl_item_refs {
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 0bcf8ab7d6c..2c325d46c0b 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -110,7 +110,8 @@ use hir::map as hir_map;
 use rustc::infer::InferOk;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
+use rustc::ty::maps::Providers;
+use rustc::traits::{ObligationCause, ObligationCauseCode, Reveal};
 use session::config;
 use util::common::time;
 
@@ -119,9 +120,6 @@ use syntax::abi::Abi;
 use syntax_pos::Span;
 
 use std::iter;
-use std::cell::RefCell;
-use util::nodemap::NodeMap;
-
 // NB: This module needs to be declared first so diagnostics are
 // registered before they are used.
 pub mod diagnostics;
@@ -140,27 +138,6 @@ pub struct TypeAndSubsts<'tcx> {
     pub ty: Ty<'tcx>,
 }
 
-pub struct CrateCtxt<'a, 'tcx: 'a> {
-    ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
-
-    /// A vector of every trait accessible in the whole crate
-    /// (i.e. including those from subcrates). This is used only for
-    /// error reporting, and so is lazily initialised and generally
-    /// shouldn't taint the common path (hence the RefCell).
-    pub all_traits: RefCell<Option<check::method::AllTraitsVec>>,
-
-    /// This stack is used to identify cycles in the user's source.
-    /// Note that these cycles can cross multiple items.
-    pub stack: RefCell<Vec<collect::AstConvRequest>>,
-
-    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
-
-    /// Obligations which will have to be checked at the end of
-    /// type-checking, after all functions have been inferred.
-    /// The key is the NodeId of the item the obligations were from.
-    pub deferred_obligations: RefCell<NodeMap<Vec<traits::DeferredObligation<'tcx>>>>,
-}
-
 fn require_c_abi_if_variadic(tcx: TyCtxt,
                              decl: &hir::FnDecl,
                              abi: Abi,
@@ -173,12 +150,12 @@ fn require_c_abi_if_variadic(tcx: TyCtxt,
     }
 }
 
-fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 cause: &ObligationCause<'tcx>,
                                 expected: Ty<'tcx>,
                                 actual: Ty<'tcx>)
                                 -> bool {
-    ccx.tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
+    tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
         match infcx.eq_types(false, &cause, expected, actual) {
             Ok(InferOk { obligations, .. }) => {
                 // FIXME(#32730) propagate obligations
@@ -193,10 +170,9 @@ fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     })
 }
 
-fn check_main_fn_ty(ccx: &CrateCtxt,
-                    main_id: ast::NodeId,
-                    main_span: Span) {
-    let tcx = ccx.tcx;
+fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                              main_id: ast::NodeId,
+                              main_span: Span) {
     let main_def_id = tcx.hir.local_def_id(main_id);
     let main_t = tcx.item_type(main_def_id);
     match main_t.sty {
@@ -206,7 +182,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
                     match it.node {
                         hir::ItemFn(.., ref generics, _) => {
                             if generics.is_parameterized() {
-                                struct_span_err!(ccx.tcx.sess, generics.span, E0131,
+                                struct_span_err!(tcx.sess, generics.span, E0131,
                                          "main function is not allowed to have type parameters")
                                     .span_label(generics.span,
                                                 &format!("main cannot have type parameters"))
@@ -221,14 +197,17 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
             }
             let substs = tcx.intern_substs(&[]);
             let se_ty = tcx.mk_fn_def(main_def_id, substs,
-                                      tcx.mk_bare_fn(ty::BareFnTy {
-                unsafety: hir::Unsafety::Normal,
-                abi: Abi::Rust,
-                sig: ty::Binder(tcx.mk_fn_sig(iter::empty(), tcx.mk_nil(), false))
-            }));
+                ty::Binder(tcx.mk_fn_sig(
+                    iter::empty(),
+                    tcx.mk_nil(),
+                    false,
+                    hir::Unsafety::Normal,
+                    Abi::Rust
+                ))
+            );
 
             require_same_types(
-                ccx,
+                tcx,
                 &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
                 se_ty,
                 main_t);
@@ -241,11 +220,10 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
     }
 }
 
-fn check_start_fn_ty(ccx: &CrateCtxt,
-                     start_id: ast::NodeId,
-                     start_span: Span) {
-    let tcx = ccx.tcx;
-    let start_def_id = ccx.tcx.hir.local_def_id(start_id);
+fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                               start_id: ast::NodeId,
+                               start_span: Span) {
+    let start_def_id = tcx.hir.local_def_id(start_id);
     let start_t = tcx.item_type(start_def_id);
     match start_t.sty {
         ty::TyFnDef(..) => {
@@ -269,21 +247,20 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
 
             let substs = tcx.intern_substs(&[]);
             let se_ty = tcx.mk_fn_def(start_def_id, substs,
-                                      tcx.mk_bare_fn(ty::BareFnTy {
-                unsafety: hir::Unsafety::Normal,
-                abi: Abi::Rust,
-                sig: ty::Binder(tcx.mk_fn_sig(
+                ty::Binder(tcx.mk_fn_sig(
                     [
                         tcx.types.isize,
                         tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
                     ].iter().cloned(),
                     tcx.types.isize,
                     false,
-                )),
-            }));
+                    hir::Unsafety::Normal,
+                    Abi::Rust
+                ))
+            );
 
             require_same_types(
-                ccx,
+                tcx,
                 &ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType),
                 se_ty,
                 start_t);
@@ -296,35 +273,33 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
     }
 }
 
-fn check_for_entry_fn(ccx: &CrateCtxt) {
-    let tcx = ccx.tcx;
+fn check_for_entry_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let _task = tcx.dep_graph.in_task(DepNode::CheckEntryFn);
     if let Some((id, sp)) = *tcx.sess.entry_fn.borrow() {
         match tcx.sess.entry_type.get() {
-            Some(config::EntryMain) => check_main_fn_ty(ccx, id, sp),
-            Some(config::EntryStart) => check_start_fn_ty(ccx, id, sp),
+            Some(config::EntryMain) => check_main_fn_ty(tcx, id, sp),
+            Some(config::EntryStart) => check_start_fn_ty(tcx, id, sp),
             Some(config::EntryNone) => {}
             None => bug!("entry function without a type")
         }
     }
 }
 
+pub fn provide(providers: &mut Providers) {
+    collect::provide(providers);
+    coherence::provide(providers);
+    check::provide(providers);
+}
+
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                             -> Result<NodeMap<Ty<'tcx>>, usize> {
+                             -> Result<(), usize> {
     let time_passes = tcx.sess.time_passes();
-    let ccx = CrateCtxt {
-        ast_ty_to_ty_cache: RefCell::new(NodeMap()),
-        all_traits: RefCell::new(None),
-        stack: RefCell::new(Vec::new()),
-        tcx: tcx,
-        deferred_obligations: RefCell::new(NodeMap()),
-    };
 
     // this ensures that later parts of type checking can assume that items
     // have valid types and not error
     tcx.sess.track_errors(|| {
         time(time_passes, "type collecting", ||
-             collect::collect_item_types(&ccx));
+             collect::collect_item_types(tcx));
 
     })?;
 
@@ -333,28 +308,28 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
 
     tcx.sess.track_errors(|| {
         time(time_passes, "impl wf inference", ||
-             impl_wf_check::impl_wf_check(&ccx));
+             impl_wf_check::impl_wf_check(tcx));
     })?;
 
     tcx.sess.track_errors(|| {
       time(time_passes, "coherence checking", ||
-          coherence::check_coherence(&ccx));
+          coherence::check_coherence(tcx));
     })?;
 
-    time(time_passes, "wf checking", || check::check_wf_new(&ccx))?;
+    time(time_passes, "wf checking", || check::check_wf_new(tcx))?;
 
-    time(time_passes, "item-types checking", || check::check_item_types(&ccx))?;
+    time(time_passes, "item-types checking", || check::check_item_types(tcx))?;
 
-    time(time_passes, "item-bodies checking", || check::check_item_bodies(&ccx))?;
+    time(time_passes, "item-bodies checking", || check::check_item_bodies(tcx))?;
 
-    time(time_passes, "drop-impl checking", || check::check_drop_impls(&ccx))?;
+    time(time_passes, "drop-impl checking", || check::check_drop_impls(tcx))?;
 
     check_unused::check_crate(tcx);
-    check_for_entry_fn(&ccx);
+    check_for_entry_fn(tcx);
 
     let err_count = tcx.sess.err_count();
     if err_count == 0 {
-        Ok(ccx.ast_ty_to_ty_cache.into_inner())
+        Ok(())
     } else {
         Err(err_count)
     }
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 860f6d98370..f0f543fa6f2 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -13,12 +13,10 @@
 //! The second pass over the AST determines the set of constraints.
 //! We walk the set of items and, for each member, generate new constraints.
 
-use dep_graph::DepTrackingMapConfig;
 use hir::def_id::DefId;
 use middle::resolve_lifetime as rl;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::maps::ItemVariances;
 use rustc::hir::map as hir_map;
 use syntax::ast;
 use rustc::hir;
@@ -28,6 +26,8 @@ use super::terms::*;
 use super::terms::VarianceTerm::*;
 use super::xform::*;
 
+use dep_graph::DepNode::ItemSignature as VarianceDepNode;
+
 pub struct ConstraintContext<'a, 'tcx: 'a> {
     pub terms_cx: TermsContext<'a, 'tcx>,
 
@@ -65,8 +65,7 @@ pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>)
     };
 
     // See README.md for a discussion on dep-graph management.
-    tcx.visit_all_item_likes_in_krate(|def_id| ItemVariances::to_dep_node(&def_id),
-                                      &mut constraint_cx);
+    tcx.visit_all_item_likes_in_krate(VarianceDepNode, &mut constraint_cx);
 
     constraint_cx
 }
@@ -279,7 +278,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
     }
 
     fn add_constraints_from_trait_ref(&mut self,
-                                      generics: &ty::Generics<'tcx>,
+                                      generics: &ty::Generics,
                                       trait_ref: ty::TraitRef<'tcx>,
                                       variance: VarianceTermPtr<'a>) {
         debug!("add_constraints_from_trait_ref: trait_ref={:?} variance={:?}",
@@ -291,7 +290,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
         // This edge is actually implied by the call to
         // `lookup_trait_def`, but I'm trying to be future-proof. See
         // README.md for a discussion on dep-graph management.
-        self.tcx().dep_graph.read(ItemVariances::to_dep_node(&trait_ref.def_id));
+        self.tcx().dep_graph.read(VarianceDepNode(trait_ref.def_id));
 
         self.add_constraints_from_substs(generics,
                                          trait_ref.def_id,
@@ -305,7 +304,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
     /// in a context with the generics defined in `generics` and
     /// ambient variance `variance`
     fn add_constraints_from_ty(&mut self,
-                               generics: &ty::Generics<'tcx>,
+                               generics: &ty::Generics,
                                ty: Ty<'tcx>,
                                variance: VarianceTermPtr<'a>) {
         debug!("add_constraints_from_ty(ty={:?}, variance={:?})",
@@ -350,7 +349,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 // This edge is actually implied by the call to
                 // `lookup_trait_def`, but I'm trying to be future-proof. See
                 // README.md for a discussion on dep-graph management.
-                self.tcx().dep_graph.read(ItemVariances::to_dep_node(&def.did));
+                self.tcx().dep_graph.read(VarianceDepNode(def.did));
 
                 self.add_constraints_from_substs(generics,
                                                  def.did,
@@ -367,7 +366,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 // This edge is actually implied by the call to
                 // `lookup_trait_def`, but I'm trying to be future-proof. See
                 // README.md for a discussion on dep-graph management.
-                self.tcx().dep_graph.read(ItemVariances::to_dep_node(&trait_ref.def_id));
+                self.tcx().dep_graph.read(VarianceDepNode(trait_ref.def_id));
 
                 self.add_constraints_from_substs(generics,
                                                  trait_ref.def_id,
@@ -412,8 +411,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 }
             }
 
-            ty::TyFnDef(.., &ty::BareFnTy { ref sig, .. }) |
-            ty::TyFnPtr(&ty::BareFnTy { ref sig, .. }) => {
+            ty::TyFnDef(.., sig) |
+            ty::TyFnPtr(sig) => {
                 self.add_constraints_from_sig(generics, sig, variance);
             }
 
@@ -433,9 +432,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
     /// Adds constraints appropriate for a nominal type (enum, struct,
     /// object, etc) appearing in a context with ambient variance `variance`
     fn add_constraints_from_substs(&mut self,
-                                   generics: &ty::Generics<'tcx>,
+                                   generics: &ty::Generics,
                                    def_id: DefId,
-                                   type_param_defs: &[ty::TypeParameterDef<'tcx>],
+                                   type_param_defs: &[ty::TypeParameterDef],
                                    region_param_defs: &[ty::RegionParameterDef],
                                    substs: &Substs<'tcx>,
                                    variance: VarianceTermPtr<'a>) {
@@ -465,8 +464,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
     /// Adds constraints appropriate for a function with signature
     /// `sig` appearing in a context with ambient variance `variance`
     fn add_constraints_from_sig(&mut self,
-                                generics: &ty::Generics<'tcx>,
-                                sig: &ty::PolyFnSig<'tcx>,
+                                generics: &ty::Generics,
+                                sig: ty::PolyFnSig<'tcx>,
                                 variance: VarianceTermPtr<'a>) {
         let contra = self.contravariant(variance);
         for &input in sig.0.inputs() {
@@ -478,7 +477,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
     /// Adds constraints appropriate for a region appearing in a
     /// context with ambient variance `variance`
     fn add_constraints_from_region(&mut self,
-                                   generics: &ty::Generics<'tcx>,
+                                   generics: &ty::Generics,
                                    region: &'tcx ty::Region,
                                    variance: VarianceTermPtr<'a>) {
         match *region {
@@ -518,7 +517,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
     /// Adds constraints appropriate for a mutability-type pair
     /// appearing in a context with ambient variance `variance`
     fn add_constraints_from_mt(&mut self,
-                               generics: &ty::Generics<'tcx>,
+                               generics: &ty::Generics,
                                mt: &ty::TypeAndMut<'tcx>,
                                variance: VarianceTermPtr<'a>) {
         match mt.mutbl {
diff --git a/src/librustc_typeck/variance/solve.rs b/src/librustc_typeck/variance/solve.rs
index 3ccec97d606..6628c7c521f 100644
--- a/src/librustc_typeck/variance/solve.rs
+++ b/src/librustc_typeck/variance/solve.rs
@@ -137,7 +137,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> {
                           item_variances);
             }
 
-            tcx.item_variance_map
+            tcx.maps.variances
                .borrow_mut()
                .insert(item_def_id, Rc::new(item_variances));
         }
diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs
index 253d7a25b63..36352f50e44 100644
--- a/src/librustc_typeck/variance/terms.rs
+++ b/src/librustc_typeck/variance/terms.rs
@@ -20,9 +20,7 @@
 // a variable.
 
 use arena::TypedArena;
-use dep_graph::DepTrackingMapConfig;
 use rustc::ty::{self, TyCtxt};
-use rustc::ty::maps::ItemVariances;
 use std::fmt;
 use std::rc::Rc;
 use syntax::ast;
@@ -34,6 +32,8 @@ use self::VarianceTerm::*;
 
 pub type VarianceTermPtr<'a> = &'a VarianceTerm<'a>;
 
+use dep_graph::DepNode::ItemSignature as VarianceDepNode;
+
 #[derive(Copy, Clone, Debug)]
 pub struct InferredIndex(pub usize);
 
@@ -109,7 +109,7 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>
     };
 
     // See README.md for a discussion on dep-graph management.
-    tcx.visit_all_item_likes_in_krate(|def_id| ItemVariances::to_dep_node(&def_id), &mut terms_cx);
+    tcx.visit_all_item_likes_in_krate(|def_id| VarianceDepNode(def_id), &mut terms_cx);
 
     terms_cx
 }
@@ -178,8 +178,7 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> {
         // parameters".
         if self.num_inferred() == inferreds_on_entry {
             let item_def_id = self.tcx.hir.local_def_id(item_id);
-            self.tcx
-                .item_variance_map
+            self.tcx.maps.variances
                 .borrow_mut()
                 .insert(item_def_id, self.empty_variances.clone());
         }
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 93854193762..c4476483186 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -15,6 +15,7 @@ use std::io;
 use std::iter::once;
 
 use syntax::ast;
+use syntax_pos::DUMMY_SP;
 use rustc::hir;
 
 use rustc::hir::def::{Def, CtorKind};
@@ -164,11 +165,7 @@ pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait {
 }
 
 fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function {
-    let ty = cx.tcx.item_type(did);
-    let (decl, style, abi) = match ty.sty {
-        ty::TyFnDef(.., ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi),
-        _ => panic!("bad function"),
-    };
+    let sig = cx.tcx.item_type(did).fn_sig();
 
     let constness = if cx.tcx.sess.cstore.is_const_fn(did) {
         hir::Constness::Const
@@ -178,11 +175,11 @@ fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function {
 
     let predicates = cx.tcx.item_predicates(did);
     clean::Function {
-        decl: decl,
+        decl: (did, sig).clean(cx),
         generics: (cx.tcx.item_generics(did), &predicates).clean(cx),
-        unsafety: style,
+        unsafety: sig.unsafety(),
         constness: constness,
-        abi: abi,
+        abi: sig.abi(),
     }
 }
 
@@ -235,10 +232,10 @@ fn build_type_alias(cx: &DocContext, did: DefId) -> clean::Typedef {
 
 pub fn build_impls(cx: &DocContext, did: DefId) -> Vec<clean::Item> {
     let tcx = cx.tcx;
-    tcx.populate_inherent_implementations_for_type_if_necessary(did);
+    tcx.populate_inherent_implementations_for_type_if_necessary(DUMMY_SP, did);
     let mut impls = Vec::new();
 
-    if let Some(i) = tcx.inherent_impls.borrow().get(&did) {
+    if let Some(i) = tcx.maps.inherent_impls.borrow().get(&did) {
         for &did in i.iter() {
             build_impl(cx, did, &mut impls);
         }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 751ed7d443d..73b82fbad5d 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -596,14 +596,18 @@ impl Clean<TyParam> for hir::TyParam {
     }
 }
 
-impl<'tcx> Clean<TyParam> for ty::TypeParameterDef<'tcx> {
+impl<'tcx> Clean<TyParam> for ty::TypeParameterDef {
     fn clean(&self, cx: &DocContext) -> TyParam {
         cx.renderinfo.borrow_mut().external_typarams.insert(self.def_id, self.name.clean(cx));
         TyParam {
             name: self.name.clean(cx),
             did: self.def_id,
             bounds: vec![], // these are filled in from the where-clauses
-            default: self.default.clean(cx),
+            default: if self.has_default {
+                Some(cx.tcx.item_type(self.def_id).clean(cx))
+            } else {
+                None
+            }
         }
     }
 }
@@ -965,7 +969,7 @@ impl Clean<Generics> for hir::Generics {
     }
 }
 
-impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>,
+impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
                                     &'a ty::GenericPredicates<'tcx>) {
     fn clean(&self, cx: &DocContext) -> Generics {
         use self::WherePredicate as WP;
@@ -1159,7 +1163,7 @@ impl<'a, A: Copy> Clean<FnDecl> for (&'a hir::FnDecl, A)
     }
 }
 
-impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
+impl<'a, 'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
     fn clean(&self, cx: &DocContext) -> FnDecl {
         let (did, sig) = *self;
         let mut names = if cx.tcx.hir.as_local_node_id(did).is_some() {
@@ -1348,11 +1352,8 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
             ty::AssociatedKind::Method => {
                 let generics = (cx.tcx.item_generics(self.def_id),
                                 &cx.tcx.item_predicates(self.def_id)).clean(cx);
-                let fty = match cx.tcx.item_type(self.def_id).sty {
-                    ty::TyFnDef(_, _, f) => f,
-                    _ => unreachable!()
-                };
-                let mut decl = (self.def_id, &fty.sig).clean(cx);
+                let sig = cx.tcx.item_type(self.def_id).fn_sig();
+                let mut decl = (self.def_id, sig).clean(cx);
 
                 if self.method_has_self_argument {
                     let self_ty = match self.container {
@@ -1361,7 +1362,7 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
                         }
                         ty::TraitContainer(_) => cx.tcx.mk_self_type()
                     };
-                    let self_arg_ty = *fty.sig.input(0).skip_binder();
+                    let self_arg_ty = *sig.input(0).skip_binder();
                     if self_arg_ty == self_ty {
                         decl.inputs.values[0].type_ = Generic(String::from("Self"));
                     } else if let ty::TyRef(_, mt) = self_arg_ty.sty {
@@ -1382,20 +1383,20 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
                 };
                 if provided {
                     MethodItem(Method {
-                        unsafety: fty.unsafety,
+                        unsafety: sig.unsafety(),
                         generics: generics,
                         decl: decl,
-                        abi: fty.abi,
+                        abi: sig.abi(),
 
                         // trait methods canot (currently, at least) be const
                         constness: hir::Constness::NotConst,
                     })
                 } else {
                     TyMethodItem(TyMethod {
-                        unsafety: fty.unsafety,
+                        unsafety: sig.unsafety(),
                         generics: generics,
                         decl: decl,
-                        abi: fty.abi,
+                        abi: sig.abi(),
                     })
                 }
             }
@@ -1768,7 +1769,7 @@ impl Clean<Type> for hir::Ty {
             }
             TyPath(hir::QPath::TypeRelative(ref qself, ref segment)) => {
                 let mut def = Def::Err;
-                if let Some(ty) = cx.hir_ty_to_ty.get(&self.id) {
+                if let Some(ty) = cx.tcx.ast_ty_to_ty_cache.borrow().get(&self.id) {
                     if let ty::TyProjection(proj) = ty.sty {
                         def = Def::Trait(proj.trait_ref.def_id);
                     }
@@ -1830,16 +1831,16 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
                 mutability: mt.mutbl.clean(cx),
                 type_: box mt.ty.clean(cx),
             },
-            ty::TyFnDef(.., ref fty) |
-            ty::TyFnPtr(ref fty) => BareFunction(box BareFunctionDecl {
-                unsafety: fty.unsafety,
+            ty::TyFnDef(.., sig) |
+            ty::TyFnPtr(sig) => BareFunction(box BareFunctionDecl {
+                unsafety: sig.unsafety(),
                 generics: Generics {
                     lifetimes: Vec::new(),
                     type_params: Vec::new(),
                     where_predicates: Vec::new()
                 },
-                decl: (cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID), &fty.sig).clean(cx),
-                abi: fty.abi,
+                decl: (cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID), sig).clean(cx),
+                abi: sig.abi(),
             }),
             ty::TyAdt(def, substs) => {
                 let did = def.did;
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 5393e395bbe..0a9db2c2646 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -15,10 +15,10 @@ use rustc::session::{self, config};
 use rustc::hir::def_id::DefId;
 use rustc::hir::def::{Def, ExportMap};
 use rustc::middle::privacy::AccessLevels;
-use rustc::ty::{self, TyCtxt, GlobalArenas, Ty};
+use rustc::ty::{self, TyCtxt, GlobalArenas};
 use rustc::hir::map as hir_map;
 use rustc::lint;
-use rustc::util::nodemap::{FxHashMap, NodeMap};
+use rustc::util::nodemap::FxHashMap;
 use rustc_trans::back::link;
 use rustc_resolve as resolve;
 use rustc_metadata::cstore::CStore;
@@ -65,9 +65,6 @@ pub struct DocContext<'a, 'tcx: 'a> {
     /// Table node id of lifetime parameter definition -> substituted lifetime
     pub lt_substs: RefCell<FxHashMap<ast::NodeId, clean::Lifetime>>,
     pub export_map: ExportMap,
-
-    /// Table from HIR Ty nodes to their resolved Ty.
-    pub hir_ty_to_ty: NodeMap<Ty<'tcx>>,
 }
 
 impl<'a, 'tcx> DocContext<'a, 'tcx> {
@@ -183,7 +180,7 @@ pub fn run_core(search_paths: SearchPaths,
             sess.fatal("Compilation failed, aborting rustdoc");
         }
 
-        let ty::CrateAnalysis { access_levels, export_map, hir_ty_to_ty, .. } = analysis;
+        let ty::CrateAnalysis { access_levels, export_map, .. } = analysis;
 
         // Convert from a NodeId set to a DefId set since we don't always have easy access
         // to the map from defid -> nodeid
@@ -202,7 +199,6 @@ pub fn run_core(search_paths: SearchPaths,
             ty_substs: Default::default(),
             lt_substs: Default::default(),
             export_map: export_map,
-            hir_ty_to_ty: hir_ty_to_ty,
         };
         debug!("crate: {:?}", tcx.hir.krate());
 
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 1c37067d7f6..c7000ee1e40 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -12,7 +12,7 @@ use std::env;
 use std::ffi::OsString;
 use std::io::prelude::*;
 use std::io;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 use std::panic::{self, AssertUnwindSafe};
 use std::process::Command;
 use std::rc::Rc;
@@ -485,7 +485,15 @@ impl Collector {
 
     pub fn get_filename(&self) -> String {
         if let Some(ref codemap) = self.codemap {
-            codemap.span_to_filename(self.position)
+            let filename = codemap.span_to_filename(self.position);
+            if let Ok(cur_dir) = env::current_dir() {
+                if let Ok(path) = Path::new(&filename).strip_prefix(&cur_dir) {
+                    if let Some(path) = path.to_str() {
+                        return path.to_owned();
+                    }
+                }
+            }
+            filename
         } else if let Some(ref filename) = self.filename {
             filename.clone()
         } else {
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 394eb477989..64f37925a98 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -199,7 +199,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         self.inside_public_path = orig_inside_public_path;
         if let Some(exports) = self.cx.export_map.get(&id) {
             for export in exports {
-                if let Def::Macro(def_id) = export.def {
+                if let Def::Macro(def_id, ..) = export.def {
                     if def_id.krate == LOCAL_CRATE {
                         continue // These are `krate.exported_macros`, handled in `self.visit()`.
                     }
diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs
index cee292f9915..852c98eb2fd 100644
--- a/src/librustdoc/visit_lib.rs
+++ b/src/librustdoc/visit_lib.rs
@@ -24,7 +24,7 @@ use clean::{AttributesExt, NestedAttributesExt};
 /// specific rustdoc annotations into account (i.e. `doc(hidden)`)
 pub struct LibEmbargoVisitor<'a, 'b: 'a, 'tcx: 'b> {
     cx: &'a ::core::DocContext<'b, 'tcx>,
-    cstore: &'a CrateStore<'tcx>,
+    cstore: &'a CrateStore,
     // Accessibility levels for reachable nodes
     access_levels: RefMut<'a, AccessLevels<DefId>>,
     // Previous accessibility level, None means unreachable
diff --git a/src/libstd/build.rs b/src/libstd/build.rs
index 0fca374f6e6..038dea77f3e 100644
--- a/src/libstd/build.rs
+++ b/src/libstd/build.rs
@@ -59,6 +59,10 @@ fn main() {
         println!("cargo:rustc-link-lib=userenv");
         println!("cargo:rustc-link-lib=shell32");
     } else if target.contains("fuchsia") {
+        // use system-provided libbacktrace
+        if cfg!(feature = "backtrace") {
+            println!("cargo:rustc-link-lib=backtrace");
+        }
         println!("cargo:rustc-link-lib=magenta");
         println!("cargo:rustc-link-lib=mxio");
         println!("cargo:rustc-link-lib=launchpad"); // for std::process
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index fd5827b4c07..f0738fe9b70 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -182,12 +182,12 @@ impl DefaultResizePolicy {
 // ----------------------
 // To protect against degenerate performance scenarios (including DOS attacks),
 // the implementation includes an adaptive behavior that can resize the map
-// early (before its capacity is exceeded) when suspiciously long probe or
-// forward shifts sequences are encountered.
+// early (before its capacity is exceeded) when suspiciously long probe sequences
+// are encountered.
 //
 // With this algorithm in place it would be possible to turn a CPU attack into
 // a memory attack due to the aggressive resizing. To prevent that the
-// adaptive behavior only triggers when the map occupancy is half the maximum occupancy.
+// adaptive behavior only triggers when the map is at least half full.
 // This reduces the effectiveness of the algorithm but also makes it completely safe.
 //
 // The previous safety measure also prevents degenerate interactions with
@@ -195,16 +195,11 @@ impl DefaultResizePolicy {
 // DOS attack.
 //
 const DISPLACEMENT_THRESHOLD: usize = 128;
-const FORWARD_SHIFT_THRESHOLD: usize = 512;
 //
-// The thresholds of 128 and 512 are chosen to minimize the chance of exceeding them.
+// The threshold of 128 is chosen to minimize the chance of exceeding it.
 // In particular, we want that chance to be less than 10^-8 with a load of 90%.
 // For displacement, the smallest constant that fits our needs is 90,
-// so we round that up to 128. For the number of forward-shifted buckets,
-// we choose k=512. Keep in mind that the run length is a sum of the displacement and
-// the number of forward-shifted buckets, so its threshold is 128+512=640.
-// Even though the probability of having a run length of more than 640 buckets may be
-// higher than the probability we want, it should be low enough.
+// so we round that up to 128.
 //
 // At a load factor of α, the odds of finding the target bucket after exactly n
 // unsuccesful probes[1] are
@@ -212,16 +207,12 @@ const FORWARD_SHIFT_THRESHOLD: usize = 512;
 // Pr_α{displacement = n} =
 // (1 - α) / α * ∑_{k≥1} e^(-kα) * (kα)^(k+n) / (k + n)! * (1 - kα / (k + n + 1))
 //
-// We use this formula to find the probability of loading half of triggering the adaptive behavior
+// We use this formula to find the probability of triggering the adaptive behavior
 //
 // Pr_0.909{displacement > 128} = 1.601 * 10^-11
 //
-// FIXME: Extend with math for shift threshold in [2]
-//
 // 1. Alfredo Viola (2005). Distributional analysis of Robin Hood linear probing
 //    hashing with buckets.
-// 2. http://www.cs.tau.ac.il/~zwick/Adv-Alg-2015/Linear-Probing.pdf
-
 
 /// A hash map implementation which uses linear probing with Robin Hood bucket
 /// stealing.
@@ -494,7 +485,7 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
                                 mut hash: SafeHash,
                                 mut key: K,
                                 mut val: V)
-                                -> (usize, &'a mut V) {
+                                -> &'a mut V {
     let start_index = bucket.index();
     let size = bucket.table().size();
     // Save the *starting point*.
@@ -519,7 +510,6 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
                 Empty(bucket) => {
                     // Found a hole!
                     let bucket = bucket.put(hash, key, val);
-                    let end_index = bucket.index();
                     // Now that it's stolen, just read the value's pointer
                     // right out of the table! Go back to the *starting point*.
                     //
@@ -527,7 +517,7 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
                     // bucket, which is a FullBucket on top of a
                     // FullBucketMut, into just one FullBucketMut. The "table"
                     // refers to the inner FullBucketMut in this context.
-                    return (end_index - start_index, bucket.into_table().into_mut_refs().1);
+                    return bucket.into_table().into_mut_refs().1;
                 }
                 Full(bucket) => bucket,
             };
@@ -2128,18 +2118,16 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
     pub fn insert(self, value: V) -> &'a mut V {
         match self.elem {
             NeqElem(bucket, disp) => {
-                let (shift, v_ref) = robin_hood(bucket, disp, self.hash, self.key, value);
-                if disp >= DISPLACEMENT_THRESHOLD || shift >= FORWARD_SHIFT_THRESHOLD {
+                if disp >= DISPLACEMENT_THRESHOLD {
                     *self.long_probes = true;
                 }
-                v_ref
+                robin_hood(bucket, disp, self.hash, self.key, value)
             },
             NoElem(bucket, disp) => {
                 if disp >= DISPLACEMENT_THRESHOLD {
                     *self.long_probes = true;
                 }
-                let bucket = bucket.put(self.hash, self.key, value);
-                bucket.into_mut_refs().1
+                bucket.put(self.hash, self.key, value).into_mut_refs().1
             },
         }
     }
diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs
index ac0d0d2afb8..f99634ecac2 100644
--- a/src/libstd/panic.rs
+++ b/src/libstd/panic.rs
@@ -198,7 +198,7 @@ impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *const T {}
 #[stable(feature = "catch_unwind", since = "1.9.0")]
 impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *mut T {}
 #[unstable(feature = "unique", issue = "27730")]
-impl<T: UnwindSafe> UnwindSafe for Unique<T> {}
+impl<T: UnwindSafe + ?Sized> UnwindSafe for Unique<T> {}
 #[unstable(feature = "shared", issue = "27730")]
 impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Shared<T> {}
 #[stable(feature = "catch_unwind", since = "1.9.0")]
diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs
index 3fba49345e6..3b5a1cffc7a 100644
--- a/src/libstd/panicking.rs
+++ b/src/libstd/panicking.rs
@@ -320,7 +320,11 @@ fn default_hook(info: &PanicInfo) {
     let log_backtrace = {
         let panics = update_panic_count(0);
 
-        panics >= 2 || backtrace::log_enabled()
+        if panics >= 2 {
+            Some(backtrace::PrintFormat::Full)
+        } else {
+            backtrace::log_enabled()
+        }
     };
 
     let file = info.location.file;
@@ -347,8 +351,8 @@ fn default_hook(info: &PanicInfo) {
 
             static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
 
-            if log_backtrace {
-                let _ = backtrace::write(err);
+            if let Some(format) = log_backtrace {
+                let _ = backtrace::print(err, format);
             } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) {
                 let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` for a backtrace.");
             }
diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs
index fc4fd4ce92b..f15e7ff8916 100644
--- a/src/libstd/sync/barrier.rs
+++ b/src/libstd/sync/barrier.rs
@@ -14,6 +14,8 @@ use sync::{Mutex, Condvar};
 /// A barrier enables multiple threads to synchronize the beginning
 /// of some computation.
 ///
+/// # Examples
+///
 /// ```
 /// use std::sync::{Arc, Barrier};
 /// use std::thread;
@@ -50,8 +52,19 @@ struct BarrierState {
 
 /// A result returned from wait.
 ///
-/// Currently this opaque structure only has one method, `.is_leader()`. Only
+/// Currently this opaque structure only has one method, [`.is_leader()`]. Only
 /// one thread will receive a result that will return `true` from this function.
+///
+/// [`.is_leader()`]: #method.is_leader
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::Barrier;
+///
+/// let barrier = Barrier::new(1);
+/// let barrier_wait_result = barrier.wait();
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BarrierWaitResult(bool);
 
@@ -65,8 +78,18 @@ impl fmt::Debug for Barrier {
 impl Barrier {
     /// Creates a new barrier that can block a given number of threads.
     ///
-    /// A barrier will block `n`-1 threads which call `wait` and then wake up
-    /// all threads at once when the `n`th thread calls `wait`.
+    /// A barrier will block `n`-1 threads which call [`wait`] and then wake up
+    /// all threads at once when the `n`th thread calls [`wait`].
+    ///
+    /// [`wait`]: #method.wait
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::Barrier;
+    ///
+    /// let barrier = Barrier::new(10);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new(n: usize) -> Barrier {
         Barrier {
@@ -84,10 +107,37 @@ impl Barrier {
     /// Barriers are re-usable after all threads have rendezvoused once, and can
     /// be used continuously.
     ///
-    /// A single (arbitrary) thread will receive a `BarrierWaitResult` that
-    /// returns `true` from `is_leader` when returning from this function, and
+    /// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that
+    /// returns `true` from [`is_leader`] when returning from this function, and
     /// all other threads will receive a result that will return `false` from
-    /// `is_leader`
+    /// [`is_leader`].
+    ///
+    /// [`BarrierWaitResult`]: struct.BarrierWaitResult.html
+    /// [`is_leader`]: struct.BarrierWaitResult.html#method.is_leader
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Barrier};
+    /// use std::thread;
+    ///
+    /// let mut handles = Vec::with_capacity(10);
+    /// let barrier = Arc::new(Barrier::new(10));
+    /// for _ in 0..10 {
+    ///     let c = barrier.clone();
+    ///     // The same messages will be printed together.
+    ///     // You will NOT see any interleaving.
+    ///     handles.push(thread::spawn(move|| {
+    ///         println!("before wait");
+    ///         c.wait();
+    ///         println!("after wait");
+    ///     }));
+    /// }
+    /// // Wait for other threads to finish.
+    /// for handle in handles {
+    ///     handle.join().unwrap();
+    /// }
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn wait(&self) -> BarrierWaitResult {
         let mut lock = self.lock.lock().unwrap();
@@ -120,10 +170,22 @@ impl fmt::Debug for BarrierWaitResult {
 }
 
 impl BarrierWaitResult {
-    /// Returns whether this thread from `wait` is the "leader thread".
+    /// Returns whether this thread from [`wait`] is the "leader thread".
     ///
     /// Only one thread will have `true` returned from their result, all other
     /// threads will have `false` returned.
+    ///
+    /// [`wait`]: struct.Barrier.html#method.wait
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::Barrier;
+    ///
+    /// let barrier = Barrier::new(1);
+    /// let barrier_wait_result = barrier.wait();
+    /// println!("{:?}", barrier_wait_result.is_leader());
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn is_leader(&self) -> bool { self.0 }
 }
diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs
index 0d6ad5e38e9..97b84d59218 100644
--- a/src/libstd/sync/mutex.rs
+++ b/src/libstd/sync/mutex.rs
@@ -133,11 +133,13 @@ unsafe impl<T: ?Sized + Send> Sync for Mutex<T> { }
 /// dropped (falls out of scope), the lock will be unlocked.
 ///
 /// The data protected by the mutex can be access through this guard via its
-/// `Deref` and `DerefMut` implementations.
+/// [`Deref`] and [`DerefMut`] implementations.
 ///
 /// This structure is created by the [`lock()`] and [`try_lock()`] methods on
 /// [`Mutex`].
 ///
+/// [`Deref`]: ../../std/ops/trait.Deref.html
+/// [`DerefMut`]: ../../std/ops/trait.DerefMut.html
 /// [`lock()`]: struct.Mutex.html#method.lock
 /// [`try_lock()`]: struct.Mutex.html#method.try_lock
 /// [`Mutex`]: struct.Mutex.html
diff --git a/src/libstd/sys/redox/backtrace.rs b/src/libstd/sys/redox/backtrace.rs
index 6f53841502a..961148fb6b4 100644
--- a/src/libstd/sys/redox/backtrace.rs
+++ b/src/libstd/sys/redox/backtrace.rs
@@ -10,9 +10,14 @@
 
 use libc;
 use io;
-use sys_common::backtrace::output;
+use sys_common::backtrace::Frame;
+
+pub use sys_common::gnu::libbacktrace::*;
+pub struct BacktraceContext;
 
 #[inline(never)]
-pub fn write(w: &mut io::Write) -> io::Result<()> {
-    output(w, 0, 0 as *mut libc::c_void, None)
+pub fn unwind_backtrace(frames: &mut [Frame])
+    -> io::Result<(usize, BacktraceContext)>
+{
+    Ok((0, BacktraceContext))
 }
diff --git a/src/libstd/sys/redox/mod.rs b/src/libstd/sys/redox/mod.rs
index 5982bdd6549..31c40ea58b1 100644
--- a/src/libstd/sys/redox/mod.rs
+++ b/src/libstd/sys/redox/mod.rs
@@ -13,7 +13,7 @@
 use io::{self, ErrorKind};
 
 pub mod args;
-#[cfg(any(not(cargobuild), feature = "backtrace"))]
+#[cfg(feature = "backtrace")]
 pub mod backtrace;
 pub mod condvar;
 pub mod env;
diff --git a/src/libstd/sys/redox/net/tcp.rs b/src/libstd/sys/redox/net/tcp.rs
index a3f202ccd97..936097d7fb2 100644
--- a/src/libstd/sys/redox/net/tcp.rs
+++ b/src/libstd/sys/redox/net/tcp.rs
@@ -63,6 +63,10 @@ impl TcpStream {
         Ok(path_to_local_addr(path.to_str().unwrap_or("")))
     }
 
+    pub fn peek(&self, _buf: &mut [u8]) -> Result<usize> {
+        Err(Error::new(ErrorKind::Other, "TcpStream::peek not implemented"))
+    }
+
     pub fn shutdown(&self, _how: Shutdown) -> Result<()> {
         Err(Error::new(ErrorKind::Other, "TcpStream::shutdown not implemented"))
     }
diff --git a/src/libstd/sys/redox/net/udp.rs b/src/libstd/sys/redox/net/udp.rs
index 36f0819d308..93ebcc95fd0 100644
--- a/src/libstd/sys/redox/net/udp.rs
+++ b/src/libstd/sys/redox/net/udp.rs
@@ -87,6 +87,14 @@ impl UdpSocket {
         Ok(path_to_local_addr(path.to_str().unwrap_or("")))
     }
 
+    pub fn peek(&self, _buf: &mut [u8]) -> Result<usize> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::peek not implemented"))
+    }
+
+    pub fn peek_from(&self, _buf: &mut [u8]) -> Result<(usize, SocketAddr)> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::peek_from not implemented"))
+    }
+
     pub fn broadcast(&self) -> Result<bool> {
         Err(Error::new(ErrorKind::Other, "UdpSocket::broadcast not implemented"))
     }
diff --git a/src/libstd/sys/unix/backtrace/mod.rs b/src/libstd/sys/unix/backtrace/mod.rs
index 1eef89bf66f..29d4012dcdf 100644
--- a/src/libstd/sys/unix/backtrace/mod.rs
+++ b/src/libstd/sys/unix/backtrace/mod.rs
@@ -83,7 +83,8 @@
 /// to symbols. This is a bit of a hokey implementation as-is, but it works for
 /// all unix platforms we support right now, so it at least gets the job done.
 
-pub use self::tracing::write;
+pub use self::tracing::unwind_backtrace;
+pub use self::printing::{foreach_symbol_fileline, resolve_symname};
 
 // tracing impls:
 mod tracing;
@@ -100,3 +101,5 @@ pub mod gnu {
         Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
     }
 }
+
+pub struct BacktraceContext;
diff --git a/src/libstd/sys/unix/backtrace/printing/dladdr.rs b/src/libstd/sys/unix/backtrace/printing/dladdr.rs
index d9b759dc673..05a071a7978 100644
--- a/src/libstd/sys/unix/backtrace/printing/dladdr.rs
+++ b/src/libstd/sys/unix/backtrace/printing/dladdr.rs
@@ -9,33 +9,45 @@
 // except according to those terms.
 
 use io;
-use io::prelude::*;
+use intrinsics;
+use ffi::CStr;
 use libc;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
 
-pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void,
-             _symaddr: *mut libc::c_void) -> io::Result<()> {
-    use sys_common::backtrace::{output};
-    use intrinsics;
-    use ffi::CStr;
-
-    #[repr(C)]
-    struct Dl_info {
-        dli_fname: *const libc::c_char,
-        dli_fbase: *mut libc::c_void,
-        dli_sname: *const libc::c_char,
-        dli_saddr: *mut libc::c_void,
-    }
-    extern {
-        fn dladdr(addr: *const libc::c_void,
-                  info: *mut Dl_info) -> libc::c_int;
+pub fn resolve_symname<F>(frame: Frame,
+                          callback: F,
+                          _: &BacktraceContext) -> io::Result<()>
+    where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+    unsafe {
+        let mut info: Dl_info = intrinsics::init();
+        let symname = if dladdr(frame.exact_position, &mut info) == 0 {
+            None
+        } else {
+            CStr::from_ptr(info.dli_sname).to_str().ok()
+        };
+        callback(symname)
     }
+}
 
-    let mut info: Dl_info = unsafe { intrinsics::init() };
-    if unsafe { dladdr(addr, &mut info) == 0 } {
-        output(w, idx,addr, None)
-    } else {
-        output(w, idx, addr, Some(unsafe {
-            CStr::from_ptr(info.dli_sname).to_bytes()
-        }))
-    }
+pub fn foreach_symbol_fileline<F>(_symbol_addr: Frame,
+                                  _f: F,
+                                  _: &BacktraceContext) -> io::Result<bool>
+    where F: FnMut(&[u8], libc::c_int) -> io::Result<()>
+{
+    Ok(false)
+}
+
+#[repr(C)]
+struct Dl_info {
+    dli_fname: *const libc::c_char,
+    dli_fbase: *mut libc::c_void,
+    dli_sname: *const libc::c_char,
+    dli_saddr: *mut libc::c_void,
+}
+
+extern {
+    fn dladdr(addr: *const libc::c_void,
+              info: *mut Dl_info) -> libc::c_int;
 }
diff --git a/src/libstd/sys/unix/backtrace/printing/mod.rs b/src/libstd/sys/unix/backtrace/printing/mod.rs
index 02e53854727..1ae82e01100 100644
--- a/src/libstd/sys/unix/backtrace/printing/mod.rs
+++ b/src/libstd/sys/unix/backtrace/printing/mod.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub use self::imp::print;
+pub use self::imp::{foreach_symbol_fileline, resolve_symname};
 
 #[cfg(any(target_os = "macos", target_os = "ios",
           target_os = "emscripten"))]
@@ -17,5 +17,6 @@ mod imp;
 
 #[cfg(not(any(target_os = "macos", target_os = "ios",
               target_os = "emscripten")))]
-#[path = "gnu.rs"]
-mod imp;
+mod imp {
+    pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
+}
diff --git a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs
index ca2e70b5003..ecd32aa9462 100644
--- a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs
+++ b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs
@@ -18,39 +18,31 @@
 /// simple to use it should be used only on iOS devices as the only viable
 /// option.
 
-use io::prelude::*;
 use io;
 use libc;
-use mem;
-use sys::mutex::Mutex;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
 
-use super::super::printing::print;
-
-#[inline(never)]
-pub fn write(w: &mut Write) -> io::Result<()> {
-    extern {
-        fn backtrace(buf: *mut *mut libc::c_void,
-                     sz: libc::c_int) -> libc::c_int;
+#[inline(never)] // if we know this is a function call, we can skip it when
+                 // tracing
+pub fn unwind_backtrace(frames: &mut [Frame])
+    -> io::Result<(usize, BacktraceContext)>
+{
+    const FRAME_LEN: usize = 100;
+    assert!(FRAME_LEN >= frames.len());
+    let mut raw_frames = [::ptr::null_mut(); FRAME_LEN];
+    let nb_frames = unsafe {
+        backtrace(raw_frames.as_mut_ptr(), raw_frames.len() as libc::c_int)
+    } as usize;
+    for (from, to) in raw_frames.iter().zip(frames.iter_mut()).take(nb_frames) {
+        *to = Frame {
+            exact_position: *from,
+            symbol_addr: *from,
+        };
     }
+    Ok((nb_frames as usize, BacktraceContext))
+}
 
-    // while it doesn't requires lock for work as everything is
-    // local, it still displays much nicer backtraces when a
-    // couple of threads panic simultaneously
-    static LOCK: Mutex = Mutex::new();
-    unsafe {
-        LOCK.lock();
-
-        writeln!(w, "stack backtrace:")?;
-        // 100 lines should be enough
-        const SIZE: usize = 100;
-        let mut buf: [*mut libc::c_void; SIZE] = mem::zeroed();
-        let cnt = backtrace(buf.as_mut_ptr(), SIZE as libc::c_int) as usize;
-
-        // skipping the first one as it is write itself
-        for i in 1..cnt {
-            print(w, i as isize, buf[i], buf[i])?
-        }
-        LOCK.unlock();
-    }
-    Ok(())
+extern {
+    fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int;
 }
diff --git a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs
index c1b45620ab0..cfeabaddda9 100644
--- a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs
+++ b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs
@@ -8,102 +8,99 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use error::Error;
 use io;
-use io::prelude::*;
 use libc;
-use mem;
-use sys_common::mutex::Mutex;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
 
-use super::super::printing::print;
 use unwind as uw;
 
-#[inline(never)] // if we know this is a function call, we can skip it when
-                 // tracing
-pub fn write(w: &mut Write) -> io::Result<()> {
-    struct Context<'a> {
-        idx: isize,
-        writer: &'a mut (Write+'a),
-        last_error: Option<io::Error>,
-    }
+struct Context<'a> {
+    idx: usize,
+    frames: &'a mut [Frame],
+}
 
-    // When using libbacktrace, we use some necessary global state, so we
-    // need to prevent more than one thread from entering this block. This
-    // is semi-reasonable in terms of printing anyway, and we know that all
-    // I/O done here is blocking I/O, not green I/O, so we don't have to
-    // worry about this being a native vs green mutex.
-    static LOCK: Mutex = Mutex::new();
-    unsafe {
-        LOCK.lock();
+#[derive(Debug)]
+struct UnwindError(uw::_Unwind_Reason_Code);
 
-        writeln!(w, "stack backtrace:")?;
+impl Error for UnwindError {
+    fn description(&self) -> &'static str {
+        "unexpected return value while unwinding"
+    }
+}
 
-        let mut cx = Context { writer: w, last_error: None, idx: 0 };
-        let ret = match {
-            uw::_Unwind_Backtrace(trace_fn,
-                                  &mut cx as *mut Context as *mut libc::c_void)
-        } {
-            uw::_URC_NO_REASON => {
-                match cx.last_error {
-                    Some(err) => Err(err),
-                    None => Ok(())
-                }
-            }
-            _ => Ok(()),
-        };
-        LOCK.unlock();
-        return ret
+impl ::fmt::Display for UnwindError {
+    fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
+        write!(f, "{}: {:?}", self.description(), self.0)
     }
+}
 
-    extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
-                       arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
-        let cx: &mut Context = unsafe { mem::transmute(arg) };
-        let mut ip_before_insn = 0;
-        let mut ip = unsafe {
-            uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
-        };
-        if !ip.is_null() && ip_before_insn == 0 {
-            // this is a non-signaling frame, so `ip` refers to the address
-            // after the calling instruction. account for that.
-            ip = (ip as usize - 1) as *mut _;
+#[inline(never)] // if we know this is a function call, we can skip it when
+                 // tracing
+pub fn unwind_backtrace(frames: &mut [Frame])
+    -> io::Result<(usize, BacktraceContext)>
+{
+    let mut cx = Context {
+        idx: 0,
+        frames: frames,
+    };
+    let result_unwind = unsafe {
+        uw::_Unwind_Backtrace(trace_fn,
+                              &mut cx as *mut Context
+                              as *mut libc::c_void)
+    };
+    // See libunwind:src/unwind/Backtrace.c for the return values.
+    // No, there is no doc.
+    match result_unwind {
+        // These return codes seem to be benign and need to be ignored for backtraces
+        // to show up properly on all tested platforms.
+        uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
+            Ok((cx.idx, BacktraceContext))
         }
-
-        // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
-        // it appears to work fine without it, so we only use
-        // FindEnclosingFunction on non-osx platforms. In doing so, we get a
-        // slightly more accurate stack trace in the process.
-        //
-        // This is often because panic involves the last instruction of a
-        // function being "call std::rt::begin_unwind", with no ret
-        // instructions after it. This means that the return instruction
-        // pointer points *outside* of the calling function, and by
-        // unwinding it we go back to the original function.
-        let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
-            ip
-        } else {
-            unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
-        };
-
-        // Don't print out the first few frames (they're not user frames)
-        cx.idx += 1;
-        if cx.idx <= 0 { return uw::_URC_NO_REASON }
-        // Don't print ginormous backtraces
-        if cx.idx > 100 {
-            match write!(cx.writer, " ... <frames omitted>\n") {
-                Ok(()) => {}
-                Err(e) => { cx.last_error = Some(e); }
-            }
-            return uw::_URC_FAILURE
+        _ => {
+            Err(io::Error::new(io::ErrorKind::Other,
+                               UnwindError(result_unwind)))
         }
+    }
+}
 
-        // Once we hit an error, stop trying to print more frames
-        if cx.last_error.is_some() { return uw::_URC_FAILURE }
+extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
+                   arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
+    let cx = unsafe { &mut *(arg as *mut Context) };
+    let mut ip_before_insn = 0;
+    let mut ip = unsafe {
+        uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
+    };
+    if !ip.is_null() && ip_before_insn == 0 {
+        // this is a non-signaling frame, so `ip` refers to the address
+        // after the calling instruction. account for that.
+        ip = (ip as usize - 1) as *mut _;
+    }
 
-        match print(cx.writer, cx.idx, ip, symaddr) {
-            Ok(()) => {}
-            Err(e) => { cx.last_error = Some(e); }
-        }
+    // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
+    // it appears to work fine without it, so we only use
+    // FindEnclosingFunction on non-osx platforms. In doing so, we get a
+    // slightly more accurate stack trace in the process.
+    //
+    // This is often because panic involves the last instruction of a
+    // function being "call std::rt::begin_unwind", with no ret
+    // instructions after it. This means that the return instruction
+    // pointer points *outside* of the calling function, and by
+    // unwinding it we go back to the original function.
+    let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
+        ip
+    } else {
+        unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
+    };
 
-        // keep going
-        uw::_URC_NO_REASON
+    if cx.idx < cx.frames.len() {
+        cx.frames[cx.idx] = Frame {
+            symbol_addr: symaddr,
+            exact_position: ip,
+        };
+        cx.idx += 1;
     }
+
+    uw::_URC_NO_REASON
 }
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
index 8b5c0c04276..d0fb96b1ff1 100644
--- a/src/libstd/sys/unix/fs.rs
+++ b/src/libstd/sys/unix/fs.rs
@@ -35,7 +35,8 @@ use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t,
            ftruncate as ftruncate64, lseek as lseek64, dirent as dirent64, open as open64};
 #[cfg(not(any(target_os = "linux",
               target_os = "emscripten",
-              target_os = "solaris")))]
+              target_os = "solaris",
+              target_os = "fuchsia")))]
 use libc::{readdir_r as readdir64_r};
 
 pub struct File(FileDesc);
@@ -59,10 +60,10 @@ pub struct DirEntry {
     entry: dirent64,
     root: Arc<PathBuf>,
     // We need to store an owned copy of the directory name
-    // on Solaris because a) it uses a zero-length array to
-    // store the name, b) its lifetime between readdir calls
-    // is not guaranteed.
-    #[cfg(target_os = "solaris")]
+    // on Solaris and Fuchsia because a) it uses a zero-length
+    // array to store the name, b) its lifetime between readdir
+    // calls is not guaranteed.
+    #[cfg(any(target_os = "solaris", target_os = "fuchsia"))]
     name: Box<[u8]>
 }
 
@@ -205,14 +206,14 @@ impl fmt::Debug for ReadDir {
 impl Iterator for ReadDir {
     type Item = io::Result<DirEntry>;
 
-    #[cfg(target_os = "solaris")]
+    #[cfg(any(target_os = "solaris", target_os = "fuchsia"))]
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
         unsafe {
             loop {
                 // Although readdir_r(3) would be a correct function to use here because
-                // of the thread safety, on Illumos the readdir(3C) function is safe to use
-                // in threaded applications and it is generally preferred over the
-                // readdir_r(3C) function.
+                // of the thread safety, on Illumos and Fuchsia the readdir(3C) function
+                // is safe to use in threaded applications and it is generally preferred
+                // over the readdir_r(3C) function.
                 super::os::set_errno(0);
                 let entry_ptr = libc::readdir(self.dirp.0);
                 if entry_ptr.is_null() {
@@ -240,7 +241,7 @@ impl Iterator for ReadDir {
         }
     }
 
-    #[cfg(not(target_os = "solaris"))]
+    #[cfg(not(any(target_os = "solaris", target_os = "fuchsia")))]
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
         unsafe {
             let mut ret = DirEntry {
@@ -344,14 +345,14 @@ impl DirEntry {
     #[cfg(any(target_os = "android",
               target_os = "linux",
               target_os = "emscripten",
-              target_os = "haiku",
-              target_os = "fuchsia"))]
+              target_os = "haiku"))]
     fn name_bytes(&self) -> &[u8] {
         unsafe {
             CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes()
         }
     }
-    #[cfg(target_os = "solaris")]
+    #[cfg(any(target_os = "solaris",
+              target_os = "fuchsia"))]
     fn name_bytes(&self) -> &[u8] {
         &*self.name
     }
diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs
index e78928c2667..36928696c40 100644
--- a/src/libstd/sys/unix/os.rs
+++ b/src/libstd/sys/unix/os.rs
@@ -64,7 +64,7 @@ pub fn errno() -> i32 {
 }
 
 /// Sets the platform-specific value of errno
-#[cfg(target_os = "solaris")] // only needed for readdir so far
+#[cfg(any(target_os = "solaris", target_os = "fuchsia"))] // only needed for readdir so far
 pub fn set_errno(e: i32) {
     unsafe {
         *errno_location() = e as c_int
diff --git a/src/libstd/sys/unix/process/magenta.rs b/src/libstd/sys/unix/process/magenta.rs
index a81bedcad22..08a827ce081 100644
--- a/src/libstd/sys/unix/process/magenta.rs
+++ b/src/libstd/sys/unix/process/magenta.rs
@@ -111,7 +111,7 @@ extern {
     pub fn mx_handle_duplicate(handle: mx_handle_t, rights: mx_rights_t,
                                out: *const mx_handle_t) -> mx_handle_t;
 
-    pub fn mx_handle_wait_one(handle: mx_handle_t, signals: mx_signals_t, timeout: mx_time_t,
+    pub fn mx_object_wait_one(handle: mx_handle_t, signals: mx_signals_t, timeout: mx_time_t,
                               pending: *mut mx_signals_t) -> mx_status_t;
 
     pub fn mx_object_get_info(handle: mx_handle_t, topic: u32, buffer: *mut c_void,
diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs
index 0bb2e0c1a83..608e44ca9e8 100644
--- a/src/libstd/sys/unix/process/process_fuchsia.rs
+++ b/src/libstd/sys/unix/process/process_fuchsia.rs
@@ -151,7 +151,7 @@ impl Process {
         let mut avail: mx_size_t = 0;
 
         unsafe {
-            mx_cvt(mx_handle_wait_one(self.handle.raw(), MX_TASK_TERMINATED,
+            mx_cvt(mx_object_wait_one(self.handle.raw(), MX_TASK_TERMINATED,
                                       MX_TIME_INFINITE, ptr::null_mut()))?;
             mx_cvt(mx_object_get_info(self.handle.raw(), MX_INFO_PROCESS,
                                       &mut proc_info as *mut _ as *mut libc::c_void,
@@ -174,7 +174,7 @@ impl Process {
         let mut avail: mx_size_t = 0;
 
         unsafe {
-            let status = mx_handle_wait_one(self.handle.raw(), MX_TASK_TERMINATED,
+            let status = mx_object_wait_one(self.handle.raw(), MX_TASK_TERMINATED,
                                             0, ptr::null_mut());
             match status {
                 0 => { }, // Success
diff --git a/src/libstd/sys/windows/backtrace_gnu.rs b/src/libstd/sys/windows/backtrace/backtrace_gnu.rs
index f0d29dd4178..f0d29dd4178 100644
--- a/src/libstd/sys/windows/backtrace_gnu.rs
+++ b/src/libstd/sys/windows/backtrace/backtrace_gnu.rs
diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace/mod.rs
index 94aaf439f3d..3c3fd8d3e4a 100644
--- a/src/libstd/sys/windows/backtrace.rs
+++ b/src/libstd/sys/windows/backtrace/mod.rs
@@ -24,37 +24,87 @@
 
 #![allow(deprecated)] // dynamic_lib
 
-use io::prelude::*;
-
 use io;
 use libc::c_void;
 use mem;
 use ptr;
 use sys::c;
 use sys::dynamic_lib::DynamicLibrary;
-use sys::mutex::Mutex;
+use sys_common::backtrace::Frame;
 
 macro_rules! sym {
     ($lib:expr, $e:expr, $t:ident) => (
-        match $lib.symbol($e) {
-            Ok(f) => $crate::mem::transmute::<usize, $t>(f),
-            Err(..) => return Ok(())
-        }
+        $lib.symbol($e).map(|f| unsafe {
+            $crate::mem::transmute::<usize, $t>(f)
+        })
     )
 }
 
-#[cfg(target_env = "msvc")]
-#[path = "printing/msvc.rs"]
-mod printing;
-
-#[cfg(target_env = "gnu")]
-#[path = "printing/gnu.rs"]
 mod printing;
 
 #[cfg(target_env = "gnu")]
 #[path = "backtrace_gnu.rs"]
 pub mod gnu;
 
+pub use self::printing::{resolve_symname, foreach_symbol_fileline};
+
+pub fn unwind_backtrace(frames: &mut [Frame])
+    -> io::Result<(usize, BacktraceContext)>
+{
+    let dbghelp = DynamicLibrary::open("dbghelp.dll")?;
+
+    // Fetch the symbols necessary from dbghelp.dll
+    let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
+    let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?;
+    let StackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn)?;
+
+    // Allocate necessary structures for doing the stack walk
+    let process = unsafe { c::GetCurrentProcess() };
+    let thread = unsafe { c::GetCurrentThread() };
+    let mut context: c::CONTEXT = unsafe { mem::zeroed() };
+    unsafe { c::RtlCaptureContext(&mut context) };
+    let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() };
+    let image = init_frame(&mut frame, &context);
+
+    let backtrace_context = BacktraceContext {
+        handle: process,
+        SymCleanup: SymCleanup,
+        dbghelp: dbghelp,
+    };
+
+    // Initialize this process's symbols
+    let ret = unsafe { SymInitialize(process, ptr::null_mut(), c::TRUE) };
+    if ret != c::TRUE {
+        return Ok((0, backtrace_context))
+    }
+
+    // And now that we're done with all the setup, do the stack walking!
+    // Start from -1 to avoid printing this stack frame, which will
+    // always be exactly the same.
+    let mut i = 0;
+    unsafe {
+        while i < frames.len() &&
+              StackWalk64(image, process, thread, &mut frame, &mut context,
+                          ptr::null_mut(),
+                          ptr::null_mut(),
+                          ptr::null_mut(),
+                          ptr::null_mut()) == c::TRUE
+        {
+            let addr = frame.AddrPC.Offset;
+            if addr == frame.AddrReturn.Offset || addr == 0 ||
+               frame.AddrReturn.Offset == 0 { break }
+
+            frames[i] = Frame {
+                symbol_addr: (addr - 1) as *const c_void,
+                exact_position: (addr - 1) as *const c_void,
+            };
+            i += 1;
+        }
+    }
+
+    Ok((i, backtrace_context))
+}
+
 type SymInitializeFn =
     unsafe extern "system" fn(c::HANDLE, *mut c_void,
                               c::BOOL) -> c::BOOL;
@@ -68,8 +118,8 @@ type StackWalk64Fn =
                               *mut c_void, *mut c_void) -> c::BOOL;
 
 #[cfg(target_arch = "x86")]
-pub fn init_frame(frame: &mut c::STACKFRAME64,
-                  ctx: &c::CONTEXT) -> c::DWORD {
+fn init_frame(frame: &mut c::STACKFRAME64,
+              ctx: &c::CONTEXT) -> c::DWORD {
     frame.AddrPC.Offset = ctx.Eip as u64;
     frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
     frame.AddrStack.Offset = ctx.Esp as u64;
@@ -80,8 +130,8 @@ pub fn init_frame(frame: &mut c::STACKFRAME64,
 }
 
 #[cfg(target_arch = "x86_64")]
-pub fn init_frame(frame: &mut c::STACKFRAME64,
-                  ctx: &c::CONTEXT) -> c::DWORD {
+fn init_frame(frame: &mut c::STACKFRAME64,
+              ctx: &c::CONTEXT) -> c::DWORD {
     frame.AddrPC.Offset = ctx.Rip as u64;
     frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
     frame.AddrStack.Offset = ctx.Rsp as u64;
@@ -91,73 +141,16 @@ pub fn init_frame(frame: &mut c::STACKFRAME64,
     c::IMAGE_FILE_MACHINE_AMD64
 }
 
-struct Cleanup {
+pub struct BacktraceContext {
     handle: c::HANDLE,
     SymCleanup: SymCleanupFn,
+    // Only used in printing for msvc and not gnu
+    #[allow(dead_code)]
+    dbghelp: DynamicLibrary,
 }
 
-impl Drop for Cleanup {
+impl Drop for BacktraceContext {
     fn drop(&mut self) {
         unsafe { (self.SymCleanup)(self.handle); }
     }
 }
-
-pub fn write(w: &mut Write) -> io::Result<()> {
-    // According to windows documentation, all dbghelp functions are
-    // single-threaded.
-    static LOCK: Mutex = Mutex::new();
-    unsafe {
-        LOCK.lock();
-        let res = _write(w);
-        LOCK.unlock();
-        return res
-    }
-}
-
-unsafe fn _write(w: &mut Write) -> io::Result<()> {
-    let dbghelp = match DynamicLibrary::open("dbghelp.dll") {
-        Ok(lib) => lib,
-        Err(..) => return Ok(()),
-    };
-
-    // Fetch the symbols necessary from dbghelp.dll
-    let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn);
-    let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn);
-    let StackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn);
-
-    // Allocate necessary structures for doing the stack walk
-    let process = c::GetCurrentProcess();
-    let thread = c::GetCurrentThread();
-    let mut context: c::CONTEXT = mem::zeroed();
-    c::RtlCaptureContext(&mut context);
-    let mut frame: c::STACKFRAME64 = mem::zeroed();
-    let image = init_frame(&mut frame, &context);
-
-    // Initialize this process's symbols
-    let ret = SymInitialize(process, ptr::null_mut(), c::TRUE);
-    if ret != c::TRUE { return Ok(()) }
-    let _c = Cleanup { handle: process, SymCleanup: SymCleanup };
-
-    // And now that we're done with all the setup, do the stack walking!
-    // Start from -1 to avoid printing this stack frame, which will
-    // always be exactly the same.
-    let mut i = -1;
-    write!(w, "stack backtrace:\n")?;
-    while StackWalk64(image, process, thread, &mut frame, &mut context,
-                      ptr::null_mut(),
-                      ptr::null_mut(),
-                      ptr::null_mut(),
-                      ptr::null_mut()) == c::TRUE {
-        let addr = frame.AddrPC.Offset;
-        if addr == frame.AddrReturn.Offset || addr == 0 ||
-           frame.AddrReturn.Offset == 0 { break }
-
-        i += 1;
-
-        if i >= 0 {
-            printing::print(w, i, addr - 1, process, &dbghelp)?;
-        }
-    }
-
-    Ok(())
-}
diff --git a/src/libstd/sys/windows/backtrace/printing/mod.rs b/src/libstd/sys/windows/backtrace/printing/mod.rs
new file mode 100644
index 00000000000..3e566f6e2bd
--- /dev/null
+++ b/src/libstd/sys/windows/backtrace/printing/mod.rs
@@ -0,0 +1,20 @@
+// 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.
+
+#[cfg(target_env = "msvc")]
+#[path = "msvc.rs"]
+mod printing;
+
+#[cfg(target_env = "gnu")]
+mod printing {
+    pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
+}
+
+pub use self::printing::{foreach_symbol_fileline, resolve_symname};
diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs
new file mode 100644
index 00000000000..3107d784324
--- /dev/null
+++ b/src/libstd/sys/windows/backtrace/printing/msvc.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 ffi::CStr;
+use io;
+use libc::{c_ulong, c_int, c_char};
+use mem;
+use sys::c;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
+
+type SymFromAddrFn =
+    unsafe extern "system" fn(c::HANDLE, u64, *mut u64,
+                              *mut c::SYMBOL_INFO) -> c::BOOL;
+type SymGetLineFromAddr64Fn =
+    unsafe extern "system" fn(c::HANDLE, u64, *mut u32,
+                              *mut c::IMAGEHLP_LINE64) -> c::BOOL;
+
+/// Converts a pointer to symbol to its string value.
+pub fn resolve_symname<F>(frame: Frame,
+                          callback: F,
+                          context: &BacktraceContext) -> io::Result<()>
+    where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+    let SymFromAddr = sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn)?;
+
+    unsafe {
+        let mut info: c::SYMBOL_INFO = mem::zeroed();
+        info.MaxNameLen = c::MAX_SYM_NAME as c_ulong;
+        // the struct size in C.  the value is different to
+        // `size_of::<SYMBOL_INFO>() - MAX_SYM_NAME + 1` (== 81)
+        // due to struct alignment.
+        info.SizeOfStruct = 88;
+
+        let mut displacement = 0u64;
+        let ret = SymFromAddr(context.handle,
+                              frame.symbol_addr as u64,
+                              &mut displacement,
+                              &mut info);
+
+        let symname = if ret == c::TRUE {
+            let ptr = info.Name.as_ptr() as *const c_char;
+            CStr::from_ptr(ptr).to_str().ok()
+        } else {
+            None
+        };
+        callback(symname)
+    }
+}
+
+pub fn foreach_symbol_fileline<F>(frame: Frame,
+                                  mut f: F,
+                                  context: &BacktraceContext)
+    -> io::Result<bool>
+    where F: FnMut(&[u8], c_int) -> io::Result<()>
+{
+    let SymGetLineFromAddr64 = sym!(&context.dbghelp,
+                                    "SymGetLineFromAddr64",
+                                    SymGetLineFromAddr64Fn)?;
+
+    unsafe {
+        let mut line: c::IMAGEHLP_LINE64 = mem::zeroed();
+        line.SizeOfStruct = ::mem::size_of::<c::IMAGEHLP_LINE64>() as u32;
+
+        let mut displacement = 0u32;
+        let ret = SymGetLineFromAddr64(context.handle,
+                                       frame.exact_position as u64,
+                                       &mut displacement,
+                                       &mut line);
+        if ret == c::TRUE {
+            let name = CStr::from_ptr(line.Filename).to_bytes();
+            f(name, line.LineNumber as c_int)?;
+        }
+        Ok(false)
+    }
+}
diff --git a/src/libstd/sys/windows/printing/msvc.rs b/src/libstd/sys/windows/printing/msvc.rs
deleted file mode 100644
index 9c29ac4082a..00000000000
--- a/src/libstd/sys/windows/printing/msvc.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-// 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 ffi::CStr;
-use io::prelude::*;
-use io;
-use libc::{c_ulong, c_int, c_char, c_void};
-use mem;
-use sys::c;
-use sys::dynamic_lib::DynamicLibrary;
-use sys_common::backtrace::{output, output_fileline};
-
-type SymFromAddrFn =
-    unsafe extern "system" fn(c::HANDLE, u64, *mut u64,
-                              *mut c::SYMBOL_INFO) -> c::BOOL;
-type SymGetLineFromAddr64Fn =
-    unsafe extern "system" fn(c::HANDLE, u64, *mut u32,
-                              *mut c::IMAGEHLP_LINE64) -> c::BOOL;
-
-pub fn print(w: &mut Write,
-             i: isize,
-             addr: u64,
-             process: c::HANDLE,
-             dbghelp: &DynamicLibrary)
-              -> io::Result<()> {
-    unsafe {
-        let SymFromAddr = sym!(dbghelp, "SymFromAddr", SymFromAddrFn);
-        let SymGetLineFromAddr64 = sym!(dbghelp,
-                                        "SymGetLineFromAddr64",
-                                        SymGetLineFromAddr64Fn);
-
-        let mut info: c::SYMBOL_INFO = mem::zeroed();
-        info.MaxNameLen = c::MAX_SYM_NAME as c_ulong;
-        // the struct size in C.  the value is different to
-        // `size_of::<SYMBOL_INFO>() - MAX_SYM_NAME + 1` (== 81)
-        // due to struct alignment.
-        info.SizeOfStruct = 88;
-
-        let mut displacement = 0u64;
-        let ret = SymFromAddr(process, addr, &mut displacement, &mut info);
-
-        let name = if ret == c::TRUE {
-            let ptr = info.Name.as_ptr() as *const c_char;
-            Some(CStr::from_ptr(ptr).to_bytes())
-        } else {
-            None
-        };
-
-        output(w, i, addr as usize as *mut c_void, name)?;
-
-        // Now find out the filename and line number
-        let mut line: c::IMAGEHLP_LINE64 = mem::zeroed();
-        line.SizeOfStruct = ::mem::size_of::<c::IMAGEHLP_LINE64>() as u32;
-
-        let mut displacement = 0u32;
-        let ret = SymGetLineFromAddr64(process, addr, &mut displacement, &mut line);
-        if ret == c::TRUE {
-            output_fileline(w,
-                            CStr::from_ptr(line.Filename).to_bytes(),
-                            line.LineNumber as c_int,
-                            false)
-        } else {
-            Ok(())
-        }
-    }
-}
diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs
index a8540fed928..99297b781e4 100644
--- a/src/libstd/sys_common/backtrace.rs
+++ b/src/libstd/sys_common/backtrace.rs
@@ -10,14 +10,25 @@
 
 #![cfg_attr(target_os = "nacl", allow(dead_code))]
 
+/// Common code for printing the backtrace in the same way across the different
+/// supported platforms.
+
 use env;
 use io::prelude::*;
 use io;
 use libc;
 use str;
 use sync::atomic::{self, Ordering};
+use path::Path;
+use sys::mutex::Mutex;
+use ptr;
 
-pub use sys::backtrace::write;
+pub use sys::backtrace::{
+    unwind_backtrace,
+    resolve_symname,
+    foreach_symbol_fileline,
+    BacktraceContext
+};
 
 #[cfg(target_pointer_width = "64")]
 pub const HEX_WIDTH: usize = 18;
@@ -25,45 +36,243 @@ pub const HEX_WIDTH: usize = 18;
 #[cfg(target_pointer_width = "32")]
 pub const HEX_WIDTH: usize = 10;
 
+/// Represents an item in the backtrace list. See `unwind_backtrace` for how
+/// it is created.
+#[derive(Debug, Copy, Clone)]
+pub struct Frame {
+    /// Exact address of the call that failed.
+    pub exact_position: *const libc::c_void,
+    /// Address of the enclosing function.
+    pub symbol_addr: *const libc::c_void,
+}
+
+/// Max number of frames to print.
+const MAX_NB_FRAMES: usize = 100;
+
+/// Prints the current backtrace.
+pub fn print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
+    static LOCK: Mutex = Mutex::new();
+
+    // Use a lock to prevent mixed output in multithreading context.
+    // Some platforms also requires it, like `SymFromAddr` on Windows.
+    unsafe {
+        LOCK.lock();
+        let res = _print(w, format);
+        LOCK.unlock();
+        res
+    }
+}
+
+fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
+    let mut frames = [Frame {
+        exact_position: ptr::null(),
+        symbol_addr: ptr::null(),
+    }; MAX_NB_FRAMES];
+    let (nb_frames, context) = unwind_backtrace(&mut frames)?;
+    let (skipped_before, skipped_after) =
+        filter_frames(&frames[..nb_frames], format, &context);
+    if skipped_before + skipped_after > 0 {
+        writeln!(w, "note: Some details are omitted, \
+                     run with `RUST_BACKTRACE=full` for a verbose backtrace.")?;
+    }
+    writeln!(w, "stack backtrace:")?;
+
+    let filtered_frames = &frames[..nb_frames - skipped_after];
+    for (index, frame) in filtered_frames.iter().skip(skipped_before).enumerate() {
+        resolve_symname(*frame, |symname| {
+            output(w, index, *frame, symname, format)
+        }, &context)?;
+        let has_more_filenames = foreach_symbol_fileline(*frame, |file, line| {
+            output_fileline(w, file, line, format)
+        }, &context)?;
+        if has_more_filenames {
+            w.write_all(b" <... and possibly more>")?;
+        }
+    }
+
+    Ok(())
+}
+
+fn filter_frames(frames: &[Frame],
+                 format: PrintFormat,
+                 context: &BacktraceContext) -> (usize, usize)
+{
+    if format == PrintFormat::Full {
+        return (0, 0);
+    }
+
+    // We want to filter out frames with some prefixes
+    // from both top and bottom of the call stack.
+    static BAD_PREFIXES_TOP: &'static [&'static str] = &[
+        "_ZN3std3sys3imp9backtrace",
+        "ZN3std3sys3imp9backtrace",
+        "std::sys::imp::backtrace",
+        "_ZN3std10sys_common9backtrace",
+        "ZN3std10sys_common9backtrace",
+        "std::sys_common::backtrace",
+        "_ZN3std9panicking",
+        "ZN3std9panicking",
+        "std::panicking",
+        "_ZN4core9panicking",
+        "ZN4core9panicking",
+        "core::panicking",
+        "_ZN4core6result13unwrap_failed",
+        "ZN4core6result13unwrap_failed",
+        "core::result::unwrap_failed",
+        "rust_begin_unwind",
+        "_ZN4drop",
+        "mingw_set_invalid_parameter_handler",
+    ];
+    static BAD_PREFIXES_BOTTOM: &'static [&'static str] = &[
+        "_ZN3std9panicking",
+        "ZN3std9panicking",
+        "std::panicking",
+        "_ZN3std5panic",
+        "ZN3std5panic",
+        "std::panic",
+        "_ZN4core9panicking",
+        "ZN4core9panicking",
+        "core::panicking",
+        "_ZN3std2rt10lang_start",
+        "ZN3std2rt10lang_start",
+        "std::rt::lang_start",
+        "panic_unwind::__rust_maybe_catch_panic",
+        "__rust_maybe_catch_panic",
+        "_rust_maybe_catch_panic",
+        "__libc_start_main",
+        "__rust_try",
+        "_start",
+        "main",
+        "BaseThreadInitThunk",
+        "RtlInitializeExceptionChain",
+        "__scrt_common_main_seh",
+        "_ZN4drop",
+        "mingw_set_invalid_parameter_handler",
+    ];
+
+    let is_good_frame = |frame: Frame, bad_prefixes: &[&str]| {
+        resolve_symname(frame, |symname| {
+            if let Some(mangled_symbol_name) = symname {
+                if !bad_prefixes.iter().any(|s| mangled_symbol_name.starts_with(s)) {
+                    return Ok(())
+                }
+            }
+            Err(io::Error::from(io::ErrorKind::Other))
+        }, context).is_ok()
+    };
+
+    let skipped_before = frames.iter().position(|frame| {
+        is_good_frame(*frame, BAD_PREFIXES_TOP)
+    }).unwrap_or(frames.len());
+    let skipped_after = frames[skipped_before..].iter().rev().position(|frame| {
+        is_good_frame(*frame, BAD_PREFIXES_BOTTOM)
+    }).unwrap_or(frames.len() - skipped_before);
+
+    if skipped_before + skipped_after == frames.len() {
+        // Avoid showing completely empty backtraces
+        return (0, 0);
+    }
+
+    (skipped_before, skipped_after)
+}
+
+/// Controls how the backtrace should be formated.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum PrintFormat {
+    /// Show all the frames with absolute path for files.
+    Full = 2,
+    /// Show only relevant data from the backtrace.
+    Short = 3,
+}
+
 // For now logging is turned off by default, and this function checks to see
 // whether the magical environment variable is present to see if it's turned on.
-pub fn log_enabled() -> bool {
+pub fn log_enabled() -> Option<PrintFormat> {
     static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
     match ENABLED.load(Ordering::SeqCst) {
-        1 => return false,
-        2 => return true,
-        _ => {}
+        0 => {},
+        1 => return None,
+        2 => return Some(PrintFormat::Full),
+        3 => return Some(PrintFormat::Short),
+        _ => unreachable!(),
     }
 
     let val = match env::var_os("RUST_BACKTRACE") {
-        Some(x) => if &x == "0" { 1 } else { 2 },
-        None => 1,
+        Some(x) => if &x == "0" {
+            None
+        } else if &x == "full" {
+            Some(PrintFormat::Full)
+        } else {
+            Some(PrintFormat::Short)
+        },
+        None => None,
     };
-    ENABLED.store(val, Ordering::SeqCst);
-    val == 2
+    ENABLED.store(match val {
+        Some(v) => v as isize,
+        None => 1,
+    }, Ordering::SeqCst);
+    val
 }
 
-// These output functions should now be used everywhere to ensure consistency.
-pub fn output(w: &mut Write, idx: isize, addr: *mut libc::c_void,
-              s: Option<&[u8]>) -> io::Result<()> {
-    write!(w, "  {:2}: {:2$?} - ", idx, addr, HEX_WIDTH)?;
-    match s.and_then(|s| str::from_utf8(s).ok()) {
-        Some(string) => demangle(w, string)?,
-        None => write!(w, "<unknown>")?,
+/// Print the symbol of the backtrace frame.
+///
+/// These output functions should now be used everywhere to ensure consistency.
+/// You may want to also use `output_fileline`.
+fn output(w: &mut Write, idx: usize, frame: Frame,
+              s: Option<&str>, format: PrintFormat) -> io::Result<()> {
+    // Remove the `17: 0x0 - <unknown>` line.
+    if format == PrintFormat::Short && frame.exact_position == ptr::null() {
+        return Ok(());
+    }
+    match format {
+        PrintFormat::Full => write!(w,
+                                    "  {:2}: {:2$?} - ",
+                                    idx,
+                                    frame.exact_position,
+                                    HEX_WIDTH)?,
+        PrintFormat::Short => write!(w, "  {:2}: ", idx)?,
     }
-    w.write_all(&['\n' as u8])
+    match s {
+        Some(string) => demangle(w, string, format)?,
+        None => w.write_all(b"<unknown>")?,
+    }
+    w.write_all(b"\n")
 }
 
+/// Print the filename and line number of the backtrace frame.
+///
+/// See also `output`.
 #[allow(dead_code)]
-pub fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int,
-                       more: bool) -> io::Result<()> {
-    let file = str::from_utf8(file).unwrap_or("<unknown>");
+fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int,
+                       format: PrintFormat) -> io::Result<()> {
     // prior line: "  ##: {:2$} - func"
-    write!(w, "      {:3$}at {}:{}", "", file, line, HEX_WIDTH)?;
-    if more {
-        write!(w, " <... and possibly more>")?;
+    w.write_all(b"")?;
+    match format {
+        PrintFormat::Full => write!(w,
+                                    "           {:1$}",
+                                    "",
+                                    HEX_WIDTH)?,
+        PrintFormat::Short => write!(w, "           ")?,
+    }
+
+    let file = str::from_utf8(file).unwrap_or("<unknown>");
+    let file_path = Path::new(file);
+    let mut already_printed = false;
+    if format == PrintFormat::Short && file_path.is_absolute() {
+        if let Ok(cwd) = env::current_dir() {
+            if let Ok(stripped) = file_path.strip_prefix(&cwd) {
+                if let Some(s) = stripped.to_str() {
+                    write!(w, "  at ./{}:{}", s, line)?;
+                    already_printed = true;
+                }
+            }
+        }
+    }
+    if !already_printed {
+        write!(w, "  at {}:{}", file, line)?;
     }
-    w.write_all(&['\n' as u8])
+
+    w.write_all(b"\n")
 }
 
 
@@ -84,7 +293,7 @@ pub fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int,
 // Note that this demangler isn't quite as fancy as it could be. We have lots
 // of other information in our symbols like hashes, version, type information,
 // etc. Additionally, this doesn't handle glue symbols at all.
-pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> {
+pub fn demangle(writer: &mut Write, s: &str, format: PrintFormat) -> io::Result<()> {
     // First validate the symbol. If it doesn't look like anything we're
     // expecting, we just print it literally. Note that we must handle non-rust
     // symbols because we could have any function in the backtrace.
@@ -123,6 +332,22 @@ pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> {
     if !valid {
         writer.write_all(s.as_bytes())?;
     } else {
+        // remove the `::hfc2edb670e5eda97` part at the end of the symbol.
+        if format == PrintFormat::Short {
+            // The symbol in still mangled.
+            let mut split = inner.rsplitn(2, "17h");
+            match (split.next(), split.next()) {
+                (Some(addr), rest) => {
+                    if addr.len() == 16 &&
+                       addr.chars().all(|c| c.is_digit(16))
+                    {
+                        inner = rest.unwrap_or("");
+                    }
+                }
+                _ => (),
+            }
+        }
+
         let mut first = true;
         while !inner.is_empty() {
             if !first {
@@ -208,7 +433,9 @@ mod tests {
     use sys_common;
     macro_rules! t { ($a:expr, $b:expr) => ({
         let mut m = Vec::new();
-        sys_common::backtrace::demangle(&mut m, $a).unwrap();
+        sys_common::backtrace::demangle(&mut m,
+                                        $a,
+                                        super::PrintFormat::Full).unwrap();
         assert_eq!(String::from_utf8(m).unwrap(), $b);
     }) }
 
diff --git a/src/libstd/sys_common/gnu/libbacktrace.rs b/src/libstd/sys_common/gnu/libbacktrace.rs
index 0bdbeddb112..1ea5cca44c7 100644
--- a/src/libstd/sys_common/gnu/libbacktrace.rs
+++ b/src/libstd/sys_common/gnu/libbacktrace.rs
@@ -8,186 +8,204 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use io;
-use io::prelude::*;
 use libc;
-use sys_common::backtrace::{output, output_fileline};
-
-pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void,
-             symaddr: *mut libc::c_void) -> io::Result<()> {
-    use ffi::CStr;
-    use mem;
-    use ptr;
-
-    ////////////////////////////////////////////////////////////////////////
-    // libbacktrace.h API
-    ////////////////////////////////////////////////////////////////////////
-    type backtrace_syminfo_callback =
-        extern "C" fn(data: *mut libc::c_void,
-                      pc: libc::uintptr_t,
-                      symname: *const libc::c_char,
-                      symval: libc::uintptr_t,
-                      symsize: libc::uintptr_t);
-    type backtrace_full_callback =
-        extern "C" fn(data: *mut libc::c_void,
-                      pc: libc::uintptr_t,
-                      filename: *const libc::c_char,
-                      lineno: libc::c_int,
-                      function: *const libc::c_char) -> libc::c_int;
-    type backtrace_error_callback =
-        extern "C" fn(data: *mut libc::c_void,
-                      msg: *const libc::c_char,
-                      errnum: libc::c_int);
-    enum backtrace_state {}
-
-    extern {
-        fn backtrace_create_state(filename: *const libc::c_char,
-                                  threaded: libc::c_int,
-                                  error: backtrace_error_callback,
-                                  data: *mut libc::c_void)
-                                  -> *mut backtrace_state;
-        fn backtrace_syminfo(state: *mut backtrace_state,
-                             addr: libc::uintptr_t,
-                             cb: backtrace_syminfo_callback,
-                             error: backtrace_error_callback,
-                             data: *mut libc::c_void) -> libc::c_int;
-        fn backtrace_pcinfo(state: *mut backtrace_state,
-                            addr: libc::uintptr_t,
-                            cb: backtrace_full_callback,
-                            error: backtrace_error_callback,
-                            data: *mut libc::c_void) -> libc::c_int;
-    }
-
-    ////////////////////////////////////////////////////////////////////////
-    // helper callbacks
-    ////////////////////////////////////////////////////////////////////////
-
-    type FileLine = (*const libc::c_char, libc::c_int);
-
-    extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char,
-                       _errnum: libc::c_int) {
-        // do nothing for now
-    }
-    extern fn syminfo_cb(data: *mut libc::c_void,
-                         _pc: libc::uintptr_t,
-                         symname: *const libc::c_char,
-                         _symval: libc::uintptr_t,
-                         _symsize: libc::uintptr_t) {
-        let slot = data as *mut *const libc::c_char;
-        unsafe { *slot = symname; }
-    }
-    extern fn pcinfo_cb(data: *mut libc::c_void,
-                        _pc: libc::uintptr_t,
-                        filename: *const libc::c_char,
-                        lineno: libc::c_int,
-                        _function: *const libc::c_char) -> libc::c_int {
-        if !filename.is_null() {
-            let slot = data as *mut &mut [FileLine];
-            let buffer = unsafe {ptr::read(slot)};
-
-            // if the buffer is not full, add file:line to the buffer
-            // and adjust the buffer for next possible calls to pcinfo_cb.
-            if !buffer.is_empty() {
-                buffer[0] = (filename, lineno);
-                unsafe { ptr::write(slot, &mut buffer[1..]); }
-            }
-        }
-
-        0
-    }
-
-    // The libbacktrace API supports creating a state, but it does not
-    // support destroying a state. I personally take this to mean that a
-    // state is meant to be created and then live forever.
-    //
-    // I would love to register an at_exit() handler which cleans up this
-    // state, but libbacktrace provides no way to do so.
-    //
-    // With these constraints, this function has a statically cached state
-    // that is calculated the first time this is requested. Remember that
-    // backtracing all happens serially (one global lock).
-    //
-    // Things don't work so well on not-Linux since libbacktrace can't track
-    // down that executable this is. We at one point used env::current_exe but
-    // it turns out that there are some serious security issues with that
-    // approach.
-    //
-    // Specifically, on certain platforms like BSDs, a malicious actor can cause
-    // an arbitrary file to be placed at the path returned by current_exe.
-    // libbacktrace does not behave defensively in the presence of ill-formed
-    // DWARF information, and has been demonstrated to segfault in at least one
-    // case. There is no evidence at the moment to suggest that a more carefully
-    // constructed file can't cause arbitrary code execution. As a result of all
-    // of this, we don't hint libbacktrace with the path to the current process.
-    unsafe fn init_state() -> *mut backtrace_state {
-        static mut STATE: *mut backtrace_state = ptr::null_mut();
-        if !STATE.is_null() { return STATE }
-
-        let filename = match ::sys::backtrace::gnu::get_executable_filename() {
-            Ok((filename, file)) => {
-                // filename is purposely leaked here since libbacktrace requires
-                // it to stay allocated permanently, file is also leaked so that
-                // the file stays locked
-                let filename_ptr = filename.as_ptr();
-                mem::forget(filename);
-                mem::forget(file);
-                filename_ptr
-            },
-            Err(_) => ptr::null(),
-        };
-
-        STATE = backtrace_create_state(filename, 0, error_cb,
-                                       ptr::null_mut());
-        STATE
-    }
-
-    ////////////////////////////////////////////////////////////////////////
-    // translation
-    ////////////////////////////////////////////////////////////////////////
-
-    // backtrace errors are currently swept under the rug, only I/O
-    // errors are reported
-    let state = unsafe { init_state() };
-    if state.is_null() {
-        return output(w, idx, addr, None)
-    }
-    let mut data = ptr::null();
-    let data_addr = &mut data as *mut *const libc::c_char;
-    let ret = unsafe {
-        backtrace_syminfo(state, symaddr as libc::uintptr_t,
-                          syminfo_cb, error_cb,
-                          data_addr as *mut libc::c_void)
-    };
-    if ret == 0 || data.is_null() {
-        output(w, idx, addr, None)?;
-    } else {
-        output(w, idx, addr, Some(unsafe { CStr::from_ptr(data).to_bytes() }))?;
-    }
 
+use ffi::CStr;
+use io;
+use mem;
+use ptr;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
+
+pub fn foreach_symbol_fileline<F>(frame: Frame,
+                                  mut f: F,
+                                  _: &BacktraceContext) -> io::Result<bool>
+where F: FnMut(&[u8], libc::c_int) -> io::Result<()>
+{
     // pcinfo may return an arbitrary number of file:line pairs,
     // in the order of stack trace (i.e. inlined calls first).
     // in order to avoid allocation, we stack-allocate a fixed size of entries.
     const FILELINE_SIZE: usize = 32;
     let mut fileline_buf = [(ptr::null(), -1); FILELINE_SIZE];
     let ret;
-    let fileline_count;
-    {
+    let fileline_count = {
+        let state = unsafe { init_state() };
         let mut fileline_win: &mut [FileLine] = &mut fileline_buf;
         let fileline_addr = &mut fileline_win as *mut &mut [FileLine];
         ret = unsafe {
-            backtrace_pcinfo(state, addr as libc::uintptr_t,
-                             pcinfo_cb, error_cb,
+            backtrace_pcinfo(state,
+                             frame.exact_position as libc::uintptr_t,
+                             pcinfo_cb,
+                             error_cb,
                              fileline_addr as *mut libc::c_void)
         };
-        fileline_count = FILELINE_SIZE - fileline_win.len();
-    }
+        FILELINE_SIZE - fileline_win.len()
+    };
     if ret == 0 {
-        for (i, &(file, line)) in fileline_buf[..fileline_count].iter().enumerate() {
+        for &(file, line) in &fileline_buf[..fileline_count] {
             if file.is_null() { continue; } // just to be sure
             let file = unsafe { CStr::from_ptr(file).to_bytes() };
-            output_fileline(w, file, line, i == FILELINE_SIZE - 1)?;
+            f(file, line)?;
+        }
+        Ok(fileline_count == FILELINE_SIZE)
+    } else {
+        Ok(false)
+    }
+}
+
+/// Converts a pointer to symbol to its string value.
+pub fn resolve_symname<F>(frame: Frame,
+                          callback: F,
+                          _: &BacktraceContext) -> io::Result<()>
+    where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+    let symname = {
+        let state = unsafe { init_state() };
+        if state.is_null() {
+            None
+        } else {
+            let mut data = ptr::null();
+            let data_addr = &mut data as *mut *const libc::c_char;
+            let ret = unsafe {
+                backtrace_syminfo(state,
+                                  frame.symbol_addr as libc::uintptr_t,
+                                  syminfo_cb,
+                                  error_cb,
+                                  data_addr as *mut libc::c_void)
+            };
+            if ret == 0 || data.is_null() {
+                None
+            } else {
+                unsafe {
+                    CStr::from_ptr(data).to_str().ok()
+                }
+            }
+        }
+    };
+    callback(symname)
+}
+
+////////////////////////////////////////////////////////////////////////
+// libbacktrace.h API
+////////////////////////////////////////////////////////////////////////
+type backtrace_syminfo_callback =
+extern "C" fn(data: *mut libc::c_void,
+              pc: libc::uintptr_t,
+              symname: *const libc::c_char,
+              symval: libc::uintptr_t,
+              symsize: libc::uintptr_t);
+type backtrace_full_callback =
+extern "C" fn(data: *mut libc::c_void,
+              pc: libc::uintptr_t,
+              filename: *const libc::c_char,
+              lineno: libc::c_int,
+              function: *const libc::c_char) -> libc::c_int;
+type backtrace_error_callback =
+extern "C" fn(data: *mut libc::c_void,
+              msg: *const libc::c_char,
+              errnum: libc::c_int);
+enum backtrace_state {}
+#[link(name = "backtrace", kind = "static")]
+#[cfg(all(not(test), not(cargobuild)))]
+extern {}
+
+extern {
+    fn backtrace_create_state(filename: *const libc::c_char,
+                              threaded: libc::c_int,
+                              error: backtrace_error_callback,
+                              data: *mut libc::c_void)
+        -> *mut backtrace_state;
+    fn backtrace_syminfo(state: *mut backtrace_state,
+                         addr: libc::uintptr_t,
+                         cb: backtrace_syminfo_callback,
+                         error: backtrace_error_callback,
+                         data: *mut libc::c_void) -> libc::c_int;
+    fn backtrace_pcinfo(state: *mut backtrace_state,
+                        addr: libc::uintptr_t,
+                        cb: backtrace_full_callback,
+                        error: backtrace_error_callback,
+                        data: *mut libc::c_void) -> libc::c_int;
+}
+
+////////////////////////////////////////////////////////////////////////
+// helper callbacks
+////////////////////////////////////////////////////////////////////////
+
+type FileLine = (*const libc::c_char, libc::c_int);
+
+extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char,
+                   _errnum: libc::c_int) {
+    // do nothing for now
+}
+extern fn syminfo_cb(data: *mut libc::c_void,
+                     _pc: libc::uintptr_t,
+                     symname: *const libc::c_char,
+                     _symval: libc::uintptr_t,
+                     _symsize: libc::uintptr_t) {
+    let slot = data as *mut *const libc::c_char;
+    unsafe { *slot = symname; }
+}
+extern fn pcinfo_cb(data: *mut libc::c_void,
+                    _pc: libc::uintptr_t,
+                    filename: *const libc::c_char,
+                    lineno: libc::c_int,
+                    _function: *const libc::c_char) -> libc::c_int {
+    if !filename.is_null() {
+        let slot = data as *mut &mut [FileLine];
+        let buffer = unsafe {ptr::read(slot)};
+
+        // if the buffer is not full, add file:line to the buffer
+        // and adjust the buffer for next possible calls to pcinfo_cb.
+        if !buffer.is_empty() {
+            buffer[0] = (filename, lineno);
+            unsafe { ptr::write(slot, &mut buffer[1..]); }
         }
     }
 
-    Ok(())
+    0
+}
+
+// The libbacktrace API supports creating a state, but it does not
+// support destroying a state. I personally take this to mean that a
+// state is meant to be created and then live forever.
+//
+// I would love to register an at_exit() handler which cleans up this
+// state, but libbacktrace provides no way to do so.
+//
+// With these constraints, this function has a statically cached state
+// that is calculated the first time this is requested. Remember that
+// backtracing all happens serially (one global lock).
+//
+// Things don't work so well on not-Linux since libbacktrace can't track
+// down that executable this is. We at one point used env::current_exe but
+// it turns out that there are some serious security issues with that
+// approach.
+//
+// Specifically, on certain platforms like BSDs, a malicious actor can cause
+// an arbitrary file to be placed at the path returned by current_exe.
+// libbacktrace does not behave defensively in the presence of ill-formed
+// DWARF information, and has been demonstrated to segfault in at least one
+// case. There is no evidence at the moment to suggest that a more carefully
+// constructed file can't cause arbitrary code execution. As a result of all
+// of this, we don't hint libbacktrace with the path to the current process.
+unsafe fn init_state() -> *mut backtrace_state {
+    static mut STATE: *mut backtrace_state = ptr::null_mut();
+    if !STATE.is_null() { return STATE  }
+
+    let filename = match ::sys::backtrace::gnu::get_executable_filename() {
+        Ok((filename, file)) => {
+            // filename is purposely leaked here since libbacktrace requires
+            // it to stay allocated permanently, file is also leaked so that
+            // the file stays locked
+            let filename_ptr = filename.as_ptr();
+            mem::forget(filename);
+            mem::forget(file);
+            filename_ptr
+        },
+        Err(_) => ptr::null(),
+    };
+
+    STATE = backtrace_create_state(filename, 0, error_cb,
+                                   ptr::null_mut());
+    STATE
 }
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index 93e320c4522..2bc066d3fea 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -235,7 +235,7 @@ pub use self::local::{LocalKey, LocalKeyState};
 pub struct Builder {
     // A name for the thread-to-be, for identification in panic messages
     name: Option<String>,
-    // The size of the stack for the spawned thread
+    // The size of the stack for the spawned thread in bytes
     stack_size: Option<usize>,
 }
 
@@ -289,14 +289,17 @@ impl Builder {
         self
     }
 
-    /// Sets the size of the stack for the new thread.
+    /// Sets the size of the stack (in bytes) for the new thread.
+    ///
+    /// The actual stack size may be greater than this value if
+    /// the platform specifies minimal stack size.
     ///
     /// # Examples
     ///
     /// ```
     /// use std::thread;
     ///
-    /// let builder = thread::Builder::new().stack_size(10);
+    /// let builder = thread::Builder::new().stack_size(32 * 1024);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn stack_size(mut self, size: usize) -> Builder {
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 455a6a0fb32..096657a6e7a 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -909,25 +909,12 @@ fn int_type_of_word(s: &str) -> Option<IntType> {
 
 #[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
 pub enum ReprAttr {
-    ReprAny,
     ReprInt(IntType),
     ReprExtern,
     ReprPacked,
     ReprSimd,
 }
 
-impl ReprAttr {
-    pub fn is_ffi_safe(&self) -> bool {
-        match *self {
-            ReprAny => false,
-            ReprInt(ity) => ity.is_ffi_safe(),
-            ReprExtern => true,
-            ReprPacked => false,
-            ReprSimd => true,
-        }
-    }
-}
-
 #[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
 pub enum IntType {
     SignedInt(ast::IntTy),
@@ -942,16 +929,6 @@ impl IntType {
             UnsignedInt(..) => false
         }
     }
-    fn is_ffi_safe(self) -> bool {
-        match self {
-            SignedInt(ast::IntTy::I8) | UnsignedInt(ast::UintTy::U8) |
-            SignedInt(ast::IntTy::I16) | UnsignedInt(ast::UintTy::U16) |
-            SignedInt(ast::IntTy::I32) | UnsignedInt(ast::UintTy::U32) |
-            SignedInt(ast::IntTy::I64) | UnsignedInt(ast::UintTy::U64) |
-            SignedInt(ast::IntTy::I128) | UnsignedInt(ast::UintTy::U128) => true,
-            SignedInt(ast::IntTy::Is) | UnsignedInt(ast::UintTy::Us) => false
-        }
-    }
 }
 
 pub trait HasAttrs: Sized {
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index b61ab74687b..666e2205b4a 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -475,7 +475,7 @@ pub type BuiltinDeriveFn =
     for<'cx> fn(&'cx mut ExtCtxt, Span, &MetaItem, &Annotatable, &mut FnMut(Annotatable));
 
 /// Represents different kinds of macro invocations that can be resolved.
-#[derive(Clone, Copy, PartialEq, Eq)]
+#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum MacroKind {
     /// A bang macro - foo!()
     Bang,
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 1bed3e27847..c2b72edb66c 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -91,11 +91,14 @@ macro_rules! declare_features {
     }
 }
 
-// If you change this list without updating src/doc/reference.md, @cmr will be sad
+// If you change this, please modify src/doc/unstable-book as well.
+//
 // Don't ever remove anything from this list; set them to 'Removed'.
+//
 // The version numbers here correspond to the version in which the current status
 // was set. This is most important for knowing when a particular feature became
 // stable (active).
+//
 // NB: The featureck.py script parses this information directly out of the source
 // so take care when modifying it.
 
@@ -197,9 +200,6 @@ declare_features! (
     // rustc internal
     (active, prelude_import, "1.2.0", None),
 
-    // Allows the definition recursive static items.
-    (active, static_recursion, "1.3.0", Some(29719)),
-
     // Allows default type parameters to influence type inference.
     (active, default_type_parameter_fallback, "1.3.0", Some(27336)),
 
@@ -325,6 +325,10 @@ declare_features! (
 
     // Used to identify crates that contain sanitizer runtimes
     // rustc internal
+    (active, closure_to_fn_coercion, "1.17.0", Some(39817)),
+
+    // Used to identify crates that contain sanitizer runtimes
+    // rustc internal
     (active, sanitizer_runtime, "1.17.0", None),
 );
 
@@ -384,8 +388,12 @@ declare_features! (
     (accepted, static_in_const, "1.17.0", Some(35897)),
     // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
     (accepted, field_init_shorthand, "1.17.0", Some(37340)),
+    // Allows the definition recursive static items.
+    (accepted, static_recursion, "1.17.0", Some(29719)),
 );
-// (changing above list without updating src/doc/reference.md makes @cmr sad)
+// If you change this, please modify src/doc/unstable-book as well. You must
+// move that documentation into the relevant place in the other docs, and
+// remove the chapter on the flag.
 
 #[derive(PartialEq, Copy, Clone, Debug)]
 pub enum AttributeType {
@@ -977,6 +985,9 @@ pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
 pub const EXPLAIN_PLACEMENT_IN: &'static str =
     "placement-in expression syntax is experimental and subject to change.";
 
+pub const CLOSURE_TO_FN_COERCION: &'static str =
+    "non-capturing closure to fn coercion is experimental";
+
 struct PostExpansionVisitor<'a> {
     context: &'a Context<'a>,
 }
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 6bc15115b09..b7f6e6a2384 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -51,10 +51,10 @@ pub struct StringReader<'a> {
     pub filemap: Rc<syntax_pos::FileMap>,
     /// If Some, stop reading the source at this position (inclusive).
     pub terminator: Option<BytePos>,
-    /// Whether to record new-lines in filemap. This is only necessary the first
-    /// time a filemap is lexed. If part of a filemap is being re-lexed, this
-    /// should be set to false.
-    pub save_new_lines: bool,
+    /// Whether to record new-lines and multibyte chars in filemap.
+    /// This is only necessary the first time a filemap is lexed.
+    /// If part of a filemap is being re-lexed, this should be set to false.
+    pub save_new_lines_and_multibyte: bool,
     // cached:
     pub peek_tok: token::Token,
     pub peek_span: Span,
@@ -162,7 +162,7 @@ impl<'a> StringReader<'a> {
             ch: Some('\n'),
             filemap: filemap,
             terminator: None,
-            save_new_lines: true,
+            save_new_lines_and_multibyte: true,
             // dummy values; not read
             peek_tok: token::Eof,
             peek_span: syntax_pos::DUMMY_SP,
@@ -183,6 +183,31 @@ impl<'a> StringReader<'a> {
         sr
     }
 
+    pub fn retokenize(sess: &'a ParseSess, mut span: Span) -> Self {
+        let begin = sess.codemap().lookup_byte_offset(span.lo);
+        let end = sess.codemap().lookup_byte_offset(span.hi);
+
+        // Make the range zero-length if the span is invalid.
+        if span.lo > span.hi || begin.fm.start_pos != end.fm.start_pos {
+            span.hi = span.lo;
+        }
+
+        let mut sr = StringReader::new_raw_internal(sess, begin.fm);
+
+        // Seek the lexer to the right byte range.
+        sr.save_new_lines_and_multibyte = false;
+        sr.next_pos = span.lo;
+        sr.terminator = Some(span.hi);
+
+        sr.bump();
+
+        if let Err(_) = sr.advance_token() {
+            sr.emit_fatal_errors();
+            panic!(FatalError);
+        }
+        sr
+    }
+
     pub fn ch_is(&self, c: char) -> bool {
         self.ch == Some(c)
     }
@@ -378,7 +403,10 @@ impl<'a> StringReader<'a> {
     pub fn bump(&mut self) {
         let new_pos = self.next_pos;
         let new_byte_offset = self.byte_offset(new_pos).to_usize();
-        if new_byte_offset < self.source_text.len() {
+        let end = self.terminator.map_or(self.source_text.len(), |t| {
+            self.byte_offset(t).to_usize()
+        });
+        if new_byte_offset < end {
             let old_ch_is_newline = self.ch.unwrap() == '\n';
             let new_ch = char_at(&self.source_text, new_byte_offset);
             let new_ch_len = new_ch.len_utf8();
@@ -387,7 +415,7 @@ impl<'a> StringReader<'a> {
             self.pos = new_pos;
             self.next_pos = new_pos + Pos::from_usize(new_ch_len);
             if old_ch_is_newline {
-                if self.save_new_lines {
+                if self.save_new_lines_and_multibyte {
                     self.filemap.next_line(self.pos);
                 }
                 self.col = CharPos(0);
@@ -395,7 +423,9 @@ impl<'a> StringReader<'a> {
                 self.col = self.col + CharPos(1);
             }
             if new_ch_len > 1 {
-                self.filemap.record_multibyte_char(self.pos, new_ch_len);
+                if self.save_new_lines_and_multibyte {
+                    self.filemap.record_multibyte_char(self.pos, new_ch_len);
+                }
             }
         } else {
             self.ch = None;
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index bfab7a250c6..013632141de 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -68,6 +68,9 @@ pub trait Visitor<'ast>: Sized {
     fn visit_expr_post(&mut self, _ex: &'ast Expr) { }
     fn visit_ty(&mut self, t: &'ast Ty) { walk_ty(self, t) }
     fn visit_generics(&mut self, g: &'ast Generics) { walk_generics(self, g) }
+    fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
+        walk_where_predicate(self, p)
+    }
     fn visit_fn(&mut self, fk: FnKind<'ast>, fd: &'ast FnDecl, s: Span, _: NodeId) {
         walk_fn(self, fk, fd, s)
     }
@@ -488,28 +491,30 @@ pub fn walk_generics<'a, V: Visitor<'a>>(visitor: &mut V, generics: &'a Generics
         walk_list!(visitor, visit_attribute, &*param.attrs);
     }
     walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
-    for predicate in &generics.where_clause.predicates {
-        match *predicate {
-            WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty,
-                                                               ref bounds,
-                                                               ref bound_lifetimes,
-                                                               ..}) => {
-                visitor.visit_ty(bounded_ty);
-                walk_list!(visitor, visit_ty_param_bound, bounds);
-                walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
-            }
-            WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
-                                                                 ref bounds,
-                                                                 ..}) => {
-                visitor.visit_lifetime(lifetime);
-                walk_list!(visitor, visit_lifetime, bounds);
-            }
-            WherePredicate::EqPredicate(WhereEqPredicate{ref lhs_ty,
-                                                         ref rhs_ty,
-                                                         ..}) => {
-                visitor.visit_ty(lhs_ty);
-                visitor.visit_ty(rhs_ty);
-            }
+    walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates);
+}
+
+pub fn walk_where_predicate<'a, V: Visitor<'a>>(visitor: &mut V, predicate: &'a WherePredicate) {
+    match *predicate {
+        WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty,
+                                                           ref bounds,
+                                                           ref bound_lifetimes,
+                                                           ..}) => {
+            visitor.visit_ty(bounded_ty);
+            walk_list!(visitor, visit_ty_param_bound, bounds);
+            walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
+        }
+        WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
+                                                             ref bounds,
+                                                             ..}) => {
+            visitor.visit_lifetime(lifetime);
+            walk_list!(visitor, visit_lifetime, bounds);
+        }
+        WherePredicate::EqPredicate(WhereEqPredicate{ref lhs_ty,
+                                                     ref rhs_ty,
+                                                     ..}) => {
+            visitor.visit_ty(lhs_ty);
+            visitor.visit_ty(rhs_ty);
         }
     }
 }
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index ce64aef516f..fe492bd7fc8 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -773,7 +773,7 @@ fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> &
     for a in type_attrs {
         for r in &attr::find_repr_attrs(diagnostic, a) {
             repr_type_name = match *r {
-                attr::ReprAny | attr::ReprPacked | attr::ReprSimd => continue,
+                attr::ReprPacked | attr::ReprSimd => continue,
                 attr::ReprExtern => "i32",
 
                 attr::ReprInt(attr::SignedInt(ast::IntTy::Is)) => "isize",
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index 112bf61cf97..5fdb0aa0641 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -106,7 +106,7 @@ impl fmt::Display for TestName {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq)]
-enum NamePadding {
+pub enum NamePadding {
     PadNone,
     PadOnRight,
 }
@@ -950,7 +950,7 @@ fn stdout_isatty() -> bool {
 }
 
 #[derive(Clone)]
-enum TestEvent {
+pub enum TestEvent {
     TeFiltered(Vec<TestDesc>),
     TeWait(TestDesc, NamePadding),
     TeResult(TestDesc, TestResult, Vec<u8>),
@@ -960,7 +960,7 @@ enum TestEvent {
 pub type MonitorMsg = (TestDesc, TestResult, Vec<u8>);
 
 
-fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) -> io::Result<()>
+pub fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) -> io::Result<()>
     where F: FnMut(TestEvent) -> io::Result<()>
 {
     use std::collections::HashMap;
diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs
index 993fb703e51..077d57a9da3 100644
--- a/src/libtest/stats.rs
+++ b/src/libtest/stats.rs
@@ -264,8 +264,8 @@ impl Stats for [f64] {
         local_sort(&mut tmp);
         let first = 25f64;
         let a = percentile_of_sorted(&tmp, first);
-        let secound = 50f64;
-        let b = percentile_of_sorted(&tmp, secound);
+        let second = 50f64;
+        let b = percentile_of_sorted(&tmp, second);
         let third = 75f64;
         let c = percentile_of_sorted(&tmp, third);
         (a, b, c)
diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs
index 7fb58373251..e22f6702672 100644
--- a/src/libunwind/libunwind.rs
+++ b/src/libunwind/libunwind.rs
@@ -18,7 +18,7 @@ macro_rules! cfg_if {
 use libc::{c_int, c_void, uintptr_t};
 
 #[repr(C)]
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Debug, Copy, Clone, PartialEq)]
 pub enum _Unwind_Reason_Code {
     _URC_NO_REASON = 0,
     _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
diff --git a/src/rustc/std_shim/Cargo.toml b/src/rustc/std_shim/Cargo.toml
deleted file mode 100644
index db96079d3e9..00000000000
--- a/src/rustc/std_shim/Cargo.toml
+++ /dev/null
@@ -1,46 +0,0 @@
-# This is a shim Cargo.toml which serves as a proxy for building the standard
-# library. The reason for this is a little subtle, as one might reasonably
-# expect that we just `cargo build` the standard library itself.
-#
-# One of the output artifacts for the standard library is a dynamic library, and
-# on platforms like OSX the name of the output artifact is actually encoded into
-# the library itself (similar to a soname on Linux). When the library is linked
-# against, this encoded name is what's literally looked for at runtime when the
-# dynamic loader is probing for libraries.
-#
-# Cargo, however, by default will not mangle the output filename of the
-# top-level target. If we were to run `cargo build` on libstd itself, we would
-# generate a file `libstd.so`. When installing, however, this file is called
-# something like `libstd-abcdef0123.so`. On OSX at least this causes a failure
-# at runtime because the encoded "soname" is `libstd.so`, not what the file is
-# actually called.
-#
-# By using this shim library to build the standard library by proxy we sidestep
-# this problem. The standard library is built with mangled hex already in its
-# name so there's nothing extra we need to do.
-
-[package]
-name = "std_shim"
-version = "0.0.0"
-authors = ["The Rust Project Developers"]
-
-[lib]
-name = "std_shim"
-path = "lib.rs"
-doc = false
-
-[dependencies]
-std = { path = "../../libstd" }
-core = { path = "../../libcore" }
-
-# Reexport features from std
-[features]
-asan = ["std/asan"]
-backtrace = ["std/backtrace"]
-debug-jemalloc = ["std/debug-jemalloc"]
-jemalloc = ["std/jemalloc"]
-force_alloc_system = ["std/force_alloc_system"]
-lsan = ["std/lsan"]
-msan = ["std/msan"]
-panic-unwind = ["std/panic-unwind"]
-tsan = ["std/tsan"]
diff --git a/src/rustc/test_shim/Cargo.toml b/src/rustc/test_shim/Cargo.toml
deleted file mode 100644
index 6ef613eee06..00000000000
--- a/src/rustc/test_shim/Cargo.toml
+++ /dev/null
@@ -1,16 +0,0 @@
-# This is a shim Cargo.toml which serves as a proxy for building libtest.
-#
-# The reason this shim exists is basically the same reason that `std_shim`
-# exists, and more documentation can be found in that `Cargo.toml` as to why.
-
-[package]
-name = "test_shim"
-version = "0.0.0"
-authors = ["The Rust Project Developers"]
-
-[lib]
-name = "test_shim"
-path = "lib.rs"
-
-[dependencies]
-test = { path = "../../libtest" }
diff --git a/COMPILER_TESTS.md b/src/test/COMPILER_TESTS.md
index 58df1aae6d3..58df1aae6d3 100644
--- a/COMPILER_TESTS.md
+++ b/src/test/COMPILER_TESTS.md
diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs
index c373cdb76c5..76313b158ab 100644
--- a/src/test/codegen/function-arguments.rs
+++ b/src/test/codegen/function-arguments.rs
@@ -121,13 +121,13 @@ pub fn unsafe_slice(_: &[UnsafeInner]) {
 fn str(_: &[u8]) {
 }
 
-// CHECK: @trait_borrow(i8* nonnull, void (i8*)** nonnull)
+// CHECK: @trait_borrow(i8* nonnull, void (i8*)** noalias nonnull readonly)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 fn trait_borrow(_: &Drop) {
 }
 
-// CHECK: @trait_box(i8* noalias nonnull, void (i8*)** nonnull)
+// CHECK: @trait_box(i8* noalias nonnull, void (i8*)** noalias nonnull readonly)
 #[no_mangle]
 fn trait_box(_: Box<Drop>) {
 }
diff --git a/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs b/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs
index c9a36920a19..eac0be6f848 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs
@@ -22,15 +22,24 @@ extern crate attr_proc_macro;
 
 use attr_proc_macro::attr_proc_macro;
 
-#[derive(FooWithLongNam)]
-//~^ ERROR cannot find derive macro `FooWithLongNam` in this scope
+macro_rules! FooWithLongNam {
+    () => {}
+}
+
+#[derive(FooWithLongNan)]
+//~^ ERROR cannot find derive macro `FooWithLongNan` in this scope
 //~^^ HELP did you mean `FooWithLongName`?
 struct Foo;
 
 #[attr_proc_macra]
 //~^ ERROR cannot find attribute macro `attr_proc_macra` in this scope
+//~^^ HELP did you mean `attr_proc_macro`?
 struct Bar;
 
+#[FooWithLongNan]
+//~^ ERROR cannot find attribute macro `FooWithLongNan` in this scope
+struct Asdf;
+
 #[derive(Dlone)]
 //~^ ERROR cannot find derive macro `Dlone` in this scope
 //~^^ HELP did you mean `Clone`?
@@ -41,4 +50,18 @@ struct A;
 //~^^ HELP did you mean `Clona`?
 struct B;
 
-fn main() {}
+#[derive(attr_proc_macra)]
+//~^ ERROR cannot find derive macro `attr_proc_macra` in this scope
+struct C;
+
+fn main() {
+    FooWithLongNama!();
+    //~^ ERROR cannot find macro `FooWithLongNama!` in this scope
+    //~^^ HELP did you mean `FooWithLongNam!`?
+
+    attr_proc_macra!();
+    //~^ ERROR cannot find macro `attr_proc_macra!` in this scope
+
+    Dlona!();
+    //~^ ERROR cannot find macro `Dlona!` in this scope
+}
diff --git a/src/test/compile-fail/E0081.rs b/src/test/compile-fail/E0081.rs
index e12eff72c7f..9911e093a89 100644
--- a/src/test/compile-fail/E0081.rs
+++ b/src/test/compile-fail/E0081.rs
@@ -9,10 +9,10 @@
 // except according to those terms.
 
 enum Enum {
-    P = 3, //~ NOTE first use of `3`
+    P = 3, //~ NOTE first use of `3isize`
     X = 3,
-    //~^ ERROR discriminant value `3` already exists
-    //~| NOTE enum already has `3`
+    //~^ ERROR discriminant value `3isize` already exists
+    //~| NOTE enum already has `3isize`
     Y = 5
 }
 
diff --git a/src/test/compile-fail/E0117.rs b/src/test/compile-fail/E0117.rs
index 4ba9c3382f3..3da00da205f 100644
--- a/src/test/compile-fail/E0117.rs
+++ b/src/test/compile-fail/E0117.rs
@@ -12,6 +12,8 @@ impl Drop for u32 {} //~ ERROR E0117
 //~^ NOTE impl doesn't use types inside crate
 //~| NOTE the impl does not reference any types defined in this crate
 //~| NOTE define and implement a trait or new type instead
+//~| ERROR the Drop trait may only be implemented on structures
+//~| implementing Drop requires a struct
 
 fn main() {
 }
diff --git a/src/test/compile-fail/E0306.rs b/src/test/compile-fail/E0306.rs
deleted file mode 100644
index 9ffaef7472b..00000000000
--- a/src/test/compile-fail/E0306.rs
+++ /dev/null
@@ -1,24 +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.
-
-const A: [u32; "hello"] = [];
-//~^ ERROR expected `usize` for array length, found string literal [E0306]
-//~| NOTE expected `usize`
-
-const B: [u32; true] = [];
-//~^ ERROR expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
-
-const C: [u32; 0.0] = [];
-//~^ ERROR expected `usize` for array length, found float [E0306]
-//~| NOTE expected `usize`
-
-fn main() {
-}
diff --git a/src/test/compile-fail/asm-bad-clobber.rs b/src/test/compile-fail/asm-bad-clobber.rs
index cb931329051..145662fd87c 100644
--- a/src/test/compile-fail/asm-bad-clobber.rs
+++ b/src/test/compile-fail/asm-bad-clobber.rs
@@ -13,6 +13,7 @@
 // ignore-aarch64
 // ignore-s390x
 // ignore-emscripten
+// ignore-powerpc
 
 #![feature(asm, rustc_attrs)]
 
diff --git a/src/test/compile-fail/asm-in-bad-modifier.rs b/src/test/compile-fail/asm-in-bad-modifier.rs
index 7ba5beac213..f0467e75223 100644
--- a/src/test/compile-fail/asm-in-bad-modifier.rs
+++ b/src/test/compile-fail/asm-in-bad-modifier.rs
@@ -10,6 +10,7 @@
 
 // ignore-s390x
 // ignore-emscripten
+// ignore-powerpc
 
 #![feature(asm)]
 
diff --git a/src/test/compile-fail/asm-misplaced-option.rs b/src/test/compile-fail/asm-misplaced-option.rs
index bafbf625e35..37a26753531 100644
--- a/src/test/compile-fail/asm-misplaced-option.rs
+++ b/src/test/compile-fail/asm-misplaced-option.rs
@@ -13,6 +13,7 @@
 // ignore-aarch64
 // ignore-s390x
 // ignore-emscripten
+// ignore-powerpc
 
 #![feature(asm, rustc_attrs)]
 
diff --git a/src/test/compile-fail/asm-out-assign-imm.rs b/src/test/compile-fail/asm-out-assign-imm.rs
index 161c0b977ff..3c4a5dcb7b0 100644
--- a/src/test/compile-fail/asm-out-assign-imm.rs
+++ b/src/test/compile-fail/asm-out-assign-imm.rs
@@ -10,6 +10,7 @@
 
 // ignore-s390x
 // ignore-emscripten
+// ignore-powerpc
 
 #![feature(asm)]
 
diff --git a/src/test/compile-fail/asm-out-no-modifier.rs b/src/test/compile-fail/asm-out-no-modifier.rs
index cb8fb19a7c7..acf575c003a 100644
--- a/src/test/compile-fail/asm-out-no-modifier.rs
+++ b/src/test/compile-fail/asm-out-no-modifier.rs
@@ -10,6 +10,7 @@
 
 // ignore-s390x
 // ignore-emscripten
+// ignore-powerpc
 
 #![feature(asm)]
 
diff --git a/src/test/compile-fail/asm-out-read-uninit.rs b/src/test/compile-fail/asm-out-read-uninit.rs
index 42bff4c633a..bd180f6e5eb 100644
--- a/src/test/compile-fail/asm-out-read-uninit.rs
+++ b/src/test/compile-fail/asm-out-read-uninit.rs
@@ -10,6 +10,7 @@
 
 // ignore-s390x
 // ignore-emscripten
+// ignore-powerpc
 
 #![feature(asm)]
 
diff --git a/src/test/compile-fail/associated-const-array-len.rs b/src/test/compile-fail/associated-const-array-len.rs
index 0239986f5ad..7f77ae2ec1f 100644
--- a/src/test/compile-fail/associated-const-array-len.rs
+++ b/src/test/compile-fail/associated-const-array-len.rs
@@ -14,7 +14,8 @@ trait Foo {
     const ID: usize;
 }
 
-const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0080
+const X: [i32; <i32 as Foo>::ID] = [0, 1, 2];
+//~^ ERROR the trait bound `i32: Foo` is not satisfied
 
 fn main() {
     assert_eq!(1, X);
diff --git a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs
index 7c3f7a1d574..7fd9605ef2c 100644
--- a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs
+++ b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs
@@ -27,8 +27,6 @@ impl Foo for Def {
 pub fn test<A: Foo, B: Foo>() {
     let _array = [4; <A as Foo>::Y];
     //~^ ERROR cannot use an outer type parameter in this context [E0402]
-    //~| ERROR constant evaluation error [E0080]
-    //~| non-constant path in constant
 }
 
 fn main() {
diff --git a/src/test/compile-fail/associated-const-type-parameter-arrays.rs b/src/test/compile-fail/associated-const-type-parameter-arrays.rs
index dcf87d5f0fc..71c7a3965ec 100644
--- a/src/test/compile-fail/associated-const-type-parameter-arrays.rs
+++ b/src/test/compile-fail/associated-const-type-parameter-arrays.rs
@@ -27,8 +27,6 @@ impl Foo for Def {
 pub fn test<A: Foo, B: Foo>() {
     let _array: [u32; <A as Foo>::Y];
     //~^ ERROR cannot use an outer type parameter in this context [E0402]
-    //~| ERROR constant evaluation error [E0080]
-    //~| non-constant path in constant
 }
 
 fn main() {
diff --git a/src/test/compile-fail/closure-no-fn.rs b/src/test/compile-fail/closure-no-fn.rs
new file mode 100644
index 00000000000..fe179e8a48f
--- /dev/null
+++ b/src/test/compile-fail/closure-no-fn.rs
@@ -0,0 +1,24 @@
+// 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.
+
+// Ensure that capturing closures are never coerced to fns
+// Especially interesting as non-capturing closures can be.
+
+fn main() {
+    let mut a = 0u8;
+    let foo: fn(u8) -> u8 = |v: u8| { a += v; a };
+    //~^ ERROR mismatched types
+    let b = 0u8;
+    let bar: fn() -> u8 = || { b };
+    //~^ ERROR mismatched types
+    let baz: fn() -> u8 = || { b } as fn() -> u8;
+    //~^ ERROR mismatched types
+    //~^^ ERROR non-scalar cast
+}
diff --git a/src/test/compile-fail/coherence-cross-crate-conflict.rs b/src/test/compile-fail/coherence-cross-crate-conflict.rs
index 9f74afbb2b3..aac870293fd 100644
--- a/src/test/compile-fail/coherence-cross-crate-conflict.rs
+++ b/src/test/compile-fail/coherence-cross-crate-conflict.rs
@@ -17,6 +17,7 @@ use trait_impl_conflict::Foo;
 
 impl<A> Foo for A {
     //~^ ERROR type parameter `A` must be used as the type parameter for some local type
+    //~| ERROR conflicting implementations of trait `trait_impl_conflict::Foo` for type `isize`
 }
 
 fn main() {
diff --git a/src/test/compile-fail/coherence-default-trait-impl.rs b/src/test/compile-fail/coherence-default-trait-impl.rs
index 3d109de76cc..15a80c64f8b 100644
--- a/src/test/compile-fail/coherence-default-trait-impl.rs
+++ b/src/test/compile-fail/coherence-default-trait-impl.rs
@@ -13,9 +13,9 @@
 trait MyTrait {}
 
 impl MyTrait for .. {}
+//~^ ERROR redundant default implementations of trait `MyTrait`
 
 impl MyTrait for .. {}
-//~^ ERROR redundant default implementations of trait `MyTrait`
 
 trait MySafeTrait {}
 
diff --git a/src/test/compile-fail/coherence-impls-sized.rs b/src/test/compile-fail/coherence-impls-sized.rs
index 79767e5157b..60b5d14d158 100644
--- a/src/test/compile-fail/coherence-impls-sized.rs
+++ b/src/test/compile-fail/coherence-impls-sized.rs
@@ -27,14 +27,20 @@ impl Sized for TestE {} //~ ERROR E0322
 impl Sized for MyType {} //~ ERROR E0322
 //~^ impl of 'Sized' not allowed
 
-impl Sized for (MyType, MyType) {} //~ ERROR E0117
+impl Sized for (MyType, MyType) {} //~ ERROR E0322
+//~^ impl of 'Sized' not allowed
+//~| ERROR E0117
 
 impl Sized for &'static NotSync {} //~ ERROR E0322
 //~^ impl of 'Sized' not allowed
 
-impl Sized for [MyType] {} //~ ERROR E0117
+impl Sized for [MyType] {} //~ ERROR E0322
+//~^ impl of 'Sized' not allowed
+//~| ERROR E0117
 
-impl Sized for &'static [NotSync] {} //~ ERROR E0117
+impl Sized for &'static [NotSync] {} //~ ERROR E0322
+//~^ impl of 'Sized' not allowed
+//~| ERROR E0117
 
 fn main() {
 }
diff --git a/src/test/compile-fail/const-array-oob.rs b/src/test/compile-fail/const-array-oob.rs
index b980bc02c85..108b7948dfc 100644
--- a/src/test/compile-fail/const-array-oob.rs
+++ b/src/test/compile-fail/const-array-oob.rs
@@ -12,8 +12,8 @@
 
 #![feature(const_indexing)]
 
-const FOO: [u32; 3] = [1, 2, 3];
-const BAR: u32 = FOO[5]; // no error, because the error below occurs before regular const eval
+const FOO: [usize; 3] = [1, 2, 3];
+const BAR: usize = FOO[5]; // no error, because the error below occurs before regular const eval
 
 const BLUB: [u32; FOO[4]] = [5, 6];
 //~^ ERROR constant evaluation error [E0080]
diff --git a/src/test/compile-fail/const-block-non-item-statement-2.rs b/src/test/compile-fail/const-block-non-item-statement-2.rs
new file mode 100644
index 00000000000..83166c9bd4b
--- /dev/null
+++ b/src/test/compile-fail/const-block-non-item-statement-2.rs
@@ -0,0 +1,26 @@
+// 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.
+
+const A: usize = { 1; 2 };
+//~^ ERROR: blocks in constants are limited to items and tail expressions
+
+const B: usize = { { } 2 };
+//~^ ERROR: blocks in constants are limited to items and tail expressions
+
+macro_rules! foo {
+    () => (()) //~ ERROR: blocks in constants are limited to items and tail expressions
+}
+const C: usize = { foo!(); 2 };
+
+const D: usize = { let x = 4; 2 };
+//~^ ERROR: blocks in constants are limited to items and tail expressions
+//~^^ ERROR: blocks in constants are limited to items and tail expressions
+
+pub fn main() {}
diff --git a/src/test/compile-fail/const-block-non-item-statement.rs b/src/test/compile-fail/const-block-non-item-statement.rs
index edb85023c9b..bdc69c937c6 100644
--- a/src/test/compile-fail/const-block-non-item-statement.rs
+++ b/src/test/compile-fail/const-block-non-item-statement.rs
@@ -8,21 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-const A: usize = { 1; 2 };
-//~^ ERROR: blocks in constants are limited to items and tail expressions
-
-const B: usize = { { } 2 };
-//~^ ERROR: blocks in constants are limited to items and tail expressions
-
-macro_rules! foo {
-    () => (()) //~ ERROR: blocks in constants are limited to items and tail expressions
-}
-const C: usize = { foo!(); 2 };
-
-const D: usize = { let x = 4; 2 };
-//~^ ERROR: blocks in constants are limited to items and tail expressions
-//~^^ ERROR: blocks in constants are limited to items and tail expressions
-
 enum Foo {
     Bar = { let x = 1; 3 }
     //~^ ERROR: blocks in constants are limited to items and tail expressions
@@ -33,8 +18,4 @@ type Array = [u32; {  let x = 2; 5 }];
 //~^ ERROR: blocks in constants are limited to items and tail expressions
 //~^^ ERROR: blocks in constants are limited to items and tail expressions
 
-pub fn main() {
-    let _: Array = [0; { let x = 3; 5 }];
-    //~^ ERROR: blocks in constants are limited to items and tail expressions
-    //~^^ ERROR: blocks in constants are limited to items and tail expressions
-}
+pub fn main() {}
diff --git a/src/test/compile-fail/const-call.rs b/src/test/compile-fail/const-call.rs
index 7e2eabf412d..ff83dd004a2 100644
--- a/src/test/compile-fail/const-call.rs
+++ b/src/test/compile-fail/const-call.rs
@@ -15,6 +15,8 @@ fn f(x: usize) -> usize {
 }
 
 fn main() {
-    let _ = [0; f(2)]; //~ ERROR constant evaluation error [E0080]
-                       //~| non-constant path in constant expression
+    let _ = [0; f(2)];
+    //~^ ERROR calls in constants are limited to constant functions
+    //~| ERROR constant evaluation error [E0080]
+    //~| non-constant path in constant expression
 }
diff --git a/src/test/compile-fail/const-eval-overflow-4b.rs b/src/test/compile-fail/const-eval-overflow-4b.rs
index 9e7a5ecae10..02072e9a1a1 100644
--- a/src/test/compile-fail/const-eval-overflow-4b.rs
+++ b/src/test/compile-fail/const-eval-overflow-4b.rs
@@ -20,8 +20,9 @@ use std::{u8, u16, u32, u64, usize};
 
 const A_I8_T
     : [u32; (i8::MAX as i8 + 1u8) as usize]
-    //~^ ERROR constant evaluation error [E0080]
+    //~^ ERROR mismatched types
     //~| expected i8, found u8
+    //~| ERROR the trait bound `i8: std::ops::Add<u8>` is not satisfied
     = [0; (i8::MAX as usize) + 1];
 
 
@@ -32,8 +33,7 @@ const A_CHAR_USIZE
 
 const A_BAD_CHAR_USIZE
     : [u32; 5i8 as char as usize]
-    //~^ ERROR constant evaluation error
-    //~| only `u8` can be cast as `char`, not `i8`
+    //~^ ERROR only `u8` can be cast as `char`, not `i8`
     = [0; 5];
 
 fn main() {}
diff --git a/src/test/compile-fail/const-eval-span.rs b/src/test/compile-fail/const-eval-span.rs
index 73351429b50..16f89606b01 100644
--- a/src/test/compile-fail/const-eval-span.rs
+++ b/src/test/compile-fail/const-eval-span.rs
@@ -14,12 +14,13 @@
 struct S(i32);
 
 const CONSTANT: S = S(0);
-//~^ ERROR E0080
-//~| unimplemented constant expression: tuple struct constructors
 
 enum E {
     V = CONSTANT,
-    //~^ NOTE: for enum discriminant here
+    //~^ ERROR mismatched types
+    //~| expected isize, found struct `S`
+    //~| NOTE expected type `isize`
+    //~|         found type `S`
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/const-integer-bool-ops.rs b/src/test/compile-fail/const-integer-bool-ops.rs
index 398dc2f2215..29bc665a22e 100644
--- a/src/test/compile-fail/const-integer-bool-ops.rs
+++ b/src/test/compile-fail/const-integer-bool-ops.rs
@@ -8,52 +8,71 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-const X: usize = 42 && 39; //~ ERROR E0080
-                           //~| can't do this op on integrals
-const ARR: [i32; X] = [99; 34]; //~ NOTE: for array length here
+const X: usize = 42 && 39;
+//~^ ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected usize, found bool
+const ARR: [i32; X] = [99; 34];
 
-const X1: usize = 42 || 39; //~ ERROR E0080
-                            //~| can't do this op on integrals
-const ARR1: [i32; X1] = [99; 47]; //~ NOTE: for array length here
+const X1: usize = 42 || 39;
+//~^ ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected usize, found bool
+const ARR1: [i32; X1] = [99; 47];
 
-const X2: usize = -42 || -39; //~ ERROR E0080
-                              //~| unary negation of unsigned integer
-const ARR2: [i32; X2] = [99; 18446744073709551607]; //~ NOTE: for array length here
+const X2: usize = -42 || -39;
+//~^ ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected usize, found bool
+const ARR2: [i32; X2] = [99; 18446744073709551607];
 
-const X3: usize = -42 && -39; //~ ERROR E0080
-                              //~| unary negation of unsigned integer
-const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here
+const X3: usize = -42 && -39;
+//~^ ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected usize, found bool
+const ARR3: [i32; X3] = [99; 6];
 
 const Y: usize = 42.0 == 42.0;
+//~^ ERROR mismatched types
+//~| expected usize, found bool
 const ARRR: [i32; Y] = [99; 1];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
 
 const Y1: usize = 42.0 >= 42.0;
-const ARRR1: [i32; Y] = [99; 1];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR1: [i32; Y1] = [99; 1];
 
 const Y2: usize = 42.0 <= 42.0;
-const ARRR2: [i32; Y] = [99; 1];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR2: [i32; Y2] = [99; 1];
 
 const Y3: usize = 42.0 > 42.0;
-const ARRR3: [i32; Y] = [99; 0];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR3: [i32; Y3] = [99; 0];
 
 const Y4: usize = 42.0 < 42.0;
-const ARRR4: [i32; Y] = [99; 0];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR4: [i32; Y4] = [99; 0];
 
 const Y5: usize = 42.0 != 42.0;
-const ARRR5: [i32; Y] = [99; 0];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
-
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR5: [i32; Y5] = [99; 0];
 
 fn main() {
     let _ = ARR;
diff --git a/src/test/compile-fail/const-tup-index-span.rs b/src/test/compile-fail/const-tup-index-span.rs
index f3fb92e2b22..b42c440f87d 100644
--- a/src/test/compile-fail/const-tup-index-span.rs
+++ b/src/test/compile-fail/const-tup-index-span.rs
@@ -11,8 +11,8 @@
 // Test spans of errors
 
 const TUP: (usize,) = 5usize << 64;
-//~^ ERROR E0080
-//~| attempt to shift left with overflow
+//~^ ERROR mismatched types
+//~| expected tuple, found usize
 const ARR: [i32; TUP.0] = [];
 
 fn main() {
diff --git a/src/test/compile-fail/cycle-projection-based-on-where-clause.rs b/src/test/compile-fail/cycle-projection-based-on-where-clause.rs
index 5ca0700ce6e..7af2f11bd28 100644
--- a/src/test/compile-fail/cycle-projection-based-on-where-clause.rs
+++ b/src/test/compile-fail/cycle-projection-based-on-where-clause.rs
@@ -26,6 +26,7 @@ struct A<T>
     where T : Trait,
           T : Add<T::Item>
     //~^ ERROR unsupported cyclic reference between types/traits detected
+    //~| ERROR associated type `Item` not found for `T`
 {
     data: T
 }
diff --git a/src/test/compile-fail/cycle-trait-default-type-trait.rs b/src/test/compile-fail/cycle-trait-default-type-trait.rs
index e6caeb34a8c..6825572b26c 100644
--- a/src/test/compile-fail/cycle-trait-default-type-trait.rs
+++ b/src/test/compile-fail/cycle-trait-default-type-trait.rs
@@ -13,6 +13,7 @@
 
 trait Foo<X = Box<Foo>> {
     //~^ ERROR unsupported cyclic reference
+    //~| ERROR unsupported cyclic reference
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/cycle-trait-supertrait-indirect.rs b/src/test/compile-fail/cycle-trait-supertrait-indirect.rs
index c9bfde3f4ed..905d546e99a 100644
--- a/src/test/compile-fail/cycle-trait-supertrait-indirect.rs
+++ b/src/test/compile-fail/cycle-trait-supertrait-indirect.rs
@@ -12,14 +12,16 @@
 // a direct participant in the cycle.
 
 trait A: B {
-    //~^ ERROR unsupported cyclic reference
+    //~^ NOTE the cycle begins when computing the supertraits of `B`...
 }
 
 trait B: C {
-    //~^ ERROR unsupported cyclic reference
+    //~^ NOTE ...which then requires computing the supertraits of `C`...
 }
 
 trait C: B { }
     //~^ ERROR unsupported cyclic reference
+    //~| cyclic reference
+    //~| NOTE ...which then again requires computing the supertraits of `B`, completing the cycle
 
 fn main() { }
diff --git a/src/test/compile-fail/default_ty_param_conflict.rs b/src/test/compile-fail/default_ty_param_conflict.rs
index 4702b504f15..8cde239ca6e 100644
--- a/src/test/compile-fail/default_ty_param_conflict.rs
+++ b/src/test/compile-fail/default_ty_param_conflict.rs
@@ -23,8 +23,6 @@ fn main() {
     // Here, F is instantiated with $0=uint
     let x = foo();
     //~^ ERROR: mismatched types
-    //~| expected type `usize`
-    //~| found type `isize`
     //~| NOTE: conflicting type parameter defaults `usize` and `isize`
     //~| NOTE: conflicting type parameter defaults `usize` and `isize`
     //~| NOTE: ...that was applied to an unconstrained type variable here
diff --git a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs
index b608c6c99be..e5b035e50aa 100644
--- a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs
+++ b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs
@@ -29,6 +29,4 @@ fn main() {
     //~| NOTE: conflicting type parameter defaults `bool` and `char`
     //~| a second default is defined on `default_param_test::bleh`
     //~| NOTE:  ...that was applied to an unconstrained type variable here
-    //~| expected type `bool`
-    //~| found type `char`
 }
diff --git a/src/test/compile-fail/discrim-ill-typed.rs b/src/test/compile-fail/discrim-ill-typed.rs
index c73b7e831b3..62e54c3f237 100644
--- a/src/test/compile-fail/discrim-ill-typed.rs
+++ b/src/test/compile-fail/discrim-ill-typed.rs
@@ -25,7 +25,7 @@ fn f_i8() {
         Ok = i8::MAX - 1,
         Ok2,
         OhNo = 0_u8,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected i8, found u8
     }
 
@@ -38,7 +38,7 @@ fn f_u8() {
         Ok = u8::MAX - 1,
         Ok2,
         OhNo = 0_i8,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected u8, found i8
     }
 
@@ -51,7 +51,7 @@ fn f_i16() {
         Ok = i16::MAX - 1,
         Ok2,
         OhNo = 0_u16,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected i16, found u16
     }
 
@@ -64,7 +64,7 @@ fn f_u16() {
         Ok = u16::MAX - 1,
         Ok2,
         OhNo = 0_i16,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected u16, found i16
     }
 
@@ -77,7 +77,7 @@ fn f_i32() {
         Ok = i32::MAX - 1,
         Ok2,
         OhNo = 0_u32,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected i32, found u32
     }
 
@@ -90,7 +90,7 @@ fn f_u32() {
         Ok = u32::MAX - 1,
         Ok2,
         OhNo = 0_i32,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected u32, found i32
     }
 
@@ -103,7 +103,7 @@ fn f_i64() {
         Ok = i64::MAX - 1,
         Ok2,
         OhNo = 0_u64,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected i64, found u64
     }
 
@@ -116,7 +116,7 @@ fn f_u64() {
         Ok = u64::MAX - 1,
         Ok2,
         OhNo = 0_i64,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected u64, found i64
     }
 
diff --git a/src/test/compile-fail/enum-discrim-too-small.rs b/src/test/compile-fail/enum-discrim-too-small.rs
index bbdb3891d99..393a67be57f 100644
--- a/src/test/compile-fail/enum-discrim-too-small.rs
+++ b/src/test/compile-fail/enum-discrim-too-small.rs
@@ -13,32 +13,32 @@
 enum Eu8 {
     Au8 = 23,
     Bu8 = 223,
-    Cu8 = -23, //~ ERROR E0080
-               //~| unary negation of unsigned integer
+    Cu8 = -23,
+    //~^ ERROR cannot apply unary operator `-` to type `u8`
 }
 
 #[repr(u16)]
 enum Eu16 {
     Au16 = 23,
     Bu16 = 55555,
-    Cu16 = -22333, //~ ERROR E0080
-                   //~| unary negation of unsigned integer
+    Cu16 = -22333,
+    //~^ ERROR cannot apply unary operator `-` to type `u16`
 }
 
 #[repr(u32)]
 enum Eu32 {
     Au32 = 23,
     Bu32 = 3_000_000_000,
-    Cu32 = -2_000_000_000, //~ ERROR E0080
-                           //~| unary negation of unsigned integer
+    Cu32 = -2_000_000_000,
+    //~^ ERROR cannot apply unary operator `-` to type `u32`
 }
 
 #[repr(u64)]
 enum Eu64 {
     Au32 = 23,
     Bu32 = 3_000_000_000,
-    Cu32 = -2_000_000_000, //~ ERROR E0080
-                           //~| unary negation of unsigned integer
+    Cu32 = -2_000_000_000,
+    //~^ ERROR cannot apply unary operator `-` to type `u64`
 }
 
 // u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`.  This is a
diff --git a/src/test/compile-fail/feature-gate-closure_to_fn_coercion.rs b/src/test/compile-fail/feature-gate-closure_to_fn_coercion.rs
new file mode 100644
index 00000000000..d074a35628e
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-closure_to_fn_coercion.rs
@@ -0,0 +1,45 @@
+// 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.
+
+// ignore-stage0: new feature, remove this when SNAP
+// revisions: a b
+
+#[cfg(a)]
+mod a {
+    const FOO: fn(u8) -> u8 = |v: u8| { v };
+    //[a]~^ ERROR non-capturing closure to fn coercion is experimental
+    //[a]~^^ ERROR mismatched types
+
+    const BAR: [fn(&mut u32); 1] = [
+        |v: &mut u32| *v += 1,
+    //[a]~^ ERROR non-capturing closure to fn coercion is experimental
+    //[a]~^^ ERROR mismatched types
+    ];
+}
+
+#[cfg(b)]
+mod b {
+    fn func_specific() -> (fn() -> u32) {
+        || return 42
+        //[b]~^ ERROR non-capturing closure to fn coercion is experimental
+        //[b]~^^ ERROR mismatched types
+    }
+    fn foo() {
+        // Items
+        assert_eq!(func_specific()(), 42);
+        let foo: fn(u8) -> u8 = |v: u8| { v };
+        //[b]~^ ERROR non-capturing closure to fn coercion is experimental
+        //[b]~^^ ERROR mismatched types
+    }
+
+}
+
+
+
diff --git a/src/test/compile-fail/feature-gate-static_recursion.rs b/src/test/compile-fail/feature-gate-static_recursion.rs
deleted file mode 100644
index bd20c891d8e..00000000000
--- a/src/test/compile-fail/feature-gate-static_recursion.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
-//~^ ERROR recursive static (see issue #29719)
-
-struct StaticDoubleLinked {
-    prev: &'static StaticDoubleLinked,
-    next: &'static StaticDoubleLinked,
-    data: i32,
-    head: bool,
-}
-
-static L1: StaticDoubleLinked = StaticDoubleLinked{prev: &L3, next: &L2, data: 1, head: true};
-//~^ ERROR recursive static (see issue #29719)
-//~^^ ERROR recursive static (see issue #29719)
-//~^^^ ERROR recursive static (see issue #29719)
-static L2: StaticDoubleLinked = StaticDoubleLinked{prev: &L1, next: &L3, data: 2, head: false};
-static L3: StaticDoubleLinked = StaticDoubleLinked{prev: &L2, next: &L1, data: 3, head: false};
-
-
-pub fn main() {
-    unsafe { assert_eq!(S, *(S as *const *const u8)); }
-
-    let mut test_vec = Vec::new();
-    let mut cur = &L1;
-    loop {
-        test_vec.push(cur.data);
-        cur = cur.next;
-        if cur.head { break }
-    }
-    assert_eq!(&test_vec, &[1,2,3]);
-
-    let mut test_vec = Vec::new();
-    let mut cur = &L1;
-    loop {
-        cur = cur.prev;
-        test_vec.push(cur.data);
-        if cur.head { break }
-    }
-    assert_eq!(&test_vec, &[3,2,1]);
-}
diff --git a/src/test/compile-fail/generic-non-trailing-defaults.rs b/src/test/compile-fail/generic-non-trailing-defaults.rs
index 77e55203263..13b7753082c 100644
--- a/src/test/compile-fail/generic-non-trailing-defaults.rs
+++ b/src/test/compile-fail/generic-non-trailing-defaults.rs
@@ -10,10 +10,10 @@
 
 struct Heap;
 
-struct Vec<A = Heap, T>;
+struct Vec<A = Heap, T>(A, T);
 //~^ ERROR type parameters with a default must be trailing
 
-struct Foo<A, B = Vec<C>, C>;
+struct Foo<A, B = Vec<C>, C>(A, B, C);
 //~^ ERROR type parameters with a default must be trailing
 //~| ERROR type parameters with a default cannot use forward declared identifiers
 
diff --git a/src/test/compile-fail/generic-type-params-forward-mention.rs b/src/test/compile-fail/generic-type-params-forward-mention.rs
index eda1b014fa7..bfa6af0da43 100644
--- a/src/test/compile-fail/generic-type-params-forward-mention.rs
+++ b/src/test/compile-fail/generic-type-params-forward-mention.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // Ensure that we get an error and not an ICE for this problematic case.
-struct Foo<T = Option<U>, U = bool>;
+struct Foo<T = Option<U>, U = bool>(T, U);
 //~^ ERROR type parameters with a default cannot use forward declared identifiers
 fn main() {
     let x: Foo;
diff --git a/src/test/compile-fail/impl-trait/auto-trait-leak.rs b/src/test/compile-fail/impl-trait/auto-trait-leak.rs
index f055d20e134..13e53cab172 100644
--- a/src/test/compile-fail/impl-trait/auto-trait-leak.rs
+++ b/src/test/compile-fail/impl-trait/auto-trait-leak.rs
@@ -52,23 +52,20 @@ fn after() -> impl Fn(i32) {
 // independently resolved and only require the concrete
 // return type, which can't depend on the obligation.
 fn cycle1() -> impl Clone {
+    //~^ ERROR unsupported cyclic reference between types/traits detected
+    //~| cyclic reference
+    //~| NOTE the cycle begins when processing `cycle1`...
+    //~| NOTE ...which then requires processing `cycle1::{{impl-Trait}}`...
+    //~| NOTE ...which then again requires processing `cycle1`, completing the cycle.
     send(cycle2().clone());
-    //~^ ERROR the trait bound `std::rc::Rc<std::string::String>: std::marker::Send` is not satisfied
-    //~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::string::String>`
-    //~| NOTE `std::rc::Rc<std::string::String>` cannot be sent between threads safely
-    //~| NOTE required because it appears within the type `impl std::clone::Clone`
-    //~| NOTE required by `send`
 
     Rc::new(Cell::new(5))
 }
 
 fn cycle2() -> impl Clone {
+    //~^ NOTE ...which then requires processing `cycle2::{{impl-Trait}}`...
+    //~| NOTE ...which then requires processing `cycle2`...
     send(cycle1().clone());
-    //~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
-    //~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<i32>>`
-    //~| NOTE `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
-    //~| NOTE required because it appears within the type `impl std::clone::Clone`
-    //~| NOTE required by `send`
 
     Rc::new(String::from("foo"))
 }
diff --git a/src/test/compile-fail/impl-trait/equality.rs b/src/test/compile-fail/impl-trait/equality.rs
index 59ad1132b35..36df4f0eb4d 100644
--- a/src/test/compile-fail/impl-trait/equality.rs
+++ b/src/test/compile-fail/impl-trait/equality.rs
@@ -49,17 +49,6 @@ impl Leak for i32 {
     fn leak(self) -> i32 { self }
 }
 
-trait CheckIfSend: Sized {
-    type T: Default;
-    fn check(self) -> Self::T { Default::default() }
-}
-impl<T> CheckIfSend for T {
-    default type T = ();
-}
-impl<T: Send> CheckIfSend for T {
-    type T = bool;
-}
-
 fn main() {
     let _: u32 = hide(0_u32);
     //~^ ERROR mismatched types
@@ -73,12 +62,6 @@ fn main() {
     //~| found type `<impl Foo as Leak>::T`
     //~| expected i32, found associated type
 
-    let _: bool = CheckIfSend::check(hide(0_i32));
-    //~^ ERROR mismatched types
-    //~| expected type `bool`
-    //~| found type `<impl Foo as CheckIfSend>::T`
-    //~| expected bool, found associated type
-
     let mut x = (hide(0_u32), hide(0_i32));
     x = (x.1,
     //~^ ERROR mismatched types
diff --git a/src/test/compile-fail/invalid-path-in-const.rs b/src/test/compile-fail/invalid-path-in-const.rs
index 9a9358b787f..ab839e7630d 100644
--- a/src/test/compile-fail/invalid-path-in-const.rs
+++ b/src/test/compile-fail/invalid-path-in-const.rs
@@ -10,6 +10,5 @@
 
 fn main() {
     fn f(a: [u8; u32::DOESNOTEXIST]) {}
-    //~^ ERROR constant evaluation error
-    //~| unresolved path in constant expression
+    //~^ ERROR no associated item named `DOESNOTEXIST` found for type `u32`
 }
diff --git a/src/test/compile-fail/issue-12511.rs b/src/test/compile-fail/issue-12511.rs
index 35697e68734..0c3073a7701 100644
--- a/src/test/compile-fail/issue-12511.rs
+++ b/src/test/compile-fail/issue-12511.rs
@@ -9,11 +9,14 @@
 // except according to those terms.
 
 trait t1 : t2 {
-//~^ ERROR: unsupported cyclic reference between types/traits detected
+//~^ NOTE the cycle begins when computing the supertraits of `t1`...
+//~| NOTE ...which then requires computing the supertraits of `t2`...
 }
 
 trait t2 : t1 {
-//~^ ERROR: unsupported cyclic reference between types/traits detected
+//~^ ERROR unsupported cyclic reference between types/traits detected
+//~| cyclic reference
+//~| NOTE ...which then again requires computing the supertraits of `t1`, completing the cycle
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/issue-15524.rs b/src/test/compile-fail/issue-15524.rs
index 0d5f5fd75eb..658a0c1546b 100644
--- a/src/test/compile-fail/issue-15524.rs
+++ b/src/test/compile-fail/issue-15524.rs
@@ -12,20 +12,20 @@ const N: isize = 1;
 
 enum Foo {
     A = 1,
-    //~^ NOTE first use of `1`
-    //~| NOTE first use of `1`
-    //~| NOTE first use of `1`
+    //~^ NOTE first use of `1isize`
+    //~| NOTE first use of `1isize`
+    //~| NOTE first use of `1isize`
     B = 1,
-    //~^ ERROR discriminant value `1` already exists
-    //~| NOTE enum already has `1`
+    //~^ ERROR discriminant value `1isize` already exists
+    //~| NOTE enum already has `1isize`
     C = 0,
     D,
-    //~^ ERROR discriminant value `1` already exists
-    //~| NOTE enum already has `1`
+    //~^ ERROR discriminant value `1isize` already exists
+    //~| NOTE enum already has `1isize`
 
     E = N,
-    //~^ ERROR discriminant value `1` already exists
-    //~| NOTE enum already has `1`
+    //~^ ERROR discriminant value `1isize` already exists
+    //~| NOTE enum already has `1isize`
 
 }
 
diff --git a/src/test/compile-fail/issue-18183.rs b/src/test/compile-fail/issue-18183.rs
index b3fc3aea148..feab04531b7 100644
--- a/src/test/compile-fail/issue-18183.rs
+++ b/src/test/compile-fail/issue-18183.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub struct Foo<Bar=Bar>; //~ ERROR E0128
-                         //~| NOTE defaulted type parameters cannot be forward declared
+pub struct Foo<Bar=Bar>(Bar); //~ ERROR E0128
+                              //~| NOTE defaulted type parameters cannot be forward declared
 pub struct Baz(Foo);
 fn main() {}
diff --git a/src/test/compile-fail/issue-20772.rs b/src/test/compile-fail/issue-20772.rs
index 44c92f946f0..7ae4250d420 100644
--- a/src/test/compile-fail/issue-20772.rs
+++ b/src/test/compile-fail/issue-20772.rs
@@ -10,6 +10,7 @@
 
 trait T : Iterator<Item=Self::Item>
 //~^ ERROR unsupported cyclic reference between types/traits detected
+//~| ERROR associated type `Item` not found for `Self`
 {}
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-21177.rs b/src/test/compile-fail/issue-21177.rs
index 5ad9a12362d..f49b7195383 100644
--- a/src/test/compile-fail/issue-21177.rs
+++ b/src/test/compile-fail/issue-21177.rs
@@ -14,6 +14,7 @@ trait Trait {
 }
 
 fn foo<T: Trait<A = T::B>>() { }
-//~^ ERROR: unsupported cyclic reference between types/traits detected
+//~^ ERROR unsupported cyclic reference between types/traits detected
+//~| ERROR associated type `B` not found for `T`
 
 fn main() { }
diff --git a/src/test/compile-fail/issue-22933-2.rs b/src/test/compile-fail/issue-22933-2.rs
index 54a24089354..c78e1f7f530 100644
--- a/src/test/compile-fail/issue-22933-2.rs
+++ b/src/test/compile-fail/issue-22933-2.rs
@@ -12,12 +12,10 @@ enum Delicious {
     Pie      = 0x1,
     Apple    = 0x2,
     ApplePie = Delicious::Apple as isize | Delicious::PIE as isize,
-    //~^ ERROR constant evaluation error
-    //~| unresolved path in constant expression
+    //~^ ERROR no associated item named `PIE` found for type `Delicious`
 }
 
 const FOO: [u32; u8::MIN as usize] = [];
-//~^ ERROR constant evaluation error
-//~| unresolved path in constant expression
+//~^ ERROR no associated item named `MIN` found for type `u8`
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-23217.rs b/src/test/compile-fail/issue-23217.rs
index c2bcbb9d54a..95f6526f115 100644
--- a/src/test/compile-fail/issue-23217.rs
+++ b/src/test/compile-fail/issue-23217.rs
@@ -10,8 +10,7 @@
 
 pub enum SomeEnum {
     B = SomeEnum::A,
-    //~^ ERROR constant evaluation error
-    //~| unresolved path in constant expression
+    //~^ ERROR no associated item named `A` found for type `SomeEnum`
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-28586.rs b/src/test/compile-fail/issue-28586.rs
index 1dfd146985f..b8571d2e85e 100644
--- a/src/test/compile-fail/issue-28586.rs
+++ b/src/test/compile-fail/issue-28586.rs
@@ -11,6 +11,7 @@
 // Regression test for issue #28586
 
 pub trait Foo {}
-impl Foo for [u8; usize::BYTES] {} //~ ERROR E0080
+impl Foo for [u8; usize::BYTES] {}
+//~^ ERROR no associated item named `BYTES` found for type `usize`
 
 fn main() { }
diff --git a/src/test/compile-fail/issue-3008-2.rs b/src/test/compile-fail/issue-3008-2.rs
index 38b5fcbb3db..3bc8413cbca 100644
--- a/src/test/compile-fail/issue-3008-2.rs
+++ b/src/test/compile-fail/issue-3008-2.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(static_recursion)]
-
 enum foo { foo_(bar) }
 struct bar { x: bar }
 //~^ ERROR E0072
diff --git a/src/test/compile-fail/issue-31910.rs b/src/test/compile-fail/issue-31910.rs
index 65fcd7df77e..aac8b89e882 100644
--- a/src/test/compile-fail/issue-31910.rs
+++ b/src/test/compile-fail/issue-31910.rs
@@ -11,7 +11,9 @@
 #![feature(associated_consts)]
 
 enum Enum<T: Trait> {
-    X = Trait::Number, //~ ERROR constant evaluation error
+    X = Trait::Number,
+    //~^ ERROR mismatched types
+    //~| expected isize, found i32
 }
 
 trait Trait {
diff --git a/src/test/compile-fail/issue-3521.rs b/src/test/compile-fail/issue-3521.rs
index e2acdcee3de..78af11a0b58 100644
--- a/src/test/compile-fail/issue-3521.rs
+++ b/src/test/compile-fail/issue-3521.rs
@@ -15,9 +15,7 @@ fn main() {
     enum Stuff {
         Bar = foo
         //~^ ERROR attempt to use a non-constant value in a constant
-        //~^^ ERROR constant evaluation error
-        //~| unresolved path in constant expression
     }
 
-    println!("{}", Stuff::Bar);
+    println!("{:?}", Stuff::Bar);
 }
diff --git a/src/test/compile-fail/issue-35869.rs b/src/test/compile-fail/issue-35869.rs
index 8b7fc80bdb6..d1d6390cce3 100644
--- a/src/test/compile-fail/issue-35869.rs
+++ b/src/test/compile-fail/issue-35869.rs
@@ -23,15 +23,19 @@ impl Foo for Bar {
     fn foo(_: fn(u16) -> ()) {}
     //~^ ERROR method `foo` has an incompatible type for trait
     //~| NOTE expected u8
+    //~| NOTE expected type `fn(fn(u8))`
     fn bar(_: Option<u16>) {}
     //~^ ERROR method `bar` has an incompatible type for trait
     //~| NOTE expected u8
+    //~| NOTE expected type `fn(std::option::Option<u8>)`
     fn baz(_: (u16, u16)) {}
     //~^ ERROR method `baz` has an incompatible type for trait
     //~| NOTE expected u8
+    //~| NOTE expected type `fn((u8, u16))`
     fn qux() -> u16 { 5u16 }
     //~^ ERROR method `qux` has an incompatible type for trait
     //~| NOTE expected u8
+    //~| NOTE expected type `fn() -> u8`
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-37131.rs b/src/test/compile-fail/issue-37131.rs
index 88c6eb7f515..efb0b249a8a 100644
--- a/src/test/compile-fail/issue-37131.rs
+++ b/src/test/compile-fail/issue-37131.rs
@@ -11,8 +11,8 @@
 // Tests that compiling for a target which is not installed will result in a helpful
 // error message.
 
-// compile-flags: --target=s390x-unknown-linux-gnu
-// ignore s390x
+// compile-flags: --target=thumbv6m-none-eabi
+// ignore-arm
 
 // error-pattern:target may not be installed
 fn main() { }
diff --git a/src/test/compile-fail/issue-37576.rs b/src/test/compile-fail/issue-37576.rs
new file mode 100644
index 00000000000..e3c1ada878d
--- /dev/null
+++ b/src/test/compile-fail/issue-37576.rs
@@ -0,0 +1,55 @@
+// 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.
+
+fn main() {
+    'test_1: while break 'test_1 {}
+    while break {}
+    //~^ ERROR `break` or `continue` with no label
+
+    'test_2: while let true = break 'test_2 {}
+    while let true = break {}
+    //~^ ERROR `break` or `continue` with no label
+
+    loop { 'test_3: while break 'test_3 {} }
+    loop { while break {} }
+    //~^ ERROR `break` or `continue` with no label
+
+    loop {
+        'test_4: while break 'test_4 {}
+        break;
+    }
+    loop {
+        while break {}
+        //~^ ERROR `break` or `continue` with no label
+        break;
+    }
+
+    'test_5: while continue 'test_5 {}
+    while continue {}
+    //~^ ERROR `break` or `continue` with no label
+
+    'test_6: while let true = continue 'test_6 {}
+    while let true = continue {}
+    //~^ ERROR `break` or `continue` with no label
+
+    loop { 'test_7: while continue 'test_7 {} }
+    loop { while continue {} }
+    //~^ ERROR `break` or `continue` with no label
+
+    loop {
+        'test_8: while continue 'test_8 {}
+        continue;
+    }
+    loop {
+        while continue {}
+        //~^ ERROR `break` or `continue` with no label
+        continue;
+    }
+}
diff --git a/src/test/compile-fail/issue-39559.rs b/src/test/compile-fail/issue-39559.rs
index a56a5e85489..06e8406cbc0 100644
--- a/src/test/compile-fail/issue-39559.rs
+++ b/src/test/compile-fail/issue-39559.rs
@@ -23,9 +23,15 @@ impl Dim for Dim3 {
 pub struct Vector<T, D: Dim> {
     entries: [T; D::dim()]
     //~^ ERROR cannot use an outer type parameter in this context
-    //~| ERROR constant evaluation error
 }
 
 fn main() {
-    let array: [usize; Dim3::dim()] = [0; Dim3::dim()];
+    let array: [usize; Dim3::dim()]
+    //~^ ERROR calls in constants are limited to constant functions
+    //~| ERROR constant evaluation error
+    //~| non-constant path in constant expression
+        = [0; Dim3::dim()];
+        //~^ ERROR calls in constants are limited to constant functions
+        //~| ERROR constant evaluation error
+        //~| non-constant path in constant expression
 }
diff --git a/src/test/compile-fail/issue-8761.rs b/src/test/compile-fail/issue-8761.rs
index 91a07dd9ba6..f8424ea64ef 100644
--- a/src/test/compile-fail/issue-8761.rs
+++ b/src/test/compile-fail/issue-8761.rs
@@ -10,10 +10,10 @@
 
 enum Foo {
     A = 1i64,
-    //~^ ERROR constant evaluation error
+    //~^ ERROR mismatched types
     //~| expected isize, found i64
     B = 2u8
-    //~^ ERROR constant evaluation error
+    //~^ ERROR mismatched types
     //~| expected isize, found u8
 }
 
diff --git a/src/test/compile-fail/match-privately-empty.rs b/src/test/compile-fail/match-privately-empty.rs
new file mode 100644
index 00000000000..3affb1c03e9
--- /dev/null
+++ b/src/test/compile-fail/match-privately-empty.rs
@@ -0,0 +1,30 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(never_type)]
+
+mod private {
+    pub struct Private {
+        _bot: !,
+        pub misc: bool,
+    }
+    pub const DATA: Option<Private> = None;
+}
+
+fn main() {
+    match private::DATA {
+    //~^ ERROR non-exhaustive patterns: `Some(Private { misc: true, .. })` not covered
+        None => {}
+        Some(private::Private {
+            misc: false,
+            ..
+        }) => {}
+    }
+}
diff --git a/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs b/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs
index 691d8d31b41..52cd4e8a3ed 100644
--- a/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs
+++ b/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs
@@ -14,6 +14,5 @@ fn main() {
     fn bar(n: isize) {
         let _x: [isize; n];
         //~^ ERROR attempt to use a non-constant value in a constant [E0435]
-        //~| ERROR constant evaluation error [E0080]
     }
 }
diff --git a/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs b/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs
index f4769a78587..1eda5087784 100644
--- a/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs
+++ b/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs
@@ -15,7 +15,5 @@ fn main() {
         let _x = [0; n];
         //~^ ERROR attempt to use a non-constant value in a constant [E0435]
         //~| NOTE non-constant used with constant
-        //~| NOTE unresolved path in constant expression
-        //~| ERROR constant evaluation error [E0080]
     }
 }
diff --git a/src/test/compile-fail/resolve-label.rs b/src/test/compile-fail/resolve-label.rs
index ed2c3e0e9b8..6695e972f33 100644
--- a/src/test/compile-fail/resolve-label.rs
+++ b/src/test/compile-fail/resolve-label.rs
@@ -17,8 +17,7 @@ fn f() {
         }
     }
 
-    // issue #37353
-    loop { 'w: while break 'w { } } //~ ERROR use of undeclared label
+    loop { 'w: while break 'w { } }
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/resolve-self-in-impl.rs b/src/test/compile-fail/resolve-self-in-impl.rs
index 04f98c7ab32..710d8e11ff0 100644
--- a/src/test/compile-fail/resolve-self-in-impl.rs
+++ b/src/test/compile-fail/resolve-self-in-impl.rs
@@ -8,22 +8,24 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(associated_type_defaults)]
+
 struct S<T = u8>(T);
-trait Tr<T = u8> {}
+trait Tr<T = u8> {
+    type A = ();
+}
 
 impl Tr<Self> for S {} // OK
+impl<T: Tr<Self>> Tr<T> for S {} // OK
+impl<T = Self> Tr<T> for S {} // OK
+impl Tr for S where Self: Copy {} // OK
+impl Tr for S where S<Self>: Copy {} // OK
+impl Tr for S where Self::A: Copy {} // OK
 
-// FIXME: `Self` cannot be used in bounds because it depends on bounds itself.
-impl<T: Tr<Self>> Tr<T> for S {} //~ ERROR `Self` type is used before it's determined
-impl<T = Self> Tr<T> for S {} //~ ERROR `Self` type is used before it's determined
-impl Tr for S where Self: Copy {} //~ ERROR `Self` type is used before it's determined
-impl Tr for S where S<Self>: Copy {} //~ ERROR `Self` type is used before it's determined
-impl Tr for S where Self::Assoc: Copy {} //~ ERROR `Self` type is used before it's determined
-                                         //~^ ERROR `Self` type is used before it's determined
-impl Tr for Self {} //~ ERROR `Self` type is used before it's determined
-impl Tr for S<Self> {} //~ ERROR `Self` type is used before it's determined
-impl Self {} //~ ERROR `Self` type is used before it's determined
-impl S<Self> {} //~ ERROR `Self` type is used before it's determined
-impl Tr<Self::Assoc> for S {} //~ ERROR `Self` type is used before it's determined
+impl Tr for Self {} //~ ERROR unsupported cyclic reference between types/traits detected
+impl Tr for S<Self> {} //~ ERROR unsupported cyclic reference between types/traits detected
+impl Self {} //~ ERROR unsupported cyclic reference between types/traits detected
+impl S<Self> {} //~ ERROR unsupported cyclic reference between types/traits detected
+impl Tr<Self::A> for S {} //~ ERROR unsupported cyclic reference between types/traits detected
 
 fn main() {}
diff --git a/src/test/compile-fail/uninhabited-matches-feature-gated.rs b/src/test/compile-fail/uninhabited-matches-feature-gated.rs
index 0f8b0a6c238..0c3ea53a903 100644
--- a/src/test/compile-fail/uninhabited-matches-feature-gated.rs
+++ b/src/test/compile-fail/uninhabited-matches-feature-gated.rs
@@ -19,16 +19,13 @@ fn main() {
     };
 
     let x: &Void = unsafe { std::mem::uninitialized() };
-    let _ = match x {};
-    //~^ ERROR non-exhaustive
+    let _ = match x {}; //~ ERROR non-exhaustive
 
     let x: (Void,) = unsafe { std::mem::uninitialized() };
-    let _ = match x {};
-    //~^ ERROR non-exhaustive
+    let _ = match x {}; //~ ERROR non-exhaustive
 
     let x: [Void; 1] = unsafe { std::mem::uninitialized() };
-    let _ = match x {};
-    //~^ ERROR non-exhaustive
+    let _ = match x {}; //~ ERROR non-exhaustive
 
     let x: &[Void] = unsafe { std::mem::uninitialized() };
     let _ = match x {   //~ ERROR non-exhaustive
@@ -47,4 +44,3 @@ fn main() {
     let Ok(x) = x;
     //~^ ERROR refutable
 }
-
diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs
index da3a953d11e..048ccb529a2 100644
--- a/src/test/incremental/hashes/enum_defs.rs
+++ b/src/test/incremental/hashes/enum_defs.rs
@@ -112,10 +112,13 @@ enum EnumChangeValueCStyleVariant0 {
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_dirty(label="HirBody", cfg="cfail2")]
 #[rustc_clean(label="HirBody", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeValueCStyleVariant0 {
     Variant1,
+
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     Variant2 = 22,
 }
 
diff --git a/src/test/incremental/issue-39828/auxiliary/generic.rs b/src/test/incremental/issue-39828/auxiliary/generic.rs
new file mode 100644
index 00000000000..a562eab1768
--- /dev/null
+++ b/src/test/incremental/issue-39828/auxiliary/generic.rs
@@ -0,0 +1,18 @@
+// 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.
+
+// revisions:rpass1 rpass2
+// compile-flags: -Z query-dep-graph
+
+#![rustc_partition_reused(module="__rustc_fallback_codegen_unit", cfg="rpass2")]
+#![feature(rustc_attrs)]
+
+#![crate_type="rlib"]
+pub fn foo<T>() { }
diff --git a/src/libstd/sys/windows/printing/gnu.rs b/src/test/incremental/issue-39828/issue-39828.rs
index be2d5273c07..c729380bd5a 100644
--- a/src/libstd/sys/windows/printing/gnu.rs
+++ b/src/test/incremental/issue-39828/issue-39828.rs
@@ -8,19 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use io::prelude::*;
-use io;
-use libc::c_void;
-use sys::c;
-use sys::dynamic_lib::DynamicLibrary;
-use sys_common::gnu::libbacktrace;
+// Regression test for #39828. If you make use of a module that
+// consists only of generics, no code is generated, just a dummy
+// module. The reduced graph consists of a single node (for that
+// module) with no inputs. Since we only serialize edges, when we
+// reload, we would consider that node dirty since it is not recreated
+// (it is not the target of any edges).
 
-pub fn print(w: &mut Write,
-             i: isize,
-             addr: u64,
-             _process: c::HANDLE,
-             _dbghelp: &DynamicLibrary)
-              -> io::Result<()> {
-    let addr = addr as usize as *mut c_void;
-    libbacktrace::print(w, i, addr, addr)
-}
+// revisions:rpass1 rpass2
+// aux-build:generic.rs
+
+extern crate generic;
+fn main() { }
diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs
index 0e8971269b0..6e80a917467 100644
--- a/src/test/mir-opt/simplify_if.rs
+++ b/src/test/mir-opt/simplify_if.rs
@@ -17,7 +17,7 @@ fn main() {
 // END RUST SOURCE
 // START rustc.node4.SimplifyBranches.initial-before.mir
 // bb0: {
-//     switchInt(const false) -> [0: bb2, otherwise: bb1];
+//     switchInt(const false) -> [0u8: bb2, otherwise: bb1];
 // }
 // END rustc.node4.SimplifyBranches.initial-before.mir
 // START rustc.node4.SimplifyBranches.initial-after.mir
diff --git a/src/test/parse-fail/range_inclusive_gate.rs b/src/test/parse-fail/range_inclusive_gate.rs
index 021b6dd3e26..30dc6fc5b20 100644
--- a/src/test/parse-fail/range_inclusive_gate.rs
+++ b/src/test/parse-fail/range_inclusive_gate.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// gate-test-inclusive_range_syntax
+
 // Make sure that #![feature(inclusive_range_syntax)] is required.
 
 // #![feature(inclusive_range_syntax, inclusive_range)]
diff --git a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot
index a3b531b1e2f..07b9c744a71 100644
--- a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot
@@ -5,10 +5,10 @@ digraph block {
     N3[label="local mut x"];
     N4[label="stmt let mut x = 10;"];
     N5[label="(dummy_node)"];
-    N6[label="expr x"];
-    N7[label="expr 0"];
-    N8[label="expr x > 0"];
-    N9[label="expr while x > 0 { x -= 1; }"];
+    N6[label="expr while x > 0 { x -= 1; }"];
+    N7[label="expr x"];
+    N8[label="expr 0"];
+    N9[label="expr x > 0"];
     N10[label="expr 1"];
     N11[label="expr x"];
     N12[label="expr x -= 1"];
@@ -20,17 +20,17 @@ digraph block {
     N2 -> N3;
     N3 -> N4;
     N4 -> N5;
-    N5 -> N6;
-    N6 -> N7;
+    N5 -> N7;
     N7 -> N8;
     N8 -> N9;
-    N8 -> N10;
+    N9 -> N6;
+    N9 -> N10;
     N10 -> N11;
     N11 -> N12;
     N12 -> N13;
     N13 -> N14;
     N14 -> N5;
-    N9 -> N15;
+    N6 -> N15;
     N15 -> N16;
     N16 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot
index f152977438c..c8bfcd6510b 100644
--- a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot
@@ -11,28 +11,28 @@ digraph block {
     N9[label="local mut z"];
     N10[label="stmt let mut z = 23;"];
     N11[label="(dummy_node)"];
-    N12[label="expr x"];
-    N13[label="expr 0"];
-    N14[label="expr x > 0"];
-    N15[label="expr while x > 0 {\l    x -= 1;\l    while y > 0 {\l        y -= 1;\l        while z > 0 { z -= 1; }\l        if x > 10 { return; \"unreachable\"; }\l    }\l}\l"];
+    N12[label="expr while x > 0 {\l    x -= 1;\l    while y > 0 {\l        y -= 1;\l        while z > 0 { z -= 1; }\l        if x > 10 { return; \"unreachable\"; }\l    }\l}\l"];
+    N13[label="expr x"];
+    N14[label="expr 0"];
+    N15[label="expr x > 0"];
     N16[label="expr 1"];
     N17[label="expr x"];
     N18[label="expr x -= 1"];
     N19[label="stmt x -= 1;"];
     N20[label="(dummy_node)"];
-    N21[label="expr y"];
-    N22[label="expr 0"];
-    N23[label="expr y > 0"];
-    N24[label="expr while y > 0 {\l    y -= 1;\l    while z > 0 { z -= 1; }\l    if x > 10 { return; \"unreachable\"; }\l}\l"];
+    N21[label="expr while y > 0 {\l    y -= 1;\l    while z > 0 { z -= 1; }\l    if x > 10 { return; \"unreachable\"; }\l}\l"];
+    N22[label="expr y"];
+    N23[label="expr 0"];
+    N24[label="expr y > 0"];
     N25[label="expr 1"];
     N26[label="expr y"];
     N27[label="expr y -= 1"];
     N28[label="stmt y -= 1;"];
     N29[label="(dummy_node)"];
-    N30[label="expr z"];
-    N31[label="expr 0"];
-    N32[label="expr z > 0"];
-    N33[label="expr while z > 0 { z -= 1; }"];
+    N30[label="expr while z > 0 { z -= 1; }"];
+    N31[label="expr z"];
+    N32[label="expr 0"];
+    N33[label="expr z > 0"];
     N34[label="expr 1"];
     N35[label="expr z"];
     N36[label="expr z -= 1"];
@@ -63,35 +63,35 @@ digraph block {
     N8 -> N9;
     N9 -> N10;
     N10 -> N11;
-    N11 -> N12;
-    N12 -> N13;
+    N11 -> N13;
     N13 -> N14;
     N14 -> N15;
-    N14 -> N16;
+    N15 -> N12;
+    N15 -> N16;
     N16 -> N17;
     N17 -> N18;
     N18 -> N19;
     N19 -> N20;
-    N20 -> N21;
-    N21 -> N22;
+    N20 -> N22;
     N22 -> N23;
     N23 -> N24;
-    N23 -> N25;
+    N24 -> N21;
+    N24 -> N25;
     N25 -> N26;
     N26 -> N27;
     N27 -> N28;
     N28 -> N29;
-    N29 -> N30;
-    N30 -> N31;
+    N29 -> N31;
     N31 -> N32;
     N32 -> N33;
-    N32 -> N34;
+    N33 -> N30;
+    N33 -> N34;
     N34 -> N35;
     N35 -> N36;
     N36 -> N37;
     N37 -> N38;
     N38 -> N29;
-    N33 -> N39;
+    N30 -> N39;
     N39 -> N40;
     N40 -> N41;
     N41 -> N42;
@@ -105,9 +105,9 @@ digraph block {
     N48 -> N49;
     N49 -> N50;
     N50 -> N20;
-    N24 -> N51;
+    N21 -> N51;
     N51 -> N11;
-    N15 -> N52;
+    N12 -> N52;
     N52 -> N53;
     N53 -> N1;
 }
diff --git a/src/test/run-make/sysroot-crates-are-unstable/Makefile b/src/test/run-make/sysroot-crates-are-unstable/Makefile
new file mode 100644
index 00000000000..2bdc76e01db
--- /dev/null
+++ b/src/test/run-make/sysroot-crates-are-unstable/Makefile
@@ -0,0 +1,34 @@
+-include ../tools.mk
+
+# This is a whitelist of crates which are stable, we don't check for the
+# instability of these crates as they're all stable!
+STABLE_CRATES := \
+	std \
+	core \
+	proc_macro \
+	rsbegin.o \
+	rsend.o \
+	dllcrt2.o \
+	crt2.o
+
+# Generate a list of all crates in the sysroot. To do this we list all files in
+# rustc's sysroot, look at the filename, strip everything after the `-`, and
+# strip the leading `lib` (if present)
+SYSROOT := $(shell $(RUSTC) --print sysroot)
+LIBS := $(wildcard $(SYSROOT)/lib/rustlib/$(TARGET)/lib/*)
+LIBS := $(foreach lib,$(LIBS),$(notdir $(lib)))
+LIBS := $(foreach lib,$(LIBS),$(word 1,$(subst -, ,$(lib))))
+LIBS := $(foreach lib,$(LIBS),$(patsubst lib%,%,$(lib)))
+LIBS := $(filter-out $(STABLE_CRATES),$(LIBS))
+
+all: $(foreach lib,$(LIBS),check-crate-$(lib)-is-unstable)
+
+check-crate-%-is-unstable:
+	@echo verifying $* is an unstable crate
+	@echo 'extern crate $*;' | \
+		$(RUSTC) - --crate-type rlib 2>&1 | cat > $(TMPDIR)/$*; \
+		true
+	@grep -q 'use of unstable library feature' $(TMPDIR)/$* || \
+		(echo crate $* is not unstable && \
+		cat $(TMPDIR)/$* && \
+		false)
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
new file mode 100644
index 00000000000..cf1a631937b
--- /dev/null
+++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/issue-40001-plugin.rs
@@ -0,0 +1,66 @@
+// 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.
+#![feature(box_syntax, plugin, plugin_registrar, rustc_private)]
+#![crate_type = "dylib"]
+
+#[macro_use]
+extern crate rustc;
+extern crate rustc_plugin;
+extern crate syntax;
+
+use rustc_plugin::Registry;
+use syntax::ext::base::*;
+use syntax::feature_gate::AttributeType::Whitelisted;
+use syntax::symbol::Symbol;
+
+use rustc::hir;
+use rustc::hir::intravisit;
+use rustc::hir::map as hir_map;
+use rustc::lint::{LateContext, LintPass, LintArray, LateLintPass, LintContext};
+use rustc::ty;
+use syntax::{ast, codemap};
+
+#[plugin_registrar]
+pub fn plugin_registrar(reg: &mut Registry) {
+    reg.register_late_lint_pass(box MissingWhitelistedAttrPass);
+    reg.register_attribute("whitelisted_attr".to_string(), Whitelisted);
+}
+
+declare_lint!(MISSING_WHITELISTED_ATTR, Deny,
+              "Checks for missing `whitelisted_attr` attribute");
+
+struct MissingWhitelistedAttrPass;
+
+impl LintPass for MissingWhitelistedAttrPass {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(MISSING_WHITELISTED_ATTR)
+    }
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingWhitelistedAttrPass {
+    fn check_fn(&mut self,
+                cx: &LateContext<'a, 'tcx>,
+                _: intravisit::FnKind<'tcx>,
+                _: &'tcx hir::FnDecl,
+                _: &'tcx hir::Body,
+                span: codemap::Span,
+                id: ast::NodeId) {
+
+        let item = match cx.tcx.hir.get(id) {
+            hir_map::Node::NodeItem(item) => item,
+            _ => cx.tcx.hir.expect_item(cx.tcx.hir.get_parent(id)),
+        };
+
+        if !item.attrs.iter().any(|a| a.check_name("whitelisted_attr")) {
+            cx.span_lint(MISSING_WHITELISTED_ATTR, span,
+                         "Missing 'whitelited_attr' attribute");
+        }
+    }
+}
diff --git a/src/test/compile-fail/E0079.rs b/src/test/run-pass-fulldeps/proc-macro/issue-40001.rs
index c9b7f549d5a..54e84b7f618 100644
--- a/src/test/compile-fail/E0079.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/issue-40001.rs
@@ -8,10 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-enum Foo {
-    Q = "32" //~ ERROR E0079
-    //~^ expected 'isize' type
-}
+// aux-build:issue-40001-plugin.rs
 
-fn main() {
-}
+#![feature(proc_macro, plugin)]
+#![plugin(issue_40001_plugin)]
+
+#[whitelisted_attr]
+fn main() {}
diff --git a/src/test/run-pass/associated-types-sugar-path.rs b/src/test/run-pass/associated-types-sugar-path.rs
index 1432369f714..587fb3f80d6 100644
--- a/src/test/run-pass/associated-types-sugar-path.rs
+++ b/src/test/run-pass/associated-types-sugar-path.rs
@@ -10,10 +10,13 @@
 
 // Test paths to associated types using the type-parameter-only sugar.
 
+use std::ops::Deref;
 
 pub trait Foo {
     type A;
     fn boo(&self) -> Self::A;
+
+    fn baz(_: Self::Target) where Self: Deref {}
 }
 
 impl Foo for isize {
diff --git a/src/rustc/test_shim/lib.rs b/src/test/run-pass/auxiliary/clibrary.rs
index d614d967e3b..7438ba21bfc 100644
--- a/src/rustc/test_shim/lib.rs
+++ b/src/test/run-pass/auxiliary/clibrary.rs
@@ -8,8 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// See comments in Cargo.toml for why this exists
+// no-prefer-dynamic
+#![crate_type = "staticlib"]
 
-#![feature(test)]
-
-extern crate test;
+#[no_mangle]
+pub extern "C" fn foo(x:i32) -> i32 { x }
diff --git a/src/test/compile-fail/static-recursion-gate.rs b/src/test/run-pass/auxiliary/issue_39823.rs
index 29b5689fa93..5342601ac14 100644
--- a/src/test/compile-fail/static-recursion-gate.rs
+++ b/src/test/run-pass/auxiliary/issue_39823.rs
@@ -1,4 +1,4 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -8,9 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
-//~^ ERROR recursive static
+#![crate_type="rlib"]
 
-pub fn main() {
-    unsafe { assert_eq!(S, *(S as *const *const u8)); }
-}
+#[derive(Debug, PartialEq)]
+pub struct RemoteC(pub u32);
+
+#[derive(Debug, PartialEq)]
+pub struct RemoteG<T>(pub T);
diff --git a/src/test/run-pass/backtrace-debuginfo.rs b/src/test/run-pass/backtrace-debuginfo.rs
index 626eccfc9ec..88fee9ed25b 100644
--- a/src/test/run-pass/backtrace-debuginfo.rs
+++ b/src/test/run-pass/backtrace-debuginfo.rs
@@ -141,12 +141,12 @@ fn run_test(me: &str) {
     use std::process::Command;
 
     let mut template = Command::new(me);
-    template.env("RUST_BACKTRACE", "1");
+    template.env("RUST_BACKTRACE", "full");
 
     let mut i = 0;
     loop {
         let out = Command::new(me)
-                          .env("RUST_BACKTRACE", "1")
+                          .env("RUST_BACKTRACE", "full")
                           .arg(i.to_string()).output().unwrap();
         let output = str::from_utf8(&out.stdout).unwrap();
         let error = str::from_utf8(&out.stderr).unwrap();
diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs
index 834ce984e66..b3a9e8928be 100644
--- a/src/test/run-pass/backtrace.rs
+++ b/src/test/run-pass/backtrace.rs
@@ -47,7 +47,7 @@ fn template(me: &str) -> Command {
 }
 
 fn expected(fn_name: &str) -> String {
-    format!(" - backtrace::{}", fn_name)
+    format!(" backtrace::{}", fn_name)
 }
 
 fn runtest(me: &str) {
@@ -58,6 +58,7 @@ fn runtest(me: &str) {
     let s = str::from_utf8(&out.stderr).unwrap();
     assert!(s.contains("stack backtrace") && s.contains(&expected("foo")),
             "bad output: {}", s);
+    assert!(s.contains(" 0:"), "the frame number should start at 0");
 
     // Make sure the stack trace is *not* printed
     // (Remove RUST_BACKTRACE from our own environment, in case developer
diff --git a/src/test/run-pass/closure-to-fn-coercion.rs b/src/test/run-pass/closure-to-fn-coercion.rs
new file mode 100644
index 00000000000..13d1d6aa139
--- /dev/null
+++ b/src/test/run-pass/closure-to-fn-coercion.rs
@@ -0,0 +1,41 @@
+// 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.
+
+// ignore-stage0: new feature, remove this when SNAP
+
+#![feature(closure_to_fn_coercion)]
+
+const FOO: fn(u8) -> u8 = |v: u8| { v };
+
+const BAR: [fn(&mut u32); 5] = [
+    |_: &mut u32| {},
+    |v: &mut u32| *v += 1,
+    |v: &mut u32| *v += 2,
+    |v: &mut u32| *v += 3,
+    |v: &mut u32| *v += 4,
+];
+fn func_specific() -> (fn() -> u32) {
+    || return 42
+}
+
+fn main() {
+    // Items
+    assert_eq!(func_specific()(), 42);
+    let foo: fn(u8) -> u8 = |v: u8| { v };
+    assert_eq!(foo(31), 31);
+    // Constants
+    assert_eq!(FOO(31), 31);
+    let mut a: u32 = 0;
+    assert_eq!({ BAR[0](&mut a); a }, 0);
+    assert_eq!({ BAR[1](&mut a); a }, 1);
+    assert_eq!({ BAR[2](&mut a); a }, 3);
+    assert_eq!({ BAR[3](&mut a); a }, 6);
+    assert_eq!({ BAR[4](&mut a); a }, 10);
+}
diff --git a/src/test/run-pass/impl-trait/auto-trait-leak.rs b/src/test/run-pass/impl-trait/auto-trait-leak.rs
index c1201e7fa4f..011d910c5a5 100644
--- a/src/test/run-pass/impl-trait/auto-trait-leak.rs
+++ b/src/test/run-pass/impl-trait/auto-trait-leak.rs
@@ -29,16 +29,3 @@ fn after() -> impl FnMut(i32) {
     let mut p = Box::new(0);
     move |x| *p = x
 }
-
-// Cycles should work as the deferred obligations are
-// independently resolved and only require the concrete
-// return type, which can't depend on the obligation.
-fn cycle1() -> impl Clone {
-    send(cycle2().clone());
-    5
-}
-
-fn cycle2() -> impl Clone {
-    send(cycle1().clone());
-    String::from("foo")
-}
diff --git a/src/test/run-pass/impl-trait/equality.rs b/src/test/run-pass/impl-trait/equality.rs
index 72b0e588ff4..ceed454e5ad 100644
--- a/src/test/run-pass/impl-trait/equality.rs
+++ b/src/test/run-pass/impl-trait/equality.rs
@@ -28,6 +28,17 @@ impl<T> Leak<T> for T {
     fn leak(self) -> T { self }
 }
 
+trait CheckIfSend: Sized {
+    type T: Default;
+    fn check(self) -> Self::T { Default::default() }
+}
+impl<T> CheckIfSend for T {
+    default type T = ();
+}
+impl<T: Send> CheckIfSend for T {
+    type T = bool;
+}
+
 fn lucky_seven() -> impl Fn(usize) -> u8 {
     let a = [1, 2, 3, 4, 5, 6, 7];
     move |i| a[i]
@@ -40,4 +51,6 @@ fn main() {
     assert_eq!(std::mem::size_of_val(&lucky_seven()), 7);
 
     assert_eq!(Leak::<i32>::leak(hide(5_i32)), 5_i32);
+
+    assert_eq!(CheckIfSend::check(hide(0_i32)), false);
 }
diff --git a/src/test/run-pass/issue-2063-resource.rs b/src/test/run-pass/issue-2063-resource.rs
index aa9a7afc37f..c3a0dc67e83 100644
--- a/src/test/run-pass/issue-2063-resource.rs
+++ b/src/test/run-pass/issue-2063-resource.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(static_recursion)]
-
 // test that autoderef of a type like this does not
 // cause compiler to loop.  Note that no instances
 // of such a type could ever be constructed.
diff --git a/src/test/run-pass/issue-2063.rs b/src/test/run-pass/issue-2063.rs
index 48da7ecc508..5be4f8e8e73 100644
--- a/src/test/run-pass/issue-2063.rs
+++ b/src/test/run-pass/issue-2063.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(static_recursion)]
-
 // test that autoderef of a type like this does not
 // cause compiler to loop.  Note that no instances
 // of such a type could ever be constructed.
diff --git a/src/test/compile-fail/issue-25145.rs b/src/test/run-pass/issue-25145.rs
index 93f75e9bfed..6f02f278381 100644
--- a/src/test/compile-fail/issue-25145.rs
+++ b/src/test/run-pass/issue-25145.rs
@@ -17,7 +17,7 @@ impl S {
 }
 
 static STUFF: [u8; S::N] = [0; S::N];
-//~^ ERROR constant evaluation error
-//~| unresolved path in constant expression
 
-fn main() {}
+fn main() {
+    assert_eq!(STUFF, [0; 3]);
+}
diff --git a/src/rustc/std_shim/lib.rs b/src/test/run-pass/issue-38972.rs
index 2fc5d8d6e53..d5df84e0fb0 100644
--- a/src/rustc/std_shim/lib.rs
+++ b/src/test/run-pass/issue-38972.rs
@@ -1,4 +1,4 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -8,10 +8,18 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// See comments in Cargo.toml for why this exists
+// This issue tracks a regression (a new warning) without
+// feature(never_type). When we make that the default, please
+// remove this test.
 
-// There's a bug right now where if we pass --extern std=... and we're cross
-// compiling then this doesn't work with `#[macro_use] extern crate std;`. Work
-// around this by not having `#[macro_use] extern crate std;`
-#![no_std]
-extern crate std;
+enum Foo { }
+
+fn make_foo() -> Option<Foo> { None }
+
+#[deny(warnings)]
+fn main() {
+    match make_foo() {
+        None => {},
+        Some(_) => {}
+    }
+}
diff --git a/src/libstd/sys/unix/backtrace/printing/gnu.rs b/src/test/run-pass/issue-39548.rs
index fb06fbedaf5..7da50670d1d 100644
--- a/src/libstd/sys/unix/backtrace/printing/gnu.rs
+++ b/src/test/run-pass/issue-39548.rs
@@ -1,4 +1,4 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -8,4 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub use sys_common::gnu::libbacktrace::print;
+type Array = [(); ((1 < 2) == false) as usize];
+
+fn main() {
+    let _: Array = [];
+}
diff --git a/src/test/run-pass/issue-39823.rs b/src/test/run-pass/issue-39823.rs
new file mode 100644
index 00000000000..061a55b03b2
--- /dev/null
+++ b/src/test/run-pass/issue-39823.rs
@@ -0,0 +1,34 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:issue_39823.rs
+
+extern crate issue_39823;
+use issue_39823::{RemoteC, RemoteG};
+
+#[derive(Debug, PartialEq)]
+struct LocalC(u32);
+
+#[derive(Debug, PartialEq)]
+struct LocalG<T>(T);
+
+fn main() {
+    let virtual_localc : &Fn(_) -> LocalC = &LocalC;
+    assert_eq!(virtual_localc(1), LocalC(1));
+
+    let virtual_localg : &Fn(_) -> LocalG<u32> = &LocalG;
+    assert_eq!(virtual_localg(1), LocalG(1));
+
+    let virtual_remotec : &Fn(_) -> RemoteC = &RemoteC;
+    assert_eq!(virtual_remotec(1), RemoteC(1));
+
+    let virtual_remoteg : &Fn(_) -> RemoteG<u32> = &RemoteG;
+    assert_eq!(virtual_remoteg(1), RemoteG(1));
+}
diff --git a/src/test/run-pass/iter-sum-overflow-overflow-checks.rs b/src/test/run-pass/iter-sum-overflow-overflow-checks.rs
new file mode 100644
index 00000000000..a3a7179fb71
--- /dev/null
+++ b/src/test/run-pass/iter-sum-overflow-overflow-checks.rs
@@ -0,0 +1,35 @@
+// 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.
+
+// compile-flags: -C overflow-checks
+
+use std::panic;
+
+fn main() {
+    let r = panic::catch_unwind(|| {
+        [1, i32::max_value()].iter().sum::<i32>();
+    });
+    assert!(r.is_err());
+
+    let r = panic::catch_unwind(|| {
+        [2, i32::max_value()].iter().product::<i32>();
+    });
+    assert!(r.is_err());
+
+    let r = panic::catch_unwind(|| {
+        [1, i32::max_value()].iter().cloned().sum::<i32>();
+    });
+    assert!(r.is_err());
+
+    let r = panic::catch_unwind(|| {
+        [2, i32::max_value()].iter().cloned().product::<i32>();
+    });
+    assert!(r.is_err());
+}
diff --git a/src/test/run-pass/lib-defaults.rs b/src/test/run-pass/lib-defaults.rs
new file mode 100644
index 00000000000..a38080f8cfe
--- /dev/null
+++ b/src/test/run-pass/lib-defaults.rs
@@ -0,0 +1,23 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:clibrary.rs
+// compile-flags: -lclibrary
+
+#[link(name = "clibrary", kind = "static")]
+extern "C" {
+    pub fn foo(x:i32) -> i32;
+}
+
+fn main() {
+    unsafe {
+        foo(42);
+    }
+}
diff --git a/src/test/run-pass/loop-break-value.rs b/src/test/run-pass/loop-break-value.rs
index 6a5e051c0c7..4906a8e71d7 100644
--- a/src/test/run-pass/loop-break-value.rs
+++ b/src/test/run-pass/loop-break-value.rs
@@ -124,10 +124,18 @@ pub fn main() {
     assert_eq!(nested_break_value, "hello");
 
     let break_from_while_cond = loop {
-        while break {
+        'inner_loop: while break 'inner_loop {
             panic!();
         }
         break 123;
     };
     assert_eq!(break_from_while_cond, 123);
+
+    let break_from_while_to_outer = 'outer_loop: loop {
+        while break 'outer_loop 567 {
+            panic!("from_inner");
+        }
+        panic!("from outer");
+    };
+    assert_eq!(break_from_while_to_outer, 567);
 }
diff --git a/src/test/run-pass/panic-safe.rs b/src/test/run-pass/panic-safe.rs
index 493a00ac5d0..9bda07f077f 100644
--- a/src/test/run-pass/panic-safe.rs
+++ b/src/test/run-pass/panic-safe.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 #![allow(dead_code)]
-#![feature(recover)]
 
 use std::panic::{UnwindSafe, AssertUnwindSafe};
 use std::cell::RefCell;
@@ -40,6 +39,10 @@ fn main() {
     assert::<&RwLock<i32>>();
     assert::<Rc<i32>>();
     assert::<Arc<i32>>();
+    assert::<Box<[u8]>>();
+
+    trait Trait: UnwindSafe {}
+    assert::<Box<Trait>>();
 
     fn bar<T>() {
         assert::<Mutex<T>>();
diff --git a/src/test/run-pass/static-recursive.rs b/src/test/run-pass/static-recursive.rs
index f3db102ea5a..4a6ba984eef 100644
--- a/src/test/run-pass/static-recursive.rs
+++ b/src/test/run-pass/static-recursive.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(static_recursion)]
-
 static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
 
 struct StaticDoubleLinked {
diff --git a/src/test/ui/mismatched_types/E0053.stderr b/src/test/ui/mismatched_types/E0053.stderr
index b6e3d663e36..d9871b8970c 100644
--- a/src/test/ui/mismatched_types/E0053.stderr
+++ b/src/test/ui/mismatched_types/E0053.stderr
@@ -6,6 +6,9 @@ error[E0053]: method `foo` has an incompatible type for trait
 ...
 19 |     fn foo(x: i16) { }
    |               ^^^ expected u16, found i16
+   |
+   = note: expected type `fn(u16)`
+              found type `fn(i16)`
 
 error[E0053]: method `bar` has an incompatible type for trait
   --> $DIR/E0053.rs:22:12
diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
index 991197c2afb..349432f64bb 100644
--- a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
+++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
@@ -6,6 +6,9 @@ error[E0053]: method `foo` has an incompatible type for trait
 ...
 21 |     fn foo(x: i16) { }
    |               ^^^ expected u16, found i16
+   |
+   = note: expected type `fn(u16)`
+              found type `fn(i16)`
 
 error[E0053]: method `bar` has an incompatible type for trait
   --> $DIR/trait-impl-fn-incompatibility.rs:22:28
diff --git a/src/test/ui/resolve/issue-23305.stderr b/src/test/ui/resolve/issue-23305.stderr
index 881f04300ed..fda87de9b9c 100644
--- a/src/test/ui/resolve/issue-23305.stderr
+++ b/src/test/ui/resolve/issue-23305.stderr
@@ -1,8 +1,15 @@
-error: `Self` type is used before it's determined
+error[E0391]: unsupported cyclic reference between types/traits detected
   --> $DIR/issue-23305.rs:15:12
    |
 15 | impl ToNbt<Self> {}
-   |            ^^^^
+   |            ^^^^ cyclic reference
+   |
+note: the cycle begins when processing `<impl at $DIR/issue-23305.rs:15:1: 15:20>`...
+  --> $DIR/issue-23305.rs:15:1
+   |
+15 | impl ToNbt<Self> {}
+   | ^^^^^^^^^^^^^^^^^^^
+   = note: ...which then again requires processing `<impl at $DIR/issue-23305.rs:15:1: 15:20>`, completing the cycle.
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/resolve/levenshtein.stderr b/src/test/ui/resolve/levenshtein.stderr
index d01ffcb2839..c7c42bcf239 100644
--- a/src/test/ui/resolve/levenshtein.stderr
+++ b/src/test/ui/resolve/levenshtein.stderr
@@ -46,11 +46,5 @@ error[E0425]: cannot find value `second` in module `m`
 32 |     let b: m::first = m::second; // Misspelled item in module.
    |                       ^^^^^^^^^ did you mean `m::Second`?
 
-error[E0080]: constant evaluation error
-  --> $DIR/levenshtein.rs:30:20
-   |
-30 |     let v = [0u32; MAXITEM]; // Misspelled constant name.
-   |                    ^^^^^^^ unresolved path in constant expression
-
-error: aborting due to previous error
+error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/span/E0204.stderr b/src/test/ui/span/E0204.stderr
index 81a60a9dd30..4fe6afaca8e 100644
--- a/src/test/ui/span/E0204.stderr
+++ b/src/test/ui/span/E0204.stderr
@@ -8,15 +8,6 @@ error[E0204]: the trait `Copy` may not be implemented for this type
    |      ^^^^
 
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/E0204.rs:27:6
-   |
-23 |     Bar { x: Vec<u32> },
-   |           ----------- this field does not implement `Copy`
-...
-27 | impl Copy for EFoo { }
-   |      ^^^^
-
-error[E0204]: the trait `Copy` may not be implemented for this type
   --> $DIR/E0204.rs:17:10
    |
 17 | #[derive(Copy)]
@@ -26,6 +17,15 @@ error[E0204]: the trait `Copy` may not be implemented for this type
    |     ---------------- this field does not implement `Copy`
 
 error[E0204]: the trait `Copy` may not be implemented for this type
+  --> $DIR/E0204.rs:27:6
+   |
+23 |     Bar { x: Vec<u32> },
+   |           ----------- this field does not implement `Copy`
+...
+27 | impl Copy for EFoo { }
+   |      ^^^^
+
+error[E0204]: the trait `Copy` may not be implemented for this type
   --> $DIR/E0204.rs:29:10
    |
 29 | #[derive(Copy)]
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 991cd02d215..c2c91487b0c 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -215,6 +215,10 @@ impl Builder {
         self.package("rust-docs", &mut manifest.pkg, TARGETS);
         self.package("rust-src", &mut manifest.pkg, &["*"]);
 
+        if self.channel == "nightly" {
+            self.package("rust-analysis", &mut manifest.pkg, TARGETS);
+        }
+
         let mut pkg = Package {
             version: self.cached_version("rust").to_string(),
             target: HashMap::new(),
@@ -264,6 +268,12 @@ impl Builder {
                         target: target.to_string(),
                     });
                 }
+                if self.channel == "nightly" {
+                    extensions.push(Component {
+                        pkg: "rust-analysis".to_string(),
+                        target: target.to_string(),
+                    });
+                }
             }
             extensions.push(Component {
                 pkg: "rust-src".to_string(),
@@ -273,7 +283,7 @@ impl Builder {
             pkg.target.insert(host.to_string(), Target {
                 available: true,
                 url: Some(self.url("rust", host)),
-                hash: Some(to_hex(digest.as_ref())),
+                hash: Some(digest),
                 components: Some(components),
                 extensions: Some(extensions),
             });
@@ -399,19 +409,3 @@ impl Builder {
         self.sign(&dst);
     }
 }
-
-fn to_hex(digest: &[u8]) -> String {
-    let mut ret = String::new();
-    for byte in digest {
-        ret.push(hex((byte & 0xf0) >> 4));
-        ret.push(hex(byte & 0xf));
-    }
-    return ret;
-
-    fn hex(b: u8) -> char {
-        match b {
-            0...9 => (b'0' + b) as char,
-            _ => (b'a' + b - 10) as char,
-        }
-    }
-}
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index c9bdcd408ea..1ec0838d45f 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1987,12 +1987,22 @@ actual:\n\
     fn check_rustdoc_test_option(&self, res: ProcRes) {
         let mut other_files = Vec::new();
         let mut files: HashMap<String, Vec<usize>> = HashMap::new();
-        files.insert(self.testpaths.file.to_str().unwrap().to_owned(),
+        let cwd = env::current_dir().unwrap();
+        files.insert(self.testpaths.file.strip_prefix(&cwd)
+                                        .unwrap_or(&self.testpaths.file)
+                                        .to_str()
+                                        .unwrap()
+                                        .replace('\\', "/"),
                      self.get_lines(&self.testpaths.file, Some(&mut other_files)));
         for other_file in other_files {
             let mut path = self.testpaths.file.clone();
             path.set_file_name(&format!("{}.rs", other_file));
-            files.insert(path.to_str().unwrap().to_owned(), self.get_lines(&path, None));
+            files.insert(path.strip_prefix(&cwd)
+                             .unwrap_or(&path)
+                             .to_str()
+                             .unwrap()
+                             .replace('\\', "/"),
+                         self.get_lines(&path, None));
         }
 
         let mut tested = 0;
@@ -2002,7 +2012,8 @@ actual:\n\
                                let tmp: Vec<&str> = s.split(" - ").collect();
                                if tmp.len() == 2 {
                                    let path = tmp[0].rsplit("test ").next().unwrap();
-                                   if let Some(ref mut v) = files.get_mut(path) {
+                                   if let Some(ref mut v) = files.get_mut(
+                                                                &path.replace('\\', "/")) {
                                        tested += 1;
                                        let mut iter = tmp[1].split("(line ");
                                        iter.next();
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 13f272517b1..2c81382bc9b 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -116,7 +116,8 @@ pub fn check(path: &Path, bad: &mut bool) {
     });
 
     super::walk_many(&[&path.join("test/compile-fail"),
-                       &path.join("test/compile-fail-fulldeps")],
+                       &path.join("test/compile-fail-fulldeps"),
+                       &path.join("test/parse-fail"),],
                      &mut |path| super::filter_dirs(path),
                      &mut |file| {
         let filename = file.file_name().unwrap().to_string_lossy();
@@ -169,8 +170,7 @@ pub fn check(path: &Path, bad: &mut bool) {
         "abi_ptx", "simd",
         "cfg_target_has_atomic",
         "unboxed_closures", "stmt_expr_attributes",
-        "cfg_target_thread_local", "unwind_attributes",
-        "inclusive_range_syntax"
+        "cfg_target_thread_local", "unwind_attributes"
     ];
 
     // Only check the number of lang features.