about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2016-12-27 17:02:52 -0800
committerEsteban Küber <esteban@kuber.com.ar>2016-12-27 17:02:52 -0800
commite766c465d2e4c4e3c106bfa8343cbe6f9192d445 (patch)
tree821a7cf1e0b04ac9c0cddede6eb760bbf2d0ce62
parent96c52d4fd86aed6320732a511c04bcbfff7d117f (diff)
parent314c28b729ae359b99586cc62c486c28e0d44424 (diff)
downloadrust-e766c465d2e4c4e3c106bfa8343cbe6f9192d445.tar.gz
rust-e766c465d2e4c4e3c106bfa8343cbe6f9192d445.zip
Merge branch 'master' into escape-reason-docs
-rw-r--r--.travis.yml27
-rw-r--r--CONTRIBUTING.md9
-rw-r--r--RELEASES.md219
-rw-r--r--appveyor.yml12
-rwxr-xr-xconfigure33
-rw-r--r--mk/cfg/x86_64-unknown-redox.mk1
-rw-r--r--mk/main.mk2
-rw-r--r--mk/tests.mk2
-rw-r--r--src/Cargo.lock20
-rw-r--r--src/bootstrap/README.md49
-rw-r--r--src/bootstrap/bin/rustc.rs55
-rw-r--r--src/bootstrap/bin/rustdoc.rs2
-rw-r--r--src/bootstrap/bootstrap.py24
-rw-r--r--src/bootstrap/channel.rs4
-rw-r--r--src/bootstrap/check.rs7
-rw-r--r--src/bootstrap/config.rs55
-rw-r--r--src/bootstrap/config.toml.example10
-rw-r--r--src/bootstrap/dist.rs36
-rw-r--r--src/bootstrap/flags.rs35
-rw-r--r--src/bootstrap/lib.rs27
-rw-r--r--src/bootstrap/mk/Makefile.in5
-rw-r--r--src/bootstrap/native.rs8
-rw-r--r--src/bootstrap/sanity.rs6
-rw-r--r--src/bootstrap/step.rs65
-rw-r--r--src/bootstrap/util.rs6
-rw-r--r--src/build_helper/lib.rs12
-rw-r--r--src/ci/docker/arm-android/Dockerfile14
-rw-r--r--src/ci/docker/cross/Dockerfile12
-rw-r--r--src/ci/docker/i686-gnu-nopt/Dockerfile12
-rw-r--r--src/ci/docker/i686-gnu/Dockerfile12
-rwxr-xr-xsrc/ci/docker/run.sh14
-rw-r--r--src/ci/docker/x86_64-freebsd/Dockerfile9
-rw-r--r--src/ci/docker/x86_64-gnu-cargotest/Dockerfile13
-rw-r--r--src/ci/docker/x86_64-gnu-debug/Dockerfile12
-rw-r--r--src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile12
-rw-r--r--src/ci/docker/x86_64-gnu-make/Dockerfile12
-rw-r--r--src/ci/docker/x86_64-gnu-nopt/Dockerfile12
-rw-r--r--src/ci/docker/x86_64-gnu/Dockerfile12
-rw-r--r--src/ci/docker/x86_64-musl/Dockerfile9
-rwxr-xr-xsrc/ci/run.sh6
-rw-r--r--src/doc/book/casting-between-types.md18
-rw-r--r--src/doc/book/documentation.md5
-rw-r--r--src/doc/book/getting-started.md52
-rw-r--r--src/doc/book/testing.md9
-rw-r--r--src/doc/reference.md3
-rw-r--r--src/doc/rust.css4
-rw-r--r--src/liballoc/arc.rs10
-rw-r--r--src/liballoc/heap.rs2
-rw-r--r--src/liballoc/rc.rs46
-rw-r--r--src/liballoc_jemalloc/build.rs5
-rw-r--r--src/liballoc_system/lib.rs8
-rw-r--r--src/libcollections/binary_heap.rs10
-rw-r--r--src/libcollections/borrow.rs36
-rw-r--r--src/libcollections/btree/set.rs69
-rw-r--r--src/libcollections/enum_set.rs3
-rw-r--r--src/libcollections/linked_list.rs70
-rw-r--r--src/libcollections/slice.rs6
-rw-r--r--src/libcollections/str.rs6
-rw-r--r--src/libcollections/string.rs10
-rw-r--r--src/libcollections/vec.rs6
-rw-r--r--src/libcollections/vec_deque.rs83
-rw-r--r--src/libcollectionstest/lib.rs1
-rw-r--r--src/libcompiler_builtins/build.rs2
-rw-r--r--src/libcore/cell.rs8
-rw-r--r--src/libcore/char.rs4
-rw-r--r--src/libcore/fmt/mod.rs10
-rw-r--r--src/libcore/hash/mod.rs40
-rw-r--r--src/libcore/iter/iterator.rs6
-rw-r--r--src/libcore/ptr.rs83
-rw-r--r--src/libcore/result.rs29
-rw-r--r--src/libcore/slice.rs22
-rw-r--r--src/libcore/sync/atomic.rs18
-rw-r--r--src/libcoretest/cell.rs37
-rw-r--r--src/libcoretest/lib.rs5
-rw-r--r--src/libcoretest/ptr.rs23
m---------src/liblibc0
-rw-r--r--src/libpanic_abort/lib.rs4
-rw-r--r--src/libpanic_unwind/lib.rs1
-rw-r--r--src/librustc/dep_graph/README.md6
-rw-r--r--src/librustc/dep_graph/shadow.rs16
-rw-r--r--src/librustc/dep_graph/visit.rs2
-rw-r--r--src/librustc/diagnostics.rs17
-rw-r--r--src/librustc/hir/def_id.rs4
-rw-r--r--src/librustc/hir/intravisit.rs1
-rw-r--r--src/librustc/hir/lowering.rs66
-rw-r--r--src/librustc/hir/map/collector.rs4
-rw-r--r--src/librustc/hir/map/def_collector.rs213
-rw-r--r--src/librustc/hir/map/definitions.rs213
-rw-r--r--src/librustc/hir/map/mod.rs45
-rw-r--r--src/librustc/hir/mod.rs13
-rw-r--r--src/librustc/hir/print.rs28
-rw-r--r--src/librustc/infer/error_reporting.rs1
-rw-r--r--src/librustc/infer/mod.rs5
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/lint/builtin.rs7
-rw-r--r--src/librustc/middle/cstore.rs37
-rw-r--r--src/librustc/middle/dead.rs24
-rw-r--r--src/librustc/middle/lang_items.rs1
-rw-r--r--src/librustc/middle/stability.rs8
-rw-r--r--src/librustc/session/code_stats.rs7
-rw-r--r--src/librustc/session/config.rs20
-rw-r--r--src/librustc/session/mod.rs5
-rw-r--r--src/librustc/traits/error_reporting.rs46
-rw-r--r--src/librustc/ty/context.rs59
-rw-r--r--src/librustc/ty/item_path.rs5
-rw-r--r--src/librustc/ty/layout.rs434
-rw-r--r--src/librustc/ty/mod.rs103
-rw-r--r--src/librustc/ty/sty.rs1
-rw-r--r--src/librustc/ty/util.rs104
-rw-r--r--src/librustc_back/target/aarch64_linux_android.rs3
-rw-r--r--src/librustc_back/target/apple_base.rs1
-rw-r--r--src/librustc_back/target/armv7_linux_androideabi.rs7
-rw-r--r--src/librustc_back/target/asmjs_unknown_emscripten.rs1
-rw-r--r--src/librustc_back/target/bitrig_base.rs1
-rw-r--r--src/librustc_back/target/dragonfly_base.rs1
-rw-r--r--src/librustc_back/target/freebsd_base.rs1
-rw-r--r--src/librustc_back/target/fuchsia_base.rs1
-rw-r--r--src/librustc_back/target/haiku_base.rs1
-rw-r--r--src/librustc_back/target/i686_linux_android.rs3
-rw-r--r--src/librustc_back/target/linux_base.rs1
-rw-r--r--src/librustc_back/target/mod.rs9
-rw-r--r--src/librustc_back/target/netbsd_base.rs1
-rw-r--r--src/librustc_back/target/openbsd_base.rs1
-rw-r--r--src/librustc_back/target/redox_base.rs50
-rw-r--r--src/librustc_back/target/solaris_base.rs1
-rw-r--r--src/librustc_back/target/wasm32_unknown_emscripten.rs1
-rw-r--r--src/librustc_back/target/windows_base.rs1
-rw-r--r--src/librustc_back/target/windows_msvc_base.rs1
-rw-r--r--src/librustc_back/target/x86_64_unknown_redox.rs30
-rw-r--r--src/librustc_borrowck/borrowck/mir/elaborate_drops.rs77
-rw-r--r--src/librustc_const_eval/_match.rs1
-rw-r--r--src/librustc_data_structures/base_n.rs2
-rw-r--r--src/librustc_data_structures/flock.rs6
-rw-r--r--src/librustc_data_structures/graph/tests.rs2
-rw-r--r--src/librustc_data_structures/lib.rs3
-rw-r--r--src/librustc_data_structures/stable_hasher.rs176
-rw-r--r--src/librustc_driver/driver.rs30
-rw-r--r--src/librustc_driver/pretty.rs5
-rw-r--r--src/librustc_driver/test.rs4
-rw-r--r--src/librustc_incremental/calculate_svh/hasher.rs88
-rw-r--r--src/librustc_incremental/calculate_svh/mod.rs9
-rw-r--r--src/librustc_incremental/calculate_svh/svh_visitor.rs50
-rw-r--r--src/librustc_incremental/ich/fingerprint.rs15
-rw-r--r--src/librustc_incremental/lib.rs2
-rw-r--r--src/librustc_incremental/persist/hash.rs5
-rw-r--r--src/librustc_incremental/persist/save.rs2
-rw-r--r--src/librustc_lint/bad_style.rs2
-rw-r--r--src/librustc_lint/lib.rs4
-rw-r--r--src/librustc_lint/types.rs3
-rw-r--r--src/librustc_llvm/build.rs14
-rw-r--r--src/librustc_llvm/ffi.rs8
-rw-r--r--src/librustc_llvm/lib.rs9
-rw-r--r--src/librustc_metadata/astencode.rs10
-rw-r--r--src/librustc_metadata/creader.rs7
-rw-r--r--src/librustc_metadata/cstore.rs4
-rw-r--r--src/librustc_metadata/cstore_impl.rs24
-rw-r--r--src/librustc_metadata/decoder.rs118
-rw-r--r--src/librustc_metadata/diagnostics.rs6
-rw-r--r--src/librustc_metadata/encoder.rs78
-rw-r--r--src/librustc_metadata/index.rs16
-rw-r--r--src/librustc_metadata/schema.rs4
-rw-r--r--src/librustc_mir/hair/cx/block.rs55
-rw-r--r--src/librustc_mir/hair/cx/expr.rs565
-rw-r--r--src/librustc_mir/hair/cx/mod.rs54
-rw-r--r--src/librustc_mir/hair/cx/to_ref.rs18
-rw-r--r--src/librustc_mir/transform/copy_prop.rs10
-rw-r--r--src/librustc_passes/ast_validation.rs8
-rw-r--r--src/librustc_plugin/registry.rs18
-rw-r--r--src/librustc_privacy/lib.rs32
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs285
-rw-r--r--src/librustc_resolve/diagnostics.rs27
-rw-r--r--src/librustc_resolve/lib.rs1734
-rw-r--r--src/librustc_resolve/macros.rs145
-rw-r--r--src/librustc_resolve/resolve_imports.rs228
-rw-r--r--src/librustc_save_analysis/data.rs35
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs82
-rw-r--r--src/librustc_save_analysis/external_data.rs49
-rw-r--r--src/librustc_save_analysis/json_api_dumper.rs55
-rw-r--r--src/librustc_save_analysis/json_dumper.rs55
-rw-r--r--src/librustc_save_analysis/lib.rs69
-rw-r--r--src/librustc_save_analysis/span_utils.rs44
-rw-r--r--src/librustc_trans/README.md1
-rw-r--r--src/librustc_trans/README.txt1
-rw-r--r--src/librustc_trans/abi.rs37
-rw-r--r--src/librustc_trans/adt.rs236
-rw-r--r--src/librustc_trans/asm.rs44
-rw-r--r--src/librustc_trans/back/linker.rs7
-rw-r--r--src/librustc_trans/back/msvc/registry.rs4
-rw-r--r--src/librustc_trans/back/symbol_names.rs8
-rw-r--r--src/librustc_trans/back/write.rs4
-rw-r--r--src/librustc_trans/base.rs782
-rw-r--r--src/librustc_trans/basic_block.rs58
-rw-r--r--src/librustc_trans/build.rs1167
-rw-r--r--src/librustc_trans/builder.rs81
-rw-r--r--src/librustc_trans/cabi_arm.rs2
-rw-r--r--src/librustc_trans/cabi_sparc.rs108
-rw-r--r--src/librustc_trans/cabi_x86.rs50
-rw-r--r--src/librustc_trans/callee.rs227
-rw-r--r--src/librustc_trans/cleanup.rs711
-rw-r--r--src/librustc_trans/collector.rs58
-rw-r--r--src/librustc_trans/common.rs541
-rw-r--r--src/librustc_trans/consts.rs3
-rw-r--r--src/librustc_trans/context.rs185
-rw-r--r--src/librustc_trans/debuginfo/create_scope_map.rs8
-rw-r--r--src/librustc_trans/debuginfo/gdb.rs27
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs82
-rw-r--r--src/librustc_trans/debuginfo/mod.rs104
-rw-r--r--src/librustc_trans/debuginfo/source_loc.rs66
-rw-r--r--src/librustc_trans/glue.rs541
-rw-r--r--src/librustc_trans/intrinsic.rs722
-rw-r--r--src/librustc_trans/lib.rs5
-rw-r--r--src/librustc_trans/meth.rs69
-rw-r--r--src/librustc_trans/mir/analyze.rs62
-rw-r--r--src/librustc_trans/mir/block.rs361
-rw-r--r--src/librustc_trans/mir/constant.rs37
-rw-r--r--src/librustc_trans/mir/lvalue.rs52
-rw-r--r--src/librustc_trans/mir/mod.rs303
-rw-r--r--src/librustc_trans/mir/operand.rs70
-rw-r--r--src/librustc_trans/mir/rvalue.rs242
-rw-r--r--src/librustc_trans/mir/statement.rs35
-rw-r--r--src/librustc_trans/trans_item.rs11
-rw-r--r--src/librustc_trans/tvec.rs58
-rw-r--r--src/librustc_trans/type_of.rs14
-rw-r--r--src/librustc_trans/value.rs156
-rw-r--r--src/librustc_typeck/astconv.rs9
-rw-r--r--src/librustc_typeck/check/_match.rs2
-rw-r--r--src/librustc_typeck/check/autoderef.rs8
-rw-r--r--src/librustc_typeck/check/cast.rs7
-rw-r--r--src/librustc_typeck/check/demand.rs71
-rw-r--r--src/librustc_typeck/check/method/mod.rs15
-rw-r--r--src/librustc_typeck/check/method/probe.rs285
-rw-r--r--src/librustc_typeck/check/mod.rs10
-rw-r--r--src/librustc_typeck/coherence/mod.rs2
-rw-r--r--src/librustc_typeck/diagnostics.rs24
-rw-r--r--src/librustc_typeck/lib.rs2
-rw-r--r--src/librustdoc/clean/mod.rs29
-rw-r--r--src/librustdoc/doctree.rs4
-rw-r--r--src/librustdoc/html/format.rs2
-rw-r--r--src/librustdoc/html/layout.rs1
-rw-r--r--src/librustdoc/html/render.rs28
-rw-r--r--src/librustdoc/html/static/main.js21
-rw-r--r--src/librustdoc/html/static/rustdoc.css16
-rw-r--r--src/librustdoc/html/static/styles/main.css8
-rw-r--r--src/librustdoc/lib.rs31
-rw-r--r--src/librustdoc/markdown.rs10
-rw-r--r--src/librustdoc/visit_ast.rs13
-rw-r--r--src/libserialize/leb128.rs54
-rw-r--r--src/libstd/ascii.rs8
-rw-r--r--src/libstd/build.rs4
-rw-r--r--src/libstd/collections/hash/map.rs83
-rw-r--r--src/libstd/collections/hash/set.rs77
-rw-r--r--src/libstd/collections/hash/table.rs29
-rw-r--r--src/libstd/env.rs36
-rw-r--r--src/libstd/fs.rs107
-rw-r--r--src/libstd/io/buffered.rs99
-rw-r--r--src/libstd/io/mod.rs25
-rw-r--r--src/libstd/io/stdio.rs52
-rw-r--r--src/libstd/io/util.rs22
-rw-r--r--src/libstd/lib.rs2
-rw-r--r--src/libstd/net/ip.rs28
-rw-r--r--src/libstd/net/mod.rs8
-rw-r--r--src/libstd/net/tcp.rs1
-rw-r--r--src/libstd/net/udp.rs59
-rw-r--r--src/libstd/os/linux/raw.rs1
-rw-r--r--src/libstd/os/mod.rs4
-rw-r--r--src/libstd/os/raw.rs9
-rw-r--r--src/libstd/panic.rs10
-rw-r--r--src/libstd/panicking.rs2
-rw-r--r--src/libstd/process.rs56
-rw-r--r--src/libstd/rand/mod.rs7
-rw-r--r--src/libstd/sync/barrier.rs17
-rw-r--r--src/libstd/sync/condvar.rs8
-rw-r--r--src/libstd/sync/mpsc/mod.rs230
-rw-r--r--src/libstd/sync/mpsc/oneshot.rs293
-rw-r--r--src/libstd/sync/mpsc/shared.rs106
-rw-r--r--src/libstd/sync/mpsc/stream.rs65
-rw-r--r--src/libstd/sync/mutex.rs9
-rw-r--r--src/libstd/sync/once.rs9
-rw-r--r--src/libstd/sync/rwlock.rs18
-rw-r--r--src/libstd/sys/mod.rs6
-rw-r--r--src/libstd/sys/redox/args.rs109
-rw-r--r--src/libstd/sys/redox/backtrace.rs18
-rw-r--r--src/libstd/sys/redox/condvar.rs106
-rw-r--r--src/libstd/sys/redox/env.rs19
-rw-r--r--src/libstd/sys/redox/ext/ffi.rs61
-rw-r--r--src/libstd/sys/redox/ext/fs.rs298
-rw-r--r--src/libstd/sys/redox/ext/io.rs151
-rw-r--r--src/libstd/sys/redox/ext/mod.rs50
-rw-r--r--src/libstd/sys/redox/ext/process.rs183
-rw-r--r--src/libstd/sys/redox/fast_thread_local.rs116
-rw-r--r--src/libstd/sys/redox/fd.rs100
-rw-r--r--src/libstd/sys/redox/fs.rs470
-rw-r--r--src/libstd/sys/redox/memchr.rs (renamed from src/test/compile-fail/issue-23305.rs)12
-rw-r--r--src/libstd/sys/redox/mod.rs95
-rw-r--r--src/libstd/sys/redox/mutex.rs179
-rw-r--r--src/libstd/sys/redox/net/dns/answer.rs22
-rw-r--r--src/libstd/sys/redox/net/dns/mod.rs217
-rw-r--r--src/libstd/sys/redox/net/dns/query.rs18
-rw-r--r--src/libstd/sys/redox/net/mod.rs113
-rw-r--r--src/libstd/sys/redox/net/netc.rs57
-rw-r--r--src/libstd/sys/redox/net/tcp.rs199
-rw-r--r--src/libstd/sys/redox/net/udp.rs188
-rw-r--r--src/libstd/sys/redox/os.rs204
-rw-r--r--src/libstd/sys/redox/os_str.rs119
-rw-r--r--src/libstd/sys/redox/path.rs39
-rw-r--r--src/libstd/sys/redox/pipe.rs107
-rw-r--r--src/libstd/sys/redox/process.rs504
-rw-r--r--src/libstd/sys/redox/rand.rs57
-rw-r--r--src/libstd/sys/redox/rwlock.rs61
-rw-r--r--src/libstd/sys/redox/stack_overflow.rs27
-rw-r--r--src/libstd/sys/redox/stdio.rs81
-rw-r--r--src/libstd/sys/redox/syscall/arch/arm.rs83
-rw-r--r--src/libstd/sys/redox/syscall/arch/x86.rs83
-rw-r--r--src/libstd/sys/redox/syscall/arch/x86_64.rs84
-rw-r--r--src/libstd/sys/redox/syscall/call.rs300
-rw-r--r--src/libstd/sys/redox/syscall/data.rs86
-rw-r--r--src/libstd/sys/redox/syscall/error.rs325
-rw-r--r--src/libstd/sys/redox/syscall/flag.rs94
-rw-r--r--src/libstd/sys/redox/syscall/mod.rs43
-rw-r--r--src/libstd/sys/redox/syscall/number.rs73
-rw-r--r--src/libstd/sys/redox/thread.rs91
-rw-r--r--src/libstd/sys/redox/thread_local.rs66
-rw-r--r--src/libstd/sys/redox/time.rs198
-rw-r--r--src/libstd/sys/unix/ext/fs.rs8
-rw-r--r--src/libstd/sys/unix/ext/mod.rs2
-rw-r--r--src/libstd/sys/unix/ext/net.rs591
-rw-r--r--src/libstd/sys/unix/ext/process.rs2
-rw-r--r--src/libstd/sys/unix/fast_thread_local.rs7
-rw-r--r--src/libstd/sys/unix/fd.rs1
-rw-r--r--src/libstd/sys/unix/fs.rs3
-rw-r--r--src/libstd/sys/unix/process/magenta.rs1
-rw-r--r--src/libstd/sys/unix/stdio.rs13
-rw-r--r--src/libstd/sys/windows/c.rs18
-rw-r--r--src/libstd/sys/windows/ext/fs.rs8
-rw-r--r--src/libstd/sys/windows/ext/mod.rs2
-rw-r--r--src/libstd/sys/windows/fs.rs3
-rw-r--r--src/libstd/sys/windows/stdio.rs37
-rw-r--r--src/libstd/sys_common/mod.rs8
-rw-r--r--src/libstd/thread/local.rs18
-rw-r--r--src/libstd/thread/mod.rs174
-rw-r--r--src/libstd/time/duration.rs79
-rw-r--r--src/libstd_unicode/char.rs14
-rw-r--r--src/libstd_unicode/lib.rs1
-rw-r--r--src/libsyntax/ast.rs142
-rw-r--r--src/libsyntax/attr.rs30
-rw-r--r--src/libsyntax/ext/base.rs10
-rw-r--r--src/libsyntax/ext/build.rs55
-rw-r--r--src/libsyntax/ext/expand.rs81
-rw-r--r--src/libsyntax/ext/hygiene.rs18
-rw-r--r--src/libsyntax/ext/placeholders.rs52
-rw-r--r--src/libsyntax/ext/tt/macro_parser.rs7
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs56
-rw-r--r--src/libsyntax/feature_gate.rs4
-rw-r--r--src/libsyntax/fold.rs34
-rw-r--r--src/libsyntax/parse/mod.rs63
-rw-r--r--src/libsyntax/parse/parser.rs90
-rw-r--r--src/libsyntax/print/pprust.rs77
-rw-r--r--src/libsyntax/std_inject.rs6
-rw-r--r--src/libsyntax/symbol.rs3
-rw-r--r--src/libsyntax/test.rs6
-rw-r--r--src/libsyntax/tokenstream.rs8
-rw-r--r--src/libsyntax/visit.rs5
-rw-r--r--src/libsyntax_ext/concat_idents.rs7
-rw-r--r--src/libsyntax_ext/deriving/generic/mod.rs11
-rw-r--r--src/libsyntax_ext/deriving/mod.rs4
-rw-r--r--src/libsyntax_ext/lib.rs5
-rw-r--r--src/libsyntax_ext/proc_macro_registrar.rs19
-rw-r--r--src/libtest/lib.rs201
m---------src/llvm0
-rw-r--r--src/rustllvm/RustWrapper.cpp54
-rw-r--r--src/rustllvm/llvm-auto-clean-trigger2
-rw-r--r--src/rustllvm/rustllvm.h1
-rw-r--r--src/stage0.txt6
-rw-r--r--src/test/codegen/fastcall-inreg.rs85
-rw-r--r--src/test/compile-fail-fulldeps/macro-crate-doesnt-resolve.rs2
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/pub-at-crate-root.rs (renamed from src/test/compile-fail-fulldeps/proc-macro/at-the-root.rs)5
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/signature.rs2
-rw-r--r--src/test/compile-fail-fulldeps/qquote.rs2
-rw-r--r--src/test/compile-fail/E0033.rs4
-rw-r--r--src/test/compile-fail/E0259.rs2
-rw-r--r--src/test/compile-fail/E0277-2.rs34
-rw-r--r--src/test/compile-fail/E0277.rs9
-rw-r--r--src/test/compile-fail/E0423.rs1
-rw-r--r--src/test/compile-fail/E0424.rs5
-rw-r--r--src/test/compile-fail/E0425.rs2
-rw-r--r--src/test/compile-fail/associated-path-shl.rs10
-rw-r--r--src/test/compile-fail/associated-types-eq-1.rs2
-rw-r--r--src/test/compile-fail/auxiliary/lint_stability.rs4
-rw-r--r--src/test/compile-fail/bad-expr-path.rs9
-rw-r--r--src/test/compile-fail/bad-expr-path2.rs7
-rw-r--r--src/test/compile-fail/blind-item-item-shadow.rs2
-rw-r--r--src/test/compile-fail/cast-rfc0401.rs123
-rw-r--r--src/test/compile-fail/class-missing-self.rs4
-rw-r--r--src/test/compile-fail/coherence-error-suppression.rs2
-rw-r--r--src/test/compile-fail/derived-errors/issue-31997.rs2
-rw-r--r--src/test/compile-fail/does-nothing.rs2
-rw-r--r--src/test/compile-fail/empty-struct-braces-expr.rs12
-rw-r--r--src/test/compile-fail/empty-struct-braces-pat-2.rs8
-rw-r--r--src/test/compile-fail/enum-variant-type-2.rs2
-rw-r--r--src/test/compile-fail/export-fully-qualified.rs4
-rw-r--r--src/test/compile-fail/export.rs7
-rw-r--r--src/test/compile-fail/export2.rs4
-rw-r--r--src/test/compile-fail/extern-with-type-bounds.rs2
-rw-r--r--src/test/compile-fail/for-expn.rs2
-rw-r--r--src/test/compile-fail/for-loop-hygiene.rs2
-rw-r--r--src/test/compile-fail/glob-resolve1.rs18
-rw-r--r--src/test/compile-fail/import-glob-0.rs4
-rw-r--r--src/test/compile-fail/imports/rfc-1560-warning-cycle.rs30
-rw-r--r--src/test/compile-fail/issue-14254.rs137
-rw-r--r--src/test/compile-fail/issue-1476.rs2
-rw-r--r--src/test/compile-fail/issue-15167.rs8
-rw-r--r--src/test/compile-fail/issue-17546.rs8
-rw-r--r--src/test/compile-fail/issue-18058.rs2
-rw-r--r--src/test/compile-fail/issue-18119.rs6
-rw-r--r--src/test/compile-fail/issue-19498.rs6
-rw-r--r--src/test/compile-fail/issue-19883.rs2
-rw-r--r--src/test/compile-fail/issue-22037.rs2
-rw-r--r--src/test/compile-fail/issue-22384.rs2
-rw-r--r--src/test/compile-fail/issue-2281-part1.rs4
-rw-r--r--src/test/compile-fail/issue-2330.rs2
-rw-r--r--src/test/compile-fail/issue-2356.rs109
-rw-r--r--src/test/compile-fail/issue-24081.rs10
-rw-r--r--src/test/compile-fail/issue-28388-1.rs4
-rw-r--r--src/test/compile-fail/issue-28388-3.rs5
-rw-r--r--src/test/compile-fail/issue-30535.rs2
-rw-r--r--src/test/compile-fail/issue-30589.rs2
-rw-r--r--src/test/compile-fail/issue-31845.rs2
-rw-r--r--src/test/compile-fail/issue-32119.rs1
-rw-r--r--src/test/compile-fail/issue-34334.rs2
-rw-r--r--src/test/compile-fail/issue-35075.rs4
-rw-r--r--src/test/compile-fail/issue-37534.rs4
-rw-r--r--src/test/compile-fail/issue-38458.rs15
-rw-r--r--src/test/compile-fail/issue-4366-2.rs4
-rw-r--r--src/test/compile-fail/issue-4366.rs2
-rw-r--r--src/test/compile-fail/issue-5099.rs2
-rw-r--r--src/test/compile-fail/issue-5927.rs2
-rw-r--r--src/test/compile-fail/issue-7607-1.rs2
-rw-r--r--src/test/compile-fail/issue-8767.rs2
-rw-r--r--src/test/compile-fail/keyword-super-as-identifier.rs2
-rw-r--r--src/test/compile-fail/keyword-super.rs2
-rw-r--r--src/test/compile-fail/lint-dead-code-type-alias.rs20
-rw-r--r--src/test/compile-fail/macro-outer-attributes.rs2
-rw-r--r--src/test/compile-fail/macro-parameter-span.rs2
-rw-r--r--src/test/compile-fail/macro-tt-matchers.rs1
-rw-r--r--src/test/compile-fail/match-join.rs2
-rw-r--r--src/test/compile-fail/match-vec-mismatch.rs2
-rw-r--r--src/test/compile-fail/mod_file_correct_spans.rs2
-rw-r--r--src/test/compile-fail/name-clash-nullary.rs4
-rw-r--r--src/test/compile-fail/namespace-mix.rs8
-rw-r--r--src/test/compile-fail/namespaced-enum-glob-import-no-impls-xcrate.rs8
-rw-r--r--src/test/compile-fail/namespaced-enum-glob-import-no-impls.rs8
-rw-r--r--src/test/compile-fail/nested-cfg-attrs.rs2
-rw-r--r--src/test/compile-fail/no-implicit-prelude-nested.rs36
-rw-r--r--src/test/compile-fail/no-implicit-prelude.rs12
-rw-r--r--src/test/compile-fail/no-link.rs2
-rw-r--r--src/test/compile-fail/parser-recovery-1.rs4
-rw-r--r--src/test/compile-fail/parser-recovery-2.rs4
-rw-r--r--src/test/compile-fail/pattern-macro-hygiene.rs2
-rw-r--r--src/test/compile-fail/privacy-ns1.rs8
-rw-r--r--src/test/compile-fail/privacy-ns2.rs8
-rw-r--r--src/test/compile-fail/privacy/restricted/test.rs2
-rw-r--r--src/test/compile-fail/privacy/restricted/ty-params.rs4
-rw-r--r--src/test/compile-fail/recursive-reexports.rs4
-rw-r--r--src/test/compile-fail/resolve-bad-import-prefix.rs24
-rw-r--r--src/test/compile-fail/resolve-bad-visibility.rs27
-rw-r--r--src/test/compile-fail/resolve-conflict-item-vs-import.rs2
-rw-r--r--src/test/compile-fail/resolve-primitive-fallback.rs20
-rw-r--r--src/test/compile-fail/resolve-unknown-trait.rs6
-rw-r--r--src/test/compile-fail/rmeta.rs2
-rw-r--r--src/test/compile-fail/struct-fields-shorthand-unresolved.rs2
-rw-r--r--src/test/compile-fail/syntax-extension-minor.rs2
-rw-r--r--src/test/compile-fail/test-cfg.rs2
-rw-r--r--src/test/compile-fail/ufcs-partially-resolved.rs66
-rw-r--r--src/test/compile-fail/variant-used-as-type.rs4
-rw-r--r--src/test/compile-fail/xcrate-unit-struct.rs2
-rw-r--r--src/test/debuginfo/borrowed-enum.rs4
-rw-r--r--src/test/debuginfo/by-value-non-immediate-argument.rs2
-rw-r--r--src/test/debuginfo/generic-struct-style-enum.rs6
-rw-r--r--src/test/debuginfo/generic-tuple-style-enum.rs6
-rw-r--r--src/test/debuginfo/struct-in-enum.rs4
-rw-r--r--src/test/debuginfo/struct-style-enum.rs6
-rw-r--r--src/test/debuginfo/tuple-style-enum.rs6
-rw-r--r--src/test/debuginfo/union-smoke.rs1
-rw-r--r--src/test/debuginfo/unique-enum.rs4
-rw-r--r--src/test/incremental/hashes/closure_expressions.rs144
-rw-r--r--src/test/incremental/hashes/enum_constructors.rs387
-rw-r--r--src/test/incremental/hashes/exported_vs_not.rs86
-rw-r--r--src/test/incremental/hashes/indexing_expressions.rs157
-rw-r--r--src/test/incremental/hashes/inherent_impls.rs410
-rw-r--r--src/test/incremental/hashes/inline_asm.rs265
-rw-r--r--src/test/incremental/hashes/struct_constructors.rs12
-rw-r--r--src/test/mir-opt/copy_propagation.rs34
-rw-r--r--src/test/parse-fail/where_with_bound.rs16
-rw-r--r--src/test/pretty/issue-4264.pp2
-rw-r--r--src/test/run-make/issue-38237/Makefile5
-rw-r--r--src/test/run-make/issue-38237/bar.rs14
-rw-r--r--src/test/run-make/issue-38237/baz.rs18
-rw-r--r--src/test/run-make/issue-38237/foo.rs20
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs2
-rw-r--r--src/test/run-pass/auxiliary/issue_38190.rs12
-rw-r--r--src/test/run-pass/backtrace.rs1
-rw-r--r--src/test/run-pass/closure-immediate.rs22
-rw-r--r--src/test/run-pass/enum-size-variance.rs3
-rw-r--r--src/test/run-pass/extern-pass-empty.rs3
-rw-r--r--src/test/run-pass/issue-38190.rs (renamed from src/test/compile-fail/unresolved_static_type_field.rs)15
-rw-r--r--src/test/run-pass/issue-38437.rs54
-rw-r--r--src/test/run-pass/issue-38556.rs (renamed from src/test/compile-fail/E0248.rs)12
-rw-r--r--src/test/run-pass/issue-8521.rs34
-rw-r--r--src/test/run-pass/multiple-reprs.rs43
-rw-r--r--src/test/run-pass/nonzero-enum.rs3
-rw-r--r--src/test/run-pass/struct-return.rs2
-rw-r--r--src/test/run-pass/trans-object-shim.rs14
-rw-r--r--src/test/run-pass/type-sizes.rs1
-rw-r--r--src/test/rustdoc/search-index-summaries.rs20
-rw-r--r--src/test/ui/codemap_tests/tab.stderr4
-rw-r--r--src/test/ui/codemap_tests/two_files.stderr6
-rw-r--r--src/test/ui/macros/macro-backtrace-nested.stderr8
-rw-r--r--src/test/ui/macros/macro_path_as_generic_bound.rs19
-rw-r--r--src/test/ui/macros/macro_path_as_generic_bound.stderr11
-rw-r--r--src/test/ui/mismatched_types/cast-rfc0401.rs82
-rw-r--r--src/test/ui/mismatched_types/cast-rfc0401.stderr240
-rw-r--r--src/test/ui/resolve/auxiliary/issue-21221-3.rs (renamed from src/test/compile-fail/auxiliary/issue-21221-3.rs)0
-rw-r--r--src/test/ui/resolve/auxiliary/issue-21221-4.rs (renamed from src/test/compile-fail/auxiliary/issue-21221-4.rs)0
-rw-r--r--src/test/ui/resolve/auxiliary/issue_19452_aux.rs (renamed from src/test/compile-fail/auxiliary/issue_19452_aux.rs)0
-rw-r--r--src/test/ui/resolve/auxiliary/issue_3907.rs (renamed from src/test/compile-fail/auxiliary/issue_3907.rs)0
-rw-r--r--src/test/ui/resolve/auxiliary/namespaced_enums.rs (renamed from src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs)15
-rw-r--r--src/test/ui/resolve/enums-are-namespaced-xc.rs (renamed from src/test/compile-fail/enums-are-namespaced-xc.rs)9
-rw-r--r--src/test/ui/resolve/enums-are-namespaced-xc.stderr29
-rw-r--r--src/test/ui/resolve/issue-14254.rs137
-rw-r--r--src/test/ui/resolve/issue-14254.stderr148
-rw-r--r--src/test/ui/resolve/issue-16058.rs (renamed from src/test/compile-fail/issue-16058.rs)7
-rw-r--r--src/test/ui/resolve/issue-16058.stderr13
-rw-r--r--src/test/ui/resolve/issue-17518.rs (renamed from src/test/compile-fail/issue-17518.rs)1
-rw-r--r--src/test/ui/resolve/issue-17518.stderr11
-rw-r--r--src/test/ui/resolve/issue-18252.rs (renamed from src/test/compile-fail/issue-18252.rs)3
-rw-r--r--src/test/ui/resolve/issue-18252.stderr8
-rw-r--r--src/test/ui/resolve/issue-19452.rs (renamed from src/test/compile-fail/issue-19452.rs)6
-rw-r--r--src/test/ui/resolve/issue-19452.stderr14
-rw-r--r--src/test/ui/resolve/issue-21221-1.rs (renamed from src/test/compile-fail/issue-21221-1.rs)13
-rw-r--r--src/test/ui/resolve/issue-21221-1.stderr41
-rw-r--r--src/test/ui/resolve/issue-21221-2.rs (renamed from src/test/compile-fail/issue-21221-2.rs)4
-rw-r--r--src/test/ui/resolve/issue-21221-2.stderr13
-rw-r--r--src/test/ui/resolve/issue-21221-3.rs (renamed from src/test/compile-fail/issue-21221-3.rs)4
-rw-r--r--src/test/ui/resolve/issue-21221-3.stderr11
-rw-r--r--src/test/ui/resolve/issue-21221-4.rs (renamed from src/test/compile-fail/issue-21221-4.rs)4
-rw-r--r--src/test/ui/resolve/issue-21221-4.stderr11
-rw-r--r--src/test/ui/resolve/issue-23305.rs22
-rw-r--r--src/test/ui/resolve/issue-23305.stderr16
-rw-r--r--src/test/ui/resolve/issue-2356.rs125
-rw-r--r--src/test/ui/resolve/issue-2356.stderr110
-rw-r--r--src/test/ui/resolve/issue-24968.rs (renamed from src/test/compile-fail/issue-24968.rs)3
-rw-r--r--src/test/ui/resolve/issue-24968.stderr8
-rw-r--r--src/test/ui/resolve/issue-33876.rs (renamed from src/test/compile-fail/issue-33876.rs)3
-rw-r--r--src/test/ui/resolve/issue-33876.stderr8
-rw-r--r--src/test/ui/resolve/issue-3907-2.rs (renamed from src/test/compile-fail/issue-3907-2.rs)0
-rw-r--r--src/test/ui/resolve/issue-3907-2.stderr10
-rw-r--r--src/test/ui/resolve/issue-3907.rs (renamed from src/test/compile-fail/issue-3907.rs)4
-rw-r--r--src/test/ui/resolve/issue-3907.stderr11
-rw-r--r--src/test/ui/resolve/issue-5035-2.rs (renamed from src/test/compile-fail/issue-5035-2.rs)0
-rw-r--r--src/test/ui/resolve/issue-5035-2.stderr11
-rw-r--r--src/test/ui/resolve/issue-5035.rs (renamed from src/test/compile-fail/issue-5035.rs)5
-rw-r--r--src/test/ui/resolve/issue-5035.stderr14
-rw-r--r--src/test/ui/resolve/issue-6702.rs (renamed from src/test/compile-fail/issue-6702.rs)4
-rw-r--r--src/test/ui/resolve/issue-6702.stderr8
-rw-r--r--src/test/ui/resolve/resolve-assoc-suggestions.rs58
-rw-r--r--src/test/ui/resolve/resolve-assoc-suggestions.stderr56
-rw-r--r--src/test/ui/resolve/resolve-hint-macro.rs (renamed from src/test/compile-fail/resolve-hint-macro.rs)4
-rw-r--r--src/test/ui/resolve/resolve-hint-macro.stderr8
-rw-r--r--src/test/ui/resolve/resolve-speculative-adjustment.rs44
-rw-r--r--src/test/ui/resolve/resolve-speculative-adjustment.stderr26
-rw-r--r--src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.rs (renamed from src/test/compile-fail/suggest-path-instead-of-mod-dot-item.rs)36
-rw-r--r--src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr58
-rw-r--r--src/test/ui/resolve/token-error-correct-2.rs (renamed from src/test/compile-fail/token-error-correct-2.rs)7
-rw-r--r--src/test/ui/resolve/token-error-correct-2.stderr20
-rw-r--r--src/test/ui/resolve/token-error-correct-3.rs (renamed from src/test/compile-fail/token-error-correct-3.rs)4
-rw-r--r--src/test/ui/resolve/token-error-correct-3.stderr45
-rw-r--r--src/test/ui/resolve/token-error-correct.rs (renamed from src/test/compile-fail/token-error-correct.rs)20
-rw-r--r--src/test/ui/resolve/token-error-correct.stderr56
-rw-r--r--src/test/ui/resolve/tuple-struct-alias.rs28
-rw-r--r--src/test/ui/resolve/tuple-struct-alias.stderr26
-rw-r--r--src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.rs21
-rw-r--r--src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr14
-rw-r--r--src/test/ui/resolve/unresolved_static_type_field.rs27
-rw-r--r--src/test/ui/resolve/unresolved_static_type_field.stderr11
-rw-r--r--src/test/ui/span/coerce-suggestions.rs47
-rw-r--r--src/test/ui/span/coerce-suggestions.stderr55
-rw-r--r--src/test/ui/span/impl-wrong-item-for-trait.stderr6
-rw-r--r--src/test/ui/span/issue-35987.stderr9
-rw-r--r--src/test/ui/span/typo-suggestion.stderr6
-rw-r--r--src/tools/cargotest/main.rs2
-rw-r--r--src/tools/compiletest/src/common.rs3
-rw-r--r--src/tools/compiletest/src/main.rs5
-rw-r--r--src/tools/compiletest/src/runtest.rs35
-rw-r--r--src/tools/tidy/src/features.rs2
-rw-r--r--src/vendor/gcc/.cargo-checksum.json2
-rw-r--r--src/vendor/gcc/.travis.yml4
-rw-r--r--src/vendor/gcc/Cargo.toml2
-rw-r--r--src/vendor/gcc/src/lib.rs60
-rw-r--r--src/vendor/gcc/src/windows_registry.rs5
-rw-r--r--src/vendor/gcc/tests/support/mod.rs3
-rwxr-xr-xx.py5
601 files changed, 19295 insertions, 10334 deletions
diff --git a/.travis.yml b/.travis.yml
index 996e5ec07b5..3a9635a8618 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,6 +8,8 @@ git:
   depth: 1
   submodules: false
 
+osx_image: xcode8.2
+
 matrix:
   include:
     # Linux builders, all docker images
@@ -27,28 +29,37 @@ matrix:
     # OSX builders
     - env: >
         RUST_CHECK_TARGET=check
-        RUST_CONFIGURE_ARGS=--target=x86_64-apple-darwin
+        RUST_CONFIGURE_ARGS=--build=x86_64-apple-darwin
         SRC=.
       os: osx
-      install: brew install ccache
+      install: &osx_install_sccache >
+        curl -L https://api.pub.build.mozilla.org/tooltool/sha512/d0025b286468cc5ada83b23d3fafbc936b9f190eaa7d4a981715b18e8e3bf720a7bcee7bfe758cfdeb8268857f6098fd52dcdd8818232692a30ce91039936596 |
+          tar xJf - -C /usr/local/bin --strip-components=1
     - env: >
         RUST_CHECK_TARGET=check
-        RUST_CONFIGURE_ARGS=--target=i686-apple-darwin
+        RUST_CONFIGURE_ARGS=--build=i686-apple-darwin
         SRC=.
       os: osx
-      install: brew install ccache
+      install: *osx_install_sccache
     - env: >
         RUST_CHECK_TARGET=check
-        RUST_CONFIGURE_ARGS=--target=x86_64-apple-darwin --disable-rustbuild
+        RUST_CONFIGURE_ARGS=--build=x86_64-apple-darwin --disable-rustbuild
         SRC=.
       os: osx
-      install: brew install ccache
+      install: *osx_install_sccache
     - env: >
         RUST_CHECK_TARGET=
         RUST_CONFIGURE_ARGS=--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios
         SRC=.
       os: osx
-      install: brew install ccache
+      install: *osx_install_sccache
+
+env:
+  global:
+    - SCCACHE_BUCKET=rust-lang-ci-sccache
+    - AWS_ACCESS_KEY_ID=AKIAIMX7VLAS3PZAVLUQ
+    # AWS_SECRET_ACCESS_KEY=...
+    - secure: "Pixhh0hXDqGCdOyLtGFjli3J2AtDWIpyb2btIrLe956nCBDRutRoMm6rv5DI9sFZN07Mms7VzNNvhc9wCW1y63JAm414d2Co7Ob8kWMZlz9l9t7ACHuktUiis8yr+S4Quq1Vqd6pqi7pf2J++UxC8R/uLeqVrubzr6+X7AbmEFE="
 
 script:
   - >
@@ -77,5 +88,3 @@ notifications:
 cache:
   directories:
     - $HOME/docker
-    - $HOME/.ccache
-    - $HOME/.cargo
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 20a0bd2e256..cdbabeaddfb 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -212,12 +212,13 @@ Some common invocations of `x.py` are:
   & everything builds in the correct manner.
 - `x.py test src/libstd --stage 1` - test the standard library without
   recompiling stage 2.
-- `x.py test src/test/run-pass --filter TESTNAME` - Run a matching set of tests.
+- `x.py test src/test/run-pass --test-args TESTNAME` - Run a matching set of
+  tests.
   - `TESTNAME` should be a substring of the tests to match against e.g. it could
     be the fully qualified test name, or just a part of it.
     `TESTNAME=collections::hash::map::test_map::test_capacity_not_less_than_len`
     or `TESTNAME=test_capacity_not_less_than_len`.
-- `x.py test src/test/run-pass --stage 1 --filter <substring-of-test-name>` -
+- `x.py test src/test/run-pass --stage 1 --test-args <substring-of-test-name>` -
   Run a single rpass test with the stage1 compiler (this will be quicker than
   running the command above as we only build the stage1 compiler, not the entire
   thing).  You can also leave off the directory argument to run all stage1 test
@@ -284,7 +285,7 @@ been approved. The PR then enters the [merge queue][merge-queue], where @bors
 will run all the tests on every platform we support. If it all works out,
 @bors will merge your code into `master` and close the pull request.
 
-[merge-queue]: http://buildbot.rust-lang.org/homu/queue/rust
+[merge-queue]: https://buildbot.rust-lang.org/homu/queue/rust
 
 Speaking of tests, Rust has a comprehensive test suite. More information about
 it can be found
@@ -403,4 +404,4 @@ are:
 [tlgba]: http://tomlee.co/2014/04/a-more-detailed-tour-of-the-rust-compiler/
 [ro]: http://www.rustaceans.org/
 [rctd]: ./COMPILER_TESTS.md
-[cheatsheet]: http://buildbot.rust-lang.org/homu/
+[cheatsheet]: https://buildbot.rust-lang.org/homu/
diff --git a/RELEASES.md b/RELEASES.md
index e468a86e7ac..e85c9d18db9 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,222 @@
+Version 1.14.0 (2016-12-22)
+===========================
+
+Language
+--------
+
+* [`..` matches multiple tuple fields in enum variants, structs
+  and tuples][36843]. [RFC 1492].
+* [Safe `fn` items can be coerced to `unsafe fn` pointers][37389]
+* [`use *` and `use ::*` both glob-import from the crate root][37367]
+* [It's now possible to call a `Vec<Box<Fn()>>` without explicit
+  dereferencing][36822]
+
+Compiler
+--------
+
+* [Mark enums with non-zero discriminant as non-zero][37224]
+* [Lower-case `static mut` names are linted like other
+  statics and consts][37162]
+* [Fix ICE on some macros in const integer positions
+   (e.g. `[u8; m!()]`)][36819]
+* [Improve error message and snippet for "did you mean `x`"][36798]
+* [Add a panic-strategy field to the target specification][36794]
+* [Include LLVM version in `--version --verbose`][37200]
+
+Compile-time Optimizations
+--------------------------
+
+* [Improve macro expansion performance][37569]
+* [Shrink `Expr_::ExprInlineAsm`][37445]
+* [Replace all uses of SHA-256 with BLAKE2b][37439]
+* [Reduce the number of bytes hashed by `IchHasher`][37427]
+* [Avoid more allocations when compiling html5ever][37373]
+* [Use `SmallVector` in `CombineFields::instantiate`][37322]
+* [Avoid some allocations in the macro parser][37318]
+* [Use a faster deflate setting][37298]
+* [Add `ArrayVec` and `AccumulateVec` to reduce heap allocations
+  during interning of slices][37270]
+* [Optimize `write_metadata`][37267]
+* [Don't process obligation forest cycles when stalled][37231]
+* [Avoid many `CrateConfig` clones][37161]
+* [Optimize `Substs::super_fold_with`][37108]
+* [Optimize `ObligationForest`'s `NodeState` handling][36993]
+* [Speed up `plug_leaks`][36917]
+
+Libraries
+---------
+
+* [`println!()`, with no arguments, prints newline][36825].
+  Previously, an empty string was required to achieve the same.
+* [`Wrapping` impls standard binary and unary operators, as well as
+   the `Sum` and `Product` iterators][37356]
+* [Implement `From<Cow<str>> for String` and `From<Cow<[T]>> for
+  Vec<T>`][37326]
+* [Improve `fold` performance for `chain`, `cloned`, `map`, and
+  `VecDeque` iterators][37315]
+* [Improve `SipHasher` performance on small values][37312]
+* [Add Iterator trait TrustedLen to enable better FromIterator /
+  Extend][37306]
+* [Expand `.zip()` specialization to `.map()` and `.cloned()`][37230]
+* [`ReadDir` implements `Debug`][37221]
+* [Implement `RefUnwindSafe` for atomic types][37178]
+* [Specialize `Vec::extend` to `Vec::extend_from_slice`][37094]
+* [Avoid allocations in `Decoder::read_str`][37064]
+* [`io::Error` implements `From<io::ErrorKind>`][37037]
+* [Impl `Debug` for raw pointers to unsized data][36880]
+* [Don't reuse `HashMap` random seeds][37470]
+* [The internal memory layout of `HashMap` is more cache-friendly, for
+  significant improvements in some operations][36692]
+* [`HashMap` uses less memory on 32-bit architectures][36595]
+* [Impl `Add<{str, Cow<str>}>` for `Cow<str>`][36430]
+
+Cargo
+-----
+
+* [Expose rustc cfg values to build scripts][cargo/3243]
+* [Allow cargo to work with read-only `CARGO_HOME`][cargo/3259]
+* [Fix passing --features when testing multiple packages][cargo/3280]
+* [Use a single profile set per workspace][cargo/3249]
+* [Load `replace` sections from lock files][cargo/3220]
+* [Ignore `panic` configuration for test/bench profiles][cargo/3175]
+
+Tooling
+-------
+
+* [rustup is the recommended Rust installation method][1.14rustup]
+* This release includes host (rustc) builds for Linux on MIPS, PowerPC, and
+  S390x. These are [tier 2] platforms and may have major defects. Follow the
+  instructions on the website to install, or add the targets to an existing
+  installation with `rustup target add`. The new target triples are:
+  - `mips-unknown-linux-gnu`
+  - `mipsel-unknown-linux-gnu`
+  - `mips64-unknown-linux-gnuabi64`
+  - `mips64el-unknown-linux-gnuabi64 `
+  - `powerpc-unknown-linux-gnu`
+  - `powerpc64-unknown-linux-gnu`
+  - `powerpc64le-unknown-linux-gnu`
+  - `s390x-unknown-linux-gnu `
+* This release includes target (std) builds for ARM Linux running MUSL
+  libc. These are [tier 2] platforms and may have major defects. Add the
+  following triples to an existing rustup installation with `rustup target add`:
+  - `arm-unknown-linux-musleabi`
+  - `arm-unknown-linux-musleabihf`
+  - `armv7-unknown-linux-musleabihf`
+* This release includes [experimental support for WebAssembly][1.14wasm], via
+  the `wasm32-unknown-emscripten` target. This target is known to have major
+  defects. Please test, report, and fix.
+* rustup no longer installs documentation by default. Run `rustup
+  component add rust-docs` to install.
+* [Fix line stepping in debugger][37310]
+* [Enable line number debuginfo in releases][37280]
+
+Misc
+----
+
+* [Disable jemalloc on aarch64/powerpc/mips][37392]
+* [Add support for Fuchsia OS][37313]
+* [Detect local-rebuild by only MAJOR.MINOR version][37273]
+
+Compatibility Notes
+-------------------
+
+* [A number of forward-compatibility lints used by the compiler
+  to gradually introduce language changes have been converted
+  to deny by default][36894]:
+  - ["use of inaccessible extern crate erroneously allowed"][36886]
+  - ["type parameter default erroneously allowed in invalid location"][36887]
+  - ["detects super or self keywords at the beginning of global path"][36888]
+  - ["two overlapping inherent impls define an item with the same name
+    were erroneously allowed"][36889]
+  - ["floating-point constants cannot be used in patterns"][36890]
+  - ["constants of struct or enum type can only be used in a pattern if
+     the struct or enum has `#[derive(PartialEq, Eq)]`"][36891]
+  - ["lifetimes or labels named `'_` were erroneously allowed"][36892]
+* [Prohibit patterns in trait methods without bodies][37378]
+* [The atomic `Ordering` enum may not be matched exhaustively][37351]
+* [Future-proofing `#[no_link]` breaks some obscure cases][37247]
+* [The `$crate` macro variable is accepted in fewer locations][37213]
+* [Impls specifying extra region requirements beyond the trait
+  they implement are rejected][37167]
+* [Enums may not be unsized][37111]. Unsized enums are intended to
+  work but never have. For now they are forbidden.
+* [Enforce the shadowing restrictions from RFC 1560 for today's macros][36767]
+
+[tier 2]: https://forge.rust-lang.org/platform-support.html
+[1.14rustup]: https://internals.rust-lang.org/t/beta-testing-rustup-rs/3316/204
+[1.14wasm]: https://users.rust-lang.org/t/compiling-to-the-web-with-rust-and-emscripten/7627
+[36430]: https://github.com/rust-lang/rust/pull/36430
+[36595]: https://github.com/rust-lang/rust/pull/36595
+[36595]: https://github.com/rust-lang/rust/pull/36595
+[36692]: https://github.com/rust-lang/rust/pull/36692
+[36767]: https://github.com/rust-lang/rust/pull/36767
+[36794]: https://github.com/rust-lang/rust/pull/36794
+[36798]: https://github.com/rust-lang/rust/pull/36798
+[36819]: https://github.com/rust-lang/rust/pull/36819
+[36822]: https://github.com/rust-lang/rust/pull/36822
+[36825]: https://github.com/rust-lang/rust/pull/36825
+[36843]: https://github.com/rust-lang/rust/pull/36843
+[36880]: https://github.com/rust-lang/rust/pull/36880
+[36886]: https://github.com/rust-lang/rust/issues/36886
+[36887]: https://github.com/rust-lang/rust/issues/36887
+[36888]: https://github.com/rust-lang/rust/issues/36888
+[36889]: https://github.com/rust-lang/rust/issues/36889
+[36890]: https://github.com/rust-lang/rust/issues/36890
+[36891]: https://github.com/rust-lang/rust/issues/36891
+[36892]: https://github.com/rust-lang/rust/issues/36892
+[36894]: https://github.com/rust-lang/rust/pull/36894
+[36917]: https://github.com/rust-lang/rust/pull/36917
+[36993]: https://github.com/rust-lang/rust/pull/36993
+[37037]: https://github.com/rust-lang/rust/pull/37037
+[37064]: https://github.com/rust-lang/rust/pull/37064
+[37094]: https://github.com/rust-lang/rust/pull/37094
+[37108]: https://github.com/rust-lang/rust/pull/37108
+[37111]: https://github.com/rust-lang/rust/pull/37111
+[37161]: https://github.com/rust-lang/rust/pull/37161
+[37162]: https://github.com/rust-lang/rust/pull/37162
+[37167]: https://github.com/rust-lang/rust/pull/37167
+[37178]: https://github.com/rust-lang/rust/pull/37178
+[37200]: https://github.com/rust-lang/rust/pull/37200
+[37213]: https://github.com/rust-lang/rust/pull/37213
+[37221]: https://github.com/rust-lang/rust/pull/37221
+[37224]: https://github.com/rust-lang/rust/pull/37224
+[37230]: https://github.com/rust-lang/rust/pull/37230
+[37231]: https://github.com/rust-lang/rust/pull/37231
+[37247]: https://github.com/rust-lang/rust/pull/37247
+[37267]: https://github.com/rust-lang/rust/pull/37267
+[37270]: https://github.com/rust-lang/rust/pull/37270
+[37273]: https://github.com/rust-lang/rust/pull/37273
+[37280]: https://github.com/rust-lang/rust/pull/37280
+[37298]: https://github.com/rust-lang/rust/pull/37298
+[37306]: https://github.com/rust-lang/rust/pull/37306
+[37310]: https://github.com/rust-lang/rust/pull/37310
+[37312]: https://github.com/rust-lang/rust/pull/37312
+[37313]: https://github.com/rust-lang/rust/pull/37313
+[37315]: https://github.com/rust-lang/rust/pull/37315
+[37318]: https://github.com/rust-lang/rust/pull/37318
+[37322]: https://github.com/rust-lang/rust/pull/37322
+[37326]: https://github.com/rust-lang/rust/pull/37326
+[37351]: https://github.com/rust-lang/rust/pull/37351
+[37356]: https://github.com/rust-lang/rust/pull/37356
+[37367]: https://github.com/rust-lang/rust/pull/37367
+[37373]: https://github.com/rust-lang/rust/pull/37373
+[37378]: https://github.com/rust-lang/rust/pull/37378
+[37389]: https://github.com/rust-lang/rust/pull/37389
+[37392]: https://github.com/rust-lang/rust/pull/37392
+[37427]: https://github.com/rust-lang/rust/pull/37427
+[37439]: https://github.com/rust-lang/rust/pull/37439
+[37445]: https://github.com/rust-lang/rust/pull/37445
+[37470]: https://github.com/rust-lang/rust/pull/37470
+[37569]: https://github.com/rust-lang/rust/pull/37569
+[RFC 1492]: https://github.com/rust-lang/rfcs/blob/master/text/1492-dotdot-in-patterns.md
+[cargo/3175]: https://github.com/rust-lang/cargo/pull/3175
+[cargo/3220]: https://github.com/rust-lang/cargo/pull/3220
+[cargo/3243]: https://github.com/rust-lang/cargo/pull/3243
+[cargo/3249]: https://github.com/rust-lang/cargo/pull/3249
+[cargo/3259]: https://github.com/rust-lang/cargo/pull/3259
+[cargo/3280]: https://github.com/rust-lang/cargo/pull/3280
+
+
 Version 1.13.0 (2016-11-10)
 ===========================
 
diff --git a/appveyor.yml b/appveyor.yml
index bf75439b74a..cb3b50cbaef 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,4 +1,9 @@
 environment:
+  SCCACHE_BUCKET: rust-lang-ci-sccache
+  AWS_ACCESS_KEY_ID: AKIAIMX7VLAS3PZAVLUQ
+  AWS_SECRET_ACCESS_KEY:
+    secure: 1UkmbiDd15tWtYbMm5O2Uqm0b0Ur8v1MoSlydxl4ojcroPeerRMlUges0l57py8c
+  SCCACHE_DIGEST: f808afabb4a4eb1d7112bcb3fa6be03b61e93412890c88e177c667eb37f46353d7ec294e559b16f9f4b5e894f2185fe7670a0df15fd064889ecbd80f0c34166c
   matrix:
   # 32/64 bit MSVC
   - MSYS_BITS: 64
@@ -84,6 +89,13 @@ install:
   # Otherwise pull in the MinGW installed on appveyor
   - if NOT defined MINGW_URL set PATH=C:\msys64\mingw%MSYS_BITS%\bin;C:\msys64\usr\bin;%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
+
 test_script:
   - git submodule update --init
   - set SRC=.
diff --git a/configure b/configure
index 0a07e41fb97..4f1e8f656ae 100755
--- a/configure
+++ b/configure
@@ -621,6 +621,7 @@ opt llvm-assertions 0 "build LLVM with assertions"
 opt debug-assertions 0 "build with debugging assertions"
 opt fast-make 0 "use .gitmodules as timestamp for submodule deps"
 opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds"
+opt sccache 0 "invoke gcc/clang via sccache to reuse object files between builds"
 opt local-rust 0 "use an installed rustc rather than downloading a snapshot"
 opt local-rebuild 0 "assume local-rust matches the current version, for rebuilds; implies local-rust, and is implied if local-rust already matches the current version"
 opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM"
@@ -916,6 +917,18 @@ case $CFG_BUILD in
 esac
 putvar CFG_LLDB_PYTHON
 
+# Do some sanity checks if running on buildbot
+# (these env vars are set by rust-buildbot)
+if [ -n "$RUST_DIST_SERVER" -a -n "$ALLOW_NONZERO_RLIMIT_CORE" ]; then
+   # Frequently the llvm submodule directory is broken by the build
+   # being killed
+   llvm_lock="${CFG_SRC_DIR}/.git/modules/src/llvm/index.lock"
+   if [ -e "$llvm_lock" ]; then
+       step_msg "removing $llvm_lock"
+       rm -f "$llvm_lock"
+   fi
+fi
+
 step_msg "looking for target specific programs"
 
 probe CFG_ADB        adb
@@ -1677,11 +1690,23 @@ do
             LLVM_CC_64_ARG1="gcc"
             ;;
         ("gcc")
-            LLVM_CXX_32="g++"
-            LLVM_CC_32="gcc"
+            if [ -z "$CFG_ENABLE_SCCACHE" ]; then
+                LLVM_CXX_32="g++"
+                LLVM_CC_32="gcc"
 
-            LLVM_CXX_64="g++"
-            LLVM_CC_64="gcc"
+                LLVM_CXX_64="g++"
+                LLVM_CC_64="gcc"
+            else
+                LLVM_CXX_32="sccache"
+                LLVM_CC_32="sccache"
+                LLVM_CXX_32_ARG1="g++"
+                LLVM_CC_32_ARG1="gcc"
+
+                LLVM_CXX_64="sccache"
+                LLVM_CC_64="sccache"
+                LLVM_CXX_64_ARG1="g++"
+                LLVM_CC_64_ARG1="gcc"
+            fi
             ;;
 
         (*)
diff --git a/mk/cfg/x86_64-unknown-redox.mk b/mk/cfg/x86_64-unknown-redox.mk
new file mode 100644
index 00000000000..34aee77ae21
--- /dev/null
+++ b/mk/cfg/x86_64-unknown-redox.mk
@@ -0,0 +1 @@
+# rustbuild-only target
diff --git a/mk/main.mk b/mk/main.mk
index 49fdfc4118d..d01ec07b424 100644
--- a/mk/main.mk
+++ b/mk/main.mk
@@ -13,7 +13,7 @@
 ######################################################################
 
 # The version number
-CFG_RELEASE_NUM=1.15.0
+CFG_RELEASE_NUM=1.16.0
 
 # An optional number to put after the label, e.g. '.2' -> '-beta.2'
 # NB Make sure it starts with a dot to conform to semver pre-release
diff --git a/mk/tests.mk b/mk/tests.mk
index 345fc1679b0..3317688f042 100644
--- a/mk/tests.mk
+++ b/mk/tests.mk
@@ -22,7 +22,7 @@ $(eval $(call RUST_CRATE,coretest))
 DEPS_collectionstest :=
 $(eval $(call RUST_CRATE,collectionstest))
 
-TEST_TARGET_CRATES = $(filter-out core rustc_unicode alloc_system libc \
+TEST_TARGET_CRATES = $(filter-out core std_unicode alloc_system libc \
 		     		  alloc_jemalloc panic_unwind \
 				  panic_abort,$(TARGET_CRATES)) \
 			collectionstest coretest
diff --git a/src/Cargo.lock b/src/Cargo.lock
index 4c6aeeddd38..9cd77e71b82 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -19,7 +19,7 @@ version = "0.0.0"
 dependencies = [
  "build_helper 0.1.0",
  "core 0.0.0",
- "gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.0.0",
 ]
 
@@ -42,7 +42,7 @@ dependencies = [
  "build_helper 0.1.0",
  "cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -63,7 +63,7 @@ name = "cmake"
 version = "0.1.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -80,7 +80,7 @@ name = "compiler_builtins"
 version = "0.0.0"
 dependencies = [
  "core 0.0.0",
- "gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -121,7 +121,7 @@ name = "flate"
 version = "0.0.0"
 dependencies = [
  "build_helper 0.1.0",
- "gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -130,7 +130,7 @@ version = "0.0.0"
 
 [[package]]
 name = "gcc"
-version = "0.3.38"
+version = "0.3.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -402,7 +402,7 @@ name = "rustc_llvm"
 version = "0.0.0"
 dependencies = [
  "build_helper 0.1.0",
- "gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_bitflags 0.0.0",
 ]
 
@@ -551,7 +551,7 @@ version = "0.0.0"
 dependencies = [
  "arena 0.0.0",
  "build_helper 0.1.0",
- "gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.0.0",
  "rustc 0.0.0",
  "rustc_back 0.0.0",
@@ -587,7 +587,7 @@ dependencies = [
  "collections 0.0.0",
  "compiler_builtins 0.0.0",
  "core 0.0.0",
- "gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.0.0",
  "panic_abort 0.0.0",
  "panic_unwind 0.0.0",
@@ -677,7 +677,7 @@ dependencies = [
 "checksum cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0e5bcf27e097a184c1df4437654ed98df3d7a516e8508a6ba45d8b092bbdf283"
 "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
 "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
-"checksum gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "553f11439bdefe755bf366b264820f1da70f3aaf3924e594b886beb9c831bcf5"
+"checksum gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "872db9e59486ef2b14f8e8c10e9ef02de2bccef6363d7f34835dedb386b3d950"
 "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
 "checksum libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "044d1360593a78f5c8e5e710beccdc24ab71d1f01bc19a29bcacdba22e8475d8"
 "checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md
index d0b501e4d89..ac84edb4038 100644
--- a/src/bootstrap/README.md
+++ b/src/bootstrap/README.md
@@ -22,7 +22,7 @@ Note that if you're on Unix you should be able to execute the script directly:
 ./x.py build
 ```
 
-The script accepts commands, flags, and filters to determine what to do:
+The script accepts commands, flags, and arguments to determine what to do:
 
 * `build` - a general purpose command for compiling code. Alone `build` will
   bootstrap the entire compiler, and otherwise arguments passed indicate what to
@@ -42,6 +42,15 @@ The script accepts commands, flags, and filters to determine what to do:
   ./x.py build --stage 0 src/libtest
   ```
 
+  If files are dirty that would normally be rebuilt from stage 0, that can be
+  overidden using `--keep-stage 0`. Using `--keep-stage n` will skip all steps
+  that belong to stage n or earlier:
+
+  ```
+  # keep old build products for stage 0 and build stage 1
+  ./x.py build --keep-stage 0 --stage 1
+  ```
+
 * `test` - a command for executing unit tests. Like the `build` command this
   will execute the entire test suite by default, and otherwise it can be used to
   select which test suite is run:
@@ -54,7 +63,7 @@ The script accepts commands, flags, and filters to determine what to do:
   ./x.py test src/test/run-pass
 
   # execute only some tests in the run-pass test suite
-  ./x.py test src/test/run-pass --filter my-filter
+  ./x.py test src/test/run-pass --test-args substring-of-test-name
 
   # execute tests in the standard library in stage0
   ./x.py test --stage 0 src/libstd
@@ -107,6 +116,42 @@ compiler. What actually happens when you invoke rustbuild is:
 The goal of each stage is to (a) leverage Cargo as much as possible and failing
 that (b) leverage Rust as much as possible!
 
+## Incremental builds
+
+You can configure rustbuild to use incremental compilation. Because
+incremental is new and evolving rapidly, if you want to use it, it is
+recommended that you replace the snapshot with a locally installed
+nightly build of rustc. You will want to keep this up to date.
+
+To follow this course of action, first thing you will want to do is to
+install a nightly, presumably using `rustup`. You will then want to
+configure your directory to use this build, like so:
+
+```
+# configure to use local rust instead of downloding a beta.
+# `--local-rust-root` is optional here. If elided, we will
+# use whatever rustc we find on your PATH.
+> configure --enable-rustbuild --local-rust-root=~/.cargo/ --enable-local-rebuild
+```
+
+After that, you can use the `--incremental` flag to actually do
+incremental builds:
+
+```
+> ../x.py build --incremental
+```
+
+The `--incremental` flag will store incremental compilation artifacts
+in `build/<host>/stage0-incremental`. Note that we only use incremental
+compilation for the stage0 -> stage1 compilation -- this is because
+the stage1 compiler is changing, and we don't try to cache and reuse
+incremental artifacts across different versions of the compiler. For
+this reason, `--incremental` defaults to `--stage 1` (though you can
+manually select a higher stage, if you prefer).
+
+You can always drop the `--incremental` to build as normal (but you
+will still be using the local nightly as your bootstrap).
+
 ## Directory Layout
 
 This build system houses all output under the `build` directory, which looks
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index 2f674a311fe..9cab6c423f5 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -25,12 +25,17 @@
 //! switching compilers for the bootstrap and for build scripts will probably
 //! never get replaced.
 
+#![deny(warnings)]
+
 extern crate bootstrap;
 
 use std::env;
 use std::ffi::OsString;
+use std::io;
+use std::io::prelude::*;
+use std::str::FromStr;
 use std::path::PathBuf;
-use std::process::Command;
+use std::process::{Command, ExitStatus};
 
 fn main() {
     let args = env::args_os().skip(1).collect::<Vec<_>>();
@@ -41,6 +46,11 @@ fn main() {
         .and_then(|w| w[1].to_str());
     let version = args.iter().find(|w| &**w == "-vV");
 
+    let verbose = match env::var("RUSTC_VERBOSE") {
+        Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"),
+        Err(_) => 0,
+    };
+
     // Build scripts always use the snapshot compiler which is guaranteed to be
     // able to produce an executable, whereas intermediate compilers may not
     // have the standard library built yet and may not be able to produce an
@@ -95,6 +105,15 @@ fn main() {
             cmd.args(&s.split(" ").filter(|s| !s.is_empty()).collect::<Vec<_>>());
         }
 
+        // Pass down incremental directory, if any.
+        if let Ok(dir) = env::var("RUSTC_INCREMENTAL") {
+            cmd.arg(format!("-Zincremental={}", dir));
+
+            if verbose > 0 {
+                cmd.arg("-Zincremental-info");
+            }
+        }
+
         // If we're compiling specifically the `panic_abort` crate then we pass
         // the `-C panic=abort` option. Note that we do not do this for any
         // other crate intentionally as this is the only crate for now that we
@@ -158,6 +177,15 @@ fn main() {
         // to change a flag in a binary?
         if env::var("RUSTC_RPATH") == Ok("true".to_string()) {
             let rpath = if target.contains("apple") {
+
+                // Note that we need to take one extra step on OSX to also pass
+                // `-Wl,-instal_name,@rpath/...` to get things to work right. To
+                // do that we pass a weird flag to the compiler to get it to do
+                // so. Note that this is definitely a hack, and we should likely
+                // flesh out rpath support more fully in the future.
+                if stage != "0" {
+                    cmd.arg("-Z").arg("osx-rpath-install-name");
+                }
                 Some("-Wl,-rpath,@loader_path/../lib")
             } else if !target.contains("windows") {
                 Some("-Wl,-rpath,$ORIGIN/../lib")
@@ -167,12 +195,33 @@ fn main() {
             if let Some(rpath) = rpath {
                 cmd.arg("-C").arg(format!("link-args={}", rpath));
             }
+
+            if let Ok(s) = env::var("RUSTFLAGS") {
+                for flag in s.split_whitespace() {
+                    cmd.arg(flag);
+                }
+            }
         }
     }
 
+    if verbose > 1 {
+        writeln!(&mut io::stderr(), "rustc command: {:?}", cmd).unwrap();
+    }
+
     // Actually run the compiler!
-    std::process::exit(match cmd.status() {
-        Ok(s) => s.code().unwrap_or(1),
+    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),
     })
 }
+
+#[cfg(unix)]
+fn exec_cmd(cmd: &mut Command) -> ::std::io::Result<ExitStatus> {
+    use std::os::unix::process::CommandExt;
+    Err(cmd.exec())
+}
+
+#[cfg(not(unix))]
+fn exec_cmd(cmd: &mut Command) -> ::std::io::Result<ExitStatus> {
+    cmd.status()
+}
diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs
index 67358e540da..a53bbe22eb9 100644
--- a/src/bootstrap/bin/rustdoc.rs
+++ b/src/bootstrap/bin/rustdoc.rs
@@ -12,6 +12,8 @@
 //!
 //! See comments in `src/bootstrap/rustc.rs` for more information.
 
+#![deny(warnings)]
+
 extern crate bootstrap;
 
 use std::env;
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 0dda7f12007..89d297760e2 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -81,7 +81,7 @@ def verify(path, sha_path, verbose):
     with open(path, "rb") as f:
         found = hashlib.sha256(f.read()).hexdigest()
     with open(sha_path, "r") as f:
-        expected, _ = f.readline().split()
+        expected = f.readline().split()[0]
     verified = found == expected
     if not verified:
         print("invalid checksum:\n"
@@ -146,7 +146,7 @@ class RustBuild(object):
     def download_stage0(self):
         cache_dst = os.path.join(self.build_dir, "cache")
         rustc_cache = os.path.join(cache_dst, self.stage0_rustc_date())
-        cargo_cache = os.path.join(cache_dst, self.stage0_cargo_date())
+        cargo_cache = os.path.join(cache_dst, self.stage0_cargo_rev())
         if not os.path.exists(rustc_cache):
             os.makedirs(rustc_cache)
         if not os.path.exists(cargo_cache):
@@ -179,21 +179,17 @@ class RustBuild(object):
         if self.cargo().startswith(self.bin_root()) and \
                 (not os.path.exists(self.cargo()) or self.cargo_out_of_date()):
             self.print_what_it_means_to_bootstrap()
-            channel = self.stage0_cargo_channel()
-            filename = "cargo-{}-{}.tar.gz".format(channel, self.build)
-            url = "https://static.rust-lang.org/cargo-dist/" + self.stage0_cargo_date()
+            filename = "cargo-nightly-{}.tar.gz".format(self.build)
+            url = "https://s3.amazonaws.com/rust-lang-ci/cargo-builds/" + self.stage0_cargo_rev()
             tarball = os.path.join(cargo_cache, filename)
             if not os.path.exists(tarball):
                 get("{}/{}".format(url, filename), tarball, verbose=self.verbose)
             unpack(tarball, self.bin_root(), match="cargo", verbose=self.verbose)
             with open(self.cargo_stamp(), 'w') as f:
-                f.write(self.stage0_cargo_date())
+                f.write(self.stage0_cargo_rev())
 
-    def stage0_cargo_date(self):
-        return self._cargo_date
-
-    def stage0_cargo_channel(self):
-        return self._cargo_channel
+    def stage0_cargo_rev(self):
+        return self._cargo_rev
 
     def stage0_rustc_date(self):
         return self._rustc_date
@@ -217,7 +213,7 @@ class RustBuild(object):
         if not os.path.exists(self.cargo_stamp()) or self.clean:
             return True
         with open(self.cargo_stamp(), 'r') as f:
-            return self.stage0_cargo_date() != f.read()
+            return self.stage0_cargo_rev() != f.read()
 
     def bin_root(self):
         return os.path.join(self.build_dir, self.build, "stage0")
@@ -294,6 +290,8 @@ class RustBuild(object):
         env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib")
         env["PATH"] = os.path.join(self.bin_root(), "bin") + \
                       os.pathsep + env["PATH"]
+        if not os.path.isfile(self.cargo()):
+            raise Exception("no cargo executable found at `%s`" % self.cargo())
         args = [self.cargo(), "build", "--manifest-path",
                 os.path.join(self.rust_root, "src/bootstrap/Cargo.toml")]
         if self.use_vendored_sources:
@@ -467,7 +465,7 @@ def main():
 
     data = stage0_data(rb.rust_root)
     rb._rustc_channel, rb._rustc_date = data['rustc'].split('-', 1)
-    rb._cargo_channel, rb._cargo_date = data['cargo'].split('-', 1)
+    rb._cargo_rev = data['cargo']
 
     start_time = time()
 
diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs
index b2341f59787..c38bb33aa02 100644
--- a/src/bootstrap/channel.rs
+++ b/src/bootstrap/channel.rs
@@ -15,7 +15,7 @@
 //! `package_vers`, and otherwise indicating to the compiler what it should
 //! print out as part of its version information.
 
-use std::fs::{self, File};
+use std::fs::File;
 use std::io::prelude::*;
 use std::process::Command;
 
@@ -69,7 +69,7 @@ pub fn collect(build: &mut Build) {
 
     // If we have a git directory, add in some various SHA information of what
     // commit this compiler was compiled from.
-    if fs::metadata(build.src.join(".git")).is_ok() {
+    if build.src.join(".git").is_dir() {
         let ver_date = output(Command::new("git").current_dir(&build.src)
                                       .arg("log").arg("-1")
                                       .arg("--date=short")
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index e0798860275..e7b0afeb8ce 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -13,6 +13,8 @@
 //! This file implements the various regression test suites that we execute on
 //! our CI.
 
+extern crate build_helper;
+
 use std::collections::HashSet;
 use std::env;
 use std::fmt;
@@ -190,7 +192,7 @@ pub fn compiletest(build: &Build,
 
     cmd.args(&build.flags.cmd.test_args());
 
-    if build.config.verbose || build.flags.verbose {
+    if build.config.verbose() || build.flags.verbose() {
         cmd.arg("--verbose");
     }
 
@@ -299,6 +301,7 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) {
     build.add_rust_test_threads(&mut cmd);
     cmd.arg("--test");
     cmd.arg(markdown);
+    cmd.env("RUSTC_BOOTSTRAP", "1");
 
     let mut test_args = build.flags.cmd.test_args().join(" ");
     if build.config.quiet_tests {
@@ -542,7 +545,7 @@ pub fn distcheck(build: &Build) {
     build.run(&mut cmd);
     build.run(Command::new("./configure")
                      .current_dir(&dir));
-    build.run(Command::new("make")
+    build.run(Command::new(build_helper::make(&build.config.build))
                      .arg("check")
                      .current_dir(&dir));
 }
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 60f65f62300..6b86e537b7d 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -38,9 +38,9 @@ use util::push_exe_path;
 /// `src/bootstrap/config.toml.example`.
 #[derive(Default)]
 pub struct Config {
-    pub ccache: bool,
+    pub ccache: Option<String>,
     pub ninja: bool,
-    pub verbose: bool,
+    pub verbose: usize,
     pub submodules: bool,
     pub compiler_docs: bool,
     pub docs: bool,
@@ -113,6 +113,7 @@ pub struct Target {
 #[derive(RustcDecodable, Default)]
 struct TomlConfig {
     build: Option<Build>,
+    install: Option<Install>,
     llvm: Option<Llvm>,
     rust: Option<Rust>,
     target: Option<HashMap<String, TomlTarget>>,
@@ -135,10 +136,16 @@ struct Build {
     python: Option<String>,
 }
 
+/// TOML representation of various global install decisions.
+#[derive(RustcDecodable, Default, Clone)]
+struct Install {
+    prefix: Option<String>,
+}
+
 /// TOML representation of how the LLVM build is configured.
 #[derive(RustcDecodable, Default)]
 struct Llvm {
-    ccache: Option<bool>,
+    ccache: Option<StringOrBool>,
     ninja: Option<bool>,
     assertions: Option<bool>,
     optimize: Option<bool>,
@@ -147,6 +154,18 @@ struct Llvm {
     static_libstdcpp: Option<bool>,
 }
 
+#[derive(RustcDecodable)]
+enum StringOrBool {
+    String(String),
+    Bool(bool),
+}
+
+impl Default for StringOrBool {
+    fn default() -> StringOrBool {
+        StringOrBool::Bool(false)
+    }
+}
+
 /// TOML representation of how the Rust build is configured.
 #[derive(RustcDecodable, Default)]
 struct Rust {
@@ -246,8 +265,20 @@ impl Config {
         set(&mut config.submodules, build.submodules);
         set(&mut config.vendor, build.vendor);
 
+        if let Some(ref install) = toml.install {
+            config.prefix = install.prefix.clone();
+        }
+
         if let Some(ref llvm) = toml.llvm {
-            set(&mut config.ccache, llvm.ccache);
+            match llvm.ccache {
+                Some(StringOrBool::String(ref s)) => {
+                    config.ccache = Some(s.to_string())
+                }
+                Some(StringOrBool::Bool(true)) => {
+                    config.ccache = Some("ccache".to_string());
+                }
+                Some(StringOrBool::Bool(false)) | None => {}
+            }
             set(&mut config.ninja, llvm.ninja);
             set(&mut config.llvm_assertions, llvm.assertions);
             set(&mut config.llvm_optimize, llvm.optimize);
@@ -255,6 +286,7 @@ impl Config {
             set(&mut config.llvm_version_check, llvm.version_check);
             set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp);
         }
+
         if let Some(ref rust) = toml.rust {
             set(&mut config.rust_debug_assertions, rust.debug_assertions);
             set(&mut config.rust_debuginfo, rust.debuginfo);
@@ -338,7 +370,6 @@ impl Config {
             }
 
             check! {
-                ("CCACHE", self.ccache),
                 ("MANAGE_SUBMODULES", self.submodules),
                 ("COMPILER_DOCS", self.compiler_docs),
                 ("DOCS", self.docs),
@@ -475,10 +506,24 @@ impl Config {
                     let path = parse_configure_path(value);
                     self.python = Some(path);
                 }
+                "CFG_ENABLE_CCACHE" if value == "1" => {
+                    self.ccache = Some("ccache".to_string());
+                }
+                "CFG_ENABLE_SCCACHE" if value == "1" => {
+                    self.ccache = Some("sccache".to_string());
+                }
                 _ => {}
             }
         }
     }
+
+    pub fn verbose(&self) -> bool {
+        self.verbose > 0
+    }
+
+    pub fn very_verbose(&self) -> bool {
+        self.verbose > 1
+    }
 }
 
 #[cfg(not(windows))]
diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example
index b6774b3af20..5fc095137c7 100644
--- a/src/bootstrap/config.toml.example
+++ b/src/bootstrap/config.toml.example
@@ -25,6 +25,8 @@
 
 # Indicates whether ccache is used when building LLVM
 #ccache = false
+# or alternatively ...
+#ccache = "/path/to/ccache"
 
 # If an external LLVM root is specified, we automatically check the version by
 # default to make sure it's within the range that we're expecting, but setting
@@ -99,6 +101,14 @@
 #vendor = false
 
 # =============================================================================
+# General install configuration options
+# =============================================================================
+[install]
+
+# Instead of installing to /usr/local, install to this path instead.
+#prefix = "/path/to/install"
+
+# =============================================================================
 # Options for compiling Rust code itself
 # =============================================================================
 [rust]
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 1d3445a9eac..6e3174ed2f6 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -48,6 +48,11 @@ pub fn tmpdir(build: &Build) -> PathBuf {
 /// Slurps up documentation from the `stage`'s `host`.
 pub fn docs(build: &Build, stage: u32, host: &str) {
     println!("Dist docs stage{} ({})", stage, host);
+    if !build.config.docs {
+        println!("\tskipping - docs disabled");
+        return
+    }
+
     let name = format!("rust-docs-{}", package_vers(build));
     let image = tmpdir(build).join(format!("{}-{}-image", name, name));
     let _ = fs::remove_dir_all(&image);
@@ -92,6 +97,7 @@ pub fn mingw(build: &Build, host: &str) {
     let name = format!("rust-mingw-{}", package_vers(build));
     let image = tmpdir(build).join(format!("{}-{}-image", name, host));
     let _ = fs::remove_dir_all(&image);
+    t!(fs::create_dir_all(&image));
 
     // The first argument to the script is a "temporary directory" which is just
     // thrown away (this contains the runtime DLLs included in the rustc package
@@ -260,6 +266,14 @@ pub fn debugger_scripts(build: &Build,
 pub fn std(build: &Build, compiler: &Compiler, target: &str) {
     println!("Dist std stage{} ({} -> {})", compiler.stage, compiler.host,
              target);
+
+    // The only true set of target libraries came from the build triple, so
+    // let's reduce redundant work by only producing archives from that host.
+    if compiler.host != build.config.build {
+        println!("\tskipping, not a build host");
+        return
+    }
+
     let name = format!("rust-std-{}", package_vers(build));
     let image = tmpdir(build).join(format!("{}-{}-image", name, target));
     let _ = fs::remove_dir_all(&image);
@@ -294,10 +308,15 @@ pub fn analysis(build: &Build, compiler: &Compiler, target: &str) {
     println!("Dist analysis");
 
     if build.config.channel != "nightly" {
-        println!("Skipping dist-analysis - not on nightly channel");
+        println!("\tskipping - not on nightly channel");
         return;
     }
+    if compiler.host != build.config.build {
+        println!("\tskipping - not a build host");
+        return
+    }
     if compiler.stage != 2 {
+        println!("\tskipping - not stage2");
         return
     }
 
@@ -324,18 +343,17 @@ pub fn analysis(build: &Build, compiler: &Compiler, target: &str) {
        .arg("--legacy-manifest-dirs=rustlib,cargo");
     build.run(&mut cmd);
     t!(fs::remove_dir_all(&image));
-
-    // Create plain source tarball
-    let mut cmd = Command::new("tar");
-    cmd.arg("-czf").arg(sanitize_sh(&distdir(build).join(&format!("{}.tar.gz", name))))
-       .arg("analysis")
-       .current_dir(&src);
-    build.run(&mut cmd);
 }
 
 /// Creates the `rust-src` installer component and the plain source tarball
-pub fn rust_src(build: &Build) {
+pub fn rust_src(build: &Build, host: &str) {
     println!("Dist src");
+
+    if host != build.config.build {
+        println!("\tskipping, not a build host");
+        return
+    }
+
     let plain_name = format!("rustc-{}-src", package_vers(build));
     let name = format!("rust-src-{}", package_vers(build));
     let image = tmpdir(build).join(format!("{}-image", name));
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 7a2d56fc5d3..b2412fbb3c8 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -27,8 +27,9 @@ use step;
 
 /// Deserialized version of all flags for this compile.
 pub struct Flags {
-    pub verbose: bool,
+    pub verbose: usize, // verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
     pub stage: Option<u32>,
+    pub keep_stage: Option<u32>,
     pub build: String,
     pub host: Vec<String>,
     pub target: Vec<String>,
@@ -36,6 +37,17 @@ pub struct Flags {
     pub src: Option<PathBuf>,
     pub jobs: Option<u32>,
     pub cmd: Subcommand,
+    pub incremental: bool,
+}
+
+impl Flags {
+    pub fn verbose(&self) -> bool {
+        self.verbose > 0
+    }
+
+    pub fn very_verbose(&self) -> bool {
+        self.verbose > 1
+    }
 }
 
 pub enum Subcommand {
@@ -62,12 +74,14 @@ pub enum Subcommand {
 impl Flags {
     pub fn parse(args: &[String]) -> Flags {
         let mut opts = Options::new();
-        opts.optflag("v", "verbose", "use verbose output");
+        opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)");
+        opts.optflag("i", "incremental", "use incremental compilation");
         opts.optopt("", "config", "TOML configuration file for build", "FILE");
         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("", "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");
         opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
         opts.optflag("h", "help", "print this help message");
@@ -108,7 +122,6 @@ Arguments:
     tests that should be compiled and run. For example:
 
         ./x.py test src/test/run-pass
-        ./x.py test src/test/run-pass/assert-*
         ./x.py test src/libstd --test-args hash_map
         ./x.py test src/libstd --stage 0
 
@@ -255,9 +268,20 @@ To learn more about a subcommand, run `./x.py <command> -h`
             }
         });
 
+        let mut stage = m.opt_str("stage").map(|j| j.parse().unwrap());
+
+        let incremental = m.opt_present("i");
+
+        if incremental {
+            if stage.is_none() {
+                stage = Some(1);
+            }
+        }
+
         Flags {
-            verbose: m.opt_present("v"),
-            stage: m.opt_str("stage").map(|j| j.parse().unwrap()),
+            verbose: m.opt_count("v"),
+            stage: stage,
+            keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()),
             build: m.opt_str("build").unwrap_or_else(|| {
                 env::var("BUILD").unwrap()
             }),
@@ -267,6 +291,7 @@ To learn more about a subcommand, run `./x.py <command> -h`
             src: m.opt_str("src").map(PathBuf::from),
             jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()),
             cmd: cmd,
+            incremental: incremental,
         }
     }
 }
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index cd80c4298dc..665e0c67b7f 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -64,6 +64,8 @@
 //! More documentation can be found in each respective module below, and you can
 //! also check out the `src/bootstrap/README.md` file for more information.
 
+#![deny(warnings)]
+
 extern crate build_helper;
 extern crate cmake;
 extern crate filetime;
@@ -74,6 +76,7 @@ extern crate rustc_serialize;
 extern crate toml;
 
 use std::collections::HashMap;
+use std::cmp;
 use std::env;
 use std::ffi::OsString;
 use std::fs::{self, File};
@@ -497,6 +500,17 @@ impl Build {
         cargo.env("RUSTC_BOOTSTRAP", "1");
         self.add_rust_test_threads(&mut cargo);
 
+        // Ignore incremental modes except for stage0, since we're
+        // not guaranteeing correctness acros builds if the compiler
+        // is changing under your feet.`
+        if self.flags.incremental && compiler.stage == 0 {
+            let incr_dir = self.incremental_dir(compiler);
+            cargo.env("RUSTC_INCREMENTAL", incr_dir);
+        }
+
+        let verbose = cmp::max(self.config.verbose, self.flags.verbose);
+        cargo.env("RUSTC_VERBOSE", format!("{}", verbose));
+
         // Specify some various options for build scripts used throughout
         // the build.
         //
@@ -516,7 +530,7 @@ impl Build {
         // FIXME: should update code to not require this env var
         cargo.env("CFG_COMPILER_HOST_TRIPLE", target);
 
-        if self.config.verbose || self.flags.verbose {
+        if self.config.verbose() || self.flags.verbose() {
             cargo.arg("-v");
         }
         // FIXME: cargo bench does not accept `--release`
@@ -630,6 +644,12 @@ impl Build {
         }
     }
 
+    /// Get the directory for incremental by-products when using the
+    /// given compiler.
+    fn incremental_dir(&self, compiler: &Compiler) -> PathBuf {
+        self.out.join(compiler.host).join(format!("stage{}-incremental", compiler.stage))
+    }
+
     /// Returns the libdir where the standard library and other artifacts are
     /// found for a compiler's sysroot.
     fn sysroot_libdir(&self, compiler: &Compiler, target: &str) -> PathBuf {
@@ -703,7 +723,8 @@ impl Build {
     fn llvm_filecheck(&self, target: &str) -> PathBuf {
         let target_config = self.config.target_config.get(target);
         if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
-            s.parent().unwrap().join(exe("FileCheck", target))
+            let llvm_bindir = output(Command::new(s).arg("--bindir"));
+            Path::new(llvm_bindir.trim()).join(exe("FileCheck", target))
         } else {
             let base = self.llvm_out(&self.config.build).join("build");
             let exe = exe("FileCheck", target);
@@ -768,7 +789,7 @@ impl Build {
 
     /// Prints a message if this build is configured in verbose mode.
     fn verbose(&self, msg: &str) {
-        if self.flags.verbose || self.config.verbose {
+        if self.flags.verbose() || self.config.verbose() {
             println!("{}", msg);
         }
     }
diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in
index 1fa70081938..0d83a79cf32 100644
--- a/src/bootstrap/mk/Makefile.in
+++ b/src/bootstrap/mk/Makefile.in
@@ -56,7 +56,8 @@ check-cargotest:
 dist:
 	$(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS)
 distcheck:
-	$(Q)$(BOOTSTRAP) test distcheck
+	$(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS)
+	$(Q)$(BOOTSTRAP) test distcheck $(BOOTSTRAP_ARGS)
 install:
 	$(Q)$(BOOTSTRAP) dist --install $(BOOTSTRAP_ARGS)
 tidy:
@@ -65,7 +66,7 @@ tidy:
 check-stage2-T-arm-linux-androideabi-H-x86_64-unknown-linux-gnu:
 	$(Q)$(BOOTSTRAP) test --target arm-linux-androideabi
 check-stage2-T-x86_64-unknown-linux-musl-H-x86_64-unknown-linux-gnu:
-	$(Q)$(BOOTSTRAP) test --target x86_64-unknown-linux-gnu
+	$(Q)$(BOOTSTRAP) test --target x86_64-unknown-linux-musl
 
 
 .PHONY: dist
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index ffa3fe1cbf2..09dbd9f8220 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -81,7 +81,7 @@ pub fn llvm(build: &Build, target: &str) {
        .profile(profile)
        .define("LLVM_ENABLE_ASSERTIONS", assertions)
        .define("LLVM_TARGETS_TO_BUILD",
-               "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430")
+               "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc")
        .define("LLVM_INCLUDE_EXAMPLES", "OFF")
        .define("LLVM_INCLUDE_TESTS", "OFF")
        .define("LLVM_INCLUDE_DOCS", "OFF")
@@ -109,10 +109,10 @@ pub fn llvm(build: &Build, target: &str) {
 
     // MSVC handles compiler business itself
     if !target.contains("msvc") {
-        if build.config.ccache {
-           cfg.define("CMAKE_C_COMPILER", "ccache")
+        if let Some(ref ccache) = build.config.ccache {
+           cfg.define("CMAKE_C_COMPILER", ccache)
               .define("CMAKE_C_COMPILER_ARG1", build.cc(target))
-              .define("CMAKE_CXX_COMPILER", "ccache")
+              .define("CMAKE_CXX_COMPILER", ccache)
               .define("CMAKE_CXX_COMPILER_ARG1", build.cxx(target));
         } else {
            cfg.define("CMAKE_C_COMPILER", build.cc(target))
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs
index f3fe22698bb..5d543419fc9 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/sanity.rs
@@ -143,7 +143,7 @@ pub fn check(build: &mut Build) {
     // Externally configured LLVM requires FileCheck to exist
     let filecheck = build.llvm_filecheck(&build.config.build);
     if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
-        panic!("filecheck executable {:?} does not exist", filecheck);
+        panic!("FileCheck executable {:?} does not exist", filecheck);
     }
 
     for target in build.config.target.iter() {
@@ -223,4 +223,8 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
     if build.lldb_version.is_some() {
         build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
     }
+
+    if let Some(ref s) = build.config.ccache {
+        need_cmd(s.as_ref());
+    }
 }
diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs
index 884cc7da8ea..c5898c1119a 100644
--- a/src/bootstrap/step.rs
+++ b/src/bootstrap/step.rs
@@ -86,7 +86,7 @@ pub fn build_rules(build: &Build) -> Rules {
     //
     // To handle this we do a bit of dynamic dispatch to see what the dependency
     // is. If we're building a LLVM for the build triple, then we don't actually
-    // have any dependencies! To do that we return a dependency on the "dummy"
+    // have any dependencies! To do that we return a dependency on the `Step::noop()`
     // target which does nothing.
     //
     // If we're build a cross-compiled LLVM, however, we need to assemble the
@@ -104,7 +104,7 @@ pub fn build_rules(build: &Build) -> Rules {
          .host(true)
          .dep(move |s| {
              if s.target == build.config.build {
-                 dummy(s, build)
+                 Step::noop()
              } else {
                  s.target(&build.config.build)
              }
@@ -115,14 +115,11 @@ pub fn build_rules(build: &Build) -> Rules {
     // going on here. You can check out the API docs below and also see a bunch
     // more examples of rules directly below as well.
 
-    // dummy rule to do nothing, useful when a dep maps to no deps
-    rules.build("dummy", "path/to/nowhere");
-
     // the compiler with no target libraries ready to go
     rules.build("rustc", "src/rustc")
          .dep(move |s| {
              if s.stage == 0 {
-                 dummy(s, build)
+                 Step::noop()
              } else {
                  s.name("librustc")
                   .host(&build.config.build)
@@ -165,7 +162,7 @@ pub fn build_rules(build: &Build) -> Rules {
              .dep(move |s| s.name("rustc").host(&build.config.build).target(s.host))
              .dep(move |s| {
                  if s.host == build.config.build {
-                    dummy(s, build)
+                     Step::noop()
                  } else {
                     s.host(&build.config.build)
                  }
@@ -183,7 +180,7 @@ pub fn build_rules(build: &Build) -> Rules {
              .dep(|s| s.name("libstd"))
              .dep(move |s| {
                  if s.host == build.config.build {
-                    dummy(s, build)
+                    Step::noop()
                  } else {
                     s.host(&build.config.build)
                  }
@@ -203,7 +200,7 @@ pub fn build_rules(build: &Build) -> Rules {
              .dep(move |s| s.name("llvm").host(&build.config.build).stage(0))
              .dep(move |s| {
                  if s.host == build.config.build {
-                    dummy(s, build)
+                    Step::noop()
                  } else {
                     s.host(&build.config.build)
                  }
@@ -233,7 +230,7 @@ pub fn build_rules(build: &Build) -> Rules {
                      if s.target.contains("android") {
                          s.name("android-copy-libs")
                      } else {
-                         dummy(s, build)
+                         Step::noop()
                      }
                  })
                  .default(true)
@@ -270,16 +267,18 @@ pub fn build_rules(build: &Build) -> Rules {
         // nothing to do for debuginfo tests
     } else if build.config.build.contains("apple") {
         rules.test("check-debuginfo", "src/test/debuginfo")
+             .default(true)
              .dep(|s| s.name("libtest"))
-             .dep(|s| s.name("tool-compiletest").host(s.host))
+             .dep(|s| s.name("tool-compiletest").target(s.host))
              .dep(|s| s.name("test-helpers"))
              .dep(|s| s.name("debugger-scripts"))
              .run(move |s| check::compiletest(build, &s.compiler(), s.target,
                                          "debuginfo-lldb", "debuginfo"));
     } else {
         rules.test("check-debuginfo", "src/test/debuginfo")
+             .default(true)
              .dep(|s| s.name("libtest"))
-             .dep(|s| s.name("tool-compiletest").host(s.host))
+             .dep(|s| s.name("tool-compiletest").target(s.host))
              .dep(|s| s.name("test-helpers"))
              .dep(|s| s.name("debugger-scripts"))
              .run(move |s| check::compiletest(build, &s.compiler(), s.target,
@@ -458,7 +457,7 @@ pub fn build_rules(build: &Build) -> Rules {
     for (krate, path, default) in krates("test_shim") {
         rules.doc(&krate.doc_step, path)
              .dep(|s| s.name("libtest"))
-             .default(default && build.config.docs)
+             .default(default && build.config.compiler_docs)
              .run(move |s| doc::test(build, s.stage, s.target));
     }
     for (krate, path, default) in krates("rustc-main") {
@@ -490,16 +489,21 @@ pub fn build_rules(build: &Build) -> Rules {
          .default(true)
          .run(move |s| dist::std(build, &s.compiler(), s.target));
     rules.dist("dist-mingw", "path/to/nowhere")
-         .run(move |s| dist::mingw(build, s.target));
+         .default(true)
+         .run(move |s| {
+             if s.target.contains("pc-windows-gnu") {
+                 dist::mingw(build, s.target)
+             }
+         });
     rules.dist("dist-src", "src")
          .default(true)
          .host(true)
-         .run(move |_| dist::rust_src(build));
+         .run(move |s| dist::rust_src(build, s.target));
     rules.dist("dist-docs", "src/doc")
          .default(true)
          .dep(|s| s.name("default:doc"))
          .run(move |s| dist::docs(build, s.stage, s.target));
-    rules.dist("dist-analysis", "src/libstd")
+    rules.dist("dist-analysis", "analysis")
          .dep(|s| s.name("dist-std"))
          .default(true)
          .run(move |s| dist::analysis(build, &s.compiler(), s.target));
@@ -509,12 +513,6 @@ pub fn build_rules(build: &Build) -> Rules {
 
     rules.verify();
     return rules;
-
-    fn dummy<'a>(s: &Step<'a>, build: &'a Build) -> Step<'a> {
-        s.name("dummy").stage(0)
-         .target(&build.config.build)
-         .host(&build.config.build)
-    }
 }
 
 #[derive(PartialEq, Eq, Hash, Clone, Debug)]
@@ -538,6 +536,10 @@ struct Step<'a> {
 }
 
 impl<'a> Step<'a> {
+    fn noop() -> Step<'a> {
+        Step { name: "", stage: 0, host: "", target: "" }
+    }
+
     /// Creates a new step which is the same as this, except has a new name.
     fn name(&self, name: &'a str) -> Step<'a> {
         Step { name: name, ..*self }
@@ -733,6 +735,9 @@ impl<'a> Rules<'a> {
                 if self.rules.contains_key(&dep.name) || dep.name.starts_with("default:") {
                     continue
                 }
+                if dep == Step::noop() {
+                    continue
+                }
                 panic!("\
 
 invalid rule dependency graph detected, was a rule added and maybe typo'd?
@@ -817,7 +822,16 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
             let hosts = if self.build.flags.host.len() > 0 {
                 &self.build.flags.host
             } else {
-                &self.build.config.host
+                if kind == Kind::Dist {
+                    // For 'dist' steps we only distribute artifacts built from
+                    // the build platform, so only consider that in the hosts
+                    // array.
+                    // NOTE: This relies on the fact that the build triple is
+                    // always placed first, as done in `config.rs`.
+                    &self.build.config.host[..1]
+                } else {
+                    &self.build.config.host
+                }
             };
             let targets = if self.build.flags.target.len() > 0 {
                 &self.build.flags.target
@@ -859,6 +873,7 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
         // of what we need to do.
         let mut order = Vec::new();
         let mut added = HashSet::new();
+        added.insert(Step::noop());
         for step in steps.iter().cloned() {
             self.fill(step, &mut order, &mut added);
         }
@@ -871,6 +886,10 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
 
         // And finally, iterate over everything and execute it.
         for step in order.iter() {
+            if self.build.flags.keep_stage.map_or(false, |s| step.stage <= s) {
+                self.build.verbose(&format!("keeping step {:?}", step));
+                continue;
+            }
             self.build.verbose(&format!("executing step {:?}", step));
             (self.rules[step.name].run)(step);
         }
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index cb5b456a0f2..c9e756b6f99 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -41,6 +41,12 @@ pub fn mtime(path: &Path) -> FileTime {
 /// Copies a file from `src` to `dst`, attempting to use hard links and then
 /// falling back to an actually filesystem copy if necessary.
 pub fn copy(src: &Path, dst: &Path) {
+    // A call to `hard_link` will fail if `dst` exists, so remove it if it
+    // already exists so we can try to help `hard_link` succeed.
+    let _ = fs::remove_file(&dst);
+
+    // Attempt to "easy copy" by creating a hard link (symlinks don't work on
+    // windows), but if that fails just fall back to a slow `copy` operation.
     let res = fs::hard_link(src, dst);
     let res = res.or_else(|_| fs::copy(src, dst).map(|_| ()));
     if let Err(e) = res {
diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs
index 07f9c91d3c7..d0d588f46a7 100644
--- a/src/build_helper/lib.rs
+++ b/src/build_helper/lib.rs
@@ -47,6 +47,8 @@ pub fn cc2ar(cc: &Path, target: &str) -> Option<PathBuf> {
         None
     } else if target.contains("musl") {
         Some(PathBuf::from("ar"))
+    } else if target.contains("openbsd") {
+        Some(PathBuf::from("ar"))
     } else {
         let parent = cc.parent().unwrap();
         let file = cc.file_name().unwrap().to_str().unwrap();
@@ -61,6 +63,16 @@ pub fn cc2ar(cc: &Path, target: &str) -> Option<PathBuf> {
     }
 }
 
+pub fn make(host: &str) -> PathBuf {
+    if host.contains("bitrig") || host.contains("dragonfly") ||
+        host.contains("freebsd") || host.contains("netbsd") ||
+        host.contains("openbsd") {
+        PathBuf::from("gmake")
+    } else {
+        PathBuf::from("make")
+    }
+}
+
 pub fn output(cmd: &mut Command) -> String {
     let output = match cmd.stderr(Stdio::inherit()).output() {
         Ok(status) => status,
diff --git a/src/ci/docker/arm-android/Dockerfile b/src/ci/docker/arm-android/Dockerfile
index 121c0263cbc..8911b4ff0cb 100644
--- a/src/ci/docker/arm-android/Dockerfile
+++ b/src/ci/docker/arm-android/Dockerfile
@@ -16,7 +16,8 @@ RUN dpkg --add-architecture i386 && \
   expect \
   openjdk-9-jre \
   sudo \
-  libstdc++6:i386
+  libstdc++6:i386 \
+  xz-utils
 
 WORKDIR /android/
 ENV PATH=$PATH:/android/ndk-arm-9/bin:/android/sdk/tools:/android/sdk/platform-tools
@@ -25,8 +26,17 @@ 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 ["/android/start-emulator.sh"]
+
+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
 
 ENV TARGETS=arm-linux-androideabi
 ENV TARGETS=$TARGETS,i686-linux-android
diff --git a/src/ci/docker/cross/Dockerfile b/src/ci/docker/cross/Dockerfile
index b7b23d74c9d..08b436313f6 100644
--- a/src/ci/docker/cross/Dockerfile
+++ b/src/ci/docker/cross/Dockerfile
@@ -21,7 +21,17 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \
   gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \
   gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \
-  gcc-s390x-linux-gnu libc6-dev-s390x-cross
+  gcc-s390x-linux-gnu libc6-dev-s390x-cross \
+  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 -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", "--"]
 
 ENV TARGETS=aarch64-unknown-linux-gnu
 ENV TARGETS=$TARGETS,arm-unknown-linux-gnueabi
diff --git a/src/ci/docker/i686-gnu-nopt/Dockerfile b/src/ci/docker/i686-gnu-nopt/Dockerfile
index a9ef29daaf1..1da33c94c7b 100644
--- a/src/ci/docker/i686-gnu-nopt/Dockerfile
+++ b/src/ci/docker/i686-gnu-nopt/Dockerfile
@@ -11,7 +11,17 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   cmake \
   ccache \
   sudo \
-  gdb
+  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 -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", "--"]
 
 ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests
 ENV RUST_CHECK_TARGET check
diff --git a/src/ci/docker/i686-gnu/Dockerfile b/src/ci/docker/i686-gnu/Dockerfile
index d0ddde95b44..9e5b0e0435e 100644
--- a/src/ci/docker/i686-gnu/Dockerfile
+++ b/src/ci/docker/i686-gnu/Dockerfile
@@ -11,7 +11,17 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   cmake \
   ccache \
   sudo \
-  gdb
+  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 -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", "--"]
 
 ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu
 ENV RUST_CHECK_TARGET check
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index ff5345d3aac..8c2c8d2a9db 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -25,18 +25,26 @@ docker \
   -t rust-ci \
   "`dirname "$script"`/$image"
 
-mkdir -p $HOME/.ccache
 mkdir -p $HOME/.cargo
 mkdir -p $root_dir/obj
 
+args=
+if [ "$SCCACHE_BUCKET" != "" ]; then
+    args="$args --env SCCACHE_BUCKET=$SCCACHE_BUCKET"
+    args="$args --env AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID"
+    args="$args --env AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY"
+else
+    mkdir -p $HOME/.cache/sccache
+    args="$args --env SCCACHE_DIR=/sccache --volume $HOME/.cache/sccache:/sccache"
+fi
+
 exec docker \
   run \
   --volume "$root_dir:/checkout:ro" \
   --volume "$root_dir/obj:/checkout/obj" \
   --workdir /checkout/obj \
   --env SRC=/checkout \
-  --env CCACHE_DIR=/ccache \
-  --volume "$HOME/.ccache:/ccache" \
+  $args \
   --env CARGO_HOME=/cargo \
   --env LOCAL_USER_ID=`id -u` \
   --volume "$HOME/.cargo:/cargo" \
diff --git a/src/ci/docker/x86_64-freebsd/Dockerfile b/src/ci/docker/x86_64-freebsd/Dockerfile
index a3a52f9e6ff..75f3174e2c0 100644
--- a/src/ci/docker/x86_64-freebsd/Dockerfile
+++ b/src/ci/docker/x86_64-freebsd/Dockerfile
@@ -18,6 +18,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 COPY build-toolchain.sh /tmp/
 RUN sh /tmp/build-toolchain.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", "--"]
+
+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
+
 ENV \
     AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \
     CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc
diff --git a/src/ci/docker/x86_64-gnu-cargotest/Dockerfile b/src/ci/docker/x86_64-gnu-cargotest/Dockerfile
index 107e2bf8a12..2c3db87d9fb 100644
--- a/src/ci/docker/x86_64-gnu-cargotest/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-cargotest/Dockerfile
@@ -11,7 +11,18 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   cmake \
   ccache \
   libssl-dev \
-  sudo
+  sudo \
+  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 -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", "--"]
 
 ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
 ENV RUST_CHECK_TARGET check-cargotest
diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile
index 9e98215775e..eec88442293 100644
--- a/src/ci/docker/x86_64-gnu-debug/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile
@@ -11,7 +11,17 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   cmake \
   ccache \
   sudo \
-  gdb
+  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 -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", "--"]
 
 ENV RUST_CONFIGURE_ARGS \
       --build=x86_64-unknown-linux-gnu \
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 c27e3d1325f..4c9198d88eb 100644
--- a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile
@@ -14,7 +14,17 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   llvm-3.7-tools \
   libedit-dev \
-  zlib1g-dev
+  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 -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", "--"]
 
 ENV RUST_CONFIGURE_ARGS \
       --build=x86_64-unknown-linux-gnu \
diff --git a/src/ci/docker/x86_64-gnu-make/Dockerfile b/src/ci/docker/x86_64-gnu-make/Dockerfile
index 93229b2a010..1c503aea13d 100644
--- a/src/ci/docker/x86_64-gnu-make/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-make/Dockerfile
@@ -11,7 +11,17 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   cmake \
   ccache \
   sudo \
-  gdb
+  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 -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", "--"]
 
 ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --disable-rustbuild
 ENV RUST_CHECK_TARGET check
diff --git a/src/ci/docker/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/x86_64-gnu-nopt/Dockerfile
index 73a3e2c726c..66de6ea13ac 100644
--- a/src/ci/docker/x86_64-gnu-nopt/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-nopt/Dockerfile
@@ -11,7 +11,17 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   cmake \
   ccache \
   sudo \
-  gdb
+  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 -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", "--"]
 
 ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --disable-optimize-tests
 ENV RUST_CHECK_TARGET check
diff --git a/src/ci/docker/x86_64-gnu/Dockerfile b/src/ci/docker/x86_64-gnu/Dockerfile
index f125693e7ae..3d71b7ffb9a 100644
--- a/src/ci/docker/x86_64-gnu/Dockerfile
+++ b/src/ci/docker/x86_64-gnu/Dockerfile
@@ -11,7 +11,17 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   cmake \
   ccache \
   sudo \
-  gdb
+  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 -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", "--"]
 
 ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
 ENV RUST_CHECK_TARGET check
diff --git a/src/ci/docker/x86_64-musl/Dockerfile b/src/ci/docker/x86_64-musl/Dockerfile
index 967940fb1f3..96b38067cbb 100644
--- a/src/ci/docker/x86_64-musl/Dockerfile
+++ b/src/ci/docker/x86_64-musl/Dockerfile
@@ -18,6 +18,15 @@ WORKDIR /build/
 COPY build-musl.sh /build/
 RUN sh /build/build-musl.sh && rm -rf /build
 
+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", "--"]
+
+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
+
 ENV RUST_CONFIGURE_ARGS \
       --target=x86_64-unknown-linux-musl \
       --musl-root-x86_64=/musl-x86_64
diff --git a/src/ci/run.sh b/src/ci/run.sh
index 10f2d15da34..152694346aa 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -26,17 +26,13 @@ if [ "$NO_VENDOR" = "" ]; then
   ENABLE_VENDOR=--enable-vendor
 fi
 
-if [ "$NO_CCACHE" = "" ]; then
-  ENABLE_CCACHE=--enable-ccache
-fi
-
 set -ex
 
 $SRC/configure \
   --disable-manage-submodules \
   --enable-debug-assertions \
   --enable-quiet-tests \
-  $ENABLE_CCACHE \
+  --enable-sccache \
   $ENABLE_VENDOR \
   $ENABLE_LLVM_ASSERTIONS \
   $RUST_CONFIGURE_ARGS
diff --git a/src/doc/book/casting-between-types.md b/src/doc/book/casting-between-types.md
index 296384ab6ef..a8f8224c58b 100644
--- a/src/doc/book/casting-between-types.md
+++ b/src/doc/book/casting-between-types.md
@@ -16,18 +16,18 @@ function result.
 
 The most common case of coercion is removing mutability from a reference:
 
- * `&mut T` to `&T`
+* `&mut T` to `&T`
 
 An analogous conversion is to remove mutability from a
 [raw pointer](raw-pointers.md):
 
- * `*mut T` to `*const T`
+* `*mut T` to `*const T`
 
 References can also be coerced to raw pointers:
 
- * `&T` to `*const T`
+* `&T` to `*const T`
 
- * `&mut T` to `*mut T`
+* `&mut T` to `*mut T`
 
 Custom coercions may be defined using [`Deref`](deref-coercions.md).
 
@@ -59,11 +59,11 @@ A cast `e as U` is valid if `e` has type `T` and `T` *coerces* to `U`.
 
 A cast `e as U` is also valid in any of the following cases:
 
- * `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast*
- * `e` is a C-like enum (with no data attached to the variants),
-    and `U` is an integer type; *enum-cast*
- * `e` has type `bool` or `char` and `U` is an integer type; *prim-int-cast*
- * `e` has type `u8` and `U` is `char`; *u8-char-cast*
+* `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast*
+* `e` is a C-like enum (with no data attached to the variants),
+   and `U` is an integer type; *enum-cast*
+* `e` has type `bool` or `char` and `U` is an integer type; *prim-int-cast*
+* `e` has type `u8` and `U` is `char`; *u8-char-cast*
 
 For example
 
diff --git a/src/doc/book/documentation.md b/src/doc/book/documentation.md
index f30a95b4e78..dafcffc39c8 100644
--- a/src/doc/book/documentation.md
+++ b/src/doc/book/documentation.md
@@ -460,8 +460,9 @@ not actually pass as a test.
 ```
 
 The `no_run` attribute will compile your code, but not run it. This is
-important for examples such as "Here's how to start up a network service,"
-which you would want to make sure compile, but might run in an infinite loop!
+important for examples such as "Here's how to retrieve a web page,"
+which you would want to ensure compiles, but might be run in a test
+environment that has no network access.
 
 ### Documenting modules
 
diff --git a/src/doc/book/getting-started.md b/src/doc/book/getting-started.md
index 2eab449dbd4..5aae693ad6b 100644
--- a/src/doc/book/getting-started.md
+++ b/src/doc/book/getting-started.md
@@ -24,41 +24,40 @@ see the website][platform-support].
 
 [platform-support]: https://forge.rust-lang.org/platform-support.html
 
-## Installing on Linux or Mac
+## Installing Rust
 
-If we're on Linux or a Mac, all we need to do is open a terminal and type this:
+All you need to do on Unix systems like Linux and macOS is open a
+terminal and type this:
 
 ```bash
-$ curl -sSf https://static.rust-lang.org/rustup.sh | sh
+$ curl https://sh.rustup.rs -sSf | sh
 ```
 
-This will download a script, and start the installation. If it all goes well,
-you’ll see this appear:
+It will download a script, and start the installation. If everything
+goes well, you’ll see this appear:
 
 ```text
-Rust is ready to roll.
+Rust is installed now. Great! 
 ```
 
-From here, press `y` for ‘yes’, and then follow the rest of the prompts.
+Installing on Windows is nearly as easy: download and run
+[rustup-init.exe]. It will start the installation in a console and
+present the above message on success.
 
-## Installing on Windows
+For other installation options and information, visit the [install]
+page of the Rust website.
 
-If you're on Windows, please download the appropriate [installer][install-page].
-
-[install-page]: https://www.rust-lang.org/install.html
+[rustup-init.exe]: https://win.rustup.rs
+[install]: https://www.rust-lang.org/install.html
 
 ## Uninstalling
 
-Uninstalling Rust is as easy as installing it. On Linux or Mac, run
-the uninstall script:
+Uninstalling Rust is as easy as installing it:
 
 ```bash
-$ sudo /usr/local/lib/rustlib/uninstall.sh
+$ rustup self uninstall
 ```
 
-If we used the Windows installer, we can re-run the `.msi` and it will give us
-an uninstall option.
-
 ## Troubleshooting
 
 If we've got Rust installed, we can open up a shell, and type this:
@@ -71,12 +70,15 @@ You should see the version number, commit hash, and commit date.
 
 If you do, Rust has been installed successfully! Congrats!
 
-If you don't and you're on Windows, check that Rust is in your %PATH% system
-variable: `$ echo %PATH%`. If it isn't, run the installer again, select "Change"
-on the "Change, repair, or remove installation" page and ensure "Add to PATH" is
-installed on the local hard drive.  If you need to configure your path manually,
-you can find the Rust executables in a directory like
-`"C:\Program Files\Rust stable GNU 1.x\bin"`.
+If you don't, that probably means that the `PATH` environment variable
+doesn't include Cargo's binary directory, `~/.cargo/bin` on Unix, or
+`%USERPROFILE%\.cargo\bin` on Windows. This is the directory where
+Rust development tools live, and most Rust developers keep it in their
+`PATH` environment variable, which makes it possible to run `rustc` on
+the command line. Due to differences in operating systems, command
+shells, and bugs in installation, you may need to restart your shell,
+log out of the system, or configure `PATH` manually as appropriate for
+your operating environment.
 
 Rust does not do its own linking, and so you’ll need to have a linker
 installed. Doing so will depend on your specific system. For
@@ -106,9 +108,7 @@ resources include [the user’s forum][users] and [Stack Overflow][stackoverflow
 [stackoverflow]: http://stackoverflow.com/questions/tagged/rust
 
 This installer also installs a copy of the documentation locally, so we 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 the directory to which Rust
-was installed.
+read it offline. It's only a `rustup doc` away!
 
 # Hello, world!
 
diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md
index ebeb9923197..96cec7295aa 100644
--- a/src/doc/book/testing.md
+++ b/src/doc/book/testing.md
@@ -589,11 +589,10 @@ please see the [Documentation chapter](documentation.html).
 
 # Testing and concurrency
 
-One thing that is important to note when writing tests is that they may be run
-concurrently using threads. For this reason you should take care that your tests
-are written in such a way as to not depend on each-other, or on any shared
-state. "Shared state" can also include the environment, such as the current
-working directory, or environment variables.
+It is important to note that tests are run concurrently using threads. For this
+reason, care should be taken to ensure your tests do not depend on each-other,
+or on any shared state. "Shared state" can also include the environment, such
+as the current working directory, or environment variables.
 
 If this is an issue it is possible to control this concurrency, either by
 setting the environment variable `RUST_TEST_THREADS`, or by passing the argument
diff --git a/src/doc/reference.md b/src/doc/reference.md
index bf286aaec4b..b5a91a170d8 100644
--- a/src/doc/reference.md
+++ b/src/doc/reference.md
@@ -1731,7 +1731,8 @@ of an item to see whether it should be allowed or not. This is where privacy
 warnings are generated, or otherwise "you used a private item of another module
 and weren't allowed to."
 
-By default, everything in Rust is *private*, with one exception. Enum variants
+By default, everything in Rust is *private*, with two exceptions: Associated
+items in a `pub` Trait are public by default; Enum variants
 in a `pub` enum are also public by default. When an item is declared as `pub`,
 it can be thought of as being accessible to the outside world. For example:
 
diff --git a/src/doc/rust.css b/src/doc/rust.css
index 932594b9912..664bc0fdab0 100644
--- a/src/doc/rust.css
+++ b/src/doc/rust.css
@@ -44,7 +44,9 @@
     font-family: 'Source Code Pro';
     font-style: normal;
     font-weight: 400;
-    src: local('Source Code Pro'), url("SourceCodePro-Regular.woff") format('woff');
+    /* Avoid using locally installed font because bad versions are in circulation:
+     * see https://github.com/rust-lang/rust/issues/24355 */
+    src: url("SourceCodePro-Regular.woff") format('woff');
 }
 
 *:not(body) {
diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs
index 3a7da18c8de..1cad8f7f407 100644
--- a/src/liballoc/arc.rs
+++ b/src/liballoc/arc.rs
@@ -392,8 +392,6 @@ impl<T: ?Sized> Arc<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(arc_counts)]
-    ///
     /// use std::sync::Arc;
     ///
     /// let five = Arc::new(5);
@@ -404,8 +402,7 @@ impl<T: ?Sized> Arc<T> {
     /// assert_eq!(1, Arc::weak_count(&five));
     /// ```
     #[inline]
-    #[unstable(feature = "arc_counts", reason = "not clearly useful, and racy",
-               issue = "28356")]
+    #[stable(feature = "arc_counts", since = "1.15.0")]
     pub fn weak_count(this: &Self) -> usize {
         this.inner().weak.load(SeqCst) - 1
     }
@@ -421,8 +418,6 @@ impl<T: ?Sized> Arc<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(arc_counts)]
-    ///
     /// use std::sync::Arc;
     ///
     /// let five = Arc::new(5);
@@ -433,8 +428,7 @@ impl<T: ?Sized> Arc<T> {
     /// assert_eq!(2, Arc::strong_count(&five));
     /// ```
     #[inline]
-    #[unstable(feature = "arc_counts", reason = "not clearly useful, and racy",
-               issue = "28356")]
+    #[stable(feature = "arc_counts", since = "1.15.0")]
     pub fn strong_count(this: &Self) -> usize {
         this.inner().strong.load(SeqCst)
     }
diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs
index 12809171b74..81ed4be7763 100644
--- a/src/liballoc/heap.rs
+++ b/src/liballoc/heap.rs
@@ -127,6 +127,7 @@ pub fn usable_size(size: usize, align: usize) -> usize {
 pub const EMPTY: *mut () = 0x1 as *mut ();
 
 /// The allocator for unique pointers.
+// This function must not unwind. If it does, MIR trans will fail.
 #[cfg(not(test))]
 #[lang = "exchange_malloc"]
 #[inline]
@@ -143,6 +144,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
 }
 
 #[cfg(not(test))]
+#[cfg(stage0)]
 #[lang = "exchange_free"]
 #[inline]
 unsafe fn exchange_free(ptr: *mut u8, old_size: usize, align: usize) {
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index d1e0e333b8f..86f8c746646 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -320,7 +320,7 @@ impl<T> Rc<T> {
     #[inline]
     #[stable(feature = "rc_unique", since = "1.4.0")]
     pub fn try_unwrap(this: Self) -> Result<T, Self> {
-        if Rc::would_unwrap(&this) {
+        if Rc::strong_count(&this) == 1 {
             unsafe {
                 let val = ptr::read(&*this); // copy the contained object
 
@@ -343,26 +343,10 @@ impl<T> Rc<T> {
     ///
     /// [try_unwrap]: struct.Rc.html#method.try_unwrap
     /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(rc_would_unwrap)]
-    ///
-    /// use std::rc::Rc;
-    ///
-    /// let x = Rc::new(3);
-    /// assert!(Rc::would_unwrap(&x));
-    /// assert_eq!(Rc::try_unwrap(x), Ok(3));
-    ///
-    /// let x = Rc::new(4);
-    /// let _y = x.clone();
-    /// assert!(!Rc::would_unwrap(&x));
-    /// assert_eq!(*Rc::try_unwrap(x).unwrap_err(), 4);
-    /// ```
     #[unstable(feature = "rc_would_unwrap",
                reason = "just added for niche usecase",
                issue = "28356")]
+    #[rustc_deprecated(since = "1.15.0", reason = "too niche; use `strong_count` instead")]
     pub fn would_unwrap(this: &Self) -> bool {
         Rc::strong_count(&this) == 1
     }
@@ -482,8 +466,6 @@ impl<T: ?Sized> Rc<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(rc_counts)]
-    ///
     /// use std::rc::Rc;
     ///
     /// let five = Rc::new(5);
@@ -492,8 +474,7 @@ impl<T: ?Sized> Rc<T> {
     /// assert_eq!(1, Rc::weak_count(&five));
     /// ```
     #[inline]
-    #[unstable(feature = "rc_counts", reason = "not clearly useful",
-               issue = "28356")]
+    #[stable(feature = "rc_counts", since = "1.15.0")]
     pub fn weak_count(this: &Self) -> usize {
         this.weak() - 1
     }
@@ -503,8 +484,6 @@ impl<T: ?Sized> Rc<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(rc_counts)]
-    ///
     /// use std::rc::Rc;
     ///
     /// let five = Rc::new(5);
@@ -513,8 +492,7 @@ impl<T: ?Sized> Rc<T> {
     /// assert_eq!(2, Rc::strong_count(&five));
     /// ```
     #[inline]
-    #[unstable(feature = "rc_counts", reason = "not clearly useful",
-               issue = "28356")]
+    #[stable(feature = "rc_counts", since = "1.15.0")]
     pub fn strong_count(this: &Self) -> usize {
         this.strong()
     }
@@ -523,21 +501,11 @@ impl<T: ?Sized> Rc<T> {
     /// this inner value.
     ///
     /// [weak]: struct.Weak.html
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(rc_counts)]
-    ///
-    /// use std::rc::Rc;
-    ///
-    /// let five = Rc::new(5);
-    ///
-    /// assert!(Rc::is_unique(&five));
-    /// ```
     #[inline]
-    #[unstable(feature = "rc_counts", reason = "uniqueness has unclear meaning",
+    #[unstable(feature = "is_unique", reason = "uniqueness has unclear meaning",
                issue = "28356")]
+    #[rustc_deprecated(since = "1.15.0",
+                       reason = "too niche; use `strong_count` and `weak_count` instead")]
     pub fn is_unique(this: &Self) -> bool {
         Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1
     }
diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs
index fc849e7a50c..2bbec9e5fc2 100644
--- a/src/liballoc_jemalloc/build.rs
+++ b/src/liballoc_jemalloc/build.rs
@@ -36,7 +36,8 @@ fn main() {
     // targets, which means we have to build the alloc_jemalloc crate
     // for targets like emscripten, even if we don't use it.
     if target.contains("rumprun") || target.contains("bitrig") || target.contains("openbsd") ||
-       target.contains("msvc") || target.contains("emscripten") || target.contains("fuchsia") {
+       target.contains("msvc") || target.contains("emscripten") || target.contains("fuchsia") ||
+       target.contains("redox") {
         println!("cargo:rustc-cfg=dummy_jemalloc");
         return;
     }
@@ -151,7 +152,7 @@ fn main() {
     cmd.arg(format!("--build={}", build_helper::gnu_target(&host)));
 
     run(&mut cmd);
-    let mut make = Command::new("make");
+    let mut make = Command::new(build_helper::make(&host));
     make.current_dir(&build_dir)
         .arg("build_lib_static");
 
diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs
index a4fabb5a2c9..4daa6cbb846 100644
--- a/src/liballoc_system/lib.rs
+++ b/src/liballoc_system/lib.rs
@@ -19,7 +19,7 @@
             issue = "27783")]
 #![feature(allocator)]
 #![feature(staged_api)]
-#![cfg_attr(unix, feature(libc))]
+#![cfg_attr(any(unix, target_os = "redox"), feature(libc))]
 
 // The minimum alignment guaranteed by the architecture. This value is used to
 // add fast paths for low alignment values. In practice, the alignment is a
@@ -71,7 +71,7 @@ pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
     imp::usable_size(size, align)
 }
 
-#[cfg(unix)]
+#[cfg(any(unix, target_os = "redox"))]
 mod imp {
     extern crate libc;
 
@@ -87,7 +87,7 @@ mod imp {
         }
     }
 
-    #[cfg(target_os = "android")]
+    #[cfg(any(target_os = "android", target_os = "redox"))]
     unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
         // On android we currently target API level 9 which unfortunately
         // doesn't have the `posix_memalign` API used below. Instead we use
@@ -109,7 +109,7 @@ mod imp {
         libc::memalign(align as libc::size_t, size as libc::size_t) as *mut u8
     }
 
-    #[cfg(not(target_os = "android"))]
+    #[cfg(not(any(target_os = "android", target_os = "redox")))]
     unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
         let mut out = ptr::null_mut();
         let ret = libc::posix_memalign(&mut out, align as libc::size_t, size as libc::size_t);
diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs
index 8d0c76c3646..c5d5ad27d23 100644
--- a/src/libcollections/binary_heap.rs
+++ b/src/libcollections/binary_heap.rs
@@ -225,7 +225,7 @@ pub struct BinaryHeap<T> {
 /// [`peek_mut()`]: struct.BinaryHeap.html#method.peek_mut
 #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
 pub struct PeekMut<'a, T: 'a + Ord> {
-    heap: &'a mut BinaryHeap<T>
+    heap: &'a mut BinaryHeap<T>,
 }
 
 #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
@@ -385,9 +385,7 @@ impl<T: Ord> BinaryHeap<T> {
         if self.is_empty() {
             None
         } else {
-            Some(PeekMut {
-                heap: self
-            })
+            Some(PeekMut { heap: self })
         }
     }
 
@@ -1126,7 +1124,9 @@ impl<T: Ord> IntoIterator for BinaryHeap<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> IntoIterator for &'a BinaryHeap<T> where T: Ord {
+impl<'a, T> IntoIterator for &'a BinaryHeap<T>
+    where T: Ord
+{
     type Item = &'a T;
     type IntoIter = Iter<'a, T>;
 
diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs
index 37618b7600a..e5bcf0d8e81 100644
--- a/src/libcollections/borrow.rs
+++ b/src/libcollections/borrow.rs
@@ -63,7 +63,9 @@ pub trait ToOwned {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T> ToOwned for T where T: Clone {
+impl<T> ToOwned for T
+    where T: Clone
+{
     type Owned = T;
     fn to_owned(&self) -> T {
         self.clone()
@@ -117,17 +119,19 @@ pub enum Cow<'a, B: ?Sized + 'a>
 {
     /// Borrowed data.
     #[stable(feature = "rust1", since = "1.0.0")]
-    Borrowed(#[stable(feature = "rust1", since = "1.0.0")] &'a B),
+    Borrowed(#[stable(feature = "rust1", since = "1.0.0")]
+             &'a B),
 
     /// Owned data.
     #[stable(feature = "rust1", since = "1.0.0")]
-    Owned(
-        #[stable(feature = "rust1", since = "1.0.0")] <B as ToOwned>::Owned
-    ),
+    Owned(#[stable(feature = "rust1", since = "1.0.0")]
+          <B as ToOwned>::Owned),
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, B: ?Sized> Clone for Cow<'a, B> where B: ToOwned {
+impl<'a, B: ?Sized> Clone for Cow<'a, B>
+    where B: ToOwned
+{
     fn clone(&self) -> Cow<'a, B> {
         match *self {
             Borrowed(b) => Borrowed(b),
@@ -139,7 +143,9 @@ impl<'a, B: ?Sized> Clone for Cow<'a, B> where B: ToOwned {
     }
 }
 
-impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned {
+impl<'a, B: ?Sized> Cow<'a, B>
+    where B: ToOwned
+{
     /// Acquires a mutable reference to the owned form of the data.
     ///
     /// Clones the data if it is not already owned.
@@ -194,7 +200,9 @@ impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, B: ?Sized> Deref for Cow<'a, B> where B: ToOwned {
+impl<'a, B: ?Sized> Deref for Cow<'a, B>
+    where B: ToOwned
+{
     type Target = B;
 
     fn deref(&self) -> &B {
@@ -209,7 +217,9 @@ impl<'a, B: ?Sized> Deref for Cow<'a, B> where B: ToOwned {
 impl<'a, B: ?Sized> Eq for Cow<'a, B> where B: Eq + ToOwned {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, B: ?Sized> Ord for Cow<'a, B> where B: Ord + ToOwned {
+impl<'a, B: ?Sized> Ord for Cow<'a, B>
+    where B: Ord + ToOwned
+{
     #[inline]
     fn cmp(&self, other: &Cow<'a, B>) -> Ordering {
         Ord::cmp(&**self, &**other)
@@ -228,7 +238,9 @@ impl<'a, 'b, B: ?Sized, C: ?Sized> PartialEq<Cow<'b, C>> for Cow<'a, B>
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, B: ?Sized> PartialOrd for Cow<'a, B> where B: PartialOrd + ToOwned {
+impl<'a, B: ?Sized> PartialOrd for Cow<'a, B>
+    where B: PartialOrd + ToOwned
+{
     #[inline]
     fn partial_cmp(&self, other: &Cow<'a, B>) -> Option<Ordering> {
         PartialOrd::partial_cmp(&**self, &**other)
@@ -273,7 +285,9 @@ impl<'a, B: ?Sized> Default for Cow<'a, B>
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, B: ?Sized> Hash for Cow<'a, B> where B: Hash + ToOwned {
+impl<'a, B: ?Sized> Hash for Cow<'a, B>
+    where B: Hash + ToOwned
+{
     #[inline]
     fn hash<H: Hasher>(&self, state: &mut H) {
         Hash::hash(&**self, state)
diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs
index c57266d9e3b..34674e3a0bd 100644
--- a/src/libcollections/btree/set.rs
+++ b/src/libcollections/btree/set.rs
@@ -74,24 +74,44 @@ pub struct BTreeSet<T> {
     map: BTreeMap<T, ()>,
 }
 
-/// An iterator over a BTreeSet's items.
+/// An iterator over a `BTreeSet`'s items.
+///
+/// This structure is created by the [`iter`] method on [`BTreeSet`].
+///
+/// [`BTreeSet`]: struct.BTreeSet.html
+/// [`iter`]: struct.BTreeSet.html#method.iter
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, T: 'a> {
     iter: Keys<'a, T, ()>,
 }
 
-/// An owning iterator over a BTreeSet's items.
+/// An owning iterator over a `BTreeSet`'s items.
+///
+/// This structure is created by the `into_iter` method on [`BTreeSet`]
+/// [`BTreeSet`] (provided by the `IntoIterator` trait).
+///
+/// [`BTreeSet`]: struct.BTreeSet.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IntoIter<T> {
     iter: ::btree_map::IntoIter<T, ()>,
 }
 
-/// An iterator over a sub-range of BTreeSet's items.
+/// An iterator over a sub-range of `BTreeSet`'s items.
+///
+/// This structure is created by the [`range`] method on [`BTreeSet`].
+///
+/// [`BTreeSet`]: struct.BTreeSet.html
+/// [`range`]: struct.BTreeSet.html#method.range
 pub struct Range<'a, T: 'a> {
     iter: ::btree_map::Range<'a, T, ()>,
 }
 
 /// A lazy iterator producing elements in the set difference (in-order).
+///
+/// This structure is created by the [`difference`] method on [`BTreeSet`].
+///
+/// [`BTreeSet`]: struct.BTreeSet.html
+/// [`difference`]: struct.BTreeSet.html#method.difference
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Difference<'a, T: 'a> {
     a: Peekable<Iter<'a, T>>,
@@ -99,6 +119,12 @@ pub struct Difference<'a, T: 'a> {
 }
 
 /// A lazy iterator producing elements in the set symmetric difference (in-order).
+///
+/// This structure is created by the [`symmetric_difference`] method on
+/// [`BTreeSet`].
+///
+/// [`BTreeSet`]: struct.BTreeSet.html
+/// [`symmetric_difference`]: struct.BTreeSet.html#method.symmetric_difference
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct SymmetricDifference<'a, T: 'a> {
     a: Peekable<Iter<'a, T>>,
@@ -106,6 +132,11 @@ pub struct SymmetricDifference<'a, T: 'a> {
 }
 
 /// A lazy iterator producing elements in the set intersection (in-order).
+///
+/// This structure is created by the [`intersection`] method on [`BTreeSet`].
+///
+/// [`BTreeSet`]: struct.BTreeSet.html
+/// [`intersection`]: struct.BTreeSet.html#method.intersection
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Intersection<'a, T: 'a> {
     a: Peekable<Iter<'a, T>>,
@@ -113,6 +144,11 @@ pub struct Intersection<'a, T: 'a> {
 }
 
 /// A lazy iterator producing elements in the set union (in-order).
+///
+/// This structure is created by the [`union`] method on [`BTreeSet`].
+///
+/// [`BTreeSet`]: struct.BTreeSet.html
+/// [`union`]: struct.BTreeSet.html#method.union
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Union<'a, T: 'a> {
     a: Peekable<Iter<'a, T>>,
@@ -120,7 +156,7 @@ pub struct Union<'a, T: 'a> {
 }
 
 impl<T: Ord> BTreeSet<T> {
-    /// Makes a new BTreeSet with a reasonable choice of B.
+    /// Makes a new `BTreeSet` with a reasonable choice of B.
     ///
     /// # Examples
     ///
@@ -137,21 +173,32 @@ impl<T: Ord> BTreeSet<T> {
 }
 
 impl<T> BTreeSet<T> {
-    /// Gets an iterator over the BTreeSet's contents.
+    /// Gets an iterator that visits the values in the `BTreeSet` in ascending order.
     ///
     /// # Examples
     ///
     /// ```
     /// use std::collections::BTreeSet;
     ///
-    /// let set: BTreeSet<usize> = [1, 2, 3, 4].iter().cloned().collect();
+    /// let set: BTreeSet<usize> = [1, 2, 3].iter().cloned().collect();
+    /// let mut set_iter = set.iter();
+    /// assert_eq!(set_iter.next(), Some(&1));
+    /// assert_eq!(set_iter.next(), Some(&2));
+    /// assert_eq!(set_iter.next(), Some(&3));
+    /// assert_eq!(set_iter.next(), None);
+    /// ```
     ///
-    /// for x in set.iter() {
-    ///     println!("{}", x);
-    /// }
+    /// Values returned by the iterator are returned in ascending order:
     ///
-    /// let v: Vec<_> = set.iter().cloned().collect();
-    /// assert_eq!(v, [1, 2, 3, 4]);
+    /// ```
+    /// use std::collections::BTreeSet;
+    ///
+    /// let set: BTreeSet<usize> = [3, 1, 2].iter().cloned().collect();
+    /// let mut set_iter = set.iter();
+    /// assert_eq!(set_iter.next(), Some(&1));
+    /// assert_eq!(set_iter.next(), Some(&2));
+    /// assert_eq!(set_iter.next(), Some(&3));
+    /// assert_eq!(set_iter.next(), None);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn iter(&self) -> Iter<T> {
diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs
index 79e0021b148..87bc5e59ef7 100644
--- a/src/libcollections/enum_set.rs
+++ b/src/libcollections/enum_set.rs
@@ -276,7 +276,8 @@ impl<E: CLike> FromIterator<E> for EnumSet<E> {
     }
 }
 
-impl<'a, E> IntoIterator for &'a EnumSet<E> where E: CLike
+impl<'a, E> IntoIterator for &'a EnumSet<E>
+    where E: CLike
 {
     type Item = E;
     type IntoIter = Iter<E>;
diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs
index 67f3708a62b..31085509088 100644
--- a/src/libcollections/linked_list.rs
+++ b/src/libcollections/linked_list.rs
@@ -10,8 +10,15 @@
 
 //! A doubly-linked list with owned nodes.
 //!
-//! The `LinkedList` allows pushing and popping elements at either end and is thus
-//! efficiently usable as a double-ended queue.
+//! The `LinkedList` allows pushing and popping elements at either end
+//! in constant time.
+//!
+//! Almost always it is better to use `Vec` or [`VecDeque`] instead of
+//! [`LinkedList`]. In general, array-based containers are faster,
+//! more memory efficient and make better use of CPU cache.
+//!
+//! [`LinkedList`]: ../linked_list/struct.LinkedList.html
+//! [`VecDeque`]: ../vec_deque/struct.VecDeque.html
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -27,7 +34,14 @@ use core::ptr::{self, Shared};
 
 use super::SpecExtend;
 
-/// A doubly-linked list.
+/// A doubly-linked list with owned nodes.
+///
+/// The `LinkedList` allows pushing and popping elements at either end
+/// in constant time.
+///
+/// Almost always it is better to use `Vec` or `VecDeque` instead of
+/// `LinkedList`. In general, array-based containers are faster,
+/// more memory efficient and make better use of CPU cache.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct LinkedList<T> {
     head: Option<Shared<Node<T>>>,
@@ -225,15 +239,17 @@ impl<T> LinkedList<T> {
     pub fn append(&mut self, other: &mut Self) {
         match self.tail {
             None => mem::swap(self, other),
-            Some(tail) => if let Some(other_head) = other.head.take() {
-                unsafe {
-                    (**tail).next = Some(other_head);
-                    (**other_head).prev = Some(tail);
-                }
+            Some(tail) => {
+                if let Some(other_head) = other.head.take() {
+                    unsafe {
+                        (**tail).next = Some(other_head);
+                        (**other_head).prev = Some(tail);
+                    }
 
-                self.tail = other.tail.take();
-                self.len += mem::replace(&mut other.len, 0);
-            },
+                    self.tail = other.tail.take();
+                    self.len += mem::replace(&mut other.len, 0);
+                }
+            }
         }
     }
 
@@ -674,7 +690,10 @@ impl<T> LinkedList<T> {
                reason = "method name and placement protocol are subject to change",
                issue = "30172")]
     pub fn front_place(&mut self) -> FrontPlace<T> {
-        FrontPlace { list: self, node: IntermediateBox::make_place() }
+        FrontPlace {
+            list: self,
+            node: IntermediateBox::make_place(),
+        }
     }
 
     /// Returns a place for insertion at the back of the list.
@@ -699,7 +718,10 @@ impl<T> LinkedList<T> {
                reason = "method name and placement protocol are subject to change",
                issue = "30172")]
     pub fn back_place(&mut self) -> BackPlace<T> {
-        BackPlace { list: self, node: IntermediateBox::make_place() }
+        BackPlace {
+            list: self,
+            node: IntermediateBox::make_place(),
+        }
     }
 }
 
@@ -852,7 +874,7 @@ impl<'a, T> IterMut<'a, T> {
                 (**head).prev = node;
 
                 self.list.len += 1;
-            }
+            },
         }
     }
 
@@ -1135,9 +1157,15 @@ impl<'a, T> InPlace<T> for BackPlace<'a, T> {
 // Ensure that `LinkedList` and its read-only iterators are covariant in their type parameters.
 #[allow(dead_code)]
 fn assert_covariance() {
-    fn a<'a>(x: LinkedList<&'static str>) -> LinkedList<&'a str> { x }
-    fn b<'i, 'a>(x: Iter<'i, &'static str>) -> Iter<'i, &'a str> { x }
-    fn c<'a>(x: IntoIter<&'static str>) -> IntoIter<&'a str> { x }
+    fn a<'a>(x: LinkedList<&'static str>) -> LinkedList<&'a str> {
+        x
+    }
+    fn b<'i, 'a>(x: Iter<'i, &'static str>) -> Iter<'i, &'a str> {
+        x
+    }
+    fn c<'a>(x: IntoIter<&'static str>) -> IntoIter<&'a str> {
+        x
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1298,10 +1326,10 @@ mod tests {
     fn test_send() {
         let n = list_from(&[1, 2, 3]);
         thread::spawn(move || {
-            check_links(&n);
-            let a: &[_] = &[&1, &2, &3];
-            assert_eq!(a, &n.iter().collect::<Vec<_>>()[..]);
-        })
+                check_links(&n);
+                let a: &[_] = &[&1, &2, &3];
+                assert_eq!(a, &n.iter().collect::<Vec<_>>()[..]);
+            })
             .join()
             .ok()
             .unwrap();
diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs
index 5fb8cd6e1e2..b5e66692205 100644
--- a/src/libcollections/slice.rs
+++ b/src/libcollections/slice.rs
@@ -1496,10 +1496,10 @@ unsafe fn merge<T, F>(v: &mut [T], mid: usize, buf: *mut T, compare: &mut F)
 /// The algorithm identifies strictly descending and non-descending subsequences, which are called
 /// natural runs. There is a stack of pending runs yet to be merged. Each newly found run is pushed
 /// onto the stack, and then some pairs of adjacent runs are merged until these two invariants are
-/// satisfied, for every `i` in `0 .. runs.len() - 2`:
+/// satisfied:
 ///
-/// 1. `runs[i].len > runs[i + 1].len`
-/// 2. `runs[i].len > runs[i + 1].len + runs[i + 2].len`
+/// 1. for every `i` in `1..runs.len()`: `runs[i - 1].len > runs[i].len`
+/// 2. for every `i` in `2..runs.len()`: `runs[i - 2].len > runs[i - 1].len + runs[i].len`
 ///
 /// The invariants ensure that the total running time is `O(n log n)` worst-case.
 fn merge_sort<T, F>(v: &mut [T], mut compare: F)
diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs
index d4be0914f15..70cedce9a90 100644
--- a/src/libcollections/str.rs
+++ b/src/libcollections/str.rs
@@ -1697,11 +1697,7 @@ impl str {
             debug_assert!('Σ'.len_utf8() == 2);
             let is_word_final = case_ignoreable_then_cased(from[..i].chars().rev()) &&
                                 !case_ignoreable_then_cased(from[i + 2..].chars());
-            to.push_str(if is_word_final {
-                "ς"
-            } else {
-                "σ"
-            });
+            to.push_str(if is_word_final { "ς" } else { "σ" });
         }
 
         fn case_ignoreable_then_cased<I: Iterator<Item = char>>(iter: I) -> bool {
diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs
index b4c41a99a6b..157c762b4a7 100644
--- a/src/libcollections/string.rs
+++ b/src/libcollections/string.rs
@@ -542,11 +542,7 @@ impl String {
             unsafe { *xs.get_unchecked(i) }
         }
         fn safe_get(xs: &[u8], i: usize, total: usize) -> u8 {
-            if i >= total {
-                0
-            } else {
-                unsafe_get(xs, i)
-            }
+            if i >= total { 0 } else { unsafe_get(xs, i) }
         }
 
         let mut res = String::with_capacity(total);
@@ -976,7 +972,7 @@ impl String {
     pub fn push(&mut self, ch: char) {
         match ch.len_utf8() {
             1 => self.vec.push(ch as u8),
-            _ => self.vec.extend_from_slice(ch.encode_utf8(&mut [0;4]).as_bytes()),
+            _ => self.vec.extend_from_slice(ch.encode_utf8(&mut [0; 4]).as_bytes()),
         }
     }
 
@@ -1935,7 +1931,7 @@ impl<'a> FromIterator<String> for Cow<'a, str> {
 
 #[stable(feature = "from_string_for_vec_u8", since = "1.14.0")]
 impl From<String> for Vec<u8> {
-    fn from(string : String) -> Vec<u8> {
+    fn from(string: String) -> Vec<u8> {
         string.into_bytes()
     }
 }
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index c9f9e513ef3..f2ef54f6e56 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -1902,14 +1902,13 @@ impl<T> IntoIter<T> {
     /// # Examples
     ///
     /// ```
-    /// # #![feature(vec_into_iter_as_slice)]
     /// let vec = vec!['a', 'b', 'c'];
     /// let mut into_iter = vec.into_iter();
     /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
     /// let _ = into_iter.next().unwrap();
     /// assert_eq!(into_iter.as_slice(), &['b', 'c']);
     /// ```
-    #[unstable(feature = "vec_into_iter_as_slice", issue = "35601")]
+    #[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")]
     pub fn as_slice(&self) -> &[T] {
         unsafe {
             slice::from_raw_parts(self.ptr, self.len())
@@ -1921,7 +1920,6 @@ impl<T> IntoIter<T> {
     /// # Examples
     ///
     /// ```
-    /// # #![feature(vec_into_iter_as_slice)]
     /// let vec = vec!['a', 'b', 'c'];
     /// let mut into_iter = vec.into_iter();
     /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
@@ -1930,7 +1928,7 @@ impl<T> IntoIter<T> {
     /// assert_eq!(into_iter.next().unwrap(), 'b');
     /// assert_eq!(into_iter.next().unwrap(), 'z');
     /// ```
-    #[unstable(feature = "vec_into_iter_as_slice", issue = "35601")]
+    #[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")]
     pub fn as_mut_slice(&self) -> &mut [T] {
         unsafe {
             slice::from_raw_parts_mut(self.ptr as *mut T, self.len())
diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs
index dbe3fec205c..67621b860bf 100644
--- a/src/libcollections/vec_deque.rs
+++ b/src/libcollections/vec_deque.rs
@@ -206,11 +206,7 @@ impl<T> VecDeque<T> {
     unsafe fn wrap_copy(&self, dst: usize, src: usize, len: usize) {
         #[allow(dead_code)]
         fn diff(a: usize, b: usize) -> usize {
-            if a <= b {
-                b - a
-            } else {
-                a - b
-            }
+            if a <= b { b - a } else { a - b }
         }
         debug_assert!(cmp::min(diff(dst, src), self.cap() - diff(dst, src)) + len <= self.cap(),
                       "wrc dst={} src={} len={} cap={}",
@@ -552,8 +548,8 @@ impl<T> VecDeque<T> {
         let old_cap = self.cap();
         let used_cap = self.len() + 1;
         let new_cap = used_cap.checked_add(additional)
-                              .and_then(|needed_cap| needed_cap.checked_next_power_of_two())
-                              .expect("capacity overflow");
+            .and_then(|needed_cap| needed_cap.checked_next_power_of_two())
+            .expect("capacity overflow");
 
         if new_cap > self.capacity() {
             self.buf.reserve_exact(used_cap, new_cap - used_cap);
@@ -1293,9 +1289,7 @@ impl<T> VecDeque<T> {
 
         let contiguous = self.is_contiguous();
 
-        match (contiguous,
-               distance_to_tail <= distance_to_head,
-               idx >= self.tail) {
+        match (contiguous, distance_to_tail <= distance_to_head, idx >= self.tail) {
             (true, true, _) if index == 0 => {
                 // push_front
                 //
@@ -1513,9 +1507,7 @@ impl<T> VecDeque<T> {
 
         let contiguous = self.is_contiguous();
 
-        match (contiguous,
-               distance_to_tail <= distance_to_head,
-               idx >= self.tail) {
+        match (contiguous, distance_to_tail <= distance_to_head, idx >= self.tail) {
             (true, true, _) => {
                 unsafe {
                     // contiguous, remove closer to tail:
@@ -1812,7 +1804,7 @@ fn wrap_index(index: usize, size: usize) -> usize {
 }
 
 /// Returns the two slices that cover the VecDeque's valid range
-trait RingSlices : Sized {
+trait RingSlices: Sized {
     fn slice(self, from: usize, to: usize) -> Self;
     fn split_at(self, i: usize) -> (Self, Self);
 
@@ -1895,7 +1887,7 @@ impl<'a, T> Iterator for Iter<'a, T> {
     }
 
     fn fold<Acc, F>(self, mut accum: Acc, mut f: F) -> Acc
-        where F: FnMut(Acc, Self::Item) -> Acc,
+        where F: FnMut(Acc, Self::Item) -> Acc
     {
         let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
         accum = front.iter().fold(accum, &mut f);
@@ -1959,7 +1951,7 @@ impl<'a, T> Iterator for IterMut<'a, T> {
     }
 
     fn fold<Acc, F>(self, mut accum: Acc, mut f: F) -> Acc
-        where F: FnMut(Acc, Self::Item) -> Acc,
+        where F: FnMut(Acc, Self::Item) -> Acc
     {
         let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
         accum = front.iter_mut().fold(accum, &mut f);
@@ -2082,17 +2074,15 @@ impl<'a, T: 'a> Drop for Drain<'a, T> {
             (_, 0) => {
                 source_deque.head = drain_tail;
             }
-            _ => {
-                unsafe {
-                    if tail_len <= head_len {
-                        source_deque.tail = source_deque.wrap_sub(drain_head, tail_len);
-                        source_deque.wrap_copy(source_deque.tail, orig_tail, tail_len);
-                    } else {
-                        source_deque.head = source_deque.wrap_add(drain_tail, head_len);
-                        source_deque.wrap_copy(drain_tail, drain_head, head_len);
-                    }
+            _ => unsafe {
+                if tail_len <= head_len {
+                    source_deque.tail = source_deque.wrap_sub(drain_head, tail_len);
+                    source_deque.wrap_copy(source_deque.tail, orig_tail, tail_len);
+                } else {
+                    source_deque.head = source_deque.wrap_add(drain_tail, head_len);
+                    source_deque.wrap_copy(drain_tail, drain_head, head_len);
                 }
-            }
+            },
         }
     }
 }
@@ -2288,10 +2278,8 @@ impl<T> From<Vec<T>> for VecDeque<T> {
 
             // We need to extend the buf if it's not a power of two, too small
             // or doesn't have at least one free space
-            if !buf.cap().is_power_of_two()
-                || (buf.cap() < (MINIMUM_CAPACITY + 1))
-                || (buf.cap() == len)
-            {
+            if !buf.cap().is_power_of_two() || (buf.cap() < (MINIMUM_CAPACITY + 1)) ||
+               (buf.cap() == len) {
                 let cap = cmp::max(buf.cap() + 1, MINIMUM_CAPACITY + 1).next_power_of_two();
                 buf.reserve_exact(len, cap - len);
             }
@@ -2299,7 +2287,7 @@ impl<T> From<Vec<T>> for VecDeque<T> {
             VecDeque {
                 tail: 0,
                 head: len,
-                buf: buf
+                buf: buf,
             }
         }
     }
@@ -2324,18 +2312,17 @@ impl<T> From<VecDeque<T>> for Vec<T> {
                     // do this in at most three copy moves.
                     if (cap - tail) > head {
                         // right hand block is the long one; move that enough for the left
-                        ptr::copy(
-                            buf.offset(tail as isize),
-                            buf.offset((tail - head) as isize),
-                            cap - tail);
+                        ptr::copy(buf.offset(tail as isize),
+                                  buf.offset((tail - head) as isize),
+                                  cap - tail);
                         // copy left in the end
                         ptr::copy(buf, buf.offset((cap - head) as isize), head);
                         // shift the new thing to the start
-                        ptr::copy(buf.offset((tail-head) as isize), buf, len);
+                        ptr::copy(buf.offset((tail - head) as isize), buf, len);
                     } else {
                         // left hand block is the long one, we can do it in two!
-                        ptr::copy(buf, buf.offset((cap-tail) as isize), head);
-                        ptr::copy(buf.offset(tail as isize), buf, cap-tail);
+                        ptr::copy(buf, buf.offset((cap - tail) as isize), head);
+                        ptr::copy(buf.offset(tail as isize), buf, cap - tail);
                     }
                 } else {
                     // Need to use N swaps to move the ring
@@ -2576,8 +2563,8 @@ mod tests {
 
                         // We should see the correct values in the VecDeque
                         let expected: VecDeque<_> = (0..drain_start)
-                                                        .chain(drain_end..len)
-                                                        .collect();
+                            .chain(drain_end..len)
+                            .collect();
                         assert_eq!(expected, tester);
                     }
                 }
@@ -2693,19 +2680,19 @@ mod tests {
             let cap = (2i32.pow(cap_pwr) - 1) as usize;
 
             // In these cases there is enough free space to solve it with copies
-            for len in 0..((cap+1)/2) {
+            for len in 0..((cap + 1) / 2) {
                 // Test contiguous cases
-                for offset in 0..(cap-len) {
+                for offset in 0..(cap - len) {
                     create_vec_and_test_convert(cap, offset, len)
                 }
 
                 // Test cases where block at end of buffer is bigger than block at start
-                for offset in (cap-len)..(cap-(len/2)) {
+                for offset in (cap - len)..(cap - (len / 2)) {
                     create_vec_and_test_convert(cap, offset, len)
                 }
 
                 // Test cases where block at start of buffer is bigger than block at end
-                for offset in (cap-(len/2))..cap {
+                for offset in (cap - (len / 2))..cap {
                     create_vec_and_test_convert(cap, offset, len)
                 }
             }
@@ -2714,19 +2701,19 @@ mod tests {
             // the ring will use swapping when:
             // (cap + 1 - offset) > (cap + 1 - len) && (len - (cap + 1 - offset)) > (cap + 1 - len))
             //  right block size  >   free space    &&      left block size       >    free space
-            for len in ((cap+1)/2)..cap {
+            for len in ((cap + 1) / 2)..cap {
                 // Test contiguous cases
-                for offset in 0..(cap-len) {
+                for offset in 0..(cap - len) {
                     create_vec_and_test_convert(cap, offset, len)
                 }
 
                 // Test cases where block at end of buffer is bigger than block at start
-                for offset in (cap-len)..(cap-(len/2)) {
+                for offset in (cap - len)..(cap - (len / 2)) {
                     create_vec_and_test_convert(cap, offset, len)
                 }
 
                 // Test cases where block at start of buffer is bigger than block at end
-                for offset in (cap-(len/2))..cap {
+                for offset in (cap - (len / 2))..cap {
                     create_vec_and_test_convert(cap, offset, len)
                 }
             }
diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs
index 0fe0a1bad64..d4fb5ea03ad 100644
--- a/src/libcollectionstest/lib.rs
+++ b/src/libcollectionstest/lib.rs
@@ -29,7 +29,6 @@
 #![feature(test)]
 #![feature(unboxed_closures)]
 #![feature(unicode)]
-#![feature(vec_into_iter_as_slice)]
 
 extern crate collections;
 extern crate test;
diff --git a/src/libcompiler_builtins/build.rs b/src/libcompiler_builtins/build.rs
index f61e2281a5c..44aa08e2458 100644
--- a/src/libcompiler_builtins/build.rs
+++ b/src/libcompiler_builtins/build.rs
@@ -242,7 +242,7 @@ fn main() {
                          "atomic_thread_fence.c"]);
     }
 
-    if !target.contains("windows") {
+    if !target.contains("redox") && !target.contains("windows") {
         sources.extend(&["emutls.c"]);
     }
 
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
index 64a7a8c5ef7..c3f862e7c54 100644
--- a/src/libcore/cell.rs
+++ b/src/libcore/cell.rs
@@ -393,6 +393,8 @@ pub struct RefCell<T: ?Sized> {
 /// An enumeration of values returned from the `state` method on a `RefCell<T>`.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 #[unstable(feature = "borrow_state", issue = "27733")]
+#[rustc_deprecated(since = "1.15.0", reason = "use `try_borrow` instead")]
+#[allow(deprecated)]
 pub enum BorrowState {
     /// The cell is currently being read, there is at least one active `borrow`.
     Reading,
@@ -511,6 +513,8 @@ impl<T: ?Sized> RefCell<T> {
     /// }
     /// ```
     #[unstable(feature = "borrow_state", issue = "27733")]
+    #[rustc_deprecated(since = "1.15.0", reason = "use `try_borrow` instead")]
+    #[allow(deprecated)]
     #[inline]
     pub fn borrow_state(&self) -> BorrowState {
         match self.borrow.get() {
@@ -888,9 +892,7 @@ impl<'b, T: ?Sized> Ref<'b, T> {
     /// `Ref::clone(...)`.  A `Clone` implementation or a method would interfere
     /// with the widespread use of `r.borrow().clone()` to clone the contents of
     /// a `RefCell`.
-    #[unstable(feature = "cell_extras",
-               reason = "likely to be moved to a method, pending language changes",
-               issue = "27746")]
+    #[stable(feature = "cell_extras", since = "1.15.0")]
     #[inline]
     pub fn clone(orig: &Ref<'b, T>) -> Ref<'b, T> {
         Ref {
diff --git a/src/libcore/char.rs b/src/libcore/char.rs
index 7f3ac13bac1..c14ae6e0898 100644
--- a/src/libcore/char.rs
+++ b/src/libcore/char.rs
@@ -327,9 +327,9 @@ pub trait CharExt {
     fn len_utf8(self) -> usize;
     #[stable(feature = "core", since = "1.6.0")]
     fn len_utf16(self) -> usize;
-    #[unstable(feature = "unicode", issue = "27784")]
+    #[stable(feature = "unicode_encode_char", since = "1.15.0")]
     fn encode_utf8(self, dst: &mut [u8]) -> &mut str;
-    #[unstable(feature = "unicode", issue = "27784")]
+    #[stable(feature = "unicode_encode_char", since = "1.15.0")]
     fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16];
 }
 
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index 9167264ba9d..2ba7d6e8bd1 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -12,7 +12,7 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use cell::{UnsafeCell, Cell, RefCell, Ref, RefMut, BorrowState};
+use cell::{UnsafeCell, Cell, RefCell, Ref, RefMut};
 use marker::PhantomData;
 use mem;
 use num::flt2dec;
@@ -1634,13 +1634,13 @@ impl<T: Copy + Debug> Debug for Cell<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized + Debug> Debug for RefCell<T> {
     fn fmt(&self, f: &mut Formatter) -> Result {
-        match self.borrow_state() {
-            BorrowState::Unused | BorrowState::Reading => {
+        match self.try_borrow() {
+            Ok(borrow) => {
                 f.debug_struct("RefCell")
-                    .field("value", &self.borrow())
+                    .field("value", &borrow)
                     .finish()
             }
-            BorrowState::Writing => {
+            Err(_) => {
                 f.debug_struct("RefCell")
                     .field("value", &"<borrowed>")
                     .finish()
diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs
index ac36cbaace7..18b465d85a1 100644
--- a/src/libcore/hash/mod.rs
+++ b/src/libcore/hash/mod.rs
@@ -255,10 +255,44 @@ pub trait BuildHasher {
     fn build_hasher(&self) -> Self::Hasher;
 }
 
-/// A structure which implements `BuildHasher` for all `Hasher` types which also
-/// implement `Default`.
+/// The `BuildHasherDefault` structure is used in scenarios where one has a
+/// type that implements [`Hasher`] and [`Default`], but needs that type to
+/// implement [`BuildHasher`].
 ///
-/// This struct is 0-sized and does not need construction.
+/// This structure is zero-sized and does not need construction.
+///
+/// # Examples
+///
+/// Using `BuildHasherDefault` to specify a custom [`BuildHasher`] for
+/// [`HashMap`]:
+///
+/// ```
+/// use std::collections::HashMap;
+/// use std::hash::{BuildHasherDefault, Hasher};
+///
+/// #[derive(Default)]
+/// struct MyHasher;
+///
+/// impl Hasher for MyHasher {
+///     fn write(&mut self, bytes: &[u8]) {
+///         // Your hashing algorithm goes here!
+///        unimplemented!()
+///     }
+///
+///     fn finish(&self) -> u64 {
+///         // Your hashing algorithm goes here!
+///         unimplemented!()
+///     }
+/// }
+///
+/// type MyBuildHasher = BuildHasherDefault<MyHasher>;
+///
+/// let hash_map = HashMap::<u32, u32, MyBuildHasher>::default();
+/// ```
+///
+/// [`BuildHasher`]: trait.BuildHasher.html
+/// [`Default`]: ../default/trait.Default.html
+/// [`Hasher`]: trait.Hasher.html
 #[stable(since = "1.7.0", feature = "build_hasher")]
 pub struct BuildHasherDefault<H>(marker::PhantomData<H>);
 
diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs
index 48808b601c1..ec590d2bd06 100644
--- a/src/libcore/iter/iterator.rs
+++ b/src/libcore/iter/iterator.rs
@@ -1696,12 +1696,11 @@ pub trait Iterator {
     /// # Examples
     ///
     /// ```
-    /// #![feature(iter_max_by)]
     /// let a = [-3_i32, 0, 1, 5, -10];
     /// assert_eq!(*a.iter().max_by(|x, y| x.cmp(y)).unwrap(), 5);
     /// ```
     #[inline]
-    #[unstable(feature = "iter_max_by", issue="36105")]
+    #[stable(feature = "iter_max_by", since = "1.15.0")]
     fn max_by<F>(self, mut compare: F) -> Option<Self::Item>
         where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering,
     {
@@ -1746,12 +1745,11 @@ pub trait Iterator {
     /// # Examples
     ///
     /// ```
-    /// #![feature(iter_min_by)]
     /// let a = [-3_i32, 0, 1, 5, -10];
     /// assert_eq!(*a.iter().min_by(|x, y| x.cmp(y)).unwrap(), -10);
     /// ```
     #[inline]
-    #[unstable(feature = "iter_min_by", issue="36105")]
+    #[stable(feature = "iter_min_by", since = "1.15.0")]
     fn min_by<F>(self, mut compare: F) -> Option<Self::Item>
         where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering,
     {
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index 2ad38de72b1..e3ca8eca76c 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -117,6 +117,8 @@ pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
 /// `zero_memory`, or `copy_memory`). Note that `*src = foo` counts as a use
 /// because it will attempt to drop the value previously at `*src`.
 ///
+/// The pointer must be aligned; use `read_unaligned` if that is not the case.
+///
 /// # Examples
 ///
 /// Basic usage:
@@ -137,6 +139,44 @@ pub unsafe fn read<T>(src: *const T) -> T {
     tmp
 }
 
+/// Reads the value from `src` without moving it. This leaves the
+/// memory in `src` unchanged.
+///
+/// Unlike `read`, the pointer may be unaligned.
+///
+/// # Safety
+///
+/// Beyond accepting a raw pointer, this is unsafe because it semantically
+/// moves the value out of `src` without preventing further usage of `src`.
+/// If `T` is not `Copy`, then care must be taken to ensure that the value at
+/// `src` is not used before the data is overwritten again (e.g. with `write`,
+/// `zero_memory`, or `copy_memory`). Note that `*src = foo` counts as a use
+/// because it will attempt to drop the value previously at `*src`.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// #![feature(ptr_unaligned)]
+///
+/// let x = 12;
+/// let y = &x as *const i32;
+///
+/// unsafe {
+///     assert_eq!(std::ptr::read_unaligned(y), 12);
+/// }
+/// ```
+#[inline(always)]
+#[unstable(feature = "ptr_unaligned", issue = "37955")]
+pub unsafe fn read_unaligned<T>(src: *const T) -> T {
+    let mut tmp: T = mem::uninitialized();
+    copy_nonoverlapping(src as *const u8,
+                        &mut tmp as *mut T as *mut u8,
+                        mem::size_of::<T>());
+    tmp
+}
+
 /// Overwrites a memory location with the given value without reading or
 /// dropping the old value.
 ///
@@ -151,6 +191,8 @@ pub unsafe fn read<T>(src: *const T) -> T {
 /// This is appropriate for initializing uninitialized memory, or overwriting
 /// memory that has previously been `read` from.
 ///
+/// The pointer must be aligned; use `write_unaligned` if that is not the case.
+///
 /// # Examples
 ///
 /// Basic usage:
@@ -171,6 +213,47 @@ pub unsafe fn write<T>(dst: *mut T, src: T) {
     intrinsics::move_val_init(&mut *dst, src)
 }
 
+/// Overwrites a memory location with the given value without reading or
+/// dropping the old value.
+///
+/// Unlike `write`, the pointer may be unaligned.
+///
+/// # Safety
+///
+/// This operation is marked unsafe because it accepts a raw pointer.
+///
+/// It does not drop the contents of `dst`. This is safe, but it could leak
+/// allocations or resources, so care must be taken not to overwrite an object
+/// that should be dropped.
+///
+/// This is appropriate for initializing uninitialized memory, or overwriting
+/// memory that has previously been `read` from.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// #![feature(ptr_unaligned)]
+///
+/// let mut x = 0;
+/// let y = &mut x as *mut i32;
+/// let z = 12;
+///
+/// unsafe {
+///     std::ptr::write_unaligned(y, z);
+///     assert_eq!(std::ptr::read_unaligned(y), 12);
+/// }
+/// ```
+#[inline]
+#[unstable(feature = "ptr_unaligned", issue = "37955")]
+pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
+    copy_nonoverlapping(&src as *const T as *const u8,
+                        dst as *mut u8,
+                        mem::size_of::<T>());
+    mem::forget(src);
+}
+
 /// Performs a volatile read of the value from `src` without moving it. This
 /// leaves the memory in `src` unchanged.
 ///
diff --git a/src/libcore/result.rs b/src/libcore/result.rs
index afed99d265f..99c407e5273 100644
--- a/src/libcore/result.rs
+++ b/src/libcore/result.rs
@@ -501,6 +501,8 @@ impl<T, E> Result<T, E> {
 
     /// Returns an iterator over the possibly contained value.
     ///
+    /// The iterator yields one value if the result is [`Ok`], otherwise none.
+    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -512,6 +514,8 @@ impl<T, E> Result<T, E> {
     /// let x: Result<u32, &str> = Err("nothing!");
     /// assert_eq!(x.iter().next(), None);
     /// ```
+    ///
+    /// [`Ok`]: enum.Result.html#variant.Ok
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn iter(&self) -> Iter<T> {
@@ -520,6 +524,8 @@ impl<T, E> Result<T, E> {
 
     /// Returns a mutable iterator over the possibly contained value.
     ///
+    /// The iterator yields one value if the result is [`Ok`], otherwise none.
+    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -535,6 +541,8 @@ impl<T, E> Result<T, E> {
     /// let mut x: Result<u32, &str> = Err("nothing!");
     /// assert_eq!(x.iter_mut().next(), None);
     /// ```
+    ///
+    /// [`Ok`]: enum.Result.html#variant.Ok
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn iter_mut(&mut self) -> IterMut<T> {
@@ -848,6 +856,8 @@ impl<T, E> IntoIterator for Result<T, E> {
 
     /// Returns a consuming iterator over the possibly contained value.
     ///
+    /// The iterator yields one value if the result is [`Ok`], otherwise none.
+    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -861,6 +871,8 @@ impl<T, E> IntoIterator for Result<T, E> {
     /// let v: Vec<u32> = x.into_iter().collect();
     /// assert_eq!(v, []);
     /// ```
+    ///
+    /// [`Ok`]: enum.Result.html#variant.Ok
     #[inline]
     fn into_iter(self) -> IntoIter<T> {
         IntoIter { inner: self.ok() }
@@ -893,8 +905,13 @@ impl<'a, T, E> IntoIterator for &'a mut Result<T, E> {
 
 /// An iterator over a reference to the [`Ok`] variant of a [`Result`].
 ///
+/// The iterator yields one value if the result is [`Ok`], otherwise none.
+///
+/// Created by [`Result::iter`].
+///
 /// [`Ok`]: enum.Result.html#variant.Ok
 /// [`Result`]: enum.Result.html
+/// [`Result::iter`]: enum.Result.html#method.iter
 #[derive(Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, T: 'a> { inner: Option<&'a T> }
@@ -934,8 +951,11 @@ impl<'a, T> Clone for Iter<'a, T> {
 
 /// An iterator over a mutable reference to the [`Ok`] variant of a [`Result`].
 ///
+/// Created by [`Result::iter_mut`].
+///
 /// [`Ok`]: enum.Result.html#variant.Ok
 /// [`Result`]: enum.Result.html
+/// [`Result::iter_mut`]: enum.Result.html#method.iter_mut
 #[derive(Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IterMut<'a, T: 'a> { inner: Option<&'a mut T> }
@@ -968,9 +988,12 @@ impl<'a, T> FusedIterator for IterMut<'a, T> {}
 #[unstable(feature = "trusted_len", issue = "37572")]
 unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {}
 
-/// An iterator over the value in a [`Ok`] variant of a [`Result`]. This struct is
-/// created by the [`into_iter`] method on [`Result`][`Result`] (provided by
-/// the [`IntoIterator`] trait).
+/// An iterator over the value in a [`Ok`] variant of a [`Result`].
+///
+/// The iterator yields one value if the result is [`Ok`], otherwise none.
+///
+/// This struct is created by the [`into_iter`] method on
+/// [`Result`][`Result`] (provided by the [`IntoIterator`] trait).
 ///
 /// [`Ok`]: enum.Result.html#variant.Ok
 /// [`Result`]: enum.Result.html
diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs
index a4a90e7a9da..e0a49e2ae45 100644
--- a/src/libcore/slice.rs
+++ b/src/libcore/slice.rs
@@ -33,6 +33,7 @@
 // * The `raw` and `bytes` submodules.
 // * Boilerplate trait implementations.
 
+use borrow::Borrow;
 use cmp::Ordering::{self, Less, Equal, Greater};
 use cmp;
 use fmt;
@@ -100,15 +101,17 @@ pub trait SliceExt {
     #[stable(feature = "core", since = "1.6.0")]
     fn as_ptr(&self) -> *const Self::Item;
     #[stable(feature = "core", since = "1.6.0")]
-    fn binary_search(&self, x: &Self::Item) -> Result<usize, usize>
-        where Self::Item: Ord;
+    fn binary_search<Q: ?Sized>(&self, x: &Q) -> Result<usize, usize>
+        where Self::Item: Borrow<Q>,
+              Q: Ord;
     #[stable(feature = "core", since = "1.6.0")]
     fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
         where F: FnMut(&'a Self::Item) -> Ordering;
     #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")]
-    fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result<usize, usize>
+    fn binary_search_by_key<'a, B, F, Q: ?Sized>(&'a self, b: &Q, f: F) -> Result<usize, usize>
         where F: FnMut(&'a Self::Item) -> B,
-              B: Ord;
+              B: Borrow<Q>,
+              Q: Ord;
     #[stable(feature = "core", since = "1.6.0")]
     fn len(&self) -> usize;
     #[stable(feature = "core", since = "1.6.0")]
@@ -493,8 +496,8 @@ impl<T> SliceExt for [T] {
         m >= n && needle == &self[m-n..]
     }
 
-    fn binary_search(&self, x: &T) -> Result<usize, usize> where T: Ord {
-        self.binary_search_by(|p| p.cmp(x))
+    fn binary_search<Q: ?Sized>(&self, x: &Q) -> Result<usize, usize> where T: Borrow<Q>, Q: Ord {
+        self.binary_search_by(|p| p.borrow().cmp(x))
     }
 
     #[inline]
@@ -522,11 +525,12 @@ impl<T> SliceExt for [T] {
     }
 
     #[inline]
-    fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize, usize>
+    fn binary_search_by_key<'a, B, F, Q: ?Sized>(&'a self, b: &Q, mut f: F) -> Result<usize, usize>
         where F: FnMut(&'a Self::Item) -> B,
-              B: Ord
+              B: Borrow<Q>,
+              Q: Ord
     {
-        self.binary_search_by(|k| f(k).cmp(b))
+        self.binary_search_by(|k| f(k).borrow().cmp(b))
     }
 }
 
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index c10f7e39fc3..198db0e7c0a 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -203,7 +203,6 @@ impl AtomicBool {
     /// # Examples
     ///
     /// ```
-    /// #![feature(atomic_access)]
     /// use std::sync::atomic::{AtomicBool, Ordering};
     ///
     /// let mut some_bool = AtomicBool::new(true);
@@ -212,7 +211,7 @@ impl AtomicBool {
     /// assert_eq!(some_bool.load(Ordering::SeqCst), false);
     /// ```
     #[inline]
-    #[unstable(feature = "atomic_access", issue = "35603")]
+    #[stable(feature = "atomic_access", since = "1.15.0")]
     pub fn get_mut(&mut self) -> &mut bool {
         unsafe { &mut *(self.v.get() as *mut bool) }
     }
@@ -225,14 +224,13 @@ impl AtomicBool {
     /// # Examples
     ///
     /// ```
-    /// #![feature(atomic_access)]
     /// use std::sync::atomic::AtomicBool;
     ///
     /// let some_bool = AtomicBool::new(true);
     /// assert_eq!(some_bool.into_inner(), true);
     /// ```
     #[inline]
-    #[unstable(feature = "atomic_access", issue = "35603")]
+    #[stable(feature = "atomic_access", since = "1.15.0")]
     pub fn into_inner(self) -> bool {
         unsafe { self.v.into_inner() != 0 }
     }
@@ -588,7 +586,6 @@ impl<T> AtomicPtr<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(atomic_access)]
     /// use std::sync::atomic::{AtomicPtr, Ordering};
     ///
     /// let mut atomic_ptr = AtomicPtr::new(&mut 10);
@@ -596,7 +593,7 @@ impl<T> AtomicPtr<T> {
     /// assert_eq!(unsafe { *atomic_ptr.load(Ordering::SeqCst) }, 5);
     /// ```
     #[inline]
-    #[unstable(feature = "atomic_access", issue = "35603")]
+    #[stable(feature = "atomic_access", since = "1.15.0")]
     pub fn get_mut(&mut self) -> &mut *mut T {
         unsafe { &mut *self.p.get() }
     }
@@ -609,14 +606,13 @@ impl<T> AtomicPtr<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(atomic_access)]
     /// use std::sync::atomic::AtomicPtr;
     ///
     /// let atomic_ptr = AtomicPtr::new(&mut 5);
     /// assert_eq!(unsafe { *atomic_ptr.into_inner() }, 5);
     /// ```
     #[inline]
-    #[unstable(feature = "atomic_access", issue = "35603")]
+    #[stable(feature = "atomic_access", since = "1.15.0")]
     pub fn into_inner(self) -> *mut T {
         unsafe { self.p.into_inner() }
     }
@@ -883,7 +879,6 @@ macro_rules! atomic_int {
             /// # Examples
             ///
             /// ```
-            /// #![feature(atomic_access)]
             /// use std::sync::atomic::{AtomicIsize, Ordering};
             ///
             /// let mut some_isize = AtomicIsize::new(10);
@@ -905,7 +900,6 @@ macro_rules! atomic_int {
             /// # Examples
             ///
             /// ```
-            /// #![feature(atomic_access)]
             /// use std::sync::atomic::AtomicIsize;
             ///
             /// let some_isize = AtomicIsize::new(5);
@@ -1261,7 +1255,7 @@ atomic_int!{
     stable(feature = "rust1", since = "1.0.0"),
     stable(feature = "extended_compare_and_swap", since = "1.10.0"),
     stable(feature = "atomic_debug", since = "1.3.0"),
-    unstable(feature = "atomic_access", issue = "35603"),
+    stable(feature = "atomic_access", since = "1.15.0"),
     isize AtomicIsize ATOMIC_ISIZE_INIT
 }
 #[cfg(target_has_atomic = "ptr")]
@@ -1269,7 +1263,7 @@ atomic_int!{
     stable(feature = "rust1", since = "1.0.0"),
     stable(feature = "extended_compare_and_swap", since = "1.10.0"),
     stable(feature = "atomic_debug", since = "1.3.0"),
-    unstable(feature = "atomic_access", issue = "35603"),
+    stable(feature = "atomic_access", since = "1.15.0"),
     usize AtomicUsize ATOMIC_USIZE_INIT
 }
 
diff --git a/src/libcoretest/cell.rs b/src/libcoretest/cell.rs
index a7c230ba979..724a312ea79 100644
--- a/src/libcoretest/cell.rs
+++ b/src/libcoretest/cell.rs
@@ -59,22 +59,22 @@ fn double_imm_borrow() {
 fn no_mut_then_imm_borrow() {
     let x = RefCell::new(0);
     let _b1 = x.borrow_mut();
-    assert_eq!(x.borrow_state(), BorrowState::Writing);
+    assert!(x.try_borrow().is_err());
 }
 
 #[test]
 fn no_imm_then_borrow_mut() {
     let x = RefCell::new(0);
     let _b1 = x.borrow();
-    assert_eq!(x.borrow_state(), BorrowState::Reading);
+    assert!(x.try_borrow_mut().is_err());
 }
 
 #[test]
 fn no_double_borrow_mut() {
     let x = RefCell::new(0);
-    assert_eq!(x.borrow_state(), BorrowState::Unused);
+    assert!(x.try_borrow().is_ok());
     let _b1 = x.borrow_mut();
-    assert_eq!(x.borrow_state(), BorrowState::Writing);
+    assert!(x.try_borrow().is_err());
 }
 
 #[test]
@@ -102,7 +102,8 @@ fn double_borrow_single_release_no_borrow_mut() {
     {
         let _b2 = x.borrow();
     }
-    assert_eq!(x.borrow_state(), BorrowState::Reading);
+    assert!(x.try_borrow().is_ok());
+    assert!(x.try_borrow_mut().is_err());
 }
 
 #[test]
@@ -119,14 +120,18 @@ fn ref_clone_updates_flag() {
     let x = RefCell::new(0);
     {
         let b1 = x.borrow();
-        assert_eq!(x.borrow_state(), BorrowState::Reading);
+        assert!(x.try_borrow().is_ok());
+        assert!(x.try_borrow_mut().is_err());
         {
             let _b2 = Ref::clone(&b1);
-            assert_eq!(x.borrow_state(), BorrowState::Reading);
+            assert!(x.try_borrow().is_ok());
+            assert!(x.try_borrow_mut().is_err());
         }
-        assert_eq!(x.borrow_state(), BorrowState::Reading);
+        assert!(x.try_borrow().is_ok());
+        assert!(x.try_borrow_mut().is_err());
     }
-    assert_eq!(x.borrow_state(), BorrowState::Unused);
+    assert!(x.try_borrow().is_ok());
+    assert!(x.try_borrow_mut().is_ok());
 }
 
 #[test]
@@ -134,15 +139,19 @@ fn ref_map_does_not_update_flag() {
     let x = RefCell::new(Some(5));
     {
         let b1: Ref<Option<u32>> = x.borrow();
-        assert_eq!(x.borrow_state(), BorrowState::Reading);
+        assert!(x.try_borrow().is_ok());
+        assert!(x.try_borrow_mut().is_err());
         {
             let b2: Ref<u32> = Ref::map(b1, |o| o.as_ref().unwrap());
             assert_eq!(*b2, 5);
-            assert_eq!(x.borrow_state(), BorrowState::Reading);
+            assert!(x.try_borrow().is_ok());
+            assert!(x.try_borrow_mut().is_err());
         }
-        assert_eq!(x.borrow_state(), BorrowState::Unused);
+        assert!(x.try_borrow().is_ok());
+        assert!(x.try_borrow_mut().is_ok());
     }
-    assert_eq!(x.borrow_state(), BorrowState::Unused);
+    assert!(x.try_borrow().is_ok());
+    assert!(x.try_borrow_mut().is_ok());
 }
 
 #[test]
@@ -247,5 +256,3 @@ fn refcell_ref_coercion() {
         assert_eq!(&*coerced, comp);
     }
 }
-
-
diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs
index 92fb01e535c..d12616a97a6 100644
--- a/src/libcoretest/lib.rs
+++ b/src/libcoretest/lib.rs
@@ -10,9 +10,7 @@
 
 #![deny(warnings)]
 
-#![feature(borrow_state)]
 #![feature(box_syntax)]
-#![feature(cell_extras)]
 #![feature(char_escape_debug)]
 #![feature(const_fn)]
 #![feature(core_private_bignum)]
@@ -32,10 +30,9 @@
 #![feature(try_from)]
 #![feature(unicode)]
 #![feature(unique)]
-#![feature(iter_max_by)]
-#![feature(iter_min_by)]
 #![feature(ordering_chaining)]
 #![feature(result_unwrap_or_default)]
+#![feature(ptr_unaligned)]
 
 extern crate core;
 extern crate test;
diff --git a/src/libcoretest/ptr.rs b/src/libcoretest/ptr.rs
index f7fe61896f8..7f6f472bfbb 100644
--- a/src/libcoretest/ptr.rs
+++ b/src/libcoretest/ptr.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use core::ptr::*;
+use core::cell::RefCell;
 
 #[test]
 fn test() {
@@ -189,3 +190,25 @@ pub fn test_variadic_fnptr() {
     let mut s = SipHasher::new();
     assert_eq!(p.hash(&mut s), q.hash(&mut s));
 }
+
+#[test]
+fn write_unaligned_drop() {
+    thread_local! {
+        static DROPS: RefCell<Vec<u32>> = RefCell::new(Vec::new());
+    }
+
+    struct Dropper(u32);
+
+    impl Drop for Dropper {
+        fn drop(&mut self) {
+            DROPS.with(|d| d.borrow_mut().push(self.0));
+        }
+    }
+
+    {
+        let c = Dropper(0);
+        let mut t = Dropper(1);
+        unsafe { write_unaligned(&mut t, c); }
+    }
+    DROPS.with(|d| assert_eq!(*d.borrow(), [0]));
+}
diff --git a/src/liblibc b/src/liblibc
-Subproject 0ac39c5ccf6a04395b7c40dd62321cb91f63f16
+Subproject e49e9bb7c3d9c7f2fd893f0ee0db81617b8db21
diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs
index 853f81ceaa9..8f85bfe2c63 100644
--- a/src/libpanic_abort/lib.rs
+++ b/src/libpanic_abort/lib.rs
@@ -28,7 +28,7 @@
 #![panic_runtime]
 #![feature(panic_runtime)]
 #![cfg_attr(unix, feature(libc))]
-#![cfg_attr(windows, feature(core_intrinsics))]
+#![cfg_attr(any(target_os = "redox", windows), feature(core_intrinsics))]
 
 // Rust's "try" function, but if we're aborting on panics we just call the
 // function as there's nothing else we need to do here.
@@ -61,7 +61,7 @@ pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 {
         libc::abort();
     }
 
-    #[cfg(windows)]
+    #[cfg(any(target_os = "redox", windows))]
     unsafe fn abort() -> ! {
         core::intrinsics::abort();
     }
diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs
index ff483fa823e..b75d9ec6520 100644
--- a/src/libpanic_unwind/lib.rs
+++ b/src/libpanic_unwind/lib.rs
@@ -69,6 +69,7 @@ mod imp;
 
 // i686-pc-windows-gnu and all others
 #[cfg(any(all(unix, not(target_os = "emscripten")),
+          target_os = "redox",
           all(windows, target_arch = "x86", target_env = "gnu")))]
 #[path = "gcc.rs"]
 mod imp;
diff --git a/src/librustc/dep_graph/README.md b/src/librustc/dep_graph/README.md
index 48f5b7ea259..d2b94db689b 100644
--- a/src/librustc/dep_graph/README.md
+++ b/src/librustc/dep_graph/README.md
@@ -418,7 +418,7 @@ to see something like:
 
     Hir(foo) -> Collect(bar)
     Collect(bar) -> TypeckItemBody(bar)
-    
+
 That first edge looks suspicious to you. So you set
 `RUST_FORBID_DEP_GRAPH_EDGE` to `Hir&foo -> Collect&bar`, re-run, and
 then observe the backtrace. Voila, bug fixed!
@@ -440,6 +440,4 @@ To achieve this, the HIR map will detect if the def-id originates in
 an inlined node and add a dependency to a suitable `MetaData` node
 instead. If you are reading a HIR node and are not sure if it may be
 inlined or not, you can use `tcx.map.read(node_id)` and it will detect
-whether the node is inlined or not and do the right thing.  You can
-also use `tcx.map.is_inlined_def_id()` and
-`tcx.map.is_inlined_node_id()` to test.
+whether the node is inlined or not and do the right thing.
diff --git a/src/librustc/dep_graph/shadow.rs b/src/librustc/dep_graph/shadow.rs
index 06def4bf19a..5d4190a8ae1 100644
--- a/src/librustc/dep_graph/shadow.rs
+++ b/src/librustc/dep_graph/shadow.rs
@@ -27,7 +27,7 @@
 //! created.  See `./README.md` for details.
 
 use hir::def_id::DefId;
-use std::cell::{BorrowState, RefCell};
+use std::cell::RefCell;
 use std::env;
 
 use super::DepNode;
@@ -71,15 +71,11 @@ impl ShadowGraph {
 
     pub fn enqueue(&self, message: &DepMessage) {
         if ENABLED {
-            match self.stack.borrow_state() {
-                BorrowState::Unused => {}
-                _ => {
-                    // When we apply edge filters, that invokes the
-                    // Debug trait on DefIds, which in turn reads from
-                    // various bits of state and creates reads! Ignore
-                    // those recursive reads.
-                    return;
-                }
+            if self.stack.try_borrow().is_err() {
+                // When we apply edge filters, that invokes the Debug trait on
+                // DefIds, which in turn reads from various bits of state and
+                // creates reads! Ignore those recursive reads.
+                return;
             }
 
             let mut stack = self.stack.borrow_mut();
diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs
index 600732fc6f7..f6a22e47cf2 100644
--- a/src/librustc/dep_graph/visit.rs
+++ b/src/librustc/dep_graph/visit.rs
@@ -40,7 +40,6 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>
             let task_id = (self.dep_node_fn)(item_def_id);
             let _task = self.tcx.dep_graph.in_task(task_id.clone());
             debug!("Started task {:?}", task_id);
-            assert!(!self.tcx.map.is_inlined_def_id(item_def_id));
             self.tcx.dep_graph.read(DepNode::Hir(item_def_id));
             self.visitor.visit_item(i);
             debug!("Ended task {:?}", task_id);
@@ -51,7 +50,6 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>
             let task_id = (self.dep_node_fn)(impl_item_def_id);
             let _task = self.tcx.dep_graph.in_task(task_id.clone());
             debug!("Started task {:?}", task_id);
-            assert!(!self.tcx.map.is_inlined_def_id(impl_item_def_id));
             self.tcx.dep_graph.read(DepNode::Hir(impl_item_def_id));
             self.visitor.visit_impl_item(i);
             debug!("Ended task {:?}", task_id);
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index ec09877ae12..1655c716b6b 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -1236,6 +1236,23 @@ struct Foo<'a, T: 'a> {
     foo: &'a T
 }
 ```
+
+To see why this is important, consider the case where `T` is itself a reference
+(e.g., `T = &str`). If we don't include the restriction that `T: 'a`, the
+following code would be perfectly legal:
+
+```compile_fail,E0309
+struct Foo<'a, T> {
+    foo: &'a T
+}
+
+fn main() {
+    let v = "42".to_string();
+    let f = Foo{foo: &v};
+    drop(v);
+    println!("{}", f.foo); // but we've already dropped v!
+}
+```
 "##,
 
 E0310: r##"
diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs
index d3771b1755b..cbf162cc136 100644
--- a/src/librustc/hir/def_id.rs
+++ b/src/librustc/hir/def_id.rs
@@ -120,9 +120,7 @@ impl fmt::Debug for DefId {
 
         ty::tls::with_opt(|opt_tcx| {
             if let Some(tcx) = opt_tcx {
-                if let Some(def_path) = tcx.opt_def_path(*self) {
-                    write!(f, " => {}", def_path.to_string(tcx))?;
-                }
+                write!(f, " => {}", tcx.def_path(*self).to_string(tcx))?;
             }
             Ok(())
         })?;
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 625bde2ca8b..186d6f62650 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -365,7 +365,6 @@ pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) {
 pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef) {
     visitor.visit_id(macro_def.id);
     visitor.visit_name(macro_def.span, macro_def.name);
-    walk_opt_name(visitor, macro_def.span, macro_def.imported_from);
     walk_list!(visitor, visit_attribute, &macro_def.attrs);
 }
 
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 74876eb59ee..1cf5e35a095 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -81,7 +81,7 @@ pub struct LoweringContext<'a> {
 }
 
 pub trait Resolver {
-    // Resolve a global hir path generated by the lowerer when expanding `for`, `if let`, etc.
+    // Resolve a hir path generated by the lowerer when expanding `for`, `if let`, etc.
     fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool);
 
     // Obtain the resolution for a node id
@@ -337,7 +337,6 @@ impl<'a> LoweringContext<'a> {
 
         let proj_start = p.segments.len() - resolution.depth;
         let path = P(hir::Path {
-            global: p.global,
             def: resolution.base_def,
             segments: p.segments[..proj_start].iter().enumerate().map(|(i, segment)| {
                 let param_mode = match (qself_position, param_mode) {
@@ -404,12 +403,17 @@ impl<'a> LoweringContext<'a> {
                         id: NodeId,
                         p: &Path,
                         name: Option<Name>,
-                        param_mode: ParamMode)
+                        param_mode: ParamMode,
+                        defaults_to_global: bool)
                         -> hir::Path {
+        let mut segments = p.segments.iter();
+        if defaults_to_global && p.is_global() {
+            segments.next();
+        }
+
         hir::Path {
-            global: p.global,
             def: self.expect_full_def(id),
-            segments: p.segments.iter().map(|segment| {
+            segments: segments.map(|segment| {
                 self.lower_path_segment(segment, param_mode)
             }).chain(name.map(|name| {
                 hir::PathSegment {
@@ -424,22 +428,29 @@ impl<'a> LoweringContext<'a> {
     fn lower_path(&mut self,
                   id: NodeId,
                   p: &Path,
-                  param_mode: ParamMode)
+                  param_mode: ParamMode,
+                  defaults_to_global: bool)
                   -> hir::Path {
-        self.lower_path_extra(id, p, None, param_mode)
+        self.lower_path_extra(id, p, None, param_mode, defaults_to_global)
     }
 
     fn lower_path_segment(&mut self,
                           segment: &PathSegment,
                           param_mode: ParamMode)
                           -> hir::PathSegment {
-        let parameters = match segment.parameters {
-            PathParameters::AngleBracketed(ref data) => {
-                let data = self.lower_angle_bracketed_parameter_data(data, param_mode);
-                hir::AngleBracketedParameters(data)
+        let parameters = if let Some(ref parameters) = segment.parameters {
+            match **parameters {
+                PathParameters::AngleBracketed(ref data) => {
+                    let data = self.lower_angle_bracketed_parameter_data(data, param_mode);
+                    hir::AngleBracketedParameters(data)
+                }
+                PathParameters::Parenthesized(ref data) => {
+                    hir::ParenthesizedParameters(self.lower_parenthesized_parameter_data(data))
+                }
             }
-            PathParameters::Parenthesized(ref data) =>
-                hir::ParenthesizedParameters(self.lower_parenthesized_parameter_data(data)),
+        } else {
+            let data = self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode);
+            hir::AngleBracketedParameters(data)
         };
 
         hir::PathSegment {
@@ -596,8 +607,8 @@ impl<'a> LoweringContext<'a> {
                         // Check if the where clause type is a plain type parameter.
                         match bound_pred.bounded_ty.node {
                             TyKind::Path(None, ref path)
-                                    if !path.global && path.segments.len() == 1 &&
-                                        bound_pred.bound_lifetimes.is_empty() => {
+                                    if path.segments.len() == 1 &&
+                                       bound_pred.bound_lifetimes.is_empty() => {
                                 if let Some(Def::TyParam(def_id)) =
                                         self.resolver.get_resolution(bound_pred.bounded_ty.id)
                                                      .map(|d| d.base_def) {
@@ -671,7 +682,7 @@ impl<'a> LoweringContext<'a> {
                                                           span}) => {
                 hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
                     id: id,
-                    path: self.lower_path(id, path, ParamMode::Explicit),
+                    path: self.lower_path(id, path, ParamMode::Explicit, false),
                     ty: self.lower_ty(ty),
                     span: span,
                 })
@@ -701,7 +712,7 @@ impl<'a> LoweringContext<'a> {
 
     fn lower_trait_ref(&mut self, p: &TraitRef) -> hir::TraitRef {
         hir::TraitRef {
-            path: self.lower_path(p.ref_id, &p.path, ParamMode::Explicit),
+            path: self.lower_path(p.ref_id, &p.path, ParamMode::Explicit, false),
             ref_id: p.ref_id,
         }
     }
@@ -794,7 +805,7 @@ impl<'a> LoweringContext<'a> {
                             };
 
                             let mut path = self.lower_path_extra(import.id, path, suffix,
-                                                                 ParamMode::Explicit);
+                                                                 ParamMode::Explicit, true);
                             path.span = span;
                             self.items.insert(import.id, hir::Item {
                                 id: import.id,
@@ -808,7 +819,7 @@ impl<'a> LoweringContext<'a> {
                         path
                     }
                 };
-                let path = P(self.lower_path(id, path, ParamMode::Explicit));
+                let path = P(self.lower_path(id, path, ParamMode::Explicit, true));
                 let kind = match view_path.node {
                     ViewPathSimple(ident, _) => {
                         *name = ident.name;
@@ -987,8 +998,6 @@ impl<'a> LoweringContext<'a> {
             attrs: self.lower_attrs(&m.attrs),
             id: m.id,
             span: m.span,
-            imported_from: m.imported_from.map(|x| x.name),
-            allow_internal_unstable: m.allow_internal_unstable,
             body: m.body.clone().into(),
         }
     }
@@ -1131,7 +1140,6 @@ impl<'a> LoweringContext<'a> {
                             Some(def) => {
                                 hir::PatKind::Path(hir::QPath::Resolved(None, P(hir::Path {
                                     span: pth1.span,
-                                    global: false,
                                     def: def,
                                     segments: hir_vec![
                                         hir::PathSegment::from_name(pth1.node.name)
@@ -1874,7 +1882,7 @@ impl<'a> LoweringContext<'a> {
             Visibility::Crate(_) => hir::Visibility::Crate,
             Visibility::Restricted { ref path, id } => {
                 hir::Visibility::Restricted {
-                    path: P(self.lower_path(id, path, ParamMode::Explicit)),
+                    path: P(self.lower_path(id, path, ParamMode::Explicit, true)),
                     id: id
                 }
             }
@@ -1967,7 +1975,6 @@ impl<'a> LoweringContext<'a> {
 
         let expr_path = hir::ExprPath(hir::QPath::Resolved(None, P(hir::Path {
             span: span,
-            global: false,
             def: def,
             segments: hir_vec![hir::PathSegment::from_name(id)],
         })));
@@ -2135,17 +2142,12 @@ impl<'a> LoweringContext<'a> {
     /// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
     /// The path is also resolved according to `is_value`.
     fn std_path(&mut self, span: Span, components: &[&str], is_value: bool) -> hir::Path {
-        let idents = self.crate_root.iter().chain(components);
-
-        let segments: Vec<_> = idents.map(|name| {
-            hir::PathSegment::from_name(Symbol::intern(name))
-        }).collect();
-
         let mut path = hir::Path {
             span: span,
-            global: true,
             def: Def::Err,
-            segments: segments.into(),
+            segments: iter::once(keywords::CrateRoot.name()).chain({
+                self.crate_root.into_iter().chain(components.iter().cloned()).map(Symbol::intern)
+            }).map(hir::PathSegment::from_name).collect(),
         };
 
         self.resolver.resolve_hir_path(&mut path, is_value);
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index c46c8f044e0..45988886a60 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -11,7 +11,6 @@
 use super::*;
 
 use hir::intravisit::{Visitor, NestedVisitorMap};
-use hir::def_id::DefId;
 use middle::cstore::InlinedItem;
 use std::iter::repeat;
 use syntax::ast::{NodeId, CRATE_NODE_ID};
@@ -47,8 +46,6 @@ impl<'ast> NodeCollector<'ast> {
     pub fn extend(krate: &'ast Crate,
                   parent: &'ast InlinedItem,
                   parent_node: NodeId,
-                  parent_def_path: DefPath,
-                  parent_def_id: DefId,
                   map: Vec<MapEntry<'ast>>)
                   -> NodeCollector<'ast> {
         let mut collector = NodeCollector {
@@ -58,7 +55,6 @@ impl<'ast> NodeCollector<'ast> {
             ignore_nested_items: true
         };
 
-        assert_eq!(parent_def_path.krate, parent_def_id.krate);
         collector.insert_entry(parent_node, RootInlinedParent(parent));
 
         collector
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index eb5a89f320e..256aee342a3 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -9,12 +9,7 @@
 // except according to those terms.
 
 use hir::map::definitions::*;
-
-use hir;
-use hir::intravisit::{self, Visitor, NestedVisitorMap};
-use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
-
-use middle::cstore::InlinedItem;
+use hir::def_id::{CRATE_DEF_INDEX, DefIndex};
 
 use syntax::ast::*;
 use syntax::ext::hygiene::Mark;
@@ -23,9 +18,6 @@ use syntax::symbol::{Symbol, keywords};
 
 /// Creates def ids for nodes in the HIR.
 pub struct DefCollector<'a> {
-    // If we are walking HIR (c.f., AST), we need to keep a reference to the
-    // crate.
-    hir_crate: Option<&'a hir::Crate>,
     definitions: &'a mut Definitions,
     parent_def: Option<DefIndex>,
     pub visit_macro_invoc: Option<&'a mut FnMut(MacroInvocationData)>,
@@ -40,43 +32,16 @@ pub struct MacroInvocationData {
 impl<'a> DefCollector<'a> {
     pub fn new(definitions: &'a mut Definitions) -> Self {
         DefCollector {
-            hir_crate: None,
             definitions: definitions,
             parent_def: None,
             visit_macro_invoc: None,
         }
     }
 
-    pub fn extend(parent_node: NodeId,
-                  parent_def_path: DefPath,
-                  parent_def_id: DefId,
-                  definitions: &'a mut Definitions)
-                  -> Self {
-        let mut collector = DefCollector::new(definitions);
-
-        assert_eq!(parent_def_path.krate, parent_def_id.krate);
-        let root_path = Box::new(InlinedRootPath {
-            data: parent_def_path.data,
-            def_id: parent_def_id,
-        });
-
-        let def = collector.create_def(parent_node, DefPathData::InlinedRoot(root_path));
-        collector.parent_def = Some(def);
-
-        collector
-    }
-
     pub fn collect_root(&mut self) {
         let root = self.create_def_with_parent(None, CRATE_NODE_ID, DefPathData::CrateRoot);
         assert_eq!(root, CRATE_DEF_INDEX);
         self.parent_def = Some(root);
-
-        self.create_def_with_parent(Some(CRATE_DEF_INDEX), DUMMY_NODE_ID, DefPathData::Misc);
-    }
-
-    pub fn walk_item(&mut self, ii: &'a InlinedItem, krate: &'a hir::Crate) {
-        self.hir_crate = Some(krate);
-        ii.visit(self);
     }
 
     fn create_def(&mut self, node_id: NodeId, data: DefPathData) -> DefIndex {
@@ -114,16 +79,6 @@ impl<'a> DefCollector<'a> {
         self.create_def(expr.id, DefPathData::Initializer);
     }
 
-    fn visit_hir_const_integer(&mut self, expr: &hir::Expr) {
-        // FIXME(eddyb) Closures should have separate
-        // function definition IDs and expression IDs.
-        if let hir::ExprClosure(..) = expr.node {
-            return;
-        }
-
-        self.create_def(expr.id, DefPathData::Initializer);
-    }
-
     fn visit_macro_invoc(&mut self, id: NodeId, const_integer: bool) {
         if let Some(ref mut visit) = self.visit_macro_invoc {
             visit(MacroInvocationData {
@@ -324,169 +279,3 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
         }
     }
 }
-
-// We walk the HIR rather than the AST when reading items from metadata.
-impl<'ast> Visitor<'ast> for DefCollector<'ast> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'ast> {
-        // note however that we override `visit_body` below
-        NestedVisitorMap::None
-    }
-
-    fn visit_body(&mut self, id: hir::ExprId) {
-        if let Some(krate) = self.hir_crate {
-            self.visit_expr(krate.expr(id));
-        }
-    }
-
-    fn visit_item(&mut self, i: &'ast hir::Item) {
-        debug!("visit_item: {:?}", i);
-
-        // Pick the def data. This need not be unique, but the more
-        // information we encapsulate into
-        let def_data = match i.node {
-            hir::ItemDefaultImpl(..) | hir::ItemImpl(..) =>
-                DefPathData::Impl,
-            hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) |
-            hir::ItemTrait(..) | hir::ItemExternCrate(..) | hir::ItemMod(..) |
-            hir::ItemForeignMod(..) | hir::ItemTy(..) =>
-                DefPathData::TypeNs(i.name.as_str()),
-            hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) =>
-                DefPathData::ValueNs(i.name.as_str()),
-            hir::ItemUse(..) => DefPathData::Misc,
-        };
-        let def = self.create_def(i.id, def_data);
-
-        self.with_parent(def, |this| {
-            match i.node {
-                hir::ItemEnum(ref enum_definition, _) => {
-                    for v in &enum_definition.variants {
-                        let variant_def_index =
-                            this.create_def(v.node.data.id(),
-                                            DefPathData::EnumVariant(v.node.name.as_str()));
-
-                        this.with_parent(variant_def_index, |this| {
-                            for field in v.node.data.fields() {
-                                this.create_def(field.id,
-                                                DefPathData::Field(field.name.as_str()));
-                            }
-                            if let Some(ref expr) = v.node.disr_expr {
-                                this.visit_hir_const_integer(expr);
-                            }
-                        });
-                    }
-                }
-                hir::ItemStruct(ref struct_def, _) |
-                hir::ItemUnion(ref struct_def, _) => {
-                    // If this is a tuple-like struct, register the constructor.
-                    if !struct_def.is_struct() {
-                        this.create_def(struct_def.id(),
-                                        DefPathData::StructCtor);
-                    }
-
-                    for field in struct_def.fields() {
-                        this.create_def(field.id, DefPathData::Field(field.name.as_str()));
-                    }
-                }
-                _ => {}
-            }
-            intravisit::walk_item(this, i);
-        });
-    }
-
-    fn visit_foreign_item(&mut self, foreign_item: &'ast hir::ForeignItem) {
-        let def = self.create_def(foreign_item.id,
-                                  DefPathData::ValueNs(foreign_item.name.as_str()));
-
-        self.with_parent(def, |this| {
-            intravisit::walk_foreign_item(this, foreign_item);
-        });
-    }
-
-    fn visit_generics(&mut self, generics: &'ast hir::Generics) {
-        for ty_param in generics.ty_params.iter() {
-            self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.name.as_str()));
-        }
-
-        intravisit::walk_generics(self, generics);
-    }
-
-    fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
-        let def_data = match ti.node {
-            hir::MethodTraitItem(..) | hir::ConstTraitItem(..) =>
-                DefPathData::ValueNs(ti.name.as_str()),
-            hir::TypeTraitItem(..) => DefPathData::TypeNs(ti.name.as_str()),
-        };
-
-        let def = self.create_def(ti.id, def_data);
-        self.with_parent(def, |this| {
-            if let hir::ConstTraitItem(_, Some(ref expr)) = ti.node {
-                this.create_def(expr.id, DefPathData::Initializer);
-            }
-
-            intravisit::walk_trait_item(this, ti);
-        });
-    }
-
-    fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) {
-        let def_data = match ii.node {
-            hir::ImplItemKind::Method(..) | hir::ImplItemKind::Const(..) =>
-                DefPathData::ValueNs(ii.name.as_str()),
-            hir::ImplItemKind::Type(..) => DefPathData::TypeNs(ii.name.as_str()),
-        };
-
-        let def = self.create_def(ii.id, def_data);
-        self.with_parent(def, |this| {
-            if let hir::ImplItemKind::Const(_, ref expr) = ii.node {
-                this.create_def(expr.id, DefPathData::Initializer);
-            }
-
-            intravisit::walk_impl_item(this, ii);
-        });
-    }
-
-    fn visit_pat(&mut self, pat: &'ast hir::Pat) {
-        let parent_def = self.parent_def;
-
-        if let hir::PatKind::Binding(_, _, name, _) = pat.node {
-            let def = self.create_def(pat.id, DefPathData::Binding(name.node.as_str()));
-            self.parent_def = Some(def);
-        }
-
-        intravisit::walk_pat(self, pat);
-        self.parent_def = parent_def;
-    }
-
-    fn visit_expr(&mut self, expr: &'ast hir::Expr) {
-        let parent_def = self.parent_def;
-
-        if let hir::ExprRepeat(_, ref count) = expr.node {
-            self.visit_hir_const_integer(count);
-        }
-
-        if let hir::ExprClosure(..) = expr.node {
-            let def = self.create_def(expr.id, DefPathData::ClosureExpr);
-            self.parent_def = Some(def);
-        }
-
-        intravisit::walk_expr(self, expr);
-        self.parent_def = parent_def;
-    }
-
-    fn visit_ty(&mut self, ty: &'ast hir::Ty) {
-        if let hir::TyArray(_, ref length) = ty.node {
-            self.visit_hir_const_integer(length);
-        }
-        if let hir::TyImplTrait(..) = ty.node {
-            self.create_def(ty.id, DefPathData::ImplTrait);
-        }
-        intravisit::walk_ty(self, ty);
-    }
-
-    fn visit_lifetime_def(&mut self, def: &'ast hir::LifetimeDef) {
-        self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name.as_str()));
-    }
-
-    fn visit_macro_def(&mut self, macro_def: &'ast hir::MacroDef) {
-        self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.name.as_str()));
-    }
-}
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 83d3627d8e6..4f64670f482 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -8,22 +8,119 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+//! For each definition, we track the following data.  A definition
+//! here is defined somewhat circularly as "something with a def-id",
+//! but it generally corresponds to things like structs, enums, etc.
+//! There are also some rather random cases (like const initializer
+//! expressions) that are mostly just leftovers.
+
 use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::StableHasher;
+use serialize::{Encodable, Decodable, Encoder, Decoder};
 use std::fmt::Write;
 use std::hash::{Hash, Hasher};
-use std::collections::hash_map::DefaultHasher;
 use syntax::ast;
 use syntax::symbol::{Symbol, InternedString};
 use ty::TyCtxt;
 use util::nodemap::NodeMap;
 
-/// The definition table containing node definitions
+/// The DefPathTable maps DefIndexes to DefKeys and vice versa.
+/// Internally the DefPathTable holds a tree of DefKeys, where each DefKey
+/// stores the DefIndex of its parent.
+/// There is one DefPathTable for each crate.
+#[derive(Clone)]
+pub struct DefPathTable {
+    index_to_key: Vec<DefKey>,
+    key_to_index: FxHashMap<DefKey, DefIndex>,
+}
+
+impl DefPathTable {
+    fn insert(&mut self, key: DefKey) -> DefIndex {
+        let index = DefIndex::new(self.index_to_key.len());
+        debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index);
+        self.index_to_key.push(key.clone());
+        self.key_to_index.insert(key, index);
+        index
+    }
+
+    #[inline(always)]
+    pub fn def_key(&self, index: DefIndex) -> DefKey {
+        self.index_to_key[index.as_usize()].clone()
+    }
+
+    #[inline(always)]
+    pub fn def_index_for_def_key(&self, key: &DefKey) -> Option<DefIndex> {
+        self.key_to_index.get(key).cloned()
+    }
+
+    #[inline(always)]
+    pub fn contains_key(&self, key: &DefKey) -> bool {
+        self.key_to_index.contains_key(key)
+    }
+
+    pub fn retrace_path(&self,
+                        path_data: &[DisambiguatedDefPathData])
+                        -> Option<DefIndex> {
+        let root_key = DefKey {
+            parent: None,
+            disambiguated_data: DisambiguatedDefPathData {
+                data: DefPathData::CrateRoot,
+                disambiguator: 0,
+            },
+        };
+
+        let root_index = self.key_to_index
+                             .get(&root_key)
+                             .expect("no root key?")
+                             .clone();
+
+        debug!("retrace_path: root_index={:?}", root_index);
+
+        let mut index = root_index;
+        for data in path_data {
+            let key = DefKey { parent: Some(index), disambiguated_data: data.clone() };
+            debug!("retrace_path: key={:?}", key);
+            match self.key_to_index.get(&key) {
+                Some(&i) => index = i,
+                None => return None,
+            }
+        }
+
+        Some(index)
+    }
+}
+
+
+impl Encodable for DefPathTable {
+    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        self.index_to_key.encode(s)
+    }
+}
+
+impl Decodable for DefPathTable {
+    fn decode<D: Decoder>(d: &mut D) -> Result<DefPathTable, D::Error> {
+        let index_to_key: Vec<DefKey> = Decodable::decode(d)?;
+        let key_to_index = index_to_key.iter()
+                                       .enumerate()
+                                       .map(|(index, key)| (key.clone(), DefIndex::new(index)))
+                                       .collect();
+        Ok(DefPathTable {
+            index_to_key: index_to_key,
+            key_to_index: key_to_index,
+        })
+    }
+}
+
+
+/// The definition table containing node definitions.
+/// It holds the DefPathTable for local DefIds/DefPaths and it also stores a
+/// mapping from NodeIds to local DefIds.
 #[derive(Clone)]
 pub struct Definitions {
-    data: Vec<DefData>,
-    key_map: FxHashMap<DefKey, DefIndex>,
-    node_map: NodeMap<DefIndex>,
+    table: DefPathTable,
+    node_to_def_index: NodeMap<DefIndex>,
+    def_index_to_node: Vec<ast::NodeId>,
 }
 
 /// A unique identifier that we can use to lookup a definition
@@ -50,19 +147,6 @@ pub struct DisambiguatedDefPathData {
     pub disambiguator: u32
 }
 
-/// For each definition, we track the following data.  A definition
-/// here is defined somewhat circularly as "something with a def-id",
-/// but it generally corresponds to things like structs, enums, etc.
-/// There are also some rather random cases (like const initializer
-/// expressions) that are mostly just leftovers.
-#[derive(Clone, Debug)]
-pub struct DefData {
-    pub key: DefKey,
-
-    /// Local ID within the HIR.
-    pub node_id: ast::NodeId,
-}
-
 #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct DefPath {
     /// the path leading from the crate root to the item
@@ -77,12 +161,11 @@ impl DefPath {
         self.krate == LOCAL_CRATE
     }
 
-    pub fn make<FN>(start_krate: CrateNum,
+    pub fn make<FN>(krate: CrateNum,
                     start_index: DefIndex,
                     mut get_key: FN) -> DefPath
         where FN: FnMut(DefIndex) -> DefKey
     {
-        let mut krate = start_krate;
         let mut data = vec![];
         let mut index = Some(start_index);
         loop {
@@ -95,13 +178,6 @@ impl DefPath {
                     assert!(key.parent.is_none());
                     break;
                 }
-                DefPathData::InlinedRoot(ref p) => {
-                    assert!(key.parent.is_none());
-                    assert!(!p.def_id.is_local());
-                    data.extend(p.data.iter().cloned().rev());
-                    krate = p.def_id.krate;
-                    break;
-                }
                 _ => {
                     data.push(key.disambiguated_data);
                     index = key.parent;
@@ -131,7 +207,8 @@ impl DefPath {
     }
 
     pub fn deterministic_hash(&self, tcx: TyCtxt) -> u64 {
-        let mut state = DefaultHasher::new();
+        debug!("deterministic_hash({:?})", self);
+        let mut state = StableHasher::new();
         self.deterministic_hash_to(tcx, &mut state);
         state.finish()
     }
@@ -143,31 +220,6 @@ impl DefPath {
     }
 }
 
-/// Root of an inlined item. We track the `DefPath` of the item within
-/// the original crate but also its def-id. This is kind of an
-/// augmented version of a `DefPath` that includes a `DefId`. This is
-/// all sort of ugly but the hope is that inlined items will be going
-/// away soon anyway.
-///
-/// Some of the constraints that led to the current approach:
-///
-/// - I don't want to have a `DefId` in the main `DefPath` because
-///   that gets serialized for incr. comp., and when reloaded the
-///   `DefId` is no longer valid. I'd rather maintain the invariant
-///   that every `DefId` is valid, and a potentially outdated `DefId` is
-///   represented as a `DefPath`.
-///   - (We don't serialize def-paths from inlined items, so it's ok to have one here.)
-/// - We need to be able to extract the def-id from inline items to
-///   make the symbol name. In theory we could retrace it from the
-///   data, but the metadata doesn't have the required indices, and I
-///   don't want to write the code to create one just for this.
-/// - It may be that we don't actually need `data` at all. We'll have
-///   to see about that.
-#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
-pub struct InlinedRootPath {
-    pub data: Vec<DisambiguatedDefPathData>,
-    pub def_id: DefId,
-}
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub enum DefPathData {
@@ -175,8 +227,6 @@ pub enum DefPathData {
     // they are treated specially by the `def_path` function.
     /// The crate root (marker)
     CrateRoot,
-    /// An inlined root
-    InlinedRoot(Box<InlinedRootPath>),
 
     // Catch-all for random DefId things like DUMMY_NODE_ID
     Misc,
@@ -218,23 +268,30 @@ impl Definitions {
     /// Create new empty definition map.
     pub fn new() -> Definitions {
         Definitions {
-            data: vec![],
-            key_map: FxHashMap(),
-            node_map: NodeMap(),
+            table: DefPathTable {
+                index_to_key: vec![],
+                key_to_index: FxHashMap(),
+            },
+            node_to_def_index: NodeMap(),
+            def_index_to_node: vec![],
         }
     }
 
+    pub fn def_path_table(&self) -> &DefPathTable {
+        &self.table
+    }
+
     /// Get the number of definitions.
     pub fn len(&self) -> usize {
-        self.data.len()
+        self.def_index_to_node.len()
     }
 
     pub fn def_key(&self, index: DefIndex) -> DefKey {
-        self.data[index.as_usize()].key.clone()
+        self.table.def_key(index)
     }
 
     pub fn def_index_for_def_key(&self, key: DefKey) -> Option<DefIndex> {
-        self.key_map.get(&key).cloned()
+        self.table.def_index_for_def_key(&key)
     }
 
     /// Returns the path from the crate root to `index`. The root
@@ -247,7 +304,7 @@ impl Definitions {
     }
 
     pub fn opt_def_index(&self, node: ast::NodeId) -> Option<DefIndex> {
-        self.node_map.get(&node).cloned()
+        self.node_to_def_index.get(&node).cloned()
     }
 
     pub fn opt_local_def_id(&self, node: ast::NodeId) -> Option<DefId> {
@@ -260,8 +317,8 @@ impl Definitions {
 
     pub fn as_local_node_id(&self, def_id: DefId) -> Option<ast::NodeId> {
         if def_id.krate == LOCAL_CRATE {
-            assert!(def_id.index.as_usize() < self.data.len());
-            Some(self.data[def_id.index.as_usize()].node_id)
+            assert!(def_id.index.as_usize() < self.def_index_to_node.len());
+            Some(self.def_index_to_node[def_id.index.as_usize()])
         } else {
             None
         }
@@ -276,16 +333,13 @@ impl Definitions {
         debug!("create_def_with_parent(parent={:?}, node_id={:?}, data={:?})",
                parent, node_id, data);
 
-        assert!(!self.node_map.contains_key(&node_id),
+        assert!(!self.node_to_def_index.contains_key(&node_id),
                 "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
                 node_id,
                 data,
-                self.data[self.node_map[&node_id].as_usize()]);
+                self.table.def_key(self.node_to_def_index[&node_id]));
 
-        assert!(parent.is_some() ^ match data {
-            DefPathData::CrateRoot | DefPathData::InlinedRoot(_) => true,
-            _ => false,
-        });
+        assert!(parent.is_some() ^ (data == DefPathData::CrateRoot));
 
         // Find a unique DefKey. This basically means incrementing the disambiguator
         // until we get no match.
@@ -297,20 +351,18 @@ impl Definitions {
             }
         };
 
-        while self.key_map.contains_key(&key) {
+        while self.table.contains_key(&key) {
             key.disambiguated_data.disambiguator += 1;
         }
 
         debug!("create_def_with_parent: after disambiguation, key = {:?}", key);
 
         // Create the definition.
-        let index = DefIndex::new(self.data.len());
-        self.data.push(DefData { key: key.clone(), node_id: node_id });
-        debug!("create_def_with_parent: node_map[{:?}] = {:?}", node_id, index);
-        self.node_map.insert(node_id, index);
-        debug!("create_def_with_parent: key_map[{:?}] = {:?}", key, index);
-        self.key_map.insert(key, index);
-
+        let index = self.table.insert(key);
+        debug!("create_def_with_parent: def_index_to_node[{:?} <-> {:?}", index, node_id);
+        self.node_to_def_index.insert(node_id, index);
+        assert_eq!(index.as_usize(), self.def_index_to_node.len());
+        self.def_index_to_node.push(node_id);
 
         index
     }
@@ -332,7 +384,6 @@ impl DefPathData {
 
             Impl |
             CrateRoot |
-            InlinedRoot(_) |
             Misc |
             ClosureExpr |
             StructCtor |
@@ -359,9 +410,6 @@ impl DefPathData {
             // note that this does not show up in user printouts
             CrateRoot => "{{root}}",
 
-            // note that this does not show up in user printouts
-            InlinedRoot(_) => "{{inlined-root}}",
-
             Impl => "{{impl}}",
             Misc => "{{?}}",
             ClosureExpr => "{{closure}}",
@@ -377,4 +425,3 @@ impl DefPathData {
         self.as_interned_str().to_string()
     }
 }
-
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 117edcf14a1..4546f6d8c27 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -13,7 +13,7 @@ use self::MapEntry::*;
 use self::collector::NodeCollector;
 pub use self::def_collector::{DefCollector, MacroInvocationData};
 pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
-                            DisambiguatedDefPathData, InlinedRootPath};
+                            DisambiguatedDefPathData};
 
 use dep_graph::{DepGraph, DepNode};
 
@@ -221,22 +221,14 @@ pub struct Map<'ast> {
     /// plain old integers.
     map: RefCell<Vec<MapEntry<'ast>>>,
 
-    definitions: RefCell<Definitions>,
+    definitions: Definitions,
 
     /// All NodeIds that are numerically greater or equal to this value come
     /// from inlined items.
     local_node_id_watermark: NodeId,
-
-    /// All def-indices that are numerically greater or equal to this value come
-    /// from inlined items.
-    local_def_id_watermark: usize,
 }
 
 impl<'ast> Map<'ast> {
-    pub fn is_inlined_def_id(&self, id: DefId) -> bool {
-        id.is_local() && id.index.as_usize() >= self.local_def_id_watermark
-    }
-
     pub fn is_inlined_node_id(&self, id: NodeId) -> bool {
         id >= self.local_node_id_watermark
     }
@@ -262,7 +254,6 @@ impl<'ast> Map<'ast> {
                     EntryItem(_, item) => {
                         assert_eq!(id, item.id);
                         let def_id = self.local_def_id(id);
-                        assert!(!self.is_inlined_def_id(def_id));
 
                         if let Some(last_id) = last_expr {
                             // The body of the item may have a separate dep node
@@ -278,7 +269,6 @@ impl<'ast> Map<'ast> {
 
                     EntryImplItem(_, item) => {
                         let def_id = self.local_def_id(id);
-                        assert!(!self.is_inlined_def_id(def_id));
 
                         if let Some(last_id) = last_expr {
                             // The body of the item may have a separate dep node
@@ -392,12 +382,16 @@ impl<'ast> Map<'ast> {
     }
 
     pub fn num_local_def_ids(&self) -> usize {
-        self.definitions.borrow().len()
+        self.definitions.len()
+    }
+
+    pub fn definitions(&self) -> &Definitions {
+        &self.definitions
     }
 
     pub fn def_key(&self, def_id: DefId) -> DefKey {
         assert!(def_id.is_local());
-        self.definitions.borrow().def_key(def_id.index)
+        self.definitions.def_key(def_id.index)
     }
 
     pub fn def_path_from_id(&self, id: NodeId) -> Option<DefPath> {
@@ -408,11 +402,11 @@ impl<'ast> Map<'ast> {
 
     pub fn def_path(&self, def_id: DefId) -> DefPath {
         assert!(def_id.is_local());
-        self.definitions.borrow().def_path(def_id.index)
+        self.definitions.def_path(def_id.index)
     }
 
     pub fn def_index_for_def_key(&self, def_key: DefKey) -> Option<DefIndex> {
-        self.definitions.borrow().def_index_for_def_key(def_key)
+        self.definitions.def_index_for_def_key(def_key)
     }
 
     pub fn local_def_id(&self, node: NodeId) -> DefId {
@@ -423,11 +417,11 @@ impl<'ast> Map<'ast> {
     }
 
     pub fn opt_local_def_id(&self, node: NodeId) -> Option<DefId> {
-        self.definitions.borrow().opt_local_def_id(node)
+        self.definitions.opt_local_def_id(node)
     }
 
     pub fn as_local_node_id(&self, def_id: DefId) -> Option<NodeId> {
-        self.definitions.borrow().as_local_node_id(def_id)
+        self.definitions.as_local_node_id(def_id)
     }
 
     fn entry_count(&self) -> usize {
@@ -930,23 +924,19 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest,
     }
 
     let local_node_id_watermark = NodeId::new(map.len());
-    let local_def_id_watermark = definitions.len();
 
     Map {
         forest: forest,
         dep_graph: forest.dep_graph.clone(),
         map: RefCell::new(map),
-        definitions: RefCell::new(definitions),
+        definitions: definitions,
         local_node_id_watermark: local_node_id_watermark,
-        local_def_id_watermark: local_def_id_watermark,
     }
 }
 
 /// Used for items loaded from external crate that are being inlined into this
 /// crate.
 pub fn map_decoded_item<'ast>(map: &Map<'ast>,
-                              parent_def_path: DefPath,
-                              parent_def_id: DefId,
                               ii: InlinedItem,
                               ii_parent_id: NodeId)
                               -> &'ast InlinedItem {
@@ -954,18 +944,9 @@ pub fn map_decoded_item<'ast>(map: &Map<'ast>,
 
     let ii = map.forest.inlined_items.alloc(ii);
 
-    let defs = &mut *map.definitions.borrow_mut();
-    let mut def_collector = DefCollector::extend(ii_parent_id,
-                                                 parent_def_path.clone(),
-                                                 parent_def_id,
-                                                 defs);
-    def_collector.walk_item(ii, map.krate());
-
     let mut collector = NodeCollector::extend(map.krate(),
                                               ii,
                                               ii_parent_id,
-                                              parent_def_path,
-                                              parent_def_id,
                                               mem::replace(&mut *map.map.borrow_mut(), vec![]));
     ii.visit(&mut collector);
     *map.map.borrow_mut() = collector.map;
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 4fd8f96ba04..4eee76d466a 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -105,15 +105,18 @@ pub struct LifetimeDef {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
 pub struct Path {
     pub span: Span,
-    /// A `::foo` path, is relative to the crate root rather than current
-    /// module (like paths in an import).
-    pub global: bool,
     /// The definition that the path resolved to.
     pub def: Def,
     /// The segments in the path: the things separated by `::`.
     pub segments: HirVec<PathSegment>,
 }
 
+impl Path {
+    pub fn is_global(&self) -> bool {
+        !self.segments.is_empty() && self.segments[0].name == keywords::CrateRoot.name()
+    }
+}
+
 impl fmt::Debug for Path {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "path({})", print::path_to_string(self))
@@ -475,8 +478,6 @@ pub struct MacroDef {
     pub attrs: HirVec<Attribute>,
     pub id: NodeId,
     pub span: Span,
-    pub imported_from: Option<Name>,
-    pub allow_internal_unstable: bool,
     pub body: HirVec<TokenTree>,
 }
 
@@ -1533,8 +1534,6 @@ pub struct ItemId {
     pub id: NodeId,
 }
 
-//  FIXME (#3300): Should allow items to be anonymous. Right now
-//  we just use dummy names for anon items.
 /// An item
 ///
 /// The name might be a dummy name in case of anonymous items
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 74920b13280..100e344d941 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -1643,17 +1643,14 @@ impl<'a> State<'a> {
                   -> io::Result<()> {
         self.maybe_print_comment(path.span.lo)?;
 
-        let mut first = !path.global;
-        for segment in &path.segments {
-            if first {
-                first = false
-            } else {
+        for (i, segment) in path.segments.iter().enumerate() {
+            if i > 0 {
                 word(&mut self.s, "::")?
             }
-
-            self.print_name(segment.name)?;
-
-            self.print_path_parameters(&segment.parameters, colons_before_params)?;
+            if segment.name != keywords::CrateRoot.name() && segment.name != "$crate" {
+                self.print_name(segment.name)?;
+                self.print_path_parameters(&segment.parameters, colons_before_params)?;
+            }
         }
 
         Ok(())
@@ -1673,15 +1670,14 @@ impl<'a> State<'a> {
                 space(&mut self.s)?;
                 self.word_space("as")?;
 
-                let mut first = !path.global;
-                for segment in &path.segments[..path.segments.len() - 1] {
-                    if first {
-                        first = false
-                    } else {
+                for (i, segment) in path.segments[..path.segments.len() - 1].iter().enumerate() {
+                    if i > 0 {
                         word(&mut self.s, "::")?
                     }
-                    self.print_name(segment.name)?;
-                    self.print_path_parameters(&segment.parameters, colons_before_params)?;
+                    if segment.name != keywords::CrateRoot.name() && segment.name != "$crate" {
+                        self.print_name(segment.name)?;
+                        self.print_path_parameters(&segment.parameters, colons_before_params)?;
+                    }
                 }
 
                 word(&mut self.s, ">")?;
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index 90d752ae6ee..9d48fbca53e 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -1620,7 +1620,6 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
         new_segs.push(new_seg);
         hir::Path {
             span: path.span,
-            global: path.global,
             def: path.def,
             segments: new_segs.into()
         }
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 9b58334e658..3e7cc0b1e3e 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1367,9 +1367,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                    cause: &ObligationCause<'tcx>,
                                    expected: Ty<'tcx>,
                                    actual: Ty<'tcx>,
-                                   err: TypeError<'tcx>) {
+                                   err: TypeError<'tcx>)
+                                   -> DiagnosticBuilder<'tcx> {
         let trace = TypeTrace::types(cause, true, expected, actual);
-        self.report_and_explain_type_error(trace, &err).emit();
+        self.report_and_explain_type_error(trace, &err)
     }
 
     pub fn report_conflicting_default_types(&self,
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 7c26b710a53..17cc34fcd83 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -24,7 +24,6 @@
 #![cfg_attr(not(stage0), deny(warnings))]
 
 #![feature(associated_consts)]
-#![feature(borrow_state)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(collections)]
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 02c1ece1634..667c2590fa9 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -212,6 +212,12 @@ declare_lint! {
 }
 
 declare_lint! {
+    pub LEGACY_IMPORTS,
+    Warn,
+    "detects names that resolve to ambiguous glob imports with RFC 1560"
+}
+
+declare_lint! {
     pub DEPRECATED,
     Warn,
     "detects use of deprecated items"
@@ -257,6 +263,7 @@ impl LintPass for HardwiredLints {
             PATTERNS_IN_FNS_WITHOUT_BODY,
             EXTRA_REQUIREMENT_IN_IMPL,
             LEGACY_DIRECTORY_OWNERSHIP,
+            LEGACY_IMPORTS,
             DEPRECATED
         )
     }
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index f2be97c8323..d0003693eef 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -25,7 +25,7 @@
 use hir::def::{self, Def};
 use hir::def_id::{CrateNum, DefId, DefIndex};
 use hir::map as hir_map;
-use hir::map::definitions::{Definitions, DefKey};
+use hir::map::definitions::{Definitions, DefKey, DisambiguatedDefPathData};
 use hir::svh::Svh;
 use middle::lang_items;
 use ty::{self, Ty, TyCtxt};
@@ -298,8 +298,7 @@ pub trait CrateStore<'tcx> {
 
     // trait/impl-item info
     fn trait_of_item(&self, def_id: DefId) -> Option<DefId>;
-    fn associated_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                           -> Option<ty::AssociatedItem>;
+    fn associated_item(&self, def: DefId) -> Option<ty::AssociatedItem>;
 
     // flags
     fn is_const_fn(&self, did: DefId) -> bool;
@@ -336,12 +335,12 @@ pub trait CrateStore<'tcx> {
     fn is_no_builtins(&self, cnum: CrateNum) -> bool;
 
     // resolve
-    fn def_index_for_def_key(&self,
-                             cnum: CrateNum,
-                             def: DefKey)
-                             -> Option<DefIndex>;
-    fn def_key(&self, def: DefId) -> hir_map::DefKey;
-    fn relative_def_path(&self, def: DefId) -> Option<hir_map::DefPath>;
+    fn retrace_path(&self,
+                    cnum: CrateNum,
+                    path_data: &[DisambiguatedDefPathData])
+                    -> Option<DefId>;
+    fn def_key(&self, def: DefId) -> DefKey;
+    fn def_path(&self, def: DefId) -> hir_map::DefPath;
     fn struct_field_names(&self, def: DefId) -> Vec<ast::Name>;
     fn item_children(&self, did: DefId) -> Vec<def::Export>;
     fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro;
@@ -442,12 +441,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
 
     // trait info
     fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId> { vec![] }
-    fn def_index_for_def_key(&self,
-                             cnum: CrateNum,
-                             def: DefKey)
-                             -> Option<DefIndex> {
-        None
-    }
 
     // impl info
     fn associated_item_def_ids(&self, def_id: DefId) -> Vec<DefId>
@@ -462,8 +455,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
 
     // trait/impl-item info
     fn trait_of_item(&self, def_id: DefId) -> Option<DefId> { bug!("trait_of_item") }
-    fn associated_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                           -> Option<ty::AssociatedItem> { bug!("associated_item") }
+    fn associated_item(&self, def: DefId) -> Option<ty::AssociatedItem> { bug!("associated_item") }
 
     // flags
     fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") }
@@ -508,8 +500,15 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     fn is_no_builtins(&self, cnum: CrateNum) -> bool { bug!("is_no_builtins") }
 
     // resolve
-    fn def_key(&self, def: DefId) -> hir_map::DefKey { bug!("def_key") }
-    fn relative_def_path(&self, def: DefId) -> Option<hir_map::DefPath> {
+    fn retrace_path(&self,
+                    cnum: CrateNum,
+                    path_data: &[DisambiguatedDefPathData])
+                    -> Option<DefId> {
+        None
+    }
+
+    fn def_key(&self, def: DefId) -> DefKey { bug!("def_key") }
+    fn def_path(&self, def: DefId) -> hir_map::DefPath {
         bug!("relative_def_path")
     }
     fn struct_field_names(&self, def: DefId) -> Vec<ast::Name> { bug!("struct_field_names") }
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 1bf6b837fd9..1c5dd97b74b 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -86,20 +86,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
         }
     }
 
-    fn handle_definition(&mut self, id: ast::NodeId, def: Def) {
-        // If `bar` is a trait item, make sure to mark Foo as alive in `Foo::bar`
-        match def {
-            Def::AssociatedTy(..) | Def::Method(_) | Def::AssociatedConst(_)
-            if self.tcx.trait_of_item(def.def_id()).is_some() => {
-                if let Some(substs) = self.tcx.tables().item_substs.get(&id) {
-                    if let ty::TyAdt(tyid, _) = substs.substs.type_at(0).sty {
-                        self.check_def_id(tyid.did);
-                    }
-                }
-            }
-            _ => {}
-        }
-
+    fn handle_definition(&mut self, def: Def) {
         match def {
             Def::Const(_) | Def::AssociatedConst(..) => {
                 self.check_def_id(def.def_id());
@@ -241,7 +228,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
         match expr.node {
             hir::ExprPath(ref qpath @ hir::QPath::TypeRelative(..)) => {
                 let def = self.tcx.tables().qpath_def(qpath, expr.id);
-                self.handle_definition(expr.id, def);
+                self.handle_definition(def);
             }
             hir::ExprMethodCall(..) => {
                 self.lookup_and_handle_method(expr.id);
@@ -281,7 +268,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
             }
             PatKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) => {
                 let def = self.tcx.tables().qpath_def(qpath, pat.id);
-                self.handle_definition(pat.id, def);
+                self.handle_definition(def);
             }
             _ => ()
         }
@@ -291,8 +278,8 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
         self.ignore_non_const_paths = false;
     }
 
-    fn visit_path(&mut self, path: &'tcx hir::Path, id: ast::NodeId) {
-        self.handle_definition(id, path.def);
+    fn visit_path(&mut self, path: &'tcx hir::Path, _: ast::NodeId) {
+        self.handle_definition(path.def);
         intravisit::walk_path(self, path);
     }
 }
@@ -426,6 +413,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
             hir::ItemStatic(..)
             | hir::ItemConst(..)
             | hir::ItemFn(..)
+            | hir::ItemTy(..)
             | hir::ItemEnum(..)
             | hir::ItemStruct(..)
             | hir::ItemUnion(..) => true,
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 1efc211b8c3..029a1d66add 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -328,7 +328,6 @@ language_item_table! {
     PanicFmtLangItem,                "panic_fmt",               panic_fmt;
 
     ExchangeMallocFnLangItem,        "exchange_malloc",         exchange_malloc_fn;
-    ExchangeFreeFnLangItem,          "exchange_free",           exchange_free_fn;
     BoxFreeFnLangItem,               "box_free",                box_free_fn;
     StrDupUniqFnLangItem,            "strdup_uniq",             strdup_uniq_fn;
 
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 3e32957aecf..f45e86f2f4b 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -302,9 +302,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
     }
 
     fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) {
-        if md.imported_from.is_none() {
-            self.annotate(md.id, &md.attrs, md.span, AnnotationKind::Required, |_| {});
-        }
+        self.annotate(md.id, &md.attrs, md.span, AnnotationKind::Required, |_| {});
     }
 }
 
@@ -373,9 +371,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'a, 'tcx> {
     }
 
     fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) {
-        if md.imported_from.is_none() {
-            self.check_missing_stability(md.id, md.span);
-        }
+        self.check_missing_stability(md.id, md.span);
     }
 }
 
diff --git a/src/librustc/session/code_stats.rs b/src/librustc/session/code_stats.rs
index 8308c54d70b..a042b2abf3a 100644
--- a/src/librustc/session/code_stats.rs
+++ b/src/librustc/session/code_stats.rs
@@ -142,7 +142,12 @@ impl CodeStats {
                 max_variant_size = cmp::max(max_variant_size, size);
 
                 let mut min_offset = discr_size;
-                for field in fields {
+
+                // We want to print fields by increasing offset.
+                let mut fields = fields.clone();
+                fields.sort_by_key(|f| f.offset);
+
+                for field in fields.iter() {
                     let FieldInfo { ref name, offset, size, align } = *field;
 
                     // Include field alignment in output only if it caused padding injection
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index e500c08ce6e..ecc8042e940 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -928,6 +928,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
           "print some statistics about MIR"),
     always_encode_mir: bool = (false, parse_bool, [TRACKED],
           "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"),
 }
 
 pub fn default_lib_output() -> CrateType {
@@ -943,26 +945,20 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
     let vendor = &sess.target.target.target_vendor;
     let max_atomic_width = sess.target.target.max_atomic_width();
 
-    let fam = if let Some(ref fam) = sess.target.target.options.target_family {
-        Symbol::intern(fam)
-    } else if sess.target.target.options.is_like_windows {
-        Symbol::intern("windows")
-    } else {
-        Symbol::intern("unix")
-    };
-
     let mut ret = HashSet::new();
     // Target bindings.
     ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
-    ret.insert((Symbol::intern("target_family"), Some(fam)));
+    if let Some(ref fam) = sess.target.target.options.target_family {
+        ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
+        if fam == "windows" || fam == "unix" {
+            ret.insert((Symbol::intern(fam), None));
+        }
+    }
     ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
     ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
     ret.insert((Symbol::intern("target_pointer_width"), Some(Symbol::intern(wordsz))));
     ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
     ret.insert((Symbol::intern("target_vendor"), Some(Symbol::intern(vendor))));
-    if fam == "windows" || fam == "unix" {
-        ret.insert((fam, None));
-    }
     if sess.target.target.options.has_elf_tls {
         ret.insert((Symbol::intern("target_thread_local"), None));
     }
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 91765e68ae6..36a887e0622 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -136,6 +136,8 @@ pub struct PerfStats {
     pub incr_comp_bytes_hashed: Cell<u64>,
     // The accumulated time spent on computing symbol hashes
     pub symbol_hash_time: Cell<Duration>,
+    // The accumulated time spent decoding def path tables from metadata
+    pub decode_def_path_tables_time: Cell<Duration>,
 }
 
 impl Session {
@@ -501,6 +503,8 @@ impl Session {
                  self.perf_stats.incr_comp_hashes_count.get());
         println!("Total time spent computing symbol hashes:      {}",
                  duration_to_secs_str(self.perf_stats.symbol_hash_time.get()));
+        println!("Total time spent decoding DefPath tables:      {}",
+                 duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get()));
     }
 }
 
@@ -635,6 +639,7 @@ pub fn build_session_(sopts: config::Options,
             incr_comp_hashes_count: Cell::new(0),
             incr_comp_bytes_hashed: Cell::new(0),
             symbol_hash_time: Cell::new(Duration::from_secs(0)),
+            decode_def_path_tables_time: Cell::new(Duration::from_secs(0)),
         },
         code_stats: RefCell::new(CodeStats::new()),
     };
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 0c0d0c010e2..ab8c552d561 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -458,11 +458,28 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         err
     }
 
+
+    /// Get the parent trait chain start
+    fn get_parent_trait_ref(&self, code: &ObligationCauseCode<'tcx>) -> Option<String> {
+        match code {
+            &ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
+                let parent_trait_ref = self.resolve_type_vars_if_possible(
+                    &data.parent_trait_ref);
+                match self.get_parent_trait_ref(&data.parent_code) {
+                    Some(t) => Some(t),
+                    None => Some(format!("{}", parent_trait_ref.0.self_ty())),
+                }
+            }
+            _ => None,
+        }
+    }
+
     pub fn report_selection_error(&self,
                                   obligation: &PredicateObligation<'tcx>,
                                   error: &SelectionError<'tcx>)
     {
         let span = obligation.cause.span;
+
         let mut err = match *error {
             SelectionError::Unimplemented => {
                 if let ObligationCauseCode::CompareImplMethodObligation {
@@ -487,14 +504,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                 return;
                             } else {
                                 let trait_ref = trait_predicate.to_poly_trait_ref();
-
-                                let mut err = struct_span_err!(self.tcx.sess, span, E0277,
-                                    "the trait bound `{}` is not satisfied",
-                                    trait_ref.to_predicate());
-                                err.span_label(span, &format!("the trait `{}` is not implemented \
-                                                               for `{}`",
-                                                              trait_ref,
-                                                              trait_ref.self_ty()));
+                                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
 
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 4854a14f733..f24ff980355 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -15,9 +15,9 @@ use session::Session;
 use middle;
 use hir::TraitMap;
 use hir::def::Def;
-use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
+use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use hir::map as ast_map;
-use hir::map::{DefKey, DefPathData, DisambiguatedDefPathData};
+use hir::map::DisambiguatedDefPathData;
 use middle::free_region::FreeRegionMap;
 use middle::region::RegionMaps;
 use middle::resolve_lifetime;
@@ -627,50 +627,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    /// Given a def-key `key` and a crate `krate`, finds the def-index
-    /// that `krate` assigned to `key`. This `DefIndex` will always be
-    /// relative to `krate`.
-    ///
-    /// Returns `None` if there is no `DefIndex` with that key.
-    pub fn def_index_for_def_key(self, krate: CrateNum, key: DefKey)
-                                 -> Option<DefIndex> {
-        if krate == LOCAL_CRATE {
-            self.map.def_index_for_def_key(key)
-        } else {
-            self.sess.cstore.def_index_for_def_key(krate, key)
-        }
-    }
-
     pub fn retrace_path(self,
                         krate: CrateNum,
                         path_data: &[DisambiguatedDefPathData])
                         -> Option<DefId> {
         debug!("retrace_path(path={:?}, krate={:?})", path_data, self.crate_name(krate));
 
-        let root_key = DefKey {
-            parent: None,
-            disambiguated_data: DisambiguatedDefPathData {
-                data: DefPathData::CrateRoot,
-                disambiguator: 0,
-            },
-        };
-
-        let root_index = self.def_index_for_def_key(krate, root_key)
-                             .expect("no root key?");
-
-        debug!("retrace_path: root_index={:?}", root_index);
-
-        let mut index = root_index;
-        for data in path_data {
-            let key = DefKey { parent: Some(index), disambiguated_data: data.clone() };
-            debug!("retrace_path: key={:?}", key);
-            match self.def_index_for_def_key(krate, key) {
-                Some(i) => index = i,
-                None => return None,
-            }
+        if krate == LOCAL_CRATE {
+            self.map
+                .definitions()
+                .def_path_table()
+                .retrace_path(path_data)
+                .map(|def_index| DefId { krate: krate, index: def_index })
+        } else {
+            self.sess.cstore.retrace_path(krate, path_data)
         }
-
-        Some(DefId { krate: krate, index: index })
     }
 
     pub fn type_parameter_def(self,
@@ -762,11 +733,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// reference to the context, to allow formatting values that need it.
     pub fn create_and_enter<F, R>(s: &'tcx Session,
                                   arenas: &'tcx CtxtArenas<'tcx>,
-                                  trait_map: TraitMap,
+                                  resolutions: ty::Resolutions,
                                   named_region_map: resolve_lifetime::NamedRegionMap,
                                   map: ast_map::Map<'tcx>,
-                                  freevars: FreevarMap,
-                                 maybe_unused_trait_imports: NodeSet,
                                   region_maps: RegionMaps,
                                   lang_items: middle::lang_items::LanguageItems,
                                   stability: stability::Index<'tcx>,
@@ -790,7 +759,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             item_variance_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             variance_computed: Cell::new(false),
             sess: s,
-            trait_map: trait_map,
+            trait_map: resolutions.trait_map,
             tables: RefCell::new(Tables::empty()),
             impl_trait_refs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             trait_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
@@ -802,8 +771,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             fulfilled_predicates: RefCell::new(fulfilled_predicates),
             map: map,
             mir_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            freevars: RefCell::new(freevars),
-            maybe_unused_trait_imports: maybe_unused_trait_imports,
+            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()),
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index 440a3916786..0e4c14029e9 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -160,11 +160,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 self.push_krate_path(buffer, def_id.krate);
             }
 
-            DefPathData::InlinedRoot(ref root_path) => {
-                assert!(key.parent.is_none());
-                self.push_item_path(buffer, root_path.def_id);
-            }
-
             DefPathData::Impl => {
                 self.push_impl_path(buffer, def_id);
             }
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 8646bccf1e9..ebac30c8e50 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -24,6 +24,7 @@ use syntax_pos::DUMMY_SP;
 use std::cmp;
 use std::fmt;
 use std::i64;
+use std::iter;
 
 /// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout)
 /// for a target, which contains everything needed to compute layouts.
@@ -415,7 +416,7 @@ impl Integer {
     /// signed discriminant range and #[repr] attribute.
     /// N.B.: u64 values above i64::MAX will be treated as signed, but
     /// that shouldn't affect anything, other than maybe debuginfo.
-    pub fn repr_discr(tcx: TyCtxt, ty: Ty, hint: attr::ReprAttr, min: i64, max: i64)
+    fn repr_discr(tcx: TyCtxt, ty: Ty, hints: &[attr::ReprAttr], min: i64, max: i64)
                       -> (Integer, bool) {
         // Theoretically, negative values could be larger in unsigned representation
         // than the unsigned representation of the signed minimum. However, if there
@@ -424,34 +425,41 @@ impl Integer {
         let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u64, max as u64));
         let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max));
 
-        let at_least = match hint {
-            attr::ReprInt(ity) => {
-                let discr = Integer::from_attr(&tcx.data_layout, ity);
-                let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
-                if discr < fit {
-                    bug!("Integer::repr_discr: `#[repr]` hint too small for \
-                          discriminant range of enum `{}", ty)
+        let mut min_from_extern = None;
+        let min_default = I8;
+
+        for &r in hints.iter() {
+            match r {
+                attr::ReprInt(ity) => {
+                    let discr = Integer::from_attr(&tcx.data_layout, ity);
+                    let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
+                    if discr < fit {
+                        bug!("Integer::repr_discr: `#[repr]` hint too small for \
+                              discriminant range of enum `{}", ty)
+                    }
+                    return (discr, ity.is_signed());
                 }
-                return (discr, ity.is_signed());
-            }
-            attr::ReprExtern => {
-                match &tcx.sess.target.target.arch[..] {
-                    // WARNING: the ARM EABI has two variants; the one corresponding
-                    // to `at_least == I32` appears to be used on Linux and NetBSD,
-                    // but some systems may use the variant corresponding to no
-                    // lower bound.  However, we don't run on those yet...?
-                    "arm" => I32,
-                    _ => I32,
+                attr::ReprExtern => {
+                    match &tcx.sess.target.target.arch[..] {
+                        // WARNING: the ARM EABI has two variants; the one corresponding
+                        // to `at_least == I32` appears to be used on Linux and NetBSD,
+                        // but some systems may use the variant corresponding to no
+                        // lower bound.  However, we don't run on those yet...?
+                        "arm" => min_from_extern = Some(I32),
+                        _ => min_from_extern = Some(I32),
+                    }
+                }
+                attr::ReprAny => {},
+                attr::ReprPacked => {
+                    bug!("Integer::repr_discr: found #[repr(packed)] on enum `{}", ty);
+                }
+                attr::ReprSimd => {
+                    bug!("Integer::repr_discr: found #[repr(simd)] on enum `{}", ty);
                 }
             }
-            attr::ReprAny => I8,
-            attr::ReprPacked => {
-                bug!("Integer::repr_discr: found #[repr(packed)] on enum `{}", ty);
-            }
-            attr::ReprSimd => {
-                bug!("Integer::repr_discr: found #[repr(simd)] on enum `{}", ty);
-            }
-        };
+        }
+
+        let at_least = min_from_extern.unwrap_or(min_default);
 
         // If there are no negative values, we can use the unsigned fit.
         if min >= 0 {
@@ -511,70 +519,162 @@ pub struct Struct {
     /// If true, the size is exact, otherwise it's only a lower bound.
     pub sized: bool,
 
-    /// Offsets for the first byte of each field.
+    /// Offsets for the first byte of each field, ordered to match the source definition order.
+    /// This vector does not go in increasing order.
     /// FIXME(eddyb) use small vector optimization for the common case.
     pub offsets: Vec<Size>,
 
+    /// Maps source order field indices to memory order indices, depending how fields were permuted.
+    /// FIXME (camlorn) also consider small vector  optimization here.
+    pub memory_index: Vec<u32>,
+
     pub min_size: Size,
 }
 
+// Info required to optimize struct layout.
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
+enum StructKind {
+    // A tuple, closure, or univariant which cannot be coerced to unsized.
+    AlwaysSizedUnivariant,
+    // A univariant, the last field of which may be coerced to unsized.
+    MaybeUnsizedUnivariant,
+    // A univariant, but part of an enum.
+    EnumVariant,
+}
+
 impl<'a, 'gcx, 'tcx> Struct {
-    pub fn new(dl: &TargetDataLayout, packed: bool) -> Struct {
-        Struct {
+    // FIXME(camlorn): reprs need a better representation to deal with multiple reprs on one type.
+    fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
+                  reprs: &[attr::ReprAttr], kind: StructKind,
+                  scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
+        let packed = reprs.contains(&attr::ReprPacked);
+        let mut ret = Struct {
             align: if packed { dl.i8_align } else { dl.aggregate_align },
             packed: packed,
             sized: true,
             offsets: vec![],
+            memory_index: vec![],
             min_size: Size::from_bytes(0),
+        };
+
+        // Anything with ReprExtern or ReprPacked doesn't optimize.
+        // Neither do  1-member and 2-member structs.
+        // In addition, code in trans assume that 2-element structs can become pairs.
+        // It's easier to just short-circuit here.
+        let mut can_optimize = fields.len() > 2 || StructKind::EnumVariant == kind;
+        if can_optimize {
+            // This exhaustive match makes new reprs force the adder to modify this function.
+            // Otherwise, things can silently break.
+            // Note the inversion, return true to stop optimizing.
+            can_optimize = !reprs.iter().any(|r| {
+                match *r {
+                    attr::ReprAny | attr::ReprInt(_) => false,
+                    attr::ReprExtern | attr::ReprPacked => true,
+                    attr::ReprSimd => bug!("Simd  vectors should be represented as layout::Vector")
+                }
+            });
         }
-    }
 
-    /// Extend the Struct with more fields.
-    pub fn extend<I>(&mut self, dl: &TargetDataLayout,
-                     fields: I,
-                     scapegoat: Ty<'gcx>)
-                     -> Result<(), LayoutError<'gcx>>
-    where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
-        self.offsets.reserve(fields.size_hint().0);
+        // Disable field reordering until we can decide what to do.
+        // The odd pattern here avoids a warning about the value never being read.
+        if can_optimize { can_optimize = false }
 
-        let mut offset = self.min_size;
+        let (optimize, sort_ascending) = match kind {
+            StructKind::AlwaysSizedUnivariant => (can_optimize, false),
+            StructKind::MaybeUnsizedUnivariant => (can_optimize, false),
+            StructKind::EnumVariant => {
+                assert!(fields.len() >= 1, "Enum variants must have discriminants.");
+                (can_optimize && fields[0].size(dl).bytes() == 1, true)
+            }
+        };
 
-        for field in fields {
-            if !self.sized {
-                bug!("Struct::extend: field #{} of `{}` comes after unsized field",
-                     self.offsets.len(), scapegoat);
+        ret.offsets = vec![Size::from_bytes(0); fields.len()];
+        let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect();
+
+        if optimize {
+            let start = if let StructKind::EnumVariant = kind { 1 } else { 0 };
+            let end = if let StructKind::MaybeUnsizedUnivariant = kind {
+                fields.len() - 1
+            } else {
+                fields.len()
+            };
+            if end > start {
+                let optimizing  = &mut inverse_memory_index[start..end];
+                if sort_ascending {
+                    optimizing.sort_by_key(|&x| fields[x as usize].align(dl).abi());
+                } else {
+                    optimizing.sort_by(| &a, &b | {
+                        let a = fields[a as usize].align(dl).abi();
+                        let b = fields[b as usize].align(dl).abi();
+                        b.cmp(&a)
+                    });
+                }
+            }
+        }
+
+        // inverse_memory_index holds field indices by increasing memory offset.
+        // That is, if field 5 has offset 0, the first element of inverse_memory_index is 5.
+        // We now write field offsets to the corresponding offset slot;
+        // field 5 with offset 0 puts 0 in offsets[5].
+        // At the bottom of this function, we use inverse_memory_index to produce memory_index.
+
+        if let StructKind::EnumVariant = kind {
+            assert_eq!(inverse_memory_index[0], 0,
+              "Enum variant discriminants must have the lowest offset.");
+        }
+
+        let mut offset = Size::from_bytes(0);
+
+        for i in inverse_memory_index.iter() {
+            let field = fields[*i as usize];
+            if !ret.sized {
+                bug!("Struct::new: field #{} of `{}` comes after unsized field",
+                     ret.offsets.len(), scapegoat);
             }
 
-            let field = field?;
             if field.is_unsized() {
-                self.sized = false;
+                ret.sized = false;
             }
 
             // Invariant: offset < dl.obj_size_bound() <= 1<<61
-            if !self.packed {
+            if !ret.packed {
                 let align = field.align(dl);
-                self.align = self.align.max(align);
+                ret.align = ret.align.max(align);
                 offset = offset.abi_align(align);
             }
 
-            self.offsets.push(offset);
-
-            debug!("Struct::extend offset: {:?} field: {:?} {:?}", offset, field, field.size(dl));
+            debug!("Struct::new offset: {:?} field: {:?} {:?}", offset, field, field.size(dl));
+            ret.offsets[*i as usize] = offset;
 
             offset = offset.checked_add(field.size(dl), dl)
                            .map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?;
         }
 
-        debug!("Struct::extend min_size: {:?}", offset);
 
-        self.min_size = offset;
+        debug!("Struct::new min_size: {:?}", offset);
+        ret.min_size = offset;
 
-        Ok(())
-    }
+        // As stated above, inverse_memory_index holds field indices by increasing offset.
+        // This makes it an already-sorted view of the offsets vec.
+        // To invert it, consider:
+        // If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0.
+        // Field 5 would be the first element, so memory_index is i:
+        // Note: if we didn't optimize, it's already right.
 
-    /// Get the size without trailing alignment padding.
+        if optimize {
+            ret.memory_index = vec![0; inverse_memory_index.len()];
 
-    /// Get the size with trailing aligment padding.
+            for i in 0..inverse_memory_index.len() {
+                ret.memory_index[inverse_memory_index[i] as usize]  = i as u32;
+            }
+        } else {
+            ret.memory_index = inverse_memory_index;
+        }
+
+        Ok(ret)
+    }
+
+    /// Get the size with trailing alignment padding.
     pub fn stride(&self) -> Size {
         self.min_size.abi_align(self.align)
     }
@@ -592,18 +692,45 @@ impl<'a, 'gcx, 'tcx> Struct {
         Ok(true)
     }
 
+    /// Get indices of the tys that made this struct by increasing offset.
+    #[inline]
+    pub fn field_index_by_increasing_offset<'b>(&'b self) -> impl iter::Iterator<Item=usize>+'b {
+        let mut inverse_small = [0u8; 64];
+        let mut inverse_big = vec![];
+        let use_small = self.memory_index.len() <= inverse_small.len();
+
+        // We have to write this logic twice in order to keep the array small.
+        if use_small {
+            for i in 0..self.memory_index.len() {
+                inverse_small[self.memory_index[i] as usize] = i as u8;
+            }
+        } else {
+            inverse_big = vec![0; self.memory_index.len()];
+            for i in 0..self.memory_index.len() {
+                inverse_big[self.memory_index[i] as usize] = i as u32;
+            }
+        }
+
+        (0..self.memory_index.len()).map(move |i| {
+            if use_small { inverse_small[i] as usize }
+            else { inverse_big[i] as usize }
+        })
+    }
+
     /// Find the path leading to a non-zero leaf field, starting from
     /// the given type and recursing through aggregates.
+    /// The tuple is `(path, source_path)`,
+    /// where `path` is in memory order and `source_path` in source order.
     // FIXME(eddyb) track value ranges and traverse already optimized enums.
-    pub fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                  ty: Ty<'gcx>)
-                                  -> Result<Option<FieldPath>, LayoutError<'gcx>> {
+    fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                               ty: Ty<'gcx>)
+                               -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>> {
         let tcx = infcx.tcx.global_tcx();
         match (ty.layout(infcx)?, &ty.sty) {
             (&Scalar { non_zero: true, .. }, _) |
-            (&CEnum { non_zero: true, .. }, _) => Ok(Some(vec![])),
+            (&CEnum { non_zero: true, .. }, _) => Ok(Some((vec![], vec![]))),
             (&FatPointer { non_zero: true, .. }, _) => {
-                Ok(Some(vec![FAT_PTR_ADDR as u32]))
+                Ok(Some((vec![FAT_PTR_ADDR as u32], vec![FAT_PTR_ADDR as u32])))
             }
 
             // Is this the NonZero lang item wrapping a pointer or integer type?
@@ -614,10 +741,11 @@ impl<'a, 'gcx, 'tcx> Struct {
                     // FIXME(eddyb) also allow floating-point types here.
                     Scalar { value: Int(_), non_zero: false } |
                     Scalar { value: Pointer, non_zero: false } => {
-                        Ok(Some(vec![0]))
+                        Ok(Some((vec![0], vec![0])))
                     }
                     FatPointer { non_zero: false, .. } => {
-                        Ok(Some(vec![FAT_PTR_ADDR as u32, 0]))
+                        let tmp = vec![FAT_PTR_ADDR as u32, 0];
+                        Ok(Some((tmp.clone(), tmp)))
                     }
                     _ => Ok(None)
                 }
@@ -625,27 +753,30 @@ impl<'a, 'gcx, 'tcx> Struct {
 
             // Perhaps one of the fields of this struct is non-zero
             // let's recurse and find out
-            (_, &ty::TyAdt(def, substs)) if def.is_struct() => {
-                Struct::non_zero_field_path(infcx, def.struct_variant().fields
+            (&Univariant { ref variant, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => {
+                Struct::non_zero_field_paths(infcx, def.struct_variant().fields
                                                       .iter().map(|field| {
                     field.ty(tcx, substs)
-                }))
+                }),
+                Some(&variant.memory_index[..]))
             }
 
             // Perhaps one of the upvars of this closure is non-zero
-            // Let's recurse and find out!
-            (_, &ty::TyClosure(def_id, ref substs)) => {
-                Struct::non_zero_field_path(infcx, substs.upvar_tys(def_id, tcx))
+            (&Univariant { ref variant, .. }, &ty::TyClosure(def, substs)) => {
+                let upvar_tys = substs.upvar_tys(def, tcx);
+                Struct::non_zero_field_paths(infcx, upvar_tys,
+                    Some(&variant.memory_index[..]))
             }
             // Can we use one of the fields in this tuple?
-            (_, &ty::TyTuple(tys)) => {
-                Struct::non_zero_field_path(infcx, tys.iter().cloned())
+            (&Univariant { ref variant, .. }, &ty::TyTuple(tys)) => {
+                Struct::non_zero_field_paths(infcx, tys.iter().cloned(),
+                    Some(&variant.memory_index[..]))
             }
 
             // Is this a fixed-size array of something non-zero
             // with at least one element?
             (_, &ty::TyArray(ety, d)) if d > 0 => {
-                Struct::non_zero_field_path(infcx, Some(ety).into_iter())
+                Struct::non_zero_field_paths(infcx, Some(ety).into_iter(), None)
             }
 
             (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => {
@@ -663,14 +794,23 @@ impl<'a, 'gcx, 'tcx> Struct {
 
     /// Find the path leading to a non-zero leaf field, starting from
     /// the given set of fields and recursing through aggregates.
-    pub fn non_zero_field_path<I>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                  fields: I)
-                                  -> Result<Option<FieldPath>, LayoutError<'gcx>>
+    /// Returns Some((path, source_path)) on success.
+    /// `path` is translated to memory order. `source_path` is not.
+    fn non_zero_field_paths<I>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                                  fields: I,
+                                  permutation: Option<&[u32]>)
+                                  -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>>
     where I: Iterator<Item=Ty<'gcx>> {
         for (i, ty) in fields.enumerate() {
-            if let Some(mut path) = Struct::non_zero_field_in_type(infcx, ty)? {
-                path.push(i as u32);
-                return Ok(Some(path));
+            if let Some((mut path, mut source_path)) = Struct::non_zero_field_in_type(infcx, ty)? {
+                source_path.push(i as u32);
+                let index = if let Some(p) = permutation {
+                    p[i] as usize
+                } else {
+                    i
+                };
+                path.push(index as u32);
+                return Ok(Some((path, source_path)));
             }
         }
         Ok(None)
@@ -723,7 +863,7 @@ impl<'a, 'gcx, 'tcx> Union {
         Ok(())
     }
 
-    /// Get the size with trailing aligment padding.
+    /// Get the size with trailing alignment padding.
     pub fn stride(&self) -> Size {
         self.min_size.abi_align(self.align)
     }
@@ -833,7 +973,9 @@ pub enum Layout {
         nndiscr: u64,
         nonnull: Struct,
         // N.B. There is a 0 at the start, for LLVM GEP through a pointer.
-        discrfield: FieldPath
+        discrfield: FieldPath,
+        // Like discrfield, but in source order. For debuginfo.
+        discrfield_source: FieldPath
     }
 }
 
@@ -887,6 +1029,7 @@ impl<'a, 'gcx, 'tcx> Layout {
         let dl = &tcx.data_layout;
         assert!(!ty.has_infer_types());
 
+
         let layout = match ty.sty {
             // Basic scalars.
             ty::TyBool => Scalar { value: Int(I1), non_zero: false },
@@ -908,7 +1051,11 @@ impl<'a, 'gcx, 'tcx> Layout {
             ty::TyFnPtr(_) => Scalar { value: Pointer, non_zero: true },
 
             // The never type.
-            ty::TyNever => Univariant { variant: Struct::new(dl, false), non_zero: false },
+            ty::TyNever => Univariant {
+                variant: Struct::new(dl, &vec![], &[],
+                  StructKind::AlwaysSizedUnivariant, ty)?,
+                non_zero: false
+            },
 
             // Potentially-fat pointers.
             ty::TyBox(pointee) |
@@ -959,27 +1106,36 @@ impl<'a, 'gcx, 'tcx> Layout {
             // Odd unit types.
             ty::TyFnDef(..) => {
                 Univariant {
-                    variant: Struct::new(dl, false),
+                    variant: Struct::new(dl, &vec![],
+                      &[], StructKind::AlwaysSizedUnivariant, ty)?,
                     non_zero: false
                 }
             }
             ty::TyDynamic(..) => {
-                let mut unit = Struct::new(dl, false);
+                let mut unit = Struct::new(dl, &vec![], &[],
+                  StructKind::AlwaysSizedUnivariant, ty)?;
                 unit.sized = false;
                 Univariant { variant: unit, non_zero: false }
             }
 
             // Tuples and closures.
             ty::TyClosure(def_id, ref substs) => {
-                let mut st = Struct::new(dl, false);
                 let tys = substs.upvar_tys(def_id, tcx);
-                st.extend(dl, tys.map(|ty| ty.layout(infcx)), ty)?;
+                let st = Struct::new(dl,
+                    &tys.map(|ty| ty.layout(infcx))
+                      .collect::<Result<Vec<_>, _>>()?,
+                    &[],
+                    StructKind::AlwaysSizedUnivariant, ty)?;
                 Univariant { variant: st, non_zero: false }
             }
 
             ty::TyTuple(tys) => {
-                let mut st = Struct::new(dl, false);
-                st.extend(dl, tys.iter().map(|ty| ty.layout(infcx)), ty)?;
+                // FIXME(camlorn): if we ever allow unsized tuples, this needs to be checked.
+                // See the univariant case below to learn how.
+                let st = Struct::new(dl,
+                    &tys.iter().map(|ty| ty.layout(infcx))
+                      .collect::<Result<Vec<_>, _>>()?,
+                    &[], StructKind::AlwaysSizedUnivariant, ty)?;
                 Univariant { variant: st, non_zero: false }
             }
 
@@ -1003,16 +1159,16 @@ impl<'a, 'gcx, 'tcx> Layout {
 
             // ADTs.
             ty::TyAdt(def, substs) => {
-                let hint = *tcx.lookup_repr_hints(def.did).get(0)
-                    .unwrap_or(&attr::ReprAny);
+                let hints = &tcx.lookup_repr_hints(def.did)[..];
 
                 if def.variants.is_empty() {
                     // Uninhabitable; represent as unit
                     // (Typechecking will reject discriminant-sizing attrs.)
-                    assert_eq!(hint, attr::ReprAny);
+                    assert_eq!(hints.len(), 0);
 
                     return success(Univariant {
-                        variant: Struct::new(dl, false),
+                        variant: Struct::new(dl, &vec![],
+                          &hints[..], StructKind::AlwaysSizedUnivariant, ty)?,
                         non_zero: false
                     });
                 }
@@ -1027,7 +1183,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                         if x > max { max = x; }
                     }
 
-                    let (discr, signed) = Integer::repr_discr(tcx, ty, hint, min, max);
+                    let (discr, signed) = Integer::repr_discr(tcx, ty, &hints[..], min, max);
                     return success(CEnum {
                         discr: discr,
                         signed: signed,
@@ -1037,21 +1193,35 @@ impl<'a, 'gcx, 'tcx> Layout {
                     });
                 }
 
-                if !def.is_enum() || def.variants.len() == 1 && hint == attr::ReprAny {
+                if !def.is_enum() || def.variants.len() == 1 && hints.is_empty() {
                     // Struct, or union, or univariant enum equivalent to a struct.
                     // (Typechecking will reject discriminant-sizing attrs.)
 
+                    let kind = if def.is_enum() || def.variants[0].fields.len() == 0{
+                        StructKind::AlwaysSizedUnivariant
+                    } else {
+                        use middle::region::ROOT_CODE_EXTENT;
+                        let param_env = tcx.construct_parameter_environment(DUMMY_SP,
+                          def.did, ROOT_CODE_EXTENT);
+                        let fields = &def.variants[0].fields;
+                        let last_field = &fields[fields.len()-1];
+                        let always_sized = last_field.ty(tcx, param_env.free_substs)
+                          .is_sized(tcx, &param_env, DUMMY_SP);
+                        if !always_sized { StructKind::MaybeUnsizedUnivariant }
+                        else { StructKind::AlwaysSizedUnivariant }
+                    };
+
                     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);
-                        un.extend(dl, fields, ty)?;
+                        un.extend(dl, fields.iter().map(|&f| Ok(f)), ty)?;
                         UntaggedUnion { variants: un }
                     } else {
-                        let mut st = Struct::new(dl, packed);
-                        st.extend(dl, fields, ty)?;
+                        let st = Struct::new(dl, &fields, &hints[..],
+                          kind, ty)?;
                         let non_zero = Some(def.did) == tcx.lang_items.non_zero();
                         Univariant { variant: st, non_zero: non_zero }
                     };
@@ -1073,7 +1243,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                     v.fields.iter().map(|field| field.ty(tcx, substs)).collect::<Vec<_>>()
                 }).collect::<Vec<_>>();
 
-                if variants.len() == 2 && hint == attr::ReprAny {
+                if variants.len() == 2 && hints.is_empty() {
                     // Nullable pointer optimization
                     for discr in 0..2 {
                         let other_fields = variants[1 - discr].iter().map(|ty| {
@@ -1082,9 +1252,11 @@ impl<'a, 'gcx, 'tcx> Layout {
                         if !Struct::would_be_zero_sized(dl, other_fields)? {
                             continue;
                         }
-                        let path = Struct::non_zero_field_path(infcx,
-                            variants[discr].iter().cloned())?;
-                        let mut path = if let Some(p) = path { p } else { continue };
+                        let paths = Struct::non_zero_field_paths(infcx,
+                            variants[discr].iter().cloned(),
+                            None)?;
+                        let (mut path, mut path_source) = if let Some(p) = paths { p }
+                          else { continue };
 
                         // FIXME(eddyb) should take advantage of a newtype.
                         if path == &[0] && variants[discr].len() == 1 {
@@ -1101,14 +1273,25 @@ impl<'a, 'gcx, 'tcx> Layout {
                             });
                         }
 
+                        let st = Struct::new(dl,
+                            &variants[discr].iter().map(|ty| ty.layout(infcx))
+                              .collect::<Result<Vec<_>, _>>()?,
+                            &hints[..], StructKind::AlwaysSizedUnivariant, ty)?;
+
+                        // We have to fix the last element of path here.
+                        let mut i = *path.last().unwrap();
+                        i = st.memory_index[i as usize];
+                        *path.last_mut().unwrap() = i;
                         path.push(0); // For GEP through a pointer.
                         path.reverse();
-                        let mut st = Struct::new(dl, false);
-                        st.extend(dl, variants[discr].iter().map(|ty| ty.layout(infcx)), ty)?;
+                        path_source.push(0);
+                        path_source.reverse();
+
                         return success(StructWrappedNullablePointer {
                             nndiscr: discr as u64,
                             nonnull: st,
-                            discrfield: path
+                            discrfield: path,
+                            discrfield_source: path_source
                         });
                     }
                 }
@@ -1116,7 +1299,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                 // The general case.
                 let discr_max = (variants.len() - 1) as i64;
                 assert!(discr_max >= 0);
-                let (min_ity, _) = Integer::repr_discr(tcx, ty, hint, 0, discr_max);
+                let (min_ity, _) = Integer::repr_discr(tcx, ty, &hints[..], 0, discr_max);
 
                 let mut align = dl.aggregate_align;
                 let mut size = Size::from_bytes(0);
@@ -1126,24 +1309,26 @@ impl<'a, 'gcx, 'tcx> Layout {
 
                 // Create the set of structs that represent each variant
                 // Use the minimum integer type we figured out above
-                let discr = Some(Scalar { value: Int(min_ity), non_zero: false });
+                let discr = Scalar { value: Int(min_ity), non_zero: false };
                 let mut variants = variants.into_iter().map(|fields| {
-                    let mut found_start = false;
-                    let fields = fields.into_iter().map(|field| {
-                        let field = field.layout(infcx)?;
-                        if !found_start {
-                            // Find the first field we can't move later
-                            // to make room for a larger discriminant.
-                            let field_align = field.align(dl);
-                            if field.size(dl).bytes() != 0 || field_align.abi() != 1 {
-                                start_align = start_align.min(field_align);
-                                found_start = true;
-                            }
+                    let mut fields = fields.into_iter().map(|field| {
+                        field.layout(infcx)
+                    }).collect::<Result<Vec<_>, _>>()?;
+                    fields.insert(0, &discr);
+                    let st = Struct::new(dl,
+                        &fields,
+                        &hints[..], StructKind::EnumVariant, ty)?;
+                    // Find the first field we can't move later
+                    // to make room for a larger discriminant.
+                    // It is important to skip the first field.
+                    for i in st.field_index_by_increasing_offset().skip(1) {
+                        let field = fields[i];
+                        let field_align = field.align(dl);
+                        if field.size(dl).bytes() != 0 || field_align.abi() != 1 {
+                            start_align = start_align.min(field_align);
+                            break;
                         }
-                        Ok(field)
-                    });
-                    let mut st = Struct::new(dl, false);
-                    st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?;
+                    }
                     size = cmp::max(size, st.min_size);
                     align = align.max(st.align);
                     Ok(st)
@@ -1177,11 +1362,12 @@ impl<'a, 'gcx, 'tcx> Layout {
                     let old_ity_size = Int(min_ity).size(dl);
                     let new_ity_size = Int(ity).size(dl);
                     for variant in &mut variants {
-                        for offset in &mut variant.offsets[1..] {
-                            if *offset > old_ity_size {
-                                break;
+                        for i in variant.offsets.iter_mut() {
+                            // The first field is the discrimminant, at offset 0.
+                            // These aren't in order, and we need to skip it.
+                            if *i <= old_ity_size && *i > Size::from_bytes(0) {
+                                *i = new_ity_size;
                             }
-                            *offset = new_ity_size;
                         }
                         // We might be making the struct larger.
                         if variant.min_size <= old_ity_size {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index df12c252907..2ab10d0446b 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -17,7 +17,7 @@ pub use self::LvaluePreference::*;
 pub use self::fold::TypeFoldable;
 
 use dep_graph::{self, DepNode};
-use hir::map as ast_map;
+use hir::{map as ast_map, FreevarMap, TraitMap};
 use middle;
 use hir::def::{Def, CtorKind, ExportMap};
 use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
@@ -112,6 +112,13 @@ pub struct CrateAnalysis<'tcx> {
     pub hir_ty_to_ty: NodeMap<Ty<'tcx>>,
 }
 
+#[derive(Clone)]
+pub struct Resolutions {
+    pub freevars: FreevarMap,
+    pub trait_map: TraitMap,
+    pub maybe_unused_trait_imports: NodeSet,
+}
+
 #[derive(Copy, Clone)]
 pub enum DtorKind {
     NoDtor,
@@ -212,26 +219,18 @@ pub enum Visibility {
     /// Visible everywhere (including in other crates).
     Public,
     /// Visible only in the given crate-local module.
-    Restricted(NodeId),
+    Restricted(DefId),
     /// Not visible anywhere in the local crate. This is the visibility of private external items.
-    PrivateExternal,
+    Invisible,
 }
 
-pub trait NodeIdTree {
-    fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool;
+pub trait DefIdTree: Copy {
+    fn parent(self, id: DefId) -> Option<DefId>;
 }
 
-impl<'a> NodeIdTree for ast_map::Map<'a> {
-    fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool {
-        let mut node_ancestor = node;
-        while node_ancestor != ancestor {
-            let node_ancestor_parent = self.get_module_parent(node_ancestor);
-            if node_ancestor_parent == node_ancestor {
-                return false;
-            }
-            node_ancestor = node_ancestor_parent;
-        }
-        true
+impl<'a, 'gcx, 'tcx> DefIdTree for TyCtxt<'a, 'gcx, 'tcx> {
+    fn parent(self, id: DefId) -> Option<DefId> {
+        self.def_key(id).parent.map(|index| DefId { index: index, ..id })
     }
 }
 
@@ -239,36 +238,46 @@ impl Visibility {
     pub fn from_hir(visibility: &hir::Visibility, id: NodeId, tcx: TyCtxt) -> Self {
         match *visibility {
             hir::Public => Visibility::Public,
-            hir::Visibility::Crate => Visibility::Restricted(ast::CRATE_NODE_ID),
+            hir::Visibility::Crate => Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)),
             hir::Visibility::Restricted { ref path, .. } => match path.def {
                 // If there is no resolution, `resolve` will have already reported an error, so
                 // assume that the visibility is public to avoid reporting more privacy errors.
                 Def::Err => Visibility::Public,
-                def => Visibility::Restricted(tcx.map.as_local_node_id(def.def_id()).unwrap()),
+                def => Visibility::Restricted(def.def_id()),
             },
-            hir::Inherited => Visibility::Restricted(tcx.map.get_module_parent(id)),
+            hir::Inherited => {
+                Visibility::Restricted(tcx.map.local_def_id(tcx.map.get_module_parent(id)))
+            }
         }
     }
 
     /// Returns true if an item with this visibility is accessible from the given block.
-    pub fn is_accessible_from<T: NodeIdTree>(self, block: NodeId, tree: &T) -> bool {
+    pub fn is_accessible_from<T: DefIdTree>(self, mut module: DefId, tree: T) -> bool {
         let restriction = match self {
             // Public items are visible everywhere.
             Visibility::Public => return true,
             // Private items from other crates are visible nowhere.
-            Visibility::PrivateExternal => return false,
+            Visibility::Invisible => return false,
             // Restricted items are visible in an arbitrary local module.
+            Visibility::Restricted(other) if other.krate != module.krate => return false,
             Visibility::Restricted(module) => module,
         };
 
-        tree.is_descendant_of(block, restriction)
+        while module != restriction {
+            match tree.parent(module) {
+                Some(parent) => module = parent,
+                None => return false,
+            }
+        }
+
+        true
     }
 
     /// Returns true if this visibility is at least as accessible as the given visibility
-    pub fn is_at_least<T: NodeIdTree>(self, vis: Visibility, tree: &T) -> bool {
+    pub fn is_at_least<T: DefIdTree>(self, vis: Visibility, tree: T) -> bool {
         let vis_restriction = match vis {
             Visibility::Public => return self == Visibility::Public,
-            Visibility::PrivateExternal => return true,
+            Visibility::Invisible => return true,
             Visibility::Restricted(module) => module,
         };
 
@@ -1772,7 +1781,7 @@ impl<'a, 'gcx, 'tcx> FieldDef {
                                   block: Option<NodeId>,
                                   tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                   substs: &'tcx Substs<'tcx>) -> bool {
-        block.map_or(true, |b| self.vis.is_accessible_from(b, &tcx.map)) &&
+        block.map_or(true, |b| tcx.vis_is_accessible_from(self.vis, b)) &&
         self.ty(tcx, substs).is_uninhabited_recurse(visited, block, tcx)
     }
 }
@@ -2062,7 +2071,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     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(self.global_tcx(), def_id)
+                return self.sess.cstore.associated_item(def_id)
                            .expect("missing AssociatedItem in metadata");
             }
 
@@ -2241,40 +2250,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Convert a `DefId` into its fully expanded `DefPath` (every
     /// `DefId` is really just an interned def-path).
     ///
-    /// Note that if `id` is not local to this crate -- or is
-    /// inlined into this crate -- the result will be a non-local
-    /// `DefPath`.
-    ///
-    /// This function is only safe to use when you are sure that the
-    /// full def-path is accessible. Examples that are known to be
-    /// safe are local def-ids or items; see `opt_def_path` for more
-    /// details.
+    /// Note that if `id` is not local to this crate, the result will
+    //  be a non-local `DefPath`.
     pub fn def_path(self, id: DefId) -> ast_map::DefPath {
-        self.opt_def_path(id).unwrap_or_else(|| {
-            bug!("could not load def-path for {:?}", id)
-        })
-    }
-
-    /// Convert a `DefId` into its fully expanded `DefPath` (every
-    /// `DefId` is really just an interned def-path).
-    ///
-    /// When going across crates, we do not save the full info for
-    /// every cross-crate def-id, and hence we may not always be able
-    /// to create a def-path. Therefore, this returns
-    /// `Option<DefPath>` to cover that possibility. It will always
-    /// return `Some` for local def-ids, however, as well as for
-    /// items. The problems arise with "minor" def-ids like those
-    /// associated with a pattern, `impl Trait`, or other internal
-    /// detail to a fn.
-    ///
-    /// Note that if `id` is not local to this crate -- or is
-    /// inlined into this crate -- the result will be a non-local
-    /// `DefPath`.
-    pub fn opt_def_path(self, id: DefId) -> Option<ast_map::DefPath> {
         if id.is_local() {
-            Some(self.map.def_path(id))
+            self.map.def_path(id)
         } else {
-            self.sess.cstore.relative_def_path(id)
+            self.sess.cstore.def_path(id)
         }
     }
 
@@ -2286,6 +2268,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
+    pub fn vis_is_accessible_from(self, vis: Visibility, block: NodeId) -> bool {
+        vis.is_accessible_from(self.map.local_def_id(self.map.get_module_parent(block)), self)
+    }
+
     pub fn item_name(self, id: DefId) -> ast::Name {
         if let Some(id) = self.map.as_local_node_id(id) {
             self.map.name(id)
@@ -2540,8 +2526,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// 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(self.global_tcx(), def_id)
-                       .and_then(|item| {
+            return self.sess.cstore.associated_item(def_id).and_then(|item| {
                 match item.container {
                     TraitContainer(_) => None,
                     ImplContainer(def_id) => Some(def_id),
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 3b7c46ef7fe..638345608c2 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -543,6 +543,7 @@ pub struct ProjectionTy<'tcx> {
 pub struct BareFnTy<'tcx> {
     pub unsafety: hir::Unsafety,
     pub abi: abi::Abi,
+    /// Signature (inputs and output) of this function type.
     pub sig: PolyFnSig<'tcx>,
 }
 
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index e6db35cc3f5..b4ac6b9d250 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -24,11 +24,11 @@ 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;
 use std::cmp;
-use std::hash::{Hash, Hasher};
-use std::collections::hash_map::DefaultHasher;
+use std::hash::Hash;
 use std::intrinsics;
 use syntax::ast::{self, Name};
 use syntax::attr::{self, SignedInt, UnsignedInt};
@@ -349,7 +349,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Creates a hash of the type `Ty` which will be the same no matter what crate
     /// context it's calculated within. This is used by the `type_id` intrinsic.
     pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 {
-        let mut hasher = TypeIdHasher::new(self, DefaultHasher::default());
+        let mut hasher = TypeIdHasher::new(self);
         hasher.visit_ty(ty);
         hasher.finish()
     }
@@ -395,96 +395,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
-/// When hashing a type this ends up affecting properties like symbol names. We
-/// want these symbol names to be calculated independent of other factors like
-/// what architecture you're compiling *from*.
-///
-/// The hashing just uses the standard `Hash` trait, but the implementations of
-/// `Hash` for the `usize` and `isize` types are *not* architecture independent
-/// (e.g. they has 4 or 8 bytes). As a result we want to avoid `usize` and
-/// `isize` completely when hashing. To ensure that these don't leak in we use a
-/// custom hasher implementation here which inflates the size of these to a `u64`
-/// and `i64`.
-///
-/// The same goes for endianess: We always convert multi-byte integers to little
-/// endian before hashing.
-#[derive(Debug)]
-pub struct ArchIndependentHasher<H> {
-    inner: H,
-}
-
-impl<H> ArchIndependentHasher<H> {
-    pub fn new(inner: H) -> ArchIndependentHasher<H> {
-        ArchIndependentHasher { inner: inner }
-    }
-
-    pub fn into_inner(self) -> H {
-        self.inner
-    }
+pub struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a, W> {
+    tcx: TyCtxt<'a, 'gcx, 'tcx>,
+    state: StableHasher<W>,
 }
 
-impl<H: Hasher> Hasher for ArchIndependentHasher<H> {
-    fn write(&mut self, bytes: &[u8]) {
-        self.inner.write(bytes)
-    }
-
-    fn finish(&self) -> u64 {
-        self.inner.finish()
-    }
-
-    fn write_u8(&mut self, i: u8) {
-        self.inner.write_u8(i)
-    }
-    fn write_u16(&mut self, i: u16) {
-        self.inner.write_u16(i.to_le())
-    }
-    fn write_u32(&mut self, i: u32) {
-        self.inner.write_u32(i.to_le())
-    }
-    fn write_u64(&mut self, i: u64) {
-        self.inner.write_u64(i.to_le())
-    }
-    fn write_usize(&mut self, i: usize) {
-        self.inner.write_u64((i as u64).to_le())
+impl<'a, 'gcx, 'tcx, W> TypeIdHasher<'a, 'gcx, 'tcx, W>
+    where W: StableHasherResult
+{
+    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
+        TypeIdHasher { tcx: tcx, state: StableHasher::new() }
     }
-    fn write_i8(&mut self, i: i8) {
-        self.inner.write_i8(i)
-    }
-    fn write_i16(&mut self, i: i16) {
-        self.inner.write_i16(i.to_le())
-    }
-    fn write_i32(&mut self, i: i32) {
-        self.inner.write_i32(i.to_le())
-    }
-    fn write_i64(&mut self, i: i64) {
-        self.inner.write_i64(i.to_le())
-    }
-    fn write_isize(&mut self, i: isize) {
-        self.inner.write_i64((i as i64).to_le())
-    }
-}
-
-pub struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a, H> {
-    tcx: TyCtxt<'a, 'gcx, 'tcx>,
-    state: ArchIndependentHasher<H>,
-}
 
-impl<'a, 'gcx, 'tcx, H: Hasher> TypeIdHasher<'a, 'gcx, 'tcx, H> {
-    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, state: H) -> Self {
-        TypeIdHasher {
-            tcx: tcx,
-            state: ArchIndependentHasher::new(state),
-        }
+    pub fn finish(self) -> W {
+        self.state.finish()
     }
 
     pub fn hash<T: Hash>(&mut self, x: T) {
         x.hash(&mut self.state);
     }
 
-    pub fn finish(self) -> u64 {
-        self.state.finish()
-    }
-
     fn hash_discriminant_u8<T>(&mut self, x: &T) {
         let v = unsafe {
             intrinsics::discriminant_value(x)
@@ -504,13 +434,11 @@ impl<'a, 'gcx, 'tcx, H: Hasher> TypeIdHasher<'a, 'gcx, 'tcx, H> {
     pub fn def_path(&mut self, def_path: &ast_map::DefPath) {
         def_path.deterministic_hash_to(self.tcx, &mut self.state);
     }
-
-    pub fn into_inner(self) -> H {
-        self.state.inner
-    }
 }
 
-impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, H> {
+impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
+    where W: StableHasherResult
+{
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
         // Distinguish between the Ty variants uniformly.
         self.hash_discriminant_u8(&ty.sty);
diff --git a/src/librustc_back/target/aarch64_linux_android.rs b/src/librustc_back/target/aarch64_linux_android.rs
index 140195c780b..54eead94986 100644
--- a/src/librustc_back/target/aarch64_linux_android.rs
+++ b/src/librustc_back/target/aarch64_linux_android.rs
@@ -10,6 +10,9 @@
 
 use target::{Target, TargetOptions, TargetResult};
 
+// See https://developer.android.com/ndk/guides/abis.html#arm64-v8a
+// for target ABI requirements.
+
 pub fn target() -> TargetResult {
     let mut base = super::android_base::opts();
     base.max_atomic_width = Some(128);
diff --git a/src/librustc_back/target/apple_base.rs b/src/librustc_back/target/apple_base.rs
index 70c7ea99e13..21a2d4293df 100644
--- a/src/librustc_back/target/apple_base.rs
+++ b/src/librustc_back/target/apple_base.rs
@@ -37,6 +37,7 @@ pub fn opts() -> TargetOptions {
         function_sections: false,
         dynamic_linking: true,
         executables: true,
+        target_family: Some("unix".to_string()),
         is_like_osx: true,
         has_rpath: true,
         dll_prefix: "lib".to_string(),
diff --git a/src/librustc_back/target/armv7_linux_androideabi.rs b/src/librustc_back/target/armv7_linux_androideabi.rs
index 42f0deaa3fb..36f409b7948 100644
--- a/src/librustc_back/target/armv7_linux_androideabi.rs
+++ b/src/librustc_back/target/armv7_linux_androideabi.rs
@@ -1,4 +1,4 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -10,9 +10,12 @@
 
 use target::{Target, TargetOptions, TargetResult};
 
+// See https://developer.android.com/ndk/guides/abis.html#v7a
+// for target ABI requirements.
+
 pub fn target() -> TargetResult {
     let mut base = super::android_base::opts();
-    base.features = "+v7,+thumb2,+vfp3,+d16".to_string();
+    base.features = "+v7,+thumb2,+vfp3,+d16,-neon".to_string();
     base.max_atomic_width = Some(64);
 
     Ok(Target {
diff --git a/src/librustc_back/target/asmjs_unknown_emscripten.rs b/src/librustc_back/target/asmjs_unknown_emscripten.rs
index d86a9b09327..98a9e343d00 100644
--- a/src/librustc_back/target/asmjs_unknown_emscripten.rs
+++ b/src/librustc_back/target/asmjs_unknown_emscripten.rs
@@ -23,6 +23,7 @@ pub fn target() -> Result<Target, String> {
         obj_is_bitcode: true,
         max_atomic_width: Some(32),
         post_link_args: vec!["-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()],
+        target_family: Some("unix".to_string()),
         .. Default::default()
     };
     Ok(Target {
diff --git a/src/librustc_back/target/bitrig_base.rs b/src/librustc_back/target/bitrig_base.rs
index 7baf80066b2..62418e68d43 100644
--- a/src/librustc_back/target/bitrig_base.rs
+++ b/src/librustc_back/target/bitrig_base.rs
@@ -15,6 +15,7 @@ pub fn opts() -> TargetOptions {
     TargetOptions {
         dynamic_linking: true,
         executables: true,
+        target_family: Some("unix".to_string()),
         linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
diff --git a/src/librustc_back/target/dragonfly_base.rs b/src/librustc_back/target/dragonfly_base.rs
index 7555181a15c..dca33e45af7 100644
--- a/src/librustc_back/target/dragonfly_base.rs
+++ b/src/librustc_back/target/dragonfly_base.rs
@@ -15,6 +15,7 @@ pub fn opts() -> TargetOptions {
     TargetOptions {
         dynamic_linking: true,
         executables: true,
+        target_family: Some("unix".to_string()),
         linker_is_gnu: true,
         has_rpath: true,
         pre_link_args: vec![
diff --git a/src/librustc_back/target/freebsd_base.rs b/src/librustc_back/target/freebsd_base.rs
index 7555181a15c..dca33e45af7 100644
--- a/src/librustc_back/target/freebsd_base.rs
+++ b/src/librustc_back/target/freebsd_base.rs
@@ -15,6 +15,7 @@ pub fn opts() -> TargetOptions {
     TargetOptions {
         dynamic_linking: true,
         executables: true,
+        target_family: Some("unix".to_string()),
         linker_is_gnu: true,
         has_rpath: true,
         pre_link_args: vec![
diff --git a/src/librustc_back/target/fuchsia_base.rs b/src/librustc_back/target/fuchsia_base.rs
index 69546684cb7..8c517224201 100644
--- a/src/librustc_back/target/fuchsia_base.rs
+++ b/src/librustc_back/target/fuchsia_base.rs
@@ -15,6 +15,7 @@ pub fn opts() -> TargetOptions {
     TargetOptions {
         dynamic_linking: true,
         executables: true,
+        target_family: Some("unix".to_string()),
         linker_is_gnu: true,
         has_rpath: true,
         pre_link_args: vec![
diff --git a/src/librustc_back/target/haiku_base.rs b/src/librustc_back/target/haiku_base.rs
index 5e319ba1838..bfdc9faaa8a 100644
--- a/src/librustc_back/target/haiku_base.rs
+++ b/src/librustc_back/target/haiku_base.rs
@@ -17,6 +17,7 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         has_rpath: true,
+        target_family: Some("unix".to_string()),
         linker_is_gnu: true,
         .. Default::default()
     }
diff --git a/src/librustc_back/target/i686_linux_android.rs b/src/librustc_back/target/i686_linux_android.rs
index a2c007d4969..f8a8f5a3500 100644
--- a/src/librustc_back/target/i686_linux_android.rs
+++ b/src/librustc_back/target/i686_linux_android.rs
@@ -10,6 +10,9 @@
 
 use target::{Target, TargetResult};
 
+// See https://developer.android.com/ndk/guides/abis.html#x86
+// for target ABI requirements.
+
 pub fn target() -> TargetResult {
     let mut base = super::android_base::opts();
 
diff --git a/src/librustc_back/target/linux_base.rs b/src/librustc_back/target/linux_base.rs
index d1ab71e4140..4b2ae9c8e69 100644
--- a/src/librustc_back/target/linux_base.rs
+++ b/src/librustc_back/target/linux_base.rs
@@ -15,6 +15,7 @@ pub fn opts() -> TargetOptions {
     TargetOptions {
         dynamic_linking: true,
         executables: true,
+        target_family: Some("unix".to_string()),
         linker_is_gnu: true,
         has_rpath: true,
         pre_link_args: vec![
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index 351d469ea28..8c37eb6986a 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -69,6 +69,7 @@ mod windows_base;
 mod windows_msvc_base;
 mod thumb_base;
 mod fuchsia_base;
+mod redox_base;
 
 pub type TargetResult = Result<Target, String>;
 
@@ -184,6 +185,8 @@ supported_targets! {
     ("aarch64-unknown-fuchsia", aarch64_unknown_fuchsia),
     ("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia),
 
+    ("x86_64-unknown-redox", x86_64_unknown_redox),
+
     ("i386-apple-ios", i386_apple_ios),
     ("x86_64-apple-ios", x86_64_apple_ios),
     ("aarch64-apple-ios", aarch64_apple_ios),
@@ -267,6 +270,9 @@ pub struct TargetOptions {
     /// user-defined libraries.
     pub post_link_args: Vec<String>,
 
+    /// Extra arguments to pass to the external assembler (when used)
+    pub asm_args: Vec<String>,
+
     /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults
     /// to "generic".
     pub cpu: String,
@@ -394,6 +400,7 @@ impl Default for TargetOptions {
             ar: option_env!("CFG_DEFAULT_AR").unwrap_or("ar").to_string(),
             pre_link_args: Vec::new(),
             post_link_args: Vec::new(),
+            asm_args: Vec::new(),
             cpu: "generic".to_string(),
             features: "".to_string(),
             dynamic_linking: false,
@@ -561,6 +568,7 @@ impl Target {
         key!(late_link_args, list);
         key!(post_link_objects, list);
         key!(post_link_args, list);
+        key!(asm_args, list);
         key!(cpu);
         key!(features);
         key!(dynamic_linking, bool);
@@ -723,6 +731,7 @@ impl ToJson for Target {
         target_option_val!(late_link_args);
         target_option_val!(post_link_objects);
         target_option_val!(post_link_args);
+        target_option_val!(asm_args);
         target_option_val!(cpu);
         target_option_val!(features);
         target_option_val!(dynamic_linking);
diff --git a/src/librustc_back/target/netbsd_base.rs b/src/librustc_back/target/netbsd_base.rs
index 6e038a7ed56..57179a68afd 100644
--- a/src/librustc_back/target/netbsd_base.rs
+++ b/src/librustc_back/target/netbsd_base.rs
@@ -15,6 +15,7 @@ pub fn opts() -> TargetOptions {
     TargetOptions {
         dynamic_linking: true,
         executables: true,
+        target_family: Some("unix".to_string()),
         linker_is_gnu: true,
         has_rpath: true,
         pre_link_args: vec![
diff --git a/src/librustc_back/target/openbsd_base.rs b/src/librustc_back/target/openbsd_base.rs
index 1f74170e399..12b8e8bdc88 100644
--- a/src/librustc_back/target/openbsd_base.rs
+++ b/src/librustc_back/target/openbsd_base.rs
@@ -15,6 +15,7 @@ pub fn opts() -> TargetOptions {
     TargetOptions {
         dynamic_linking: true,
         executables: true,
+        target_family: Some("unix".to_string()),
         linker_is_gnu: true,
         has_rpath: true,
         is_like_openbsd: true,
diff --git a/src/librustc_back/target/redox_base.rs b/src/librustc_back/target/redox_base.rs
new file mode 100644
index 00000000000..1dffff59809
--- /dev/null
+++ b/src/librustc_back/target/redox_base.rs
@@ -0,0 +1,50 @@
+// 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 PanicStrategy;
+use target::TargetOptions;
+use std::default::Default;
+
+pub fn opts() -> TargetOptions {
+    TargetOptions {
+        pre_link_args: vec![
+            // We want to be able to strip as much executable code as possible
+            // from the linker command line, and this flag indicates to the
+            // linker that it can avoid linking in dynamic libraries that don't
+            // actually satisfy any symbols up to that point (as with many other
+            // resolutions the linker does). This option only applies to all
+            // following libraries so we're sure to pass it as one of the first
+            // arguments.
+            "-Wl,--as-needed".to_string(),
+
+            // Always enable NX protection when it is available
+            "-Wl,-z,noexecstack".to_string(),
+
+            // Static link
+            "-static".to_string()
+        ],
+        late_link_args: vec![
+            "-lc".to_string(),
+            "-lm".to_string()
+        ],
+        executables: true,
+        relocation_model: "static".to_string(),
+        disable_redzone: true,
+        eliminate_frame_pointer: false,
+        target_family: None,
+        linker_is_gnu: true,
+        no_default_libraries: true,
+        lib_allocation_crate: "alloc_system".to_string(),
+        exe_allocation_crate: "alloc_system".to_string(),
+        has_elf_tls: true,
+        panic_strategy: PanicStrategy::Abort,
+        .. Default::default()
+    }
+}
diff --git a/src/librustc_back/target/solaris_base.rs b/src/librustc_back/target/solaris_base.rs
index a7af0462e57..41323c9c26b 100644
--- a/src/librustc_back/target/solaris_base.rs
+++ b/src/librustc_back/target/solaris_base.rs
@@ -16,6 +16,7 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         has_rpath: true,
+        target_family: Some("unix".to_string()),
         is_like_solaris: true,
         exe_allocation_crate: super::maybe_jemalloc(),
 
diff --git a/src/librustc_back/target/wasm32_unknown_emscripten.rs b/src/librustc_back/target/wasm32_unknown_emscripten.rs
index 77ab4fcae70..fec269074da 100644
--- a/src/librustc_back/target/wasm32_unknown_emscripten.rs
+++ b/src/librustc_back/target/wasm32_unknown_emscripten.rs
@@ -26,6 +26,7 @@ pub fn target() -> Result<Target, String> {
         max_atomic_width: Some(32),
         post_link_args: vec!["-s".to_string(), "BINARYEN=1".to_string(),
                              "-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()],
+        target_family: Some("unix".to_string()),
         .. Default::default()
     };
     Ok(Target {
diff --git a/src/librustc_back/target/windows_base.rs b/src/librustc_back/target/windows_base.rs
index 19ca0df51b9..db02e142fcc 100644
--- a/src/librustc_back/target/windows_base.rs
+++ b/src/librustc_back/target/windows_base.rs
@@ -24,6 +24,7 @@ pub fn opts() -> TargetOptions {
         staticlib_prefix: "".to_string(),
         staticlib_suffix: ".lib".to_string(),
         no_default_libraries: true,
+        target_family: Some("windows".to_string()),
         is_like_windows: true,
         allows_weak_linkage: false,
         pre_link_args: vec![
diff --git a/src/librustc_back/target/windows_msvc_base.rs b/src/librustc_back/target/windows_msvc_base.rs
index 84e22e84fdb..efa215b419d 100644
--- a/src/librustc_back/target/windows_msvc_base.rs
+++ b/src/librustc_back/target/windows_msvc_base.rs
@@ -53,6 +53,7 @@ pub fn opts() -> TargetOptions {
         exe_suffix: ".exe".to_string(),
         staticlib_prefix: "".to_string(),
         staticlib_suffix: ".lib".to_string(),
+        target_family: Some("windows".to_string()),
         is_like_windows: true,
         is_like_msvc: true,
         pre_link_args: vec![
diff --git a/src/librustc_back/target/x86_64_unknown_redox.rs b/src/librustc_back/target/x86_64_unknown_redox.rs
new file mode 100644
index 00000000000..cecac06b235
--- /dev/null
+++ b/src/librustc_back/target/x86_64_unknown_redox.rs
@@ -0,0 +1,30 @@
+// 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::redox_base::opts();
+    base.cpu = "x86-64".to_string();
+    base.max_atomic_width = Some(64);
+    base.pre_link_args.push("-m64".to_string());
+
+    Ok(Target {
+        llvm_target: "x86_64-unknown-redox".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "64".to_string(),
+        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        arch: "x86_64".to_string(),
+        target_os: "redox".to_string(),
+        target_env: "".to_string(),
+        target_vendor: "unknown".to_string(),
+        options: base,
+    })
+}
diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
index 4f49bfc9725..88e5bae483d 100644
--- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
+++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
@@ -481,54 +481,55 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                            is_cleanup: bool)
                            -> Vec<BasicBlock>
     {
-        let mut succ = succ;
         let mut unwind_succ = if is_cleanup {
             None
         } else {
             c.unwind
         };
-        let mut update_drop_flag = true;
+
+        let mut succ = self.new_block(
+            c, c.is_cleanup, TerminatorKind::Goto { target: succ }
+        );
+
+        // Always clear the "master" drop flag at the bottom of the
+        // ladder. This is needed because the "master" drop flag
+        // protects the ADT's discriminant, which is invalidated
+        // after the ADT is dropped.
+        self.set_drop_flag(
+            Location { block: succ, statement_index: 0 },
+            c.path,
+            DropFlagState::Absent
+        );
 
         fields.iter().rev().enumerate().map(|(i, &(ref lv, path))| {
-            let drop_block = match path {
-                Some(path) => {
-                    debug!("drop_ladder: for std field {} ({:?})", i, lv);
-
-                    self.elaborated_drop_block(&DropCtxt {
-                        source_info: c.source_info,
-                        is_cleanup: is_cleanup,
-                        init_data: c.init_data,
-                        lvalue: lv,
-                        path: path,
-                        succ: succ,
-                        unwind: unwind_succ,
-                    })
-                }
-                None => {
-                    debug!("drop_ladder: for rest field {} ({:?})", i, lv);
-
-                    let blk = self.complete_drop(&DropCtxt {
-                        source_info: c.source_info,
-                        is_cleanup: is_cleanup,
-                        init_data: c.init_data,
-                        lvalue: lv,
-                        path: c.path,
-                        succ: succ,
-                        unwind: unwind_succ,
-                    }, update_drop_flag);
-
-                    // the drop flag has been updated - updating
-                    // it again would clobber it.
-                    update_drop_flag = false;
-
-                    blk
-                }
+            succ = if let Some(path) = path {
+                debug!("drop_ladder: for std field {} ({:?})", i, lv);
+
+                self.elaborated_drop_block(&DropCtxt {
+                    source_info: c.source_info,
+                    is_cleanup: is_cleanup,
+                    init_data: c.init_data,
+                    lvalue: lv,
+                    path: path,
+                    succ: succ,
+                    unwind: unwind_succ,
+                })
+            } else {
+                debug!("drop_ladder: for rest field {} ({:?})", i, lv);
+
+                self.complete_drop(&DropCtxt {
+                    source_info: c.source_info,
+                    is_cleanup: is_cleanup,
+                    init_data: c.init_data,
+                    lvalue: lv,
+                    path: c.path,
+                    succ: succ,
+                    unwind: unwind_succ,
+                }, false)
             };
 
-            succ = drop_block;
             unwind_succ = unwind_ladder.as_ref().map(|p| p[i]);
-
-            drop_block
+            succ
         }).collect()
     }
 
diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs
index 23771f4bae3..ebe10349011 100644
--- a/src/librustc_const_eval/_match.rs
+++ b/src/librustc_const_eval/_match.rs
@@ -324,7 +324,6 @@ impl Witness {
                     let v = ctor.variant_for_adt(adt);
                     let qpath = hir::QPath::Resolved(None, P(hir::Path {
                         span: DUMMY_SP,
-                        global: false,
                         def: Def::Err,
                         segments: vec![hir::PathSegment::from_name(v.name)].into(),
                     }));
diff --git a/src/librustc_data_structures/base_n.rs b/src/librustc_data_structures/base_n.rs
index bf3e682f86f..4359581a897 100644
--- a/src/librustc_data_structures/base_n.rs
+++ b/src/librustc_data_structures/base_n.rs
@@ -14,6 +14,8 @@
 use std::str;
 
 pub const MAX_BASE: u64 = 64;
+pub const ALPHANUMERIC_ONLY: u64 = 62;
+
 const BASE_64: &'static [u8; MAX_BASE as usize] =
     b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@$";
 
diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs
index 510c9ceef09..33d71ba8626 100644
--- a/src/librustc_data_structures/flock.rs
+++ b/src/librustc_data_structures/flock.rs
@@ -31,6 +31,7 @@ mod imp {
     mod os {
         use libc;
 
+        #[repr(C)]
         pub struct flock {
             pub l_type: libc::c_short,
             pub l_whence: libc::c_short,
@@ -53,6 +54,7 @@ mod imp {
     mod os {
         use libc;
 
+        #[repr(C)]
         pub struct flock {
             pub l_start: libc::off_t,
             pub l_len: libc::off_t,
@@ -76,6 +78,7 @@ mod imp {
     mod os {
         use libc;
 
+        #[repr(C)]
         pub struct flock {
             pub l_start: libc::off_t,
             pub l_len: libc::off_t,
@@ -98,6 +101,7 @@ mod imp {
     mod os {
         use libc;
 
+        #[repr(C)]
         pub struct flock {
             pub l_type: libc::c_short,
             pub l_whence: libc::c_short,
@@ -119,6 +123,7 @@ mod imp {
     mod os {
         use libc;
 
+        #[repr(C)]
         pub struct flock {
             pub l_start: libc::off_t,
             pub l_len: libc::off_t,
@@ -141,6 +146,7 @@ mod imp {
     mod os {
         use libc;
 
+        #[repr(C)]
         pub struct flock {
             pub l_type: libc::c_short,
             pub l_whence: libc::c_short,
diff --git a/src/librustc_data_structures/graph/tests.rs b/src/librustc_data_structures/graph/tests.rs
index a87410e6e1c..bdefc39a61a 100644
--- a/src/librustc_data_structures/graph/tests.rs
+++ b/src/librustc_data_structures/graph/tests.rs
@@ -11,8 +11,6 @@
 use graph::*;
 use std::fmt::Debug;
 
-type TestNode = Node<&'static str>;
-type TestEdge = Edge<&'static str>;
 type TestGraph = Graph<&'static str, &'static str>;
 
 fn create_graph() -> TestGraph {
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index de13b9bf4be..86f244d65dd 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -44,6 +44,8 @@ extern crate serialize as rustc_serialize; // used by deriving
 #[cfg(unix)]
 extern crate libc;
 
+pub use rustc_serialize::hex::ToHex;
+
 pub mod array_vec;
 pub mod accumulate_vec;
 pub mod small_vec;
@@ -59,6 +61,7 @@ pub mod indexed_vec;
 pub mod obligation_forest;
 pub mod snapshot_map;
 pub mod snapshot_vec;
+pub mod stable_hasher;
 pub mod transitive_relation;
 pub mod unify;
 pub mod fnv;
diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs
new file mode 100644
index 00000000000..ed97c3dde5e
--- /dev/null
+++ b/src/librustc_data_structures/stable_hasher.rs
@@ -0,0 +1,176 @@
+// 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 std::hash::Hasher;
+use std::marker::PhantomData;
+use std::mem;
+use blake2b::Blake2bHasher;
+use rustc_serialize::leb128;
+
+fn write_unsigned_leb128_to_buf(buf: &mut [u8; 16], value: u64) -> usize {
+    leb128::write_unsigned_leb128_to(value, |i, v| buf[i] = v)
+}
+
+fn write_signed_leb128_to_buf(buf: &mut [u8; 16], value: i64) -> usize {
+    leb128::write_signed_leb128_to(value, |i, v| buf[i] = v)
+}
+
+/// When hashing something that ends up affecting properties like symbol names. We
+/// want these symbol names to be calculated independent of other factors like
+/// what architecture you're compiling *from*.
+///
+/// The hashing just uses the standard `Hash` trait, but the implementations of
+/// `Hash` for the `usize` and `isize` types are *not* architecture independent
+/// (e.g. they has 4 or 8 bytes). As a result we want to avoid `usize` and
+/// `isize` completely when hashing.
+///
+/// To do that, we encode all integers to be hashed with some
+/// arch-independent encoding.
+///
+/// At the moment, we pass i8/u8 straight through and encode
+/// all other integers using leb128.
+///
+/// This hasher currently always uses the stable Blake2b algorithm
+/// and allows for variable output lengths through its type
+/// parameter.
+#[derive(Debug)]
+pub struct StableHasher<W> {
+    state: Blake2bHasher,
+    bytes_hashed: u64,
+    width: PhantomData<W>,
+}
+
+pub trait StableHasherResult: Sized {
+    fn finish(hasher: StableHasher<Self>) -> Self;
+}
+
+impl<W: StableHasherResult> StableHasher<W> {
+    pub fn new() -> Self {
+        StableHasher {
+            state: Blake2bHasher::new(mem::size_of::<W>(), &[]),
+            bytes_hashed: 0,
+            width: PhantomData,
+        }
+    }
+
+    pub fn finish(self) -> W {
+        W::finish(self)
+    }
+}
+
+impl StableHasherResult for [u8; 20] {
+    fn finish(mut hasher: StableHasher<Self>) -> Self {
+        let mut result: [u8; 20] = [0; 20];
+        result.copy_from_slice(hasher.state.finalize());
+        result
+    }
+}
+
+impl StableHasherResult for u64 {
+    fn finish(mut hasher: StableHasher<Self>) -> Self {
+        hasher.state.finalize();
+        hasher.state.finish()
+    }
+}
+
+impl<W> StableHasher<W> {
+    #[inline]
+    pub fn finalize(&mut self) -> &[u8] {
+        self.state.finalize()
+    }
+
+    #[inline]
+    pub fn bytes_hashed(&self) -> u64 {
+        self.bytes_hashed
+    }
+
+    #[inline]
+    fn write_uleb128(&mut self, value: u64) {
+        let mut buf = [0; 16];
+        let len = write_unsigned_leb128_to_buf(&mut buf, value);
+        self.state.write(&buf[..len]);
+        self.bytes_hashed += len as u64;
+    }
+
+    #[inline]
+    fn write_ileb128(&mut self, value: i64) {
+        let mut buf = [0; 16];
+        let len = write_signed_leb128_to_buf(&mut buf, value);
+        self.state.write(&buf[..len]);
+        self.bytes_hashed += len as u64;
+    }
+}
+
+// For the non-u8 integer cases we leb128 encode them first. Because small
+// integers dominate, this significantly and cheaply reduces the number of
+// bytes hashed, which is good because blake2b is expensive.
+impl<W> Hasher for StableHasher<W> {
+    fn finish(&self) -> u64 {
+        panic!("use StableHasher::finish instead");
+    }
+
+    #[inline]
+    fn write(&mut self, bytes: &[u8]) {
+        self.state.write(bytes);
+        self.bytes_hashed += bytes.len() as u64;
+    }
+
+    #[inline]
+    fn write_u8(&mut self, i: u8) {
+        self.state.write_u8(i);
+        self.bytes_hashed += 1;
+    }
+
+    #[inline]
+    fn write_u16(&mut self, i: u16) {
+        self.write_uleb128(i as u64);
+    }
+
+    #[inline]
+    fn write_u32(&mut self, i: u32) {
+        self.write_uleb128(i as u64);
+    }
+
+    #[inline]
+    fn write_u64(&mut self, i: u64) {
+        self.write_uleb128(i);
+    }
+
+    #[inline]
+    fn write_usize(&mut self, i: usize) {
+        self.write_uleb128(i as u64);
+    }
+
+    #[inline]
+    fn write_i8(&mut self, i: i8) {
+        self.state.write_i8(i);
+        self.bytes_hashed += 1;
+    }
+
+    #[inline]
+    fn write_i16(&mut self, i: i16) {
+        self.write_ileb128(i as i64);
+    }
+
+    #[inline]
+    fn write_i32(&mut self, i: i32) {
+        self.write_ileb128(i as i64);
+    }
+
+    #[inline]
+    fn write_i64(&mut self, i: i64) {
+        self.write_ileb128(i);
+    }
+
+    #[inline]
+    fn write_isize(&mut self, i: isize) {
+        self.write_ileb128(i as i64);
+    }
+}
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 8d995e97b95..8da9a23f4fa 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -8,12 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::hir;
-use rustc::hir::{map as hir_map, FreevarMap, TraitMap};
+use rustc::hir::{self, map as hir_map};
 use rustc::hir::lowering::lower_crate;
-use rustc_data_structures::blake2b::Blake2bHasher;
-use rustc_data_structures::fmt_wrap::FmtWrap;
-use rustc::ty::util::ArchIndependentHasher;
+use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_mir as mir;
 use rustc::session::{Session, CompileResult, compile_result_from_err_count};
 use rustc::session::config::{self, Input, OutputFilenames, OutputType,
@@ -22,11 +19,12 @@ use rustc::session::search_paths::PathKind;
 use rustc::lint;
 use rustc::middle::{self, dependency_format, stability, reachable};
 use rustc::middle::privacy::AccessLevels;
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::{self, TyCtxt, Resolutions};
 use rustc::util::common::time;
 use rustc::util::nodemap::{NodeSet, NodeMap};
 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;
@@ -60,13 +58,6 @@ use syntax_ext;
 
 use derive_registrar;
 
-#[derive(Clone)]
-pub struct Resolutions {
-    pub freevars: FreevarMap,
-    pub trait_map: TraitMap,
-    pub maybe_unused_trait_imports: NodeSet,
-}
-
 pub fn compile_input(sess: &Session,
                      cstore: &CStore,
                      input: &Input,
@@ -601,6 +592,7 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
         }
     });
 
+    let whitelisted_legacy_custom_derives = registry.take_whitelisted_custom_derives();
     let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups,
                    llvm_passes, attributes, mir_passes, .. } = registry;
 
@@ -640,6 +632,7 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
     let resolver_arenas = Resolver::arenas();
     let mut resolver =
         Resolver::new(sess, &krate, make_glob_map, &mut crate_loader, &resolver_arenas);
+    resolver.whitelisted_legacy_custom_derives = whitelisted_legacy_custom_derives;
     syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote);
 
     krate = time(time_passes, "expansion", || {
@@ -865,11 +858,9 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
 
     TyCtxt::create_and_enter(sess,
                              arenas,
-                             resolutions.trait_map,
+                             resolutions,
                              named_region_map,
                              hir_map,
-                             resolutions.freevars,
-                             resolutions.maybe_unused_trait_imports,
                              region_map,
                              lang_items,
                              index,
@@ -1274,7 +1265,7 @@ pub fn compute_crate_disambiguator(session: &Session) -> String {
     // FIXME(mw): It seems that the crate_disambiguator is used everywhere as
     //            a hex-string instead of raw bytes. We should really use the
     //            smaller representation.
-    let mut hasher = ArchIndependentHasher::new(Blake2bHasher::new(128 / 8, &[]));
+    let mut hasher = StableHasher::<Fingerprint>::new();
 
     let mut metadata = session.opts.cg.metadata.clone();
     // We don't want the crate_disambiguator to dependent on the order
@@ -1292,14 +1283,11 @@ pub fn compute_crate_disambiguator(session: &Session) -> String {
         hasher.write(s.as_bytes());
     }
 
-    let mut hash_state = hasher.into_inner();
-    let hash_bytes = hash_state.finalize();
-
     // If this is an executable, add a special suffix, so that we don't get
     // symbol conflicts when linking against a library of the same name.
     let is_exe = session.crate_types.borrow().contains(&config::CrateTypeExecutable);
 
-    format!("{:x}{}", FmtWrap(hash_bytes), if is_exe { "-exe" } else {""})
+    format!("{}{}", hasher.finish().to_hex(), if is_exe { "-exe" } else {""})
 }
 
 pub fn build_output_filenames(input: &Input,
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index b055b043723..74df1e52bde 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -15,10 +15,9 @@ pub use self::PpSourceMode::*;
 pub use self::PpMode::*;
 use self::NodesMatchingUII::*;
 
-use abort_on_err;
-use driver::{self, Resolutions};
+use {abort_on_err, driver};
 
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::{self, TyCtxt, Resolutions};
 use rustc::cfg;
 use rustc::cfg::graphviz::LabelledCFG;
 use rustc::dep_graph::DepGraph;
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 2f8550e5acd..cbab39c3908 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -138,11 +138,9 @@ fn test_env<F>(source_string: &str,
     let index = stability::Index::new(&ast_map);
     TyCtxt::create_and_enter(&sess,
                              &arenas,
-                             resolutions.trait_map,
+                             resolutions,
                              named_region_map.unwrap(),
                              ast_map,
-                             resolutions.freevars,
-                             resolutions.maybe_unused_trait_imports,
                              region_map,
                              lang_items,
                              index,
diff --git a/src/librustc_incremental/calculate_svh/hasher.rs b/src/librustc_incremental/calculate_svh/hasher.rs
deleted file mode 100644
index d7d9c231a91..00000000000
--- a/src/librustc_incremental/calculate_svh/hasher.rs
+++ /dev/null
@@ -1,88 +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.
-
-use std::mem;
-use std::hash::Hasher;
-use rustc_data_structures::blake2b::Blake2bHasher;
-use rustc::ty::util::ArchIndependentHasher;
-use ich::Fingerprint;
-use rustc_serialize::leb128::write_unsigned_leb128;
-
-#[derive(Debug)]
-pub struct IchHasher {
-    state: ArchIndependentHasher<Blake2bHasher>,
-    leb128_helper: Vec<u8>,
-    bytes_hashed: u64,
-}
-
-impl IchHasher {
-    pub fn new() -> IchHasher {
-        let hash_size = mem::size_of::<Fingerprint>();
-        IchHasher {
-            state: ArchIndependentHasher::new(Blake2bHasher::new(hash_size, &[])),
-            leb128_helper: vec![],
-            bytes_hashed: 0
-        }
-    }
-
-    pub fn bytes_hashed(&self) -> u64 {
-        self.bytes_hashed
-    }
-
-    pub fn finish(self) -> Fingerprint {
-        let mut fingerprint = Fingerprint::zero();
-        fingerprint.0.copy_from_slice(self.state.into_inner().finalize());
-        fingerprint
-    }
-
-    #[inline]
-    fn write_uleb128(&mut self, value: u64) {
-        let len = write_unsigned_leb128(&mut self.leb128_helper, 0, value);
-        self.state.write(&self.leb128_helper[0..len]);
-        self.bytes_hashed += len as u64;
-    }
-}
-
-// For the non-u8 integer cases we leb128 encode them first. Because small
-// integers dominate, this significantly and cheaply reduces the number of
-// bytes hashed, which is good because blake2b is expensive.
-impl Hasher for IchHasher {
-    fn finish(&self) -> u64 {
-        bug!("Use other finish() implementation to get the full 128-bit hash.");
-    }
-
-    #[inline]
-    fn write(&mut self, bytes: &[u8]) {
-        self.state.write(bytes);
-        self.bytes_hashed += bytes.len() as u64;
-    }
-
-    // There is no need to leb128-encode u8 values.
-
-    #[inline]
-    fn write_u16(&mut self, i: u16) {
-        self.write_uleb128(i as u64);
-    }
-
-    #[inline]
-    fn write_u32(&mut self, i: u32) {
-        self.write_uleb128(i as u64);
-    }
-
-    #[inline]
-    fn write_u64(&mut self, i: u64) {
-        self.write_uleb128(i);
-    }
-
-    #[inline]
-    fn write_usize(&mut self, i: usize) {
-        self.write_uleb128(i as u64);
-    }
-}
diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs
index df65c4d2794..eb31be4a8ad 100644
--- a/src/librustc_incremental/calculate_svh/mod.rs
+++ b/src/librustc_incremental/calculate_svh/mod.rs
@@ -36,6 +36,8 @@ use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
 use rustc::hir::intravisit as visit;
 use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
 use rustc::ty::TyCtxt;
+use rustc_data_structures::stable_hasher::StableHasher;
+use ich::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc::util::common::record_time;
 use rustc::session::config::DebugInfoLevel::NoDebugInfo;
@@ -43,14 +45,12 @@ use rustc::session::config::DebugInfoLevel::NoDebugInfo;
 use self::def_path_hash::DefPathHashes;
 use self::svh_visitor::StrictVersionHashVisitor;
 use self::caching_codemap_view::CachingCodemapView;
-use self::hasher::IchHasher;
-use ich::Fingerprint;
-
 
 mod def_path_hash;
 mod svh_visitor;
 mod caching_codemap_view;
-pub mod hasher;
+
+pub type IchHasher = StableHasher<Fingerprint>;
 
 pub struct IncrementalHashesMap {
     hashes: FxHashMap<DepNode<DefId>, Fingerprint>,
@@ -244,4 +244,3 @@ impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
         visit::walk_foreign_item(self, item);
     }
 }
-
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index de52b70f1ec..ccae5f3b003 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -28,11 +28,11 @@ use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit as visit;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fnv;
-use std::hash::Hash;
+use std::hash::{Hash, Hasher};
 
 use super::def_path_hash::DefPathHashes;
 use super::caching_codemap_view::CachingCodemapView;
-use super::hasher::IchHasher;
+use super::IchHasher;
 
 const IGNORED_ATTRIBUTES: &'static [&'static str] = &[
     "cfg",
@@ -189,7 +189,6 @@ enum SawAbiComponent<'a> {
     SawStructField,
     SawVariant,
     SawQPath,
-    SawPath(bool),
     SawPathSegment,
     SawPathParameters,
     SawBlock,
@@ -265,7 +264,7 @@ enum SawExprComponent<'a> {
     SawExprPath,
     SawExprAddrOf(hir::Mutability),
     SawExprRet,
-    SawExprInlineAsm(&'a hir::InlineAsm),
+    SawExprInlineAsm(StableInlineAsm<'a>),
     SawExprStruct,
     SawExprRepeat,
 }
@@ -341,7 +340,7 @@ fn saw_expr<'a>(node: &'a Expr_,
         ExprBreak(label, _)      => (SawExprBreak(label.map(|l| l.name.as_str())), false),
         ExprAgain(label)         => (SawExprAgain(label.map(|l| l.name.as_str())), false),
         ExprRet(..)              => (SawExprRet, false),
-        ExprInlineAsm(ref a,..)  => (SawExprInlineAsm(a), false),
+        ExprInlineAsm(ref a,..)  => (SawExprInlineAsm(StableInlineAsm(a)), false),
         ExprStruct(..)           => (SawExprStruct, false),
         ExprRepeat(..)           => (SawExprRepeat, false),
     }
@@ -492,6 +491,46 @@ enum SawSpanExpnKind {
     SomeExpansion,
 }
 
+/// A wrapper that provides a stable Hash implementation.
+struct StableInlineAsm<'a>(&'a InlineAsm);
+
+impl<'a> Hash for StableInlineAsm<'a> {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        let InlineAsm {
+            asm,
+            asm_str_style,
+            ref outputs,
+            ref inputs,
+            ref clobbers,
+            volatile,
+            alignstack,
+            dialect,
+            expn_id: _, // This is used for error reporting
+        } = *self.0;
+
+        asm.as_str().hash(state);
+        asm_str_style.hash(state);
+        outputs.len().hash(state);
+        for output in outputs {
+            let InlineAsmOutput { constraint, is_rw, is_indirect } = *output;
+            constraint.as_str().hash(state);
+            is_rw.hash(state);
+            is_indirect.hash(state);
+        }
+        inputs.len().hash(state);
+        for input in inputs {
+            input.as_str().hash(state);
+        }
+        clobbers.len().hash(state);
+        for clobber in clobbers {
+            clobber.as_str().hash(state);
+        }
+        volatile.hash(state);
+        alignstack.hash(state);
+        dialect.hash(state);
+    }
+}
+
 macro_rules! hash_attrs {
     ($visitor:expr, $attrs:expr) => ({
         let attrs = $attrs;
@@ -678,7 +717,6 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
 
     fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) {
         debug!("visit_path: st={:?}", self.st);
-        SawPath(path.global).hash(self.st);
         hash_span!(self, path.span);
         visit::walk_path(self, path)
     }
diff --git a/src/librustc_incremental/ich/fingerprint.rs b/src/librustc_incremental/ich/fingerprint.rs
index 005ac3896ce..d296d8293fb 100644
--- a/src/librustc_incremental/ich/fingerprint.rs
+++ b/src/librustc_incremental/ich/fingerprint.rs
@@ -9,6 +9,8 @@
 // except according to those terms.
 
 use rustc_serialize::{Encodable, Decodable, Encoder, Decoder};
+use rustc_data_structures::stable_hasher;
+use rustc_data_structures::ToHex;
 
 const FINGERPRINT_LENGTH: usize = 16;
 
@@ -44,6 +46,10 @@ impl Fingerprint {
         ((self.0[6] as u64) << 48) |
         ((self.0[7] as u64) << 56)
     }
+
+    pub fn to_hex(&self) -> String {
+        self.0.to_hex()
+    }
 }
 
 impl Encodable for Fingerprint {
@@ -79,3 +85,12 @@ impl ::std::fmt::Display for Fingerprint {
         Ok(())
     }
 }
+
+
+impl stable_hasher::StableHasherResult for Fingerprint {
+    fn finish(mut hasher: stable_hasher::StableHasher<Self>) -> Self {
+        let mut fingerprint = Fingerprint::zero();
+        fingerprint.0.copy_from_slice(hasher.finalize());
+        fingerprint
+    }
+}
diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs
index 3cb5244413b..ce73b14ef2d 100644
--- a/src/librustc_incremental/lib.rs
+++ b/src/librustc_incremental/lib.rs
@@ -48,7 +48,7 @@ pub mod ich;
 pub use assert_dep_graph::assert_dep_graph;
 pub use calculate_svh::compute_incremental_hashes_map;
 pub use calculate_svh::IncrementalHashesMap;
-pub use calculate_svh::hasher::IchHasher;
+pub use calculate_svh::IchHasher;
 pub use persist::load_dep_graph;
 pub use persist::save_dep_graph;
 pub use persist::save_trans_partition;
diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs
index e5203ea02b4..799cb6c5e3d 100644
--- a/src/librustc_incremental/persist/hash.rs
+++ b/src/librustc_incremental/persist/hash.rs
@@ -66,11 +66,6 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> {
                         def_id,
                         self.tcx.item_path_str(def_id));
 
-                assert!(!self.tcx.map.is_inlined_def_id(def_id),
-                        "cannot hash HIR for inlined def-id {:?} => {:?}",
-                        def_id,
-                        self.tcx.item_path_str(def_id));
-
                 Some(self.incremental_hashes_map[dep_node])
             }
 
diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs
index 1ce4bf7f033..f3bbd02dffa 100644
--- a/src/librustc_incremental/persist/save.rs
+++ b/src/librustc_incremental/persist/save.rs
@@ -30,7 +30,7 @@ use super::preds::*;
 use super::fs::*;
 use super::dirty_clean;
 use super::file_format;
-use calculate_svh::hasher::IchHasher;
+use calculate_svh::IchHasher;
 
 pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 incremental_hashes_map: &IncrementalHashesMap,
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index 2aa74407afc..1d384741d96 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -382,7 +382,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals {
     fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
         // Lint for constants that look like binding identifiers (#7526)
         if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.node {
-            if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() {
+            if path.segments.len() == 1 && path.segments[0].parameters.is_empty() {
                 if let Def::Const(..) = path.def {
                     NonUpperCaseGlobals::check_upper_case(cx,
                                                           "constant in pattern",
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 6c9a3e99a04..a53d43b2a25 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -234,6 +234,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
             id: LintId::of(LEGACY_DIRECTORY_OWNERSHIP),
             reference: "issue #37872 <https://github.com/rust-lang/rust/issues/37872>",
         },
+        FutureIncompatibleInfo {
+            id: LintId::of(LEGACY_IMPORTS),
+            reference: "issue #38260 <https://github.com/rust-lang/rust/issues/38260>",
+        },
         ]);
 
     // Register renamed and removed lints
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 5e9fdbfa073..751c9c3440f 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -750,7 +750,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
                 if let Layout::General { ref variants, ref size, discr, .. } = *layout {
                     let discr_size = Primitive::Int(discr).size(&cx.tcx.data_layout).bytes();
 
-                    debug!("enum `{}` is {} bytes large", t, size.bytes());
+                    debug!("enum `{}` is {} bytes large with layout:\n{:#?}",
+                      t, size.bytes(), layout);
 
                     let (largest, slargest, largest_index) = enum_definition.variants
                         .iter()
diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs
index 50bc3e7b624..e681a81cf0c 100644
--- a/src/librustc_llvm/build.rs
+++ b/src/librustc_llvm/build.rs
@@ -95,7 +95,8 @@ fn main() {
     let is_crossed = target != host;
 
     let optional_components =
-        ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz", "jsbackend", "msp430"];
+        ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz", "jsbackend", "msp430",
+         "sparc"];
 
     // FIXME: surely we don't need all these components, right? Stuff like mcjit
     //        or interpreter the compiler itself never uses.
@@ -230,6 +231,13 @@ fn main() {
         }
     }
 
+    // OpenBSD has a particular C++ runtime library name
+    let stdcppname = if target.contains("openbsd") {
+        "estdc++"
+    } else {
+        "stdc++"
+    };
+
     // C++ runtime library
     if !target.contains("msvc") {
         if let Some(s) = env::var_os("LLVM_STATIC_STDCPP") {
@@ -237,11 +245,11 @@ fn main() {
             let path = PathBuf::from(s);
             println!("cargo:rustc-link-search=native={}",
                      path.parent().unwrap().display());
-            println!("cargo:rustc-link-lib=static=stdc++");
+            println!("cargo:rustc-link-lib=static={}", stdcppname);
         } else if cxxflags.contains("stdlib=libc++") {
             println!("cargo:rustc-link-lib=c++");
         } else {
-            println!("cargo:rustc-link-lib=stdc++");
+            println!("cargo:rustc-link-lib={}", stdcppname);
         }
     }
 }
diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs
index a6b2fe471df..f3dbac7ce68 100644
--- a/src/librustc_llvm/ffi.rs
+++ b/src/librustc_llvm/ffi.rs
@@ -117,6 +117,7 @@ pub enum Attribute {
     StructRet       = 16,
     UWTable         = 17,
     ZExt            = 18,
+    InReg           = 19,
 }
 
 /// LLVMIntPredicate
@@ -710,6 +711,7 @@ extern "C" {
 
     // Operations on instructions
     pub fn LLVMGetInstructionParent(Inst: ValueRef) -> BasicBlockRef;
+    pub fn LLVMGetFirstBasicBlock(Fn: ValueRef) -> BasicBlockRef;
     pub fn LLVMGetFirstInstruction(BB: BasicBlockRef) -> ValueRef;
     pub fn LLVMInstructionEraseFromParent(Inst: ValueRef);
 
@@ -1417,7 +1419,8 @@ extern "C" {
                                                  Ty: DIType,
                                                  isLocalToUnit: bool,
                                                  Val: ValueRef,
-                                                 Decl: DIDescriptor)
+                                                 Decl: DIDescriptor,
+                                                 AlignInBits: u64)
                                                  -> DIGlobalVariable;
 
     pub fn LLVMRustDIBuilderCreateVariable(Builder: DIBuilderRef,
@@ -1429,7 +1432,8 @@ extern "C" {
                                            Ty: DIType,
                                            AlwaysPreserve: bool,
                                            Flags: DIFlags,
-                                           ArgNo: c_uint)
+                                           ArgNo: c_uint,
+                                           AlignInBits: u64)
                                            -> DIVariable;
 
     pub fn LLVMRustDIBuilderCreateArrayType(Builder: DIBuilderRef,
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index a15edcd44be..69709f72b8b 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -270,7 +270,8 @@ pub fn mk_section_iter(llof: ObjectFileRef) -> SectionIter {
 /// Safe wrapper around `LLVMGetParam`, because segfaults are no fun.
 pub fn get_param(llfn: ValueRef, index: c_uint) -> ValueRef {
     unsafe {
-        assert!(index < LLVMCountParams(llfn));
+        assert!(index < LLVMCountParams(llfn),
+            "out of bounds argument access: {} out of {} arguments", index, LLVMCountParams(llfn));
         LLVMGetParam(llfn, index)
     }
 }
@@ -370,6 +371,12 @@ pub fn initialize_available_targets() {
                  LLVMInitializeMSP430Target,
                  LLVMInitializeMSP430TargetMC,
                  LLVMInitializeMSP430AsmPrinter);
+    init_target!(llvm_component = "sparc",
+                 LLVMInitializeSparcTargetInfo,
+                 LLVMInitializeSparcTarget,
+                 LLVMInitializeSparcTargetMC,
+                 LLVMInitializeSparcAsmPrinter,
+                 LLVMInitializeSparcAsmParser);
 }
 
 pub fn last_error() -> Option<String> {
diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs
index 6598b7dcc52..926c44824ce 100644
--- a/src/librustc_metadata/astencode.rs
+++ b/src/librustc_metadata/astencode.rs
@@ -102,8 +102,6 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> {
 /// ast-map.
 pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata,
                                      tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                     parent_def_path: ast_map::DefPath,
-                                     parent_did: DefId,
                                      ast: Ast<'tcx>,
                                      orig_did: DefId)
                                      -> &'tcx InlinedItem {
@@ -120,17 +118,9 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata,
     let ii = ast.item.decode((cdata, tcx, id_ranges));
     let item_node_id = tcx.sess.next_node_id();
     let ii = ast_map::map_decoded_item(&tcx.map,
-                                       parent_def_path,
-                                       parent_did,
                                        ii,
                                        item_node_id);
 
-    let inlined_did = tcx.map.local_def_id(item_node_id);
-    let ty = tcx.item_type(orig_did);
-    let generics = tcx.item_generics(orig_did);
-    tcx.item_types.borrow_mut().insert(inlined_did, ty);
-    tcx.generics.borrow_mut().insert(inlined_did, generics);
-
     for (id, entry) in ast.side_tables.decode((cdata, tcx, id_ranges)) {
         match entry {
             TableEntry::TypeRelativeDef(def) => {
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index d36242537b8..a9af4118c59 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -22,6 +22,7 @@ use rustc_back::PanicStrategy;
 use rustc::session::search_paths::PathKind;
 use rustc::middle;
 use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
+use rustc::util::common::record_time;
 use rustc::util::nodemap::FxHashSet;
 use rustc::middle::cstore::NativeLibrary;
 use rustc::hir::map::Definitions;
@@ -297,10 +298,14 @@ impl<'a> CrateLoader<'a> {
 
         let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
 
+        let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || {
+            crate_root.def_path_table.decode(&metadata)
+        });
+
         let mut cmeta = cstore::CrateMetadata {
             name: name,
             extern_crate: Cell::new(None),
-            key_map: metadata.load_key_map(crate_root.index),
+            def_path_table: def_path_table,
             proc_macros: crate_root.macro_derive_registrar.map(|_| {
                 self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
             }),
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index 7700ebde181..7ec847d24cf 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -16,7 +16,7 @@ use schema;
 
 use rustc::dep_graph::DepGraph;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefIndex, DefId};
-use rustc::hir::map::DefKey;
+use rustc::hir::map::definitions::DefPathTable;
 use rustc::hir::svh::Svh;
 use rustc::middle::cstore::{DepKind, ExternCrate};
 use rustc_back::PanicStrategy;
@@ -78,7 +78,7 @@ pub struct CrateMetadata {
     /// hashmap, which gives the reverse mapping.  This allows us to
     /// quickly retrace a `DefPath`, which is needed for incremental
     /// compilation support.
-    pub key_map: FxHashMap<DefKey, DefIndex>,
+    pub def_path_table: DefPathTable,
 
     pub dep_kind: Cell<DepKind>,
     pub source: CrateSource,
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 1a1bb1432ee..0ac3ffd5cb9 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -22,8 +22,7 @@ use rustc::ty::{self, Ty, TyCtxt};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
 
 use rustc::dep_graph::DepNode;
-use rustc::hir::map as hir_map;
-use rustc::hir::map::DefKey;
+use rustc::hir::map::{DefKey, DefPath, DisambiguatedDefPathData};
 use rustc::mir::Mir;
 use rustc::util::nodemap::{NodeSet, DefIdMap};
 use rustc_back::PanicStrategy;
@@ -189,8 +188,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<'a>(&self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                           -> Option<ty::AssociatedItem>
+    fn associated_item(&self, def: DefId) -> Option<ty::AssociatedItem>
     {
         self.dep_graph.read(DepNode::MetaData(def));
         self.get_crate_data(def.krate).get_associated_item(def.index)
@@ -336,18 +334,20 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         self.get_crate_data(cnum).is_no_builtins()
     }
 
-    fn def_index_for_def_key(&self,
-                             cnum: CrateNum,
-                             def: DefKey)
-                             -> Option<DefIndex> {
+    fn retrace_path(&self,
+                    cnum: CrateNum,
+                    path: &[DisambiguatedDefPathData])
+                    -> Option<DefId> {
         let cdata = self.get_crate_data(cnum);
-        cdata.key_map.get(&def).cloned()
+        cdata.def_path_table
+             .retrace_path(&path)
+             .map(|index| DefId { krate: cnum, index: index })
     }
 
     /// Returns the `DefKey` for a given `DefId`. This indicates the
     /// parent `DefId` as well as some idea of what kind of data the
     /// `DefId` refers to.
-    fn def_key(&self, def: DefId) -> hir_map::DefKey {
+    fn def_key(&self, def: DefId) -> DefKey {
         // Note: loading the def-key (or def-path) for a def-id is not
         // a *read* of its metadata. This is because the def-id is
         // really just an interned shorthand for a def-path, which is the
@@ -357,7 +357,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         self.get_crate_data(def.krate).def_key(def.index)
     }
 
-    fn relative_def_path(&self, def: DefId) -> Option<hir_map::DefPath> {
+    fn def_path(&self, def: DefId) -> DefPath {
         // See `Note` above in `def_key()` for why this read is
         // commented out:
         //
@@ -418,8 +418,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
             ident: ast::Ident::with_empty_ctxt(name),
             id: ast::DUMMY_NODE_ID,
             span: local_span,
-            imported_from: None, // FIXME
-            allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
             attrs: attrs,
             body: body,
         })
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 54c195b1881..400a3ac0e3e 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -12,12 +12,9 @@
 
 use astencode::decode_inlined_item;
 use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary};
-use index::Index;
 use schema::*;
 
-use rustc::hir::map as hir_map;
-use rustc::hir::map::{DefKey, DefPathData};
-use rustc::util::nodemap::FxHashMap;
+use rustc::hir::map::{DefKey, DefPath, DefPathData};
 use rustc::hir;
 use rustc::hir::intravisit::IdRange;
 
@@ -44,7 +41,7 @@ use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque};
 use syntax::attr;
 use syntax::ast::{self, NodeId};
 use syntax::codemap;
-use syntax_pos::{self, Span, BytePos, Pos};
+use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP};
 
 pub struct DecodeContext<'a, 'tcx: 'a> {
     opaque: opaque::Decoder<'a>,
@@ -456,14 +453,6 @@ impl<'a, 'tcx> MetadataBlob {
         Lazy::with_position(pos).decode(self)
     }
 
-    /// Go through each item in the metadata and create a map from that
-    /// item's def-key to the item's DefIndex.
-    pub fn load_key_map(&self, index: LazySeq<Index>) -> FxHashMap<DefKey, DefIndex> {
-        index.iter_enumerated(self.raw_bytes())
-            .map(|(index, item)| (item.decode(self).def_key.decode(self), index))
-            .collect()
-    }
-
     pub fn list_crate_metadata(&self, out: &mut io::Write) -> io::Result<()> {
         write!(out, "=External Dependencies=\n")?;
         let root = self.get_root();
@@ -515,7 +504,12 @@ impl<'tcx> EntryKind<'tcx> {
 }
 
 impl<'a, 'tcx> CrateMetadata {
+    fn is_proc_macro(&self, id: DefIndex) -> bool {
+        self.proc_macros.is_some() && id != CRATE_DEF_INDEX
+    }
+
     fn maybe_entry(&self, item_id: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
+        assert!(!self.is_proc_macro(item_id));
         self.root.index.lookup(self.blob.raw_bytes(), item_id)
     }
 
@@ -538,9 +532,8 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    fn item_name(&self, item: &Entry<'tcx>) -> ast::Name {
-        item.def_key
-            .decode(self)
+    fn item_name(&self, item_index: DefIndex) -> ast::Name {
+        self.def_key(item_index)
             .disambiguated_data
             .data
             .get_opt_name()
@@ -548,18 +541,17 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
     pub fn get_def(&self, index: DefIndex) -> Option<Def> {
-        if self.proc_macros.is_some() {
-            Some(match index {
-                CRATE_DEF_INDEX => Def::Mod(self.local_def_id(index)),
-                _ => Def::Macro(self.local_def_id(index)),
-            })
-        } else {
-            self.entry(index).kind.to_def(self.local_def_id(index))
+        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)),
         }
     }
 
     pub fn get_span(&self, index: DefIndex, sess: &Session) -> Span {
-        self.entry(index).span.decode((self, sess))
+        match self.is_proc_macro(index) {
+            true => DUMMY_SP,
+            false => self.entry(index).span.decode((self, sess)),
+        }
     }
 
     pub fn get_trait_def(&self,
@@ -574,7 +566,7 @@ impl<'a, 'tcx> CrateMetadata {
         ty::TraitDef::new(self.local_def_id(item_id),
                           data.unsafety,
                           data.paren_sugar,
-                          self.def_path(item_id).unwrap().deterministic_hash(tcx))
+                          self.def_path(item_id).deterministic_hash(tcx))
     }
 
     fn get_variant(&self,
@@ -590,13 +582,13 @@ impl<'a, 'tcx> CrateMetadata {
 
         (ty::VariantDef {
             did: self.local_def_id(data.struct_ctor.unwrap_or(index)),
-            name: self.item_name(item),
+            name: self.item_name(index),
             fields: item.children.decode(self).map(|index| {
                 let f = self.entry(index);
                 ty::FieldDef {
                     did: self.local_def_id(index),
-                    name: self.item_name(&f),
-                    vis: f.visibility
+                    name: self.item_name(index),
+                    vis: f.visibility.decode(self)
                 }
             }).collect(),
             disr_val: ConstInt::Infer(data.disr),
@@ -670,23 +662,23 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
     pub fn get_stability(&self, id: DefIndex) -> Option<attr::Stability> {
-        match self.proc_macros {
-            Some(_) if id != CRATE_DEF_INDEX => None,
-            _ => self.entry(id).stability.map(|stab| stab.decode(self)),
+        match self.is_proc_macro(id) {
+            true => None,
+            false => self.entry(id).stability.map(|stab| stab.decode(self)),
         }
     }
 
     pub fn get_deprecation(&self, id: DefIndex) -> Option<attr::Deprecation> {
-        match self.proc_macros {
-            Some(_) if id != CRATE_DEF_INDEX => None,
-            _ => self.entry(id).deprecation.map(|depr| depr.decode(self)),
+        match self.is_proc_macro(id) {
+            true => None,
+            false => self.entry(id).deprecation.map(|depr| depr.decode(self)),
         }
     }
 
     pub fn get_visibility(&self, id: DefIndex) -> ty::Visibility {
-        match self.proc_macros {
-            Some(_) => ty::Visibility::Public,
-            _ => self.entry(id).visibility,
+        match self.is_proc_macro(id) {
+            true => ty::Visibility::Public,
+            false => self.entry(id).visibility.decode(self),
         }
     }
 
@@ -767,7 +759,7 @@ impl<'a, 'tcx> CrateMetadata {
                             if let Some(def) = self.get_def(child_index) {
                                 callback(def::Export {
                                     def: def,
-                                    name: self.item_name(&self.entry(child_index)),
+                                    name: self.item_name(child_index),
                                 });
                             }
                         }
@@ -779,7 +771,7 @@ impl<'a, 'tcx> CrateMetadata {
                     _ => {}
                 }
 
-                let def_key = child.def_key.decode(self);
+                let def_key = self.def_key(child_index);
                 if let (Some(def), Some(name)) =
                     (self.get_def(child_index), def_key.disambiguated_data.data.get_opt_name()) {
                     callback(def::Export {
@@ -832,18 +824,17 @@ impl<'a, 'tcx> CrateMetadata {
                               id: DefIndex)
                               -> Option<&'tcx InlinedItem> {
         debug!("Looking up item: {:?}", id);
+        if self.is_proc_macro(id) { return None; }
         let item_doc = self.entry(id);
         let item_did = self.local_def_id(id);
-        let parent_def_id = self.local_def_id(self.def_key(id).parent.unwrap());
-        let mut parent_def_path = self.def_path(id).unwrap();
-        parent_def_path.data.pop();
         item_doc.ast.map(|ast| {
             let ast = ast.decode(self);
-            decode_inlined_item(self, tcx, parent_def_path, parent_def_id, ast, item_did)
+            decode_inlined_item(self, tcx, ast, item_did)
         })
     }
 
     pub fn is_item_mir_available(&self, id: DefIndex) -> bool {
+        !self.is_proc_macro(id) &&
         self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some()
     }
 
@@ -874,13 +865,16 @@ impl<'a, 'tcx> CrateMetadata {
                               tcx: TyCtxt<'a, 'tcx, 'tcx>,
                               id: DefIndex)
                               -> Option<Mir<'tcx>> {
-        self.entry(id).mir.map(|mir| mir.decode((self, tcx)))
+        match self.is_proc_macro(id) {
+            true => None,
+            false => self.entry(id).mir.map(|mir| mir.decode((self, tcx))),
+        }
     }
 
     pub fn get_associated_item(&self, id: DefIndex) -> Option<ty::AssociatedItem> {
         let item = self.entry(id);
         let parent_and_name = || {
-            let def_key = item.def_key.decode(self);
+            let def_key = self.def_key(id);
             (self.local_def_id(def_key.parent.unwrap()),
              def_key.disambiguated_data.data.get_opt_name().unwrap())
         };
@@ -891,7 +885,7 @@ impl<'a, 'tcx> CrateMetadata {
                 ty::AssociatedItem {
                     name: name,
                     kind: ty::AssociatedKind::Const,
-                    vis: item.visibility,
+                    vis: item.visibility.decode(self),
                     defaultness: container.defaultness(),
                     def_id: self.local_def_id(id),
                     container: container.with_def_id(parent),
@@ -904,7 +898,7 @@ impl<'a, 'tcx> CrateMetadata {
                 ty::AssociatedItem {
                     name: name,
                     kind: ty::AssociatedKind::Method,
-                    vis: item.visibility,
+                    vis: item.visibility.decode(self),
                     defaultness: data.container.defaultness(),
                     def_id: self.local_def_id(id),
                     container: data.container.with_def_id(parent),
@@ -916,7 +910,7 @@ impl<'a, 'tcx> CrateMetadata {
                 ty::AssociatedItem {
                     name: name,
                     kind: ty::AssociatedKind::Type,
-                    vis: item.visibility,
+                    vis: item.visibility.decode(self),
                     defaultness: container.defaultness(),
                     def_id: self.local_def_id(id),
                     container: container.with_def_id(parent),
@@ -950,14 +944,14 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
     pub fn get_item_attrs(&self, node_id: DefIndex) -> Vec<ast::Attribute> {
-        if self.proc_macros.is_some() && node_id != CRATE_DEF_INDEX {
+        if self.is_proc_macro(node_id) {
             return Vec::new();
         }
         // The attributes for a tuple struct are attached to the definition, not the ctor;
         // we assume that someone passing in a tuple struct ctor is actually wanting to
         // look at the definition
         let mut item = self.entry(node_id);
-        let def_key = item.def_key.decode(self);
+        let def_key = self.def_key(node_id);
         if def_key.disambiguated_data.data == DefPathData::StructCtor {
             item = self.entry(def_key.parent.unwrap());
         }
@@ -968,7 +962,7 @@ impl<'a, 'tcx> CrateMetadata {
         self.entry(id)
             .children
             .decode(self)
-            .map(|index| self.item_name(&self.entry(index)))
+            .map(|index| self.item_name(index))
             .collect()
     }
 
@@ -1012,6 +1006,7 @@ impl<'a, 'tcx> CrateMetadata {
         let filter = match filter.map(|def_id| self.reverse_translate_def_id(def_id)) {
             Some(Some(def_id)) => Some((def_id.krate.as_u32(), def_id.index)),
             Some(None) => return,
+            None if self.proc_macros.is_some() => return,
             None => None,
         };
 
@@ -1030,7 +1025,7 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
     pub fn get_trait_of_item(&self, id: DefIndex) -> Option<DefId> {
-        self.entry(id).def_key.decode(self).parent.and_then(|parent_index| {
+        self.def_key(id).parent.and_then(|parent_index| {
             match self.entry(parent_index).kind {
                 EntryKind::Trait(_) => Some(self.local_def_id(parent_index)),
                 _ => None,
@@ -1076,7 +1071,7 @@ impl<'a, 'tcx> CrateMetadata {
     pub fn get_macro(&self, id: DefIndex) -> (ast::Name, MacroDef) {
         let entry = self.entry(id);
         match entry.kind {
-            EntryKind::MacroDef(macro_def) => (self.item_name(&entry), macro_def.decode(self)),
+            EntryKind::MacroDef(macro_def) => (self.item_name(id), macro_def.decode(self)),
             _ => bug!(),
         }
     }
@@ -1129,21 +1124,14 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn def_key(&self, id: DefIndex) -> hir_map::DefKey {
-        debug!("def_key: id={:?}", id);
-        self.entry(id).def_key.decode(self)
+    pub fn def_key(&self, index: DefIndex) -> DefKey {
+        self.def_path_table.def_key(index)
     }
 
-    // Returns the path leading to the thing with this `id`. Note that
-    // some def-ids don't wind up in the metadata, so `def_path` sometimes
-    // returns `None`
-    pub fn def_path(&self, id: DefIndex) -> Option<hir_map::DefPath> {
+    // Returns the path leading to the thing with this `id`.
+    pub fn def_path(&self, id: DefIndex) -> DefPath {
         debug!("def_path(id={:?})", id);
-        if self.maybe_entry(id).is_some() {
-            Some(hir_map::DefPath::make(self.cnum, id, |parent| self.def_key(parent)))
-        } else {
-            None
-        }
+        DefPath::make(self.cnum, id, |parent| self.def_path_table.def_key(parent))
     }
 
     /// Imports the codemap from an external crate into the codemap of the crate
diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs
index 6cf1a9e8a39..d3a2b6f1683 100644
--- a/src/librustc_metadata/diagnostics.rs
+++ b/src/librustc_metadata/diagnostics.rs
@@ -57,9 +57,9 @@ An unknown "kind" was specified for a link attribute. Erroneous code example:
 
 Please specify a valid "kind" value, from one of the following:
 
- * static
- * dylib
- * framework
+* static
+* dylib
+* framework
 
 "##,
 
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 443f3fbaa6e..bc0a64b9a51 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -16,6 +16,7 @@ use rustc::middle::cstore::{InlinedItemRef, LinkMeta};
 use rustc::middle::cstore::{LinkagePreference, NativeLibrary};
 use rustc::hir::def;
 use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId};
+use rustc::hir::map::definitions::DefPathTable;
 use rustc::middle::dependency_format::Linkage;
 use rustc::middle::lang_items;
 use rustc::mir;
@@ -233,13 +234,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         Ok(())
     }
 
-    /// For every DefId that we create a metadata item for, we include a
-    /// serialized copy of its DefKey, which allows us to recreate a path.
-    fn encode_def_key(&mut self, def_id: DefId) -> Lazy<hir::map::DefKey> {
-        let tcx = self.tcx;
-        self.lazy(&tcx.map.def_key(def_id))
-    }
-
     fn encode_item_variances(&mut self, def_id: DefId) -> LazySeq<ty::Variance> {
         let tcx = self.tcx;
         self.lazy_seq(tcx.item_variances(def_id).iter().cloned())
@@ -274,9 +268,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         Entry {
             kind: EntryKind::Variant(self.lazy(&data)),
-            visibility: enum_vis.simplify(),
+            visibility: self.lazy(&ty::Visibility::from_hir(enum_vis, enum_id, tcx)),
             span: self.lazy(&tcx.def_span(def_id)),
-            def_key: self.encode_def_key(def_id),
             attributes: self.encode_attributes(&tcx.get_attrs(def_id)),
             children: self.lazy_seq(variant.fields.iter().map(|f| {
                 assert!(f.did.is_local());
@@ -313,9 +306,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         Entry {
             kind: EntryKind::Mod(self.lazy(&data)),
-            visibility: vis.simplify(),
+            visibility: self.lazy(&ty::Visibility::from_hir(vis, id, tcx)),
             span: self.lazy(&md.inner),
-            def_key: self.encode_def_key(def_id),
             attributes: self.encode_attributes(attrs),
             children: self.lazy_seq(md.item_ids.iter().map(|item_id| {
                 tcx.map.local_def_id(item_id.id).index
@@ -335,30 +327,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 }
 
-trait Visibility {
-    fn simplify(&self) -> ty::Visibility;
-}
-
-impl Visibility for hir::Visibility {
-    fn simplify(&self) -> ty::Visibility {
-        if *self == hir::Public {
-            ty::Visibility::Public
-        } else {
-            ty::Visibility::PrivateExternal
-        }
-    }
-}
-
-impl Visibility for ty::Visibility {
-    fn simplify(&self) -> ty::Visibility {
-        if *self == ty::Visibility::Public {
-            ty::Visibility::Public
-        } else {
-            ty::Visibility::PrivateExternal
-        }
-    }
-}
-
 impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
     fn encode_fields(&mut self, adt_def_id: DefId) {
         let def = self.tcx.lookup_adt_def(adt_def_id);
@@ -394,9 +362,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         Entry {
             kind: EntryKind::Field,
-            visibility: field.vis.simplify(),
+            visibility: self.lazy(&field.vis),
             span: self.lazy(&tcx.def_span(def_id)),
-            def_key: self.encode_def_key(def_id),
             attributes: self.encode_attributes(&variant_data.fields()[field_index].attrs),
             children: LazySeq::empty(),
             stability: self.encode_stability(def_id),
@@ -428,9 +395,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         Entry {
             kind: EntryKind::Struct(self.lazy(&data)),
-            visibility: struct_vis.simplify(),
+            visibility: self.lazy(&ty::Visibility::from_hir(struct_vis, struct_id, tcx)),
             span: self.lazy(&tcx.def_span(def_id)),
-            def_key: self.encode_def_key(def_id),
             attributes: LazySeq::empty(),
             children: LazySeq::empty(),
             stability: self.encode_stability(def_id),
@@ -495,9 +461,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         Entry {
             kind: kind,
-            visibility: trait_item.vis.simplify(),
+            visibility: self.lazy(&trait_item.vis),
             span: self.lazy(&ast_item.span),
-            def_key: self.encode_def_key(def_id),
             attributes: self.encode_attributes(&ast_item.attrs),
             children: LazySeq::empty(),
             stability: self.encode_stability(def_id),
@@ -585,9 +550,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         Entry {
             kind: kind,
-            visibility: impl_item.vis.simplify(),
+            visibility: self.lazy(&impl_item.vis),
             span: self.lazy(&ast_item.span),
-            def_key: self.encode_def_key(def_id),
             attributes: self.encode_attributes(&ast_item.attrs),
             children: LazySeq::empty(),
             stability: self.encode_stability(def_id),
@@ -748,9 +712,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         Entry {
             kind: kind,
-            visibility: item.vis.simplify(),
+            visibility: self.lazy(&ty::Visibility::from_hir(&item.vis, item.id, tcx)),
             span: self.lazy(&item.span),
-            def_key: self.encode_def_key(def_id),
             attributes: self.encode_attributes(&item.attrs),
             children: match item.node {
                 hir::ItemForeignMod(ref fm) => {
@@ -858,14 +821,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
     /// Serialize the text of exported macros
     fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef) -> Entry<'tcx> {
-        let def_id = self.tcx.map.local_def_id(macro_def.id);
         Entry {
             kind: EntryKind::MacroDef(self.lazy(&MacroDef {
                 body: ::syntax::print::pprust::tts_to_string(&macro_def.body)
             })),
-            visibility: ty::Visibility::Public,
+            visibility: self.lazy(&ty::Visibility::Public),
             span: self.lazy(&macro_def.span),
-            def_key: self.encode_def_key(def_id),
 
             attributes: self.encode_attributes(&macro_def.attrs),
             children: LazySeq::empty(),
@@ -965,9 +926,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         Entry {
             kind: kind,
-            visibility: nitem.vis.simplify(),
+            visibility: self.lazy(&ty::Visibility::from_hir(&nitem.vis, nitem.id, tcx)),
             span: self.lazy(&nitem.span),
-            def_key: self.encode_def_key(def_id),
             attributes: self.encode_attributes(&nitem.attrs),
             children: LazySeq::empty(),
             stability: self.encode_stability(def_id),
@@ -1048,9 +1008,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let tcx = self.tcx;
         Entry {
             kind: EntryKind::Type,
-            visibility: ty::Visibility::Public,
+            visibility: self.lazy(&ty::Visibility::Public),
             span: self.lazy(&tcx.def_span(def_id)),
-            def_key: self.encode_def_key(def_id),
             attributes: LazySeq::empty(),
             children: LazySeq::empty(),
             stability: None,
@@ -1077,9 +1036,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         Entry {
             kind: EntryKind::Closure(self.lazy(&data)),
-            visibility: ty::Visibility::Public,
+            visibility: self.lazy(&ty::Visibility::Public),
             span: self.lazy(&tcx.def_span(def_id)),
-            def_key: self.encode_def_key(def_id),
             attributes: self.encode_attributes(&tcx.get_attrs(def_id)),
             children: LazySeq::empty(),
             stability: None,
@@ -1179,6 +1137,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             })
             .map(|filemap| &**filemap))
     }
+
+    fn encode_def_path_table(&mut self) -> Lazy<DefPathTable> {
+        let definitions = self.tcx.map.definitions();
+        self.lazy(definitions.def_path_table())
+    }
 }
 
 struct ImplVisitor<'a, 'tcx: 'a> {
@@ -1276,6 +1239,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let codemap = self.encode_codemap();
         let codemap_bytes = self.position() - i;
 
+        // Encode DefPathTable
+        i = self.position();
+        let def_path_table = self.encode_def_path_table();
+        let def_path_table_bytes = self.position() - i;
+
         // Encode the def IDs of impls, for coherence checking.
         i = self.position();
         let impls = self.encode_impls();
@@ -1321,6 +1289,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             lang_items_missing: lang_items_missing,
             native_libraries: native_libraries,
             codemap: codemap,
+            def_path_table: def_path_table,
             impls: impls,
             exported_symbols: exported_symbols,
             index: index,
@@ -1343,6 +1312,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             println!("         codemap bytes: {}", codemap_bytes);
             println!("            impl bytes: {}", impl_bytes);
             println!("    exp. symbols bytes: {}", exported_symbols_bytes);
+            println!("  def-path table bytes: {}", def_path_table_bytes);
             println!("            item bytes: {}", item_bytes);
             println!("           index bytes: {}", index_bytes);
             println!("            zero bytes: {}", zero_bytes);
diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs
index 53e6988c756..5b52b268849 100644
--- a/src/librustc_metadata/index.rs
+++ b/src/librustc_metadata/index.rs
@@ -70,7 +70,7 @@ impl<'tcx> LazySeq<Index> {
                index,
                words.len());
 
-        let position = u32::from_le(words[index]);
+        let position = u32::from_le(words[index].get());
         if position == u32::MAX {
             debug!("Index::lookup: position=u32::MAX");
             None
@@ -84,7 +84,7 @@ impl<'tcx> LazySeq<Index> {
                                bytes: &'a [u8])
                                -> impl Iterator<Item = (DefIndex, Lazy<Entry<'tcx>>)> + 'a {
         let words = &bytes_to_words(&bytes[self.position..])[..self.len];
-        words.iter().enumerate().filter_map(|(index, &position)| {
+        words.iter().map(|word| word.get()).enumerate().filter_map(|(index, position)| {
             if position == u32::MAX {
                 None
             } else {
@@ -95,8 +95,16 @@ impl<'tcx> LazySeq<Index> {
     }
 }
 
-fn bytes_to_words(b: &[u8]) -> &[u32] {
-    unsafe { slice::from_raw_parts(b.as_ptr() as *const u32, b.len() / 4) }
+#[repr(packed)]
+#[derive(Copy, Clone)]
+struct Unaligned<T>(T);
+
+impl<T> Unaligned<T> {
+    fn get(self) -> T { self.0 }
+}
+
+fn bytes_to_words(b: &[u8]) -> &[Unaligned<u32>] {
+    unsafe { slice::from_raw_parts(b.as_ptr() as *const Unaligned<u32>, b.len() / 4) }
 }
 
 fn words_to_bytes(w: &[u32]) -> &[u8] {
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index f92051cbf19..2bd5a9ea59d 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -179,6 +179,7 @@ pub struct CrateRoot {
     pub lang_items_missing: LazySeq<lang_items::LangItem>,
     pub native_libraries: LazySeq<NativeLibrary>,
     pub codemap: LazySeq<syntax_pos::FileMap>,
+    pub def_path_table: Lazy<hir::map::definitions::DefPathTable>,
     pub impls: LazySeq<TraitImpls>,
     pub exported_symbols: LazySeq<DefIndex>,
     pub index: LazySeq<index::Index>,
@@ -200,9 +201,8 @@ pub struct TraitImpls {
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct Entry<'tcx> {
     pub kind: EntryKind<'tcx>,
-    pub visibility: ty::Visibility,
+    pub visibility: Lazy<ty::Visibility>,
     pub span: Lazy<Span>,
-    pub def_key: Lazy<hir::map::DefKey>,
     pub attributes: LazySeq<ast::Attribute>,
     pub children: LazySeq<DefIndex>,
     pub stability: Option<Lazy<attr::Stability>>,
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index cb69de2cb3c..b355c8f2c4c 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -26,7 +26,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Block {
             extent: cx.tcx.region_maps.node_extent(self.id),
             span: self.span,
             stmts: stmts,
-            expr: self.expr.to_ref()
+            expr: self.expr.to_ref(),
         }
     }
 }
@@ -34,39 +34,44 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Block {
 fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                 block_id: ast::NodeId,
                                 stmts: &'tcx [hir::Stmt])
-                                -> Vec<StmtRef<'tcx>>
-{
+                                -> Vec<StmtRef<'tcx>> {
     let mut result = vec![];
     for (index, stmt) in stmts.iter().enumerate() {
         match stmt.node {
-            hir::StmtExpr(ref expr, id) | hir::StmtSemi(ref expr, id) =>
+            hir::StmtExpr(ref expr, id) |
+            hir::StmtSemi(ref expr, id) => {
                 result.push(StmtRef::Mirror(Box::new(Stmt {
                     span: stmt.span,
                     kind: StmtKind::Expr {
                         scope: cx.tcx.region_maps.node_extent(id),
-                        expr: expr.to_ref()
+                        expr: expr.to_ref(),
+                    },
+                })))
+            }
+            hir::StmtDecl(ref decl, id) => {
+                match decl.node {
+                    hir::DeclItem(..) => {
+                        // ignore for purposes of the MIR
                     }
-                }))),
-            hir::StmtDecl(ref decl, id) => match decl.node {
-                hir::DeclItem(..) => { /* ignore for purposes of the MIR */ }
-                hir::DeclLocal(ref local) => {
-                    let remainder_extent = CodeExtentData::Remainder(BlockRemainder {
-                        block: block_id,
-                        first_statement_index: index as u32,
-                    });
-                    let remainder_extent =
-                        cx.tcx.region_maps.lookup_code_extent(remainder_extent);
+                    hir::DeclLocal(ref local) => {
+                        let remainder_extent = CodeExtentData::Remainder(BlockRemainder {
+                            block: block_id,
+                            first_statement_index: index as u32,
+                        });
+                        let remainder_extent =
+                            cx.tcx.region_maps.lookup_code_extent(remainder_extent);
 
-                    let pattern = Pattern::from_hir(cx.tcx, &local.pat);
-                    result.push(StmtRef::Mirror(Box::new(Stmt {
-                        span: stmt.span,
-                        kind: StmtKind::Let {
-                            remainder_scope: remainder_extent,
-                            init_scope: cx.tcx.region_maps.node_extent(id),
-                            pattern: pattern,
-                            initializer: local.init.to_ref(),
-                        },
-                    })));
+                        let pattern = Pattern::from_hir(cx.tcx, &local.pat);
+                        result.push(StmtRef::Mirror(Box::new(Stmt {
+                            span: stmt.span,
+                            kind: StmtKind::Let {
+                                remainder_scope: remainder_extent,
+                                init_scope: cx.tcx.region_maps.node_extent(id),
+                                pattern: pattern,
+                                initializer: local.init.to_ref(),
+                            },
+                        })));
+                    }
                 }
             }
         }
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index bd4724159b4..d579cdb042f 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -36,7 +36,8 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
         let adj = cx.tcx.tables().adjustments.get(&self.id).cloned();
 
         debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}",
-               expr, adj);
+               expr,
+               adj);
 
         // Now apply adjustments, if any.
         match adj.map(|adj| (adj.kind, adj.target)) {
@@ -78,41 +79,44 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                 for i in 0..autoderefs {
                     let i = i as u32;
                     let adjusted_ty =
-                        expr.ty.adjust_for_autoderef(
-                            cx.tcx,
-                            self.id,
-                            self.span,
-                            i,
-                            |mc| cx.tcx.tables().method_map.get(&mc).map(|m| m.ty));
-                    debug!("make_mirror: autoderef #{}, adjusted_ty={:?}", i, adjusted_ty);
+                        expr.ty.adjust_for_autoderef(cx.tcx, self.id, self.span, i, |mc| {
+                            cx.tcx.tables().method_map.get(&mc).map(|m| m.ty)
+                        });
+                    debug!("make_mirror: autoderef #{}, adjusted_ty={:?}",
+                           i,
+                           adjusted_ty);
                     let method_key = ty::MethodCall::autoderef(self.id, i);
-                    let meth_ty =
-                        cx.tcx.tables().method_map.get(&method_key).map(|m| m.ty);
+                    let meth_ty = cx.tcx.tables().method_map.get(&method_key).map(|m| m.ty);
                     let kind = if let Some(meth_ty) = meth_ty {
                         debug!("make_mirror: overloaded autoderef (meth_ty={:?})", meth_ty);
 
                         let ref_ty = cx.tcx.no_late_bound_regions(&meth_ty.fn_ret());
                         let (region, mutbl) = match ref_ty {
-                            Some(&ty::TyS {
-                                sty: ty::TyRef(region, mt), ..
-                            }) => (region, mt.mutbl),
-                            _ => span_bug!(expr.span, "autoderef returned bad type")
+                            Some(&ty::TyS { sty: ty::TyRef(region, mt), .. }) => (region, mt.mutbl),
+                            _ => span_bug!(expr.span, "autoderef returned bad type"),
                         };
 
                         expr = Expr {
                             temp_lifetime: temp_lifetime,
-                            ty: cx.tcx.mk_ref(
-                                region, ty::TypeAndMut { ty: expr.ty, mutbl: mutbl }),
+                            ty: cx.tcx.mk_ref(region,
+                                              ty::TypeAndMut {
+                                                  ty: expr.ty,
+                                                  mutbl: mutbl,
+                                              }),
                             span: expr.span,
                             kind: ExprKind::Borrow {
                                 region: region,
                                 borrow_kind: to_borrow_kind(mutbl),
-                                arg: expr.to_ref()
-                            }
+                                arg: expr.to_ref(),
+                            },
                         };
 
-                        overloaded_lvalue(cx, self, method_key,
-                                          PassArgs::ByRef, expr.to_ref(), vec![])
+                        overloaded_lvalue(cx,
+                                          self,
+                                          method_key,
+                                          PassArgs::ByRef,
+                                          expr.to_ref(),
+                                          vec![])
                     } else {
                         debug!("make_mirror: built-in autoderef");
                         ExprKind::Deref { arg: expr.to_ref() }
@@ -148,7 +152,11 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                             let region = cx.tcx.mk_region(region);
                             expr = Expr {
                                 temp_lifetime: temp_lifetime,
-                                ty: cx.tcx.mk_ref(region, ty::TypeAndMut { ty: expr.ty, mutbl: m }),
+                                ty: cx.tcx.mk_ref(region,
+                                                  ty::TypeAndMut {
+                                                      ty: expr.ty,
+                                                      mutbl: m,
+                                                  }),
                                 span: self.span,
                                 kind: ExprKind::Borrow {
                                     region: region,
@@ -240,12 +248,12 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
                 let sig = match method.ty.sty {
                     ty::TyFnDef(.., fn_ty) => &fn_ty.sig,
-                    _ => span_bug!(expr.span, "type of method is not an fn")
+                    _ => span_bug!(expr.span, "type of method is not an fn"),
                 };
 
-                let sig = cx.tcx.no_late_bound_regions(sig).unwrap_or_else(|| {
-                    span_bug!(expr.span, "method call has late-bound regions")
-                });
+                let sig = cx.tcx
+                    .no_late_bound_regions(sig)
+                    .unwrap_or_else(|| span_bug!(expr.span, "method call has late-bound regions"));
 
                 assert_eq!(sig.inputs().len(), 2);
 
@@ -253,44 +261,49 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     ty: sig.inputs()[1],
                     temp_lifetime: temp_lifetime,
                     span: expr.span,
-                    kind: ExprKind::Tuple {
-                        fields: args.iter().map(ToRef::to_ref).collect()
-                    }
+                    kind: ExprKind::Tuple { fields: args.iter().map(ToRef::to_ref).collect() },
                 };
 
                 ExprKind::Call {
                     ty: method.ty,
                     fun: method.to_ref(),
-                    args: vec![fun.to_ref(), tupled_args.to_ref()]
+                    args: vec![fun.to_ref(), tupled_args.to_ref()],
                 }
             } else {
                 let adt_data = if let hir::ExprPath(hir::QPath::Resolved(_, ref path)) = fun.node {
                     // Tuple-like ADTs are represented as ExprCall. We convert them here.
-                    expr_ty.ty_adt_def().and_then(|adt_def|{
+                    expr_ty.ty_adt_def().and_then(|adt_def| {
                         match path.def {
                             Def::VariantCtor(variant_id, CtorKind::Fn) => {
                                 Some((adt_def, adt_def.variant_index_with_id(variant_id)))
-                            },
-                            Def::StructCtor(_, CtorKind::Fn) => {
-                                Some((adt_def, 0))
-                            },
-                            _ => None
+                            }
+                            Def::StructCtor(_, CtorKind::Fn) => Some((adt_def, 0)),
+                            _ => None,
                         }
                     })
-                } else { None };
+                } else {
+                    None
+                };
                 if let Some((adt_def, index)) = adt_data {
-                    let substs = cx.tcx.tables().node_id_item_substs(fun.id)
+                    let substs = cx.tcx
+                        .tables()
+                        .node_id_item_substs(fun.id)
                         .unwrap_or_else(|| cx.tcx.intern_substs(&[]));
-                    let field_refs = args.iter().enumerate().map(|(idx, e)| FieldExprRef {
-                        name: Field::new(idx),
-                        expr: e.to_ref()
-                    }).collect();
+                    let field_refs = args.iter()
+                        .enumerate()
+                        .map(|(idx, e)| {
+                            FieldExprRef {
+                                name: Field::new(idx),
+                                expr: e.to_ref(),
+                            }
+                        })
+                        .collect();
                     ExprKind::Adt {
                         adt_def: adt_def,
                         substs: substs,
                         variant_index: index,
                         fields: field_refs,
-                        base: None
+                        base: None,
                     }
                 } else {
                     ExprKind::Call {
@@ -314,9 +327,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             }
         }
 
-        hir::ExprBlock(ref blk) => {
-            ExprKind::Block { body: &blk }
-        }
+        hir::ExprBlock(ref blk) => ExprKind::Block { body: &blk },
 
         hir::ExprAssign(ref lhs, ref rhs) => {
             ExprKind::Assign {
@@ -332,8 +343,12 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 } else {
                     PassArgs::ByRef
                 };
-                overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id),
-                                    pass_args, lhs.to_ref(), vec![rhs])
+                overloaded_operator(cx,
+                                    expr,
+                                    ty::MethodCall::expr(expr.id),
+                                    pass_args,
+                                    lhs.to_ref(),
+                                    vec![rhs])
             } else {
                 ExprKind::AssignOp {
                     op: bin_op(op.node),
@@ -343,9 +358,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             }
         }
 
-        hir::ExprLit(..) => ExprKind::Literal {
-            literal: cx.const_eval_literal(expr)
-        },
+        hir::ExprLit(..) => ExprKind::Literal { literal: cx.const_eval_literal(expr) },
 
         hir::ExprBinary(op, ref lhs, ref rhs) => {
             if cx.tcx.tables().is_method_call(expr.id) {
@@ -354,8 +367,12 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 } else {
                     PassArgs::ByRef
                 };
-                overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id),
-                                    pass_args, lhs.to_ref(), vec![rhs])
+                overloaded_operator(cx,
+                                    expr,
+                                    ty::MethodCall::expr(expr.id),
+                                    pass_args,
+                                    lhs.to_ref(),
+                                    vec![rhs])
             } else {
                 // FIXME overflow
                 match (op.node, cx.constness) {
@@ -405,8 +422,12 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
         hir::ExprIndex(ref lhs, ref index) => {
             if cx.tcx.tables().is_method_call(expr.id) {
-                overloaded_lvalue(cx, expr, ty::MethodCall::expr(expr.id),
-                                  PassArgs::ByValue, lhs.to_ref(), vec![index])
+                overloaded_lvalue(cx,
+                                  expr,
+                                  ty::MethodCall::expr(expr.id),
+                                  PassArgs::ByValue,
+                                  lhs.to_ref(),
+                                  vec![index])
             } else {
                 ExprKind::Index {
                     lhs: lhs.to_ref(),
@@ -417,8 +438,12 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
         hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => {
             if cx.tcx.tables().is_method_call(expr.id) {
-                overloaded_lvalue(cx, expr, ty::MethodCall::expr(expr.id),
-                                  PassArgs::ByValue, arg.to_ref(), vec![])
+                overloaded_lvalue(cx,
+                                  expr,
+                                  ty::MethodCall::expr(expr.id),
+                                  PassArgs::ByValue,
+                                  arg.to_ref(),
+                                  vec![])
             } else {
                 ExprKind::Deref { arg: arg.to_ref() }
             }
@@ -426,8 +451,12 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
         hir::ExprUnary(hir::UnOp::UnNot, ref arg) => {
             if cx.tcx.tables().is_method_call(expr.id) {
-                overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id),
-                                    PassArgs::ByValue, arg.to_ref(), vec![])
+                overloaded_operator(cx,
+                                    expr,
+                                    ty::MethodCall::expr(expr.id),
+                                    PassArgs::ByValue,
+                                    arg.to_ref(),
+                                    vec![])
             } else {
                 ExprKind::Unary {
                     op: UnOp::Not,
@@ -438,14 +467,16 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
         hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => {
             if cx.tcx.tables().is_method_call(expr.id) {
-                overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id),
-                                    PassArgs::ByValue, arg.to_ref(), vec![])
+                overloaded_operator(cx,
+                                    expr,
+                                    ty::MethodCall::expr(expr.id),
+                                    PassArgs::ByValue,
+                                    arg.to_ref(),
+                                    vec![])
             } else {
                 // FIXME runtime-overflow
                 if let hir::ExprLit(_) = arg.node {
-                    ExprKind::Literal {
-                        literal: cx.const_eval_literal(expr),
-                    }
+                    ExprKind::Literal { literal: cx.const_eval_literal(expr) }
                 } else {
                     ExprKind::Unary {
                         op: UnOp::Neg,
@@ -457,56 +488,54 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
         hir::ExprStruct(ref qpath, ref fields, ref base) => {
             match expr_ty.sty {
-                ty::TyAdt(adt, substs) => match adt.adt_kind() {
-                    AdtKind::Struct | AdtKind::Union => {
-                        let field_refs = field_refs(&adt.variants[0], fields);
-                        ExprKind::Adt {
-                            adt_def: adt,
-                            variant_index: 0,
-                            substs: substs,
-                            fields: field_refs,
-                            base: base.as_ref().map(|base| {
-                                FruInfo {
-                                    base: base.to_ref(),
-                                    field_types:
-                                        cx.tcx.tables().fru_field_types[&expr.id].clone()
-                                }
-                            })
+                ty::TyAdt(adt, substs) => {
+                    match adt.adt_kind() {
+                        AdtKind::Struct | AdtKind::Union => {
+                            let field_refs = field_refs(&adt.variants[0], fields);
+                            ExprKind::Adt {
+                                adt_def: adt,
+                                variant_index: 0,
+                                substs: substs,
+                                fields: field_refs,
+                                base: base.as_ref().map(|base| {
+                                    FruInfo {
+                                        base: base.to_ref(),
+                                        field_types: cx.tcx.tables().fru_field_types[&expr.id]
+                                            .clone(),
+                                    }
+                                }),
+                            }
                         }
-                    }
-                    AdtKind::Enum => {
-                        let def = match *qpath {
-                            hir::QPath::Resolved(_, ref path) => path.def,
-                            hir::QPath::TypeRelative(..) => Def::Err
-                        };
-                        match def {
-                            Def::Variant(variant_id) => {
-                                assert!(base.is_none());
-
-                                let index = adt.variant_index_with_id(variant_id);
-                                let field_refs = field_refs(&adt.variants[index], fields);
-                                ExprKind::Adt {
-                                    adt_def: adt,
-                                    variant_index: index,
-                                    substs: substs,
-                                    fields: field_refs,
-                                    base: None
+                        AdtKind::Enum => {
+                            let def = match *qpath {
+                                hir::QPath::Resolved(_, ref path) => path.def,
+                                hir::QPath::TypeRelative(..) => Def::Err,
+                            };
+                            match def {
+                                Def::Variant(variant_id) => {
+                                    assert!(base.is_none());
+
+                                    let index = adt.variant_index_with_id(variant_id);
+                                    let field_refs = field_refs(&adt.variants[index], fields);
+                                    ExprKind::Adt {
+                                        adt_def: adt,
+                                        variant_index: index,
+                                        substs: substs,
+                                        fields: field_refs,
+                                        base: None,
+                                    }
+                                }
+                                _ => {
+                                    span_bug!(expr.span, "unexpected def: {:?}", def);
                                 }
-                            }
-                            _ => {
-                                span_bug!(
-                                    expr.span,
-                                    "unexpected def: {:?}",
-                                    def);
                             }
                         }
                     }
-                },
+                }
                 _ => {
-                    span_bug!(
-                        expr.span,
-                        "unexpected type for struct literal: {:?}",
-                        expr_ty);
+                    span_bug!(expr.span,
+                              "unexpected type for struct literal: {:?}",
+                              expr_ty);
                 }
             }
         }
@@ -516,9 +545,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             let (def_id, substs) = match closure_ty.sty {
                 ty::TyClosure(def_id, substs) => (def_id, substs),
                 _ => {
-                    span_bug!(expr.span,
-                              "closure expr w/o closure type: {:?}",
-                              closure_ty);
+                    span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty);
                 }
             };
             let upvars = cx.tcx.with_freevars(expr.id, |freevars| {
@@ -543,69 +570,81 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             ExprKind::InlineAsm {
                 asm: asm,
                 outputs: outputs.to_ref(),
-                inputs: inputs.to_ref()
+                inputs: inputs.to_ref(),
             }
         }
 
         // Now comes the rote stuff:
-
-        hir::ExprRepeat(ref v, ref c) => ExprKind::Repeat {
-            value: v.to_ref(),
-            count: TypedConstVal {
-                ty: cx.tcx.tables().expr_ty(c),
-                span: c.span,
-                value: match const_eval::eval_const_expr(cx.tcx.global_tcx(), c) {
-                    ConstVal::Integral(ConstInt::Usize(u)) => u,
-                    other => bug!("constant evaluation of repeat count yielded {:?}", other),
+        hir::ExprRepeat(ref v, ref c) => {
+            ExprKind::Repeat {
+                value: v.to_ref(),
+                count: TypedConstVal {
+                    ty: cx.tcx.tables().expr_ty(c),
+                    span: c.span,
+                    value: match const_eval::eval_const_expr(cx.tcx.global_tcx(), c) {
+                        ConstVal::Integral(ConstInt::Usize(u)) => u,
+                        other => bug!("constant evaluation of repeat count yielded {:?}", other),
+                    },
                 },
             }
-        },
-        hir::ExprRet(ref v) =>
-            ExprKind::Return { value: v.to_ref() },
-        hir::ExprBreak(label, ref value) =>
+        }
+        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()
-            },
-        hir::ExprAgain(label) =>
+                label: label.map(|label| cx.tcx.region_maps.node_extent(label.loop_id)),
+                value: value.to_ref(),
+            }
+        }
+        hir::ExprAgain(label) => {
             ExprKind::Continue {
-                label: label.map(|label| {
-                    cx.tcx.region_maps.node_extent(label.loop_id)
-                })
-            },
-        hir::ExprMatch(ref discr, ref arms, _) =>
-            ExprKind::Match { discriminant: discr.to_ref(),
-                              arms: arms.iter().map(|a| convert_arm(cx, a)).collect() },
-        hir::ExprIf(ref cond, ref then, ref otherwise) =>
-            ExprKind::If { condition: cond.to_ref(),
-                           then: block::to_expr_ref(cx, then),
-                           otherwise: otherwise.to_ref() },
-        hir::ExprWhile(ref cond, ref body, _) =>
-            ExprKind::Loop { condition: Some(cond.to_ref()),
-                             body: block::to_expr_ref(cx, body) },
-        hir::ExprLoop(ref body, _, _) =>
-            ExprKind::Loop { condition: None,
-                             body: block::to_expr_ref(cx, body) },
+                label: label.map(|label| cx.tcx.region_maps.node_extent(label.loop_id)),
+            }
+        }
+        hir::ExprMatch(ref discr, ref arms, _) => {
+            ExprKind::Match {
+                discriminant: discr.to_ref(),
+                arms: arms.iter().map(|a| convert_arm(cx, a)).collect(),
+            }
+        }
+        hir::ExprIf(ref cond, ref then, ref otherwise) => {
+            ExprKind::If {
+                condition: cond.to_ref(),
+                then: block::to_expr_ref(cx, then),
+                otherwise: otherwise.to_ref(),
+            }
+        }
+        hir::ExprWhile(ref cond, ref body, _) => {
+            ExprKind::Loop {
+                condition: Some(cond.to_ref()),
+                body: block::to_expr_ref(cx, body),
+            }
+        }
+        hir::ExprLoop(ref body, _, _) => {
+            ExprKind::Loop {
+                condition: None,
+                body: block::to_expr_ref(cx, body),
+            }
+        }
         hir::ExprField(ref source, name) => {
             let index = match cx.tcx.tables().expr_ty_adjusted(source).sty {
-                ty::TyAdt(adt_def, _) =>
-                    adt_def.variants[0].index_of_field_named(name.node),
-                ref ty =>
-                    span_bug!(expr.span, "field of non-ADT: {:?}", ty),
+                ty::TyAdt(adt_def, _) => adt_def.variants[0].index_of_field_named(name.node),
+                ref ty => span_bug!(expr.span, "field of non-ADT: {:?}", ty),
             };
-            let index = index.unwrap_or_else(|| {
-                span_bug!(
-                    expr.span,
-                    "no index found for field `{}`",
-                    name.node)
-            });
-            ExprKind::Field { lhs: source.to_ref(), name: Field::new(index) }
+            let index =
+                index.unwrap_or_else(|| {
+                    span_bug!(expr.span, "no index found for field `{}`", name.node)
+                });
+            ExprKind::Field {
+                lhs: source.to_ref(),
+                name: Field::new(index),
+            }
+        }
+        hir::ExprTupField(ref source, index) => {
+            ExprKind::Field {
+                lhs: source.to_ref(),
+                name: Field::new(index.node as usize),
+            }
         }
-        hir::ExprTupField(ref source, index) =>
-            ExprKind::Field { lhs: source.to_ref(),
-                              name: Field::new(index.node as usize) },
         hir::ExprCast(ref source, _) => {
             // Check to see if this cast is a "coercion cast", where the cast is actually done
             // using a coercion (or is a no-op).
@@ -616,17 +655,15 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 ExprKind::Cast { source: source.to_ref() }
             }
         }
-        hir::ExprType(ref source, _) =>
-            return source.make_mirror(cx),
-        hir::ExprBox(ref value) =>
+        hir::ExprType(ref source, _) => return source.make_mirror(cx),
+        hir::ExprBox(ref value) => {
             ExprKind::Box {
                 value: value.to_ref(),
-                value_extents: cx.tcx.region_maps.node_extent(value.id)
-            },
-        hir::ExprArray(ref fields) =>
-            ExprKind::Vec { fields: fields.to_ref() },
-        hir::ExprTup(ref fields) =>
-            ExprKind::Tuple { fields: fields.to_ref() },
+                value_extents: cx.tcx.region_maps.node_extent(value.id),
+            }
+        }
+        hir::ExprArray(ref fields) => ExprKind::Vec { fields: fields.to_ref() },
+        hir::ExprTup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() },
     };
 
     Expr {
@@ -663,8 +700,7 @@ fn to_borrow_kind(m: hir::Mutability) -> BorrowKind {
     }
 }
 
-fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
-                               arm: &'tcx hir::Arm) -> Arm<'tcx> {
+fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
     Arm {
         patterns: arm.pats.iter().map(|p| Pattern::from_hir(cx.tcx, p)).collect(),
         guard: arm.guard.to_ref(),
@@ -676,41 +712,48 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                      expr: &'tcx hir::Expr,
                                      def: Def)
                                      -> ExprKind<'tcx> {
-    let substs = cx.tcx.tables().node_id_item_substs(expr.id)
+    let substs = cx.tcx
+        .tables()
+        .node_id_item_substs(expr.id)
         .unwrap_or_else(|| cx.tcx.intern_substs(&[]));
     let def_id = match def {
         // A regular function, constructor function or a constant.
-        Def::Fn(def_id) | Def::Method(def_id) |
+        Def::Fn(def_id) |
+        Def::Method(def_id) |
         Def::StructCtor(def_id, CtorKind::Fn) |
         Def::VariantCtor(def_id, CtorKind::Fn) |
-        Def::Const(def_id) | Def::AssociatedConst(def_id) => def_id,
+        Def::Const(def_id) |
+        Def::AssociatedConst(def_id) => def_id,
 
         Def::StructCtor(def_id, CtorKind::Const) |
         Def::VariantCtor(def_id, CtorKind::Const) => {
             match cx.tcx.tables().node_id_to_type(expr.id).sty {
                 // A unit struct/variant which is used as a value.
                 // We return a completely different ExprKind here to account for this special case.
-                ty::TyAdt(adt_def, substs) => return ExprKind::Adt {
-                    adt_def: adt_def,
-                    variant_index: adt_def.variant_index_with_id(def_id),
-                    substs: substs,
-                    fields: vec![],
-                    base: None,
-                },
-                ref sty => bug!("unexpected sty: {:?}", sty)
+                ty::TyAdt(adt_def, substs) => {
+                    return ExprKind::Adt {
+                        adt_def: adt_def,
+                        variant_index: adt_def.variant_index_with_id(def_id),
+                        substs: substs,
+                        fields: vec![],
+                        base: None,
+                    }
+                }
+                ref sty => bug!("unexpected sty: {:?}", sty),
             }
         }
 
-        Def::Static(node_id, _) => return ExprKind::StaticRef {
-            id: node_id,
-        },
+        Def::Static(node_id, _) => return ExprKind::StaticRef { id: node_id },
 
         Def::Local(..) | Def::Upvar(..) => return convert_var(cx, expr, def),
 
         _ => span_bug!(expr.span, "def `{:?}` not yet implemented", def),
     };
     ExprKind::Literal {
-        literal: Literal::Item { def_id: def_id, substs: substs }
+        literal: Literal::Item {
+            def_id: def_id,
+            substs: substs,
+        },
     }
 }
 
@@ -723,14 +766,15 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
     match def {
         Def::Local(def_id) => {
             let node_id = cx.tcx.map.as_local_node_id(def_id).unwrap();
-            ExprKind::VarRef {
-                id: node_id,
-            }
+            ExprKind::VarRef { id: node_id }
         }
 
         Def::Upvar(def_id, index, closure_expr_id) => {
             let id_var = cx.tcx.map.as_local_node_id(def_id).unwrap();
-            debug!("convert_var(upvar({:?}, {:?}, {:?}))", id_var, index, closure_expr_id);
+            debug!("convert_var(upvar({:?}, {:?}, {:?}))",
+                   id_var,
+                   index,
+                   closure_expr_id);
             let var_ty = cx.tcx.tables().node_id_to_type(id_var);
 
             let body_id = match cx.tcx.map.find(closure_expr_id) {
@@ -761,41 +805,45 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
             let self_expr = match cx.tcx.closure_kind(cx.tcx.map.local_def_id(closure_expr_id)) {
                 ty::ClosureKind::Fn => {
-                    let ref_closure_ty =
-                        cx.tcx.mk_ref(region,
-                                   ty::TypeAndMut { ty: closure_ty,
-                                                    mutbl: hir::MutImmutable });
+                    let ref_closure_ty = cx.tcx.mk_ref(region,
+                                                       ty::TypeAndMut {
+                                                           ty: closure_ty,
+                                                           mutbl: hir::MutImmutable,
+                                                       });
                     Expr {
                         ty: closure_ty,
                         temp_lifetime: temp_lifetime,
                         span: expr.span,
                         kind: ExprKind::Deref {
                             arg: Expr {
-                                ty: ref_closure_ty,
-                                temp_lifetime: temp_lifetime,
-                                span: expr.span,
-                                kind: ExprKind::SelfRef
-                            }.to_ref()
-                        }
+                                    ty: ref_closure_ty,
+                                    temp_lifetime: temp_lifetime,
+                                    span: expr.span,
+                                    kind: ExprKind::SelfRef,
+                                }
+                                .to_ref(),
+                        },
                     }
                 }
                 ty::ClosureKind::FnMut => {
-                    let ref_closure_ty =
-                        cx.tcx.mk_ref(region,
-                                   ty::TypeAndMut { ty: closure_ty,
-                                                    mutbl: hir::MutMutable });
+                    let ref_closure_ty = cx.tcx.mk_ref(region,
+                                                       ty::TypeAndMut {
+                                                           ty: closure_ty,
+                                                           mutbl: hir::MutMutable,
+                                                       });
                     Expr {
                         ty: closure_ty,
                         temp_lifetime: temp_lifetime,
                         span: expr.span,
                         kind: ExprKind::Deref {
                             arg: Expr {
-                                ty: ref_closure_ty,
-                                temp_lifetime: temp_lifetime,
-                                span: expr.span,
-                                kind: ExprKind::SelfRef
-                            }.to_ref()
-                        }
+                                    ty: ref_closure_ty,
+                                    temp_lifetime: temp_lifetime,
+                                    span: expr.span,
+                                    kind: ExprKind::SelfRef,
+                                }
+                                .to_ref(),
+                        },
                     }
                 }
                 ty::ClosureKind::FnOnce => {
@@ -823,10 +871,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             let upvar_capture = match cx.tcx.tables().upvar_capture(upvar_id) {
                 Some(c) => c,
                 None => {
-                    span_bug!(
-                        expr.span,
-                        "no upvar_capture for {:?}",
-                        upvar_id);
+                    span_bug!(expr.span, "no upvar_capture for {:?}", upvar_id);
                 }
             };
             match upvar_capture {
@@ -834,15 +879,16 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 ty::UpvarCapture::ByRef(borrow) => {
                     ExprKind::Deref {
                         arg: Expr {
-                            temp_lifetime: temp_lifetime,
-                            ty: cx.tcx.mk_ref(borrow.region,
-                                ty::TypeAndMut {
-                                    ty: var_ty,
-                                    mutbl: borrow.kind.to_mutbl_lossy()
-                                }),
-                            span: expr.span,
-                            kind: field_kind,
-                        }.to_ref()
+                                temp_lifetime: temp_lifetime,
+                                ty: cx.tcx.mk_ref(borrow.region,
+                                                  ty::TypeAndMut {
+                                                      ty: var_ty,
+                                                      mutbl: borrow.kind.to_mutbl_lossy(),
+                                                  }),
+                                span: expr.span,
+                                kind: field_kind,
+                            }
+                            .to_ref(),
                     }
                 }
             }
@@ -894,30 +940,31 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
     // the arguments, unfortunately, do not, so if this is a ByRef
     // operator, we have to gin up the autorefs (but by value is easy)
     match pass_args {
-        PassArgs::ByValue => {
-            argrefs.extend(args.iter().map(|arg| arg.to_ref()))
-        }
+        PassArgs::ByValue => argrefs.extend(args.iter().map(|arg| arg.to_ref())),
 
         PassArgs::ByRef => {
             let region = cx.tcx.node_scope_region(expr.id);
             let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
-            argrefs.extend(
-                args.iter()
-                    .map(|arg| {
-                        let arg_ty = cx.tcx.tables().expr_ty_adjusted(arg);
-                        let adjusted_ty =
-                            cx.tcx.mk_ref(region,
-                                       ty::TypeAndMut { ty: arg_ty,
-                                                        mutbl: hir::MutImmutable });
-                        Expr {
+            argrefs.extend(args.iter()
+                .map(|arg| {
+                    let arg_ty = cx.tcx.tables().expr_ty_adjusted(arg);
+                    let adjusted_ty = cx.tcx.mk_ref(region,
+                                                    ty::TypeAndMut {
+                                                        ty: arg_ty,
+                                                        mutbl: hir::MutImmutable,
+                                                    });
+                    Expr {
                             temp_lifetime: temp_lifetime,
                             ty: adjusted_ty,
                             span: expr.span,
-                            kind: ExprKind::Borrow { region: region,
-                                                     borrow_kind: BorrowKind::Shared,
-                                                     arg: arg.to_ref() }
-                        }.to_ref()
-                    }))
+                            kind: ExprKind::Borrow {
+                                region: region,
+                                borrow_kind: BorrowKind::Shared,
+                                arg: arg.to_ref(),
+                            },
+                        }
+                        .to_ref()
+                }))
         }
     }
 
@@ -981,9 +1028,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         kind: convert_var(cx, closure_expr, freevar.def),
     };
     match upvar_capture {
-        ty::UpvarCapture::ByValue => {
-            captured_var.to_ref()
-        }
+        ty::UpvarCapture::ByValue => captured_var.to_ref(),
         ty::UpvarCapture::ByRef(upvar_borrow) => {
             let borrow_kind = match upvar_borrow.kind {
                 ty::BorrowKind::ImmBorrow => BorrowKind::Shared,
@@ -991,13 +1036,16 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 ty::BorrowKind::MutBorrow => BorrowKind::Mut,
             };
             Expr {
-                temp_lifetime: temp_lifetime,
-                ty: freevar_ty,
-                span: closure_expr.span,
-                kind: ExprKind::Borrow { region: upvar_borrow.region,
-                                         borrow_kind: borrow_kind,
-                                         arg: captured_var.to_ref() }
-            }.to_ref()
+                    temp_lifetime: temp_lifetime,
+                    ty: freevar_ty,
+                    span: closure_expr.span,
+                    kind: ExprKind::Borrow {
+                        region: upvar_borrow.region,
+                        borrow_kind: borrow_kind,
+                        arg: captured_var.to_ref(),
+                    },
+                }
+                .to_ref()
         }
     }
 }
@@ -1005,12 +1053,13 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 /// Converts a list of named fields (i.e. for struct-like struct/enum ADTs) into FieldExprRef.
 fn field_refs<'tcx>(variant: &'tcx VariantDef,
                     fields: &'tcx [hir::Field])
-                    -> Vec<FieldExprRef<'tcx>>
-{
+                    -> Vec<FieldExprRef<'tcx>> {
     fields.iter()
-          .map(|field| FieldExprRef {
-              name: Field::new(variant.index_of_field_named(field.name.node).unwrap()),
-              expr: field.expr.to_ref(),
-          })
-          .collect()
+        .map(|field| {
+            FieldExprRef {
+                name: Field::new(variant.index_of_field_named(field.name.node).unwrap()),
+                expr: field.expr.to_ref(),
+            }
+        })
+        .collect()
 }
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index e7a6b40c830..7d111fccd00 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -8,12 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-/*!
- * This module contains the code to convert from the wacky tcx data
- * structures into the hair. The `builder` is generally ignorant of
- * the tcx etc, and instead goes through the `Cx` for most of its
- * work.
- */
+//! This module contains the code to convert from the wacky tcx data
+//! structures into the hair. The `builder` is generally ignorant of
+//! the tcx etc, and instead goes through the `Cx` for most of its
+//! work.
+//!
 
 use hair::*;
 use rustc::mir::transform::MirSource;
@@ -32,19 +31,17 @@ use rustc::hir;
 use rustc_const_math::{ConstInt, ConstUsize};
 
 #[derive(Copy, Clone)]
-pub struct Cx<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
     constness: hir::Constness,
 
     /// True if this constant/function needs overflow checks.
-    check_overflow: bool
+    check_overflow: bool,
 }
 
 impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
-    pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-               src: MirSource)
-               -> Cx<'a, 'gcx, 'tcx> {
+    pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, src: MirSource) -> Cx<'a, 'gcx, 'tcx> {
         let constness = match src {
             MirSource::Const(_) |
             MirSource::Static(..) => hir::Constness::Const,
@@ -52,7 +49,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
                 let fn_like = FnLikeNode::from_node(infcx.tcx.map.get(id));
                 fn_like.map_or(hir::Constness::NotConst, |f| f.constness())
             }
-            MirSource::Promoted(..) => bug!()
+            MirSource::Promoted(..) => bug!(),
         };
 
         let src_node_id = src.item_id();
@@ -70,13 +67,16 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         // Some functions always have overflow checks enabled,
         // however, they may not get codegen'd, depending on
         // the settings for the crate they are translated in.
-        let mut check_overflow = attrs.iter().any(|item| {
-            item.check_name("rustc_inherit_overflow_checks")
-        });
+        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);
+        check_overflow |= infcx.tcx
+            .sess
+            .opts
+            .debugging_opts
+            .force_overflow_checks
+            .unwrap_or(infcx.tcx.sess.opts.debug_assertions);
 
         // Constants and const fn's always need overflow checks.
         check_overflow |= constness == hir::Constness::Const;
@@ -85,7 +85,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
             tcx: infcx.tcx,
             infcx: infcx,
             constness: constness,
-            check_overflow: check_overflow
+            check_overflow: check_overflow,
         }
     }
 }
@@ -102,7 +102,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
 
     pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
         match ConstUsize::new(value, self.tcx.sess.target.uint_type) {
-            Ok(val) => Literal::Value { value: ConstVal::Integral(ConstInt::Usize(val))},
+            Ok(val) => Literal::Value { value: ConstVal::Integral(ConstInt::Usize(val)) },
             Err(_) => bug!("usize literal out of range for target"),
         }
     }
@@ -128,9 +128,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
     }
 
     pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> {
-        Literal::Value {
-            value: const_eval::eval_const_expr(self.tcx.global_tcx(), e)
-        }
+        Literal::Value { value: const_eval::eval_const_expr(self.tcx.global_tcx(), e) }
     }
 
     pub fn trait_method(&mut self,
@@ -145,10 +143,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
             if item.kind == ty::AssociatedKind::Method && item.name == method_name {
                 let method_ty = self.tcx.item_type(item.def_id);
                 let method_ty = method_ty.subst(self.tcx, substs);
-                return (method_ty, Literal::Item {
-                    def_id: item.def_id,
-                    substs: substs,
-                });
+                return (method_ty,
+                        Literal::Item {
+                            def_id: item.def_id,
+                            substs: substs,
+                        });
             }
         }
 
@@ -168,7 +167,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
     pub fn needs_drop(&mut self, ty: Ty<'tcx>) -> bool {
         let ty = self.tcx.lift_to_global(&ty).unwrap_or_else(|| {
             bug!("MIR: Cx::needs_drop({}) got \
-                  type with inference types/regions", ty);
+                  type with inference types/regions",
+                 ty);
         });
         self.tcx.type_needs_drop_given_env(ty, &self.infcx.parameter_environment)
     }
diff --git a/src/librustc_mir/hair/cx/to_ref.rs b/src/librustc_mir/hair/cx/to_ref.rs
index 63dbde47438..6930a959d65 100644
--- a/src/librustc_mir/hair/cx/to_ref.rs
+++ b/src/librustc_mir/hair/cx/to_ref.rs
@@ -18,7 +18,7 @@ pub trait ToRef {
     fn to_ref(self) -> Self::Output;
 }
 
-impl<'a,'tcx:'a> ToRef for &'tcx hir::Expr {
+impl<'a, 'tcx: 'a> ToRef for &'tcx hir::Expr {
     type Output = ExprRef<'tcx>;
 
     fn to_ref(self) -> ExprRef<'tcx> {
@@ -26,7 +26,7 @@ impl<'a,'tcx:'a> ToRef for &'tcx hir::Expr {
     }
 }
 
-impl<'a,'tcx:'a> ToRef for &'tcx P<hir::Expr> {
+impl<'a, 'tcx: 'a> ToRef for &'tcx P<hir::Expr> {
     type Output = ExprRef<'tcx>;
 
     fn to_ref(self) -> ExprRef<'tcx> {
@@ -34,7 +34,7 @@ impl<'a,'tcx:'a> ToRef for &'tcx P<hir::Expr> {
     }
 }
 
-impl<'a,'tcx:'a> ToRef for Expr<'tcx> {
+impl<'a, 'tcx: 'a> ToRef for Expr<'tcx> {
     type Output = ExprRef<'tcx>;
 
     fn to_ref(self) -> ExprRef<'tcx> {
@@ -42,8 +42,8 @@ impl<'a,'tcx:'a> ToRef for Expr<'tcx> {
     }
 }
 
-impl<'a,'tcx:'a,T,U> ToRef for &'tcx Option<T>
-    where &'tcx T: ToRef<Output=U>
+impl<'a, 'tcx: 'a, T, U> ToRef for &'tcx Option<T>
+    where &'tcx T: ToRef<Output = U>
 {
     type Output = Option<U>;
 
@@ -52,8 +52,8 @@ impl<'a,'tcx:'a,T,U> ToRef for &'tcx Option<T>
     }
 }
 
-impl<'a,'tcx:'a,T,U> ToRef for &'tcx Vec<T>
-    where &'tcx T: ToRef<Output=U>
+impl<'a, 'tcx: 'a, T, U> ToRef for &'tcx Vec<T>
+    where &'tcx T: ToRef<Output = U>
 {
     type Output = Vec<U>;
 
@@ -62,8 +62,8 @@ impl<'a,'tcx:'a,T,U> ToRef for &'tcx Vec<T>
     }
 }
 
-impl<'a,'tcx:'a,T,U> ToRef for &'tcx P<[T]>
-    where &'tcx T: ToRef<Output=U>
+impl<'a, 'tcx: 'a, T, U> ToRef for &'tcx P<[T]>
+    where &'tcx T: ToRef<Output = U>
 {
     type Output = Vec<U>;
 
diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs
index d16b51adbaf..3cbf8573ba9 100644
--- a/src/librustc_mir/transform/copy_prop.rs
+++ b/src/librustc_mir/transform/copy_prop.rs
@@ -30,7 +30,7 @@
 //! future.
 
 use def_use::DefUseAnalysis;
-use rustc::mir::{Constant, Local, Location, Lvalue, Mir, Operand, Rvalue, StatementKind};
+use rustc::mir::{Constant, Local, LocalKind, Location, Lvalue, Mir, Operand, Rvalue, StatementKind};
 use rustc::mir::transform::{MirPass, MirSource, Pass};
 use rustc::mir::visit::MutVisitor;
 use rustc::ty::TyCtxt;
@@ -122,7 +122,7 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
                                 local == dest_local => {
                             let maybe_action = match *operand {
                                 Operand::Consume(ref src_lvalue) => {
-                                    Action::local_copy(&def_use_analysis, src_lvalue)
+                                    Action::local_copy(&mir, &def_use_analysis, src_lvalue)
                                 }
                                 Operand::Constant(ref src_constant) => {
                                     Action::constant(src_constant)
@@ -159,7 +159,7 @@ enum Action<'tcx> {
 }
 
 impl<'tcx> Action<'tcx> {
-    fn local_copy(def_use_analysis: &DefUseAnalysis, src_lvalue: &Lvalue<'tcx>)
+    fn local_copy(mir: &Mir<'tcx>, def_use_analysis: &DefUseAnalysis, src_lvalue: &Lvalue<'tcx>)
                   -> Option<Action<'tcx>> {
         // The source must be a local.
         let src_local = if let Lvalue::Local(local) = *src_lvalue {
@@ -195,7 +195,9 @@ impl<'tcx> Action<'tcx> {
         //     SRC = X;
         //     USE(SRC);
         let src_def_count = src_use_info.def_count_not_including_drop();
-        if src_def_count != 1 {
+        // allow function arguments to be propagated
+        if src_def_count > 1 ||
+            (src_def_count == 0 && mir.local_kind(src_local) != LocalKind::Arg) {
             debug!("  Can't copy-propagate local: {} defs of src",
                    src_use_info.def_count_not_including_drop());
             return None
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 2d0f0864752..52bdd014933 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -154,8 +154,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
     }
 
     fn visit_path(&mut self, path: &'a Path, id: NodeId) {
-        if path.global && path.segments.len() > 0 {
-            let ident = path.segments[0].identifier;
+        if path.segments.len() >= 2 && path.is_global() {
+            let ident = path.segments[1].identifier;
             if token::Ident(ident).is_path_segment_keyword() {
                 self.session.add_lint(lint::builtin::SUPER_OR_SELF_IN_GLOBAL_PATH,
                                       id,
@@ -171,7 +171,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         match item.node {
             ItemKind::Use(ref view_path) => {
                 let path = view_path.node.path();
-                if !path.segments.iter().all(|segment| segment.parameters.is_empty()) {
+                if path.segments.iter().any(|segment| segment.parameters.is_some()) {
                     self.err_handler()
                         .span_err(path.span, "type or lifetime parameters in import path");
                 }
@@ -275,7 +275,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
     fn visit_vis(&mut self, vis: &'a Visibility) {
         match *vis {
             Visibility::Restricted { ref path, .. } => {
-                if !path.segments.iter().all(|segment| segment.parameters.is_empty()) {
+                if !path.segments.iter().all(|segment| segment.parameters.is_none()) {
                     self.err_handler()
                         .span_err(path.span, "type or lifetime parameters in visibility path");
                 }
diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs
index fe2f9713d1b..3700d0295e9 100644
--- a/src/librustc_plugin/registry.rs
+++ b/src/librustc_plugin/registry.rs
@@ -64,6 +64,8 @@ pub struct Registry<'a> {
 
     #[doc(hidden)]
     pub attributes: Vec<(String, AttributeType)>,
+
+    whitelisted_custom_derives: Vec<ast::Name>,
 }
 
 impl<'a> Registry<'a> {
@@ -80,6 +82,7 @@ impl<'a> Registry<'a> {
             llvm_passes: vec![],
             attributes: vec![],
             mir_passes: Vec::new(),
+            whitelisted_custom_derives: Vec::new(),
         }
     }
 
@@ -115,6 +118,21 @@ impl<'a> Registry<'a> {
         }));
     }
 
+    /// This can be used in place of `register_syntax_extension` to register legacy custom derives
+    /// (i.e. attribute syntax extensions whose name begins with `derive_`). Legacy custom
+    /// derives defined by this function do not trigger deprecation warnings when used.
+    #[unstable(feature = "rustc_private", issue = "27812")]
+    #[rustc_deprecated(since = "1.15.0", reason = "replaced by macros 1.1 (RFC 1861)")]
+    pub fn register_custom_derive(&mut self, name: ast::Name, extension: SyntaxExtension) {
+        assert!(name.as_str().starts_with("derive_"));
+        self.whitelisted_custom_derives.push(name);
+        self.register_syntax_extension(name, extension);
+    }
+
+    pub fn take_whitelisted_custom_derives(&mut self) -> Vec<ast::Name> {
+        ::std::mem::replace(&mut self.whitelisted_custom_derives, Vec::new())
+    }
+
     /// Register a macro of the usual kind.
     ///
     /// This is a convenience wrapper for `register_syntax_extension`.
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 145b9176f6b..ca3e4e1c762 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -28,7 +28,7 @@ extern crate syntax_pos;
 use rustc::dep_graph::DepNode;
 use rustc::hir::{self, PatKind};
 use rustc::hir::def::{self, Def, CtorKind};
-use rustc::hir::def_id::DefId;
+use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::itemlikevisit::DeepVisitor;
 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
@@ -391,7 +391,7 @@ impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b
 
 struct PrivacyVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    curitem: ast::NodeId,
+    curitem: DefId,
     in_foreign: bool,
 }
 
@@ -401,12 +401,12 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
             Some(node_id) =>
                 ty::Visibility::from_hir(&self.tcx.map.expect_item(node_id).vis, node_id, self.tcx),
             None => self.tcx.sess.cstore.visibility(did),
-        }.is_accessible_from(self.curitem, &self.tcx.map)
+        }.is_accessible_from(self.curitem, self.tcx)
     }
 
     // Checks that a field is in scope.
     fn check_field(&mut self, span: Span, def: &'tcx ty::AdtDef, field: &'tcx ty::FieldDef) {
-        if !def.is_enum() && !field.vis.is_accessible_from(self.curitem, &self.tcx.map) {
+        if !def.is_enum() && !field.vis.is_accessible_from(self.curitem, self.tcx) {
             struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private",
                       field.name, def.variant_descr(), self.tcx.item_path_str(def.did))
                 .span_label(span, &format!("field `{}` is private", field.name))
@@ -437,7 +437,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> {
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item) {
-        let orig_curitem = replace(&mut self.curitem, item.id);
+        let orig_curitem = replace(&mut self.curitem, self.tcx.map.local_def_id(item.id));
         intravisit::walk_item(self, item);
         self.curitem = orig_curitem;
     }
@@ -474,7 +474,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> {
                 if let Def::StructCtor(_, CtorKind::Fn) = path.def {
                     let adt_def = self.tcx.expect_variant_def(path.def);
                     let private_indexes = adt_def.fields.iter().enumerate().filter(|&(_, field)| {
-                        !field.vis.is_accessible_from(self.curitem, &self.tcx.map)
+                        !field.vis.is_accessible_from(self.curitem, self.tcx)
                     }).map(|(i, _)| i).collect::<Vec<_>>();
 
                     if !private_indexes.is_empty() {
@@ -940,7 +940,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
             ty::TyAdt(adt, _) => Some(adt.did),
             ty::TyDynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()),
             ty::TyProjection(ref proj) => {
-                if self.required_visibility == ty::Visibility::PrivateExternal {
+                if self.required_visibility == ty::Visibility::Invisible {
                     // Conservatively approximate the whole type alias as public without
                     // recursing into its components when determining impl publicity.
                     // For example, `impl <Type as Trait>::Alias {...}` may be a public impl
@@ -961,10 +961,10 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
                 let item = self.tcx.map.expect_item(node_id);
                 let vis = ty::Visibility::from_hir(&item.vis, node_id, self.tcx);
 
-                if !vis.is_at_least(self.min_visibility, &self.tcx.map) {
+                if !vis.is_at_least(self.min_visibility, self.tcx) {
                     self.min_visibility = vis;
                 }
-                if !vis.is_at_least(self.required_visibility, &self.tcx.map) {
+                if !vis.is_at_least(self.required_visibility, self.tcx) {
                     if self.tcx.sess.features.borrow().pub_restricted || self.has_old_errors {
                         let mut err = struct_span_err!(self.tcx.sess, self.span, E0446,
                             "private type `{}` in public interface", ty);
@@ -996,10 +996,10 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
             let item = self.tcx.map.expect_item(node_id);
             let vis = ty::Visibility::from_hir(&item.vis, node_id, self.tcx);
 
-            if !vis.is_at_least(self.min_visibility, &self.tcx.map) {
+            if !vis.is_at_least(self.min_visibility, self.tcx) {
                 self.min_visibility = vis;
             }
-            if !vis.is_at_least(self.required_visibility, &self.tcx.map) {
+            if !vis.is_at_least(self.required_visibility, self.tcx) {
                 if self.tcx.sess.features.borrow().pub_restricted || self.has_old_errors {
                     struct_span_err!(self.tcx.sess, self.span, E0445,
                                      "private trait `{}` in public interface", trait_ref)
@@ -1071,7 +1071,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         let tcx = self.tcx;
         let min = |vis1: ty::Visibility, vis2| {
-            if vis1.is_at_least(vis2, &tcx.map) { vis2 } else { vis1 }
+            if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 }
         };
 
         let item_visibility = ty::Visibility::from_hir(&item.vis, item.id, tcx);
@@ -1137,8 +1137,8 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
             // An inherent impl is public when its type is public
             // Subitems of inherent impls have their own publicity
             hir::ItemImpl(.., None, _, ref impl_item_refs) => {
-                let ty_vis = self.check(item.id, ty::Visibility::PrivateExternal)
-                                 .item_type().min_visibility;
+                let ty_vis =
+                    self.check(item.id, ty::Visibility::Invisible).item_type().min_visibility;
                 self.check(item.id, ty_vis).generics().predicates();
 
                 for impl_item_ref in impl_item_refs {
@@ -1156,7 +1156,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
             // A trait impl is public when both its type and its trait are public
             // Subitems of trait impls have inherited publicity
             hir::ItemImpl(.., Some(_), _, ref impl_item_refs) => {
-                let vis = self.check(item.id, ty::Visibility::PrivateExternal)
+                let vis = self.check(item.id, ty::Visibility::Invisible)
                               .item_type().impl_trait_ref().min_visibility;
                 self.check(item.id, vis).generics().predicates();
                 for impl_item_ref in impl_item_refs {
@@ -1203,7 +1203,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     // Use the parent map to check the privacy of everything
     let mut visitor = PrivacyVisitor {
-        curitem: ast::DUMMY_NODE_ID,
+        curitem: DefId::local(CRATE_DEF_INDEX),
         in_foreign: false,
         tcx: tcx,
     };
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 25a37931ba3..1b3791355d2 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -16,7 +16,8 @@
 use macros::{InvocationData, LegacyScope};
 use resolve_imports::ImportDirective;
 use resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport};
-use {Resolver, Module, ModuleS, ModuleKind, NameBinding, NameBindingKind, ToNameBinding};
+use {Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, ToNameBinding};
+use {Resolver, ResolverArenas};
 use Namespace::{self, TypeNS, ValueNS, MacroNS};
 use {resolve_error, resolve_struct_error, ResolutionError};
 
@@ -28,7 +29,7 @@ use rustc::ty;
 use std::cell::Cell;
 use std::rc::Rc;
 
-use syntax::ast::Name;
+use syntax::ast::{Name, Ident};
 use syntax::attr;
 
 use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind};
@@ -39,30 +40,31 @@ use syntax::ext::base::Determinacy::Undetermined;
 use syntax::ext::expand::mark_tts;
 use syntax::ext::hygiene::Mark;
 use syntax::ext::tt::macro_rules;
+use syntax::parse::token;
 use syntax::symbol::keywords;
 use syntax::visit::{self, Visitor};
 
 use syntax_pos::{Span, DUMMY_SP};
 
 impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, Mark) {
-    fn to_name_binding(self) -> NameBinding<'a> {
-        NameBinding {
+    fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
+        arenas.alloc_name_binding(NameBinding {
             kind: NameBindingKind::Module(self.0),
             vis: self.1,
             span: self.2,
             expansion: self.3,
-        }
+        })
     }
 }
 
 impl<'a> ToNameBinding<'a> for (Def, ty::Visibility, Span, Mark) {
-    fn to_name_binding(self) -> NameBinding<'a> {
-        NameBinding {
+    fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
+        arenas.alloc_name_binding(NameBinding {
             kind: NameBindingKind::Def(self.0),
             vis: self.1,
             span: self.2,
             expansion: self.3,
-        }
+        })
     }
 }
 
@@ -73,15 +75,15 @@ struct LegacyMacroImports {
     reexports: Vec<(Name, Span)>,
 }
 
-impl<'b> Resolver<'b> {
+impl<'a> Resolver<'a> {
     /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
     /// otherwise, reports an error.
-    fn define<T>(&mut self, parent: Module<'b>, name: Name, ns: Namespace, def: T)
-        where T: ToNameBinding<'b>,
+    fn define<T>(&mut self, parent: Module<'a>, ident: Ident, ns: Namespace, def: T)
+        where T: ToNameBinding<'a>,
     {
-        let binding = def.to_name_binding();
-        if let Err(old_binding) = self.try_define(parent, name, ns, binding.clone()) {
-            self.report_conflict(parent, name, ns, old_binding, &binding);
+        let binding = def.to_name_binding(self.arenas);
+        if let Err(old_binding) = self.try_define(parent, ident, ns, binding) {
+            self.report_conflict(parent, ident, ns, old_binding, &binding);
         }
     }
 
@@ -102,7 +104,7 @@ impl<'b> Resolver<'b> {
     /// Constructs the reduced graph for one item.
     fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
         let parent = self.current_module;
-        let name = item.ident.name;
+        let ident = item.ident;
         let sp = item.span;
         let vis = self.resolve_visibility(&item.vis);
 
@@ -111,7 +113,7 @@ impl<'b> Resolver<'b> {
                 // Extract and intern the module part of the path. For
                 // globs and lists, the path is found directly in the AST;
                 // for simple paths we have to munge the path a little.
-                let module_path: Vec<_> = match view_path.node {
+                let mut module_path: Vec<_> = match view_path.node {
                     ViewPathSimple(_, ref full_path) => {
                         full_path.segments
                                  .split_last()
@@ -131,6 +133,12 @@ impl<'b> Resolver<'b> {
                     }
                 };
 
+                // This can be removed once warning cycle #36888 is complete.
+                if module_path.len() >= 2 && module_path[0].name == keywords::CrateRoot.name() &&
+                   token::Ident(module_path[1]).is_path_segment_keyword() {
+                    module_path.remove(0);
+                }
+
                 // Build up the import directives.
                 let is_prelude = attr::contains_name(&item.attrs, "prelude_import");
 
@@ -157,8 +165,8 @@ impl<'b> Resolver<'b> {
                         }
 
                         let subclass = SingleImport {
-                            target: binding.name,
-                            source: source.name,
+                            target: binding,
+                            source: source,
                             result: self.per_ns(|_, _| Cell::new(Err(Undetermined))),
                         };
                         self.add_import_directive(
@@ -187,31 +195,29 @@ impl<'b> Resolver<'b> {
 
                         for source_item in source_items {
                             let node = source_item.node;
-                            let (module_path, name, rename) = {
+                            let (module_path, ident, rename) = {
                                 if node.name.name != keywords::SelfValue.name() {
-                                    let rename = node.rename.unwrap_or(node.name).name;
-                                    (module_path.clone(), node.name.name, rename)
+                                    let rename = node.rename.unwrap_or(node.name);
+                                    (module_path.clone(), node.name, rename)
                                 } else {
-                                    let name = match module_path.last() {
-                                        Some(ident) => ident.name,
-                                        None => {
-                                            resolve_error(
-                                                self,
-                                                source_item.span,
-                                                ResolutionError::
-                                                SelfImportOnlyInImportListWithNonEmptyPrefix
-                                            );
-                                            continue;
-                                        }
-                                    };
+                                    let ident = *module_path.last().unwrap();
+                                    if ident.name == keywords::CrateRoot.name() {
+                                        resolve_error(
+                                            self,
+                                            source_item.span,
+                                            ResolutionError::
+                                            SelfImportOnlyInImportListWithNonEmptyPrefix
+                                        );
+                                        continue;
+                                    }
                                     let module_path = module_path.split_last().unwrap().1;
-                                    let rename = node.rename.map(|i| i.name).unwrap_or(name);
-                                    (module_path.to_vec(), name, rename)
+                                    let rename = node.rename.unwrap_or(ident);
+                                    (module_path.to_vec(), ident, rename)
                                 }
                             };
                             let subclass = SingleImport {
                                 target: rename,
-                                source: name,
+                                source: ident,
                                 result: self.per_ns(|_, _| Cell::new(Err(Undetermined))),
                             };
                             let id = source_item.node.id;
@@ -223,7 +229,7 @@ impl<'b> Resolver<'b> {
                     ViewPathGlob(_) => {
                         let subclass = GlobImport {
                             is_prelude: is_prelude,
-                            max_vis: Cell::new(ty::Visibility::PrivateExternal),
+                            max_vis: Cell::new(ty::Visibility::Invisible),
                         };
                         self.add_import_directive(
                             module_path, subclass, view_path.span, item.id, vis, expansion,
@@ -238,8 +244,8 @@ impl<'b> Resolver<'b> {
                 // n.b. we don't need to look at the path option here, because cstore already did
                 let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id).unwrap();
                 let module = self.get_extern_crate_root(crate_id);
-                let binding = (module, ty::Visibility::Public, sp, expansion).to_name_binding();
-                let binding = self.arenas.alloc_name_binding(binding);
+                let binding =
+                    (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.arenas);
                 let directive = self.arenas.alloc_import_directive(ImportDirective {
                     id: item.id,
                     parent: parent,
@@ -251,7 +257,7 @@ impl<'b> Resolver<'b> {
                     expansion: expansion,
                 });
                 let imported_binding = self.import(binding, directive);
-                self.define(parent, name, TypeNS, imported_binding);
+                self.define(parent, ident, TypeNS, imported_binding);
                 self.populate_module_if_necessary(module);
                 self.process_legacy_macro_imports(item, module, expansion);
             }
@@ -259,16 +265,16 @@ impl<'b> Resolver<'b> {
             ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root
 
             ItemKind::Mod(..) => {
-                let def = Def::Mod(self.definitions.local_def_id(item.id));
-                let module = self.arenas.alloc_module(ModuleS {
+                let def_id = self.definitions.local_def_id(item.id);
+                let module_kind = ModuleKind::Def(Def::Mod(def_id), ident.name);
+                let module = self.arenas.alloc_module(ModuleData {
                     no_implicit_prelude: parent.no_implicit_prelude || {
                         attr::contains_name(&item.attrs, "no_implicit_prelude")
                     },
-                    normal_ancestor_id: Some(item.id),
-                    ..ModuleS::new(Some(parent), ModuleKind::Def(def, name))
+                    ..ModuleData::new(Some(parent), module_kind, def_id)
                 });
-                self.define(parent, name, TypeNS, (module, vis, sp, expansion));
-                self.module_map.insert(item.id, module);
+                self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
+                self.module_map.insert(def_id, module);
 
                 // Descend into the module.
                 self.current_module = module;
@@ -280,27 +286,28 @@ impl<'b> Resolver<'b> {
             ItemKind::Static(_, m, _) => {
                 let mutbl = m == Mutability::Mutable;
                 let def = Def::Static(self.definitions.local_def_id(item.id), mutbl);
-                self.define(parent, name, ValueNS, (def, vis, sp, expansion));
+                self.define(parent, ident, ValueNS, (def, vis, sp, expansion));
             }
             ItemKind::Const(..) => {
                 let def = Def::Const(self.definitions.local_def_id(item.id));
-                self.define(parent, name, ValueNS, (def, vis, sp, expansion));
+                self.define(parent, ident, ValueNS, (def, vis, sp, expansion));
             }
             ItemKind::Fn(..) => {
                 let def = Def::Fn(self.definitions.local_def_id(item.id));
-                self.define(parent, name, ValueNS, (def, vis, sp, expansion));
+                self.define(parent, ident, ValueNS, (def, vis, sp, expansion));
             }
 
             // These items live in the type namespace.
             ItemKind::Ty(..) => {
                 let def = Def::TyAlias(self.definitions.local_def_id(item.id));
-                self.define(parent, name, TypeNS, (def, vis, sp, expansion));
+                self.define(parent, ident, TypeNS, (def, vis, sp, expansion));
             }
 
             ItemKind::Enum(ref enum_definition, _) => {
                 let def = Def::Enum(self.definitions.local_def_id(item.id));
-                let module = self.new_module(parent, ModuleKind::Def(def, name), true);
-                self.define(parent, name, TypeNS, (module, vis, sp, expansion));
+                let module_kind = ModuleKind::Def(def, ident.name);
+                let module = self.new_module(parent, module_kind, parent.normal_ancestor_id);
+                self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
 
                 for variant in &(*enum_definition).variants {
                     self.build_reduced_graph_for_variant(variant, module, vis, expansion);
@@ -311,14 +318,14 @@ impl<'b> Resolver<'b> {
             ItemKind::Struct(ref struct_def, _) => {
                 // Define a name in the type namespace.
                 let def = Def::Struct(self.definitions.local_def_id(item.id));
-                self.define(parent, name, TypeNS, (def, vis, sp, expansion));
+                self.define(parent, ident, TypeNS, (def, vis, sp, expansion));
 
                 // If this is a tuple or unit struct, define a name
                 // in the value namespace as well.
                 if !struct_def.is_struct() {
                     let ctor_def = Def::StructCtor(self.definitions.local_def_id(struct_def.id()),
                                                    CtorKind::from_ast(struct_def));
-                    self.define(parent, name, ValueNS, (ctor_def, vis, sp, expansion));
+                    self.define(parent, ident, ValueNS, (ctor_def, vis, sp, expansion));
                 }
 
                 // Record field names for error reporting.
@@ -332,7 +339,7 @@ impl<'b> Resolver<'b> {
 
             ItemKind::Union(ref vdata, _) => {
                 let def = Def::Union(self.definitions.local_def_id(item.id));
-                self.define(parent, name, TypeNS, (def, vis, sp, expansion));
+                self.define(parent, ident, TypeNS, (def, vis, sp, expansion));
 
                 // Record field names for error reporting.
                 let field_names = vdata.fields().iter().filter_map(|field| {
@@ -349,9 +356,9 @@ impl<'b> Resolver<'b> {
                 let def_id = self.definitions.local_def_id(item.id);
 
                 // Add all the items within to a new module.
-                let module =
-                    self.new_module(parent, ModuleKind::Def(Def::Trait(def_id), name), true);
-                self.define(parent, name, TypeNS, (module, vis, sp, expansion));
+                let module_kind = ModuleKind::Def(Def::Trait(def_id), ident.name);
+                let module = self.new_module(parent, module_kind, parent.normal_ancestor_id);
+                self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
                 self.current_module = module;
             }
             ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"),
@@ -362,29 +369,26 @@ impl<'b> Resolver<'b> {
     // type and value namespaces.
     fn build_reduced_graph_for_variant(&mut self,
                                        variant: &Variant,
-                                       parent: Module<'b>,
+                                       parent: Module<'a>,
                                        vis: ty::Visibility,
                                        expansion: Mark) {
-        let name = variant.node.name.name;
+        let ident = variant.node.name;
         let def_id = self.definitions.local_def_id(variant.node.data.id());
 
         // Define a name in the type namespace.
         let def = Def::Variant(def_id);
-        self.define(parent, name, TypeNS, (def, vis, variant.span, expansion));
+        self.define(parent, ident, TypeNS, (def, vis, variant.span, expansion));
 
         // Define a constructor name in the value namespace.
         // Braced variants, unlike structs, generate unusable names in
         // value namespace, they are reserved for possible future use.
         let ctor_kind = CtorKind::from_ast(&variant.node.data);
         let ctor_def = Def::VariantCtor(def_id, ctor_kind);
-        self.define(parent, name, ValueNS, (ctor_def, vis, variant.span, expansion));
+        self.define(parent, ident, ValueNS, (ctor_def, vis, variant.span, expansion));
     }
 
     /// Constructs the reduced graph for one foreign item.
     fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem, expansion: Mark) {
-        let parent = self.current_module;
-        let name = item.ident.name;
-
         let def = match item.node {
             ForeignItemKind::Fn(..) => {
                 Def::Fn(self.definitions.local_def_id(item.id))
@@ -393,111 +397,79 @@ impl<'b> Resolver<'b> {
                 Def::Static(self.definitions.local_def_id(item.id), m)
             }
         };
+        let parent = self.current_module;
         let vis = self.resolve_visibility(&item.vis);
-        self.define(parent, name, ValueNS, (def, vis, item.span, expansion));
+        self.define(parent, item.ident, ValueNS, (def, vis, item.span, expansion));
     }
 
     fn build_reduced_graph_for_block(&mut self, block: &Block) {
         let parent = self.current_module;
         if self.block_needs_anonymous_module(block) {
-            let block_id = block.id;
-
-            debug!("(building reduced graph for block) creating a new anonymous module for block \
-                    {}",
-                   block_id);
-
-            let new_module = self.new_module(parent, ModuleKind::Block(block_id), true);
-            self.module_map.insert(block_id, new_module);
-            self.current_module = new_module; // Descend into the block.
+            let module =
+                self.new_module(parent, ModuleKind::Block(block.id), parent.normal_ancestor_id);
+            self.block_map.insert(block.id, module);
+            self.current_module = module; // Descend into the block.
         }
     }
 
     /// Builds the reduced graph for a single item in an external crate.
-    fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, child: Export) {
-        let name = child.name;
+    fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'a>, child: Export) {
+        let ident = Ident::with_empty_ctxt(child.name);
         let def = child.def;
         let def_id = def.def_id();
-        let vis = match def {
-            Def::Macro(..) => ty::Visibility::Public,
-            _ if parent.is_trait() => ty::Visibility::Public,
-            _ => self.session.cstore.visibility(def_id),
-        };
+        let vis = self.session.cstore.visibility(def_id);
 
         match def {
             Def::Mod(..) | Def::Enum(..) => {
-                let module = self.new_module(parent, ModuleKind::Def(def, name), false);
-                self.define(parent, name, TypeNS, (module, vis, DUMMY_SP, Mark::root()));
+                let module = self.new_module(parent, ModuleKind::Def(def, ident.name), def_id);
+                self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, Mark::root()));
             }
-            Def::Variant(..) => {
-                self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
+            Def::Variant(..) | Def::TyAlias(..) => {
+                self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
             }
-            Def::VariantCtor(..) => {
-                self.define(parent, name, ValueNS, (def, vis, DUMMY_SP, Mark::root()));
-            }
-            Def::Fn(..) |
-            Def::Static(..) |
-            Def::Const(..) |
-            Def::AssociatedConst(..) |
-            Def::Method(..) => {
-                self.define(parent, name, ValueNS, (def, vis, DUMMY_SP, Mark::root()));
+            Def::Fn(..) | Def::Static(..) | Def::Const(..) |
+            Def::VariantCtor(..) | Def::StructCtor(..) => {
+                self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, Mark::root()));
             }
             Def::Trait(..) => {
-                let module = self.new_module(parent, ModuleKind::Def(def, name), false);
-                self.define(parent, name, TypeNS, (module, vis, DUMMY_SP, Mark::root()));
-
-                // If this is a trait, add all the trait item names to the trait info.
-                let trait_item_def_ids = self.session.cstore.associated_item_def_ids(def_id);
-                for trait_item_def_id in trait_item_def_ids {
-                    let trait_item_name = self.session.cstore.def_key(trait_item_def_id)
-                                              .disambiguated_data.data.get_opt_name()
-                                              .expect("opt_item_name returned None for trait");
-                    self.trait_item_map.insert((trait_item_name, def_id), false);
+                let module_kind = ModuleKind::Def(def, ident.name);
+                let module = self.new_module(parent, module_kind, parent.normal_ancestor_id);
+                self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, Mark::root()));
+
+                for child in self.session.cstore.item_children(def_id) {
+                    let ns = if let Def::AssociatedTy(..) = child.def { TypeNS } else { ValueNS };
+                    let ident = Ident::with_empty_ctxt(child.name);
+                    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);
+                    self.trait_item_map.insert((def_id, child.name, ns), (child.def, has_self));
                 }
+                module.populated.set(true);
             }
-            Def::TyAlias(..) | Def::AssociatedTy(..) => {
-                self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
-            }
-            Def::Struct(..) => {
-                self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
-
-                // Record field names for error reporting.
-                let field_names = self.session.cstore.struct_field_names(def_id);
-                self.insert_field_names(def_id, field_names);
-            }
-            Def::StructCtor(..) => {
-                self.define(parent, name, ValueNS, (def, vis, DUMMY_SP, Mark::root()));
-            }
-            Def::Union(..) => {
-                self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
+            Def::Struct(..) | Def::Union(..) => {
+                self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
 
                 // Record field names for error reporting.
                 let field_names = self.session.cstore.struct_field_names(def_id);
                 self.insert_field_names(def_id, field_names);
             }
             Def::Macro(..) => {
-                self.define(parent, name, MacroNS, (def, vis, DUMMY_SP, Mark::root()));
-            }
-            Def::Local(..) |
-            Def::PrimTy(..) |
-            Def::TyParam(..) |
-            Def::Upvar(..) |
-            Def::Label(..) |
-            Def::SelfTy(..) |
-            Def::Err => {
-                bug!("unexpected definition: {:?}", def);
+                self.define(parent, ident, MacroNS, (def, vis, DUMMY_SP, Mark::root()));
             }
+            _ => bug!("unexpected definition: {:?}", def)
         }
     }
 
-    fn get_extern_crate_root(&mut self, cnum: CrateNum) -> Module<'b> {
+    fn get_extern_crate_root(&mut self, cnum: CrateNum) -> Module<'a> {
         let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+        let name = self.session.cstore.crate_name(cnum);
         let macros_only = self.session.cstore.dep_kind(cnum).macros_only();
+        let module_kind = ModuleKind::Def(Def::Mod(def_id), name);
         let arenas = self.arenas;
         *self.extern_crate_roots.entry((cnum, macros_only)).or_insert_with(|| {
-            arenas.alloc_module(ModuleS {
-                populated: Cell::new(false),
-                ..ModuleS::new(None, ModuleKind::Def(Def::Mod(def_id), keywords::Invalid.name()))
-            })
+            arenas.alloc_module(ModuleData::new(None, module_kind, def_id))
         })
     }
 
@@ -532,7 +504,7 @@ impl<'b> Resolver<'b> {
 
     /// Ensures that the reduced graph rooted at the given external module
     /// is built, building it if it is not.
-    pub fn populate_module_if_necessary(&mut self, module: Module<'b>) {
+    pub fn populate_module_if_necessary(&mut self, module: Module<'a>) {
         if module.populated.get() { return }
         for child in self.session.cstore.item_children(module.def_id().unwrap()) {
             self.build_reduced_graph_for_external_crate_def(module, child);
@@ -542,7 +514,7 @@ impl<'b> Resolver<'b> {
 
     fn legacy_import_macro(&mut self,
                            name: Name,
-                           binding: &'b NameBinding<'b>,
+                           binding: &'a NameBinding<'a>,
                            span: Span,
                            allow_shadowing: bool) {
         self.used_crates.insert(binding.def().def_id().krate);
@@ -555,7 +527,7 @@ impl<'b> Resolver<'b> {
         }
     }
 
-    fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'b>, expansion: Mark) {
+    fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>, expansion: Mark) {
         let allow_shadowing = expansion == Mark::root();
         let legacy_imports = self.legacy_macro_imports(&item.attrs);
         let cnum = module.def_id().unwrap().krate;
@@ -574,12 +546,13 @@ impl<'b> Resolver<'b> {
         }
 
         if let Some(span) = legacy_imports.import_all {
-            module.for_each_child(|name, ns, binding| if ns == MacroNS {
-                self.legacy_import_macro(name, binding, span, allow_shadowing);
+            module.for_each_child(|ident, ns, binding| if ns == MacroNS {
+                self.legacy_import_macro(ident.name, binding, span, allow_shadowing);
             });
         } else {
             for (name, span) in legacy_imports.imports {
-                let result = self.resolve_name_in_module(module, name, MacroNS, false, None);
+                let ident = Ident::with_empty_ctxt(name);
+                let result = self.resolve_ident_in_module(module, ident, MacroNS, false, None);
                 if let Ok(binding) = result {
                     self.legacy_import_macro(name, binding, span, allow_shadowing);
                 } else {
@@ -591,7 +564,8 @@ impl<'b> Resolver<'b> {
             let krate = module.def_id().unwrap().krate;
             self.used_crates.insert(krate);
             self.session.cstore.export_macros(krate);
-            let result = self.resolve_name_in_module(module, name, MacroNS, false, None);
+            let ident = Ident::with_empty_ctxt(name);
+            let result = self.resolve_ident_in_module(module, ident, MacroNS, false, None);
             if let Ok(binding) = result {
                 self.macro_exports.push(Export { name: name, def: binding.def() });
             } else {
@@ -696,9 +670,13 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
 
     fn visit_item(&mut self, item: &'a Item) {
         let macro_use = match item.node {
-            ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => return, // Scope placeholder
-            ItemKind::Mac(..) => {
-                return self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id));
+            ItemKind::Mac(ref mac) => {
+                if mac.node.path.segments.is_empty() {
+                    self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id));
+                } else {
+                    self.resolver.define_macro(item, &mut self.legacy_scope);
+                }
+                return
             }
             ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs),
             _ => false,
@@ -745,21 +723,18 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
 
         // Add the item to the trait info.
         let item_def_id = self.resolver.definitions.local_def_id(item.id);
-        let mut is_static_method = false;
-        let (def, ns) = match item.node {
-            TraitItemKind::Const(..) => (Def::AssociatedConst(item_def_id), ValueNS),
-            TraitItemKind::Method(ref sig, _) => {
-                is_static_method = !sig.decl.has_self();
-                (Def::Method(item_def_id), ValueNS)
-            }
-            TraitItemKind::Type(..) => (Def::AssociatedTy(item_def_id), TypeNS),
+        let (def, ns, has_self) = match item.node {
+            TraitItemKind::Const(..) => (Def::AssociatedConst(item_def_id), ValueNS, false),
+            TraitItemKind::Method(ref sig, _) =>
+                (Def::Method(item_def_id), ValueNS, sig.decl.has_self()),
+            TraitItemKind::Type(..) => (Def::AssociatedTy(item_def_id), TypeNS, false),
             TraitItemKind::Macro(_) => bug!(),  // handled above
         };
 
-        self.resolver.trait_item_map.insert((item.ident.name, def_id), is_static_method);
+        self.resolver.trait_item_map.insert((def_id, item.ident.name, ns), (def, has_self));
 
         let vis = ty::Visibility::Public;
-        self.resolver.define(parent, item.ident.name, ns, (def, vis, item.span, self.expansion));
+        self.resolver.define(parent, item.ident, ns, (def, vis, item.span, self.expansion));
 
         self.resolver.current_module = parent.parent.unwrap(); // nearest normal ancestor
         visit::walk_trait_item(self, item);
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index d54f4e7b20c..2fada8a9ec2 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -860,6 +860,26 @@ match (A, B, C) {
 ```
 "##,
 
+E0422: r##"
+You are trying to use an identifier that is either undefined or not a struct.
+Erroneous code example:
+``` compile_fail,E0422
+fn main () {
+    let x = Foo { x: 1, y: 2 };
+}
+```
+In this case, `Foo` is undefined, so it inherently isn't anything, and
+definitely not a struct.
+```compile_fail
+fn main () {
+    let foo = 1;
+    let x = foo { x: 1, y: 2 };
+}
+```
+In this case, `foo` is defined, but is not a struct, so Rust can't use it as
+one.
+"##,
+
 E0423: r##"
 A `struct` variant name was used like a function name.
 
@@ -1519,7 +1539,12 @@ register_diagnostics! {
 //  E0419, merged into 531
 //  E0420, merged into 532
 //  E0421, merged into 531
-//  E0422, merged into 531/532
     E0531, // unresolved pattern path kind `name`
 //  E0427, merged into 530
+    E0573,
+    E0574,
+    E0575,
+    E0576,
+    E0577,
+    E0578,
 }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index f7aaf2475f6..a0af4c45653 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -18,7 +18,6 @@
 #![cfg_attr(not(stage0), deny(warnings))]
 
 #![feature(associated_consts)]
-#![feature(borrow_state)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
@@ -34,7 +33,6 @@ extern crate arena;
 extern crate rustc;
 
 use self::Namespace::*;
-use self::FallbackSuggestion::*;
 use self::TypeParameters::*;
 use self::RibKind::*;
 
@@ -44,14 +42,13 @@ use rustc::middle::cstore::CrateLoader;
 use rustc::session::Session;
 use rustc::lint;
 use rustc::hir::def::*;
-use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
+use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
 use rustc::ty;
 use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
 use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet};
 
 use syntax::ext::hygiene::{Mark, SyntaxContext};
-use syntax::ast::{self, FloatTy};
-use syntax::ast::{CRATE_NODE_ID, Name, NodeId, Ident, SpannedIdent, IntTy, UintTy};
+use syntax::ast::{self, Name, NodeId, Ident, SpannedIdent, FloatTy, IntTy, UintTy};
 use syntax::ext::base::SyntaxExtension;
 use syntax::ext::base::Determinacy::{Determined, Undetermined};
 use syntax::symbol::{Symbol, keywords};
@@ -63,9 +60,9 @@ use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind};
 use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, Generics};
 use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
 use syntax::ast::{Local, Mutability, Pat, PatKind, Path};
-use syntax::ast::{PathSegment, PathParameters, QSelf, TraitItemKind, TraitRef, Ty, TyKind};
+use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
 
-use syntax_pos::{Span, DUMMY_SP};
+use syntax_pos::{Span, DUMMY_SP, MultiSpan};
 use errors::DiagnosticBuilder;
 
 use std::cell::{Cell, RefCell};
@@ -85,16 +82,16 @@ mod check_unused;
 mod build_reduced_graph;
 mod resolve_imports;
 
-enum SuggestionType {
-    Macro(String),
-    Function(Symbol),
-    NotFound,
+/// A free importable items suggested in case of resolution failure.
+struct ImportSuggestion {
+    path: Path,
 }
 
-/// Candidates for a name resolution failure
-struct SuggestedCandidates {
-    name: String,
-    candidates: Vec<Path>,
+/// A field or associated item from self type suggested in case of resolution failure.
+enum AssocSuggestion {
+    Field,
+    MethodWithSelf,
+    AssocItem,
 }
 
 enum ResolutionError<'a> {
@@ -104,10 +101,6 @@ enum ResolutionError<'a> {
     OuterTypeParameterContext,
     /// error E0403: the name is already used for a type parameter in this type parameter list
     NameAlreadyUsedInTypeParameterList(Name, &'a Span),
-    /// error E0404: is not a trait
-    IsNotATrait(&'a str, &'a str),
-    /// error E0405: use of undeclared trait name
-    UndeclaredTraitName(&'a str, SuggestedCandidates),
     /// error E0407: method is not a member of trait
     MethodNotMemberOfTrait(Name, &'a str),
     /// error E0437: type is not a member of trait
@@ -118,27 +111,10 @@ enum ResolutionError<'a> {
     VariableNotBoundInPattern(Name, usize, usize),
     /// error E0409: variable is bound with different mode in pattern #{} than in pattern #1
     VariableBoundWithDifferentMode(Name, usize, Span),
-    /// error E0411: use of `Self` outside of an impl or trait
-    SelfUsedOutsideImplOrTrait,
-    /// error E0412: use of undeclared
-    UseOfUndeclared(&'a str, &'a str, SuggestedCandidates),
     /// error E0415: identifier is bound more than once in this parameter list
     IdentifierBoundMoreThanOnceInParameterList(&'a str),
     /// error E0416: identifier is bound more than once in the same pattern
     IdentifierBoundMoreThanOnceInSamePattern(&'a str),
-    /// error E0423: is a struct variant name, but this expression uses it like a function name
-    StructVariantUsedAsFunction(&'a str),
-    /// error E0424: `self` is not available in a static method
-    SelfNotAvailableInStaticMethod,
-    /// error E0425: unresolved name
-    UnresolvedName {
-        path: &'a str,
-        message: &'a str,
-        context: UnresolvedNameContext<'a>,
-        is_static_method: bool,
-        is_field: bool,
-        def: Def,
-    },
     /// error E0426: use of undeclared label
     UndeclaredLabel(&'a str),
     /// error E0429: `self` imports are only allowed within a { } list
@@ -157,37 +133,18 @@ enum ResolutionError<'a> {
     AttemptToUseNonConstantValueInConstant,
     /// error E0530: X bindings cannot shadow Ys
     BindingShadowsSomethingUnacceptable(&'a str, Name, &'a NameBinding<'a>),
-    /// error E0531: unresolved pattern path kind `name`
-    PatPathUnresolved(&'a str, &'a Path),
-    /// error E0532: expected pattern path kind, found another pattern path kind
-    PatPathUnexpected(&'a str, &'a str, &'a Path),
-}
-
-/// Context of where `ResolutionError::UnresolvedName` arose.
-#[derive(Clone, PartialEq, Eq, Debug)]
-enum UnresolvedNameContext<'a> {
-    /// `PathIsMod(parent)` indicates that a given path, used in
-    /// expression context, actually resolved to a module rather than
-    /// a value. The optional expression attached to the variant is the
-    /// the parent of the erroneous path expression.
-    PathIsMod(Option<&'a Expr>),
-
-    /// `Other` means we have no extra information about the context
-    /// of the unresolved name error. (Maybe we could eliminate all
-    /// such cases; but for now, this is an information-free default.)
-    Other,
 }
 
-fn resolve_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
-                                 span: syntax_pos::Span,
-                                 resolution_error: ResolutionError<'c>) {
+fn resolve_error<'sess, 'a>(resolver: &'sess Resolver,
+                            span: Span,
+                            resolution_error: ResolutionError<'a>) {
     resolve_struct_error(resolver, span, resolution_error).emit();
 }
 
-fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
-                                        span: syntax_pos::Span,
-                                        resolution_error: ResolutionError<'c>)
-                                        -> DiagnosticBuilder<'a> {
+fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
+                                   span: Span,
+                                   resolution_error: ResolutionError<'a>)
+                                   -> DiagnosticBuilder<'sess> {
     match resolution_error {
         ResolutionError::TypeParametersFromOuterFunction => {
             let mut err = struct_span_err!(resolver.session,
@@ -214,26 +171,6 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
              err.span_label(span, &format!("already used"));
              err.span_label(first_use_span.clone(), &format!("first use of `{}`", name));
              err
-
-        }
-        ResolutionError::IsNotATrait(name, kind_name) => {
-            let mut err = struct_span_err!(resolver.session,
-                                           span,
-                                           E0404,
-                                           "`{}` is not a trait",
-                                           name);
-            err.span_label(span, &format!("expected trait, found {}", kind_name));
-            err
-        }
-        ResolutionError::UndeclaredTraitName(name, candidates) => {
-            let mut err = struct_span_err!(resolver.session,
-                                           span,
-                                           E0405,
-                                           "trait `{}` is not in scope",
-                                           name);
-            show_candidates(&mut err, &candidates);
-            err.span_label(span, &format!("`{}` is not in scope", name));
-            err
         }
         ResolutionError::MethodNotMemberOfTrait(method, trait_) => {
             let mut err = struct_span_err!(resolver.session,
@@ -290,25 +227,6 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
             err.span_label(first_binding_span, &format!("first binding"));
             err
         }
-        ResolutionError::SelfUsedOutsideImplOrTrait => {
-            let mut err = struct_span_err!(resolver.session,
-                                           span,
-                                           E0411,
-                                           "use of `Self` outside of an impl or trait");
-            err.span_label(span, &format!("used outside of impl or trait"));
-            err
-        }
-        ResolutionError::UseOfUndeclared(kind, name, candidates) => {
-            let mut err = struct_span_err!(resolver.session,
-                                           span,
-                                           E0412,
-                                           "{} `{}` is undefined or not in scope",
-                                           kind,
-                                           name);
-            show_candidates(&mut err, &candidates);
-            err.span_label(span, &format!("undefined or not in scope"));
-            err
-        }
         ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => {
             let mut err = struct_span_err!(resolver.session,
                              span,
@@ -327,69 +245,6 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
             err.span_label(span, &format!("used in a pattern more than once"));
             err
         }
-        ResolutionError::StructVariantUsedAsFunction(path_name) => {
-            let mut err = struct_span_err!(resolver.session,
-                             span,
-                             E0423,
-                             "`{}` is the name of a struct or struct variant, but this expression \
-                             uses it like a function name",
-                             path_name);
-            err.span_label(span, &format!("struct called like a function"));
-            err
-        }
-        ResolutionError::SelfNotAvailableInStaticMethod => {
-            let mut err = struct_span_err!(resolver.session,
-                             span,
-                             E0424,
-                             "`self` is not available in a static method");
-            err.span_label(span, &format!("not available in static method"));
-            err.note(&format!("maybe a `self` argument is missing?"));
-            err
-        }
-        ResolutionError::UnresolvedName { path, message: msg, context, is_static_method,
-                                          is_field, def } => {
-            let mut err = struct_span_err!(resolver.session,
-                                           span,
-                                           E0425,
-                                           "unresolved name `{}`",
-                                           path);
-            if msg != "" {
-                err.span_label(span, &msg);
-            } else {
-                err.span_label(span, &format!("unresolved name"));
-            }
-
-            match context {
-                UnresolvedNameContext::Other => {
-                    if msg.is_empty() && is_static_method && is_field {
-                        err.help("this is an associated function, you don't have access to \
-                                  this type's fields or methods");
-                    }
-                }
-                UnresolvedNameContext::PathIsMod(parent) => {
-                    err.help(&match parent.map(|parent| &parent.node) {
-                        Some(&ExprKind::Field(_, ident)) => {
-                            format!("to reference an item from the `{module}` module, \
-                                     use `{module}::{ident}`",
-                                    module = path,
-                                    ident = ident.node)
-                        }
-                        Some(&ExprKind::MethodCall(ident, ..)) => {
-                            format!("to call a function from the `{module}` module, \
-                                     use `{module}::{ident}(..)`",
-                                    module = path,
-                                    ident = ident.node)
-                        }
-                        _ => {
-                            format!("{def} `{module}` cannot be used as an expression",
-                                    def = def.kind_name(),
-                                    module = path)
-                        }
-                    });
-                }
-            }
-            err
-        }
         ResolutionError::UndeclaredLabel(name) => {
             let mut err = struct_span_err!(resolver.session,
                                            span,
@@ -464,23 +319,6 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
             err.span_label(binding.span, msg);
             err
         }
-        ResolutionError::PatPathUnresolved(expected_what, path) => {
-            struct_span_err!(resolver.session,
-                             span,
-                             E0531,
-                             "unresolved {} `{}`",
-                             expected_what,
-                             path)
-        }
-        ResolutionError::PatPathUnexpected(expected_what, found_what, path) => {
-            struct_span_err!(resolver.session,
-                             span,
-                             E0532,
-                             "expected {}, found {} `{}`",
-                             expected_what,
-                             found_what,
-                             path)
-        }
     }
 }
 
@@ -522,6 +360,163 @@ impl PatternSource {
     }
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+enum PathSource<'a> {
+    // Type paths `Path`.
+    Type,
+    // Trait paths in bounds or impls.
+    Trait,
+    // Expression paths `path`, with optional parent context.
+    Expr(Option<&'a ExprKind>),
+    // Paths in path patterns `Path`.
+    Pat,
+    // Paths in struct expressions and patterns `Path { .. }`.
+    Struct,
+    // Paths in tuple struct patterns `Path(..)`.
+    TupleStruct,
+    // `m::A::B` in `<T as m::A>::B::C`.
+    TraitItem(Namespace),
+    // Path in `pub(path)`
+    Visibility,
+    // Path in `use a::b::{...};`
+    ImportPrefix,
+}
+
+impl<'a> PathSource<'a> {
+    fn namespace(self) -> Namespace {
+        match self {
+            PathSource::Type | PathSource::Trait | PathSource::Struct |
+            PathSource::Visibility | PathSource::ImportPrefix => TypeNS,
+            PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS,
+            PathSource::TraitItem(ns) => ns,
+        }
+    }
+
+    fn global_by_default(self) -> bool {
+        match self {
+            PathSource::Visibility | PathSource::ImportPrefix => true,
+            PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
+            PathSource::Struct | PathSource::TupleStruct |
+            PathSource::Trait | PathSource::TraitItem(..) => false,
+        }
+    }
+
+    fn defer_to_typeck(self) -> bool {
+        match self {
+            PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
+            PathSource::Struct | PathSource::TupleStruct => true,
+            PathSource::Trait | PathSource::TraitItem(..) |
+            PathSource::Visibility | PathSource::ImportPrefix => false,
+        }
+    }
+
+    fn descr_expected(self) -> &'static str {
+        match self {
+            PathSource::Type => "type",
+            PathSource::Trait => "trait",
+            PathSource::Pat => "unit struct/variant or constant",
+            PathSource::Struct => "struct, variant or union type",
+            PathSource::TupleStruct => "tuple struct/variant",
+            PathSource::Visibility => "module",
+            PathSource::ImportPrefix => "module or enum",
+            PathSource::TraitItem(ns) => match ns {
+                TypeNS => "associated type",
+                ValueNS => "method or associated constant",
+                MacroNS => bug!("associated macro"),
+            },
+            PathSource::Expr(parent) => match parent {
+                // "function" here means "anything callable" rather than `Def::Fn`,
+                // this is not precise but usually more helpful than just "value".
+                Some(&ExprKind::Call(..)) => "function",
+                _ => "value",
+            },
+        }
+    }
+
+    fn is_expected(self, def: Def) -> bool {
+        match self {
+            PathSource::Type => match def {
+                Def::Struct(..) | Def::Union(..) | Def::Enum(..) |
+                Def::Trait(..) | Def::TyAlias(..) | Def::AssociatedTy(..) |
+                Def::PrimTy(..) | Def::TyParam(..) | Def::SelfTy(..) => true,
+                _ => false,
+            },
+            PathSource::Trait => match def {
+                Def::Trait(..) => true,
+                _ => false,
+            },
+            PathSource::Expr(..) => match def {
+                Def::StructCtor(_, CtorKind::Const) | Def::StructCtor(_, CtorKind::Fn) |
+                Def::VariantCtor(_, CtorKind::Const) | Def::VariantCtor(_, CtorKind::Fn) |
+                Def::Const(..) | Def::Static(..) | Def::Local(..) | Def::Upvar(..) |
+                Def::Fn(..) | Def::Method(..) | Def::AssociatedConst(..) => true,
+                _ => false,
+            },
+            PathSource::Pat => match def {
+                Def::StructCtor(_, CtorKind::Const) |
+                Def::VariantCtor(_, CtorKind::Const) |
+                Def::Const(..) | Def::AssociatedConst(..) => true,
+                _ => false,
+            },
+            PathSource::TupleStruct => match def {
+                Def::StructCtor(_, CtorKind::Fn) | Def::VariantCtor(_, CtorKind::Fn) => true,
+                _ => false,
+            },
+            PathSource::Struct => match def {
+                Def::Struct(..) | Def::Union(..) | Def::Variant(..) |
+                Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => true,
+                _ => false,
+            },
+            PathSource::TraitItem(ns) => match def {
+                Def::AssociatedConst(..) | Def::Method(..) if ns == ValueNS => true,
+                Def::AssociatedTy(..) if ns == TypeNS => true,
+                _ => false,
+            },
+            PathSource::ImportPrefix => match def {
+                Def::Mod(..) | Def::Enum(..) => true,
+                _ => false,
+            },
+            PathSource::Visibility => match def {
+                Def::Mod(..) => true,
+                _ => false,
+            },
+        }
+    }
+
+    fn error_code(self, has_unexpected_resolution: bool) -> &'static str {
+        __diagnostic_used!(E0404);
+        __diagnostic_used!(E0405);
+        __diagnostic_used!(E0412);
+        __diagnostic_used!(E0422);
+        __diagnostic_used!(E0423);
+        __diagnostic_used!(E0425);
+        __diagnostic_used!(E0531);
+        __diagnostic_used!(E0532);
+        __diagnostic_used!(E0573);
+        __diagnostic_used!(E0574);
+        __diagnostic_used!(E0575);
+        __diagnostic_used!(E0576);
+        __diagnostic_used!(E0577);
+        __diagnostic_used!(E0578);
+        match (self, has_unexpected_resolution) {
+            (PathSource::Trait, true) => "E0404",
+            (PathSource::Trait, false) => "E0405",
+            (PathSource::Type, true) => "E0573",
+            (PathSource::Type, false) => "E0412",
+            (PathSource::Struct, true) => "E0574",
+            (PathSource::Struct, false) => "E0422",
+            (PathSource::Expr(..), true) => "E0423",
+            (PathSource::Expr(..), false) => "E0425",
+            (PathSource::Pat, true) | (PathSource::TupleStruct, true) => "E0532",
+            (PathSource::Pat, false) | (PathSource::TupleStruct, false) => "E0531",
+            (PathSource::TraitItem(..), true) => "E0575",
+            (PathSource::TraitItem(..), false) => "E0576",
+            (PathSource::Visibility, true) | (PathSource::ImportPrefix, true) => "E0577",
+            (PathSource::Visibility, false) | (PathSource::ImportPrefix, false) => "E0578",
+        }
+    }
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub enum Namespace {
     TypeNS,
@@ -574,15 +569,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
         self.resolve_local(local);
     }
     fn visit_ty(&mut self, ty: &'tcx Ty) {
-        self.resolve_type(ty);
+        if let TyKind::Path(ref qself, ref path) = ty.node {
+            self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
+        }
+        visit::walk_ty(self, ty);
     }
     fn visit_poly_trait_ref(&mut self,
                             tref: &'tcx ast::PolyTraitRef,
                             m: &'tcx ast::TraitBoundModifier) {
-        let ast::Path { ref segments, span, global } = tref.trait_ref.path;
-        let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect();
-        let def = self.resolve_trait_reference(&path, global, None, span);
-        self.record_def(tref.trait_ref.ref_id, def);
+        self.smart_resolve_path(tref.trait_ref.ref_id, None,
+                                &tref.trait_ref.path, PathSource::Trait);
         visit::walk_poly_trait_ref(self, tref, m);
     }
     fn visit_variant(&mut self,
@@ -668,13 +664,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
 
 pub type ErrorMessage = Option<(Span, String)>;
 
-enum FallbackSuggestion {
-    NoSuggestion,
-    Field,
-    TraitItem,
-    TraitMethod(String),
-}
-
 #[derive(Copy, Clone)]
 enum TypeParameters<'a, 'b> {
     NoTypeParameters,
@@ -734,7 +723,7 @@ impl<'a> Rib<'a> {
 }
 
 /// A definition along with the index of the rib it was found on
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 struct LocalDef {
     ribs: Option<(Namespace, usize)>,
     def: Def,
@@ -754,13 +743,6 @@ impl<'a> LexicalScopeBinding<'a> {
     }
 }
 
-#[derive(Copy, Clone)]
-enum PathScope {
-    Global,
-    Lexical,
-    Import,
-}
-
 #[derive(Clone)]
 enum PathResult<'a> {
     Module(Module<'a>),
@@ -775,16 +757,16 @@ enum ModuleKind {
 }
 
 /// One node in the tree of modules.
-pub struct ModuleS<'a> {
+pub struct ModuleData<'a> {
     parent: Option<Module<'a>>,
     kind: ModuleKind,
 
-    // The node id of the closest normal module (`mod`) ancestor (including this module).
-    normal_ancestor_id: Option<NodeId>,
+    // The def id of the closest normal module (`mod`) ancestor (including this module).
+    normal_ancestor_id: DefId,
 
-    resolutions: RefCell<FxHashMap<(Name, Namespace), &'a RefCell<NameResolution<'a>>>>,
-    legacy_macro_resolutions: RefCell<Vec<(Mark, Name, Span)>>,
-    macro_resolutions: RefCell<Vec<(Box<[Ident]>, PathScope, Span)>>,
+    resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
+    legacy_macro_resolutions: RefCell<Vec<(Mark, Ident, Span)>>,
+    macro_resolutions: RefCell<Vec<(Box<[Ident]>, Span)>>,
 
     // Macro invocations that can expand into items in this module.
     unresolved_invocations: RefCell<FxHashSet<Mark>>,
@@ -795,7 +777,7 @@ pub struct ModuleS<'a> {
     globs: RefCell<Vec<&'a ImportDirective<'a>>>,
 
     // Used to memoize the traits in this module for faster searches through all traits in scope.
-    traits: RefCell<Option<Box<[(Name, &'a NameBinding<'a>)]>>>,
+    traits: RefCell<Option<Box<[(Ident, &'a NameBinding<'a>)]>>>,
 
     // Whether this module is populated. If not populated, any attempt to
     // access the children must be preceded with a
@@ -803,14 +785,14 @@ pub struct ModuleS<'a> {
     populated: Cell<bool>,
 }
 
-pub type Module<'a> = &'a ModuleS<'a>;
+pub type Module<'a> = &'a ModuleData<'a>;
 
-impl<'a> ModuleS<'a> {
-    fn new(parent: Option<Module<'a>>, kind: ModuleKind) -> Self {
-        ModuleS {
+impl<'a> ModuleData<'a> {
+    fn new(parent: Option<Module<'a>>, kind: ModuleKind, normal_ancestor_id: DefId) -> Self {
+        ModuleData {
             parent: parent,
             kind: kind,
-            normal_ancestor_id: None,
+            normal_ancestor_id: normal_ancestor_id,
             resolutions: RefCell::new(FxHashMap()),
             legacy_macro_resolutions: RefCell::new(Vec::new()),
             macro_resolutions: RefCell::new(Vec::new()),
@@ -819,13 +801,13 @@ impl<'a> ModuleS<'a> {
             glob_importers: RefCell::new(Vec::new()),
             globs: RefCell::new((Vec::new())),
             traits: RefCell::new(None),
-            populated: Cell::new(true),
+            populated: Cell::new(normal_ancestor_id.is_local()),
         }
     }
 
-    fn for_each_child<F: FnMut(Name, Namespace, &'a NameBinding<'a>)>(&self, mut f: F) {
-        for (&(name, ns), name_resolution) in self.resolutions.borrow().iter() {
-            name_resolution.borrow().binding.map(|binding| f(name, ns, binding));
+    fn for_each_child<F: FnMut(Ident, Namespace, &'a NameBinding<'a>)>(&self, mut f: F) {
+        for (&(ident, ns), name_resolution) in self.resolutions.borrow().iter() {
+            name_resolution.borrow().binding.map(|binding| f(ident, ns, binding));
         }
     }
 
@@ -856,11 +838,11 @@ impl<'a> ModuleS<'a> {
     }
 
     fn is_local(&self) -> bool {
-        self.normal_ancestor_id.is_some()
+        self.normal_ancestor_id.is_local()
     }
 }
 
-impl<'a> fmt::Debug for ModuleS<'a> {
+impl<'a> fmt::Debug for ModuleData<'a> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "{:?}", self.def())
     }
@@ -876,11 +858,11 @@ pub struct NameBinding<'a> {
 }
 
 pub trait ToNameBinding<'a> {
-    fn to_name_binding(self) -> NameBinding<'a>;
+    fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a>;
 }
 
-impl<'a> ToNameBinding<'a> for NameBinding<'a> {
-    fn to_name_binding(self) -> NameBinding<'a> {
+impl<'a> ToNameBinding<'a> for &'a NameBinding<'a> {
+    fn to_name_binding(self, _: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
         self
     }
 }
@@ -897,6 +879,7 @@ enum NameBindingKind<'a> {
     Ambiguity {
         b1: &'a NameBinding<'a>,
         b2: &'a NameBinding<'a>,
+        legacy: bool,
     }
 }
 
@@ -908,6 +891,7 @@ struct AmbiguityError<'a> {
     lexical: bool,
     b1: &'a NameBinding<'a>,
     b2: &'a NameBinding<'a>,
+    legacy: bool,
 }
 
 impl<'a> NameBinding<'a> {
@@ -915,6 +899,7 @@ impl<'a> NameBinding<'a> {
         match self.kind {
             NameBindingKind::Module(module) => Some(module),
             NameBindingKind::Import { binding, .. } => binding.module(),
+            NameBindingKind::Ambiguity { legacy: true, b1, .. } => b1.module(),
             _ => None,
         }
     }
@@ -924,6 +909,7 @@ impl<'a> NameBinding<'a> {
             NameBindingKind::Def(def) => def,
             NameBindingKind::Module(module) => module.def().unwrap(),
             NameBindingKind::Import { binding, .. } => binding.def(),
+            NameBindingKind::Ambiguity { legacy: true, b1, .. } => b1.def(),
             NameBindingKind::Ambiguity { .. } => Def::Err,
         }
     }
@@ -1030,7 +1016,7 @@ pub struct Resolver<'a> {
 
     prelude: Option<Module<'a>>,
 
-    trait_item_map: FxHashMap<(Name, DefId), bool /* is static method? */>,
+    trait_item_map: FxHashMap<(DefId, Name, Namespace), (Def, bool /* has self */)>,
 
     // Names of fields of an item `DefId` accessible with dot syntax.
     // Used for hints during error reporting.
@@ -1067,7 +1053,7 @@ pub struct Resolver<'a> {
     pub export_map: ExportMap,
     pub trait_map: TraitMap,
 
-    // A map from nodes to modules, both normal (`mod`) modules and anonymous modules.
+    // A map from nodes to anonymous modules.
     // Anonymous modules are pseudo-modules that are implicitly created around items
     // contained within blocks.
     //
@@ -1081,7 +1067,8 @@ pub struct Resolver<'a> {
     //
     // There will be an anonymous module created around `g` with the ID of the
     // entry block for `f`.
-    module_map: NodeMap<Module<'a>>,
+    block_map: NodeMap<Module<'a>>,
+    module_map: FxHashMap<DefId, Module<'a>>,
     extern_crate_roots: FxHashMap<(CrateNum, bool /* MacrosOnly? */), Module<'a>>,
 
     pub make_glob_map: bool,
@@ -1108,6 +1095,7 @@ pub struct Resolver<'a> {
     lexical_macro_resolutions: Vec<(Name, &'a Cell<LegacyScope<'a>>)>,
     macro_map: FxHashMap<DefId, Rc<SyntaxExtension>>,
     macro_exports: Vec<Export>,
+    pub whitelisted_legacy_custom_derives: Vec<Name>,
 
     // Maps the `Mark` of an expansion to its containing module or block.
     invocations: FxHashMap<Mark, &'a InvocationData<'a>>,
@@ -1117,7 +1105,7 @@ pub struct Resolver<'a> {
 }
 
 pub struct ResolverArenas<'a> {
-    modules: arena::TypedArena<ModuleS<'a>>,
+    modules: arena::TypedArena<ModuleData<'a>>,
     local_modules: RefCell<Vec<Module<'a>>>,
     name_bindings: arena::TypedArena<NameBinding<'a>>,
     import_directives: arena::TypedArena<ImportDirective<'a>>,
@@ -1127,7 +1115,7 @@ pub struct ResolverArenas<'a> {
 }
 
 impl<'a> ResolverArenas<'a> {
-    fn alloc_module(&'a self, module: ModuleS<'a>) -> Module<'a> {
+    fn alloc_module(&'a self, module: ModuleData<'a>) -> Module<'a> {
         let module = self.modules.alloc(module);
         if module.def_id().map(|def_id| def_id.is_local()).unwrap_or(true) {
             self.local_modules.borrow_mut().push(module);
@@ -1156,28 +1144,24 @@ impl<'a> ResolverArenas<'a> {
     }
 }
 
-impl<'a> ty::NodeIdTree for Resolver<'a> {
-    fn is_descendant_of(&self, mut node: NodeId, ancestor: NodeId) -> bool {
-        while node != ancestor {
-            node = match self.module_map[&node].parent {
-                Some(parent) => parent.normal_ancestor_id.unwrap(),
-                None => return false,
-            }
-        }
-        true
+impl<'a, 'b: 'a> ty::DefIdTree for &'a Resolver<'b> {
+    fn parent(self, id: DefId) -> Option<DefId> {
+        match id.krate {
+            LOCAL_CRATE => self.definitions.def_key(id.index).parent,
+            _ => self.session.cstore.def_key(id).parent,
+        }.map(|index| DefId { index: index, ..id })
     }
 }
 
 impl<'a> hir::lowering::Resolver for Resolver<'a> {
     fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool) {
         let namespace = if is_value { ValueNS } else { TypeNS };
-        let hir::Path { ref segments, span, global, ref mut def } = *path;
+        let hir::Path { ref segments, span, ref mut def } = *path;
         let path: Vec<_> = segments.iter().map(|seg| Ident::with_empty_ctxt(seg.name)).collect();
-        let scope = if global { PathScope::Global } else { PathScope::Lexical };
-        match self.resolve_path(&path, scope, Some(namespace), Some(span)) {
+        match self.resolve_path(&path, Some(namespace), Some(span)) {
             PathResult::Module(module) => *def = module.def().unwrap(),
             PathResult::NonModule(path_res) if path_res.depth == 0 => *def = path_res.base_def,
-            PathResult::NonModule(..) => match self.resolve_path(&path, scope, None, Some(span)) {
+            PathResult::NonModule(..) => match self.resolve_path(&path, None, Some(span)) {
                 PathResult::Failed(msg, _) => {
                     resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
                 }
@@ -1206,14 +1190,14 @@ impl<'a> Resolver<'a> {
                crate_loader: &'a mut CrateLoader,
                arenas: &'a ResolverArenas<'a>)
                -> Resolver<'a> {
-        let root_def = Def::Mod(DefId::local(CRATE_DEF_INDEX));
-        let graph_root = arenas.alloc_module(ModuleS {
-            normal_ancestor_id: Some(CRATE_NODE_ID),
+        let root_def_id = DefId::local(CRATE_DEF_INDEX);
+        let root_module_kind = ModuleKind::Def(Def::Mod(root_def_id), keywords::Invalid.name());
+        let graph_root = arenas.alloc_module(ModuleData {
             no_implicit_prelude: attr::contains_name(&krate.attrs, "no_implicit_prelude"),
-            ..ModuleS::new(None, ModuleKind::Def(root_def, keywords::Invalid.name()))
+            ..ModuleData::new(None, root_module_kind, root_def_id)
         });
-        let mut module_map = NodeMap();
-        module_map.insert(CRATE_NODE_ID, graph_root);
+        let mut module_map = FxHashMap();
+        module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root);
 
         let mut definitions = Definitions::new();
         DefCollector::new(&mut definitions).collect_root();
@@ -1258,6 +1242,7 @@ impl<'a> Resolver<'a> {
             export_map: NodeMap(),
             trait_map: NodeMap(),
             module_map: module_map,
+            block_map: NodeMap(),
             extern_crate_roots: FxHashMap(),
 
             make_glob_map: make_glob_map == MakeGlobMap::Yes,
@@ -1289,6 +1274,7 @@ impl<'a> Resolver<'a> {
             macro_exports: Vec::new(),
             invocations: invocations,
             name_already_seen: FxHashMap(),
+            whitelisted_legacy_custom_derives: Vec::new(),
         }
     }
 
@@ -1327,18 +1313,15 @@ impl<'a> Resolver<'a> {
         self.crate_loader.postprocess(krate);
     }
 
-    fn new_module(&self, parent: Module<'a>, kind: ModuleKind, local: bool) -> Module<'a> {
-        self.arenas.alloc_module(ModuleS {
-            normal_ancestor_id: if local { self.current_module.normal_ancestor_id } else { None },
-            populated: Cell::new(local),
-            ..ModuleS::new(Some(parent), kind)
-        })
+    fn new_module(&self, parent: Module<'a>, kind: ModuleKind, normal_ancestor_id: DefId)
+                  -> Module<'a> {
+        self.arenas.alloc_module(ModuleData::new(Some(parent), kind, normal_ancestor_id))
     }
 
-    fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
+    fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
                   -> bool /* true if an error was reported */ {
         // track extern crates for unused_extern_crate lint
-        if let Some(DefId { krate, .. }) = binding.module().and_then(ModuleS::def_id) {
+        if let Some(DefId { krate, .. }) = binding.module().and_then(ModuleData::def_id) {
             self.used_crates.insert(krate);
         }
 
@@ -1346,23 +1329,26 @@ impl<'a> Resolver<'a> {
             NameBindingKind::Import { directive, binding, ref used } if !used.get() => {
                 used.set(true);
                 self.used_imports.insert((directive.id, ns));
-                self.add_to_glob_map(directive.id, name);
-                self.record_use(name, ns, binding, span)
+                self.add_to_glob_map(directive.id, ident);
+                self.record_use(ident, ns, binding, span)
             }
             NameBindingKind::Import { .. } => false,
-            NameBindingKind::Ambiguity { b1, b2 } => {
+            NameBindingKind::Ambiguity { b1, b2, legacy } => {
                 self.ambiguity_errors.push(AmbiguityError {
-                    span: span, name: name, lexical: false, b1: b1, b2: b2,
+                    span: span, name: ident.name, lexical: false, b1: b1, b2: b2, legacy: legacy,
                 });
-                true
+                if legacy {
+                    self.record_use(ident, ns, b1, span);
+                }
+                !legacy
             }
             _ => false
         }
     }
 
-    fn add_to_glob_map(&mut self, id: NodeId, name: Name) {
+    fn add_to_glob_map(&mut self, id: NodeId, ident: Ident) {
         if self.make_glob_map {
-            self.glob_map.entry(id).or_insert_with(FxHashSet).insert(name);
+            self.glob_map.entry(id).or_insert_with(FxHashSet).insert(ident.name);
         }
     }
 
@@ -1389,23 +1375,20 @@ impl<'a> Resolver<'a> {
                                       record_used: Option<Span>)
                                       -> Option<LexicalScopeBinding<'a>> {
         if ns == TypeNS {
-            ident = Ident::with_empty_ctxt(ident.name);
+            ident = ident.unhygienize();
         }
 
         // Walk backwards up the ribs in scope.
         for i in (0 .. self.ribs[ns].len()).rev() {
             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(if let Some(span) = record_used {
-                    self.adjust_local_def(LocalDef { ribs: Some((ns, i)), def: def }, span)
-                } else {
-                    def
-                }));
+                return Some(LexicalScopeBinding::Def(
+                    self.adjust_local_def(LocalDef { ribs: Some((ns, i)), def: def }, record_used)
+                ));
             }
 
             if let ModuleRibKind(module) = self.ribs[ns][i].kind {
-                let name = ident.name;
-                let item = self.resolve_name_in_module(module, name, ns, false, record_used);
+                let item = self.resolve_ident_in_module(module, ident, ns, false, record_used);
                 if let Ok(binding) = item {
                     // The ident resolves to an item.
                     return Some(LexicalScopeBinding::Item(binding));
@@ -1414,7 +1397,7 @@ impl<'a> Resolver<'a> {
                 if let ModuleKind::Block(..) = module.kind { // We can see through blocks
                 } else if !module.no_implicit_prelude {
                     return self.prelude.and_then(|prelude| {
-                        self.resolve_name_in_module(prelude, name, ns, false, None).ok()
+                        self.resolve_ident_in_module(prelude, ident, ns, false, None).ok()
                     }).map(LexicalScopeBinding::Item)
                 } else {
                     return None;
@@ -1463,6 +1446,7 @@ impl<'a> Resolver<'a> {
     fn with_scope<F>(&mut self, id: NodeId, f: F)
         where F: FnOnce(&mut Resolver)
     {
+        let id = self.definitions.local_def_id(id);
         let module = self.module_map.get(&id).cloned(); // clones a reference
         if let Some(module) = module {
             // Move down in the graph.
@@ -1526,7 +1510,7 @@ impl<'a> Resolver<'a> {
             }
 
             ItemKind::DefaultImpl(_, ref trait_ref) => {
-                self.with_optional_trait_ref(Some(trait_ref), |_, _| {}, None);
+                self.with_optional_trait_ref(Some(trait_ref), |_, _| {});
             }
             ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
                 self.resolve_implementation(generics,
@@ -1591,34 +1575,9 @@ impl<'a> Resolver<'a> {
 
             ItemKind::Use(ref view_path) => {
                 match view_path.node {
-                    ast::ViewPathList(ref prefix, ref items) => {
-                        let path: Vec<_> =
-                            prefix.segments.iter().map(|seg| seg.identifier).collect();
-                        // Resolve prefix of an import with empty braces (issue #28388)
-                        if items.is_empty() && !prefix.segments.is_empty() {
-                            let (scope, span) = (PathScope::Import, prefix.span);
-                            // FIXME(#38012) This should be a module path, not anything in TypeNS.
-                            let result =
-                                self.resolve_path(&path, scope, Some(TypeNS), Some(span));
-                            let (def, msg) = match result {
-                                PathResult::Module(module) => (module.def().unwrap(), None),
-                                PathResult::NonModule(res) if res.depth == 0 =>
-                                    (res.base_def, None),
-                                PathResult::NonModule(_) => {
-                                    // Resolve a module path for better errors
-                                    match self.resolve_path(&path, scope, None, Some(span)) {
-                                        PathResult::Failed(msg, _) => (Def::Err, Some(msg)),
-                                        _ => unreachable!(),
-                                    }
-                                }
-                                PathResult::Indeterminate => unreachable!(),
-                                PathResult::Failed(msg, _) => (Def::Err, Some(msg)),
-                            };
-                            if let Some(msg) = msg {
-                                resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
-                            }
-                            self.record_def(item.id, PathResolution::new(def));
-                        }
+                    ast::ViewPathList(ref prefix, ref items) if items.is_empty() => {
+                        // Resolve prefix of an import with empty braces (issue #28388).
+                        self.smart_resolve_path(item.id, None, prefix, PathSource::ImportPrefix);
                     }
                     _ => {}
                 }
@@ -1691,56 +1650,6 @@ impl<'a> Resolver<'a> {
         self.ribs[ValueNS].pop();
     }
 
-    fn resolve_trait_reference(&mut self,
-                               path: &[Ident],
-                               global: bool,
-                               generics: Option<&Generics>,
-                               span: Span)
-                               -> PathResolution {
-        let scope = if global { PathScope::Global } else { PathScope::Lexical };
-        let def = match self.resolve_path(path, scope, None, Some(span)) {
-            PathResult::Module(module) => Some(module.def().unwrap()),
-            PathResult::NonModule(..) => return err_path_resolution(),
-            PathResult::Failed(msg, false) => {
-                resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
-                return err_path_resolution();
-            }
-            _ => match self.resolve_path(path, scope, Some(TypeNS), None) {
-                PathResult::NonModule(path_resolution) => Some(path_resolution.base_def),
-                _ => None,
-            },
-        };
-
-        if let Some(def) = def {
-            if let Def::Trait(_) = def {
-                return PathResolution::new(def);
-            }
-
-            let mut err = resolve_struct_error(self, span, {
-                ResolutionError::IsNotATrait(&names_to_string(path), def.kind_name())
-            });
-            if let Some(generics) = generics {
-                if let Some(span) = generics.span_for_name(&names_to_string(path)) {
-                    err.span_label(span, &"type parameter defined here");
-                }
-            }
-
-            // If it's a typedef, give a note
-            if let Def::TyAlias(..) = def {
-                err.note(&format!("type aliases cannot be used for traits"));
-            }
-            err.emit();
-        } else {
-            // find possible candidates
-            let is_trait = |def| match def { Def::Trait(_) => true, _ => false };
-            let candidates = self.lookup_candidates(path.last().unwrap().name, TypeNS, is_trait);
-
-            let path = names_to_string(path);
-            resolve_error(self, span, ResolutionError::UndeclaredTraitName(&path, candidates));
-        }
-        err_path_resolution()
-    }
-
     fn with_current_self_type<T, F>(&mut self, self_type: &Ty, f: F) -> T
         where F: FnOnce(&mut Resolver) -> T
     {
@@ -1751,24 +1660,17 @@ impl<'a> Resolver<'a> {
         result
     }
 
-    fn with_optional_trait_ref<T, F>(&mut self,
-                                     opt_trait_ref: Option<&TraitRef>,
-                                     f: F,
-                                     generics: Option<&Generics>)
-        -> T
+    fn with_optional_trait_ref<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T
         where F: FnOnce(&mut Resolver, Option<DefId>) -> T
     {
         let mut new_val = None;
         let mut new_id = None;
         if let Some(trait_ref) = opt_trait_ref {
-            let ast::Path { ref segments, span, global } = trait_ref.path;
-            let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect();
-            let path_res = self.resolve_trait_reference(&path, global, generics, span);
-            assert!(path_res.depth == 0);
-            self.record_def(trait_ref.ref_id, path_res);
-            if path_res.base_def != Def::Err {
-                new_val = Some((path_res.base_def.def_id(), trait_ref.clone()));
-                new_id = Some(path_res.base_def.def_id());
+            let def = self.smart_resolve_path(trait_ref.ref_id, None,
+                                              &trait_ref.path, PathSource::Trait).base_def;
+            if def != Def::Err {
+                new_val = Some((def.def_id(), trait_ref.clone()));
+                new_id = Some(def.def_id());
             }
             visit::walk_trait_ref(self, trait_ref);
         }
@@ -1816,6 +1718,7 @@ impl<'a> Resolver<'a> {
                                     // If this is a trait impl, ensure the const
                                     // exists in trait
                                     this.check_trait_item(impl_item.ident.name,
+                                                          ValueNS,
                                                           impl_item.span,
                                         |n, s| ResolutionError::ConstNotMemberOfTrait(n, s));
                                     visit::walk_impl_item(this, impl_item);
@@ -1824,6 +1727,7 @@ impl<'a> Resolver<'a> {
                                     // If this is a trait impl, ensure the method
                                     // exists in trait
                                     this.check_trait_item(impl_item.ident.name,
+                                                          ValueNS,
                                                           impl_item.span,
                                         |n, s| ResolutionError::MethodNotMemberOfTrait(n, s));
 
@@ -1840,6 +1744,7 @@ impl<'a> Resolver<'a> {
                                     // If this is a trait impl, ensure the type
                                     // exists in trait
                                     this.check_trait_item(impl_item.ident.name,
+                                                          TypeNS,
                                                           impl_item.span,
                                         |n, s| ResolutionError::TypeNotMemberOfTrait(n, s));
 
@@ -1850,18 +1755,18 @@ impl<'a> Resolver<'a> {
                         }
                     });
                 });
-            }, Some(&generics));
+            });
         });
     }
 
-    fn check_trait_item<F>(&self, name: Name, span: Span, err: F)
+    fn check_trait_item<F>(&self, name: Name, ns: Namespace, span: Span, err: F)
         where F: FnOnce(Name, &str) -> ResolutionError
     {
         // If there is a TraitRef in scope for an impl, then the method must be in the
         // trait.
         if let Some((did, ref trait_ref)) = self.current_trait_ref {
-            if !self.trait_item_map.contains_key(&(name, did)) {
-                let path_str = path_names_to_string(&trait_ref.path, 0);
+            if !self.trait_item_map.contains_key(&(did, name, ns)) {
+                let path_str = path_names_to_string(&trait_ref.path);
                 resolve_error(self, span, err(name, &path_str));
             }
         }
@@ -1962,7 +1867,7 @@ impl<'a> Resolver<'a> {
         debug!("(resolving block) entering block");
         // Move down in the graph, if there's an anonymous module rooted here.
         let orig_module = self.current_module;
-        let anonymous_module = self.module_map.get(&block.id).cloned(); // clones a reference
+        let anonymous_module = self.block_map.get(&block.id).cloned(); // clones a reference
 
         let mut num_macro_definition_ribs = 0;
         if let Some(anonymous_module) = anonymous_module {
@@ -2001,58 +1906,6 @@ impl<'a> Resolver<'a> {
         debug!("(resolving block) leaving block");
     }
 
-    fn resolve_type(&mut self, ty: &Ty) {
-        if let TyKind::Path(ref maybe_qself, ref path) = ty.node {
-            // This is a path in the type namespace. Walk through scopes looking for it.
-            if let Some(def) =
-                    self.resolve_possibly_assoc_item(ty.id, maybe_qself.as_ref(), path, TypeNS) {
-                match def.base_def {
-                    Def::Mod(..) if def.depth == 0 => {
-                        self.session.span_err(path.span, "expected type, found module");
-                        self.record_def(ty.id, err_path_resolution());
-                    }
-                    _ => {
-                        // Write the result into the def map.
-                        debug!("(resolving type) writing resolution for `{}` (id {}) = {:?}",
-                               path_names_to_string(path, 0), ty.id, def);
-                        self.record_def(ty.id, def);
-                   }
-                }
-            } else {
-                self.record_def(ty.id, err_path_resolution());
-                // Keep reporting some errors even if they're ignored above.
-                let kind = if maybe_qself.is_some() { "associated type" } else { "type name" };
-                let is_invalid_self_type_name = {
-                    path.segments.len() > 0 &&
-                    maybe_qself.is_none() &&
-                    path.segments[0].identifier.name == keywords::SelfType.name()
-                };
-
-                if is_invalid_self_type_name {
-                    resolve_error(self, ty.span, ResolutionError::SelfUsedOutsideImplOrTrait);
-                } else {
-                    let type_name = path.segments.last().unwrap().identifier.name;
-                    let candidates = self.lookup_candidates(type_name, TypeNS, |def| {
-                        match def {
-                            Def::Trait(_) |
-                            Def::Enum(_) |
-                            Def::Struct(_) |
-                            Def::Union(_) |
-                            Def::TyAlias(_) => true,
-                            _ => false,
-                        }
-                    });
-
-                    let name = &path_names_to_string(path, 0);
-                    let error = ResolutionError::UseOfUndeclared(kind, name, candidates);
-                    resolve_error(self, ty.span, error);
-                }
-            }
-        }
-        // Resolve embedded types.
-        visit::walk_ty(self, ty);
-    }
-
     fn fresh_binding(&mut self,
                      ident: &SpannedIdent,
                      pat_id: NodeId,
@@ -2106,61 +1959,6 @@ impl<'a> Resolver<'a> {
         PathResolution::new(def)
     }
 
-    fn resolve_pattern_path<ExpectedFn>(&mut self,
-                                        pat_id: NodeId,
-                                        qself: Option<&QSelf>,
-                                        path: &Path,
-                                        namespace: Namespace,
-                                        expected_fn: ExpectedFn,
-                                        expected_what: &str)
-        where ExpectedFn: FnOnce(Def) -> bool
-    {
-        let resolution = if let Some(resolution) = self.resolve_possibly_assoc_item(pat_id,
-                                                                        qself, path, namespace) {
-            if resolution.depth == 0 {
-                if expected_fn(resolution.base_def) || resolution.base_def == Def::Err {
-                    resolution
-                } else {
-                    resolve_error(
-                        self,
-                        path.span,
-                        ResolutionError::PatPathUnexpected(expected_what,
-                                                           resolution.kind_name(), path)
-                    );
-                    err_path_resolution()
-                }
-            } else {
-                // Not fully resolved associated item `T::A::B` or `<T as Tr>::A::B`
-                // or `<T>::A::B`. If `B` should be resolved in value namespace then
-                // it needs to be added to the trait map.
-                if namespace == ValueNS {
-                    let item_name = path.segments.last().unwrap().identifier.name;
-                    let traits = self.get_traits_containing_item(item_name);
-                    self.trait_map.insert(pat_id, traits);
-                }
-                resolution
-            }
-        } else {
-            let error = ResolutionError::PatPathUnresolved(expected_what, path);
-            resolve_error(self, path.span, error);
-            err_path_resolution()
-        };
-
-        self.record_def(pat_id, resolution);
-    }
-
-    fn resolve_struct_path(&mut self, node_id: NodeId, path: &Path) {
-        // Resolution logic is equivalent for expressions and patterns,
-        // reuse `resolve_pattern_path` for both.
-        self.resolve_pattern_path(node_id, None, path, TypeNS, |def| {
-            match def {
-                Def::Struct(..) | Def::Union(..) | Def::Variant(..) |
-                Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => true,
-                _ => false,
-            }
-        }, "struct, variant or union type");
-    }
-
     fn resolve_pattern(&mut self,
                        pat: &Pat,
                        pat_src: PatternSource,
@@ -2184,8 +1982,7 @@ impl<'a> Resolver<'a> {
                             Def::VariantCtor(_, CtorKind::Const) |
                             Def::Const(..) if !always_binding => {
                                 // A unit struct/variant or constant pattern.
-                                let name = ident.node.name;
-                                self.record_use(name, ValueNS, binding.unwrap(), ident.span);
+                                self.record_use(ident.node, ValueNS, binding.unwrap(), ident.span);
                                 Some(PathResolution::new(def))
                             }
                             Def::StructCtor(..) | Def::VariantCtor(..) |
@@ -2217,28 +2014,15 @@ impl<'a> Resolver<'a> {
                 }
 
                 PatKind::TupleStruct(ref path, ..) => {
-                    self.resolve_pattern_path(pat.id, None, path, ValueNS, |def| {
-                        match def {
-                            Def::StructCtor(_, CtorKind::Fn) |
-                            Def::VariantCtor(_, CtorKind::Fn) => true,
-                            _ => false,
-                        }
-                    }, "tuple struct/variant");
+                    self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct);
                 }
 
                 PatKind::Path(ref qself, ref path) => {
-                    self.resolve_pattern_path(pat.id, qself.as_ref(), path, ValueNS, |def| {
-                        match def {
-                            Def::StructCtor(_, CtorKind::Const) |
-                            Def::VariantCtor(_, CtorKind::Const) |
-                            Def::Const(..) | Def::AssociatedConst(..) => true,
-                            _ => false,
-                        }
-                    }, "unit struct/variant or constant");
+                    self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat);
                 }
 
                 PatKind::Struct(ref path, ..) => {
-                    self.resolve_struct_path(pat.id, path);
+                    self.smart_resolve_path(pat.id, None, path, PathSource::Struct);
                 }
 
                 _ => {}
@@ -2249,34 +2033,245 @@ impl<'a> Resolver<'a> {
         visit::walk_pat(self, pat);
     }
 
-    /// Handles paths that may refer to associated items
-    fn resolve_possibly_assoc_item(&mut self,
+    // High-level and context dependent path resolution routine.
+    // Resolves the path and records the resolution into definition map.
+    // If resolution fails tries several techniques to find likely
+    // resolution candidates, suggest imports or other help, and report
+    // errors in user friendly way.
+    fn smart_resolve_path(&mut self,
+                          id: NodeId,
+                          qself: Option<&QSelf>,
+                          path: &Path,
+                          source: PathSource)
+                          -> PathResolution {
+        let segments = &path.segments.iter().map(|seg| seg.identifier).collect::<Vec<_>>();
+        self.smart_resolve_path_fragment(id, qself, segments, path.span, source)
+    }
+
+    fn smart_resolve_path_fragment(&mut self,
                                    id: NodeId,
-                                   maybe_qself: Option<&QSelf>,
-                                   path: &Path,
-                                   ns: Namespace)
-                                   -> Option<PathResolution> {
-        let ast::Path { ref segments, global, span } = *path;
-        let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect();
-        let scope = if global { PathScope::Global } else { PathScope::Lexical };
-
-        if let Some(qself) = maybe_qself {
+                                   qself: Option<&QSelf>,
+                                   path: &[Ident],
+                                   span: Span,
+                                   source: PathSource)
+                                   -> PathResolution {
+        let ns = source.namespace();
+        let is_expected = &|def| source.is_expected(def);
+
+        // Base error is amended with one short label and possibly some longer helps/notes.
+        let report_errors = |this: &mut Self, def: Option<Def>| {
+            // Make the base error.
+            let expected = source.descr_expected();
+            let path_str = names_to_string(path);
+            let code = source.error_code(def.is_some());
+            let base_msg = if let Some(def) = def {
+                format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str)
+            } else {
+                format!("unresolved {} `{}`", expected, path_str)
+            };
+            let mut err = this.session.struct_span_err_with_code(span, &base_msg, code);
+
+            // Emit special messages for unresolved `Self` and `self`.
+            if is_self_type(path, ns) {
+                __diagnostic_used!(E0411);
+                err.code("E0411".into());
+                err.span_label(span, &format!("`Self` is only available in traits and impls"));
+                return err;
+            }
+            if is_self_value(path, ns) {
+                __diagnostic_used!(E0424);
+                err.code("E0424".into());
+                err.span_label(span, &format!("`self` value is only available in \
+                                               methods with `self` parameter"));
+                return err;
+            }
+
+            // Try to lookup the name in more relaxed fashion for better error reporting.
+            let name = path.last().unwrap().name;
+            let candidates = this.lookup_import_candidates(name, ns, is_expected);
+            if !candidates.is_empty() {
+                // Report import candidates as help and proceed searching for labels.
+                show_candidates(&mut err, &candidates, def.is_some());
+            }
+            if path.len() == 1 && this.self_type_is_available() {
+                if let Some(candidate) = this.lookup_assoc_candidate(name, ns, is_expected) {
+                    let self_is_available = this.self_value_is_available(path[0].ctxt);
+                    match candidate {
+                        AssocSuggestion::Field => {
+                            err.span_label(span, &format!("did you mean `self.{}`?", path_str));
+                            if !self_is_available {
+                                err.span_label(span, &format!("`self` value is only available in \
+                                                               methods with `self` parameter"));
+                            }
+                        }
+                        AssocSuggestion::MethodWithSelf if self_is_available => {
+                            err.span_label(span, &format!("did you mean `self.{}(...)`?",
+                                                           path_str));
+                        }
+                        AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => {
+                            err.span_label(span, &format!("did you mean `Self::{}`?", path_str));
+                        }
+                    }
+                    return err;
+                }
+            }
+
+            // Try context dependent help if relaxed lookup didn't work.
+            if let Some(def) = def {
+                match (def, source) {
+                    (Def::Macro(..), _) => {
+                        err.span_label(span, &format!("did you mean `{}!(...)`?", path_str));
+                        return err;
+                    }
+                    (Def::TyAlias(..), PathSource::Trait) => {
+                        err.span_label(span, &format!("type aliases cannot be used for traits"));
+                        return err;
+                    }
+                    (Def::Mod(..), PathSource::Expr(Some(parent))) => match *parent {
+                        ExprKind::Field(_, ident) => {
+                            err.span_label(span, &format!("did you mean `{}::{}`?",
+                                                           path_str, ident.node));
+                            return err;
+                        }
+                        ExprKind::MethodCall(ident, ..) => {
+                            err.span_label(span, &format!("did you mean `{}::{}(...)`?",
+                                                           path_str, ident.node));
+                            return err;
+                        }
+                        _ => {}
+                    },
+                    _ if ns == ValueNS && is_struct_like(def) => {
+                        err.span_label(span, &format!("did you mean `{} {{ /* fields */ }}`?",
+                                                       path_str));
+                        return err;
+                    }
+                    _ => {}
+                }
+            }
+
+            // Try Levenshtein if nothing else worked.
+            if path.len() == 1 {
+                if let Some(candidate) = this.lookup_typo_candidate(name, ns, is_expected) {
+                    err.span_label(span, &format!("did you mean `{}`?", candidate));
+                    return err;
+                }
+            }
+
+            // Fallback labels.
+            if def.is_some() {
+                err.span_label(span, &format!("not a {}", expected));
+            } else {
+                err.span_label(span, &format!("no resolution found"));
+            }
+            err
+        };
+        let report_errors = |this: &mut Self, def: Option<Def>| {
+            report_errors(this, def).emit();
+            err_path_resolution()
+        };
+
+        let resolution = match self.resolve_qpath_anywhere(id, qself, path, ns, span,
+                                                           source.defer_to_typeck(),
+                                                           source.global_by_default()) {
+            Some(resolution) if resolution.depth == 0 => {
+                if is_expected(resolution.base_def) || resolution.base_def == Def::Err {
+                    resolution
+                } else {
+                    report_errors(self, Some(resolution.base_def))
+                }
+            }
+            Some(resolution) if source.defer_to_typeck() => {
+                // Not fully resolved associated item `T::A::B` or `<T as Tr>::A::B`
+                // or `<T>::A::B`. If `B` should be resolved in value namespace then
+                // it needs to be added to the trait map.
+                if ns == ValueNS {
+                    let item_name = path.last().unwrap().name;
+                    let traits = self.get_traits_containing_item(item_name, ns);
+                    self.trait_map.insert(id, traits);
+                }
+                resolution
+            }
+            _ => report_errors(self, None)
+        };
+
+        if let PathSource::TraitItem(..) = source {} else {
+            // Avoid recording definition of `A::B` in `<T as A>::B::C`.
+            self.record_def(id, resolution);
+        }
+        resolution
+    }
+
+    fn self_type_is_available(&mut self) -> bool {
+        let binding = self.resolve_ident_in_lexical_scope(keywords::SelfType.ident(), TypeNS, None);
+        if let Some(LexicalScopeBinding::Def(def)) = binding { def != Def::Err } else { false }
+    }
+
+    fn self_value_is_available(&mut self, ctxt: SyntaxContext) -> bool {
+        let ident = Ident { name: keywords::SelfValue.name(), ctxt: ctxt };
+        let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None);
+        if let Some(LexicalScopeBinding::Def(def)) = binding { def != Def::Err } else { false }
+    }
+
+    // Resolve in alternative namespaces if resolution in the primary namespace fails.
+    fn resolve_qpath_anywhere(&mut self,
+                              id: NodeId,
+                              qself: Option<&QSelf>,
+                              path: &[Ident],
+                              primary_ns: Namespace,
+                              span: Span,
+                              defer_to_typeck: bool,
+                              global_by_default: bool)
+                              -> Option<PathResolution> {
+        let mut fin_res = None;
+        // FIXME: can't resolve paths in macro namespace yet, macros are
+        // processed by the little special hack below.
+        for (i, ns) in [primary_ns, TypeNS, ValueNS, /*MacroNS*/].iter().cloned().enumerate() {
+            if i == 0 || ns != primary_ns {
+                match self.resolve_qpath(id, qself, path, ns, span, global_by_default) {
+                    // If defer_to_typeck, then resolution > no resolution,
+                    // otherwise full resolution > partial resolution > no resolution.
+                    Some(res) if res.depth == 0 || defer_to_typeck => return Some(res),
+                    res => if fin_res.is_none() { fin_res = res },
+                };
+            }
+        }
+        if primary_ns != MacroNS && path.len() == 1 &&
+                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))));
+        }
+        fin_res
+    }
+
+    /// Handles paths that may refer to associated items.
+    fn resolve_qpath(&mut self,
+                     id: NodeId,
+                     qself: Option<&QSelf>,
+                     path: &[Ident],
+                     ns: Namespace,
+                     span: Span,
+                     global_by_default: bool)
+                     -> Option<PathResolution> {
+        if let Some(qself) = qself {
             if qself.position == 0 {
                 // FIXME: Create some fake resolution that can't possibly be a type.
                 return Some(PathResolution {
-                    base_def: Def::Mod(self.definitions.local_def_id(ast::CRATE_NODE_ID)),
+                    base_def: Def::Mod(DefId::local(CRATE_DEF_INDEX)),
                     depth: path.len(),
                 });
             }
-            // Make sure the trait is valid.
-            self.resolve_trait_reference(&path[..qself.position], global, None, span);
+            // Make sure `A::B` in `<T as A>::B::C` is a trait item.
+            let ns = if qself.position + 1 == path.len() { ns } else { TypeNS };
+            let mut res = self.smart_resolve_path_fragment(id, None, &path[..qself.position + 1],
+                                                           span, PathSource::TraitItem(ns));
+            if res.base_def != Def::Err {
+                res.depth += path.len() - qself.position - 1;
+            }
+            return Some(res);
         }
 
-        let result = match self.resolve_path(&path, scope, Some(ns), Some(span)) {
-            PathResult::NonModule(path_res) => match path_res.base_def {
-                Def::Trait(..) if maybe_qself.is_some() => return None,
-                _ => path_res,
-            },
+        let result = match self.resolve_path(&path, Some(ns), Some(span)) {
+            PathResult::NonModule(path_res) => path_res,
             PathResult::Module(module) if !module.is_normal() => {
                 PathResolution::new(module.def().unwrap())
             }
@@ -2292,10 +2287,12 @@ impl<'a> Resolver<'a> {
             //
             // Such behavior is required for backward compatibility.
             // The same fallback is used when `a` resolves to nothing.
-            _ if self.primitive_type_table.primitive_types.contains_key(&path[0].name) => {
+            PathResult::Module(..) | PathResult::Failed(..)
+                    if (ns == TypeNS || path.len() > 1) &&
+                       self.primitive_type_table.primitive_types.contains_key(&path[0].name) => {
                 PathResolution {
                     base_def: Def::PrimTy(self.primitive_type_table.primitive_types[&path[0].name]),
-                    depth: segments.len() - 1,
+                    depth: path.len() - 1,
                 }
             }
             PathResult::Module(module) => PathResolution::new(module.def().unwrap()),
@@ -2303,15 +2300,16 @@ impl<'a> Resolver<'a> {
                 resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
                 err_path_resolution()
             }
-            _ => return None,
+            PathResult::Failed(..) => return None,
+            PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"),
         };
 
-        if path.len() == 1 || result.base_def == Def::Err {
+        if path.len() == 1 || global_by_default || result.base_def == Def::Err {
             return Some(result);
         }
 
         let unqualified_result = {
-            match self.resolve_path(&[*path.last().unwrap()], PathScope::Lexical, Some(ns), None) {
+            match self.resolve_path(&[*path.last().unwrap()], Some(ns), None) {
                 PathResult::NonModule(path_res) => path_res.base_def,
                 PathResult::Module(module) => module.def().unwrap(),
                 _ => return Some(result),
@@ -2327,32 +2325,24 @@ impl<'a> Resolver<'a> {
 
     fn resolve_path(&mut self,
                     path: &[Ident],
-                    scope: PathScope,
                     opt_ns: Option<Namespace>, // `None` indicates a module path
                     record_used: Option<Span>)
                     -> PathResult<'a> {
-        let (mut module, allow_self) = match scope {
-            PathScope::Lexical => (None, true),
-            PathScope::Import => (Some(self.graph_root), true),
-            PathScope::Global => (Some(self.graph_root), false),
-        };
-        let mut allow_super = allow_self;
+        let mut module = None;
+        let mut allow_super = true;
 
         for (i, &ident) in path.iter().enumerate() {
             let is_last = i == path.len() - 1;
             let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
 
-            if i == 0 && allow_self && ns == TypeNS && ident.name == keywords::SelfValue.name() {
-                module = Some(self.module_map[&self.current_module.normal_ancestor_id.unwrap()]);
-                continue
-            } else if i == 0 && allow_self && ns == TypeNS && ident.name == "$crate" {
-                module = Some(self.resolve_crate_var(ident.ctxt));
+            if i == 0 && ns == TypeNS && ident.name == keywords::SelfValue.name() {
+                module = Some(self.module_map[&self.current_module.normal_ancestor_id]);
                 continue
             } else if allow_super && ns == TypeNS && ident.name == keywords::Super.name() {
                 let current_module = if i == 0 { self.current_module } else { module.unwrap() };
-                let self_module = self.module_map[&current_module.normal_ancestor_id.unwrap()];
+                let self_module = self.module_map[&current_module.normal_ancestor_id];
                 if let Some(parent) = self_module.parent {
-                    module = Some(self.module_map[&parent.normal_ancestor_id.unwrap()]);
+                    module = Some(self.module_map[&parent.normal_ancestor_id]);
                     continue
                 } else {
                     let msg = "There are too many initial `super`s.".to_string();
@@ -2361,10 +2351,18 @@ impl<'a> Resolver<'a> {
             }
             allow_super = false;
 
+            if i == 0 && ns == TypeNS && ident.name == keywords::CrateRoot.name() {
+                module = Some(self.graph_root);
+                continue
+            } else if i == 0 && ns == TypeNS && ident.name == "$crate" {
+                module = Some(self.resolve_crate_var(ident.ctxt));
+                continue
+            }
+
             let binding = if let Some(module) = module {
-                self.resolve_name_in_module(module, ident.name, ns, false, record_used)
+                self.resolve_ident_in_module(module, ident, ns, false, record_used)
             } else if opt_ns == Some(MacroNS) {
-                self.resolve_lexical_macro_path_segment(ident.name, ns, record_used)
+                self.resolve_lexical_macro_path_segment(ident, ns, record_used)
             } else {
                 match self.resolve_ident_in_lexical_scope(ident, ns, record_used) {
                     Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
@@ -2404,13 +2402,13 @@ impl<'a> Resolver<'a> {
                             });
                         }
                     }
-                    let msg = if module.and_then(ModuleS::def) == self.graph_root.def() {
+                    let msg = if module.and_then(ModuleData::def) == self.graph_root.def() {
                         let is_mod = |def| match def { Def::Mod(..) => true, _ => false };
                         let mut candidates =
-                            self.lookup_candidates(ident.name, TypeNS, is_mod).candidates;
-                        candidates.sort_by_key(|path| (path.segments.len(), path.to_string()));
+                            self.lookup_import_candidates(ident.name, TypeNS, is_mod);
+                        candidates.sort_by_key(|c| (c.path.segments.len(), c.path.to_string()));
                         if let Some(candidate) = candidates.get(0) {
-                            format!("Did you mean `{}`?", candidate)
+                            format!("Did you mean `{}`?", candidate.path)
                         } else {
                             format!("Maybe a missing `extern crate {};`?", ident)
                         }
@@ -2424,11 +2422,11 @@ impl<'a> Resolver<'a> {
             }
         }
 
-        PathResult::Module(module.unwrap())
+        PathResult::Module(module.unwrap_or(self.graph_root))
     }
 
     // Resolve a local definition, potentially adjusting for closures.
-    fn adjust_local_def(&mut self, local_def: LocalDef, span: Span) -> Def {
+    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 &[_],
@@ -2436,7 +2434,7 @@ impl<'a> Resolver<'a> {
         let mut def = local_def.def;
         match def {
             Def::Upvar(..) => {
-                span_bug!(span, "unexpected {:?} in bindings", def)
+                span_bug!(record_used.unwrap_or(DUMMY_SP), "unexpected {:?} in bindings", def)
             }
             Def::Local(def_id) => {
                 for rib in ribs {
@@ -2459,28 +2457,32 @@ impl<'a> Resolver<'a> {
                                           .entry(function_id)
                                           .or_insert_with(|| vec![]);
                             let depth = vec.len();
-                            vec.push(Freevar {
-                                def: prev_def,
-                                span: span,
-                            });
-
                             def = Def::Upvar(def_id, depth, function_id);
-                            seen.insert(node_id, depth);
+
+                            if let Some(span) = record_used {
+                                vec.push(Freevar {
+                                    def: prev_def,
+                                    span: span,
+                                });
+                                seen.insert(node_id, depth);
+                            }
                         }
                         ItemRibKind | MethodRibKind(_) => {
                             // This was an attempt to access an upvar inside a
                             // named function item. This is not allowed, so we
                             // report an error.
-                            resolve_error(self,
-                                          span,
-                                          ResolutionError::CannotCaptureDynamicEnvironmentInFnItem);
+                            if let Some(span) = record_used {
+                                resolve_error(self, span,
+                                        ResolutionError::CannotCaptureDynamicEnvironmentInFnItem);
+                            }
                             return Def::Err;
                         }
                         ConstantItemRibKind => {
                             // Still doesn't deal with upvars
-                            resolve_error(self,
-                                          span,
-                                          ResolutionError::AttemptToUseNonConstantValueInConstant);
+                            if let Some(span) = record_used {
+                                resolve_error(self, span,
+                                        ResolutionError::AttemptToUseNonConstantValueInConstant);
+                            }
                             return Def::Err;
                         }
                     }
@@ -2496,15 +2498,18 @@ impl<'a> Resolver<'a> {
                         ItemRibKind => {
                             // This was an attempt to use a type parameter outside
                             // its scope.
-
-                            resolve_error(self,
-                                          span,
-                                          ResolutionError::TypeParametersFromOuterFunction);
+                            if let Some(span) = record_used {
+                                resolve_error(self, span,
+                                              ResolutionError::TypeParametersFromOuterFunction);
+                            }
                             return Def::Err;
                         }
                         ConstantItemRibKind => {
                             // see #9186
-                            resolve_error(self, span, ResolutionError::OuterTypeParameterContext);
+                            if let Some(span) = record_used {
+                                resolve_error(self, span,
+                                              ResolutionError::OuterTypeParameterContext);
+                            }
                             return Def::Err;
                         }
                     }
@@ -2540,7 +2545,13 @@ impl<'a> Resolver<'a> {
         result
     }
 
-    fn find_fallback_in_self_type(&mut self, name: Name) -> FallbackSuggestion {
+    fn lookup_assoc_candidate<FilterFn>(&mut self,
+                                        name: Name,
+                                        ns: Namespace,
+                                        filter_fn: FilterFn)
+                                        -> Option<AssocSuggestion>
+        where FilterFn: Fn(Def) -> bool
+    {
         fn extract_node_id(t: &Ty) -> Option<NodeId> {
             match t.node {
                 TyKind::Path(None, _) => Some(t.id),
@@ -2552,51 +2563,59 @@ impl<'a> Resolver<'a> {
             }
         }
 
-        if let Some(node_id) = self.current_self_type.as_ref().and_then(extract_node_id) {
-            // Look for a field with the same name in the current self_type.
-            if let Some(resolution) = self.def_map.get(&node_id) {
-                match resolution.base_def {
-                    Def::Struct(did) | Def::Union(did) if resolution.depth == 0 => {
-                        if let Some(field_names) = self.field_names.get(&did) {
-                            if field_names.iter().any(|&field_name| name == field_name) {
-                                return Field;
+        // Fields are generally expected in the same contexts as locals.
+        if filter_fn(Def::Local(DefId::local(CRATE_DEF_INDEX))) {
+            if let Some(node_id) = self.current_self_type.as_ref().and_then(extract_node_id) {
+                // Look for a field with the same name in the current self_type.
+                if let Some(resolution) = self.def_map.get(&node_id) {
+                    match resolution.base_def {
+                        Def::Struct(did) | Def::Union(did) if resolution.depth == 0 => {
+                            if let Some(field_names) = self.field_names.get(&did) {
+                                if field_names.iter().any(|&field_name| name == field_name) {
+                                    return Some(AssocSuggestion::Field);
+                                }
                             }
                         }
+                        _ => {}
                     }
-                    _ => {}
                 }
             }
         }
 
-        // Look for a method in the current trait.
-        if let Some((trait_did, ref trait_ref)) = self.current_trait_ref {
-            if let Some(&is_static_method) = self.trait_item_map.get(&(name, trait_did)) {
-                if is_static_method {
-                    return TraitMethod(path_names_to_string(&trait_ref.path, 0));
-                } else {
-                    return TraitItem;
+        // Look for associated items in the current trait.
+        if let Some((trait_did, _)) = self.current_trait_ref {
+            if let Some(&(def, has_self)) = self.trait_item_map.get(&(trait_did, name, ns)) {
+                if filter_fn(def) {
+                    return Some(if has_self {
+                        AssocSuggestion::MethodWithSelf
+                    } else {
+                        AssocSuggestion::AssocItem
+                    });
                 }
             }
         }
 
-        NoSuggestion
+        None
     }
 
-    fn find_best_match(&mut self, name: &str) -> SuggestionType {
-        if let Some(macro_name) = self.macro_names.iter().find(|&n| n == &name) {
-            return SuggestionType::Macro(format!("{}!", macro_name));
+    fn lookup_typo_candidate<FilterFn>(&mut self,
+                                       name: Name,
+                                       ns: Namespace,
+                                       filter_fn: FilterFn)
+                                       -> Option<Name>
+        where FilterFn: Fn(Def) -> bool
+    {
+        // FIXME: bindings in ribs provide quite modest set of candidates,
+        // extend it with other names in scope.
+        let names = self.ribs[ns].iter().rev().flat_map(|rib| {
+            rib.bindings.iter().filter_map(|(ident, def)| {
+                if filter_fn(*def) { Some(&ident.name) } else { None }
+            })
+        });
+        match find_best_match_for_name(names, &name.as_str(), None) {
+            Some(found) if found != name => Some(found),
+            _ => None,
         }
-
-        let names = self.ribs[ValueNS]
-                    .iter()
-                    .rev()
-                    .flat_map(|rib| rib.bindings.keys().map(|ident| &ident.name));
-
-        if let Some(found) = find_best_match_for_name(names, name, None) {
-            if found != name {
-                return SuggestionType::Function(found);
-            }
-        } SuggestionType::NotFound
     }
 
     fn resolve_labeled_block(&mut self, label: Option<SpannedIdent>, id: NodeId, block: &Block) {
@@ -2611,7 +2630,7 @@ impl<'a> Resolver<'a> {
         }
     }
 
-    fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
+    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.
 
@@ -2619,144 +2638,13 @@ impl<'a> Resolver<'a> {
 
         // Next, resolve the node.
         match expr.node {
-            ExprKind::Path(ref maybe_qself, ref path) => {
-                // This is a local path in the value namespace. Walk through
-                // scopes looking for it.
-                if let Some(path_res) = self.resolve_possibly_assoc_item(expr.id,
-                                                            maybe_qself.as_ref(), path, ValueNS) {
-                    // Check if struct variant
-                    let is_struct_variant = match path_res.base_def {
-                        Def::VariantCtor(_, CtorKind::Fictive) => true,
-                        _ => false,
-                    };
-                    if is_struct_variant {
-                        let path_name = path_names_to_string(path, 0);
-
-                        let mut err = resolve_struct_error(self,
-                                        expr.span,
-                                        ResolutionError::StructVariantUsedAsFunction(&path_name));
-
-                        let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?",
-                                          path_name);
-                        err.help(&msg);
-                        err.emit();
-                        self.record_def(expr.id, err_path_resolution());
-                    } else {
-                        // Write the result into the def map.
-                        debug!("(resolving expr) resolved `{}`",
-                               path_names_to_string(path, 0));
-
-                        // Partial resolutions will need the set of traits in scope,
-                        // so they can be completed during typeck.
-                        if path_res.depth != 0 {
-                            let method_name = path.segments.last().unwrap().identifier.name;
-                            let traits = self.get_traits_containing_item(method_name);
-                            self.trait_map.insert(expr.id, traits);
-                        }
-
-                        self.record_def(expr.id, path_res);
-                    }
-                } else {
-                    // Be helpful if the name refers to a struct
-                    let path_name = path_names_to_string(path, 0);
-                    let ast::Path { ref segments, global, .. } = *path;
-                    let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect();
-                    let scope = if global { PathScope::Global } else { PathScope::Lexical };
-                    let type_res = match self.resolve_path(&path, scope, Some(TypeNS), None) {
-                        PathResult::NonModule(type_res) => Some(type_res),
-                        _ => None,
-                    };
-
-                    self.record_def(expr.id, err_path_resolution());
-
-                    if let Some(Def::Struct(..)) = type_res.map(|r| r.base_def) {
-                        let error_variant =
-                            ResolutionError::StructVariantUsedAsFunction(&path_name);
-                        let mut err = resolve_struct_error(self, expr.span, error_variant);
-
-                        let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?",
-                                          path_name);
-
-                        err.help(&msg);
-                        err.emit();
-                    } else {
-                        // Keep reporting some errors even if they're ignored above.
-                        let mut method_scope = false;
-                        let mut is_static = false;
-                        self.ribs[ValueNS].iter().rev().all(|rib| {
-                            method_scope = match rib.kind {
-                                MethodRibKind(is_static_) => {
-                                    is_static = is_static_;
-                                    true
-                                }
-                                ItemRibKind | ConstantItemRibKind => false,
-                                _ => return true, // Keep advancing
-                            };
-                            false // Stop advancing
-                        });
-
-                        if method_scope && keywords::SelfValue.name() == &*path_name {
-                            let error = ResolutionError::SelfNotAvailableInStaticMethod;
-                            resolve_error(self, expr.span, error);
-                        } else {
-                            let fallback =
-                                self.find_fallback_in_self_type(path.last().unwrap().name);
-                            let (mut msg, is_field) = match fallback {
-                                NoSuggestion => {
-                                    // limit search to 5 to reduce the number
-                                    // of stupid suggestions
-                                    (match self.find_best_match(&path_name) {
-                                        SuggestionType::Macro(s) => {
-                                            format!("the macro `{}`", s)
-                                        }
-                                        SuggestionType::Function(s) => format!("`{}`", s),
-                                        SuggestionType::NotFound => "".to_string(),
-                                    }, false)
-                                }
-                                Field => {
-                                    (if is_static && method_scope {
-                                        "".to_string()
-                                    } else {
-                                        format!("`self.{}`", path_name)
-                                    }, true)
-                                }
-                                TraitItem => (format!("to call `self.{}`", path_name), false),
-                                TraitMethod(path_str) =>
-                                    (format!("to call `{}::{}`", path_str, path_name), false),
-                            };
-
-                            let mut context = UnresolvedNameContext::Other;
-                            let mut def = Def::Err;
-                            if !msg.is_empty() {
-                                msg = format!("did you mean {}?", msg);
-                            } else {
-                                // we display a help message if this is a module
-                                if let PathResult::Module(module) =
-                                        self.resolve_path(&path, scope, None, None) {
-                                    def = module.def().unwrap();
-                                    context = UnresolvedNameContext::PathIsMod(parent);
-                                }
-                            }
-
-                            let error = ResolutionError::UnresolvedName {
-                                path: &path_name,
-                                message: &msg,
-                                context: context,
-                                is_static_method: method_scope && is_static,
-                                is_field: is_field,
-                                def: def,
-                            };
-                            resolve_error(self, expr.span, error);
-                        }
-                    }
-                }
-
+            ExprKind::Path(ref qself, ref path) => {
+                self.smart_resolve_path(expr.id, qself.as_ref(), path, PathSource::Expr(parent));
                 visit::walk_expr(self, expr);
             }
 
             ExprKind::Struct(ref path, ..) => {
-                self.resolve_struct_path(expr.id, path);
-
+                self.smart_resolve_path(expr.id, None, path, PathSource::Struct);
                 visit::walk_expr(self, expr);
             }
 
@@ -2819,12 +2707,13 @@ impl<'a> Resolver<'a> {
                 self.ribs[ValueNS].pop();
             }
 
+            // Equivalent to `visit::walk_expr` + passing some context to children.
             ExprKind::Field(ref subexpression, _) => {
-                self.resolve_expr(subexpression, Some(expr));
+                self.resolve_expr(subexpression, Some(&expr.node));
             }
             ExprKind::MethodCall(_, ref types, ref arguments) => {
                 let mut arguments = arguments.iter();
-                self.resolve_expr(arguments.next().unwrap(), Some(expr));
+                self.resolve_expr(arguments.next().unwrap(), Some(&expr.node));
                 for argument in arguments {
                     self.resolve_expr(argument, None);
                 }
@@ -2832,6 +2721,12 @@ impl<'a> Resolver<'a> {
                     self.visit_ty(ty);
                 }
             }
+            ExprKind::Call(ref callee, ref arguments) => {
+                self.resolve_expr(callee, Some(&expr.node));
+                for argument in arguments {
+                    self.resolve_expr(argument, None);
+                }
+            }
 
             _ => {
                 visit::walk_expr(self, expr);
@@ -2846,13 +2741,13 @@ impl<'a> Resolver<'a> {
                 // field, we need to add any trait methods we find that match
                 // the field name so that we can do some nice error reporting
                 // later on in typeck.
-                let traits = self.get_traits_containing_item(name.node.name);
+                let traits = self.get_traits_containing_item(name.node.name, ValueNS);
                 self.trait_map.insert(expr.id, traits);
             }
             ExprKind::MethodCall(name, ..) => {
                 debug!("(recording candidate traits for expr) recording traits for {}",
                        expr.id);
-                let traits = self.get_traits_containing_item(name.node.name);
+                let traits = self.get_traits_containing_item(name.node.name, ValueNS);
                 self.trait_map.insert(expr.id, traits);
             }
             _ => {
@@ -2861,75 +2756,68 @@ impl<'a> Resolver<'a> {
         }
     }
 
-    fn get_traits_containing_item(&mut self, name: Name) -> Vec<TraitCandidate> {
+    fn get_traits_containing_item(&mut self, name: Name, ns: Namespace) -> Vec<TraitCandidate> {
         debug!("(getting traits containing item) looking for '{}'", name);
 
-        fn add_trait_info(found_traits: &mut Vec<TraitCandidate>,
-                          trait_def_id: DefId,
-                          import_id: Option<NodeId>,
-                          name: Name) {
-            debug!("(adding trait info) found trait {:?} for method '{}'",
-                   trait_def_id,
-                   name);
-            found_traits.push(TraitCandidate {
-                def_id: trait_def_id,
-                import_id: import_id,
-            });
-        }
-
         let mut found_traits = Vec::new();
         // Look for the current trait.
         if let Some((trait_def_id, _)) = self.current_trait_ref {
-            if self.trait_item_map.contains_key(&(name, trait_def_id)) {
-                add_trait_info(&mut found_traits, trait_def_id, None, name);
+            if self.trait_item_map.contains_key(&(trait_def_id, name, ns)) {
+                found_traits.push(TraitCandidate { def_id: trait_def_id, import_id: None });
             }
         }
 
         let mut search_module = self.current_module;
         loop {
-            // Look for trait children.
-            let mut search_in_module = |this: &mut Self, module: Module<'a>| {
-                let mut traits = module.traits.borrow_mut();
-                if traits.is_none() {
-                    let mut collected_traits = Vec::new();
-                    module.for_each_child(|name, ns, binding| {
-                        if ns != TypeNS { return }
-                        if let Def::Trait(_) = binding.def() {
-                            collected_traits.push((name, binding));
-                        }
-                    });
-                    *traits = Some(collected_traits.into_boxed_slice());
-                }
-
-                for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
-                    let trait_def_id = binding.def().def_id();
-                    if this.trait_item_map.contains_key(&(name, trait_def_id)) {
-                        let mut import_id = None;
-                        if let NameBindingKind::Import { directive, .. } = binding.kind {
-                            let id = directive.id;
-                            this.maybe_unused_trait_imports.insert(id);
-                            this.add_to_glob_map(id, trait_name);
-                            import_id = Some(id);
-                        }
-                        add_trait_info(&mut found_traits, trait_def_id, import_id, name);
-                    }
-                }
-            };
-            search_in_module(self, search_module);
+            self.get_traits_in_module_containing_item(name, ns, search_module, &mut found_traits);
+            match search_module.kind {
+                ModuleKind::Block(..) => search_module = search_module.parent.unwrap(),
+                _ => break,
+            }
+        }
 
-            if let ModuleKind::Block(..) = search_module.kind {
-                search_module = search_module.parent.unwrap();
-            } else {
-                if !search_module.no_implicit_prelude {
-                    self.prelude.map(|prelude| search_in_module(self, prelude));
-                }
-                break;
+        if let Some(prelude) = self.prelude {
+            if !search_module.no_implicit_prelude {
+                self.get_traits_in_module_containing_item(name, ns, prelude, &mut found_traits);
             }
         }
 
         found_traits
     }
 
+    fn get_traits_in_module_containing_item(&mut self,
+                                            name: Name,
+                                            ns: Namespace,
+                                            module: Module,
+                                            found_traits: &mut Vec<TraitCandidate>) {
+        let mut traits = module.traits.borrow_mut();
+        if traits.is_none() {
+            let mut collected_traits = Vec::new();
+            module.for_each_child(|name, ns, binding| {
+                if ns != TypeNS { return }
+                if let Def::Trait(_) = binding.def() {
+                    collected_traits.push((name, binding));
+                }
+            });
+            *traits = Some(collected_traits.into_boxed_slice());
+        }
+
+        for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
+            let trait_def_id = binding.def().def_id();
+            if self.trait_item_map.contains_key(&(trait_def_id, name, ns)) {
+                let import_id = match binding.kind {
+                    NameBindingKind::Import { directive, .. } => {
+                        self.maybe_unused_trait_imports.insert(directive.id);
+                        self.add_to_glob_map(directive.id, trait_name);
+                        Some(directive.id)
+                    }
+                    _ => None,
+                };
+                found_traits.push(TraitCandidate { def_id: trait_def_id, import_id: import_id });
+            }
+        }
+    }
+
     /// When name resolution fails, this method can be used to look up candidate
     /// entities with the expected name. It allows filtering them using the
     /// supplied predicate (which should be used to only accept the types of
@@ -2937,14 +2825,16 @@ impl<'a> Resolver<'a> {
     ///
     /// NOTE: The method does not look into imports, but this is not a problem,
     /// since we report the definitions (thus, the de-aliased imports).
-    fn lookup_candidates<FilterFn>(&mut self,
-                                   lookup_name: Name,
-                                   namespace: Namespace,
-                                   filter_fn: FilterFn) -> SuggestedCandidates
-        where FilterFn: Fn(Def) -> bool {
-
-        let mut lookup_results = Vec::new();
+    fn lookup_import_candidates<FilterFn>(&mut self,
+                                          lookup_name: Name,
+                                          namespace: Namespace,
+                                          filter_fn: FilterFn)
+                                          -> Vec<ImportSuggestion>
+        where FilterFn: Fn(Def) -> bool
+    {
+        let mut candidates = Vec::new();
         let mut worklist = Vec::new();
+        let mut seen_modules = FxHashSet();
         worklist.push((self.graph_root, Vec::new(), false));
 
         while let Some((in_module,
@@ -2952,27 +2842,22 @@ impl<'a> Resolver<'a> {
                         in_module_is_extern)) = worklist.pop() {
             self.populate_module_if_necessary(in_module);
 
-            in_module.for_each_child(|name, ns, name_binding| {
+            in_module.for_each_child(|ident, ns, name_binding| {
 
                 // avoid imports entirely
                 if name_binding.is_import() && !name_binding.is_extern_crate() { return; }
+                // avoid non-importable candidates as well
+                if !name_binding.is_importable() { return; }
 
                 // collect results based on the filter function
-                if name == lookup_name && ns == namespace {
+                if ident.name == lookup_name && ns == namespace {
                     if filter_fn(name_binding.def()) {
                         // create the path
-                        let ident = Ident::with_empty_ctxt(name);
-                        let params = PathParameters::none();
-                        let segment = PathSegment {
-                            identifier: ident,
-                            parameters: params,
-                        };
                         let span = name_binding.span;
                         let mut segms = path_segments.clone();
-                        segms.push(segment);
+                        segms.push(ident.into());
                         let path = Path {
                             span: span,
-                            global: false,
                             segments: segms,
                         };
                         // the entity is accessible in the following cases:
@@ -2983,7 +2868,7 @@ impl<'a> Resolver<'a> {
                         // declared as public (due to pruning, we don't explore
                         // outside crate private modules => no need to check this)
                         if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
-                            lookup_results.push(path);
+                            candidates.push(ImportSuggestion { path: path });
                         }
                     }
                 }
@@ -2992,15 +2877,12 @@ impl<'a> Resolver<'a> {
                 if let Some(module) = name_binding.module() {
                     // form the path
                     let mut path_segments = path_segments.clone();
-                    path_segments.push(PathSegment {
-                        identifier: Ident::with_empty_ctxt(name),
-                        parameters: PathParameters::none(),
-                    });
+                    path_segments.push(ident.into());
 
                     if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
                         // add the module to the lookup
                         let is_extern = in_module_is_extern || name_binding.is_extern_crate();
-                        if !worklist.iter().any(|&(m, ..)| m.def() == module.def()) {
+                        if seen_modules.insert(module.def_id().unwrap()) {
                             worklist.push((module, path_segments, is_extern));
                         }
                     }
@@ -3008,82 +2890,87 @@ impl<'a> Resolver<'a> {
             })
         }
 
-        SuggestedCandidates {
-            name: lookup_name.as_str().to_string(),
-            candidates: lookup_results,
-        }
+        candidates
     }
 
     fn record_def(&mut self, node_id: NodeId, resolution: PathResolution) {
         debug!("(recording def) recording {:?} for {}", resolution, node_id);
+        assert!(resolution.depth == 0 || resolution.base_def != Def::Err);
         if let Some(prev_res) = self.def_map.insert(node_id, resolution) {
             panic!("path resolved multiple times ({:?} before, {:?} now)", prev_res, resolution);
         }
     }
 
     fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility {
-        let (segments, span, id) = match *vis {
-            ast::Visibility::Public => return ty::Visibility::Public,
-            ast::Visibility::Crate(_) => return ty::Visibility::Restricted(ast::CRATE_NODE_ID),
-            ast::Visibility::Restricted { ref path, id } => (&path.segments, path.span, id),
+        match *vis {
+            ast::Visibility::Public => ty::Visibility::Public,
+            ast::Visibility::Crate(..) => ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)),
             ast::Visibility::Inherited => {
-                return ty::Visibility::Restricted(self.current_module.normal_ancestor_id.unwrap());
-            }
-        };
-
-        let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect();
-        let mut path_resolution = err_path_resolution();
-        let vis = match self.resolve_path(&path, PathScope::Import, None, Some(span)) {
-            PathResult::Module(module) => {
-                path_resolution = PathResolution::new(module.def().unwrap());
-                ty::Visibility::Restricted(module.normal_ancestor_id.unwrap())
+                ty::Visibility::Restricted(self.current_module.normal_ancestor_id)
             }
-            PathResult::Failed(msg, _) => {
-                self.session.span_err(span, &format!("failed to resolve module path. {}", msg));
-                ty::Visibility::Public
+            ast::Visibility::Restricted { ref path, id } => {
+                let def = self.smart_resolve_path(id, None, path, PathSource::Visibility).base_def;
+                if def == Def::Err {
+                    ty::Visibility::Public
+                } else {
+                    let vis = ty::Visibility::Restricted(def.def_id());
+                    if self.is_accessible(vis) {
+                        vis
+                    } else {
+                        self.session.span_err(path.span, "visibilities can only be restricted \
+                                                          to ancestor modules");
+                        ty::Visibility::Public
+                    }
+                }
             }
-            _ => ty::Visibility::Public,
-        };
-        self.def_map.insert(id, path_resolution);
-        if !self.is_accessible(vis) {
-            let msg = format!("visibilities can only be restricted to ancestor modules");
-            self.session.span_err(span, &msg);
         }
-        vis
     }
 
     fn is_accessible(&self, vis: ty::Visibility) -> bool {
-        vis.is_accessible_from(self.current_module.normal_ancestor_id.unwrap(), self)
+        vis.is_accessible_from(self.current_module.normal_ancestor_id, self)
     }
 
     fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
-        vis.is_accessible_from(module.normal_ancestor_id.unwrap(), self)
+        vis.is_accessible_from(module.normal_ancestor_id, self)
     }
 
     fn report_errors(&mut self) {
         self.report_shadowing_errors();
         let mut reported_spans = FxHashSet();
 
-        for &AmbiguityError { span, name, b1, b2, lexical } in &self.ambiguity_errors {
+        for &AmbiguityError { span, name, b1, b2, lexical, legacy } in &self.ambiguity_errors {
             if !reported_spans.insert(span) { continue }
             let participle = |binding: &NameBinding| {
                 if binding.is_import() { "imported" } else { "defined" }
             };
             let msg1 = format!("`{}` could resolve to the name {} here", name, participle(b1));
             let msg2 = format!("`{}` could also resolve to the name {} here", name, participle(b2));
-            self.session.struct_span_err(span, &format!("`{}` is ambiguous", name))
-                .span_note(b1.span, &msg1)
-                .span_note(b2.span, &msg2)
-                .note(&if !lexical && b1.is_glob_import() {
-                    format!("consider adding an explicit import of `{}` to disambiguate", name)
-                } else if let Def::Macro(..) = b1.def() {
-                    format!("macro-expanded {} do not shadow",
-                            if b1.is_import() { "macro imports" } else { "macros" })
-                } else {
-                    format!("macro-expanded {} do not shadow when used in a macro invocation path",
-                            if b1.is_import() { "imports" } else { "items" })
-                })
-                .emit();
+            let note = if !lexical && b1.is_glob_import() {
+                format!("consider adding an explicit import of `{}` to disambiguate", name)
+            } else if let Def::Macro(..) = b1.def() {
+                format!("macro-expanded {} do not shadow",
+                        if b1.is_import() { "macro imports" } else { "macros" })
+            } else {
+                format!("macro-expanded {} do not shadow when used in a macro invocation path",
+                        if b1.is_import() { "imports" } else { "items" })
+            };
+            if legacy {
+                let id = match b2.kind {
+                    NameBindingKind::Import { directive, .. } => directive.id,
+                    _ => unreachable!(),
+                };
+                let mut span = MultiSpan::from_span(span);
+                span.push_span_label(b1.span, msg1);
+                span.push_span_label(b2.span, msg2);
+                let msg = format!("`{}` is ambiguous", name);
+                self.session.add_lint(lint::builtin::LEGACY_IMPORTS, id, span, msg);
+            } else {
+                self.session.struct_span_err(span, &format!("`{}` is ambiguous", name))
+                    .span_note(b1.span, &msg1)
+                    .span_note(b2.span, &msg2)
+                    .note(&note)
+                    .emit();
+            }
         }
 
         for &PrivacyError(span, name, binding) in &self.privacy_errors {
@@ -3123,13 +3010,13 @@ impl<'a> Resolver<'a> {
 
     fn report_conflict(&mut self,
                        parent: Module,
-                       name: Name,
+                       ident: Ident,
                        ns: Namespace,
                        binding: &NameBinding,
                        old_binding: &NameBinding) {
         // Error on the second of two conflicting names
         if old_binding.span.lo > binding.span.lo {
-            return self.report_conflict(parent, name, ns, old_binding, binding);
+            return self.report_conflict(parent, ident, ns, old_binding, binding);
         }
 
         let container = match parent.kind {
@@ -3144,7 +3031,7 @@ impl<'a> Resolver<'a> {
             false => ("defined", "definition"),
         };
 
-        let span = binding.span;
+        let (name, span) = (ident.name, binding.span);
 
         if let Some(s) = self.name_already_seen.get(&name) {
             if s == &span {
@@ -3166,40 +3053,19 @@ impl<'a> Resolver<'a> {
         };
 
         let mut err = match (old_binding.is_extern_crate(), binding.is_extern_crate()) {
-            (true, true) => {
-                let mut e = struct_span_err!(self.session, span, E0259, "{}", msg);
-                e.span_label(span, &format!("`{}` was already imported", name));
-                e
-            },
-            (true, _) | (_, true) if binding.is_import() && old_binding.is_import() => {
-                let mut e = struct_span_err!(self.session, span, E0254, "{}", msg);
-                e.span_label(span, &"already imported");
-                e
-            },
-            (true, _) | (_, true) => {
-                let mut e = struct_span_err!(self.session, span, E0260, "{}", msg);
-                e.span_label(span, &format!("`{}` already imported", name));
-                e
+            (true, true) => struct_span_err!(self.session, span, E0259, "{}", msg),
+            (true, _) | (_, true) => match binding.is_import() && old_binding.is_import() {
+                true => struct_span_err!(self.session, span, E0254, "{}", msg),
+                false => struct_span_err!(self.session, span, E0260, "{}", msg),
             },
             _ => match (old_binding.is_import(), binding.is_import()) {
-                (false, false) => {
-                    let mut e = struct_span_err!(self.session, span, E0428, "{}", msg);
-                    e.span_label(span, &format!("already defined"));
-                    e
-                },
-                (true, true) => {
-                    let mut e = struct_span_err!(self.session, span, E0252, "{}", msg);
-                    e.span_label(span, &format!("already imported"));
-                    e
-                },
-                _ => {
-                    let mut e = struct_span_err!(self.session, span, E0255, "{}", msg);
-                    e.span_label(span, &format!("`{}` was already imported", name));
-                    e
-                }
+                (false, false) => struct_span_err!(self.session, span, E0428, "{}", msg),
+                (true, true) => struct_span_err!(self.session, span, E0252, "{}", msg),
+                _ => struct_span_err!(self.session, span, E0255, "{}", msg),
             },
         };
 
+        err.span_label(span, &format!("`{}` already {}", name, participle));
         if old_binding.span != syntax_pos::DUMMY_SP {
             err.span_label(old_binding.span, &format!("previous {} of `{}` here", noun, name));
         }
@@ -3208,80 +3074,72 @@ impl<'a> Resolver<'a> {
     }
 }
 
-fn names_to_string(names: &[Ident]) -> String {
-    let mut first = true;
+fn is_struct_like(def: Def) -> bool {
+    match def {
+        Def::VariantCtor(_, CtorKind::Fictive) => true,
+        _ => PathSource::Struct.is_expected(def),
+    }
+}
+
+fn is_self_type(path: &[Ident], namespace: Namespace) -> bool {
+    namespace == TypeNS && path.len() == 1 && path[0].name == keywords::SelfType.name()
+}
+
+fn is_self_value(path: &[Ident], namespace: Namespace) -> bool {
+    namespace == ValueNS && path.len() == 1 && path[0].name == keywords::SelfValue.name()
+}
+
+fn names_to_string(idents: &[Ident]) -> String {
     let mut result = String::new();
-    for ident in names {
-        if first {
-            first = false
-        } else {
-            result.push_str("::")
+    for (i, ident) in idents.iter().filter(|i| i.name != keywords::CrateRoot.name()).enumerate() {
+        if i > 0 {
+            result.push_str("::");
         }
         result.push_str(&ident.name.as_str());
     }
     result
 }
 
-fn path_names_to_string(path: &Path, depth: usize) -> String {
-    let names: Vec<_> =
-        path.segments[..path.segments.len() - depth].iter().map(|seg| seg.identifier).collect();
-    names_to_string(&names)
+fn path_names_to_string(path: &Path) -> String {
+    names_to_string(&path.segments.iter().map(|seg| seg.identifier).collect::<Vec<_>>())
 }
 
 /// When an entity with a given name is not available in scope, we search for
 /// entities with that name in all crates. This method allows outputting the
 /// results of this search in a programmer-friendly way
 fn show_candidates(session: &mut DiagnosticBuilder,
-                   candidates: &SuggestedCandidates) {
-
-    let paths = &candidates.candidates;
-
-    if paths.len() > 0 {
-        // don't show more than MAX_CANDIDATES results, so
-        // we're consistent with the trait suggestions
-        const MAX_CANDIDATES: usize = 5;
-
-        // we want consistent results across executions, but candidates are produced
-        // by iterating through a hash map, so make sure they are ordered:
-        let mut path_strings: Vec<_> = paths.into_iter()
-                                            .map(|p| path_names_to_string(&p, 0))
-                                            .collect();
-        path_strings.sort();
-
-        // behave differently based on how many candidates we have:
-        if !paths.is_empty() {
-            if paths.len() == 1 {
-                session.help(
-                    &format!("you can import it into scope: `use {};`.",
-                        &path_strings[0]),
-                );
-            } else {
-                session.help("you can import several candidates \
-                    into scope (`use ...;`):");
-                let count = path_strings.len() as isize - MAX_CANDIDATES as isize + 1;
-
-                for (idx, path_string) in path_strings.iter().enumerate() {
-                    if idx == MAX_CANDIDATES - 1 && count > 1 {
-                        session.help(
-                            &format!("  and {} other candidates", count).to_string(),
-                        );
-                        break;
-                    } else {
-                        session.help(
-                            &format!("  `{}`", path_string).to_string(),
-                        );
-                    }
-                }
-            }
-        }
-    } else {
-        // nothing found:
-        session.help(
-            &format!("no candidates by the name of `{}` found in your \
-            project; maybe you misspelled the name or forgot to import \
-            an external crate?", candidates.name.to_string()),
-        );
+                   candidates: &[ImportSuggestion],
+                   better: bool) {
+    // don't show more than MAX_CANDIDATES results, so
+    // we're consistent with the trait suggestions
+    const MAX_CANDIDATES: usize = 5;
+
+    // we want consistent results across executions, but candidates are produced
+    // by iterating through a hash map, so make sure they are ordered:
+    let mut path_strings: Vec<_> =
+        candidates.into_iter().map(|c| path_names_to_string(&c.path)).collect();
+    path_strings.sort();
+
+    let better = if better { "better " } else { "" };
+    let msg_diff = match path_strings.len() {
+        1 => " is found in another module, you can import it",
+        _ => "s are found in other modules, you can import them",
     };
+    session.help(&format!("possible {}candidate{} into scope:", better, msg_diff));
+
+    let count = path_strings.len() as isize - MAX_CANDIDATES as isize + 1;
+    for (idx, path_string) in path_strings.iter().enumerate() {
+        if idx == MAX_CANDIDATES - 1 && count > 1 {
+            session.help(
+                &format!("  and {} other candidates", count).to_string(),
+            );
+            break;
+        } else {
+            session.help(
+                &format!("  `use {};`", path_string).to_string(),
+            );
+        }
+    }
 }
 
 /// A somewhat inefficient routine to obtain the name of a module.
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 6c02967672d..44cc580ad12 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use {AmbiguityError, Resolver, ResolutionError, resolve_error};
-use {Module, ModuleKind, NameBinding, NameBindingKind, PathScope, PathResult};
+use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult};
 use Namespace::{self, MacroNS};
 use build_reduced_graph::BuildReducedGraphVisitor;
 use resolve_imports::ImportResolver;
@@ -19,16 +19,18 @@ use rustc::hir::map::{self, DefCollector};
 use rustc::ty;
 use std::cell::Cell;
 use std::rc::Rc;
-use syntax::ast::{self, Name};
+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, SyntaxExtension};
-use syntax::ext::expand::Expansion;
+use syntax::ext::base::{NormalTT, Resolver as SyntaxResolver, SyntaxExtension};
+use syntax::ext::expand::{Expansion, mark_tts};
 use syntax::ext::hygiene::Mark;
 use syntax::ext::tt::macro_rules;
 use syntax::feature_gate::{emit_feature_err, GateIssue};
 use syntax::fold::Folder;
 use syntax::ptr::P;
+use syntax::symbol::keywords;
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax::visit::Visitor;
 use syntax_pos::{Span, DUMMY_SP};
@@ -86,7 +88,7 @@ impl<'a> base::Resolver for Resolver<'a> {
 
     fn get_module_scope(&mut self, id: ast::NodeId) -> Mark {
         let mark = Mark::fresh();
-        let module = self.module_map[&id];
+        let module = self.module_map[&self.definitions.local_def_id(id)];
         self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData {
             module: Cell::new(module),
             def_index: module.def_id().unwrap().index,
@@ -104,15 +106,13 @@ impl<'a> base::Resolver for Resolver<'a> {
             fn fold_path(&mut self, mut path: ast::Path) -> ast::Path {
                 let ident = path.segments[0].identifier;
                 if ident.name == "$crate" {
-                    path.global = true;
+                    path.segments[0].identifier.name = keywords::CrateRoot.name();
                     let module = self.0.resolve_crate_var(ident.ctxt);
-                    if module.is_local() {
-                        path.segments.remove(0);
-                    } else {
-                        path.segments[0].identifier = match module.kind {
-                            ModuleKind::Def(_, name) => ast::Ident::with_empty_ctxt(name),
+                    if !module.is_local() {
+                        path.segments.insert(1, match module.kind {
+                            ModuleKind::Def(_, name) => ast::Ident::with_empty_ctxt(name).into(),
                             _ => unreachable!(),
-                        };
+                        })
                     }
                 }
                 path
@@ -122,6 +122,10 @@ impl<'a> base::Resolver for Resolver<'a> {
         EliminateCrateVar(self).fold_item(item).expect_one("")
     }
 
+    fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool {
+        self.whitelisted_legacy_custom_derives.contains(&name)
+    }
+
     fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
         let invocation = self.invocations[&mark];
         self.collect_def_ids(invocation, expansion);
@@ -138,34 +142,6 @@ impl<'a> base::Resolver for Resolver<'a> {
         invocation.expansion.set(visitor.legacy_scope);
     }
 
-    fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef, export: bool) {
-        if def.ident.name == "macro_rules" {
-            self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`");
-        }
-
-        let invocation = self.invocations[&scope];
-        let binding = self.arenas.alloc_legacy_binding(LegacyBinding {
-            parent: Cell::new(invocation.legacy_scope.get()),
-            name: def.ident.name,
-            ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)),
-            span: def.span,
-        });
-        invocation.legacy_scope.set(LegacyScope::Binding(binding));
-        self.macro_names.insert(def.ident.name);
-
-        if export {
-            def.id = self.next_node_id();
-            DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| {
-                collector.visit_macro_def(&def)
-            });
-            self.macro_exports.push(Export {
-                name: def.ident.name,
-                def: Def::Macro(self.definitions.local_def_id(def.id)),
-            });
-            self.exported_macros.push(def);
-        }
-    }
-
     fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
         if let NormalTT(..) = *ext {
             self.macro_names.insert(ident.name);
@@ -178,7 +154,7 @@ impl<'a> base::Resolver for Resolver<'a> {
         let binding = self.arenas.alloc_name_binding(NameBinding {
             kind: NameBindingKind::Def(Def::Macro(def_id)),
             span: DUMMY_SP,
-            vis: ty::Visibility::PrivateExternal,
+            vis: ty::Visibility::Invisible,
             expansion: Mark::root(),
         });
         self.builtin_macros.insert(ident.name, binding);
@@ -209,21 +185,20 @@ impl<'a> base::Resolver for Resolver<'a> {
 
     fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
                      -> Result<Rc<SyntaxExtension>, Determinacy> {
-        let ast::Path { ref segments, global, span } = *path;
-        if segments.iter().any(|segment| !segment.parameters.is_empty()) {
+        let ast::Path { ref segments, span } = *path;
+        if segments.iter().any(|segment| segment.parameters.is_some()) {
             let kind =
-                if segments.last().unwrap().parameters.is_empty() { "module" } else { "macro" };
+                if segments.last().unwrap().parameters.is_some() { "macro" } else { "module" };
             let msg = format!("type parameters are not allowed on {}s", kind);
             self.session.span_err(path.span, &msg);
             return Err(Determinacy::Determined);
         }
 
-        let path_scope = if global { PathScope::Global } else { PathScope::Lexical };
         let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect();
         let invocation = self.invocations[&scope];
         self.current_module = invocation.module.get();
 
-        if path.len() > 1 || global {
+        if path.len() > 1 {
             if !self.use_extern_macros {
                 let msg = "non-ident macro paths are experimental";
                 let feature = "use_extern_macros";
@@ -231,14 +206,17 @@ impl<'a> base::Resolver for Resolver<'a> {
                 return Err(Determinacy::Determined);
             }
 
-            let ext = match self.resolve_path(&path, path_scope, Some(MacroNS), None) {
-                PathResult::NonModule(path_res) => Ok(self.get_macro(path_res.base_def)),
+            let ext = match self.resolve_path(&path, Some(MacroNS), None) {
+                PathResult::NonModule(path_res) => match path_res.base_def {
+                    Def::Err => Err(Determinacy::Determined),
+                    def @ _ => Ok(self.get_macro(def)),
+                },
                 PathResult::Module(..) => unreachable!(),
                 PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
                 _ => Err(Determinacy::Determined),
             };
             self.current_module.macro_resolutions.borrow_mut()
-                .push((path.into_boxed_slice(), path_scope, span));
+                .push((path.into_boxed_slice(), span));
             return ext;
         }
 
@@ -246,7 +224,7 @@ impl<'a> base::Resolver for Resolver<'a> {
         let result = match self.resolve_legacy_scope(&invocation.legacy_scope, name, false) {
             Some(MacroBinding::Legacy(binding)) => Ok(binding.ext.clone()),
             Some(MacroBinding::Modern(binding)) => Ok(binding.get_macro(self)),
-            None => match self.resolve_lexical_macro_path_segment(name, MacroNS, None) {
+            None => match self.resolve_lexical_macro_path_segment(path[0], MacroNS, None) {
                 Ok(binding) => Ok(binding.get_macro(self)),
                 Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined),
                 _ => {
@@ -260,7 +238,7 @@ impl<'a> base::Resolver for Resolver<'a> {
         };
 
         if self.use_extern_macros {
-            self.current_module.legacy_macro_resolutions.borrow_mut().push((scope, name, span));
+            self.current_module.legacy_macro_resolutions.borrow_mut().push((scope, path[0], span));
         }
         result
     }
@@ -269,7 +247,7 @@ impl<'a> base::Resolver for Resolver<'a> {
 impl<'a> Resolver<'a> {
     // Resolve the initial segment of a non-global macro path (e.g. `foo` in `foo::bar!();`)
     pub fn resolve_lexical_macro_path_segment(&mut self,
-                                              name: Name,
+                                              ident: Ident,
                                               ns: Namespace,
                                               record_used: Option<Span>)
                                               -> Result<&'a NameBinding<'a>, Determinacy> {
@@ -278,7 +256,7 @@ impl<'a> Resolver<'a> {
         loop {
             // Since expanded macros may not shadow the lexical scope (enforced below),
             // we can ignore unresolved invocations (indicated by the penultimate argument).
-            match self.resolve_name_in_module(module, name, ns, true, record_used) {
+            match self.resolve_ident_in_module(module, ident, ns, true, record_used) {
                 Ok(binding) => {
                     let span = match record_used {
                         Some(span) => span,
@@ -286,8 +264,10 @@ impl<'a> Resolver<'a> {
                     };
                     match potential_expanded_shadower {
                         Some(shadower) if shadower.def() != binding.def() => {
+                            let name = ident.name;
                             self.ambiguity_errors.push(AmbiguityError {
                                 span: span, name: name, b1: shadower, b2: binding, lexical: true,
+                                legacy: false,
                             });
                             return Ok(shadower);
                         }
@@ -373,8 +353,8 @@ impl<'a> Resolver<'a> {
 
     pub fn finalize_current_module_macro_resolutions(&mut self) {
         let module = self.current_module;
-        for &(ref path, scope, span) in module.macro_resolutions.borrow().iter() {
-            match self.resolve_path(path, scope, Some(MacroNS), Some(span)) {
+        for &(ref path, span) in module.macro_resolutions.borrow().iter() {
+            match self.resolve_path(path, Some(MacroNS), Some(span)) {
                 PathResult::NonModule(_) => {},
                 PathResult::Failed(msg, _) => {
                     resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
@@ -383,10 +363,10 @@ impl<'a> Resolver<'a> {
             }
         }
 
-        for &(mark, name, span) in module.legacy_macro_resolutions.borrow().iter() {
+        for &(mark, ident, span) in module.legacy_macro_resolutions.borrow().iter() {
             let legacy_scope = &self.invocations[&mark].legacy_scope;
-            let legacy_resolution = self.resolve_legacy_scope(legacy_scope, name, true);
-            let resolution = self.resolve_lexical_macro_path_segment(name, MacroNS, Some(span));
+            let legacy_resolution = self.resolve_legacy_scope(legacy_scope, ident.name, true);
+            let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, Some(span));
             let (legacy_resolution, resolution) = match (legacy_resolution, resolution) {
                 (Some(legacy_resolution), Ok(resolution)) => (legacy_resolution, resolution),
                 _ => continue,
@@ -396,9 +376,9 @@ impl<'a> Resolver<'a> {
                 MacroBinding::Modern(binding) => (binding.span, "imported"),
                 MacroBinding::Legacy(binding) => (binding.span, "defined"),
             };
-            let msg1 = format!("`{}` could resolve to the macro {} here", name, participle);
-            let msg2 = format!("`{}` could also resolve to the macro imported here", name);
-            self.session.struct_span_err(span, &format!("`{}` is ambiguous", name))
+            let msg1 = format!("`{}` could resolve to the macro {} here", ident, participle);
+            let msg2 = format!("`{}` could also resolve to the macro imported here", ident);
+            self.session.struct_span_err(span, &format!("`{}` is ambiguous", ident))
                 .span_note(legacy_span, &msg1)
                 .span_note(resolution.span, &msg2)
                 .emit();
@@ -442,4 +422,47 @@ impl<'a> Resolver<'a> {
             expansion.visit_with(def_collector)
         });
     }
+
+    pub fn define_macro(&mut self, item: &ast::Item, legacy_scope: &mut LegacyScope<'a>) {
+        let tts = match item.node {
+            ast::ItemKind::Mac(ref mac) => &mac.node.tts,
+            _ => unreachable!(),
+        };
+
+        if item.ident.name == "macro_rules" {
+            self.session.span_err(item.span, "user-defined macros may not be named `macro_rules`");
+        }
+
+        let mark = Mark::from_placeholder_id(item.id);
+        let invocation = self.invocations[&mark];
+        invocation.module.set(self.current_module);
+
+        let mut def = ast::MacroDef {
+            ident: item.ident,
+            attrs: item.attrs.clone(),
+            id: ast::DUMMY_NODE_ID,
+            span: item.span,
+            body: mark_tts(tts, mark),
+        };
+
+        *legacy_scope = LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding {
+            parent: Cell::new(*legacy_scope),
+            name: def.ident.name,
+            ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)),
+            span: def.span,
+        }));
+        self.macro_names.insert(def.ident.name);
+
+        if attr::contains_name(&def.attrs, "macro_export") {
+            def.id = self.next_node_id();
+            DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| {
+                collector.visit_macro_def(&def)
+            });
+            self.macro_exports.push(Export {
+                name: def.ident.name,
+                def: Def::Macro(self.definitions.local_def_id(def.id)),
+            });
+            self.exported_macros.push(def);
+        }
+    }
 }
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index b634d57a842..41d8f16b88d 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -12,18 +12,20 @@ use self::ImportDirectiveSubclass::*;
 
 use {AmbiguityError, Module, PerNS};
 use Namespace::{self, TypeNS, MacroNS};
-use {NameBinding, NameBindingKind, PathResult, PathScope, PrivacyError, ToNameBinding};
+use {NameBinding, NameBindingKind, PathResult, PrivacyError};
 use Resolver;
 use {names_to_string, module_to_string};
 use {resolve_error, ResolutionError};
 
 use rustc::ty;
 use rustc::lint::builtin::PRIVATE_IN_PUBLIC;
+use rustc::hir::def_id::DefId;
 use rustc::hir::def::*;
 
-use syntax::ast::{Ident, NodeId, Name};
+use syntax::ast::{Ident, NodeId};
 use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
 use syntax::ext::hygiene::Mark;
+use syntax::parse::token;
 use syntax::symbol::keywords;
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::Span;
@@ -35,8 +37,8 @@ use std::mem;
 #[derive(Clone, Debug)]
 pub enum ImportDirectiveSubclass<'a> {
     SingleImport {
-        target: Name,
-        source: Name,
+        target: Ident,
+        source: Ident,
         result: PerNS<Cell<Result<&'a NameBinding<'a>, Determinacy>>>,
     },
     GlobImport {
@@ -126,33 +128,32 @@ impl<'a> NameResolution<'a> {
 }
 
 impl<'a> Resolver<'a> {
-    fn resolution(&self, module: Module<'a>, name: Name, ns: Namespace)
+    fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
                   -> &'a RefCell<NameResolution<'a>> {
-        *module.resolutions.borrow_mut().entry((name, ns))
+        let ident = ident.unhygienize();
+        *module.resolutions.borrow_mut().entry((ident, ns))
                .or_insert_with(|| self.arenas.alloc_name_resolution())
     }
 
-    /// Attempts to resolve the supplied name in the given module for the given namespace.
-    /// If successful, returns the binding corresponding to the name.
+    /// Attempts to resolve `ident` in namespaces `ns` of `module`.
     /// Invariant: if `record_used` is `Some`, import resolution must be complete.
-    pub fn resolve_name_in_module(&mut self,
-                                  module: Module<'a>,
-                                  name: Name,
-                                  ns: Namespace,
-                                  ignore_unresolved_invocations: bool,
-                                  record_used: Option<Span>)
-                                  -> Result<&'a NameBinding<'a>, Determinacy> {
+    pub fn resolve_ident_in_module(&mut self,
+                                   module: Module<'a>,
+                                   ident: Ident,
+                                   ns: Namespace,
+                                   ignore_unresolved_invocations: bool,
+                                   record_used: Option<Span>)
+                                   -> Result<&'a NameBinding<'a>, Determinacy> {
         self.populate_module_if_necessary(module);
 
-        let resolution = self.resolution(module, name, ns);
-        let resolution = match resolution.borrow_state() {
-            ::std::cell::BorrowState::Unused => resolution.borrow_mut(),
-            _ => return Err(Determined), // This happens when there is a cycle of imports
-        };
+        let resolution = self.resolution(module, ident, ns)
+            .try_borrow_mut()
+            .map_err(|_| Determined)?; // This happens when there is a cycle of imports
 
         if let Some(span) = record_used {
             if let Some(binding) = resolution.binding {
                 if let Some(shadowed_glob) = resolution.shadows_glob {
+                    let name = ident.name;
                     // If we ignore unresolved invocations, we must forbid
                     // expanded shadowing to avoid time travel.
                     if ignore_unresolved_invocations &&
@@ -161,14 +162,15 @@ impl<'a> Resolver<'a> {
                        binding.def() != shadowed_glob.def() {
                         self.ambiguity_errors.push(AmbiguityError {
                             span: span, name: name, lexical: false, b1: binding, b2: shadowed_glob,
+                            legacy: false,
                         });
                     }
                 }
-                if self.record_use(name, ns, binding, span) {
+                if self.record_use(ident, ns, binding, span) {
                     return Ok(self.dummy_binding);
                 }
                 if !self.is_accessible(binding.vis) {
-                    self.privacy_errors.push(PrivacyError(span, name, binding));
+                    self.privacy_errors.push(PrivacyError(span, ident.name, binding));
                 }
             }
 
@@ -196,11 +198,11 @@ impl<'a> Resolver<'a> {
                     Some(module) => module,
                     None => return Err(Undetermined),
                 };
-                let name = match directive.subclass {
+                let ident = match directive.subclass {
                     SingleImport { source, .. } => source,
                     _ => unreachable!(),
                 };
-                match self.resolve_name_in_module(module, name, ns, false, None) {
+                match self.resolve_ident_in_module(module, ident, ns, false, None) {
                     Err(Determined) => {}
                     _ => return Err(Undetermined),
                 }
@@ -222,7 +224,7 @@ impl<'a> Resolver<'a> {
         for directive in module.globs.borrow().iter() {
             if self.is_accessible(directive.vis.get()) {
                 if let Some(module) = directive.imported_module.get() {
-                    let result = self.resolve_name_in_module(module, name, ns, false, None);
+                    let result = self.resolve_ident_in_module(module, ident, ns, false, None);
                     if let Err(Undetermined) = result {
                         return Err(Undetermined);
                     }
@@ -273,8 +275,8 @@ impl<'a> Resolver<'a> {
 
     // Given a binding and an import directive that resolves to it,
     // return the corresponding binding defined by the import directive.
-    pub fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
-                  -> NameBinding<'a> {
+    pub fn import(&self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
+                  -> &'a NameBinding<'a> {
         let vis = if binding.pseudo_vis().is_at_least(directive.vis.get(), self) ||
                      !directive.is_glob() && binding.is_extern_crate() { // c.f. `PRIVATE_IN_PUBLIC`
             directive.vis.get()
@@ -288,7 +290,7 @@ impl<'a> Resolver<'a> {
             }
         }
 
-        NameBinding {
+        self.arenas.alloc_name_binding(NameBinding {
             kind: NameBindingKind::Import {
                 binding: binding,
                 directive: directive,
@@ -297,16 +299,17 @@ impl<'a> Resolver<'a> {
             span: directive.span,
             vis: vis,
             expansion: directive.expansion,
-        }
+        })
     }
 
     // Define the name or return the existing binding if there is a collision.
-    pub fn try_define<T>(&mut self, module: Module<'a>, name: Name, ns: Namespace, binding: T)
-                         -> Result<(), &'a NameBinding<'a>>
-        where T: ToNameBinding<'a>
-    {
-        let binding = self.arenas.alloc_name_binding(binding.to_name_binding());
-        self.update_resolution(module, name, ns, |this, resolution| {
+    pub fn try_define(&mut self,
+                      module: Module<'a>,
+                      ident: Ident,
+                      ns: Namespace,
+                      binding: &'a NameBinding<'a>)
+                      -> Result<(), &'a NameBinding<'a>> {
+        self.update_resolution(module, ident, ns, |this, resolution| {
             if let Some(old_binding) = resolution.binding {
                 if binding.is_glob_import() {
                     if !old_binding.is_glob_import() &&
@@ -314,7 +317,7 @@ impl<'a> Resolver<'a> {
                         resolution.shadows_glob = Some(binding);
                     } else if binding.def() != old_binding.def() {
                         resolution.binding = Some(this.ambiguity(old_binding, binding));
-                    } else if !old_binding.vis.is_at_least(binding.vis, this) {
+                    } else if !old_binding.vis.is_at_least(binding.vis, &*this) {
                         // We are glob-importing the same item but with greater visibility.
                         resolution.binding = Some(binding);
                     }
@@ -337,10 +340,10 @@ impl<'a> Resolver<'a> {
         })
     }
 
-    pub fn ambiguity(&mut self, b1: &'a NameBinding<'a>, b2: &'a NameBinding<'a>)
-                 -> &'a NameBinding<'a> {
+    pub fn ambiguity(&self, b1: &'a NameBinding<'a>, b2: &'a NameBinding<'a>)
+                     -> &'a NameBinding<'a> {
         self.arenas.alloc_name_binding(NameBinding {
-            kind: NameBindingKind::Ambiguity { b1: b1, b2: b2 },
+            kind: NameBindingKind::Ambiguity { b1: b1, b2: b2, legacy: false },
             vis: if b1.vis.is_at_least(b2.vis, self) { b1.vis } else { b2.vis },
             span: b1.span,
             expansion: Mark::root(),
@@ -349,13 +352,14 @@ impl<'a> Resolver<'a> {
 
     // Use `f` to mutate the resolution of the name in the module.
     // If the resolution becomes a success, define it in the module's glob importers.
-    fn update_resolution<T, F>(&mut self, module: Module<'a>, name: Name, ns: Namespace, f: F) -> T
+    fn update_resolution<T, F>(&mut self, module: Module<'a>, ident: Ident, ns: Namespace, f: F)
+                               -> T
         where F: FnOnce(&mut Resolver<'a>, &mut NameResolution<'a>) -> T
     {
         // Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
         // during which the resolution might end up getting re-defined via a glob cycle.
         let (binding, t) = {
-            let mut resolution = &mut *self.resolution(module, name, ns).borrow_mut();
+            let mut resolution = &mut *self.resolution(module, ident, ns).borrow_mut();
             let old_binding = resolution.binding();
 
             let t = f(self, resolution);
@@ -374,7 +378,7 @@ impl<'a> Resolver<'a> {
         for directive in module.glob_importers.borrow_mut().iter() {
             if self.is_accessible_from(binding.vis, directive.parent) {
                 let imported_binding = self.import(binding, directive);
-                let _ = self.try_define(directive.parent, name, ns, imported_binding);
+                let _ = self.try_define(directive.parent, ident, ns, imported_binding);
             }
         }
 
@@ -388,7 +392,7 @@ impl<'a> Resolver<'a> {
             let dummy_binding = self.dummy_binding;
             let dummy_binding = self.import(dummy_binding, directive);
             self.per_ns(|this, ns| {
-                let _ = this.try_define(directive.parent, target, ns, dummy_binding.clone());
+                let _ = this.try_define(directive.parent, target, ns, dummy_binding);
             });
         }
     }
@@ -411,9 +415,9 @@ impl<'a, 'b: 'a> ::std::ops::DerefMut for ImportResolver<'a, 'b> {
     }
 }
 
-impl<'a, 'b: 'a> ty::NodeIdTree for ImportResolver<'a, 'b> {
-    fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool {
-        self.resolver.is_descendant_of(node, ancestor)
+impl<'a, 'b: 'a> ty::DefIdTree for &'a ImportResolver<'a, 'b> {
+    fn parent(self, id: DefId) -> Option<DefId> {
+        self.resolver.parent(id)
     }
 }
 
@@ -486,8 +490,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
             let vis = directive.vis.get();
             // For better failure detection, pretend that the import will not define any names
             // while resolving its module path.
-            directive.vis.set(ty::Visibility::PrivateExternal);
-            let result = self.resolve_path(&directive.module_path, PathScope::Import, None, None);
+            directive.vis.set(ty::Visibility::Invisible);
+            let result = self.resolve_path(&directive.module_path, None, None);
             directive.vis.set(vis);
 
             match result {
@@ -510,15 +514,16 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
         let mut indeterminate = false;
         self.per_ns(|this, ns| {
             if let Err(Undetermined) = result[ns].get() {
-                result[ns].set(this.resolve_name_in_module(module, source, ns, false, None));
+                result[ns].set(this.resolve_ident_in_module(module, source, ns, false, None));
             } else {
                 return
             };
 
+            let parent = directive.parent;
             match result[ns].get() {
                 Err(Undetermined) => indeterminate = true,
                 Err(Determined) => {
-                    this.update_resolution(directive.parent, target, ns, |_, resolution| {
+                    this.update_resolution(parent, target, ns, |_, resolution| {
                         resolution.single_imports.directive_failed()
                     });
                 }
@@ -533,10 +538,9 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
                 }
                 Ok(binding) => {
                     let imported_binding = this.import(binding, directive);
-                    let conflict = this.try_define(directive.parent, target, ns, imported_binding);
+                    let conflict = this.try_define(parent, target, ns, imported_binding);
                     if let Err(old_binding) = conflict {
-                        let binding = &this.import(binding, directive);
-                        this.report_conflict(directive.parent, target, ns, binding, old_binding);
+                        this.report_conflict(parent, target, ns, imported_binding, old_binding);
                     }
                 }
             }
@@ -550,15 +554,17 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
         self.current_module = directive.parent;
 
         let ImportDirective { ref module_path, span, .. } = *directive;
-        let module_result = self.resolve_path(&module_path, PathScope::Import, None, Some(span));
+        let module_result = self.resolve_path(&module_path, None, Some(span));
         let module = match module_result {
             PathResult::Module(module) => module,
             PathResult::Failed(msg, _) => {
-                let mut path = vec![keywords::SelfValue.ident()];
-                path.extend(module_path);
-                let result = self.resolve_path(&path, PathScope::Import, None, None);
-                return if let PathResult::Module(..) = result {
-                    Some(format!("Did you mean `self::{}`?", &names_to_string(module_path)))
+                let (mut self_path, mut self_result) = (module_path.clone(), None);
+                if !self_path.is_empty() && !token::Ident(self_path[0]).is_path_segment_keyword() {
+                    self_path[0].name = keywords::SelfValue.name();
+                    self_result = Some(self.resolve_path(&self_path, None, None));
+                }
+                return if let Some(PathResult::Module(..)) = self_result {
+                    Some(format!("Did you mean `{}`?", names_to_string(&self_path)))
                 } else {
                     Some(msg)
                 };
@@ -566,7 +572,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
             _ => return None,
         };
 
-        let (name, result) = match directive.subclass {
+        let (ident, result) = match directive.subclass {
             SingleImport { source, ref result, .. } => (source, result),
             GlobImport { .. } if module.def_id() == directive.parent.def_id() => {
                 // Importing a module into itself is not allowed.
@@ -574,8 +580,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
             }
             GlobImport { is_prelude, ref max_vis } => {
                 if !is_prelude &&
-                   max_vis.get() != ty::Visibility::PrivateExternal && // Allow empty globs.
-                   !max_vis.get().is_at_least(directive.vis.get(), self) {
+                   max_vis.get() != ty::Visibility::Invisible && // Allow empty globs.
+                   !max_vis.get().is_at_least(directive.vis.get(), &*self) {
                     let msg = "A non-empty glob must import something with the glob's visibility";
                     self.session.span_err(directive.span, msg);
                 }
@@ -588,8 +594,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
         self.per_ns(|this, ns| {
             if let Ok(binding) = result[ns].get() {
                 all_ns_err = false;
-                if this.record_use(name, ns, binding, directive.span) {
-                    this.resolution(module, name, ns).borrow_mut().binding =
+                if this.record_use(ident, ns, binding, directive.span) {
+                    this.resolution(module, ident, ns).borrow_mut().binding =
                         Some(this.dummy_binding);
                 }
             }
@@ -598,7 +604,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
         if all_ns_err {
             let mut all_ns_failed = true;
             self.per_ns(|this, ns| {
-                match this.resolve_name_in_module(module, name, ns, false, Some(span)) {
+                match this.resolve_ident_in_module(module, ident, ns, false, Some(span)) {
                     Ok(_) => all_ns_failed = false,
                     _ => {}
                 }
@@ -606,27 +612,28 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
 
             return if all_ns_failed {
                 let resolutions = module.resolutions.borrow();
-                let names = resolutions.iter().filter_map(|(&(ref n, _), resolution)| {
-                    if *n == name { return None; } // Never suggest the same name
+                let names = resolutions.iter().filter_map(|(&(ref i, _), resolution)| {
+                    if *i == ident { return None; } // Never suggest the same name
                     match *resolution.borrow() {
-                        NameResolution { binding: Some(_), .. } => Some(n),
+                        NameResolution { binding: Some(_), .. } => Some(&i.name),
                         NameResolution { single_imports: SingleImports::None, .. } => None,
-                        _ => Some(n),
+                        _ => Some(&i.name),
                     }
                 });
-                let lev_suggestion = match find_best_match_for_name(names, &name.as_str(), None) {
-                    Some(name) => format!(". Did you mean to use `{}`?", name),
-                    None => "".to_owned(),
-                };
+                let lev_suggestion =
+                    match find_best_match_for_name(names, &ident.name.as_str(), None) {
+                        Some(name) => format!(". Did you mean to use `{}`?", name),
+                        None => "".to_owned(),
+                    };
                 let module_str = module_to_string(module);
                 let msg = if &module_str == "???" {
-                    format!("no `{}` in the root{}", name, lev_suggestion)
+                    format!("no `{}` in the root{}", ident, lev_suggestion)
                 } else {
-                    format!("no `{}` in `{}`{}", name, module_str, lev_suggestion)
+                    format!("no `{}` in `{}`{}", ident, module_str, lev_suggestion)
                 };
                 Some(msg)
             } else {
-                // `resolve_name_in_module` reported a privacy error.
+                // `resolve_ident_in_module` reported a privacy error.
                 self.import_dummy_binding(directive);
                 None
             }
@@ -637,7 +644,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
         self.per_ns(|this, ns| {
             if let Ok(binding) = result[ns].get() {
                 let vis = directive.vis.get();
-                if !binding.pseudo_vis().is_at_least(vis, this) {
+                if !binding.pseudo_vis().is_at_least(vis, &*this) {
                     reexport_error = Some((ns, binding));
                 } else {
                     any_successful_reexport = true;
@@ -651,18 +658,18 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
             if ns == TypeNS && binding.is_extern_crate() {
                 let msg = format!("extern crate `{}` is private, and cannot be reexported \
                                    (error E0364), consider declaring with `pub`",
-                                   name);
+                                   ident);
                 self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg);
             } else if ns == TypeNS {
                 struct_span_err!(self.session, directive.span, E0365,
-                                 "`{}` is private, and cannot be reexported", name)
-                    .span_label(directive.span, &format!("reexport of private `{}`", name))
-                    .note(&format!("consider declaring type or module `{}` with `pub`", name))
+                                 "`{}` is private, and cannot be reexported", ident)
+                    .span_label(directive.span, &format!("reexport of private `{}`", ident))
+                    .note(&format!("consider declaring type or module `{}` with `pub`", ident))
                     .emit();
             } else {
-                let msg = format!("`{}` is private, and cannot be reexported", name);
+                let msg = format!("`{}` is private, and cannot be reexported", ident);
                 let note_msg =
-                    format!("consider marking `{}` as `pub` in the imported module", name);
+                    format!("consider marking `{}` as `pub` in the imported module", ident);
                 struct_span_err!(self.session, directive.span, E0364, "{}", &msg)
                     .span_note(directive.span, &note_msg)
                     .emit();
@@ -699,21 +706,18 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
 
         // Ensure that `resolutions` isn't borrowed during `try_define`,
         // since it might get updated via a glob cycle.
-        let bindings = module.resolutions.borrow().iter().filter_map(|(name, resolution)| {
-            resolution.borrow().binding().map(|binding| (*name, binding))
+        let bindings = module.resolutions.borrow().iter().filter_map(|(&ident, resolution)| {
+            resolution.borrow().binding().map(|binding| (ident, binding))
         }).collect::<Vec<_>>();
-        for ((name, ns), binding) in bindings {
+        for ((ident, ns), binding) in bindings {
             if binding.pseudo_vis() == ty::Visibility::Public || self.is_accessible(binding.vis) {
                 let imported_binding = self.import(binding, directive);
-                let _ = self.try_define(directive.parent, name, ns, imported_binding);
+                let _ = self.try_define(directive.parent, ident, ns, imported_binding);
             }
         }
 
         // Record the destination of this import
-        if let Some(did) = module.def_id() {
-            let resolution = PathResolution::new(Def::Mod(did));
-            self.def_map.insert(directive.id, resolution);
-        }
+        self.record_def(directive.id, PathResolution::new(module.def().unwrap()));
     }
 
     // Miscellaneous post-processing, including recording reexports, reporting conflicts,
@@ -727,8 +731,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
             reexports = mem::replace(&mut self.macro_exports, Vec::new());
         }
 
-        for (&(name, ns), resolution) in module.resolutions.borrow().iter() {
-            let resolution = resolution.borrow();
+        for (&(ident, ns), resolution) in module.resolutions.borrow().iter() {
+            let resolution = &mut *resolution.borrow_mut();
             let binding = match resolution.binding {
                 Some(binding) => binding,
                 None => continue,
@@ -741,18 +745,38 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
                     if !def.def_id().is_local() {
                         self.session.cstore.export_macros(def.def_id().krate);
                     }
-                    reexports.push(Export { name: name, def: def });
+                    reexports.push(Export { name: ident.name, def: def });
                 }
             }
 
-            if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind {
-                if ns == TypeNS && orig_binding.is_variant() &&
-                   !orig_binding.vis.is_at_least(binding.vis, self) {
-                    let msg = format!("variant `{}` is private, and cannot be reexported \
-                                       (error E0364), consider declaring its enum as `pub`",
-                                      name);
-                    self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, binding.span, msg);
+            match binding.kind {
+                NameBindingKind::Import { binding: orig_binding, directive, .. } => {
+                    if ns == TypeNS && orig_binding.is_variant() &&
+                       !orig_binding.vis.is_at_least(binding.vis, &*self) {
+                        let msg = format!("variant `{}` is private, and cannot be reexported \
+                                           (error E0364), consider declaring its enum as `pub`",
+                                          ident);
+                        self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, binding.span, msg);
+                    }
+                }
+                NameBindingKind::Ambiguity { b1, b2, .. }
+                        if b1.is_glob_import() && b2.is_glob_import() => {
+                    let (orig_b1, orig_b2) = match (&b1.kind, &b2.kind) {
+                        (&NameBindingKind::Import { binding: b1, .. },
+                         &NameBindingKind::Import { binding: b2, .. }) => (b1, b2),
+                        _ => continue,
+                    };
+                    let (b1, b2) = match (orig_b1.vis, orig_b2.vis) {
+                        (ty::Visibility::Public, ty::Visibility::Public) => continue,
+                        (ty::Visibility::Public, _) => (b1, b2),
+                        (_, ty::Visibility::Public) => (b2, b1),
+                        _ => continue,
+                    };
+                    resolution.binding = Some(self.arenas.alloc_name_binding(NameBinding {
+                        kind: NameBindingKind::Ambiguity { b1: b1, b2: b2, legacy: true }, ..*b1
+                    }));
                 }
+                _ => {}
             }
         }
 
@@ -766,6 +790,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
 }
 
 fn import_path_to_string(names: &[Ident], subclass: &ImportDirectiveSubclass) -> String {
+    let global = !names.is_empty() && names[0].name == keywords::CrateRoot.name();
+    let names = if global { &names[1..] } else { names };
     if names.is_empty() {
         import_directive_subclass_to_string(subclass)
     } else {
diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs
index fc235aaf927..0a6281bf8c5 100644
--- a/src/librustc_save_analysis/data.rs
+++ b/src/librustc_save_analysis/data.rs
@@ -135,6 +135,7 @@ pub struct EnumData {
     pub variants: Vec<NodeId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 /// Data for extern crates.
@@ -169,6 +170,7 @@ pub struct FunctionData {
     pub visibility: Visibility,
     pub parent: Option<DefId>,
     pub docs: String,
+    pub sig: Signature,
 }
 
 /// Data about a function call.
@@ -253,6 +255,7 @@ pub struct MethodData {
     pub parent: Option<DefId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 /// Data for modules.
@@ -267,6 +270,7 @@ pub struct ModData {
     pub items: Vec<NodeId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 /// Data for a reference to a module.
@@ -290,6 +294,7 @@ pub struct StructData {
     pub fields: Vec<NodeId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -303,6 +308,7 @@ pub struct StructVariantData {
     pub scope: NodeId,
     pub parent: Option<DefId>,
     pub docs: String,
+    pub sig: Signature,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -316,6 +322,7 @@ pub struct TraitData {
     pub items: Vec<NodeId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -329,6 +336,7 @@ pub struct TupleVariantData {
     pub scope: NodeId,
     pub parent: Option<DefId>,
     pub docs: String,
+    pub sig: Signature,
 }
 
 /// Data for a typedef.
@@ -342,6 +350,7 @@ pub struct TypeDefData {
     pub visibility: Visibility,
     pub parent: Option<DefId>,
     pub docs: String,
+    pub sig: Option<Signature>,
 }
 
 /// Data for a reference to a type or trait.
@@ -386,6 +395,7 @@ pub struct VariableData {
     pub type_value: String,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Option<Signature>,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -405,3 +415,28 @@ pub struct VariableRefData {
     pub scope: NodeId,
     pub ref_id: DefId,
 }
+
+
+/// Encodes information about the signature of a definition. This should have
+/// enough information to create a nice display about a definition without
+/// access to the source code.
+#[derive(Clone, Debug, RustcEncodable)]
+pub struct Signature {
+    pub span: Span,
+    pub text: String,
+    // These identify the main identifier for the defintion as byte offsets into
+    // `text`. E.g., of `foo` in `pub fn foo(...)`
+    pub ident_start: usize,
+    pub ident_end: usize,
+    pub defs: Vec<SigElement>,
+    pub refs: Vec<SigElement>,
+}
+
+/// An element of a signature. `start` and `end` are byte offsets into the `text`
+/// of the parent `Signature`.
+#[derive(Clone, Debug, RustcEncodable)]
+pub struct SigElement {
+    pub id: DefId,
+    pub start: usize,
+    pub end: usize,
+}
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index afa78a05a63..093a739c69f 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -143,19 +143,20 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
     // a str representation of the entire prefix.
     fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> {
         let spans = self.span.spans_for_path_segments(path);
+        let segments = &path.segments[if path.is_global() { 1 } else { 0 }..];
 
         // Paths to enums seem to not match their spans - the span includes all the
         // variants too. But they seem to always be at the end, so I hope we can cope with
         // always using the first ones. So, only error out if we don't have enough spans.
         // What could go wrong...?
-        if spans.len() < path.segments.len() {
+        if spans.len() < segments.len() {
             if generated_code(path.span) {
                 return vec![];
             }
             error!("Mis-calculated spans for path '{}'. Found {} spans, expected {}. Found spans:",
                    path_to_string(path),
                    spans.len(),
-                   path.segments.len());
+                   segments.len());
             for s in &spans {
                 let loc = self.sess.codemap().lookup_char_pos(s.lo);
                 error!("    '{}' in {}, line {}",
@@ -170,14 +171,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         let mut result: Vec<(Span, String)> = vec![];
 
         let mut segs = vec![];
-        for (i, (seg, span)) in path.segments.iter().zip(&spans).enumerate() {
+        for (i, (seg, span)) in segments.iter().zip(&spans).enumerate() {
             segs.push(seg.clone());
             let sub_path = ast::Path {
                 span: *span, // span for the last segment
-                global: path.global,
                 segments: segs,
             };
-            let qualname = if i == 0 && path.global {
+            let qualname = if i == 0 && path.is_global() {
                 format!("::{}", path_to_string(&sub_path))
             } else {
                 path_to_string(&sub_path)
@@ -189,20 +189,11 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         result
     }
 
-    // The global arg allows us to override the global-ness of the path (which
-    // actually means 'does the path start with `::`', rather than 'is the path
-    // semantically global). We use the override for `use` imports (etc.) where
-    // the syntax is non-global, but the semantics are global.
-    fn write_sub_paths(&mut self, path: &ast::Path, global: bool) {
+    fn write_sub_paths(&mut self, path: &ast::Path) {
         let sub_paths = self.process_path_prefixes(path);
-        for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() {
-            let qualname = if i == 0 && global && !path.global {
-                format!("::{}", qualname)
-            } else {
-                qualname.clone()
-            };
+        for (span, qualname) in sub_paths {
             self.dumper.mod_ref(ModRefData {
-                span: *span,
+                span: span,
                 qualname: qualname,
                 scope: self.cur_scope,
                 ref_id: None
@@ -212,22 +203,16 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
 
     // As write_sub_paths, but does not process the last ident in the path (assuming it
     // will be processed elsewhere). See note on write_sub_paths about global.
-    fn write_sub_paths_truncated(&mut self, path: &ast::Path, global: bool) {
+    fn write_sub_paths_truncated(&mut self, path: &ast::Path) {
         let sub_paths = self.process_path_prefixes(path);
         let len = sub_paths.len();
         if len <= 1 {
             return;
         }
 
-        let sub_paths = &sub_paths[..len-1];
-        for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() {
-            let qualname = if i == 0 && global && !path.global {
-                format!("::{}", qualname)
-            } else {
-                qualname.clone()
-            };
+        for (span, qualname) in sub_paths.into_iter().take(len - 1) {
             self.dumper.mod_ref(ModRefData {
-                span: *span,
+                span: span,
                 qualname: qualname,
                 scope: self.cur_scope,
                 ref_id: None
@@ -372,6 +357,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                         parent: None,
                         visibility: Visibility::Inherited,
                         docs: String::new(),
+                        sig: None,
                     }.lower(self.tcx));
                 }
             }
@@ -444,6 +430,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                     parent: trait_id,
                     visibility: vis,
                     docs: docs_for_attrs(attrs),
+                    sig: method_data.sig,
                 }.lower(self.tcx));
             }
 
@@ -515,6 +502,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                     visibility: Visibility::Inherited,
                     parent: None,
                     docs: String::new(),
+                    sig: None,
                 }.lower(self.tcx));
             }
         }
@@ -587,6 +575,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                 parent: Some(parent_id),
                 visibility: vis,
                 docs: docs_for_attrs(attrs),
+                sig: None,
             }.lower(self.tcx));
         }
 
@@ -630,11 +619,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                 fields: fields,
                 visibility: From::from(&item.vis),
                 docs: docs_for_attrs(&item.attrs),
+                sig: self.save_ctxt.sig_base(item),
             }.lower(self.tcx));
         }
 
-
-        // fields
         for field in def.fields() {
             self.process_struct_field_def(field, item.id);
             self.visit_ty(&field.ty);
@@ -663,6 +651,18 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             qualname.push_str("::");
             qualname.push_str(&name);
 
+            let text = self.span.signature_string_for_span(variant.span);
+            let ident_start = text.find(&name).unwrap();
+            let ident_end = ident_start + name.len();
+            let sig = Signature {
+                span: variant.span,
+                text: text,
+                ident_start: ident_start,
+                ident_end: ident_end,
+                defs: vec![],
+                refs: vec![],
+            };
+
             match variant.node.data {
                 ast::VariantData::Struct(ref fields, _) => {
                     let sub_span = self.span.span_for_first_ident(variant.span);
@@ -684,6 +684,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                             scope: enum_data.scope,
                             parent: Some(make_def_id(item.id, &self.tcx.map)),
                             docs: docs_for_attrs(&variant.node.attrs),
+                            sig: sig,
                         }.lower(self.tcx));
                     }
                 }
@@ -709,6 +710,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                             scope: enum_data.scope,
                             parent: Some(make_def_id(item.id, &self.tcx.map)),
                             docs: docs_for_attrs(&variant.node.attrs),
+                            sig: sig,
                         }.lower(self.tcx));
                     }
                 }
@@ -793,6 +795,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                 items: methods.iter().map(|i| i.id).collect(),
                 visibility: From::from(&item.vis),
                 docs: docs_for_attrs(&item.attrs),
+                sig: self.save_ctxt.sig_base(item),
             }.lower(self.tcx));
         }
 
@@ -935,7 +938,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             Def::Union(..) |
             Def::Variant(..) |
             Def::TyAlias(..) |
-            Def::AssociatedTy(..) => self.write_sub_paths_truncated(path, false),
+            Def::AssociatedTy(..) => self.write_sub_paths_truncated(path),
             _ => {}
         }
     }
@@ -946,7 +949,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                           fields: &'l [ast::Field],
                           variant: &'l ty::VariantDef,
                           base: &'l Option<P<ast::Expr>>) {
-        self.write_sub_paths_truncated(path, false);
+        self.write_sub_paths_truncated(path);
 
         if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
             down_cast_data!(struct_lit_data, TypeRefData, ex.span);
@@ -1058,6 +1061,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                     parent: None,
                     visibility: Visibility::Inherited,
                     docs: String::new(),
+                    sig: None,
                 }.lower(self.tcx));
             }
         }
@@ -1201,7 +1205,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                                 visibility: From::from(&item.vis),
                             }.lower(self.tcx));
                         }
-                        self.write_sub_paths_truncated(path, true);
+                        self.write_sub_paths_truncated(path);
                     }
                     ast::ViewPathGlob(ref path) => {
                         // Make a comma-separated list of names of imported modules.
@@ -1225,7 +1229,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                                 visibility: From::from(&item.vis),
                             }.lower(self.tcx));
                         }
-                        self.write_sub_paths(path, true);
+                        self.write_sub_paths(path);
                     }
                     ast::ViewPathList(ref path, ref list) => {
                         for plid in list {
@@ -1237,7 +1241,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                             }
                         }
 
-                        self.write_sub_paths(path, true);
+                        self.write_sub_paths(path);
                     }
                 }
             }
@@ -1272,10 +1276,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
             Struct(ref def, ref ty_params) => self.process_struct(item, def, ty_params),
             Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
             Impl(..,
-                          ref ty_params,
-                          ref trait_ref,
-                          ref typ,
-                          ref impl_items) => {
+                 ref ty_params,
+                 ref trait_ref,
+                 ref typ,
+                 ref impl_items) => {
                 self.process_impl(item, ty_params, trait_ref, &typ, impl_items)
             }
             Trait(_, ref generics, ref trait_refs, ref methods) =>
@@ -1298,6 +1302,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                         visibility: From::from(&item.vis),
                         parent: None,
                         docs: docs_for_attrs(&item.attrs),
+                        sig: Some(self.save_ctxt.sig_base(item)),
                     }.lower(self.tcx));
                 }
 
@@ -1340,7 +1345,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                     }.lower(self.tcx));
                 }
 
-                self.write_sub_paths_truncated(path, false);
+                self.write_sub_paths_truncated(path);
 
                 visit::walk_path(self, path);
             }
@@ -1507,6 +1512,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                             parent: None,
                             visibility: Visibility::Inherited,
                             docs: String::new(),
+                            sig: None,
                         }.lower(self.tcx));
                     }
                 }
diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs
index 58475757423..18ae3a7fa9e 100644
--- a/src/librustc_save_analysis/external_data.rs
+++ b/src/librustc_save_analysis/external_data.rs
@@ -15,7 +15,7 @@ use syntax::ast::NodeId;
 use syntax::codemap::CodeMap;
 use syntax_pos::Span;
 
-use data::{self, Visibility};
+use data::{self, Visibility, SigElement};
 
 // FIXME: this should be pub(crate), but the current snapshot doesn't allow it yet
 pub trait Lower {
@@ -97,6 +97,7 @@ pub struct EnumData {
     pub variants: Vec<DefId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 impl Lower for data::EnumData {
@@ -113,6 +114,7 @@ impl Lower for data::EnumData {
             variants: self.variants.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(),
             visibility: self.visibility,
             docs: self.docs,
+            sig: self.sig.lower(tcx),
         }
     }
 }
@@ -176,6 +178,7 @@ pub struct FunctionData {
     pub visibility: Visibility,
     pub parent: Option<DefId>,
     pub docs: String,
+    pub sig: Signature,
 }
 
 impl Lower for data::FunctionData {
@@ -193,6 +196,7 @@ impl Lower for data::FunctionData {
             visibility: self.visibility,
             parent: self.parent,
             docs: self.docs,
+            sig: self.sig.lower(tcx),
         }
     }
 }
@@ -341,6 +345,7 @@ pub struct MethodData {
     pub visibility: Visibility,
     pub parent: Option<DefId>,
     pub docs: String,
+    pub sig: Signature,
 }
 
 impl Lower for data::MethodData {
@@ -358,6 +363,7 @@ impl Lower for data::MethodData {
             visibility: self.visibility,
             parent: self.parent,
             docs: self.docs,
+            sig: self.sig.lower(tcx),
         }
     }
 }
@@ -374,6 +380,7 @@ pub struct ModData {
     pub items: Vec<DefId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 impl Lower for data::ModData {
@@ -390,6 +397,7 @@ impl Lower for data::ModData {
             items: self.items.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(),
             visibility: self.visibility,
             docs: self.docs,
+            sig: self.sig.lower(tcx),
         }
     }
 }
@@ -428,6 +436,7 @@ pub struct StructData {
     pub fields: Vec<DefId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 impl Lower for data::StructData {
@@ -445,6 +454,7 @@ impl Lower for data::StructData {
             fields: self.fields.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(),
             visibility: self.visibility,
             docs: self.docs,
+            sig: self.sig.lower(tcx),
         }
     }
 }
@@ -460,6 +470,7 @@ pub struct StructVariantData {
     pub scope: DefId,
     pub parent: Option<DefId>,
     pub docs: String,
+    pub sig: Signature,
 }
 
 impl Lower for data::StructVariantData {
@@ -476,6 +487,7 @@ impl Lower for data::StructVariantData {
             scope: make_def_id(self.scope, &tcx.map),
             parent: self.parent,
             docs: self.docs,
+            sig: self.sig.lower(tcx),
         }
     }
 }
@@ -491,6 +503,7 @@ pub struct TraitData {
     pub items: Vec<DefId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 impl Lower for data::TraitData {
@@ -507,6 +520,7 @@ impl Lower for data::TraitData {
             items: self.items.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(),
             visibility: self.visibility,
             docs: self.docs,
+            sig: self.sig.lower(tcx),
         }
     }
 }
@@ -522,6 +536,7 @@ pub struct TupleVariantData {
     pub scope: DefId,
     pub parent: Option<DefId>,
     pub docs: String,
+    pub sig: Signature,
 }
 
 impl Lower for data::TupleVariantData {
@@ -538,6 +553,7 @@ impl Lower for data::TupleVariantData {
             scope: make_def_id(self.scope, &tcx.map),
             parent: self.parent,
             docs: self.docs,
+            sig: self.sig.lower(tcx),
         }
     }
 }
@@ -553,6 +569,7 @@ pub struct TypeDefData {
     pub visibility: Visibility,
     pub parent: Option<DefId>,
     pub docs: String,
+    pub sig: Option<Signature>,
 }
 
 impl Lower for data::TypeDefData {
@@ -568,6 +585,7 @@ impl Lower for data::TypeDefData {
             visibility: self.visibility,
             parent: self.parent,
             docs: self.docs,
+            sig: self.sig.map(|s| s.lower(tcx)),
         }
     }
 }
@@ -656,6 +674,7 @@ pub struct VariableData {
     pub parent: Option<DefId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Option<Signature>,
 }
 
 impl Lower for data::VariableData {
@@ -674,6 +693,7 @@ impl Lower for data::VariableData {
             parent: self.parent,
             visibility: self.visibility,
             docs: self.docs,
+            sig: self.sig.map(|s| s.lower(tcx)),
         }
     }
 }
@@ -700,3 +720,30 @@ impl Lower for data::VariableRefData {
         }
     }
 }
+
+#[derive(Clone, Debug, RustcEncodable)]
+pub struct Signature {
+    pub span: SpanData,
+    pub text: String,
+    // These identify the main identifier for the defintion as byte offsets into
+    // `text`. E.g., of `foo` in `pub fn foo(...)`
+    pub ident_start: usize,
+    pub ident_end: usize,
+    pub defs: Vec<SigElement>,
+    pub refs: Vec<SigElement>,
+}
+
+impl Lower for data::Signature {
+    type Target = Signature;
+
+    fn lower(self, tcx: TyCtxt) -> Signature {
+        Signature {
+            span: SpanData::from_span(self.span, tcx.sess.codemap()),
+            text: self.text,
+            ident_start: self.ident_start,
+            ident_end: self.ident_end,
+            defs: self.defs,
+            refs: self.refs,
+        }
+    }
+}
diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs
index d56aae18a7c..342c33af2f8 100644
--- a/src/librustc_save_analysis/json_api_dumper.rs
+++ b/src/librustc_save_analysis/json_api_dumper.rs
@@ -14,7 +14,7 @@ use rustc::hir::def_id::DefId;
 use rustc_serialize::json::as_json;
 
 use external_data::*;
-use data::{VariableKind, Visibility};
+use data::{VariableKind, Visibility, SigElement};
 use dump::Dump;
 use super::Format;
 
@@ -179,6 +179,7 @@ struct Def {
     children: Vec<Id>,
     decl_id: Option<Id>,
     docs: String,
+    sig: Option<JsonSignature>,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -221,6 +222,7 @@ impl From<EnumData> for Option<Def> {
                 children: data.variants.into_iter().map(|id| From::from(id)).collect(),
                 decl_id: None,
                 docs: data.docs,
+                sig: Some(From::from(data.sig)),
             }),
             _ => None,
         }
@@ -240,6 +242,7 @@ impl From<TupleVariantData> for Option<Def> {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         })
     }
 }
@@ -256,6 +259,7 @@ impl From<StructVariantData> for Option<Def> {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         })
     }
 }
@@ -273,6 +277,7 @@ impl From<StructData> for Option<Def> {
             children: data.fields.into_iter().map(|id| From::from(id)).collect(),
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         }),
             _ => None,
         }
@@ -292,6 +297,7 @@ impl From<TraitData> for Option<Def> {
                 parent: None,
                 decl_id: None,
                 docs: data.docs,
+                sig: Some(From::from(data.sig)),
             }),
             _ => None,
         }
@@ -311,6 +317,7 @@ impl From<FunctionData> for Option<Def> {
                 parent: data.parent.map(|id| From::from(id)),
                 decl_id: None,
                 docs: data.docs,
+                sig: Some(From::from(data.sig)),
             }),
             _ => None,
         }
@@ -330,6 +337,7 @@ impl From<MethodData> for Option<Def> {
                 parent: data.parent.map(|id| From::from(id)),
                 decl_id: data.decl_id.map(|id| From::from(id)),
                 docs: data.docs,
+                sig: Some(From::from(data.sig)),
             }),
             _ => None,
         }
@@ -348,6 +356,7 @@ impl From<MacroData> for Option<Def> {
             parent: None,
             decl_id: None,
             docs: data.docs,
+            sig: None,
         })
     }
 }
@@ -365,6 +374,7 @@ impl From<ModData> for Option<Def> {
                 parent: None,
                 decl_id: None,
                 docs: data.docs,
+                sig: Some(From::from(data.sig)),
             }),
             _ => None,
         }
@@ -384,11 +394,13 @@ impl From<TypeDefData> for Option<Def> {
                 parent: data.parent.map(|id| From::from(id)),
                 decl_id: None,
                 docs: String::new(),
+                sig: data.sig.map(|s| From::from(s)),
             }),
             _ => None,
         }
     }
 }
+
 impl From<VariableData> for Option<Def> {
     fn from(data: VariableData) -> Option<Def> {
         match data.visibility {
@@ -408,8 +420,49 @@ impl From<VariableData> for Option<Def> {
                 parent: data.parent.map(|id| From::from(id)),
                 decl_id: None,
                 docs: data.docs,
+                sig: data.sig.map(|s| From::from(s)),
             }),
             _ => None,
         }
     }
 }
+
+#[derive(Debug, RustcEncodable)]
+pub struct JsonSignature {
+    span: SpanData,
+    text: String,
+    ident_start: usize,
+    ident_end: usize,
+    defs: Vec<JsonSigElement>,
+    refs: Vec<JsonSigElement>,
+}
+
+impl From<Signature> for JsonSignature {
+    fn from(data: Signature) -> JsonSignature {
+        JsonSignature {
+            span: data.span,
+            text: data.text,
+            ident_start: data.ident_start,
+            ident_end: data.ident_end,
+            defs: data.defs.into_iter().map(|s| From::from(s)).collect(),
+            refs: data.refs.into_iter().map(|s| From::from(s)).collect(),
+        }
+    }
+}
+
+#[derive(Debug, RustcEncodable)]
+pub struct JsonSigElement {
+    id: Id,
+    start: usize,
+    end: usize,
+}
+
+impl From<SigElement> for JsonSigElement {
+    fn from(data: SigElement) -> JsonSigElement {
+        JsonSigElement {
+            id: From::from(data.id),
+            start: data.start,
+            end: data.end,
+        }
+    }
+}
diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs
index f97272ad544..16c06a556df 100644
--- a/src/librustc_save_analysis/json_dumper.rs
+++ b/src/librustc_save_analysis/json_dumper.rs
@@ -14,7 +14,7 @@ use rustc::hir::def_id::DefId;
 use rustc_serialize::json::as_json;
 
 use external_data::*;
-use data::VariableKind;
+use data::{VariableKind, SigElement};
 use dump::Dump;
 use super::Format;
 
@@ -86,6 +86,7 @@ impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> {
             children: data.items.into_iter().map(|id| From::from(id)).collect(),
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         };
         if def.span.file_name != def.value {
             // If the module is an out-of-line defintion, then we'll make the
@@ -223,6 +224,7 @@ struct Def {
     children: Vec<Id>,
     decl_id: Option<Id>,
     docs: String,
+    sig: Option<JsonSignature>,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -264,6 +266,7 @@ impl From<EnumData> for Def {
             children: data.variants.into_iter().map(|id| From::from(id)).collect(),
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         }
     }
 }
@@ -280,6 +283,7 @@ impl From<TupleVariantData> for Def {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         }
     }
 }
@@ -295,6 +299,7 @@ impl From<StructVariantData> for Def {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         }
     }
 }
@@ -310,6 +315,7 @@ impl From<StructData> for Def {
             children: data.fields.into_iter().map(|id| From::from(id)).collect(),
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         }
     }
 }
@@ -325,6 +331,7 @@ impl From<TraitData> for Def {
             children: data.items.into_iter().map(|id| From::from(id)).collect(),
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         }
     }
 }
@@ -340,6 +347,7 @@ impl From<FunctionData> for Def {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         }
     }
 }
@@ -355,6 +363,7 @@ impl From<MethodData> for Def {
             children: vec![],
             decl_id: data.decl_id.map(|id| From::from(id)),
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         }
     }
 }
@@ -370,10 +379,10 @@ impl From<MacroData> for Def {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: None,
         }
     }
 }
-
 impl From<TypeDefData> for Def {
     fn from(data: TypeDefData) -> Def {
         Def {
@@ -386,6 +395,7 @@ impl From<TypeDefData> for Def {
             children: vec![],
             decl_id: None,
             docs: String::new(),
+            sig: data.sig.map(|s| From::from(s)),
         }
     }
 }
@@ -406,6 +416,7 @@ impl From<VariableData> for Def {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: None,
         }
     }
 }
@@ -496,3 +507,43 @@ impl From<MacroUseData> for MacroRef {
         }
     }
 }
+
+#[derive(Debug, RustcEncodable)]
+pub struct JsonSignature {
+    span: SpanData,
+    text: String,
+    ident_start: usize,
+    ident_end: usize,
+    defs: Vec<JsonSigElement>,
+    refs: Vec<JsonSigElement>,
+}
+
+impl From<Signature> for JsonSignature {
+    fn from(data: Signature) -> JsonSignature {
+        JsonSignature {
+            span: data.span,
+            text: data.text,
+            ident_start: data.ident_start,
+            ident_end: data.ident_end,
+            defs: data.defs.into_iter().map(|s| From::from(s)).collect(),
+            refs: data.refs.into_iter().map(|s| From::from(s)).collect(),
+        }
+    }
+}
+
+#[derive(Debug, RustcEncodable)]
+pub struct JsonSigElement {
+    id: Id,
+    start: usize,
+    end: usize,
+}
+
+impl From<SigElement> for JsonSigElement {
+    fn from(data: SigElement) -> JsonSigElement {
+        JsonSigElement {
+            id: From::from(data.id),
+            start: data.start,
+            end: data.end,
+        }
+    }
+}
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 0c910240b60..491521a3239 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -48,7 +48,7 @@ use rustc::session::config::CrateType::CrateTypeExecutable;
 use rustc::ty::{self, TyCtxt};
 
 use std::env;
-use std::fs::{self, File};
+use std::fs::File;
 use std::path::{Path, PathBuf};
 
 use syntax::ast::{self, NodeId, PatKind, Attribute, CRATE_NODE_ID};
@@ -152,6 +152,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     visibility: From::from(&item.vis),
                     parent: None,
                     docs: docs_for_attrs(&item.attrs),
+                    sig: self.sig_base(item),
                 }))
             }
             ast::ItemKind::Static(ref typ, mt, ref expr) => {
@@ -179,6 +180,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     type_value: ty_to_string(&typ),
                     visibility: From::from(&item.vis),
                     docs: docs_for_attrs(&item.attrs),
+                    sig: Some(self.sig_base(item)),
                 }))
             }
             ast::ItemKind::Const(ref typ, ref expr) => {
@@ -197,6 +199,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     type_value: ty_to_string(&typ),
                     visibility: From::from(&item.vis),
                     docs: docs_for_attrs(&item.attrs),
+                    sig: Some(self.sig_base(item)),
                 }))
             }
             ast::ItemKind::Mod(ref m) => {
@@ -207,6 +210,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
 
                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Mod);
                 filter!(self.span_utils, sub_span, item.span, None);
+
                 Some(Data::ModData(ModData {
                     id: item.id,
                     name: item.ident.to_string(),
@@ -217,6 +221,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     items: m.items.iter().map(|i| i.id).collect(),
                     visibility: From::from(&item.vis),
                     docs: docs_for_attrs(&item.attrs),
+                    sig: self.sig_base(item),
                 }))
             }
             ast::ItemKind::Enum(ref def, _) => {
@@ -239,6 +244,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     variants: def.variants.iter().map(|v| v.node.data.id()).collect(),
                     visibility: From::from(&item.vis),
                     docs: docs_for_attrs(&item.attrs),
+                    sig: self.sig_base(item),
                 }))
             }
             ast::ItemKind::Impl(.., ref trait_ref, ref typ, _) => {
@@ -287,18 +293,34 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         }
     }
 
-    pub fn get_field_data(&self, field: &ast::StructField,
-                          scope: NodeId) -> Option<VariableData> {
+    pub fn get_field_data(&self,
+                          field: &ast::StructField,
+                          scope: NodeId)
+                          -> Option<VariableData> {
         if let Some(ident) = field.ident {
+            let name = ident.to_string();
             let qualname = format!("::{}::{}", self.tcx.node_path_str(scope), ident);
-            let def_id = self.tcx.map.local_def_id(field.id);
-            let typ = self.tcx.item_type(def_id).to_string();
             let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon);
             filter!(self.span_utils, sub_span, field.span, None);
+            let def_id = self.tcx.map.local_def_id(field.id);
+            let typ = self.tcx.item_type(def_id).to_string();
+
+            let span = field.span;
+            let text = self.span_utils.snippet(field.span);
+            let ident_start = text.find(&name).unwrap();
+            let ident_end = ident_start + name.len();
+            let sig = Signature {
+                span: span,
+                text: text,
+                ident_start: ident_start,
+                ident_end: ident_end,
+                defs: vec![],
+                refs: vec![],
+            };
             Some(VariableData {
                 id: field.id,
                 kind: VariableKind::Field,
-                name: ident.to_string(),
+                name: name,
                 qualname: qualname,
                 span: sub_span.unwrap(),
                 scope: scope,
@@ -307,6 +329,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 type_value: typ,
                 visibility: From::from(&field.vis),
                 docs: docs_for_attrs(&field.attrs),
+                sig: Some(sig),
             })
         } else {
             None
@@ -388,9 +411,23 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
 
         let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn);
         filter!(self.span_utils, sub_span, span, None);
+
+        let name = name.to_string();
+        let text = self.span_utils.signature_string_for_span(span);
+        let ident_start = text.find(&name).unwrap();
+        let ident_end = ident_start + name.len();
+        let sig = Signature {
+            span: span,
+            text: text,
+            ident_start: ident_start,
+            ident_end: ident_end,
+            defs: vec![],
+            refs: vec![],
+        };
+
         Some(FunctionData {
             id: id,
-            name: name.to_string(),
+            name: name,
             qualname: qualname,
             declaration: decl_id,
             span: sub_span.unwrap(),
@@ -400,6 +437,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             visibility: vis,
             parent: parent_scope,
             docs: docs,
+            sig: sig,
         })
     }
 
@@ -695,6 +733,21 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         }
     }
 
+    fn sig_base(&self, item: &ast::Item) -> Signature {
+        let text = self.span_utils.signature_string_for_span(item.span);
+        let name = item.ident.to_string();
+        let ident_start = text.find(&name).expect("Name not in signature?");
+        let ident_end = ident_start + name.len();
+        Signature {
+            span: mk_sp(item.span.lo, item.span.lo + BytePos(text.len() as u32)),
+            text: text,
+            ident_start: ident_start,
+            ident_end: ident_end,
+            defs: vec![],
+            refs: vec![],
+        }
+    }
+
     #[inline]
     pub fn enclosing_scope(&self, id: NodeId) -> NodeId {
         self.tcx.map.get_enclosing_scope(id).unwrap_or(CRATE_NODE_ID)
@@ -832,7 +885,7 @@ pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>,
         },
     };
 
-    if let Err(e) = fs::create_dir_all(&root_path) {
+    if let Err(e) = rustc::util::fs::create_dir_racy(&root_path) {
         tcx.sess.err(&format!("Could not create directory {}: {}",
                               root_path.display(),
                               e));
diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs
index e06aefd865f..448bb2e7617 100644
--- a/src/librustc_save_analysis/span_utils.rs
+++ b/src/librustc_save_analysis/span_utils.rs
@@ -19,7 +19,9 @@ use std::path::Path;
 use syntax::ast;
 use syntax::parse::lexer::{self, Reader, StringReader};
 use syntax::parse::token::{self, Token};
+use syntax::parse::parser::Parser;
 use syntax::symbol::keywords;
+use syntax::tokenstream::TokenTree;
 use syntax_pos::*;
 
 #[derive(Clone)]
@@ -87,6 +89,12 @@ impl<'a> SpanUtils<'a> {
         lexer::StringReader::new(s.diagnostic(), filemap)
     }
 
+    fn span_to_tts(&self, span: Span) -> Vec<TokenTree> {
+        let srdr = self.retokenise_span(span);
+        let mut p = Parser::new(&self.sess.parse_sess, Box::new(srdr), None, false);
+        p.parse_all_token_trees().expect("Couldn't re-parse span")
+    }
+
     // Re-parses a path and returns the span for the last identifier in the path
     pub fn span_for_last_ident(&self, span: Span) -> Option<Span> {
         let mut result = None;
@@ -308,6 +316,42 @@ impl<'a> SpanUtils<'a> {
         }
     }
 
+    /// `span` must be the span for an item such as a function or struct. This
+    /// function returns the program text from the start of the span until the
+    /// 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 prev = toks.next().unwrap();
+        let first_span = prev.get_span();
+        let mut angle_count = 0;
+        for tok in toks {
+            if let TokenTree::Token(_, ref tok) = prev {
+                angle_count += match *tok {
+                    token::Eof => { break; }
+                    token::Lt => 1,
+                    token::Gt => -1,
+                    token::BinOp(token::Shl) => 2,
+                    token::BinOp(token::Shr) => -2,
+                    _ => 0,
+                };
+            }
+            if angle_count > 0 {
+                prev = tok;
+                continue;
+            }
+            if let TokenTree::Token(_, token::Semi) = tok {
+                return self.snippet(mk_sp(first_span.lo, prev.get_span().hi));
+            } else if let TokenTree::Delimited(_, ref d) = tok {
+                if d.delim == token::Brace {
+                    return self.snippet(mk_sp(first_span.lo, prev.get_span().hi));
+                }
+            }
+            prev = tok;
+        }
+        self.snippet(span)
+    }
+
     pub fn sub_span_before_token(&self, span: Span, tok: Token) -> Option<Span> {
         let mut toks = self.retokenise_span(span);
         let mut prev = toks.real_token();
diff --git a/src/librustc_trans/README.md b/src/librustc_trans/README.md
new file mode 100644
index 00000000000..cd43cbd7052
--- /dev/null
+++ b/src/librustc_trans/README.md
@@ -0,0 +1 @@
+See [librustc/README.md](../librustc/README.md).
diff --git a/src/librustc_trans/README.txt b/src/librustc_trans/README.txt
deleted file mode 100644
index 1f416d5404d..00000000000
--- a/src/librustc_trans/README.txt
+++ /dev/null
@@ -1 +0,0 @@
-See the README.md in ../librustc.
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 0ac853e99ee..9c4246e079b 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -10,7 +10,6 @@
 
 use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector, AttributePlace};
 use base;
-use build::AllocaFcx;
 use common::{type_is_fat_ptr, BlockAndBuilder, C_uint};
 use context::CrateContext;
 use cabi_x86;
@@ -25,6 +24,7 @@ use cabi_mips;
 use cabi_mips64;
 use cabi_asmjs;
 use cabi_msp430;
+use cabi_sparc;
 use machine::{llalign_of_min, llsize_of, llsize_of_alloc};
 use type_::Type;
 use type_of;
@@ -59,7 +59,7 @@ mod attr_impl {
     // The subset of llvm::Attribute needed for arguments, packed into a bitfield.
     bitflags! {
         #[derive(Default, Debug)]
-        flags ArgAttribute : u8 {
+        flags ArgAttribute : u16 {
             const ByVal     = 1 << 0,
             const NoAlias   = 1 << 1,
             const NoCapture = 1 << 2,
@@ -68,6 +68,7 @@ mod attr_impl {
             const SExt      = 1 << 5,
             const StructRet = 1 << 6,
             const ZExt      = 1 << 7,
+            const InReg     = 1 << 8,
         }
     }
 }
@@ -81,7 +82,7 @@ macro_rules! for_each_kind {
 impl ArgAttribute {
     fn for_each_kind<F>(&self, mut f: F) where F: FnMut(llvm::Attribute) {
         for_each_kind!(self, f,
-                       ByVal, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt)
+                       ByVal, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg)
     }
 }
 
@@ -99,21 +100,11 @@ impl ArgAttributes {
         self
     }
 
-    pub fn unset(&mut self, attr: ArgAttribute) -> &mut Self {
-        self.regular = self.regular - attr;
-        self
-    }
-
     pub fn set_dereferenceable(&mut self, bytes: u64) -> &mut Self {
         self.dereferenceable_bytes = bytes;
         self
     }
 
-    pub fn unset_dereferenceable(&mut self) -> &mut Self {
-        self.dereferenceable_bytes = 0;
-        self
-    }
-
     pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) {
         unsafe {
             self.regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn));
@@ -246,7 +237,7 @@ impl ArgType {
         if self.is_ignore() {
             return;
         }
-        let ccx = bcx.ccx();
+        let ccx = bcx.ccx;
         if self.is_indirect() {
             let llsz = llsize_of(ccx, self.ty);
             let llalign = llalign_of_min(ccx, self.ty);
@@ -278,7 +269,7 @@ impl ArgType {
                 //   bitcasting to the struct type yields invalid cast errors.
 
                 // We instead thus allocate some scratch space...
-                let llscratch = AllocaFcx(bcx.fcx(), ty, "abi_cast");
+                let llscratch = bcx.fcx().alloca(ty, "abi_cast");
                 base::Lifetime::Start.call(bcx, llscratch);
 
                 // ...where we first store the value...
@@ -431,7 +422,7 @@ impl FnType {
         let ret_ty = sig.output();
         let mut ret = arg_of(ret_ty, true);
 
-        if !type_is_fat_ptr(ccx.tcx(), ret_ty) {
+        if !type_is_fat_ptr(ccx, ret_ty) {
             // The `noalias` attribute on the return value is useful to a
             // function ptr caller.
             if let ty::TyBox(_) = ret_ty.sty {
@@ -496,7 +487,7 @@ impl FnType {
         for ty in inputs.iter().chain(extra_args.iter()) {
             let mut arg = arg_of(ty, false);
 
-            if type_is_fat_ptr(ccx.tcx(), ty) {
+            if type_is_fat_ptr(ccx, ty) {
                 let original_tys = arg.original_ty.field_types();
                 let sizing_tys = arg.ty.field_types();
                 assert_eq!((original_tys.len(), sizing_tys.len()), (2, 2));
@@ -569,7 +560,7 @@ impl FnType {
             };
             // Fat pointers are returned by-value.
             if !self.ret.is_ignore() {
-                if !type_is_fat_ptr(ccx.tcx(), sig.output()) {
+                if !type_is_fat_ptr(ccx, sig.output()) {
                     fixup(&mut self.ret);
                 }
             }
@@ -584,7 +575,14 @@ impl FnType {
         }
 
         match &ccx.sess().target.target.arch[..] {
-            "x86" => cabi_x86::compute_abi_info(ccx, self),
+            "x86" => {
+                let flavor = if abi == Abi::Fastcall {
+                    cabi_x86::Flavor::Fastcall
+                } else {
+                    cabi_x86::Flavor::General
+                };
+                cabi_x86::compute_abi_info(ccx, self, flavor);
+            },
             "x86_64" => if abi == Abi::SysV64 {
                 cabi_x86_64::compute_abi_info(ccx, self);
             } else if abi == Abi::Win64 || ccx.sess().target.target.options.is_like_windows {
@@ -609,6 +607,7 @@ impl FnType {
             "asmjs" => cabi_asmjs::compute_abi_info(ccx, self),
             "wasm32" => cabi_asmjs::compute_abi_info(ccx, self),
             "msp430" => cabi_msp430::compute_abi_info(ccx, self),
+            "sparc" => cabi_sparc::compute_abi_info(ccx, self),
             a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a))
         }
 
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index 8ee362bae35..31a5538a3c1 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -48,9 +48,7 @@ use std;
 use llvm::{ValueRef, True, IntEQ, IntNE};
 use rustc::ty::layout;
 use rustc::ty::{self, Ty, AdtKind};
-use build::*;
 use common::*;
-use debuginfo::DebugLoc;
 use glue;
 use base;
 use machine;
@@ -151,14 +149,14 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         | layout::UntaggedUnion { .. } | layout::RawNullablePointer { .. } => { }
         layout::Univariant { ..}
         | layout::StructWrappedNullablePointer { .. } => {
-            let (nonnull_variant, packed) = match *l {
-                layout::Univariant { ref variant, .. } => (0, variant.packed),
+            let (nonnull_variant_index, nonnull_variant, packed) = match *l {
+                layout::Univariant { ref variant, .. } => (0, variant, variant.packed),
                 layout::StructWrappedNullablePointer { nndiscr, ref nonnull, .. } =>
-                    (nndiscr, nonnull.packed),
+                    (nndiscr, nonnull, nonnull.packed),
                 _ => unreachable!()
             };
-            let fields = compute_fields(cx, t, nonnull_variant as usize, true);
-            llty.set_struct_body(&struct_llfields(cx, &fields, false, false),
+            let fields = compute_fields(cx, t, nonnull_variant_index as usize, true);
+            llty.set_struct_body(&struct_llfields(cx, &fields, nonnull_variant, false, false),
                                  packed)
         },
         _ => bug!("This function cannot handle {} with layout {:#?}", t, l)
@@ -188,7 +186,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             let fields = compute_fields(cx, t, nndiscr as usize, false);
             match name {
                 None => {
-                    Type::struct_(cx, &struct_llfields(cx, &fields, sizing, dst),
+                    Type::struct_(cx, &struct_llfields(cx, &fields, nonnull, sizing, dst),
                                   nonnull.packed)
                 }
                 Some(name) => {
@@ -203,7 +201,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             let fields = compute_fields(cx, t, 0, true);
             match name {
                 None => {
-                    let fields = struct_llfields(cx, &fields, sizing, dst);
+                    let fields = struct_llfields(cx, &fields, &variant, sizing, dst);
                     Type::struct_(cx, &fields, variant.packed)
                 }
                 Some(name) => {
@@ -291,23 +289,26 @@ fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type {
 
 
 fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fields: &Vec<Ty<'tcx>>,
+                             variant: &layout::Struct,
                              sizing: bool, dst: bool) -> Vec<Type> {
+    let fields = variant.field_index_by_increasing_offset().map(|i| fields[i as usize]);
     if sizing {
-        fields.iter().filter(|&ty| !dst || type_is_sized(cx.tcx(), *ty))
-            .map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
+        fields.filter(|ty| !dst || cx.shared().type_is_sized(*ty))
+            .map(|ty| type_of::sizing_type_of(cx, ty)).collect()
     } else {
-        fields.iter().map(|&ty| type_of::in_memory_type_of(cx, ty)).collect()
+        fields.map(|ty| type_of::in_memory_type_of(cx, ty)).collect()
     }
 }
 
 /// Obtain a representation of the discriminant sufficient to translate
 /// destructuring; this may or may not involve the actual discriminant.
-pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                t: Ty<'tcx>,
-                                scrutinee: ValueRef,
-                                range_assert: bool)
-                                -> (BranchKind, Option<ValueRef>) {
-    let l = bcx.ccx().layout_of(t);
+pub fn trans_switch<'a, 'tcx>(
+    bcx: &BlockAndBuilder<'a, 'tcx>,
+    t: Ty<'tcx>,
+    scrutinee: ValueRef,
+    range_assert: bool
+) -> (BranchKind, Option<ValueRef>) {
+    let l = bcx.ccx.layout_of(t);
     match *l {
         layout::CEnum { .. } | layout::General { .. } |
         layout::RawNullablePointer { .. } | layout::StructWrappedNullablePointer { .. } => {
@@ -329,34 +330,37 @@ pub fn is_discr_signed<'tcx>(l: &layout::Layout) -> bool {
 }
 
 /// Obtain the actual discriminant of a value.
-pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>,
-                                   scrutinee: ValueRef, cast_to: Option<Type>,
-                                   range_assert: bool)
-    -> ValueRef {
+pub fn trans_get_discr<'a, 'tcx>(
+    bcx: &BlockAndBuilder<'a, 'tcx>,
+    t: Ty<'tcx>,
+    scrutinee: ValueRef,
+    cast_to: Option<Type>,
+    range_assert: bool
+) -> ValueRef {
     let (def, substs) = match t.sty {
         ty::TyAdt(ref def, substs) if def.adt_kind() == AdtKind::Enum => (def, substs),
         _ => bug!("{} is not an enum", t)
     };
 
     debug!("trans_get_discr t: {:?}", t);
-    let l = bcx.ccx().layout_of(t);
+    let l = bcx.ccx.layout_of(t);
 
     let val = match *l {
         layout::CEnum { discr, min, max, .. } => {
             load_discr(bcx, discr, scrutinee, min, max, range_assert)
         }
         layout::General { discr, .. } => {
-            let ptr = StructGEP(bcx, scrutinee, 0);
+            let ptr = bcx.struct_gep(scrutinee, 0);
             load_discr(bcx, discr, ptr, 0, def.variants.len() as u64 - 1,
                        range_assert)
         }
-        layout::Univariant { .. } | layout::UntaggedUnion { .. } => C_u8(bcx.ccx(), 0),
+        layout::Univariant { .. } | layout::UntaggedUnion { .. } => C_u8(bcx.ccx, 0),
         layout::RawNullablePointer { nndiscr, .. } => {
             let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
-            let llptrty = type_of::sizing_type_of(bcx.ccx(),
-                monomorphize::field_ty(bcx.ccx().tcx(), substs,
+            let llptrty = type_of::sizing_type_of(bcx.ccx,
+                monomorphize::field_ty(bcx.ccx.tcx(), substs,
                 &def.variants[nndiscr as usize].fields[0]));
-            ICmp(bcx, cmp, Load(bcx, scrutinee), C_null(llptrty), DebugLoc::None)
+            bcx.icmp(cmp, bcx.load(scrutinee), C_null(llptrty))
         }
         layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
             struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee)
@@ -365,24 +369,28 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>,
     };
     match cast_to {
         None => val,
-        Some(llty) => if is_discr_signed(&l) { SExt(bcx, val, llty) } else { ZExt(bcx, val, llty) }
+        Some(llty) => if is_discr_signed(&l) { bcx.sext(val, llty) } else { bcx.zext(val, llty) }
     }
 }
 
-fn struct_wrapped_nullable_bitdiscr(bcx: Block, nndiscr: u64, discrfield: &layout::FieldPath,
-                                    scrutinee: ValueRef) -> ValueRef {
-    let llptrptr = GEPi(bcx, scrutinee,
+fn struct_wrapped_nullable_bitdiscr(
+    bcx: &BlockAndBuilder,
+    nndiscr: u64,
+    discrfield: &layout::FieldPath,
+    scrutinee: ValueRef
+) -> ValueRef {
+    let llptrptr = bcx.gepi(scrutinee,
         &discrfield.iter().map(|f| *f as usize).collect::<Vec<_>>()[..]);
-    let llptr = Load(bcx, llptrptr);
+    let llptr = bcx.load(llptrptr);
     let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
-    ICmp(bcx, cmp, llptr, C_null(val_ty(llptr)), DebugLoc::None)
+    bcx.icmp(cmp, llptr, C_null(val_ty(llptr)))
 }
 
 /// Helper for cases where the discriminant is simply loaded.
-fn load_discr(bcx: Block, ity: layout::Integer, ptr: ValueRef, min: u64, max: u64,
+fn load_discr(bcx: &BlockAndBuilder, ity: layout::Integer, ptr: ValueRef, min: u64, max: u64,
               range_assert: bool)
     -> ValueRef {
-    let llty = Type::from_integer(bcx.ccx(), ity);
+    let llty = Type::from_integer(bcx.ccx, ity);
     assert_eq!(val_ty(ptr), llty.ptr_to());
     let bits = ity.size().bits();
     assert!(bits <= 64);
@@ -395,11 +403,11 @@ fn load_discr(bcx: Block, ity: layout::Integer, ptr: ValueRef, min: u64, max: u6
         // rejected by the LLVM verifier (it would mean either an
         // empty set, which is impossible, or the entire range of the
         // type, which is pointless).
-        Load(bcx, ptr)
+        bcx.load(ptr)
     } else {
         // llvm::ConstantRange can deal with ranges that wrap around,
         // so an overflow on (max + 1) is fine.
-        LoadRangeAssert(bcx, ptr, min, max.wrapping_add(1), /* signed: */ True)
+        bcx.load_range_assert(ptr, min, max.wrapping_add(1), /* signed: */ True)
     }
 }
 
@@ -407,18 +415,17 @@ fn load_discr(bcx: Block, ity: layout::Integer, ptr: ValueRef, min: u64, max: u6
 /// discriminant-like value returned by `trans_switch`.
 ///
 /// This should ideally be less tightly tied to `_match`.
-pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, value: Disr)
-                              -> ValueRef {
-    let l = bcx.ccx().layout_of(t);
+pub fn trans_case<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>, t: Ty<'tcx>, value: Disr) -> ValueRef {
+    let l = bcx.ccx.layout_of(t);
     match *l {
         layout::CEnum { discr, .. }
         | layout::General { discr, .. }=> {
-            C_integral(Type::from_integer(bcx.ccx(), discr), value.0, true)
+            C_integral(Type::from_integer(bcx.ccx, discr), value.0, true)
         }
         layout::RawNullablePointer { .. } |
         layout::StructWrappedNullablePointer { .. } => {
             assert!(value == Disr(0) || value == Disr(1));
-            C_bool(bcx.ccx(), value != Disr(0))
+            C_bool(bcx.ccx, value != Disr(0))
         }
         _ => {
             bug!("{} does not have a discriminant. Represented as {:#?}", t, l);
@@ -428,18 +435,19 @@ pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, value: Disr)
 
 /// Set the discriminant for a new value of the given case of the given
 /// representation.
-pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>,
-                                   val: ValueRef, to: Disr) {
-    let l = bcx.ccx().layout_of(t);
+pub fn trans_set_discr<'a, 'tcx>(
+    bcx: &BlockAndBuilder<'a, 'tcx>, t: Ty<'tcx>, val: ValueRef, to: Disr
+) {
+    let l = bcx.ccx.layout_of(t);
     match *l {
         layout::CEnum{ discr, min, max, .. } => {
             assert_discr_in_range(Disr(min), Disr(max), to);
-            Store(bcx, C_integral(Type::from_integer(bcx.ccx(), discr), to.0, true),
+            bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to.0, true),
                   val);
         }
         layout::General{ discr, .. } => {
-            Store(bcx, C_integral(Type::from_integer(bcx.ccx(), discr), to.0, true),
-                  StructGEP(bcx, val, 0));
+            bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to.0, true),
+                  bcx.struct_gep(val, 0));
         }
         layout::Univariant { .. }
         | layout::UntaggedUnion { .. }
@@ -447,10 +455,10 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>,
             assert_eq!(to, Disr(0));
         }
         layout::RawNullablePointer { nndiscr, .. } => {
-            let nnty = compute_fields(bcx.ccx(), t, nndiscr as usize, false)[0];
+            let nnty = compute_fields(bcx.ccx, t, nndiscr as usize, false)[0];
             if to.0 != nndiscr {
-                let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty);
-                Store(bcx, C_null(llptrty), val);
+                let llptrty = type_of::sizing_type_of(bcx.ccx, nnty);
+                bcx.store(C_null(llptrty), val);
             }
         }
         layout::StructWrappedNullablePointer { nndiscr, ref discrfield, ref nonnull, .. } => {
@@ -459,17 +467,16 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>,
                     // Issue #34427: As workaround for LLVM bug on
                     // ARM, use memset of 0 on whole struct rather
                     // than storing null to single target field.
-                    let b = B(bcx);
-                    let llptr = b.pointercast(val, Type::i8(b.ccx).ptr_to());
-                    let fill_byte = C_u8(b.ccx, 0);
-                    let size = C_uint(b.ccx, nonnull.stride().bytes());
-                    let align = C_i32(b.ccx, nonnull.align.abi() as i32);
-                    base::call_memset(&b, llptr, fill_byte, size, align, false);
+                    let llptr = bcx.pointercast(val, Type::i8(bcx.ccx).ptr_to());
+                    let fill_byte = C_u8(bcx.ccx, 0);
+                    let size = C_uint(bcx.ccx, nonnull.stride().bytes());
+                    let align = C_i32(bcx.ccx, nonnull.align.abi() as i32);
+                    base::call_memset(bcx, llptr, fill_byte, size, align, false);
                 } else {
                     let path = discrfield.iter().map(|&i| i as usize).collect::<Vec<_>>();
-                    let llptrptr = GEPi(bcx, val, &path[..]);
+                    let llptrptr = bcx.gepi(val, &path[..]);
                     let llptrty = val_ty(llptrptr).element_type();
-                    Store(bcx, C_null(llptrty), llptrptr);
+                    bcx.store(C_null(llptrty), llptrptr);
                 }
             }
         }
@@ -477,7 +484,7 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>,
     }
 }
 
-fn target_sets_discr_via_memset<'blk, 'tcx>(bcx: Block<'blk, 'tcx>) -> bool {
+fn target_sets_discr_via_memset<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>) -> bool {
     bcx.sess().target.target.arch == "arm" || bcx.sess().target.target.arch == "aarch64"
 }
 
@@ -490,19 +497,15 @@ fn assert_discr_in_range(min: Disr, max: Disr, discr: Disr) {
 }
 
 /// Access a field, at a point when the value's case is known.
-pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>,
-                                   val: MaybeSizedValue, discr: Disr, ix: usize) -> ValueRef {
-    trans_field_ptr_builder(&bcx.build(), t, val, discr, ix)
-}
-
-/// Access a field, at a point when the value's case is known.
-pub fn trans_field_ptr_builder<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
-                                           t: Ty<'tcx>,
-                                           val: MaybeSizedValue,
-                                           discr: Disr, ix: usize)
-                                           -> ValueRef {
-    let l = bcx.ccx().layout_of(t);
-    debug!("trans_field_ptr_builder on {} represented as {:#?}", t, l);
+pub fn trans_field_ptr<'a, 'tcx>(
+    bcx: &BlockAndBuilder<'a, 'tcx>,
+    t: Ty<'tcx>,
+    val: MaybeSizedValue,
+    discr: Disr,
+    ix: usize
+) -> ValueRef {
+    let l = bcx.ccx.layout_of(t);
+    debug!("trans_field_ptr on {} represented as {:#?}", t, l);
     // Note: if this ever needs to generate conditionals (e.g., if we
     // decide to do some kind of cdr-coding-like non-unique repr
     // someday), it will need to return a possibly-new bcx as well.
@@ -510,7 +513,7 @@ pub fn trans_field_ptr_builder<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
         layout::Univariant { ref variant, .. } => {
             assert_eq!(discr, Disr(0));
             struct_field_ptr(bcx, &variant,
-             &compute_fields(bcx.ccx(), t, 0, false),
+             &compute_fields(bcx.ccx, t, 0, false),
              val, ix, false)
         }
         layout::Vector { count, .. } => {
@@ -519,61 +522,57 @@ pub fn trans_field_ptr_builder<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
             bcx.struct_gep(val.value, ix)
         }
         layout::General { discr: d, ref variants, .. } => {
-            let mut fields = compute_fields(bcx.ccx(), t, discr.0 as usize, false);
-            fields.insert(0, d.to_ty(&bcx.ccx().tcx(), false));
+            let mut fields = compute_fields(bcx.ccx, t, discr.0 as usize, false);
+            fields.insert(0, d.to_ty(&bcx.ccx.tcx(), false));
             struct_field_ptr(bcx, &variants[discr.0 as usize],
              &fields,
              val, ix + 1, true)
         }
         layout::UntaggedUnion { .. } => {
-            let fields = compute_fields(bcx.ccx(), t, 0, false);
-            let ty = type_of::in_memory_type_of(bcx.ccx(), fields[ix]);
-            if bcx.is_unreachable() { return C_undef(ty.ptr_to()); }
+            let fields = compute_fields(bcx.ccx, t, 0, false);
+            let ty = type_of::in_memory_type_of(bcx.ccx, fields[ix]);
             bcx.pointercast(val.value, ty.ptr_to())
         }
         layout::RawNullablePointer { nndiscr, .. } |
         layout::StructWrappedNullablePointer { nndiscr,  .. } if discr.0 != nndiscr => {
-            let nullfields = compute_fields(bcx.ccx(), t, (1-nndiscr) as usize, false);
+            let nullfields = compute_fields(bcx.ccx, t, (1-nndiscr) as usize, false);
             // The unit-like case might have a nonzero number of unit-like fields.
             // (e.d., Result of Either with (), as one side.)
-            let ty = type_of::type_of(bcx.ccx(), nullfields[ix]);
-            assert_eq!(machine::llsize_of_alloc(bcx.ccx(), ty), 0);
-            // The contents of memory at this pointer can't matter, but use
-            // the value that's "reasonable" in case of pointer comparison.
-            if bcx.is_unreachable() { return C_undef(ty.ptr_to()); }
+            let ty = type_of::type_of(bcx.ccx, nullfields[ix]);
+            assert_eq!(machine::llsize_of_alloc(bcx.ccx, ty), 0);
             bcx.pointercast(val.value, ty.ptr_to())
         }
         layout::RawNullablePointer { nndiscr, .. } => {
-            let nnty = compute_fields(bcx.ccx(), t, nndiscr as usize, false)[0];
+            let nnty = compute_fields(bcx.ccx, t, nndiscr as usize, false)[0];
             assert_eq!(ix, 0);
             assert_eq!(discr.0, nndiscr);
-            let ty = type_of::type_of(bcx.ccx(), nnty);
-            if bcx.is_unreachable() { return C_undef(ty.ptr_to()); }
+            let ty = type_of::type_of(bcx.ccx, nnty);
             bcx.pointercast(val.value, ty.ptr_to())
         }
         layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
             assert_eq!(discr.0, nndiscr);
             struct_field_ptr(bcx, &nonnull,
-             &compute_fields(bcx.ccx(), t, discr.0 as usize, false),
+             &compute_fields(bcx.ccx, t, discr.0 as usize, false),
              val, ix, false)
         }
         _ => bug!("element access in type without elements: {} represented as {:#?}", t, l)
     }
 }
 
-fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
-                                st: &layout::Struct, fields: &Vec<Ty<'tcx>>, val: MaybeSizedValue,
-                                ix: usize, needs_cast: bool) -> ValueRef {
-    let ccx = bcx.ccx();
+fn struct_field_ptr<'a, 'tcx>(
+    bcx: &BlockAndBuilder<'a, 'tcx>,
+    st: &layout::Struct,
+    fields: &Vec<Ty<'tcx>>,
+    val: MaybeSizedValue,
+    ix: usize,
+    needs_cast: bool
+) -> ValueRef {
     let fty = fields[ix];
-    let ll_fty = type_of::in_memory_type_of(bcx.ccx(), fty);
-    if bcx.is_unreachable() {
-        return C_undef(ll_fty.ptr_to());
-    }
+    let ccx = bcx.ccx;
 
     let ptr_val = if needs_cast {
-        let fields = fields.iter().map(|&ty| {
-            type_of::in_memory_type_of(ccx, ty)
+        let fields = st.field_index_by_increasing_offset().map(|i| {
+            type_of::in_memory_type_of(ccx, fields[i])
         }).collect::<Vec<_>>();
         let real_ty = Type::struct_(ccx, &fields[..], st.packed);
         bcx.pointercast(val.value, real_ty.ptr_to())
@@ -585,15 +584,16 @@ fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
     //   * First field - Always aligned properly
     //   * Packed struct - There is no alignment padding
     //   * Field is sized - pointer is properly aligned already
-    if ix == 0 || st.packed || type_is_sized(bcx.tcx(), fty) {
-        return bcx.struct_gep(ptr_val, ix);
+    if st.offsets[ix] == layout::Size::from_bytes(0) || st.packed ||
+        bcx.ccx.shared().type_is_sized(fty) {
+        return bcx.struct_gep(ptr_val, st.memory_index[ix] as usize);
     }
 
     // If the type of the last field is [T] or str, then we don't need to do
     // any adjusments
     match fty.sty {
         ty::TySlice(..) | ty::TyStr => {
-            return bcx.struct_gep(ptr_val, ix);
+            return bcx.struct_gep(ptr_val, st.memory_index[ix] as usize);
         }
         _ => ()
     }
@@ -605,8 +605,6 @@ fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
         return bcx.struct_gep(ptr_val, ix);
     }
 
-    let dbloc = DebugLoc::None;
-
     // We need to get the pointer manually now.
     // We do this by casting to a *i8, then offsetting it by the appropriate amount.
     // We do this instead of, say, simply adjusting the pointer from the result of a GEP
@@ -626,7 +624,7 @@ fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
 
 
     let offset = st.offsets[ix].bytes();
-    let unaligned_offset = C_uint(bcx.ccx(), offset);
+    let unaligned_offset = C_uint(bcx.ccx, offset);
 
     // Get the alignment of the field
     let (_, align) = glue::size_and_align_of_dst(bcx, fty, meta);
@@ -637,19 +635,18 @@ fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
     //   (unaligned offset + (align - 1)) & -align
 
     // Calculate offset
-    dbloc.apply(bcx.fcx());
-    let align_sub_1 = bcx.sub(align, C_uint(bcx.ccx(), 1u64));
+    let align_sub_1 = bcx.sub(align, C_uint(bcx.ccx, 1u64));
     let offset = bcx.and(bcx.add(unaligned_offset, align_sub_1),
                          bcx.neg(align));
 
     debug!("struct_field_ptr: DST field offset: {:?}", Value(offset));
 
     // Cast and adjust pointer
-    let byte_ptr = bcx.pointercast(ptr_val, Type::i8p(bcx.ccx()));
+    let byte_ptr = bcx.pointercast(ptr_val, Type::i8p(bcx.ccx));
     let byte_ptr = bcx.gep(byte_ptr, &[offset]);
 
     // Finally, cast back to the type expected
-    let ll_fty = type_of::in_memory_type_of(bcx.ccx(), fty);
+    let ll_fty = type_of::in_memory_type_of(bcx.ccx, fty);
     debug!("struct_field_ptr: Field type is {:?}", ll_fty);
     bcx.pointercast(byte_ptr, ll_fty.ptr_to())
 }
@@ -755,8 +752,12 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // offset of current value
     let mut offset = 0;
     let mut cfields = Vec::new();
-    let offsets = st.offsets.iter().map(|i| i.bytes());
-    for (&val, target_offset) in vals.iter().zip(offsets) {
+    cfields.reserve(st.offsets.len()*2);
+
+    let parts = st.field_index_by_increasing_offset().map(|i| {
+        (&vals[i], st.offsets[i].bytes())
+    });
+    for (&val, target_offset) in parts {
         if offset < target_offset {
             cfields.push(padding(ccx, target_offset - offset));
             offset = target_offset;
@@ -807,14 +808,11 @@ pub fn const_get_field<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
     let l = ccx.layout_of(t);
     match *l {
         layout::CEnum { .. } => bug!("element access in C-like enum const"),
-        layout::Univariant { .. } | layout::Vector { .. } => const_struct_field(val, ix),
+        layout::Univariant { ref variant, .. } => {
+            const_struct_field(val, variant.memory_index[ix] as usize)
+        }
+        layout::Vector { .. } => const_struct_field(val, ix),
         layout::UntaggedUnion { .. } => const_struct_field(val, 0),
-        layout::General { .. } => const_struct_field(val, ix + 1),
-        layout::RawNullablePointer { .. } => {
-            assert_eq!(ix, 0);
-            val
-        },
-        layout::StructWrappedNullablePointer{ .. } => const_struct_field(val, ix),
         _ => bug!("{} does not have fields.", t)
     }
 }
diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs
index 665e12cbe87..d6385e1ca15 100644
--- a/src/librustc_trans/asm.rs
+++ b/src/librustc_trans/asm.rs
@@ -12,7 +12,6 @@
 
 use llvm::{self, ValueRef};
 use base;
-use build::*;
 use common::*;
 use type_of;
 use type_::Type;
@@ -25,10 +24,12 @@ use syntax::ast::AsmDialect;
 use libc::{c_uint, c_char};
 
 // Take an inline assembly expression and splat it out via LLVM
-pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                    ia: &hir::InlineAsm,
-                                    outputs: Vec<(ValueRef, Ty<'tcx>)>,
-                                    mut inputs: Vec<ValueRef>) {
+pub fn trans_inline_asm<'a, 'tcx>(
+    bcx: &BlockAndBuilder<'a, 'tcx>,
+    ia: &hir::InlineAsm,
+    outputs: Vec<(ValueRef, Ty<'tcx>)>,
+    mut inputs: Vec<ValueRef>
+) {
     let mut ext_constraints = vec![];
     let mut output_types = vec![];
 
@@ -47,7 +48,7 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         if out.is_indirect {
             indirect_outputs.push(val.unwrap());
         } else {
-            output_types.push(type_of::type_of(bcx.ccx(), ty));
+            output_types.push(type_of::type_of(bcx.ccx, ty));
         }
     }
     if !indirect_outputs.is_empty() {
@@ -78,9 +79,9 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     // Depending on how many outputs we have, the return type is different
     let num_outputs = output_types.len();
     let output_type = match num_outputs {
-        0 => Type::void(bcx.ccx()),
+        0 => Type::void(bcx.ccx),
         1 => output_types[0],
-        _ => Type::struct_(bcx.ccx(), &output_types[..], false)
+        _ => Type::struct_(bcx.ccx, &output_types[..], false)
     };
 
     let dialect = match ia.dialect {
@@ -90,32 +91,33 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     let asm = CString::new(ia.asm.as_str().as_bytes()).unwrap();
     let constraint_cstr = CString::new(all_constraints).unwrap();
-    let r = InlineAsmCall(bcx,
-                          asm.as_ptr(),
-                          constraint_cstr.as_ptr(),
-                          &inputs,
-                          output_type,
-                          ia.volatile,
-                          ia.alignstack,
-                          dialect);
+    let r = bcx.inline_asm_call(
+        asm.as_ptr(),
+        constraint_cstr.as_ptr(),
+        &inputs,
+        output_type,
+        ia.volatile,
+        ia.alignstack,
+        dialect
+    );
 
     // Again, based on how many outputs we have
     let outputs = ia.outputs.iter().zip(&outputs).filter(|&(ref o, _)| !o.is_indirect);
     for (i, (_, &(val, _))) in outputs.enumerate() {
-        let v = if num_outputs == 1 { r } else { ExtractValue(bcx, r, i) };
-        Store(bcx, v, val);
+        let v = if num_outputs == 1 { r } else { bcx.extract_value(r, i) };
+        bcx.store(v, val);
     }
 
     // Store expn_id in a metadata node so we can map LLVM errors
     // back to source locations.  See #17552.
     unsafe {
         let key = "srcloc";
-        let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx().llcx(),
+        let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx.llcx(),
             key.as_ptr() as *const c_char, key.len() as c_uint);
 
-        let val: llvm::ValueRef = C_i32(bcx.ccx(), ia.expn_id.into_u32() as i32);
+        let val: llvm::ValueRef = C_i32(bcx.ccx, ia.expn_id.into_u32() as i32);
 
         llvm::LLVMSetMetadata(r, kind,
-            llvm::LLVMMDNodeInContext(bcx.ccx().llcx(), &val, 1));
+            llvm::LLVMMDNodeInContext(bcx.ccx.llcx(), &val, 1));
     }
 }
diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs
index 040a05b69a3..a147b598940 100644
--- a/src/librustc_trans/back/linker.rs
+++ b/src/librustc_trans/back/linker.rs
@@ -207,7 +207,12 @@ impl<'a> Linker for GnuLinker<'a> {
         if self.sess.target.target.options.is_like_osx {
             self.cmd.args(&["-dynamiclib", "-Wl,-dylib"]);
 
-            if self.sess.opts.cg.rpath {
+            // Note that the `osx_rpath_install_name` option here is a hack
+            // purely to support rustbuild right now, we should get a more
+            // principled solution at some point to force the compiler to pass
+            // the right `-Wl,-install_name` with an `@rpath` in it.
+            if self.sess.opts.cg.rpath ||
+               self.sess.opts.debugging_opts.osx_rpath_install_name {
                 let mut v = OsString::from("-Wl,-install_name,@rpath/");
                 v.push(out_filename.file_name().unwrap());
                 self.cmd.arg(&v);
diff --git a/src/librustc_trans/back/msvc/registry.rs b/src/librustc_trans/back/msvc/registry.rs
index 44b161a7575..8242f53896a 100644
--- a/src/librustc_trans/back/msvc/registry.rs
+++ b/src/librustc_trans/back/msvc/registry.rs
@@ -12,7 +12,7 @@ use std::io;
 use std::ffi::{OsString, OsStr};
 use std::os::windows::prelude::*;
 use std::ptr;
-use libc::{c_void, c_long};
+use libc::c_long;
 
 pub type DWORD = u32;
 type LPCWSTR = *const u16;
@@ -38,8 +38,6 @@ pub enum __HKEY__ {}
 pub type HKEY = *mut __HKEY__;
 pub type PHKEY = *mut HKEY;
 pub type REGSAM = DWORD;
-pub type LPWSTR = *mut u16;
-pub type PFILETIME = *mut c_void;
 
 #[link(name = "advapi32")]
 extern "system" {
diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs
index ff40cfda5ff..938848054fe 100644
--- a/src/librustc_trans/back/symbol_names.rs
+++ b/src/librustc_trans/back/symbol_names.rs
@@ -99,8 +99,6 @@
 
 use common::SharedCrateContext;
 use monomorphize::Instance;
-use rustc_data_structures::fmt_wrap::FmtWrap;
-use rustc_data_structures::blake2b::Blake2bHasher;
 
 use rustc::middle::weak_lang_items;
 use rustc::hir::def_id::LOCAL_CRATE;
@@ -135,7 +133,7 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 
     let tcx = scx.tcx();
 
-    let mut hasher = ty::util::TypeIdHasher::new(tcx, Blake2bHasher::new(8, &[]));
+    let mut hasher = ty::util::TypeIdHasher::<u64>::new(tcx);
 
     record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
         // the main symbol name is not necessarily unique; hash in the
@@ -158,9 +156,7 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
     });
 
     // 64 bits should be enough to avoid collisions.
-    let mut hasher = hasher.into_inner();
-    let hash_bytes = hasher.finalize();
-    format!("h{:x}", FmtWrap(hash_bytes))
+    format!("h{:016x}", hasher.finish())
 }
 
 impl<'a, 'tcx> Instance<'tcx> {
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index ffab0bde7ab..de8814f143e 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -1085,6 +1085,10 @@ fn run_work_multithreaded(sess: &Session,
 pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
     let (pname, mut cmd, _) = get_linker(sess);
 
+    for arg in &sess.target.target.options.asm_args {
+        cmd.arg(arg);
+    }
+
     cmd.arg("-c").arg("-o").arg(&outputs.path(OutputType::Object))
                            .arg(&outputs.temp_path(OutputType::Assembly, None));
     debug!("{:?}", cmd);
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index f70c24c3ccb..76bb1c56af3 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -23,8 +23,6 @@
 //!     but one TypeRef corresponds to many `Ty`s; for instance, tup(int, int,
 //!     int) and rec(x=int, y=int, z=int) will have the same TypeRef.
 
-#![allow(non_camel_case_types)]
-
 use super::CrateTranslation;
 use super::ModuleLlvm;
 use super::ModuleSource;
@@ -37,7 +35,7 @@ use back::symbol_export::{self, ExportedSymbols};
 use llvm::{Linkage, ValueRef, Vector, get_param};
 use llvm;
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
-use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
+use middle::lang_items::StartFnLangItem;
 use rustc::ty::subst::Substs;
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
@@ -51,20 +49,18 @@ use session::{self, DataTypeKind, Session};
 use abi::{self, Abi, FnType};
 use adt;
 use attributes;
-use build::*;
-use builder::{Builder, noname};
+use builder::Builder;
 use callee::{Callee};
-use common::{Block, C_bool, C_bytes_in_context, C_i32, C_uint};
+use common::{BlockAndBuilder, C_bool, C_bytes_in_context, C_i32, C_uint};
 use collector::{self, TransItemCollectionMode};
-use common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef};
+use common::{C_struct_in_context, C_u64, C_undef};
 use common::{CrateContext, FunctionContext};
-use common::{Result};
 use common::{fulfill_obligation};
 use common::{type_is_zero_size, val_ty};
 use common;
 use consts;
 use context::{SharedCrateContext, CrateContextList};
-use debuginfo::{self, DebugLoc};
+use debuginfo;
 use declare;
 use machine;
 use machine::{llalign_of_min, llsize_of};
@@ -81,11 +77,8 @@ use value::Value;
 use Disr;
 use util::nodemap::{NodeSet, FxHashMap, FxHashSet};
 
-use arena::TypedArena;
 use libc::c_uint;
 use std::ffi::{CStr, CString};
-use std::cell::{Cell, RefCell};
-use std::ptr;
 use std::rc::Rc;
 use std::str;
 use std::i32;
@@ -95,52 +88,6 @@ use rustc::hir;
 use rustc::ty::layout::{self, Layout};
 use syntax::ast;
 
-thread_local! {
-    static TASK_LOCAL_INSN_KEY: RefCell<Option<Vec<&'static str>>> = {
-        RefCell::new(None)
-    }
-}
-
-pub fn with_insn_ctxt<F>(blk: F)
-    where F: FnOnce(&[&'static str])
-{
-    TASK_LOCAL_INSN_KEY.with(move |slot| {
-        slot.borrow().as_ref().map(move |s| blk(s));
-    })
-}
-
-pub fn init_insn_ctxt() {
-    TASK_LOCAL_INSN_KEY.with(|slot| {
-        *slot.borrow_mut() = Some(Vec::new());
-    });
-}
-
-pub struct _InsnCtxt {
-    _cannot_construct_outside_of_this_module: (),
-}
-
-impl Drop for _InsnCtxt {
-    fn drop(&mut self) {
-        TASK_LOCAL_INSN_KEY.with(|slot| {
-            if let Some(ctx) = slot.borrow_mut().as_mut() {
-                ctx.pop();
-            }
-        })
-    }
-}
-
-pub fn push_ctxt(s: &'static str) -> _InsnCtxt {
-    debug!("new InsnCtxt: {}", s);
-    TASK_LOCAL_INSN_KEY.with(|slot| {
-        if let Some(ctx) = slot.borrow_mut().as_mut() {
-            ctx.push(s)
-        }
-    });
-    _InsnCtxt {
-        _cannot_construct_outside_of_this_module: (),
-    }
-}
-
 pub struct StatRecorder<'a, 'tcx: 'a> {
     ccx: &'a CrateContext<'a, 'tcx>,
     name: Option<String>,
@@ -162,10 +109,7 @@ impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> {
     fn drop(&mut self) {
         if self.ccx.sess().trans_stats() {
             let iend = self.ccx.stats().n_llvm_insns.get();
-            self.ccx
-                .stats()
-                .fn_stats
-                .borrow_mut()
+            self.ccx.stats().fn_stats.borrow_mut()
                 .push((self.name.take().unwrap(), iend - self.istart));
             self.ccx.stats().n_fns.set(self.ccx.stats().n_fns.get() + 1);
             // Reset LLVM insn count to avoid compound costs.
@@ -174,52 +118,14 @@ impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> {
     }
 }
 
-pub fn get_meta(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
-    StructGEP(bcx, fat_ptr, abi::FAT_PTR_EXTRA)
-}
-
-pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
-    StructGEP(bcx, fat_ptr, abi::FAT_PTR_ADDR)
+pub fn get_meta(bcx: &Builder, fat_ptr: ValueRef) -> ValueRef {
+    bcx.struct_gep(fat_ptr, abi::FAT_PTR_EXTRA)
 }
 
-pub fn get_meta_builder(b: &Builder, fat_ptr: ValueRef) -> ValueRef {
-    b.struct_gep(fat_ptr, abi::FAT_PTR_EXTRA)
+pub fn get_dataptr(bcx: &Builder, fat_ptr: ValueRef) -> ValueRef {
+    bcx.struct_gep(fat_ptr, abi::FAT_PTR_ADDR)
 }
 
-pub fn get_dataptr_builder(b: &Builder, fat_ptr: ValueRef) -> ValueRef {
-    b.struct_gep(fat_ptr, abi::FAT_PTR_ADDR)
-}
-
-fn require_alloc_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, info_ty: Ty<'tcx>, it: LangItem) -> DefId {
-    match bcx.tcx().lang_items.require(it) {
-        Ok(id) => id,
-        Err(s) => {
-            bcx.sess().fatal(&format!("allocation of `{}` {}", info_ty, s));
-        }
-    }
-}
-
-// The following malloc_raw_dyn* functions allocate a box to contain
-// a given type, but with a potentially dynamic size.
-
-pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                  llty_ptr: Type,
-                                  info_ty: Ty<'tcx>,
-                                  size: ValueRef,
-                                  align: ValueRef,
-                                  debug_loc: DebugLoc)
-                                  -> Result<'blk, 'tcx> {
-    let _icx = push_ctxt("malloc_raw_exchange");
-
-    // Allocate space:
-    let def_id = require_alloc_fn(bcx, info_ty, ExchangeMallocFnLangItem);
-    let r = Callee::def(bcx.ccx(), def_id, bcx.tcx().intern_substs(&[]))
-        .call(bcx, debug_loc, &[size, align], None);
-
-    Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr))
-}
-
-
 pub fn bin_op_to_icmp_predicate(op: hir::BinOp_,
                                 signed: bool)
                                 -> llvm::IntPredicate {
@@ -254,18 +160,18 @@ pub fn bin_op_to_fcmp_predicate(op: hir::BinOp_) -> llvm::RealPredicate {
     }
 }
 
-pub fn compare_simd_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                      lhs: ValueRef,
-                                      rhs: ValueRef,
-                                      t: Ty<'tcx>,
-                                      ret_ty: Type,
-                                      op: hir::BinOp_,
-                                      debug_loc: DebugLoc)
-                                      -> ValueRef {
+pub fn compare_simd_types<'a, 'tcx>(
+    bcx: &BlockAndBuilder<'a, 'tcx>,
+    lhs: ValueRef,
+    rhs: ValueRef,
+    t: Ty<'tcx>,
+    ret_ty: Type,
+    op: hir::BinOp_
+) -> ValueRef {
     let signed = match t.sty {
         ty::TyFloat(_) => {
             let cmp = bin_op_to_fcmp_predicate(op);
-            return SExt(bcx, FCmp(bcx, cmp, lhs, rhs, debug_loc), ret_ty);
+            return bcx.sext(bcx.fcmp(cmp, lhs, rhs), ret_ty);
         },
         ty::TyUint(_) => false,
         ty::TyInt(_) => true,
@@ -277,7 +183,7 @@ pub fn compare_simd_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     // to get the correctly sized type. This will compile to a single instruction
     // once the IR is converted to assembly if the SIMD instruction is supported
     // by the target architecture.
-    SExt(bcx, ICmp(bcx, cmp, lhs, rhs, debug_loc), ret_ty)
+    bcx.sext(bcx.icmp(cmp, lhs, rhs), ret_ty)
 }
 
 /// Retrieve the information we are losing (making dynamic) in an unsizing
@@ -311,11 +217,12 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
 }
 
 /// Coerce `src` to `dst_ty`. `src_ty` must be a thin pointer.
-pub fn unsize_thin_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                   src: ValueRef,
-                                   src_ty: Ty<'tcx>,
-                                   dst_ty: Ty<'tcx>)
-                                   -> (ValueRef, ValueRef) {
+pub fn unsize_thin_ptr<'a, 'tcx>(
+    bcx: &BlockAndBuilder<'a, 'tcx>,
+    src: ValueRef,
+    src_ty: Ty<'tcx>,
+    dst_ty: Ty<'tcx>
+) -> (ValueRef, ValueRef) {
     debug!("unsize_thin_ptr: {:?} => {:?}", src_ty, dst_ty);
     match (&src_ty.sty, &dst_ty.sty) {
         (&ty::TyBox(a), &ty::TyBox(b)) |
@@ -325,10 +232,9 @@ pub fn unsize_thin_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
          &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) |
         (&ty::TyRawPtr(ty::TypeAndMut { ty: a, .. }),
          &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => {
-            assert!(common::type_is_sized(bcx.tcx(), a));
-            let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), b).ptr_to();
-            (PointerCast(bcx, src, ptr_ty),
-             unsized_info(bcx.ccx(), a, b, None))
+            assert!(bcx.ccx.shared().type_is_sized(a));
+            let ptr_ty = type_of::in_memory_type_of(bcx.ccx, b).ptr_to();
+            (bcx.pointercast(src, ptr_ty), unsized_info(bcx.ccx, a, b, None))
         }
         _ => bug!("unsize_thin_ptr: called on bad types"),
     }
@@ -336,24 +242,24 @@ pub fn unsize_thin_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
 /// Coerce `src`, which is a reference to a value of type `src_ty`,
 /// to a value of type `dst_ty` and store the result in `dst`
-pub fn coerce_unsized_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                       src: ValueRef,
-                                       src_ty: Ty<'tcx>,
-                                       dst: ValueRef,
-                                       dst_ty: Ty<'tcx>) {
+pub fn coerce_unsized_into<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+                                     src: ValueRef,
+                                     src_ty: Ty<'tcx>,
+                                     dst: ValueRef,
+                                     dst_ty: Ty<'tcx>) {
     match (&src_ty.sty, &dst_ty.sty) {
         (&ty::TyBox(..), &ty::TyBox(..)) |
         (&ty::TyRef(..), &ty::TyRef(..)) |
         (&ty::TyRef(..), &ty::TyRawPtr(..)) |
         (&ty::TyRawPtr(..), &ty::TyRawPtr(..)) => {
-            let (base, info) = if common::type_is_fat_ptr(bcx.tcx(), src_ty) {
+            let (base, info) = if common::type_is_fat_ptr(bcx.ccx, src_ty) {
                 // fat-ptr to fat-ptr unsize preserves the vtable
                 // i.e. &'a fmt::Debug+Send => &'a fmt::Debug
                 // So we need to pointercast the base to ensure
                 // the types match up.
                 let (base, info) = load_fat_ptr(bcx, src, src_ty);
-                let llcast_ty = type_of::fat_ptr_base_ty(bcx.ccx(), dst_ty);
-                let base = PointerCast(bcx, base, llcast_ty);
+                let llcast_ty = type_of::fat_ptr_base_ty(bcx.ccx, dst_ty);
+                let base = bcx.pointercast(base, llcast_ty);
                 (base, info)
             } else {
                 let base = load_ty(bcx, src, src_ty);
@@ -377,7 +283,7 @@ pub fn coerce_unsized_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
             let iter = src_fields.zip(dst_fields).enumerate();
             for (i, (src_fty, dst_fty)) in iter {
-                if type_is_zero_size(bcx.ccx(), dst_fty) {
+                if type_is_zero_size(bcx.ccx, dst_fty) {
                     continue;
                 }
 
@@ -415,8 +321,10 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx
     }
 }
 
-pub fn cast_shift_expr_rhs(cx: Block, op: hir::BinOp_, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
-    cast_shift_rhs(op, lhs, rhs, |a, b| Trunc(cx, a, b), |a, b| ZExt(cx, a, b))
+pub fn cast_shift_expr_rhs(
+    cx: &BlockAndBuilder, op: hir::BinOp_, lhs: ValueRef, rhs: ValueRef
+) -> ValueRef {
+    cast_shift_rhs(op, lhs, rhs, |a, b| cx.trunc(a, b), |a, b| cx.zext(a, b))
 }
 
 pub fn cast_shift_const_rhs(op: hir::BinOp_, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
@@ -462,42 +370,6 @@ fn cast_shift_rhs<F, G>(op: hir::BinOp_,
     }
 }
 
-pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                          llfn: ValueRef,
-                          llargs: &[ValueRef],
-                          debug_loc: DebugLoc)
-                          -> (ValueRef, Block<'blk, 'tcx>) {
-    let _icx = push_ctxt("invoke_");
-    if bcx.unreachable.get() {
-        return (C_null(Type::i8(bcx.ccx())), bcx);
-    }
-
-    if need_invoke(bcx) {
-        debug!("invoking {:?} at {:?}", Value(llfn), bcx.llbb);
-        for &llarg in llargs {
-            debug!("arg: {:?}", Value(llarg));
-        }
-        let normal_bcx = bcx.fcx.new_block("normal-return");
-        let landing_pad = bcx.fcx.get_landing_pad();
-
-        let llresult = Invoke(bcx,
-                              llfn,
-                              &llargs[..],
-                              normal_bcx.llbb,
-                              landing_pad,
-                              debug_loc);
-        return (llresult, normal_bcx);
-    } else {
-        debug!("calling {:?} at {:?}", Value(llfn), bcx.llbb);
-        for &llarg in llargs {
-            debug!("arg: {:?}", Value(llarg));
-        }
-
-        let llresult = Call(bcx, llfn, &llargs[..], debug_loc);
-        return (llresult, bcx);
-    }
-}
-
 /// Returns whether this session's target will use SEH-based unwinding.
 ///
 /// This is only true for MSVC targets, and even then the 64-bit MSVC target
@@ -507,18 +379,6 @@ pub fn wants_msvc_seh(sess: &Session) -> bool {
     sess.target.target.options.is_like_msvc
 }
 
-pub fn avoid_invoke(bcx: Block) -> bool {
-    bcx.sess().no_landing_pads() || bcx.lpad().is_some()
-}
-
-pub fn need_invoke(bcx: Block) -> bool {
-    if avoid_invoke(bcx) {
-        false
-    } else {
-        bcx.fcx.needs_invoke()
-    }
-}
-
 pub fn call_assume<'a, 'tcx>(b: &Builder<'a, 'tcx>, val: ValueRef) {
     let assume_intrinsic = b.ccx.get_intrinsic("llvm.assume");
     b.call(assume_intrinsic, &[val], None);
@@ -527,14 +387,7 @@ pub fn call_assume<'a, 'tcx>(b: &Builder<'a, 'tcx>, val: ValueRef) {
 /// Helper for loading values from memory. Does the necessary conversion if the in-memory type
 /// differs from the type used for SSA values. Also handles various special cases where the type
 /// gives us better information about what we are loading.
-pub fn load_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, ptr: ValueRef, t: Ty<'tcx>) -> ValueRef {
-    if cx.unreachable.get() {
-        return C_undef(type_of::type_of(cx.ccx(), t));
-    }
-    load_ty_builder(&B(cx), ptr, t)
-}
-
-pub fn load_ty_builder<'a, 'tcx>(b: &Builder<'a, 'tcx>, ptr: ValueRef, t: Ty<'tcx>) -> ValueRef {
+pub fn load_ty<'a, 'tcx>(b: &Builder<'a, 'tcx>, ptr: ValueRef, t: Ty<'tcx>) -> ValueRef {
     let ccx = b.ccx;
     if type_is_zero_size(ccx, t) {
         return C_undef(type_of::type_of(ccx, t));
@@ -559,8 +412,7 @@ pub fn load_ty_builder<'a, 'tcx>(b: &Builder<'a, 'tcx>, ptr: ValueRef, t: Ty<'tc
         // a char is a Unicode codepoint, and so takes values from 0
         // to 0x10FFFF inclusive only.
         b.load_range_assert(ptr, 0, 0x10FFFF + 1, llvm::False)
-    } else if (t.is_region_ptr() || t.is_unique()) &&
-              !common::type_is_fat_ptr(ccx.tcx(), t) {
+    } else if (t.is_region_ptr() || t.is_unique()) && !common::type_is_fat_ptr(ccx, t) {
         b.load_nonnull(ptr)
     } else {
         b.load(ptr)
@@ -569,54 +421,32 @@ pub fn load_ty_builder<'a, 'tcx>(b: &Builder<'a, 'tcx>, ptr: ValueRef, t: Ty<'tc
 
 /// Helper for storing values in memory. Does the necessary conversion if the in-memory type
 /// differs from the type used for SSA values.
-pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t: Ty<'tcx>) {
-    if cx.unreachable.get() {
-        return;
-    }
-
+pub fn store_ty<'a, 'tcx>(cx: &BlockAndBuilder<'a, 'tcx>, v: ValueRef, dst: ValueRef, t: Ty<'tcx>) {
     debug!("store_ty: {:?} : {:?} <- {:?}", Value(dst), t, Value(v));
 
-    if common::type_is_fat_ptr(cx.tcx(), t) {
-        let lladdr = ExtractValue(cx, v, abi::FAT_PTR_ADDR);
-        let llextra = ExtractValue(cx, v, abi::FAT_PTR_EXTRA);
+    if common::type_is_fat_ptr(cx.ccx, t) {
+        let lladdr = cx.extract_value(v, abi::FAT_PTR_ADDR);
+        let llextra = cx.extract_value(v, abi::FAT_PTR_EXTRA);
         store_fat_ptr(cx, lladdr, llextra, dst, t);
     } else {
-        Store(cx, from_immediate(cx, v), dst);
+        cx.store(from_immediate(cx, v), dst);
     }
 }
 
-pub fn store_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
-                                 data: ValueRef,
-                                 extra: ValueRef,
-                                 dst: ValueRef,
-                                 _ty: Ty<'tcx>) {
+pub fn store_fat_ptr<'a, 'tcx>(cx: &BlockAndBuilder<'a, 'tcx>,
+                               data: ValueRef,
+                               extra: ValueRef,
+                               dst: ValueRef,
+                               _ty: Ty<'tcx>) {
     // FIXME: emit metadata
-    Store(cx, data, get_dataptr(cx, dst));
-    Store(cx, extra, get_meta(cx, dst));
+    cx.store(data, get_dataptr(cx, dst));
+    cx.store(extra, get_meta(cx, dst));
 }
 
-pub fn load_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
-                                src: ValueRef,
-                                ty: Ty<'tcx>)
-                                -> (ValueRef, ValueRef)
-{
-    if cx.unreachable.get() {
-        // FIXME: remove me
-        return (Load(cx, get_dataptr(cx, src)),
-                Load(cx, get_meta(cx, src)));
-    }
-
-    load_fat_ptr_builder(&B(cx), src, ty)
-}
-
-pub fn load_fat_ptr_builder<'a, 'tcx>(
-    b: &Builder<'a, 'tcx>,
-    src: ValueRef,
-    t: Ty<'tcx>)
-    -> (ValueRef, ValueRef)
-{
-
-    let ptr = get_dataptr_builder(b, src);
+pub fn load_fat_ptr<'a, 'tcx>(
+    b: &Builder<'a, 'tcx>, src: ValueRef, t: Ty<'tcx>
+) -> (ValueRef, ValueRef) {
+    let ptr = get_dataptr(b, src);
     let ptr = if t.is_region_ptr() || t.is_unique() {
         b.load_nonnull(ptr)
     } else {
@@ -624,122 +454,63 @@ pub fn load_fat_ptr_builder<'a, 'tcx>(
     };
 
     // FIXME: emit metadata on `meta`.
-    let meta = b.load(get_meta_builder(b, src));
+    let meta = b.load(get_meta(b, src));
 
     (ptr, meta)
 }
 
-pub fn from_immediate(bcx: Block, val: ValueRef) -> ValueRef {
-    if val_ty(val) == Type::i1(bcx.ccx()) {
-        ZExt(bcx, val, Type::i8(bcx.ccx()))
+pub fn from_immediate(bcx: &BlockAndBuilder, val: ValueRef) -> ValueRef {
+    if val_ty(val) == Type::i1(bcx.ccx) {
+        bcx.zext(val, Type::i8(bcx.ccx))
     } else {
         val
     }
 }
 
-pub fn to_immediate(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef {
+pub fn to_immediate(bcx: &BlockAndBuilder, val: ValueRef, ty: Ty) -> ValueRef {
     if ty.is_bool() {
-        Trunc(bcx, val, Type::i1(bcx.ccx()))
+        bcx.trunc(val, Type::i1(bcx.ccx))
     } else {
         val
     }
 }
 
-pub fn with_cond<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, val: ValueRef, f: F) -> Block<'blk, 'tcx>
-    where F: FnOnce(Block<'blk, 'tcx>) -> Block<'blk, 'tcx>
-{
-    let _icx = push_ctxt("with_cond");
-
-    if bcx.unreachable.get() || common::const_to_opt_uint(val) == Some(0) {
-        return bcx;
-    }
-
-    let fcx = bcx.fcx;
-    let next_cx = fcx.new_block("next");
-    let cond_cx = fcx.new_block("cond");
-    CondBr(bcx, val, cond_cx.llbb, next_cx.llbb, DebugLoc::None);
-    let after_cx = f(cond_cx);
-    if !after_cx.terminated.get() {
-        Br(after_cx, next_cx.llbb, DebugLoc::None);
-    }
-    next_cx
-}
-
 pub enum Lifetime { Start, End }
 
-// If LLVM lifetime intrinsic support is enabled (i.e. optimizations
-// on), and `ptr` is nonzero-sized, then extracts the size of `ptr`
-// and the intrinsic for `lt` and passes them to `emit`, which is in
-// charge of generating code to call the passed intrinsic on whatever
-// block of generated code is targetted for the intrinsic.
-//
-// If LLVM lifetime intrinsic support is disabled (i.e.  optimizations
-// off) or `ptr` is zero-sized, then no-op (does not call `emit`).
-fn core_lifetime_emit<'blk, 'tcx, F>(ccx: &'blk CrateContext<'blk, 'tcx>,
-                                     ptr: ValueRef,
-                                     lt: Lifetime,
-                                     emit: F)
-    where F: FnOnce(&'blk CrateContext<'blk, 'tcx>, machine::llsize, ValueRef)
-{
-    if ccx.sess().opts.optimize == config::OptLevel::No {
-        return;
-    }
-
-    let _icx = push_ctxt(match lt {
-        Lifetime::Start => "lifetime_start",
-        Lifetime::End => "lifetime_end"
-    });
-
-    let size = machine::llsize_of_alloc(ccx, val_ty(ptr).element_type());
-    if size == 0 {
-        return;
-    }
-
-    let lifetime_intrinsic = ccx.get_intrinsic(match lt {
-        Lifetime::Start => "llvm.lifetime.start",
-        Lifetime::End => "llvm.lifetime.end"
-    });
-    emit(ccx, size, lifetime_intrinsic)
-}
-
 impl Lifetime {
+    // If LLVM lifetime intrinsic support is enabled (i.e. optimizations
+    // on), and `ptr` is nonzero-sized, then extracts the size of `ptr`
+    // and the intrinsic for `lt` and passes them to `emit`, which is in
+    // charge of generating code to call the passed intrinsic on whatever
+    // block of generated code is targetted for the intrinsic.
+    //
+    // If LLVM lifetime intrinsic support is disabled (i.e.  optimizations
+    // off) or `ptr` is zero-sized, then no-op (does not call `emit`).
     pub fn call(self, b: &Builder, ptr: ValueRef) {
-        core_lifetime_emit(b.ccx, ptr, self, |ccx, size, lifetime_intrinsic| {
-            let ptr = b.pointercast(ptr, Type::i8p(ccx));
-            b.call(lifetime_intrinsic, &[C_u64(ccx, size), ptr], None);
-        });
-    }
-}
+        if b.ccx.sess().opts.optimize == config::OptLevel::No {
+            return;
+        }
 
-pub fn call_lifetime_start(bcx: Block, ptr: ValueRef) {
-    if !bcx.unreachable.get() {
-        Lifetime::Start.call(&bcx.build(), ptr);
-    }
-}
+        let size = machine::llsize_of_alloc(b.ccx, val_ty(ptr).element_type());
+        if size == 0 {
+            return;
+        }
 
-pub fn call_lifetime_end(bcx: Block, ptr: ValueRef) {
-    if !bcx.unreachable.get() {
-        Lifetime::End.call(&bcx.build(), ptr);
-    }
-}
+        let lifetime_intrinsic = b.ccx.get_intrinsic(match self {
+            Lifetime::Start => "llvm.lifetime.start",
+            Lifetime::End => "llvm.lifetime.end"
+        });
 
-// Generates code for resumption of unwind at the end of a landing pad.
-pub fn trans_unwind_resume(bcx: Block, lpval: ValueRef) {
-    if !bcx.sess().target.target.options.custom_unwind_resume {
-        Resume(bcx, lpval);
-    } else {
-        let exc_ptr = ExtractValue(bcx, lpval, 0);
-        bcx.fcx.eh_unwind_resume()
-            .call(bcx, DebugLoc::None, &[exc_ptr], None);
+        let ptr = b.pointercast(ptr, Type::i8p(b.ccx));
+        b.call(lifetime_intrinsic, &[C_u64(b.ccx, size), ptr], None);
     }
 }
 
-pub fn call_memcpy<'bcx, 'tcx>(b: &Builder<'bcx, 'tcx>,
+pub fn call_memcpy<'a, 'tcx>(b: &Builder<'a, 'tcx>,
                                dst: ValueRef,
                                src: ValueRef,
                                n_bytes: ValueRef,
                                align: u32) {
-    let _icx = push_ctxt("call_memcpy");
     let ccx = b.ccx;
     let ptr_width = &ccx.sess().target.target.target_pointer_width[..];
     let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width);
@@ -752,11 +523,12 @@ pub fn call_memcpy<'bcx, 'tcx>(b: &Builder<'bcx, 'tcx>,
     b.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None);
 }
 
-pub fn memcpy_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, dst: ValueRef, src: ValueRef, t: Ty<'tcx>) {
-    let _icx = push_ctxt("memcpy_ty");
-    let ccx = bcx.ccx();
+pub fn memcpy_ty<'a, 'tcx>(
+    bcx: &BlockAndBuilder<'a, 'tcx>, dst: ValueRef, src: ValueRef, t: Ty<'tcx>
+) {
+    let ccx = bcx.ccx;
 
-    if type_is_zero_size(ccx, t) || bcx.unreachable.get() {
+    if type_is_zero_size(ccx, t) {
         return;
     }
 
@@ -764,8 +536,8 @@ pub fn memcpy_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, dst: ValueRef, src: ValueRe
         let llty = type_of::type_of(ccx, t);
         let llsz = llsize_of(ccx, llty);
         let llalign = type_of::align_of(ccx, t);
-        call_memcpy(&B(bcx), dst, src, llsz, llalign as u32);
-    } else if common::type_is_fat_ptr(bcx.tcx(), t) {
+        call_memcpy(bcx, dst, src, llsz, llalign as u32);
+    } else if common::type_is_fat_ptr(bcx.ccx, t) {
         let (data, extra) = load_fat_ptr(bcx, src, t);
         store_fat_ptr(bcx, data, extra, dst, t);
     } else {
@@ -773,232 +545,22 @@ pub fn memcpy_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, dst: ValueRef, src: ValueRe
     }
 }
 
-pub fn init_zero_mem<'blk, 'tcx>(cx: Block<'blk, 'tcx>, llptr: ValueRef, t: Ty<'tcx>) {
-    if cx.unreachable.get() {
-        return;
-    }
-    let _icx = push_ctxt("init_zero_mem");
-    let bcx = cx;
-    memfill(&B(bcx), llptr, t, 0);
-}
-
-// Always use this function instead of storing a constant byte to the memory
-// in question. e.g. if you store a zero constant, LLVM will drown in vreg
-// allocation for large data structures, and the generated code will be
-// awful. (A telltale sign of this is large quantities of
-// `mov [byte ptr foo],0` in the generated code.)
-fn memfill<'a, 'tcx>(b: &Builder<'a, 'tcx>, llptr: ValueRef, ty: Ty<'tcx>, byte: u8) {
-    let _icx = push_ctxt("memfill");
-    let ccx = b.ccx;
-    let llty = type_of::type_of(ccx, ty);
-    let llptr = b.pointercast(llptr, Type::i8(ccx).ptr_to());
-    let llzeroval = C_u8(ccx, byte);
-    let size = machine::llsize_of(ccx, llty);
-    let align = C_i32(ccx, type_of::align_of(ccx, ty) as i32);
-    call_memset(b, llptr, llzeroval, size, align, false);
-}
-
-pub fn call_memset<'bcx, 'tcx>(b: &Builder<'bcx, 'tcx>,
+pub fn call_memset<'a, 'tcx>(b: &Builder<'a, 'tcx>,
                                ptr: ValueRef,
                                fill_byte: ValueRef,
                                size: ValueRef,
                                align: ValueRef,
-                               volatile: bool) {
-    let ccx = b.ccx;
-    let ptr_width = &ccx.sess().target.target.target_pointer_width[..];
+                               volatile: bool) -> ValueRef {
+    let ptr_width = &b.ccx.sess().target.target.target_pointer_width[..];
     let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width);
-    let llintrinsicfn = ccx.get_intrinsic(&intrinsic_key);
-    let volatile = C_bool(ccx, volatile);
-    b.call(llintrinsicfn, &[ptr, fill_byte, size, align, volatile], None);
+    let llintrinsicfn = b.ccx.get_intrinsic(&intrinsic_key);
+    let volatile = C_bool(b.ccx, volatile);
+    b.call(llintrinsicfn, &[ptr, fill_byte, size, align, volatile], None)
 }
 
-pub fn alloc_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                            ty: Ty<'tcx>,
-                            name: &str) -> ValueRef {
+pub fn alloc_ty<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>, ty: Ty<'tcx>, name: &str) -> ValueRef {
     assert!(!ty.has_param_types());
-    alloca(bcx, type_of::type_of(bcx.ccx(), ty), name)
-}
-
-pub fn alloca(cx: Block, ty: Type, name: &str) -> ValueRef {
-    let _icx = push_ctxt("alloca");
-    if cx.unreachable.get() {
-        unsafe {
-            return llvm::LLVMGetUndef(ty.ptr_to().to_ref());
-        }
-    }
-    DebugLoc::None.apply(cx.fcx);
-    Alloca(cx, ty, name)
-}
-
-impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
-    /// Create a function context for the given function.
-    /// Beware that you must call `fcx.init` or `fcx.bind_args`
-    /// before doing anything with the returned function context.
-    pub fn new(ccx: &'blk CrateContext<'blk, 'tcx>,
-               llfndecl: ValueRef,
-               fn_ty: FnType,
-               definition: Option<(Instance<'tcx>, &ty::FnSig<'tcx>, Abi)>,
-               block_arena: &'blk TypedArena<common::BlockS<'blk, 'tcx>>)
-               -> FunctionContext<'blk, 'tcx> {
-        let (param_substs, def_id) = match definition {
-            Some((instance, ..)) => {
-                common::validate_substs(instance.substs);
-                (instance.substs, Some(instance.def))
-            }
-            None => (ccx.tcx().intern_substs(&[]), None)
-        };
-
-        let local_id = def_id.and_then(|id| ccx.tcx().map.as_local_node_id(id));
-
-        debug!("FunctionContext::new({})",
-               definition.map_or(String::new(), |d| d.0.to_string()));
-
-        let no_debug = if let Some(id) = local_id {
-            ccx.tcx().map.attrs(id)
-               .iter().any(|item| item.check_name("no_debug"))
-        } else if let Some(def_id) = def_id {
-            ccx.sess().cstore.item_attrs(def_id)
-               .iter().any(|item| item.check_name("no_debug"))
-        } else {
-            false
-        };
-
-        let mir = def_id.map(|id| ccx.tcx().item_mir(id));
-
-        let debug_context = if let (false, Some((instance, sig, abi)), &Some(ref mir)) =
-                (no_debug, definition, &mir) {
-            debuginfo::create_function_debug_context(ccx, instance, sig, abi, llfndecl, mir)
-        } else {
-            debuginfo::empty_function_debug_context(ccx)
-        };
-
-        FunctionContext {
-            mir: mir,
-            llfn: llfndecl,
-            llretslotptr: Cell::new(None),
-            param_env: ccx.tcx().empty_parameter_environment(),
-            alloca_insert_pt: Cell::new(None),
-            landingpad_alloca: Cell::new(None),
-            fn_ty: fn_ty,
-            param_substs: param_substs,
-            span: None,
-            block_arena: block_arena,
-            lpad_arena: TypedArena::new(),
-            ccx: ccx,
-            debug_context: debug_context,
-            scopes: RefCell::new(Vec::new()),
-        }
-    }
-
-    /// Performs setup on a newly created function, creating the entry
-    /// scope block and allocating space for the return pointer.
-    pub fn init(&'blk self, skip_retptr: bool) -> Block<'blk, 'tcx> {
-        let entry_bcx = self.new_block("entry-block");
-
-        // Use a dummy instruction as the insertion point for all allocas.
-        // This is later removed in FunctionContext::cleanup.
-        self.alloca_insert_pt.set(Some(unsafe {
-            Load(entry_bcx, C_null(Type::i8p(self.ccx)));
-            llvm::LLVMGetFirstInstruction(entry_bcx.llbb)
-        }));
-
-        if !self.fn_ty.ret.is_ignore() && !skip_retptr {
-            // We normally allocate the llretslotptr, unless we
-            // have been instructed to skip it for immediate return
-            // values, or there is nothing to return at all.
-
-            // We create an alloca to hold a pointer of type `ret.original_ty`
-            // which will hold the pointer to the right alloca which has the
-            // final ret value
-            let llty = self.fn_ty.ret.memory_ty(self.ccx);
-            // But if there are no nested returns, we skip the indirection
-            // and have a single retslot
-            let slot = if self.fn_ty.ret.is_indirect() {
-                get_param(self.llfn, 0)
-            } else {
-                AllocaFcx(self, llty, "sret_slot")
-            };
-
-            self.llretslotptr.set(Some(slot));
-        }
-
-        entry_bcx
-    }
-
-    /// Ties up the llstaticallocas -> llloadenv -> lltop edges,
-    /// and builds the return block.
-    pub fn finish(&'blk self, ret_cx: Block<'blk, 'tcx>,
-                  ret_debug_loc: DebugLoc) {
-        let _icx = push_ctxt("FunctionContext::finish");
-
-        self.build_return_block(ret_cx, ret_debug_loc);
-
-        DebugLoc::None.apply(self);
-        self.cleanup();
-    }
-
-    // Builds the return block for a function.
-    pub fn build_return_block(&self, ret_cx: Block<'blk, 'tcx>,
-                              ret_debug_location: DebugLoc) {
-        if self.llretslotptr.get().is_none() ||
-           ret_cx.unreachable.get() ||
-           self.fn_ty.ret.is_indirect() {
-            return RetVoid(ret_cx, ret_debug_location);
-        }
-
-        let retslot = self.llretslotptr.get().unwrap();
-        let retptr = Value(retslot);
-        let llty = self.fn_ty.ret.original_ty;
-        match (retptr.get_dominating_store(ret_cx), self.fn_ty.ret.cast) {
-            // If there's only a single store to the ret slot, we can directly return
-            // the value that was stored and omit the store and the alloca.
-            // However, we only want to do this when there is no cast needed.
-            (Some(s), None) => {
-                let mut retval = s.get_operand(0).unwrap().get();
-                s.erase_from_parent();
-
-                if retptr.has_no_uses() {
-                    retptr.erase_from_parent();
-                }
-
-                if self.fn_ty.ret.is_indirect() {
-                    Store(ret_cx, retval, get_param(self.llfn, 0));
-                    RetVoid(ret_cx, ret_debug_location)
-                } else {
-                    if llty == Type::i1(self.ccx) {
-                        retval = Trunc(ret_cx, retval, llty);
-                    }
-                    Ret(ret_cx, retval, ret_debug_location)
-                }
-            }
-            (_, cast_ty) if self.fn_ty.ret.is_indirect() => {
-                // Otherwise, copy the return value to the ret slot.
-                assert_eq!(cast_ty, None);
-                let llsz = llsize_of(self.ccx, self.fn_ty.ret.ty);
-                let llalign = llalign_of_min(self.ccx, self.fn_ty.ret.ty);
-                call_memcpy(&B(ret_cx), get_param(self.llfn, 0),
-                            retslot, llsz, llalign as u32);
-                RetVoid(ret_cx, ret_debug_location)
-            }
-            (_, Some(cast_ty)) => {
-                let load = Load(ret_cx, PointerCast(ret_cx, retslot, cast_ty.ptr_to()));
-                let llalign = llalign_of_min(self.ccx, self.fn_ty.ret.ty);
-                unsafe {
-                    llvm::LLVMSetAlignment(load, llalign);
-                }
-                Ret(ret_cx, load, ret_debug_location)
-            }
-            (_, None) => {
-                let retval = if llty == Type::i1(self.ccx) {
-                    let val = LoadRangeAssert(ret_cx, retslot, 0, 2, llvm::False);
-                    Trunc(ret_cx, val, llty)
-                } else {
-                    Load(ret_cx, retslot)
-                };
-                Ret(ret_cx, retval, ret_debug_location)
-            }
-        }
-    }
+    bcx.fcx().alloca(type_of::type_of(bcx.ccx, ty), name)
 }
 
 pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) {
@@ -1016,8 +578,6 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
     // release builds.
     info!("trans_instance({})", instance);
 
-    let _icx = push_ctxt("trans_instance");
-
     let fn_ty = ccx.tcx().item_type(instance.def);
     let fn_ty = ccx.tcx().erase_regions(&fn_ty);
     let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty);
@@ -1038,19 +598,9 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
 
     let fn_ty = FnType::new(ccx, abi, &sig, &[]);
 
-    let (arena, fcx): (TypedArena<_>, FunctionContext);
-    arena = TypedArena::new();
-    fcx = FunctionContext::new(ccx,
-                               lldecl,
-                               fn_ty,
-                               Some((instance, &sig, abi)),
-                               &arena);
-
-    if fcx.mir.is_none() {
-        bug!("attempted translation of `{}` w/o MIR", instance);
-    }
-
-    mir::trans_mir(&fcx);
+    let fcx = FunctionContext::new(ccx, lldecl);
+    let mir = ccx.tcx().item_mir(instance.def);
+    mir::trans_mir(&fcx, fn_ty, &mir, instance, &sig, abi);
 }
 
 pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
@@ -1067,34 +617,55 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&ctor_ty.fn_sig());
     let fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
 
-    let (arena, fcx): (TypedArena<_>, FunctionContext);
-    arena = TypedArena::new();
-    fcx = FunctionContext::new(ccx, llfndecl, fn_ty, None, &arena);
-    let bcx = fcx.init(false);
-
-    if !fcx.fn_ty.ret.is_ignore() {
-        let dest = fcx.llretslotptr.get().unwrap();
+    let fcx = FunctionContext::new(ccx, llfndecl);
+    let bcx = fcx.get_entry_block();
+    if !fn_ty.ret.is_ignore() {
+        // But if there are no nested returns, we skip the indirection
+        // and have a single retslot
+        let dest = if fn_ty.ret.is_indirect() {
+            get_param(fcx.llfn, 0)
+        } else {
+            // We create an alloca to hold a pointer of type `ret.original_ty`
+            // which will hold the pointer to the right alloca which has the
+            // final ret value
+            fcx.alloca(fn_ty.ret.memory_ty(ccx), "sret_slot")
+        };
         let dest_val = adt::MaybeSizedValue::sized(dest); // Can return unsized value
-        let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize;
+        let mut llarg_idx = fn_ty.ret.is_indirect() as usize;
         let mut arg_idx = 0;
         for (i, arg_ty) in sig.inputs().iter().enumerate() {
-            let lldestptr = adt::trans_field_ptr(bcx, sig.output(), dest_val, Disr::from(disr), i);
-            let arg = &fcx.fn_ty.args[arg_idx];
+            let lldestptr = adt::trans_field_ptr(&bcx, sig.output(), dest_val, Disr::from(disr), i);
+            let arg = &fn_ty.args[arg_idx];
             arg_idx += 1;
-            let b = &bcx.build();
-            if common::type_is_fat_ptr(bcx.tcx(), arg_ty) {
-                let meta = &fcx.fn_ty.args[arg_idx];
+            if common::type_is_fat_ptr(bcx.ccx, arg_ty) {
+                let meta = &fn_ty.args[arg_idx];
                 arg_idx += 1;
-                arg.store_fn_arg(b, &mut llarg_idx, get_dataptr(bcx, lldestptr));
-                meta.store_fn_arg(b, &mut llarg_idx, get_meta(bcx, lldestptr));
+                arg.store_fn_arg(&bcx, &mut llarg_idx, get_dataptr(&bcx, lldestptr));
+                meta.store_fn_arg(&bcx, &mut llarg_idx, get_meta(&bcx, lldestptr));
             } else {
-                arg.store_fn_arg(b, &mut llarg_idx, lldestptr);
+                arg.store_fn_arg(&bcx, &mut llarg_idx, lldestptr);
             }
         }
-        adt::trans_set_discr(bcx, sig.output(), dest, disr);
-    }
+        adt::trans_set_discr(&bcx, sig.output(), dest, disr);
 
-    fcx.finish(bcx, DebugLoc::None);
+        if fn_ty.ret.is_indirect() {
+            bcx.ret_void();
+            return;
+        }
+
+        if let Some(cast_ty) = fn_ty.ret.cast {
+            let load = bcx.load(bcx.pointercast(dest, cast_ty.ptr_to()));
+            let llalign = llalign_of_min(ccx, fn_ty.ret.ty);
+            unsafe {
+                llvm::LLVMSetAlignment(load, llalign);
+            }
+            bcx.ret(load)
+        } else {
+            bcx.ret(bcx.load(dest))
+        }
+    } else {
+        bcx.ret_void();
+    }
 }
 
 pub fn llvm_linkage_by_name(name: &str) -> Option<Linkage> {
@@ -1166,9 +737,7 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) {
 
     let et = ccx.sess().entry_type.get().unwrap();
     match et {
-        config::EntryMain => {
-            create_entry_fn(ccx, span, main_llfn, true);
-        }
+        config::EntryMain => create_entry_fn(ccx, span, main_llfn, true),
         config::EntryStart => create_entry_fn(ccx, span, main_llfn, false),
         config::EntryNone => {}    // Do nothing.
     }
@@ -1193,47 +762,27 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) {
         attributes::set_frame_pointer_elimination(ccx, llfn);
 
         let llbb = unsafe {
-            llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn, "top\0".as_ptr() as *const _)
+            let name = CString::new("top").unwrap();
+            llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn, name.as_ptr())
         };
-        let bld = ccx.raw_builder();
-        unsafe {
-            llvm::LLVMPositionBuilderAtEnd(bld, llbb);
-
-            debuginfo::gdb::insert_reference_to_gdb_debug_scripts_section_global(ccx);
-
-            let (start_fn, args) = if use_start_lang_item {
-                let start_def_id = match ccx.tcx().lang_items.require(StartFnLangItem) {
-                    Ok(id) => id,
-                    Err(s) => ccx.sess().fatal(&s)
-                };
-                let empty_substs = ccx.tcx().intern_substs(&[]);
-                let start_fn = Callee::def(ccx, start_def_id, empty_substs).reify(ccx);
-                let args = {
-                    let opaque_rust_main =
-                        llvm::LLVMBuildPointerCast(bld,
-                                                   rust_main,
-                                                   Type::i8p(ccx).to_ref(),
-                                                   "rust_main\0".as_ptr() as *const _);
-
-                    vec![opaque_rust_main, get_param(llfn, 0), get_param(llfn, 1)]
-                };
-                (start_fn, args)
-            } else {
-                debug!("using user-defined start fn");
-                let args = vec![get_param(llfn, 0 as c_uint), get_param(llfn, 1 as c_uint)];
+        let bld = Builder::with_ccx(ccx);
+        bld.position_at_end(llbb);
 
-                (rust_main, args)
-            };
+        debuginfo::gdb::insert_reference_to_gdb_debug_scripts_section_global(ccx, &bld);
 
-            let result = llvm::LLVMRustBuildCall(bld,
-                                                 start_fn,
-                                                 args.as_ptr(),
-                                                 args.len() as c_uint,
-                                                 ptr::null_mut(),
-                                                 noname());
+        let (start_fn, args) = if use_start_lang_item {
+            let start_def_id = ccx.tcx().require_lang_item(StartFnLangItem);
+            let empty_substs = ccx.tcx().intern_substs(&[]);
+            let start_fn = Callee::def(ccx, start_def_id, empty_substs).reify(ccx);
+            (start_fn, vec![bld.pointercast(rust_main, Type::i8p(ccx).ptr_to()), get_param(llfn, 0),
+                get_param(llfn, 1)])
+        } else {
+            debug!("using user-defined start fn");
+            (rust_main, vec![get_param(llfn, 0 as c_uint), get_param(llfn, 1 as c_uint)])
+        };
 
-            llvm::LLVMBuildRet(bld, result);
-        }
+        let result = bld.call(start_fn, &args, None);
+        bld.ret(result);
     }
 }
 
@@ -1868,7 +1417,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         match **layout {
             Layout::StructWrappedNullablePointer { nonnull: ref variant_layout,
                                                    nndiscr,
-                                                   discrfield: _ } => {
+                                                   discrfield: _,
+                                                   discrfield_source: _ } => {
                 debug!("print-type-size t: `{:?}` adt struct-wrapped nullable nndiscr {} is {:?}",
                        ty, nndiscr, variant_layout);
                 let variant_def = &adt_def.variants[nndiscr as usize];
diff --git a/src/librustc_trans/basic_block.rs b/src/librustc_trans/basic_block.rs
deleted file mode 100644
index 60bd3fb8ef1..00000000000
--- a/src/librustc_trans/basic_block.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2013 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 llvm;
-use llvm::BasicBlockRef;
-use value::{Users, Value};
-use std::iter::{Filter, Map};
-
-#[derive(Copy, Clone)]
-pub struct BasicBlock(pub BasicBlockRef);
-
-pub type Preds = Map<Filter<Users, fn(&Value) -> bool>, fn(Value) -> BasicBlock>;
-
-/// Wrapper for LLVM BasicBlockRef
-impl BasicBlock {
-    pub fn get(&self) -> BasicBlockRef {
-        let BasicBlock(v) = *self; v
-    }
-
-    pub fn as_value(self) -> Value {
-        unsafe {
-            Value(llvm::LLVMBasicBlockAsValue(self.get()))
-        }
-    }
-
-    pub fn pred_iter(self) -> Preds {
-        fn is_a_terminator_inst(user: &Value) -> bool { user.is_a_terminator_inst() }
-        let is_a_terminator_inst: fn(&Value) -> bool = is_a_terminator_inst;
-
-        fn get_parent(user: Value) -> BasicBlock { user.get_parent().unwrap() }
-        let get_parent: fn(Value) -> BasicBlock = get_parent;
-
-        self.as_value().user_iter()
-            .filter(is_a_terminator_inst)
-            .map(get_parent)
-    }
-
-    pub fn get_single_predecessor(self) -> Option<BasicBlock> {
-        let mut iter = self.pred_iter();
-        match (iter.next(), iter.next()) {
-            (Some(first), None) => Some(first),
-            _ => None
-        }
-    }
-
-    pub fn delete(self) {
-        unsafe {
-            llvm::LLVMDeleteBasicBlock(self.0);
-        }
-    }
-}
diff --git a/src/librustc_trans/build.rs b/src/librustc_trans/build.rs
deleted file mode 100644
index 8cd47bd148d..00000000000
--- a/src/librustc_trans/build.rs
+++ /dev/null
@@ -1,1167 +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.
-
-#![allow(dead_code)] // FFI wrappers
-#![allow(non_snake_case)]
-
-use llvm;
-use llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect};
-use llvm::{Opcode, IntPredicate, RealPredicate};
-use llvm::{ValueRef, BasicBlockRef};
-use common::*;
-use syntax_pos::Span;
-
-use builder::Builder;
-use type_::Type;
-use value::Value;
-use debuginfo::DebugLoc;
-
-use libc::{c_uint, c_char};
-
-pub fn terminate(cx: Block, _: &str) {
-    debug!("terminate({})", cx.to_str());
-    cx.terminated.set(true);
-}
-
-pub fn check_not_terminated(cx: Block) {
-    if cx.terminated.get() {
-        bug!("already terminated!");
-    }
-}
-
-pub fn B<'blk, 'tcx>(cx: Block<'blk, 'tcx>) -> Builder<'blk, 'tcx> {
-    let b = cx.fcx.ccx.builder();
-    b.position_at_end(cx.llbb);
-    b
-}
-
-// The difference between a block being unreachable and being terminated is
-// somewhat obscure, and has to do with error checking. When a block is
-// terminated, we're saying that trying to add any further statements in the
-// block is an error. On the other hand, if something is unreachable, that
-// means that the block was terminated in some way that we don't want to check
-// for (panic/break/return statements, call to diverging functions, etc), and
-// further instructions to the block should simply be ignored.
-
-pub fn RetVoid(cx: Block, debug_loc: DebugLoc) {
-    if cx.unreachable.get() {
-        return;
-    }
-    check_not_terminated(cx);
-    terminate(cx, "RetVoid");
-    debug_loc.apply(cx.fcx);
-    B(cx).ret_void();
-}
-
-pub fn Ret(cx: Block, v: ValueRef, debug_loc: DebugLoc) {
-    if cx.unreachable.get() {
-        return;
-    }
-    check_not_terminated(cx);
-    terminate(cx, "Ret");
-    debug_loc.apply(cx.fcx);
-    B(cx).ret(v);
-}
-
-pub fn AggregateRet(cx: Block,
-                    ret_vals: &[ValueRef],
-                    debug_loc: DebugLoc) {
-    if cx.unreachable.get() {
-        return;
-    }
-    check_not_terminated(cx);
-    terminate(cx, "AggregateRet");
-    debug_loc.apply(cx.fcx);
-    B(cx).aggregate_ret(ret_vals);
-}
-
-pub fn Br(cx: Block, dest: BasicBlockRef, debug_loc: DebugLoc) {
-    if cx.unreachable.get() {
-        return;
-    }
-    check_not_terminated(cx);
-    terminate(cx, "Br");
-    debug_loc.apply(cx.fcx);
-    B(cx).br(dest);
-}
-
-pub fn CondBr(cx: Block,
-              if_: ValueRef,
-              then: BasicBlockRef,
-              else_: BasicBlockRef,
-              debug_loc: DebugLoc) {
-    if cx.unreachable.get() {
-        return;
-    }
-    check_not_terminated(cx);
-    terminate(cx, "CondBr");
-    debug_loc.apply(cx.fcx);
-    B(cx).cond_br(if_, then, else_);
-}
-
-pub fn Switch(cx: Block, v: ValueRef, else_: BasicBlockRef, num_cases: usize)
-    -> ValueRef {
-    if cx.unreachable.get() { return _Undef(v); }
-    check_not_terminated(cx);
-    terminate(cx, "Switch");
-    B(cx).switch(v, else_, num_cases)
-}
-
-pub fn AddCase(s: ValueRef, on_val: ValueRef, dest: BasicBlockRef) {
-    unsafe {
-        if llvm::LLVMIsUndef(s) == llvm::True { return; }
-        llvm::LLVMAddCase(s, on_val, dest);
-    }
-}
-
-pub fn IndirectBr(cx: Block,
-                  addr: ValueRef,
-                  num_dests: usize,
-                  debug_loc: DebugLoc) {
-    if cx.unreachable.get() {
-        return;
-    }
-    check_not_terminated(cx);
-    terminate(cx, "IndirectBr");
-    debug_loc.apply(cx.fcx);
-    B(cx).indirect_br(addr, num_dests);
-}
-
-pub fn Invoke(cx: Block,
-              fn_: ValueRef,
-              args: &[ValueRef],
-              then: BasicBlockRef,
-              catch: BasicBlockRef,
-              debug_loc: DebugLoc)
-              -> ValueRef {
-    if cx.unreachable.get() {
-        return C_null(Type::i8(cx.ccx()));
-    }
-    check_not_terminated(cx);
-    terminate(cx, "Invoke");
-    debug!("Invoke({:?} with arguments ({}))",
-           Value(fn_),
-           args.iter().map(|a| {
-                format!("{:?}", Value(*a))
-           }).collect::<Vec<String>>().join(", "));
-    debug_loc.apply(cx.fcx);
-    let bundle = cx.lpad().and_then(|b| b.bundle());
-    B(cx).invoke(fn_, args, then, catch, bundle)
-}
-
-pub fn Unreachable(cx: Block) {
-    if cx.unreachable.get() {
-        return
-    }
-    cx.unreachable.set(true);
-    if !cx.terminated.get() {
-        B(cx).unreachable();
-    }
-}
-
-pub fn _Undef(val: ValueRef) -> ValueRef {
-    unsafe {
-        return llvm::LLVMGetUndef(val_ty(val).to_ref());
-    }
-}
-
-/* Arithmetic */
-pub fn Add(cx: Block,
-           lhs: ValueRef,
-           rhs: ValueRef,
-           debug_loc: DebugLoc)
-           -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).add(lhs, rhs)
-}
-
-pub fn NSWAdd(cx: Block,
-              lhs: ValueRef,
-              rhs: ValueRef,
-              debug_loc: DebugLoc)
-              -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).nswadd(lhs, rhs)
-}
-
-pub fn NUWAdd(cx: Block,
-              lhs: ValueRef,
-              rhs: ValueRef,
-              debug_loc: DebugLoc)
-              -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).nuwadd(lhs, rhs)
-}
-
-pub fn FAdd(cx: Block,
-            lhs: ValueRef,
-            rhs: ValueRef,
-            debug_loc: DebugLoc)
-            -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).fadd(lhs, rhs)
-}
-
-pub fn FAddFast(cx: Block,
-                lhs: ValueRef,
-                rhs: ValueRef,
-                debug_loc: DebugLoc)
-            -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).fadd_fast(lhs, rhs)
-}
-
-pub fn Sub(cx: Block,
-           lhs: ValueRef,
-           rhs: ValueRef,
-           debug_loc: DebugLoc)
-           -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).sub(lhs, rhs)
-}
-
-pub fn NSWSub(cx: Block,
-              lhs: ValueRef,
-              rhs: ValueRef,
-              debug_loc: DebugLoc)
-              -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).nswsub(lhs, rhs)
-}
-
-pub fn NUWSub(cx: Block,
-              lhs: ValueRef,
-              rhs: ValueRef,
-              debug_loc: DebugLoc)
-              -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).nuwsub(lhs, rhs)
-}
-
-pub fn FSub(cx: Block,
-            lhs: ValueRef,
-            rhs: ValueRef,
-            debug_loc: DebugLoc)
-            -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).fsub(lhs, rhs)
-}
-
-pub fn FSubFast(cx: Block,
-                lhs: ValueRef,
-                rhs: ValueRef,
-                debug_loc: DebugLoc)
-            -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).fsub_fast(lhs, rhs)
-}
-
-pub fn Mul(cx: Block,
-           lhs: ValueRef,
-           rhs: ValueRef,
-           debug_loc: DebugLoc)
-           -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).mul(lhs, rhs)
-}
-
-pub fn NSWMul(cx: Block,
-              lhs: ValueRef,
-              rhs: ValueRef,
-              debug_loc: DebugLoc)
-              -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).nswmul(lhs, rhs)
-}
-
-pub fn NUWMul(cx: Block,
-              lhs: ValueRef,
-              rhs: ValueRef,
-              debug_loc: DebugLoc)
-              -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).nuwmul(lhs, rhs)
-}
-
-pub fn FMul(cx: Block,
-            lhs: ValueRef,
-            rhs: ValueRef,
-            debug_loc: DebugLoc)
-            -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).fmul(lhs, rhs)
-}
-
-pub fn FMulFast(cx: Block,
-                lhs: ValueRef,
-                rhs: ValueRef,
-                debug_loc: DebugLoc)
-            -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).fmul_fast(lhs, rhs)
-}
-
-pub fn UDiv(cx: Block,
-            lhs: ValueRef,
-            rhs: ValueRef,
-            debug_loc: DebugLoc)
-            -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).udiv(lhs, rhs)
-}
-
-pub fn SDiv(cx: Block,
-            lhs: ValueRef,
-            rhs: ValueRef,
-            debug_loc: DebugLoc)
-            -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).sdiv(lhs, rhs)
-}
-
-pub fn ExactSDiv(cx: Block,
-                 lhs: ValueRef,
-                 rhs: ValueRef,
-                 debug_loc: DebugLoc)
-                 -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).exactsdiv(lhs, rhs)
-}
-
-pub fn FDiv(cx: Block,
-            lhs: ValueRef,
-            rhs: ValueRef,
-            debug_loc: DebugLoc)
-            -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).fdiv(lhs, rhs)
-}
-
-pub fn FDivFast(cx: Block,
-                lhs: ValueRef,
-                rhs: ValueRef,
-                debug_loc: DebugLoc)
-            -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).fdiv_fast(lhs, rhs)
-}
-
-pub fn URem(cx: Block,
-            lhs: ValueRef,
-            rhs: ValueRef,
-            debug_loc: DebugLoc)
-            -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).urem(lhs, rhs)
-}
-
-pub fn SRem(cx: Block,
-            lhs: ValueRef,
-            rhs: ValueRef,
-            debug_loc: DebugLoc)
-            -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).srem(lhs, rhs)
-}
-
-pub fn FRem(cx: Block,
-            lhs: ValueRef,
-            rhs: ValueRef,
-            debug_loc: DebugLoc)
-            -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).frem(lhs, rhs)
-}
-
-pub fn FRemFast(cx: Block,
-                lhs: ValueRef,
-                rhs: ValueRef,
-                debug_loc: DebugLoc)
-            -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).frem_fast(lhs, rhs)
-}
-
-pub fn Shl(cx: Block,
-           lhs: ValueRef,
-           rhs: ValueRef,
-           debug_loc: DebugLoc)
-           -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).shl(lhs, rhs)
-}
-
-pub fn LShr(cx: Block,
-            lhs: ValueRef,
-            rhs: ValueRef,
-            debug_loc: DebugLoc)
-            -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).lshr(lhs, rhs)
-}
-
-pub fn AShr(cx: Block,
-            lhs: ValueRef,
-            rhs: ValueRef,
-            debug_loc: DebugLoc)
-            -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).ashr(lhs, rhs)
-}
-
-pub fn And(cx: Block,
-           lhs: ValueRef,
-           rhs: ValueRef,
-           debug_loc: DebugLoc)
-           -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).and(lhs, rhs)
-}
-
-pub fn Or(cx: Block,
-          lhs: ValueRef,
-          rhs: ValueRef,
-          debug_loc: DebugLoc)
-          -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).or(lhs, rhs)
-}
-
-pub fn Xor(cx: Block,
-           lhs: ValueRef,
-           rhs: ValueRef,
-           debug_loc: DebugLoc)
-           -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).xor(lhs, rhs)
-}
-
-pub fn BinOp(cx: Block,
-             op: Opcode,
-             lhs: ValueRef,
-             rhs: ValueRef,
-             debug_loc: DebugLoc)
-          -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(lhs);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).binop(op, lhs, rhs)
-}
-
-pub fn Neg(cx: Block, v: ValueRef, debug_loc: DebugLoc) -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(v);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).neg(v)
-}
-
-pub fn NSWNeg(cx: Block, v: ValueRef, debug_loc: DebugLoc) -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(v);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).nswneg(v)
-}
-
-pub fn NUWNeg(cx: Block, v: ValueRef, debug_loc: DebugLoc) -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(v);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).nuwneg(v)
-}
-pub fn FNeg(cx: Block, v: ValueRef, debug_loc: DebugLoc) -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(v);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).fneg(v)
-}
-
-pub fn Not(cx: Block, v: ValueRef, debug_loc: DebugLoc) -> ValueRef {
-    if cx.unreachable.get() {
-        return _Undef(v);
-    }
-    debug_loc.apply(cx.fcx);
-    B(cx).not(v)
-}
-
-pub fn Alloca(cx: Block, ty: Type, name: &str) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(ty.ptr_to().to_ref()); }
-        AllocaFcx(cx.fcx, ty, name)
-    }
-}
-
-pub fn AllocaFcx(fcx: &FunctionContext, ty: Type, name: &str) -> ValueRef {
-    let b = fcx.ccx.builder();
-    b.position_before(fcx.alloca_insert_pt.get().unwrap());
-    DebugLoc::None.apply(fcx);
-    b.alloca(ty, name)
-}
-
-pub fn Free(cx: Block, pointer_val: ValueRef) {
-    if cx.unreachable.get() { return; }
-    B(cx).free(pointer_val)
-}
-
-pub fn Load(cx: Block, pointer_val: ValueRef) -> ValueRef {
-    unsafe {
-        let ccx = cx.fcx.ccx;
-        if cx.unreachable.get() {
-            let ty = val_ty(pointer_val);
-            let eltty = if ty.kind() == llvm::Array {
-                ty.element_type()
-            } else {
-                ccx.int_type()
-            };
-            return llvm::LLVMGetUndef(eltty.to_ref());
-        }
-        B(cx).load(pointer_val)
-    }
-}
-
-pub fn VolatileLoad(cx: Block, pointer_val: ValueRef) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() {
-            return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref());
-        }
-        B(cx).volatile_load(pointer_val)
-    }
-}
-
-pub fn AtomicLoad(cx: Block, pointer_val: ValueRef, order: AtomicOrdering) -> ValueRef {
-    unsafe {
-        let ccx = cx.fcx.ccx;
-        if cx.unreachable.get() {
-            return llvm::LLVMGetUndef(ccx.int_type().to_ref());
-        }
-        B(cx).atomic_load(pointer_val, order)
-    }
-}
-
-
-pub fn LoadRangeAssert(cx: Block, pointer_val: ValueRef, lo: u64,
-                       hi: u64, signed: llvm::Bool) -> ValueRef {
-    if cx.unreachable.get() {
-        let ccx = cx.fcx.ccx;
-        let ty = val_ty(pointer_val);
-        let eltty = if ty.kind() == llvm::Array {
-            ty.element_type()
-        } else {
-            ccx.int_type()
-        };
-        unsafe {
-            llvm::LLVMGetUndef(eltty.to_ref())
-        }
-    } else {
-        B(cx).load_range_assert(pointer_val, lo, hi, signed)
-    }
-}
-
-pub fn LoadNonNull(cx: Block, ptr: ValueRef) -> ValueRef {
-    if cx.unreachable.get() {
-        let ccx = cx.fcx.ccx;
-        let ty = val_ty(ptr);
-        let eltty = if ty.kind() == llvm::Array {
-            ty.element_type()
-        } else {
-            ccx.int_type()
-        };
-        unsafe {
-            llvm::LLVMGetUndef(eltty.to_ref())
-        }
-    } else {
-        B(cx).load_nonnull(ptr)
-    }
-}
-
-pub fn Store(cx: Block, val: ValueRef, ptr: ValueRef) -> ValueRef {
-    if cx.unreachable.get() { return C_nil(cx.ccx()); }
-    B(cx).store(val, ptr)
-}
-
-pub fn VolatileStore(cx: Block, val: ValueRef, ptr: ValueRef) -> ValueRef {
-    if cx.unreachable.get() { return C_nil(cx.ccx()); }
-    B(cx).volatile_store(val, ptr)
-}
-
-pub fn AtomicStore(cx: Block, val: ValueRef, ptr: ValueRef, order: AtomicOrdering) {
-    if cx.unreachable.get() { return; }
-    B(cx).atomic_store(val, ptr, order)
-}
-
-pub fn GEP(cx: Block, pointer: ValueRef, indices: &[ValueRef]) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() {
-            return llvm::LLVMGetUndef(Type::nil(cx.ccx()).ptr_to().to_ref());
-        }
-        B(cx).gep(pointer, indices)
-    }
-}
-
-// Simple wrapper around GEP that takes an array of ints and wraps them
-// in C_i32()
-#[inline]
-pub fn GEPi(cx: Block, base: ValueRef, ixs: &[usize]) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() {
-            return llvm::LLVMGetUndef(Type::nil(cx.ccx()).ptr_to().to_ref());
-        }
-        B(cx).gepi(base, ixs)
-    }
-}
-
-pub fn InBoundsGEP(cx: Block, pointer: ValueRef, indices: &[ValueRef]) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() {
-            return llvm::LLVMGetUndef(Type::nil(cx.ccx()).ptr_to().to_ref());
-        }
-        B(cx).inbounds_gep(pointer, indices)
-    }
-}
-
-pub fn StructGEP(cx: Block, pointer: ValueRef, idx: usize) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() {
-            return llvm::LLVMGetUndef(Type::nil(cx.ccx()).ptr_to().to_ref());
-        }
-        B(cx).struct_gep(pointer, idx)
-    }
-}
-
-pub fn GlobalString(cx: Block, _str: *const c_char) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() {
-            return llvm::LLVMGetUndef(Type::i8p(cx.ccx()).to_ref());
-        }
-        B(cx).global_string(_str)
-    }
-}
-
-pub fn GlobalStringPtr(cx: Block, _str: *const c_char) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() {
-            return llvm::LLVMGetUndef(Type::i8p(cx.ccx()).to_ref());
-        }
-        B(cx).global_string_ptr(_str)
-    }
-}
-
-/* Casts */
-pub fn Trunc(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).trunc(val, dest_ty)
-    }
-}
-
-pub fn ZExt(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).zext(val, dest_ty)
-    }
-}
-
-pub fn SExt(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).sext(val, dest_ty)
-    }
-}
-
-pub fn FPToUI(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).fptoui(val, dest_ty)
-    }
-}
-
-pub fn FPToSI(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).fptosi(val, dest_ty)
-    }
-}
-
-pub fn UIToFP(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).uitofp(val, dest_ty)
-    }
-}
-
-pub fn SIToFP(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).sitofp(val, dest_ty)
-    }
-}
-
-pub fn FPTrunc(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).fptrunc(val, dest_ty)
-    }
-}
-
-pub fn FPExt(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).fpext(val, dest_ty)
-    }
-}
-
-pub fn PtrToInt(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).ptrtoint(val, dest_ty)
-    }
-}
-
-pub fn IntToPtr(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).inttoptr(val, dest_ty)
-    }
-}
-
-pub fn BitCast(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).bitcast(val, dest_ty)
-    }
-}
-
-pub fn ZExtOrBitCast(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).zext_or_bitcast(val, dest_ty)
-    }
-}
-
-pub fn SExtOrBitCast(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).sext_or_bitcast(val, dest_ty)
-    }
-}
-
-pub fn TruncOrBitCast(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).trunc_or_bitcast(val, dest_ty)
-    }
-}
-
-pub fn Cast(cx: Block, op: Opcode, val: ValueRef, dest_ty: Type,
-            _: *const u8)
-     -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).cast(op, val, dest_ty)
-    }
-}
-
-pub fn PointerCast(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).pointercast(val, dest_ty)
-    }
-}
-
-pub fn IntCast(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).intcast(val, dest_ty)
-    }
-}
-
-pub fn FPCast(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); }
-        B(cx).fpcast(val, dest_ty)
-    }
-}
-
-
-/* Comparisons */
-pub fn ICmp(cx: Block,
-            op: IntPredicate,
-            lhs: ValueRef,
-            rhs: ValueRef,
-            debug_loc: DebugLoc)
-            -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() {
-            return llvm::LLVMGetUndef(Type::i1(cx.ccx()).to_ref());
-        }
-        debug_loc.apply(cx.fcx);
-        B(cx).icmp(op, lhs, rhs)
-    }
-}
-
-pub fn FCmp(cx: Block,
-            op: RealPredicate,
-            lhs: ValueRef,
-            rhs: ValueRef,
-            debug_loc: DebugLoc)
-            -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() {
-            return llvm::LLVMGetUndef(Type::i1(cx.ccx()).to_ref());
-        }
-        debug_loc.apply(cx.fcx);
-        B(cx).fcmp(op, lhs, rhs)
-    }
-}
-
-/* Miscellaneous instructions */
-pub fn EmptyPhi(cx: Block, ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(ty.to_ref()); }
-        B(cx).empty_phi(ty)
-    }
-}
-
-pub fn Phi(cx: Block, ty: Type, vals: &[ValueRef],
-           bbs: &[BasicBlockRef]) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(ty.to_ref()); }
-        B(cx).phi(ty, vals, bbs)
-    }
-}
-
-pub fn AddIncomingToPhi(phi: ValueRef, val: ValueRef, bb: BasicBlockRef) {
-    unsafe {
-        if llvm::LLVMIsUndef(phi) == llvm::True { return; }
-        llvm::LLVMAddIncoming(phi, &val, &bb, 1 as c_uint);
-    }
-}
-
-pub fn _UndefReturn(cx: Block, fn_: ValueRef) -> ValueRef {
-    unsafe {
-        let ccx = cx.fcx.ccx;
-        let ty = val_ty(fn_);
-        let retty = if ty.kind() == llvm::Function {
-            ty.return_type()
-        } else {
-            ccx.int_type()
-        };
-        B(cx).count_insn("ret_undef");
-        llvm::LLVMGetUndef(retty.to_ref())
-    }
-}
-
-pub fn add_span_comment(cx: Block, sp: Span, text: &str) {
-    B(cx).add_span_comment(sp, text)
-}
-
-pub fn add_comment(cx: Block, text: &str) {
-    B(cx).add_comment(text)
-}
-
-pub fn InlineAsmCall(cx: Block, asm: *const c_char, cons: *const c_char,
-                     inputs: &[ValueRef], output: Type,
-                     volatile: bool, alignstack: bool,
-                     dia: AsmDialect) -> ValueRef {
-    B(cx).inline_asm_call(asm, cons, inputs, output, volatile, alignstack, dia)
-}
-
-pub fn Call(cx: Block,
-            fn_: ValueRef,
-            args: &[ValueRef],
-            debug_loc: DebugLoc)
-            -> ValueRef {
-    if cx.unreachable.get() {
-        return _UndefReturn(cx, fn_);
-    }
-    debug_loc.apply(cx.fcx);
-    let bundle = cx.lpad.get().and_then(|b| b.bundle());
-    B(cx).call(fn_, args, bundle)
-}
-
-pub fn AtomicFence(cx: Block, order: AtomicOrdering, scope: SynchronizationScope) {
-    if cx.unreachable.get() { return; }
-    B(cx).atomic_fence(order, scope)
-}
-
-pub fn Select(cx: Block, if_: ValueRef, then: ValueRef, else_: ValueRef) -> ValueRef {
-    if cx.unreachable.get() { return _Undef(then); }
-    B(cx).select(if_, then, else_)
-}
-
-pub fn VAArg(cx: Block, list: ValueRef, ty: Type) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(ty.to_ref()); }
-        B(cx).va_arg(list, ty)
-    }
-}
-
-pub fn ExtractElement(cx: Block, vec_val: ValueRef, index: ValueRef) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() {
-            return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref());
-        }
-        B(cx).extract_element(vec_val, index)
-    }
-}
-
-pub fn InsertElement(cx: Block, vec_val: ValueRef, elt_val: ValueRef,
-                     index: ValueRef) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() {
-            return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref());
-        }
-        B(cx).insert_element(vec_val, elt_val, index)
-    }
-}
-
-pub fn ShuffleVector(cx: Block, v1: ValueRef, v2: ValueRef,
-                     mask: ValueRef) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() {
-            return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref());
-        }
-        B(cx).shuffle_vector(v1, v2, mask)
-    }
-}
-
-pub fn VectorSplat(cx: Block, num_elts: usize, elt_val: ValueRef) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() {
-            return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref());
-        }
-        B(cx).vector_splat(num_elts, elt_val)
-    }
-}
-
-pub fn ExtractValue(cx: Block, agg_val: ValueRef, index: usize) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() {
-            return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref());
-        }
-        B(cx).extract_value(agg_val, index)
-    }
-}
-
-pub fn InsertValue(cx: Block, agg_val: ValueRef, elt_val: ValueRef, index: usize) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() {
-            return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref());
-        }
-        B(cx).insert_value(agg_val, elt_val, index)
-    }
-}
-
-pub fn IsNull(cx: Block, val: ValueRef) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() {
-            return llvm::LLVMGetUndef(Type::i1(cx.ccx()).to_ref());
-        }
-        B(cx).is_null(val)
-    }
-}
-
-pub fn IsNotNull(cx: Block, val: ValueRef) -> ValueRef {
-    unsafe {
-        if cx.unreachable.get() {
-            return llvm::LLVMGetUndef(Type::i1(cx.ccx()).to_ref());
-        }
-        B(cx).is_not_null(val)
-    }
-}
-
-pub fn PtrDiff(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
-    unsafe {
-        let ccx = cx.fcx.ccx;
-        if cx.unreachable.get() { return llvm::LLVMGetUndef(ccx.int_type().to_ref()); }
-        B(cx).ptrdiff(lhs, rhs)
-    }
-}
-
-pub fn Trap(cx: Block) {
-    if cx.unreachable.get() { return; }
-    B(cx).trap();
-}
-
-pub fn LandingPad(cx: Block, ty: Type, pers_fn: ValueRef,
-                  num_clauses: usize) -> ValueRef {
-    check_not_terminated(cx);
-    assert!(!cx.unreachable.get());
-    B(cx).landing_pad(ty, pers_fn, num_clauses, cx.fcx.llfn)
-}
-
-pub fn AddClause(cx: Block, landing_pad: ValueRef, clause: ValueRef) {
-    B(cx).add_clause(landing_pad, clause)
-}
-
-pub fn SetCleanup(cx: Block, landing_pad: ValueRef) {
-    B(cx).set_cleanup(landing_pad)
-}
-
-pub fn SetPersonalityFn(cx: Block, f: ValueRef) {
-    B(cx).set_personality_fn(f)
-}
-
-pub fn Resume(cx: Block, exn: ValueRef) -> ValueRef {
-    check_not_terminated(cx);
-    terminate(cx, "Resume");
-    B(cx).resume(exn)
-}
-
-// Atomic Operations
-pub fn AtomicCmpXchg(cx: Block, dst: ValueRef,
-                     cmp: ValueRef, src: ValueRef,
-                     order: AtomicOrdering,
-                     failure_order: AtomicOrdering,
-                     weak: llvm::Bool) -> ValueRef {
-    B(cx).atomic_cmpxchg(dst, cmp, src, order, failure_order, weak)
-}
-pub fn AtomicRMW(cx: Block, op: AtomicRmwBinOp,
-                 dst: ValueRef, src: ValueRef,
-                 order: AtomicOrdering) -> ValueRef {
-    B(cx).atomic_rmw(op, dst, src, order)
-}
-
-pub fn CleanupPad(cx: Block,
-                  parent: Option<ValueRef>,
-                  args: &[ValueRef]) -> ValueRef {
-    check_not_terminated(cx);
-    assert!(!cx.unreachable.get());
-    B(cx).cleanup_pad(parent, args)
-}
-
-pub fn CleanupRet(cx: Block,
-                  cleanup: ValueRef,
-                  unwind: Option<BasicBlockRef>) -> ValueRef {
-    check_not_terminated(cx);
-    terminate(cx, "CleanupRet");
-    B(cx).cleanup_ret(cleanup, unwind)
-}
-
-pub fn CatchPad(cx: Block,
-                parent: ValueRef,
-                args: &[ValueRef]) -> ValueRef {
-    check_not_terminated(cx);
-    assert!(!cx.unreachable.get());
-    B(cx).catch_pad(parent, args)
-}
-
-pub fn CatchRet(cx: Block, pad: ValueRef, unwind: BasicBlockRef) -> ValueRef {
-    check_not_terminated(cx);
-    terminate(cx, "CatchRet");
-    B(cx).catch_ret(pad, unwind)
-}
-
-pub fn CatchSwitch(cx: Block,
-                   parent: Option<ValueRef>,
-                   unwind: Option<BasicBlockRef>,
-                   num_handlers: usize) -> ValueRef {
-    check_not_terminated(cx);
-    terminate(cx, "CatchSwitch");
-    B(cx).catch_switch(parent, unwind, num_handlers)
-}
-
-pub fn AddHandler(cx: Block, catch_switch: ValueRef, handler: BasicBlockRef) {
-    B(cx).add_handler(catch_switch, handler)
-}
diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs
index 0480bb82a99..136d1aad31a 100644
--- a/src/librustc_trans/builder.rs
+++ b/src/librustc_trans/builder.rs
@@ -14,12 +14,10 @@ use llvm;
 use llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect};
 use llvm::{Opcode, IntPredicate, RealPredicate, False, OperandBundleDef};
 use llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef};
-use base;
 use common::*;
 use machine::llalign_of_pref;
 use type_::Type;
 use value::Value;
-use util::nodemap::FxHashMap;
 use libc::{c_uint, c_char};
 
 use std::borrow::Cow;
@@ -32,65 +30,40 @@ pub struct Builder<'a, 'tcx: 'a> {
     pub ccx: &'a CrateContext<'a, 'tcx>,
 }
 
+impl<'a, 'tcx> Drop for Builder<'a, 'tcx> {
+    fn drop(&mut self) {
+        unsafe {
+            llvm::LLVMDisposeBuilder(self.llbuilder);
+        }
+    }
+}
+
 // This is a really awful way to get a zero-length c-string, but better (and a
 // lot more efficient) than doing str::as_c_str("", ...) every time.
-pub fn noname() -> *const c_char {
+fn noname() -> *const c_char {
     static CNULL: c_char = 0;
     &CNULL
 }
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
-    pub fn new(ccx: &'a CrateContext<'a, 'tcx>) -> Builder<'a, 'tcx> {
+    pub fn with_ccx(ccx: &'a CrateContext<'a, 'tcx>) -> Self {
+        // Create a fresh builder from the crate context.
+        let llbuilder = unsafe {
+            llvm::LLVMCreateBuilderInContext(ccx.llcx())
+        };
         Builder {
-            llbuilder: ccx.raw_builder(),
+            llbuilder: llbuilder,
             ccx: ccx,
         }
     }
 
-    pub fn count_insn(&self, category: &str) {
+    fn count_insn(&self, category: &str) {
         if self.ccx.sess().trans_stats() {
-            self.ccx.stats().n_llvm_insns.set(self.ccx
-                                                .stats()
-                                                .n_llvm_insns
-                                                .get() + 1);
+            self.ccx.stats().n_llvm_insns.set(self.ccx.stats().n_llvm_insns.get() + 1);
         }
-        self.ccx.count_llvm_insn();
         if self.ccx.sess().count_llvm_insns() {
-            base::with_insn_ctxt(|v| {
-                let mut h = self.ccx.stats().llvm_insns.borrow_mut();
-
-                // Build version of path with cycles removed.
-
-                // Pass 1: scan table mapping str -> rightmost pos.
-                let mut mm = FxHashMap();
-                let len = v.len();
-                let mut i = 0;
-                while i < len {
-                    mm.insert(v[i], i);
-                    i += 1;
-                }
-
-                // Pass 2: concat strings for each elt, skipping
-                // forwards over any cycles by advancing to rightmost
-                // occurrence of each element in path.
-                let mut s = String::from(".");
-                i = 0;
-                while i < len {
-                    i = mm[v[i]];
-                    s.push('/');
-                    s.push_str(v[i]);
-                    i += 1;
-                }
-
-                s.push('/');
-                s.push_str(category);
-
-                let n = match h.get(&s) {
-                    Some(&n) => n,
-                    _ => 0
-                };
-                h.insert(s, n+1);
-            })
+            let mut h = self.ccx.stats().llvm_insns.borrow_mut();
+            *h.entry(category.to_string()).or_insert(0) += 1;
         }
     }
 
@@ -462,7 +435,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
     }
 
-    pub fn alloca(&self, ty: Type, name: &str) -> ValueRef {
+    pub fn dynamic_alloca(&self, ty: Type, name: &str) -> ValueRef {
         self.count_insn("alloca");
         unsafe {
             if name.is_empty() {
@@ -1103,6 +1076,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
     }
 
+    pub fn add_case(&self, s: ValueRef, on_val: ValueRef, dest: BasicBlockRef) {
+        unsafe {
+            if llvm::LLVMIsUndef(s) == llvm::True { return; }
+            llvm::LLVMAddCase(s, on_val, dest)
+        }
+    }
+
+    pub fn add_incoming_to_phi(&self, phi: ValueRef, val: ValueRef, bb: BasicBlockRef) {
+        unsafe {
+            if llvm::LLVMIsUndef(phi) == llvm::True { return; }
+            llvm::LLVMAddIncoming(phi, &val, &bb, 1 as c_uint);
+        }
+    }
+
     /// Returns the ptr value that should be used for storing `val`.
     fn check_store<'b>(&self,
                        val: ValueRef,
diff --git a/src/librustc_trans/cabi_arm.rs b/src/librustc_trans/cabi_arm.rs
index 93d43f7d961..85b26074bae 100644
--- a/src/librustc_trans/cabi_arm.rs
+++ b/src/librustc_trans/cabi_arm.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_upper_case_globals)]
-
 use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
 use abi::{self, align_up_to, FnType, ArgType};
 use context::CrateContext;
diff --git a/src/librustc_trans/cabi_sparc.rs b/src/librustc_trans/cabi_sparc.rs
new file mode 100644
index 00000000000..25fe53e7ef4
--- /dev/null
+++ b/src/librustc_trans/cabi_sparc.rs
@@ -0,0 +1,108 @@
+// Copyright 2012-2013 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.
+
+#![allow(non_upper_case_globals)]
+
+use libc::c_uint;
+use std::cmp;
+use llvm;
+use llvm::{Integer, Pointer, Float, Double, Vector};
+use abi::{self, align_up_to, ArgType, FnType};
+use context::CrateContext;
+use type_::Type;
+
+fn ty_align(ty: Type) -> usize {
+    abi::ty_align(ty, 4)
+}
+
+fn ty_size(ty: Type) -> usize {
+    abi::ty_size(ty, 4)
+}
+
+fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
+    if is_reg_ty(ret.ty) {
+        ret.extend_integer_width_to(32);
+    } else {
+        ret.make_indirect(ccx);
+    }
+}
+
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
+    let orig_offset = *offset;
+    let size = ty_size(arg.ty) * 8;
+    let mut align = ty_align(arg.ty);
+
+    align = cmp::min(cmp::max(align, 4), 8);
+    *offset = align_up_to(*offset, align);
+    *offset += align_up_to(size, align * 8) / 8;
+
+    if !is_reg_ty(arg.ty) {
+        arg.cast = Some(struct_ty(ccx, arg.ty));
+        arg.pad = padding_ty(ccx, align, orig_offset);
+    } else {
+        arg.extend_integer_width_to(32);
+    }
+}
+
+fn is_reg_ty(ty: Type) -> bool {
+    return match ty.kind() {
+        Integer
+        | Pointer
+        | Float
+        | Double
+        | Vector => true,
+        _ => false
+    };
+}
+
+fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option<Type> {
+    if ((align - 1 ) & offset) > 0 {
+        Some(Type::i32(ccx))
+    } else {
+        None
+    }
+}
+
+fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec<Type> {
+    let int_ty = Type::i32(ccx);
+    let mut args = Vec::new();
+
+    let mut n = size / 32;
+    while n > 0 {
+        args.push(int_ty);
+        n -= 1;
+    }
+
+    let r = size % 32;
+    if r > 0 {
+        unsafe {
+            args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
+        }
+    }
+
+    args
+}
+
+fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
+    let size = ty_size(ty) * 8;
+    Type::struct_(ccx, &coerce_to_int(ccx, size), false)
+}
+
+pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(ccx, &mut fty.ret);
+    }
+
+    let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };
+    for arg in &mut fty.args {
+        if arg.is_ignore() { continue; }
+        classify_arg_ty(ccx, arg, &mut offset);
+    }
+}
diff --git a/src/librustc_trans/cabi_x86.rs b/src/librustc_trans/cabi_x86.rs
index ce85234f203..fea005f3d77 100644
--- a/src/librustc_trans/cabi_x86.rs
+++ b/src/librustc_trans/cabi_x86.rs
@@ -14,7 +14,13 @@ use type_::Type;
 use super::common::*;
 use super::machine::*;
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+#[derive(PartialEq)]
+pub enum Flavor {
+    General,
+    Fastcall
+}
+
+pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
     if !fty.ret.is_ignore() {
         if fty.ret.ty.kind() == Struct {
             // Returning a structure. Most often, this will use
@@ -51,4 +57,46 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
             arg.extend_integer_width_to(32);
         }
     }
+
+    if flavor == Flavor::Fastcall {
+        // Mark arguments as InReg like clang does it,
+        // so our fastcall is compatible with C/C++ fastcall.
+
+        // Clang reference: lib/CodeGen/TargetInfo.cpp
+        // See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs()
+
+        // IsSoftFloatABI is only set to true on ARM platforms,
+        // which in turn can't be x86?
+
+        let mut free_regs = 2;
+
+        for arg in &mut fty.args {
+            if arg.is_ignore() || arg.is_indirect() { continue; }
+
+            if arg.ty.kind() == Float {
+                continue;
+            }
+
+            let size = llbitsize_of_real(ccx, arg.ty);
+            let size_in_regs = (size + 31) / 32;
+
+            if size_in_regs == 0 {
+                continue;
+            }
+
+            if size_in_regs > free_regs {
+                break;
+            }
+
+            free_regs -= size_in_regs;
+
+            if size <= 32 && (arg.ty.kind() == Pointer || arg.ty.kind() == Integer) {
+                arg.attrs.set(ArgAttribute::InReg);
+            }
+
+            if free_regs == 0 {
+                break;
+            }
+        }
+    }
 }
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index d7e9f1372e0..1abe25ea607 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -16,7 +16,6 @@
 
 pub use self::CalleeData::*;
 
-use arena::TypedArena;
 use llvm::{self, ValueRef, get_params};
 use rustc::hir::def_id::DefId;
 use rustc::ty::subst::Substs;
@@ -25,10 +24,11 @@ use abi::{Abi, FnType};
 use attributes;
 use base;
 use base::*;
-use build::*;
-use common::{self, Block, Result, CrateContext, FunctionContext, SharedCrateContext};
+use common::{
+    self, CrateContext, FunctionContext, SharedCrateContext
+};
+use adt::MaybeSizedValue;
 use consts;
-use debuginfo::DebugLoc;
 use declare;
 use value::Value;
 use meth;
@@ -71,25 +71,8 @@ impl<'tcx> Callee<'tcx> {
         }
     }
 
-    /// Trait or impl method call.
-    pub fn method_call<'blk>(bcx: Block<'blk, 'tcx>,
-                             method_call: ty::MethodCall)
-                             -> Callee<'tcx> {
-        let method = bcx.tcx().tables().method_map[&method_call];
-        Callee::method(bcx, method)
-    }
-
-    /// Trait or impl method.
-    pub fn method<'blk>(bcx: Block<'blk, 'tcx>,
-                        method: ty::MethodCallee<'tcx>) -> Callee<'tcx> {
-        let substs = bcx.fcx.monomorphize(&method.substs);
-        Callee::def(bcx.ccx(), method.def_id, substs)
-    }
-
     /// Function or method definition.
-    pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>,
-                   def_id: DefId,
-                   substs: &'tcx Substs<'tcx>)
+    pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>)
                    -> Callee<'tcx> {
         let tcx = ccx.tcx();
 
@@ -196,25 +179,6 @@ impl<'tcx> Callee<'tcx> {
         fn_ty
     }
 
-    /// This behemoth of a function translates function calls. Unfortunately, in
-    /// order to generate more efficient LLVM output at -O0, it has quite a complex
-    /// signature (refactoring this into two functions seems like a good idea).
-    ///
-    /// In particular, for lang items, it is invoked with a dest of None, and in
-    /// that case the return value contains the result of the fn. The lang item must
-    /// not return a structural type or else all heck breaks loose.
-    ///
-    /// For non-lang items, `dest` is always Some, and hence the result is written
-    /// into memory somewhere. Nonetheless we return the actual return value of the
-    /// function.
-    pub fn call<'a, 'blk>(self, bcx: Block<'blk, 'tcx>,
-                          debug_loc: DebugLoc,
-                          args: &[ValueRef],
-                          dest: Option<ValueRef>)
-                          -> Result<'blk, 'tcx> {
-        trans_call_inner(bcx, debug_loc, self, args, dest)
-    }
-
     /// Turn the callee into a function pointer.
     pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
         match self.data {
@@ -267,8 +231,6 @@ fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
     // then adapt the self type
     let llfn_closure_kind = ccx.tcx().closure_kind(def_id);
 
-    let _icx = push_ctxt("trans_closure_adapter_shim");
-
     debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \
            trait_closure_kind={:?}, llfn={:?})",
            llfn_closure_kind, trait_closure_kind, Value(llfn));
@@ -367,23 +329,28 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty);
     attributes::set_frame_pointer_elimination(ccx, lloncefn);
 
-    let (block_arena, fcx): (TypedArena<_>, FunctionContext);
-    block_arena = TypedArena::new();
-    fcx = FunctionContext::new(ccx, lloncefn, fn_ty, None, &block_arena);
-    let mut bcx = fcx.init(false);
+    let orig_fn_ty = fn_ty;
+    let fcx = FunctionContext::new(ccx, lloncefn);
+    let mut bcx = fcx.get_entry_block();
 
+    let callee = Callee {
+        data: Fn(llreffn),
+        ty: llref_fn_ty
+    };
 
     // the first argument (`self`) will be the (by value) closure env.
 
     let mut llargs = get_params(fcx.llfn);
-    let mut self_idx = fcx.fn_ty.ret.is_indirect() as usize;
-    let env_arg = &fcx.fn_ty.args[0];
+    let fn_ret = callee.ty.fn_ret();
+    let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
+    let self_idx = fn_ty.ret.is_indirect() as usize;
+    let env_arg = &orig_fn_ty.args[0];
     let llenv = if env_arg.is_indirect() {
         llargs[self_idx]
     } else {
-        let scratch = alloc_ty(bcx, closure_ty, "self");
+        let scratch = alloc_ty(&bcx, closure_ty, "self");
         let mut llarg_idx = self_idx;
-        env_arg.store_fn_arg(&bcx.build(), &mut llarg_idx, scratch);
+        env_arg.store_fn_arg(&bcx, &mut llarg_idx, scratch);
         scratch
     };
 
@@ -391,33 +358,37 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     // Adjust llargs such that llargs[self_idx..] has the call arguments.
     // For zero-sized closures that means sneaking in a new argument.
     if env_arg.is_ignore() {
-        if self_idx > 0 {
-            self_idx -= 1;
-            llargs[self_idx] = llenv;
-        } else {
-            llargs.insert(0, llenv);
-        }
+        llargs.insert(self_idx, llenv);
     } else {
         llargs[self_idx] = llenv;
     }
 
-    let dest = fcx.llretslotptr.get();
-
-    let callee = Callee {
-        data: Fn(llreffn),
-        ty: llref_fn_ty
-    };
-
     // Call the by-ref closure body with `self` in a cleanup scope,
     // to drop `self` when the body returns, or in case it unwinds.
-    let self_scope = fcx.push_custom_cleanup_scope();
-    fcx.schedule_drop_mem(self_scope, llenv, closure_ty);
-
-    bcx = callee.call(bcx, DebugLoc::None, &llargs[self_idx..], dest).bcx;
+    let self_scope = fcx.schedule_drop_mem(MaybeSizedValue::sized(llenv), closure_ty);
+
+    let llfn = callee.reify(bcx.ccx);
+    let llret;
+    if let Some(landing_pad) = self_scope.landing_pad {
+        let normal_bcx = bcx.fcx().build_new_block("normal-return");
+        llret = bcx.invoke(llfn, &llargs[..], normal_bcx.llbb(), landing_pad, None);
+        bcx = normal_bcx;
+    } else {
+        llret = bcx.call(llfn, &llargs[..], None);
+    }
+    fn_ty.apply_attrs_callsite(llret);
 
-    fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope);
+    if fn_ret.0.is_never() {
+        bcx.unreachable();
+    } else {
+        self_scope.trans(&bcx);
 
-    fcx.finish(bcx, DebugLoc::None);
+        if fn_ty.ret.is_indirect() || fn_ty.ret.is_ignore() {
+            bcx.ret_void();
+        } else {
+            bcx.ret(llret);
+        }
+    }
 
     ccx.instances().borrow_mut().insert(method_instance, lloncefn);
 
@@ -443,7 +414,6 @@ fn trans_fn_pointer_shim<'a, 'tcx>(
     bare_fn_ty: Ty<'tcx>)
     -> ValueRef
 {
-    let _icx = push_ctxt("trans_fn_pointer_shim");
     let tcx = ccx.tcx();
 
     // Normalize the type for better caching.
@@ -519,32 +489,39 @@ fn trans_fn_pointer_shim<'a, 'tcx>(
     let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty);
     attributes::set_frame_pointer_elimination(ccx, llfn);
     //
-    let (block_arena, fcx): (TypedArena<_>, FunctionContext);
-    block_arena = TypedArena::new();
-    fcx = FunctionContext::new(ccx, llfn, fn_ty, None, &block_arena);
-    let mut bcx = fcx.init(false);
+    let fcx = FunctionContext::new(ccx, llfn);
+    let bcx = fcx.get_entry_block();
 
-    let llargs = get_params(fcx.llfn);
+    let mut llargs = get_params(fcx.llfn);
 
-    let self_idx = fcx.fn_ty.ret.is_indirect() as usize;
+    let self_arg = llargs.remove(fn_ty.ret.is_indirect() as usize);
     let llfnpointer = llfnpointer.unwrap_or_else(|| {
         // the first argument (`self`) will be ptr to the fn pointer
         if is_by_ref {
-            Load(bcx, llargs[self_idx])
+            bcx.load(self_arg)
         } else {
-            llargs[self_idx]
+            self_arg
         }
     });
 
-    let dest = fcx.llretslotptr.get();
-
     let callee = Callee {
         data: Fn(llfnpointer),
         ty: bare_fn_ty
     };
-    bcx = callee.call(bcx, DebugLoc::None, &llargs[(self_idx + 1)..], dest).bcx;
+    let fn_ret = callee.ty.fn_ret();
+    let fn_ty = callee.direct_fn_type(ccx, &[]);
+    let llret = bcx.call(llfnpointer, &llargs, None);
+    fn_ty.apply_attrs_callsite(llret);
 
-    fcx.finish(bcx, DebugLoc::None);
+    if fn_ret.0.is_never() {
+        bcx.unreachable();
+    } else {
+        if fn_ty.ret.is_indirect() || fn_ty.ret.is_ignore() {
+            bcx.ret_void();
+        } else {
+            bcx.ret(llret);
+        }
+    }
 
     ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref, llfn);
 
@@ -649,87 +626,3 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     (llfn, fn_ty)
 }
-
-// ______________________________________________________________________
-// Translating calls
-
-fn trans_call_inner<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                    debug_loc: DebugLoc,
-                                    callee: Callee<'tcx>,
-                                    args: &[ValueRef],
-                                    opt_llretslot: Option<ValueRef>)
-                                    -> Result<'blk, 'tcx> {
-    // Introduce a temporary cleanup scope that will contain cleanups
-    // for the arguments while they are being evaluated. The purpose
-    // this cleanup is to ensure that, should a panic occur while
-    // evaluating argument N, the values for arguments 0...N-1 are all
-    // cleaned up. If no panic occurs, the values are handed off to
-    // the callee, and hence none of the cleanups in this temporary
-    // scope will ever execute.
-    let fcx = bcx.fcx;
-    let ccx = fcx.ccx;
-
-    let fn_ret = callee.ty.fn_ret();
-    let fn_ty = callee.direct_fn_type(ccx, &[]);
-
-    let mut callee = match callee.data {
-        NamedTupleConstructor(_) | Intrinsic => {
-            bug!("{:?} calls should not go through Callee::call", callee);
-        }
-        f => f
-    };
-
-    // If there no destination, return must be direct, with no cast.
-    if opt_llretslot.is_none() {
-        assert!(!fn_ty.ret.is_indirect() && fn_ty.ret.cast.is_none());
-    }
-
-    let mut llargs = Vec::new();
-
-    if fn_ty.ret.is_indirect() {
-        let mut llretslot = opt_llretslot.unwrap();
-        if let Some(ty) = fn_ty.ret.cast {
-            llretslot = PointerCast(bcx, llretslot, ty.ptr_to());
-        }
-        llargs.push(llretslot);
-    }
-
-    match callee {
-        Virtual(idx) => {
-            llargs.push(args[0]);
-
-            let fn_ptr = meth::get_virtual_method(bcx, args[1], idx);
-            let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to();
-            callee = Fn(PointerCast(bcx, fn_ptr, llty));
-            llargs.extend_from_slice(&args[2..]);
-        }
-        _ => llargs.extend_from_slice(args)
-    }
-
-    let llfn = match callee {
-        Fn(f) => f,
-        _ => bug!("expected fn pointer callee, found {:?}", callee)
-    };
-
-    let (llret, bcx) = base::invoke(bcx, llfn, &llargs, debug_loc);
-    if !bcx.unreachable.get() {
-        fn_ty.apply_attrs_callsite(llret);
-
-        // If the function we just called does not use an outpointer,
-        // store the result into the rust outpointer. Cast the outpointer
-        // type to match because some ABIs will use a different type than
-        // the Rust type. e.g., a {u32,u32} struct could be returned as
-        // u64.
-        if !fn_ty.ret.is_indirect() {
-            if let Some(llretslot) = opt_llretslot {
-                fn_ty.ret.store(&bcx.build(), llret, llretslot);
-            }
-        }
-    }
-
-    if fn_ret.0.is_never() {
-        Unreachable(bcx);
-    }
-
-    Result::new(bcx, llret)
-}
diff --git a/src/librustc_trans/cleanup.rs b/src/librustc_trans/cleanup.rs
index b9f24eba9dc..4e59ea3f6c5 100644
--- a/src/librustc_trans/cleanup.rs
+++ b/src/librustc_trans/cleanup.rs
@@ -11,216 +11,98 @@
 //! ## The Cleanup module
 //!
 //! The cleanup module tracks what values need to be cleaned up as scopes
-//! are exited, either via panic or just normal control flow. The basic
-//! idea is that the function context maintains a stack of cleanup scopes
-//! that are pushed/popped as we traverse the AST tree. There is typically
-//! at least one cleanup scope per AST node; some AST nodes may introduce
-//! additional temporary scopes.
+//! are exited, either via panic or just normal control flow.
 //!
 //! Cleanup items can be scheduled into any of the scopes on the stack.
-//! Typically, when a scope is popped, we will also generate the code for
-//! each of its cleanups at that time. This corresponds to a normal exit
-//! from a block (for example, an expression completing evaluation
-//! successfully without panic). However, it is also possible to pop a
-//! block *without* executing its cleanups; this is typically used to
-//! guard intermediate values that must be cleaned up on panic, but not
-//! if everything goes right. See the section on custom scopes below for
-//! more details.
-//!
-//! Cleanup scopes come in three kinds:
-//!
-//! - **AST scopes:** each AST node in a function body has a corresponding
-//!   AST scope. We push the AST scope when we start generate code for an AST
-//!   node and pop it once the AST node has been fully generated.
-//! - **Loop scopes:** loops have an additional cleanup scope. Cleanups are
-//!   never scheduled into loop scopes; instead, they are used to record the
-//!   basic blocks that we should branch to when a `continue` or `break` statement
-//!   is encountered.
-//! - **Custom scopes:** custom scopes are typically used to ensure cleanup
-//!   of intermediate values.
-//!
-//! ### When to schedule cleanup
-//!
-//! Although the cleanup system is intended to *feel* fairly declarative,
-//! it's still important to time calls to `schedule_clean()` correctly.
-//! Basically, you should not schedule cleanup for memory until it has
-//! been initialized, because if an unwind should occur before the memory
-//! is fully initialized, then the cleanup will run and try to free or
-//! drop uninitialized memory. If the initialization itself produces
-//! byproducts that need to be freed, then you should use temporary custom
-//! scopes to ensure that those byproducts will get freed on unwind.  For
-//! example, an expression like `box foo()` will first allocate a box in the
-//! heap and then call `foo()` -- if `foo()` should panic, this box needs
-//! to be *shallowly* freed.
-//!
-//! ### Long-distance jumps
-//!
-//! In addition to popping a scope, which corresponds to normal control
-//! flow exiting the scope, we may also *jump out* of a scope into some
-//! earlier scope on the stack. This can occur in response to a `return`,
-//! `break`, or `continue` statement, but also in response to panic. In
-//! any of these cases, we will generate a series of cleanup blocks for
-//! each of the scopes that is exited. So, if the stack contains scopes A
-//! ... Z, and we break out of a loop whose corresponding cleanup scope is
-//! X, we would generate cleanup blocks for the cleanups in X, Y, and Z.
-//! After cleanup is done we would branch to the exit point for scope X.
-//! But if panic should occur, we would generate cleanups for all the
-//! scopes from A to Z and then resume the unwind process afterwards.
-//!
-//! To avoid generating tons of code, we cache the cleanup blocks that we
-//! create for breaks, returns, unwinds, and other jumps. Whenever a new
-//! cleanup is scheduled, though, we must clear these cached blocks. A
-//! possible improvement would be to keep the cached blocks but simply
-//! generate a new block which performs the additional cleanup and then
-//! branches to the existing cached blocks.
-//!
-//! ### AST and loop cleanup scopes
-//!
-//! AST cleanup scopes are pushed when we begin and end processing an AST
-//! node. They are used to house cleanups related to rvalue temporary that
-//! get referenced (e.g., due to an expression like `&Foo()`). Whenever an
-//! AST scope is popped, we always trans all the cleanups, adding the cleanup
-//! code after the postdominator of the AST node.
-//!
-//! AST nodes that represent breakable loops also push a loop scope; the
-//! loop scope never has any actual cleanups, it's just used to point to
-//! the basic blocks where control should flow after a "continue" or
-//! "break" statement. Popping a loop scope never generates code.
-//!
-//! ### Custom cleanup scopes
-//!
-//! Custom cleanup scopes are used for a variety of purposes. The most
-//! common though is to handle temporary byproducts, where cleanup only
-//! needs to occur on panic. The general strategy is to push a custom
-//! cleanup scope, schedule *shallow* cleanups into the custom scope, and
-//! then pop the custom scope (without transing the cleanups) when
-//! execution succeeds normally. This way the cleanups are only trans'd on
-//! unwind, and only up until the point where execution succeeded, at
-//! which time the complete value should be stored in an lvalue or some
-//! other place where normal cleanup applies.
-//!
-//! To spell it out, here is an example. Imagine an expression `box expr`.
-//! We would basically:
-//!
-//! 1. Push a custom cleanup scope C.
-//! 2. Allocate the box.
-//! 3. Schedule a shallow free in the scope C.
-//! 4. Trans `expr` into the box.
-//! 5. Pop the scope C.
-//! 6. Return the box as an rvalue.
-//!
-//! This way, if a panic occurs while transing `expr`, the custom
-//! cleanup scope C is pushed and hence the box will be freed. The trans
-//! code for `expr` itself is responsible for freeing any other byproducts
-//! that may be in play.
-
-pub use self::EarlyExitLabel::*;
+//! Typically, when a scope is finished, we generate the cleanup code. This
+//! corresponds to a normal exit from a block (for example, an expression
+//! completing evaluation successfully without panic).
 
-use llvm::{BasicBlockRef, ValueRef};
+use llvm::BasicBlockRef;
 use base;
-use build;
-use common;
-use common::{Block, FunctionContext, LandingPad};
-use debuginfo::{DebugLoc};
+use adt::MaybeSizedValue;
+use common::{BlockAndBuilder, FunctionContext, Funclet};
 use glue;
 use type_::Type;
-use value::Value;
 use rustc::ty::Ty;
 
 pub struct CleanupScope<'tcx> {
-    // Cleanups to run upon scope exit.
-    cleanups: Vec<DropValue<'tcx>>,
-
-    // The debug location any drop calls generated for this scope will be
-    // associated with.
-    debug_loc: DebugLoc,
+    // Cleanup to run upon scope exit.
+    cleanup: Option<DropValue<'tcx>>,
 
-    cached_early_exits: Vec<CachedEarlyExit>,
-    cached_landing_pad: Option<BasicBlockRef>,
+    // Computed on creation if compiling with landing pads (!sess.no_landing_pads)
+    pub landing_pad: Option<BasicBlockRef>,
 }
 
-#[derive(Copy, Clone, Debug)]
-pub struct CustomScopeIndex {
-    index: usize
+#[derive(Copy, Clone)]
+pub struct DropValue<'tcx> {
+    val: MaybeSizedValue,
+    ty: Ty<'tcx>,
+    skip_dtor: bool,
 }
 
-#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum EarlyExitLabel {
-    UnwindExit(UnwindKind),
-}
+impl<'tcx> DropValue<'tcx> {
+    fn trans<'a>(&self, funclet: Option<&'a Funclet>, bcx: &BlockAndBuilder<'a, 'tcx>) {
+        glue::call_drop_glue(bcx, self.val, self.ty, self.skip_dtor, funclet)
+    }
 
-#[derive(Copy, Clone, Debug)]
-pub enum UnwindKind {
-    LandingPad,
-    CleanupPad(ValueRef),
-}
+    /// Creates a landing pad for the top scope. The landing pad will perform all cleanups necessary
+    /// for an unwind and then `resume` to continue error propagation:
+    ///
+    ///     landing_pad -> ... cleanups ... -> [resume]
+    ///
+    /// This should only be called once per function, as it creates an alloca for the landingpad.
+    fn get_landing_pad<'a>(&self, fcx: &FunctionContext<'a, 'tcx>) -> BasicBlockRef {
+        debug!("get_landing_pad");
+        let bcx = fcx.build_new_block("cleanup_unwind");
+        let llpersonality = bcx.ccx.eh_personality();
+        bcx.set_personality_fn(llpersonality);
 
-#[derive(Copy, Clone)]
-pub struct CachedEarlyExit {
-    label: EarlyExitLabel,
-    cleanup_block: BasicBlockRef,
-    last_cleanup: usize,
-}
+        if base::wants_msvc_seh(fcx.ccx.sess()) {
+            let pad = bcx.cleanup_pad(None, &[]);
+            let funclet = Some(Funclet::new(pad));
+            self.trans(funclet.as_ref(), &bcx);
 
-impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
-    pub fn push_custom_cleanup_scope(&self) -> CustomScopeIndex {
-        let index = self.scopes_len();
-        debug!("push_custom_cleanup_scope(): {}", index);
+            bcx.cleanup_ret(pad, None);
+        } else {
+            // The landing pad return type (the type being propagated). Not sure
+            // what this represents but it's determined by the personality
+            // function and this is what the EH proposal example uses.
+            let llretty = Type::struct_(fcx.ccx, &[Type::i8p(fcx.ccx), Type::i32(fcx.ccx)], false);
 
-        // Just copy the debuginfo source location from the enclosing scope
-        let debug_loc = self.scopes
-                            .borrow()
-                            .last()
-                            .map(|opt_scope| opt_scope.debug_loc)
-                            .unwrap_or(DebugLoc::None);
+            // The only landing pad clause will be 'cleanup'
+            let llretval = bcx.landing_pad(llretty, llpersonality, 1, bcx.fcx().llfn);
 
-        self.push_scope(CleanupScope::new(debug_loc));
-        CustomScopeIndex { index: index }
-    }
+            // The landing pad block is a cleanup
+            bcx.set_cleanup(llretval);
 
-    /// Removes the top cleanup scope from the stack without executing its cleanups. The top
-    /// cleanup scope must be the temporary scope `custom_scope`.
-    pub fn pop_custom_cleanup_scope(&self,
-                                    custom_scope: CustomScopeIndex) {
-        debug!("pop_custom_cleanup_scope({})", custom_scope.index);
-        assert!(self.is_valid_to_pop_custom_scope(custom_scope));
-        let _ = self.pop_scope();
-    }
+            // Insert cleanup instructions into the cleanup block
+            self.trans(None, &bcx);
 
-    /// Removes the top cleanup scope from the stack, which must be a temporary scope, and
-    /// generates the code to do its cleanups for normal exit.
-    pub fn pop_and_trans_custom_cleanup_scope(&self,
-                                              bcx: Block<'blk, 'tcx>,
-                                              custom_scope: CustomScopeIndex)
-                                              -> Block<'blk, 'tcx> {
-        debug!("pop_and_trans_custom_cleanup_scope({:?})", custom_scope);
-        assert!(self.is_valid_to_pop_custom_scope(custom_scope));
+            if !bcx.sess().target.target.options.custom_unwind_resume {
+                bcx.resume(llretval);
+            } else {
+                let exc_ptr = bcx.extract_value(llretval, 0);
+                bcx.call(bcx.ccx.eh_unwind_resume(), &[exc_ptr], None);
+                bcx.unreachable();
+            }
+        }
 
-        let scope = self.pop_scope();
-        self.trans_scope_cleanups(bcx, &scope)
+        bcx.llbb()
     }
+}
 
-    /// Schedules a (deep) drop of `val`, which is a pointer to an instance of
-    /// `ty`
-    pub fn schedule_drop_mem(&self,
-                             cleanup_scope: CustomScopeIndex,
-                             val: ValueRef,
-                             ty: Ty<'tcx>) {
-        if !self.type_needs_drop(ty) { return; }
+impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
+    /// Schedules a (deep) drop of `val`, which is a pointer to an instance of `ty`
+    pub fn schedule_drop_mem(&self, val: MaybeSizedValue, ty: Ty<'tcx>) -> CleanupScope<'tcx> {
+        if !self.ccx.shared().type_needs_drop(ty) { return CleanupScope::noop(); }
         let drop = DropValue {
-            is_immediate: false,
             val: val,
             ty: ty,
             skip_dtor: false,
         };
 
-        debug!("schedule_drop_mem({:?}, val={:?}, ty={:?}) skip_dtor={}",
-               cleanup_scope,
-               Value(val),
-               ty,
-               drop.skip_dtor);
-
-        self.schedule_clean(cleanup_scope, drop);
+        CleanupScope::new(self, drop)
     }
 
     /// Issue #23611: Schedules a (deep) drop of the contents of
@@ -228,477 +110,44 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
     /// `ty`. The scheduled code handles extracting the discriminant
     /// and dropping the contents associated with that variant
     /// *without* executing any associated drop implementation.
-    pub fn schedule_drop_adt_contents(&self,
-                                      cleanup_scope: CustomScopeIndex,
-                                      val: ValueRef,
-                                      ty: Ty<'tcx>) {
+    pub fn schedule_drop_adt_contents(&self, val: MaybeSizedValue, ty: Ty<'tcx>)
+        -> CleanupScope<'tcx> {
         // `if` below could be "!contents_needs_drop"; skipping drop
         // is just an optimization, so sound to be conservative.
-        if !self.type_needs_drop(ty) { return; }
+        if !self.ccx.shared().type_needs_drop(ty) { return CleanupScope::noop(); }
 
         let drop = DropValue {
-            is_immediate: false,
             val: val,
             ty: ty,
             skip_dtor: true,
         };
 
-        debug!("schedule_drop_adt_contents({:?}, val={:?}, ty={:?}) skip_dtor={}",
-               cleanup_scope,
-               Value(val),
-               ty,
-               drop.skip_dtor);
-
-        self.schedule_clean(cleanup_scope, drop);
-    }
-
-    /// Schedules a (deep) drop of `val`, which is an instance of `ty`
-    pub fn schedule_drop_immediate(&self,
-                                   cleanup_scope: CustomScopeIndex,
-                                   val: ValueRef,
-                                   ty: Ty<'tcx>) {
-
-        if !self.type_needs_drop(ty) { return; }
-        let drop = DropValue {
-            is_immediate: true,
-            val: val,
-            ty: ty,
-            skip_dtor: false,
-        };
-
-        debug!("schedule_drop_immediate({:?}, val={:?}, ty={:?}) skip_dtor={}",
-               cleanup_scope,
-               Value(val),
-               ty,
-               drop.skip_dtor);
-
-        self.schedule_clean(cleanup_scope, drop);
-    }
-
-    /// Schedules a cleanup to occur in the top-most scope, which must be a temporary scope.
-    fn schedule_clean(&self, custom_scope: CustomScopeIndex, cleanup: DropValue<'tcx>) {
-        debug!("schedule_clean_in_custom_scope(custom_scope={})",
-               custom_scope.index);
-
-        assert!(self.is_valid_custom_scope(custom_scope));
-
-        let mut scopes = self.scopes.borrow_mut();
-        let scope = &mut (*scopes)[custom_scope.index];
-        scope.cleanups.push(cleanup);
-        scope.cached_landing_pad = None;
-    }
-
-    /// Returns true if there are pending cleanups that should execute on panic.
-    pub fn needs_invoke(&self) -> bool {
-        self.scopes.borrow().iter().rev().any(|s| s.needs_invoke())
-    }
-
-    /// Returns a basic block to branch to in the event of a panic. This block
-    /// will run the panic cleanups and eventually resume the exception that
-    /// caused the landing pad to be run.
-    pub fn get_landing_pad(&'blk self) -> BasicBlockRef {
-        let _icx = base::push_ctxt("get_landing_pad");
-
-        debug!("get_landing_pad");
-
-        let orig_scopes_len = self.scopes_len();
-        assert!(orig_scopes_len > 0);
-
-        // Remove any scopes that do not have cleanups on panic:
-        let mut popped_scopes = vec![];
-        while !self.top_scope(|s| s.needs_invoke()) {
-            debug!("top scope does not need invoke");
-            popped_scopes.push(self.pop_scope());
-        }
-
-        // Check for an existing landing pad in the new topmost scope:
-        let llbb = self.get_or_create_landing_pad();
-
-        // Push the scopes we removed back on:
-        loop {
-            match popped_scopes.pop() {
-                Some(scope) => self.push_scope(scope),
-                None => break
-            }
-        }
-
-        assert_eq!(self.scopes_len(), orig_scopes_len);
-
-        return llbb;
-    }
-
-    fn is_valid_to_pop_custom_scope(&self, custom_scope: CustomScopeIndex) -> bool {
-        self.is_valid_custom_scope(custom_scope) &&
-            custom_scope.index == self.scopes.borrow().len() - 1
-    }
-
-    fn is_valid_custom_scope(&self, custom_scope: CustomScopeIndex) -> bool {
-        let scopes = self.scopes.borrow();
-        custom_scope.index < scopes.len()
-    }
-
-    /// Generates the cleanups for `scope` into `bcx`
-    fn trans_scope_cleanups(&self, // cannot borrow self, will recurse
-                            bcx: Block<'blk, 'tcx>,
-                            scope: &CleanupScope<'tcx>) -> Block<'blk, 'tcx> {
-
-        let mut bcx = bcx;
-        if !bcx.unreachable.get() {
-            for cleanup in scope.cleanups.iter().rev() {
-                bcx = cleanup.trans(bcx, scope.debug_loc);
-            }
-        }
-        bcx
-    }
-
-    fn scopes_len(&self) -> usize {
-        self.scopes.borrow().len()
-    }
-
-    fn push_scope(&self, scope: CleanupScope<'tcx>) {
-        self.scopes.borrow_mut().push(scope)
-    }
-
-    fn pop_scope(&self) -> CleanupScope<'tcx> {
-        debug!("popping cleanup scope {}, {} scopes remaining",
-               self.top_scope(|s| s.block_name("")),
-               self.scopes_len() - 1);
-
-        self.scopes.borrow_mut().pop().unwrap()
-    }
-
-    fn top_scope<R, F>(&self, f: F) -> R where F: FnOnce(&CleanupScope<'tcx>) -> R {
-        f(self.scopes.borrow().last().unwrap())
-    }
-
-    /// Used when the caller wishes to jump to an early exit, such as a return,
-    /// break, continue, or unwind. This function will generate all cleanups
-    /// between the top of the stack and the exit `label` and return a basic
-    /// block that the caller can branch to.
-    ///
-    /// For example, if the current stack of cleanups were as follows:
-    ///
-    ///      AST 22
-    ///      Custom 1
-    ///      AST 23
-    ///      Loop 23
-    ///      Custom 2
-    ///      AST 24
-    ///
-    /// and the `label` specifies a break from `Loop 23`, then this function
-    /// would generate a series of basic blocks as follows:
-    ///
-    ///      Cleanup(AST 24) -> Cleanup(Custom 2) -> break_blk
-    ///
-    /// where `break_blk` is the block specified in `Loop 23` as the target for
-    /// breaks. The return value would be the first basic block in that sequence
-    /// (`Cleanup(AST 24)`). The caller could then branch to `Cleanup(AST 24)`
-    /// and it will perform all cleanups and finally branch to the `break_blk`.
-    fn trans_cleanups_to_exit_scope(&'blk self,
-                                    label: EarlyExitLabel)
-                                    -> BasicBlockRef {
-        debug!("trans_cleanups_to_exit_scope label={:?} scopes={}",
-               label, self.scopes_len());
-
-        let orig_scopes_len = self.scopes_len();
-        let mut prev_llbb;
-        let mut popped_scopes = vec![];
-        let mut skip = 0;
-
-        // First we pop off all the cleanup stacks that are
-        // traversed until the exit is reached, pushing them
-        // onto the side vector `popped_scopes`. No code is
-        // generated at this time.
-        //
-        // So, continuing the example from above, we would wind up
-        // with a `popped_scopes` vector of `[AST 24, Custom 2]`.
-        // (Presuming that there are no cached exits)
-        loop {
-            if self.scopes_len() == 0 {
-                match label {
-                    UnwindExit(val) => {
-                        // Generate a block that will resume unwinding to the
-                        // calling function
-                        let bcx = self.new_block("resume");
-                        match val {
-                            UnwindKind::LandingPad => {
-                                let addr = self.landingpad_alloca.get()
-                                               .unwrap();
-                                let lp = build::Load(bcx, addr);
-                                base::call_lifetime_end(bcx, addr);
-                                base::trans_unwind_resume(bcx, lp);
-                            }
-                            UnwindKind::CleanupPad(_) => {
-                                let pad = build::CleanupPad(bcx, None, &[]);
-                                build::CleanupRet(bcx, pad, None);
-                            }
-                        }
-                        prev_llbb = bcx.llbb;
-                        break;
-                    }
-                }
-            }
-
-            // Pop off the scope, since we may be generating
-            // unwinding code for it.
-            let top_scope = self.pop_scope();
-            let cached_exit = top_scope.cached_early_exit(label);
-            popped_scopes.push(top_scope);
-
-            // Check if we have already cached the unwinding of this
-            // scope for this label. If so, we can stop popping scopes
-            // and branch to the cached label, since it contains the
-            // cleanups for any subsequent scopes.
-            if let Some((exit, last_cleanup)) = cached_exit {
-                prev_llbb = exit;
-                skip = last_cleanup;
-                break;
-            }
-        }
-
-        debug!("trans_cleanups_to_exit_scope: popped {} scopes",
-               popped_scopes.len());
-
-        // Now push the popped scopes back on. As we go,
-        // we track in `prev_llbb` the exit to which this scope
-        // should branch when it's done.
-        //
-        // So, continuing with our example, we will start out with
-        // `prev_llbb` being set to `break_blk` (or possibly a cached
-        // early exit). We will then pop the scopes from `popped_scopes`
-        // and generate a basic block for each one, prepending it in the
-        // series and updating `prev_llbb`. So we begin by popping `Custom 2`
-        // and generating `Cleanup(Custom 2)`. We make `Cleanup(Custom 2)`
-        // branch to `prev_llbb == break_blk`, giving us a sequence like:
-        //
-        //     Cleanup(Custom 2) -> prev_llbb
-        //
-        // We then pop `AST 24` and repeat the process, giving us the sequence:
-        //
-        //     Cleanup(AST 24) -> Cleanup(Custom 2) -> prev_llbb
-        //
-        // At this point, `popped_scopes` is empty, and so the final block
-        // that we return to the user is `Cleanup(AST 24)`.
-        while let Some(mut scope) = popped_scopes.pop() {
-            if !scope.cleanups.is_empty() {
-                let name = scope.block_name("clean");
-                debug!("generating cleanups for {}", name);
-
-                let bcx_in = self.new_block(&name[..]);
-                let exit_label = label.start(bcx_in);
-                let mut bcx_out = bcx_in;
-                let len = scope.cleanups.len();
-                for cleanup in scope.cleanups.iter().rev().take(len - skip) {
-                    bcx_out = cleanup.trans(bcx_out, scope.debug_loc);
-                }
-                skip = 0;
-                exit_label.branch(bcx_out, prev_llbb);
-                prev_llbb = bcx_in.llbb;
-
-                scope.add_cached_early_exit(exit_label, prev_llbb, len);
-            }
-            self.push_scope(scope);
-        }
-
-        debug!("trans_cleanups_to_exit_scope: prev_llbb={:?}", prev_llbb);
-
-        assert_eq!(self.scopes_len(), orig_scopes_len);
-        prev_llbb
-    }
-
-    /// Creates a landing pad for the top scope, if one does not exist.  The
-    /// landing pad will perform all cleanups necessary for an unwind and then
-    /// `resume` to continue error propagation:
-    ///
-    ///     landing_pad -> ... cleanups ... -> [resume]
-    ///
-    /// (The cleanups and resume instruction are created by
-    /// `trans_cleanups_to_exit_scope()`, not in this function itself.)
-    fn get_or_create_landing_pad(&'blk self) -> BasicBlockRef {
-        let pad_bcx;
-
-        debug!("get_or_create_landing_pad");
-
-        // Check if a landing pad block exists; if not, create one.
-        {
-            let mut scopes = self.scopes.borrow_mut();
-            let last_scope = scopes.last_mut().unwrap();
-            match last_scope.cached_landing_pad {
-                Some(llbb) => return llbb,
-                None => {
-                    let name = last_scope.block_name("unwind");
-                    pad_bcx = self.new_block(&name[..]);
-                    last_scope.cached_landing_pad = Some(pad_bcx.llbb);
-                }
-            }
-        };
-
-        let llpersonality = pad_bcx.fcx.eh_personality();
-
-        let val = if base::wants_msvc_seh(self.ccx.sess()) {
-            // A cleanup pad requires a personality function to be specified, so
-            // we do that here explicitly (happens implicitly below through
-            // creation of the landingpad instruction). We then create a
-            // cleanuppad instruction which has no filters to run cleanup on all
-            // exceptions.
-            build::SetPersonalityFn(pad_bcx, llpersonality);
-            let llretval = build::CleanupPad(pad_bcx, None, &[]);
-            UnwindKind::CleanupPad(llretval)
-        } else {
-            // The landing pad return type (the type being propagated). Not sure
-            // what this represents but it's determined by the personality
-            // function and this is what the EH proposal example uses.
-            let llretty = Type::struct_(self.ccx,
-                                        &[Type::i8p(self.ccx), Type::i32(self.ccx)],
-                                        false);
-
-            // The only landing pad clause will be 'cleanup'
-            let llretval = build::LandingPad(pad_bcx, llretty, llpersonality, 1);
-
-            // The landing pad block is a cleanup
-            build::SetCleanup(pad_bcx, llretval);
-
-            let addr = match self.landingpad_alloca.get() {
-                Some(addr) => addr,
-                None => {
-                    let addr = base::alloca(pad_bcx, common::val_ty(llretval),
-                                            "");
-                    base::call_lifetime_start(pad_bcx, addr);
-                    self.landingpad_alloca.set(Some(addr));
-                    addr
-                }
-            };
-            build::Store(pad_bcx, llretval, addr);
-            UnwindKind::LandingPad
-        };
-
-        // Generate the cleanup block and branch to it.
-        let label = UnwindExit(val);
-        let cleanup_llbb = self.trans_cleanups_to_exit_scope(label);
-        label.branch(pad_bcx, cleanup_llbb);
-
-        return pad_bcx.llbb;
+        CleanupScope::new(self, drop)
     }
 }
 
 impl<'tcx> CleanupScope<'tcx> {
-    fn new(debug_loc: DebugLoc) -> CleanupScope<'tcx> {
+    fn new<'a>(fcx: &FunctionContext<'a, 'tcx>, drop_val: DropValue<'tcx>) -> CleanupScope<'tcx> {
         CleanupScope {
-            debug_loc: debug_loc,
-            cleanups: vec![],
-            cached_early_exits: vec![],
-            cached_landing_pad: None,
-        }
-    }
-
-    fn cached_early_exit(&self,
-                         label: EarlyExitLabel)
-                         -> Option<(BasicBlockRef, usize)> {
-        self.cached_early_exits.iter().rev().
-            find(|e| e.label == label).
-            map(|e| (e.cleanup_block, e.last_cleanup))
-    }
-
-    fn add_cached_early_exit(&mut self,
-                             label: EarlyExitLabel,
-                             blk: BasicBlockRef,
-                             last_cleanup: usize) {
-        self.cached_early_exits.push(
-            CachedEarlyExit { label: label,
-                              cleanup_block: blk,
-                              last_cleanup: last_cleanup});
-    }
-
-    /// True if this scope has cleanups that need unwinding
-    fn needs_invoke(&self) -> bool {
-        self.cached_landing_pad.is_some() ||
-            !self.cleanups.is_empty()
-    }
-
-    /// Returns a suitable name to use for the basic block that handles this cleanup scope
-    fn block_name(&self, prefix: &str) -> String {
-        format!("{}_custom_", prefix)
-    }
-}
-
-impl EarlyExitLabel {
-    /// Generates a branch going from `from_bcx` to `to_llbb` where `self` is
-    /// the exit label attached to the start of `from_bcx`.
-    ///
-    /// Transitions from an exit label to other exit labels depend on the type
-    /// of label. For example with MSVC exceptions unwind exit labels will use
-    /// the `cleanupret` instruction instead of the `br` instruction.
-    fn branch(&self, from_bcx: Block, to_llbb: BasicBlockRef) {
-        if let UnwindExit(UnwindKind::CleanupPad(pad)) = *self {
-            build::CleanupRet(from_bcx, pad, Some(to_llbb));
-        } else {
-            build::Br(from_bcx, to_llbb, DebugLoc::None);
+            cleanup: Some(drop_val),
+            landing_pad: if !fcx.ccx.sess().no_landing_pads() {
+                Some(drop_val.get_landing_pad(fcx))
+            } else {
+                None
+            },
         }
     }
 
-    /// Generates the necessary instructions at the start of `bcx` to prepare
-    /// for the same kind of early exit label that `self` is.
-    ///
-    /// This function will appropriately configure `bcx` based on the kind of
-    /// label this is. For UnwindExit labels, the `lpad` field of the block will
-    /// be set to `Some`, and for MSVC exceptions this function will generate a
-    /// `cleanuppad` instruction at the start of the block so it may be jumped
-    /// to in the future (e.g. so this block can be cached as an early exit).
-    ///
-    /// Returns a new label which will can be used to cache `bcx` in the list of
-    /// early exits.
-    fn start(&self, bcx: Block) -> EarlyExitLabel {
-        match *self {
-            UnwindExit(UnwindKind::CleanupPad(..)) => {
-                let pad = build::CleanupPad(bcx, None, &[]);
-                bcx.lpad.set(Some(bcx.fcx.lpad_arena.alloc(LandingPad::msvc(pad))));
-                UnwindExit(UnwindKind::CleanupPad(pad))
-            }
-            UnwindExit(UnwindKind::LandingPad) => {
-                bcx.lpad.set(Some(bcx.fcx.lpad_arena.alloc(LandingPad::gnu())));
-                *self
-            }
+    pub fn noop() -> CleanupScope<'tcx> {
+        CleanupScope {
+            cleanup: None,
+            landing_pad: None,
         }
     }
-}
 
-impl PartialEq for UnwindKind {
-    fn eq(&self, val: &UnwindKind) -> bool {
-        match (*self, *val) {
-            (UnwindKind::LandingPad, UnwindKind::LandingPad) |
-            (UnwindKind::CleanupPad(..), UnwindKind::CleanupPad(..)) => true,
-            _ => false,
+    pub fn trans<'a>(self, bcx: &'a BlockAndBuilder<'a, 'tcx>) {
+        if let Some(cleanup) = self.cleanup {
+            cleanup.trans(None, &bcx);
         }
     }
 }
-
-///////////////////////////////////////////////////////////////////////////
-// Cleanup types
-
-#[derive(Copy, Clone)]
-pub struct DropValue<'tcx> {
-    is_immediate: bool,
-    val: ValueRef,
-    ty: Ty<'tcx>,
-    skip_dtor: bool,
-}
-
-impl<'tcx> DropValue<'tcx> {
-    fn trans<'blk>(&self,
-                   bcx: Block<'blk, 'tcx>,
-                   debug_loc: DebugLoc)
-                   -> Block<'blk, 'tcx> {
-        let skip_dtor = self.skip_dtor;
-        let _icx = if skip_dtor {
-            base::push_ctxt("<DropValue as Cleanup>::trans skip_dtor=true")
-        } else {
-            base::push_ctxt("<DropValue as Cleanup>::trans skip_dtor=false")
-        };
-        let bcx = if self.is_immediate {
-            glue::drop_ty_immediate(bcx, self.val, self.ty, debug_loc, self.skip_dtor)
-        } else {
-            glue::drop_ty_core(bcx, self.val, self.ty, debug_loc, self.skip_dtor)
-        };
-        bcx
-    }
-}
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index 3af3ada66b3..84222bfe56e 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -193,9 +193,9 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
 
 use rustc::hir::map as hir_map;
 use rustc::hir::def_id::DefId;
-use rustc::middle::lang_items::{ExchangeFreeFnLangItem, ExchangeMallocFnLangItem};
+use rustc::middle::lang_items::{BoxFreeFnLangItem, ExchangeMallocFnLangItem};
 use rustc::traits;
-use rustc::ty::subst::{Substs, Subst};
+use rustc::ty::subst::{Kind, Substs, Subst};
 use rustc::ty::{self, TypeFoldable, TyCtxt};
 use rustc::ty::adjustment::CustomCoerceUnsized;
 use rustc::mir::{self, Location};
@@ -208,13 +208,15 @@ use syntax::abi::Abi;
 use syntax_pos::DUMMY_SP;
 use base::custom_coerce_unsize_info;
 use context::SharedCrateContext;
-use common::{fulfill_obligation, type_is_sized};
+use common::fulfill_obligation;
 use glue::{self, DropGlueKind};
 use monomorphize::{self, Instance};
 use util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
 
 use trans_item::{TransItem, DefPathBasedNames};
 
+use std::iter;
+
 #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
 pub enum TransItemCollectionMode {
     Eager,
@@ -337,7 +339,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
         TransItem::Static(node_id) => {
             let def_id = scx.tcx().map.local_def_id(node_id);
             let ty = scx.tcx().item_type(def_id);
-            let ty = glue::get_drop_glue_type(scx.tcx(), ty);
+            let ty = glue::get_drop_glue_type(scx, ty);
             neighbors.push(TransItem::DropGlue(DropGlueKind::Ty(ty)));
 
             recursion_depth_reset = None;
@@ -542,7 +544,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                                                       self.param_substs,
                                                       &ty);
             assert!(ty.is_normalized_for_trans());
-            let ty = glue::get_drop_glue_type(self.scx.tcx(), ty);
+            let ty = glue::get_drop_glue_type(self.scx, ty);
             self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty)));
         }
 
@@ -678,7 +680,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                             let operand_ty = monomorphize::apply_param_substs(self.scx,
                                                                               self.param_substs,
                                                                               &mt.ty);
-                            let ty = glue::get_drop_glue_type(tcx, operand_ty);
+                            let ty = glue::get_drop_glue_type(self.scx, operand_ty);
                             self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty)));
                         } else {
                             bug!("Has the drop_in_place() intrinsic's signature changed?")
@@ -723,23 +725,17 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 
     debug!("find_drop_glue_neighbors: {}", type_to_string(scx.tcx(), ty));
 
-    // Make sure the exchange_free_fn() lang-item gets translated if
-    // there is a boxed value.
-    if let ty::TyBox(_) = ty.sty {
-        let exchange_free_fn_def_id = scx.tcx()
-                                         .lang_items
-                                         .require(ExchangeFreeFnLangItem)
-                                         .unwrap_or_else(|e| scx.sess().fatal(&e));
-
-        assert!(can_have_local_instance(scx.tcx(), exchange_free_fn_def_id));
-        let fn_substs = scx.empty_substs_for_def_id(exchange_free_fn_def_id);
-        let exchange_free_fn_trans_item =
+    // Make sure the BoxFreeFn lang-item gets translated if there is a boxed value.
+    if let ty::TyBox(content_type) = ty.sty {
+        let def_id = scx.tcx().require_lang_item(BoxFreeFnLangItem);
+        assert!(can_have_local_instance(scx.tcx(), def_id));
+        let box_free_fn_trans_item =
             create_fn_trans_item(scx,
-                                 exchange_free_fn_def_id,
-                                 fn_substs,
+                                 def_id,
+                                 scx.tcx().mk_substs(iter::once(Kind::from(content_type))),
                                  scx.tcx().intern_substs(&[]));
 
-        output.push(exchange_free_fn_trans_item);
+        output.push(box_free_fn_trans_item);
     }
 
     // If the type implements Drop, also add a translation item for the
@@ -804,17 +800,17 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                 let field_type = monomorphize::apply_param_substs(scx,
                                                                   substs,
                                                                   &field_type);
-                let field_type = glue::get_drop_glue_type(scx.tcx(), field_type);
+                let field_type = glue::get_drop_glue_type(scx, field_type);
 
-                if glue::type_needs_drop(scx.tcx(), field_type) {
+                if scx.type_needs_drop(field_type) {
                     output.push(TransItem::DropGlue(DropGlueKind::Ty(field_type)));
                 }
             }
         }
         ty::TyClosure(def_id, substs) => {
             for upvar_ty in substs.upvar_tys(def_id, scx.tcx()) {
-                let upvar_ty = glue::get_drop_glue_type(scx.tcx(), upvar_ty);
-                if glue::type_needs_drop(scx.tcx(), upvar_ty) {
+                let upvar_ty = glue::get_drop_glue_type(scx, upvar_ty);
+                if scx.type_needs_drop(upvar_ty) {
                     output.push(TransItem::DropGlue(DropGlueKind::Ty(upvar_ty)));
                 }
             }
@@ -822,15 +818,15 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
         ty::TyBox(inner_type)      |
         ty::TySlice(inner_type)    |
         ty::TyArray(inner_type, _) => {
-            let inner_type = glue::get_drop_glue_type(scx.tcx(), inner_type);
-            if glue::type_needs_drop(scx.tcx(), inner_type) {
+            let inner_type = glue::get_drop_glue_type(scx, inner_type);
+            if scx.type_needs_drop(inner_type) {
                 output.push(TransItem::DropGlue(DropGlueKind::Ty(inner_type)));
             }
         }
         ty::TyTuple(args) => {
             for arg in args {
-                let arg = glue::get_drop_glue_type(scx.tcx(), arg);
-                if glue::type_needs_drop(scx.tcx(), arg) {
+                let arg = glue::get_drop_glue_type(scx, arg);
+                if scx.type_needs_drop(arg) {
                     output.push(TransItem::DropGlue(DropGlueKind::Ty(arg)));
                 }
             }
@@ -969,7 +965,7 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
          &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => {
             let (inner_source, inner_target) = (a, b);
 
-            if !type_is_sized(scx.tcx(), inner_source) {
+            if !scx.type_is_sized(inner_source) {
                 (inner_source, inner_target)
             } else {
                 scx.tcx().struct_lockstep_tails(inner_source, inner_target)
@@ -1051,7 +1047,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a,
             output.extend(methods);
         }
         // Also add the destructor
-        let dg_type = glue::get_drop_glue_type(scx.tcx(), impl_ty);
+        let dg_type = glue::get_drop_glue_type(scx, impl_ty);
         output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type)));
     }
 }
@@ -1097,7 +1093,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
                                def_id_to_string(self.scx.tcx(), def_id));
 
                         let ty = self.scx.tcx().item_type(def_id);
-                        let ty = glue::get_drop_glue_type(self.scx.tcx(), ty);
+                        let ty = glue::get_drop_glue_type(self.scx, ty);
                         self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty)));
                     }
                 }
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index b1d61cea39c..71e17f1ea74 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -14,24 +14,16 @@
 
 use session::Session;
 use llvm;
-use llvm::{ValueRef, BasicBlockRef, BuilderRef, ContextRef, TypeKind};
+use llvm::{ValueRef, BasicBlockRef, ContextRef, TypeKind};
 use llvm::{True, False, Bool, OperandBundleDef};
 use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::DefPathData;
-use rustc::infer::TransNormalize;
-use rustc::mir::Mir;
 use rustc::util::common::MemoizationMap;
 use middle::lang_items::LangItem;
-use rustc::ty::subst::Substs;
-use abi::{Abi, FnType};
 use base;
-use build;
 use builder::Builder;
-use callee::Callee;
-use cleanup;
 use consts;
-use debuginfo::{self, DebugLoc};
 use declare;
 use machine;
 use monomorphize;
@@ -40,34 +32,26 @@ use value::Value;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::layout::Layout;
 use rustc::traits::{self, SelectionContext, Reveal};
-use rustc::ty::fold::TypeFoldable;
 use rustc::hir;
 
-use arena::TypedArena;
 use libc::{c_uint, c_char};
 use std::borrow::Cow;
 use std::iter;
 use std::ops::Deref;
 use std::ffi::CString;
-use std::cell::{Cell, RefCell, Ref};
 
 use syntax::ast;
 use syntax::symbol::{Symbol, InternedString};
-use syntax_pos::{DUMMY_SP, Span};
+use syntax_pos::Span;
 
 pub use context::{CrateContext, SharedCrateContext};
 
-/// Is the type's representation size known at compile time?
-pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
-    ty.is_sized(tcx, &tcx.empty_parameter_environment(), DUMMY_SP)
-}
-
-pub fn type_is_fat_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
+pub fn type_is_fat_ptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
     match ty.sty {
         ty::TyRawPtr(ty::TypeAndMut{ty, ..}) |
         ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
         ty::TyBox(ty) => {
-            !type_is_sized(tcx, ty)
+            !ccx.shared().type_is_sized(ty)
         }
         _ => {
             false
@@ -79,14 +63,13 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
     use machine::llsize_of_alloc;
     use type_of::sizing_type_of;
 
-    let tcx = ccx.tcx();
     let simple = ty.is_scalar() ||
         ty.is_unique() || ty.is_region_ptr() ||
         ty.is_simd();
-    if simple && !type_is_fat_ptr(tcx, ty) {
+    if simple && !type_is_fat_ptr(ccx, ty) {
         return true;
     }
-    if !type_is_sized(tcx, ty) {
+    if !ccx.shared().type_is_sized(ty) {
         return false;
     }
     match ty.sty {
@@ -236,416 +219,139 @@ impl<'a, 'tcx> VariantInfo<'tcx> {
     }
 }
 
-pub struct BuilderRef_res {
-    pub b: BuilderRef,
-}
-
-impl Drop for BuilderRef_res {
-    fn drop(&mut self) {
-        unsafe {
-            llvm::LLVMDisposeBuilder(self.b);
-        }
-    }
-}
-
-pub fn BuilderRef_res(b: BuilderRef) -> BuilderRef_res {
-    BuilderRef_res {
-        b: b
-    }
-}
-
-pub fn validate_substs(substs: &Substs) {
-    assert!(!substs.needs_infer());
-}
-
-// Function context.  Every LLVM function we create will have one of
-// these.
+// Function context. Every LLVM function we create will have one of these.
 pub struct FunctionContext<'a, 'tcx: 'a> {
-    // The MIR for this function.
-    pub mir: Option<Ref<'tcx, Mir<'tcx>>>,
-
     // The ValueRef returned from a call to llvm::LLVMAddFunction; the
     // address of the first instruction in the sequence of
     // instructions for this function that will go in the .text
     // section of the executable we're generating.
     pub llfn: ValueRef,
 
-    // always an empty parameter-environment NOTE: @jroesch another use of ParamEnv
-    pub param_env: ty::ParameterEnvironment<'tcx>,
-
-    // A pointer to where to store the return value. If the return type is
-    // immediate, this points to an alloca in the function. Otherwise, it's a
-    // pointer to the hidden first parameter of the function. After function
-    // construction, this should always be Some.
-    pub llretslotptr: Cell<Option<ValueRef>>,
-
-    // These pub elements: "hoisted basic blocks" containing
-    // administrative activities that have to happen in only one place in
-    // the function, due to LLVM's quirks.
     // A marker for the place where we want to insert the function's static
     // allocas, so that LLVM will coalesce them into a single alloca call.
-    pub alloca_insert_pt: Cell<Option<ValueRef>>,
-
-    // When working with landingpad-based exceptions this value is alloca'd and
-    // later loaded when using the resume instruction. This ends up being
-    // critical to chaining landing pads and resuing already-translated
-    // cleanups.
-    //
-    // Note that for cleanuppad-based exceptions this is not used.
-    pub landingpad_alloca: Cell<Option<ValueRef>>,
-
-    // Describes the return/argument LLVM types and their ABI handling.
-    pub fn_ty: FnType,
-
-    // If this function is being monomorphized, this contains the type
-    // substitutions used.
-    pub param_substs: &'tcx Substs<'tcx>,
-
-    // The source span and nesting context where this function comes from, for
-    // error reporting and symbol generation.
-    pub span: Option<Span>,
-
-    // The arena that blocks are allocated from.
-    pub block_arena: &'a TypedArena<BlockS<'a, 'tcx>>,
-
-    // The arena that landing pads are allocated from.
-    pub lpad_arena: TypedArena<LandingPad>,
+    alloca_insert_pt: Option<ValueRef>,
 
     // This function's enclosing crate context.
     pub ccx: &'a CrateContext<'a, 'tcx>,
 
-    // Used and maintained by the debuginfo module.
-    pub debug_context: debuginfo::FunctionDebugContext,
-
-    // Cleanup scopes.
-    pub scopes: RefCell<Vec<cleanup::CleanupScope<'tcx>>>,
+    alloca_builder: Builder<'a, 'tcx>,
 }
 
 impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
-    pub fn mir(&self) -> Ref<'tcx, Mir<'tcx>> {
-        self.mir.as_ref().map(Ref::clone).expect("fcx.mir was empty")
+    /// Create a function context for the given function.
+    /// Call FunctionContext::get_entry_block for the first entry block.
+    pub fn new(ccx: &'a CrateContext<'a, 'tcx>, llfndecl: ValueRef) -> FunctionContext<'a, 'tcx> {
+        let mut fcx = FunctionContext {
+            llfn: llfndecl,
+            alloca_insert_pt: None,
+            ccx: ccx,
+            alloca_builder: Builder::with_ccx(ccx),
+        };
+
+        let val = {
+            let entry_bcx = fcx.build_new_block("entry-block");
+            let val = entry_bcx.load(C_null(Type::i8p(ccx)));
+            fcx.alloca_builder.position_at_start(entry_bcx.llbb());
+            val
+        };
+
+        // Use a dummy instruction as the insertion point for all allocas.
+        // This is later removed in the drop of FunctionContext.
+        fcx.alloca_insert_pt = Some(val);
+
+        fcx
     }
 
-    pub fn cleanup(&self) {
-        unsafe {
-            llvm::LLVMInstructionEraseFromParent(self.alloca_insert_pt
-                                                     .get()
-                                                     .unwrap());
-        }
+    pub fn get_entry_block(&'a self) -> BlockAndBuilder<'a, 'tcx> {
+        BlockAndBuilder::new(unsafe {
+            llvm::LLVMGetFirstBasicBlock(self.llfn)
+        }, self)
     }
 
-    pub fn new_block(&'a self,
-                     name: &str)
-                     -> Block<'a, 'tcx> {
+    pub fn new_block(&'a self, name: &str) -> BasicBlockRef {
         unsafe {
             let name = CString::new(name).unwrap();
-            let llbb = llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(),
-                                                           self.llfn,
-                                                           name.as_ptr());
-            BlockS::new(llbb, self)
+            llvm::LLVMAppendBasicBlockInContext(
+                self.ccx.llcx(),
+                self.llfn,
+                name.as_ptr()
+            )
         }
     }
 
-    pub fn monomorphize<T>(&self, value: &T) -> T
-        where T: TransNormalize<'tcx>
-    {
-        monomorphize::apply_param_substs(self.ccx.shared(),
-                                         self.param_substs,
-                                         value)
-    }
-
-    /// This is the same as `common::type_needs_drop`, except that it
-    /// may use or update caches within this `FunctionContext`.
-    pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
-        self.ccx.tcx().type_needs_drop_given_env(ty, &self.param_env)
+    pub fn build_new_block(&'a self, name: &str) -> BlockAndBuilder<'a, 'tcx> {
+        BlockAndBuilder::new(self.new_block(name), self)
     }
 
-    pub fn eh_personality(&self) -> ValueRef {
-        // The exception handling personality function.
-        //
-        // If our compilation unit has the `eh_personality` lang item somewhere
-        // within it, then we just need to translate that. Otherwise, we're
-        // building an rlib which will depend on some upstream implementation of
-        // this function, so we just codegen a generic reference to it. We don't
-        // specify any of the types for the function, we just make it a symbol
-        // that LLVM can later use.
-        //
-        // Note that MSVC is a little special here in that we don't use the
-        // `eh_personality` lang item at all. Currently LLVM has support for
-        // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the
-        // *name of the personality function* to decide what kind of unwind side
-        // tables/landing pads to emit. It looks like Dwarf is used by default,
-        // injecting a dependency on the `_Unwind_Resume` symbol for resuming
-        // an "exception", but for MSVC we want to force SEH. This means that we
-        // can't actually have the personality function be our standard
-        // `rust_eh_personality` function, but rather we wired it up to the
-        // CRT's custom personality function, which forces LLVM to consider
-        // landing pads as "landing pads for SEH".
-        let ccx = self.ccx;
-        let tcx = ccx.tcx();
-        match tcx.lang_items.eh_personality() {
-            Some(def_id) if !base::wants_msvc_seh(ccx.sess()) => {
-                Callee::def(ccx, def_id, tcx.intern_substs(&[])).reify(ccx)
-            }
-            _ => {
-                if let Some(llpersonality) = ccx.eh_personality().get() {
-                    return llpersonality
-                }
-                let name = if base::wants_msvc_seh(ccx.sess()) {
-                    "__CxxFrameHandler3"
-                } else {
-                    "rust_eh_personality"
-                };
-                let fty = Type::variadic_func(&[], &Type::i32(ccx));
-                let f = declare::declare_cfn(ccx, name, fty);
-                ccx.eh_personality().set(Some(f));
-                f
-            }
-        }
+    pub fn alloca(&self, ty: Type, name: &str) -> ValueRef {
+        self.alloca_builder.dynamic_alloca(ty, name)
     }
+}
 
-    // Returns a ValueRef of the "eh_unwind_resume" lang item if one is defined,
-    // otherwise declares it as an external function.
-    pub fn eh_unwind_resume(&self) -> Callee<'tcx> {
-        use attributes;
-        let ccx = self.ccx;
-        let tcx = ccx.tcx();
-        assert!(ccx.sess().target.target.options.custom_unwind_resume);
-        if let Some(def_id) = tcx.lang_items.eh_unwind_resume() {
-            return Callee::def(ccx, def_id, tcx.intern_substs(&[]));
-        }
-
-        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 unwresume = ccx.eh_unwind_resume();
-        if let Some(llfn) = unwresume.get() {
-            return Callee::ptr(llfn, ty);
+impl<'a, 'tcx> Drop for FunctionContext<'a, 'tcx> {
+    fn drop(&mut self) {
+        unsafe {
+            llvm::LLVMInstructionEraseFromParent(self.alloca_insert_pt.unwrap());
         }
-        let llfn = declare::declare_fn(ccx, "rust_eh_unwind_resume", ty);
-        attributes::unwind(llfn, true);
-        unwresume.set(Some(llfn));
-        Callee::ptr(llfn, ty)
     }
 }
 
-// Basic block context.  We create a block context for each basic block
-// (single-entry, single-exit sequence of instructions) we generate from Rust
-// code.  Each basic block we generate is attached to a function, typically
-// with many basic blocks per function.  All the basic blocks attached to a
-// function are organized as a directed graph.
-pub struct BlockS<'blk, 'tcx: 'blk> {
+#[must_use]
+pub struct BlockAndBuilder<'a, 'tcx: 'a> {
     // The BasicBlockRef returned from a call to
     // llvm::LLVMAppendBasicBlock(llfn, name), which adds a basic
     // block to the function pointed to by llfn.  We insert
     // instructions into that block by way of this block context.
     // The block pointing to this one in the function's digraph.
-    pub llbb: BasicBlockRef,
-    pub terminated: Cell<bool>,
-    pub unreachable: Cell<bool>,
-
-    // If this block part of a landing pad, then this is `Some` indicating what
-    // kind of landing pad its in, otherwise this is none.
-    pub lpad: Cell<Option<&'blk LandingPad>>,
+    llbb: BasicBlockRef,
 
     // The function context for the function to which this block is
     // attached.
-    pub fcx: &'blk FunctionContext<'blk, 'tcx>,
-}
-
-pub type Block<'blk, 'tcx> = &'blk BlockS<'blk, 'tcx>;
-
-impl<'blk, 'tcx> BlockS<'blk, 'tcx> {
-    pub fn new(llbb: BasicBlockRef,
-               fcx: &'blk FunctionContext<'blk, 'tcx>)
-               -> Block<'blk, 'tcx> {
-        fcx.block_arena.alloc(BlockS {
-            llbb: llbb,
-            terminated: Cell::new(false),
-            unreachable: Cell::new(false),
-            lpad: Cell::new(None),
-            fcx: fcx
-        })
-    }
-
-    pub fn ccx(&self) -> &'blk CrateContext<'blk, 'tcx> {
-        self.fcx.ccx
-    }
-    pub fn fcx(&self) -> &'blk FunctionContext<'blk, 'tcx> {
-        self.fcx
-    }
-    pub fn tcx(&self) -> TyCtxt<'blk, 'tcx, 'tcx> {
-        self.fcx.ccx.tcx()
-    }
-    pub fn sess(&self) -> &'blk Session { self.fcx.ccx.sess() }
-
-    pub fn lpad(&self) -> Option<&'blk LandingPad> {
-        self.lpad.get()
-    }
-
-    pub fn set_lpad_ref(&self, lpad: Option<&'blk LandingPad>) {
-        // FIXME: use an IVar?
-        self.lpad.set(lpad);
-    }
+    fcx: &'a FunctionContext<'a, 'tcx>,
 
-    pub fn set_lpad(&self, lpad: Option<LandingPad>) {
-        self.set_lpad_ref(lpad.map(|p| &*self.fcx().lpad_arena.alloc(p)))
-    }
-
-    pub fn mir(&self) -> Ref<'tcx, Mir<'tcx>> {
-        self.fcx.mir()
-    }
-
-    pub fn name(&self, name: ast::Name) -> String {
-        name.to_string()
-    }
-
-    pub fn node_id_to_string(&self, id: ast::NodeId) -> String {
-        self.tcx().map.node_to_string(id).to_string()
-    }
-
-    pub fn to_str(&self) -> String {
-        format!("[block {:p}]", self)
-    }
-
-    pub fn monomorphize<T>(&self, value: &T) -> T
-        where T: TransNormalize<'tcx>
-    {
-        monomorphize::apply_param_substs(self.fcx.ccx.shared(),
-                                         self.fcx.param_substs,
-                                         value)
-    }
-
-    pub fn build(&'blk self) -> BlockAndBuilder<'blk, 'tcx> {
-        BlockAndBuilder::new(self, OwnedBuilder::new_with_ccx(self.ccx()))
-    }
-}
-
-pub struct OwnedBuilder<'blk, 'tcx: 'blk> {
-    builder: Builder<'blk, 'tcx>
+    builder: Builder<'a, 'tcx>,
 }
 
-impl<'blk, 'tcx> OwnedBuilder<'blk, 'tcx> {
-    pub fn new_with_ccx(ccx: &'blk CrateContext<'blk, 'tcx>) -> Self {
-        // Create a fresh builder from the crate context.
-        let llbuilder = unsafe {
-            llvm::LLVMCreateBuilderInContext(ccx.llcx())
-        };
-        OwnedBuilder {
-            builder: Builder {
-                llbuilder: llbuilder,
-                ccx: ccx,
-            }
-        }
-    }
-}
-
-impl<'blk, 'tcx> Drop for OwnedBuilder<'blk, 'tcx> {
-    fn drop(&mut self) {
-        unsafe {
-            llvm::LLVMDisposeBuilder(self.builder.llbuilder);
-        }
-    }
-}
-
-pub struct BlockAndBuilder<'blk, 'tcx: 'blk> {
-    bcx: Block<'blk, 'tcx>,
-    owned_builder: OwnedBuilder<'blk, 'tcx>,
-}
-
-impl<'blk, 'tcx> BlockAndBuilder<'blk, 'tcx> {
-    pub fn new(bcx: Block<'blk, 'tcx>, owned_builder: OwnedBuilder<'blk, 'tcx>) -> Self {
+impl<'a, 'tcx> BlockAndBuilder<'a, 'tcx> {
+    pub fn new(llbb: BasicBlockRef, fcx: &'a FunctionContext<'a, 'tcx>) -> Self {
+        let builder = Builder::with_ccx(fcx.ccx);
         // Set the builder's position to this block's end.
-        owned_builder.builder.position_at_end(bcx.llbb);
+        builder.position_at_end(llbb);
         BlockAndBuilder {
-            bcx: bcx,
-            owned_builder: owned_builder,
+            llbb: llbb,
+            fcx: fcx,
+            builder: builder,
         }
     }
 
-    pub fn with_block<F, R>(&self, f: F) -> R
-        where F: FnOnce(Block<'blk, 'tcx>) -> R
-    {
-        let result = f(self.bcx);
-        self.position_at_end(self.bcx.llbb);
-        result
-    }
-
-    pub fn map_block<F>(self, f: F) -> Self
-        where F: FnOnce(Block<'blk, 'tcx>) -> Block<'blk, 'tcx>
-    {
-        let BlockAndBuilder { bcx, owned_builder } = self;
-        let bcx = f(bcx);
-        BlockAndBuilder::new(bcx, owned_builder)
-    }
-
     pub fn at_start<F, R>(&self, f: F) -> R
-        where F: FnOnce(&BlockAndBuilder<'blk, 'tcx>) -> R
+        where F: FnOnce(&BlockAndBuilder<'a, 'tcx>) -> R
     {
-        self.position_at_start(self.bcx.llbb);
+        self.position_at_start(self.llbb);
         let r = f(self);
-        self.position_at_end(self.bcx.llbb);
+        self.position_at_end(self.llbb);
         r
     }
 
-    // Methods delegated to bcx
-
-    pub fn is_unreachable(&self) -> bool {
-        self.bcx.unreachable.get()
-    }
-
-    pub fn ccx(&self) -> &'blk CrateContext<'blk, 'tcx> {
-        self.bcx.ccx()
-    }
-    pub fn fcx(&self) -> &'blk FunctionContext<'blk, 'tcx> {
-        self.bcx.fcx()
+    pub fn fcx(&self) -> &'a FunctionContext<'a, 'tcx> {
+        self.fcx
     }
-    pub fn tcx(&self) -> TyCtxt<'blk, 'tcx, 'tcx> {
-        self.bcx.tcx()
+    pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
+        self.ccx.tcx()
     }
-    pub fn sess(&self) -> &'blk Session {
-        self.bcx.sess()
+    pub fn sess(&self) -> &'a Session {
+        self.ccx.sess()
     }
 
     pub fn llbb(&self) -> BasicBlockRef {
-        self.bcx.llbb
-    }
-
-    pub fn mir(&self) -> Ref<'tcx, Mir<'tcx>> {
-        self.bcx.mir()
-    }
-
-    pub fn monomorphize<T>(&self, value: &T) -> T
-        where T: TransNormalize<'tcx>
-    {
-        self.bcx.monomorphize(value)
-    }
-
-    pub fn set_lpad(&self, lpad: Option<LandingPad>) {
-        self.bcx.set_lpad(lpad)
-    }
-
-    pub fn set_lpad_ref(&self, lpad: Option<&'blk LandingPad>) {
-        // FIXME: use an IVar?
-        self.bcx.set_lpad_ref(lpad);
-    }
-
-    pub fn lpad(&self) -> Option<&'blk LandingPad> {
-        self.bcx.lpad()
+        self.llbb
     }
 }
 
-impl<'blk, 'tcx> Deref for BlockAndBuilder<'blk, 'tcx> {
-    type Target = Builder<'blk, 'tcx>;
+impl<'a, 'tcx> Deref for BlockAndBuilder<'a, 'tcx> {
+    type Target = Builder<'a, 'tcx>;
     fn deref(&self) -> &Self::Target {
-        &self.owned_builder.builder
+        &self.builder
     }
 }
 
@@ -663,53 +369,33 @@ impl<'blk, 'tcx> Deref for BlockAndBuilder<'blk, 'tcx> {
 /// When inside of a landing pad, each function call in LLVM IR needs to be
 /// annotated with which landing pad it's a part of. This is accomplished via
 /// the `OperandBundleDef` value created for MSVC landing pads.
-pub struct LandingPad {
-    cleanuppad: Option<ValueRef>,
-    operand: Option<OperandBundleDef>,
+pub struct Funclet {
+    cleanuppad: ValueRef,
+    operand: OperandBundleDef,
 }
 
-impl LandingPad {
-    pub fn gnu() -> LandingPad {
-        LandingPad { cleanuppad: None, operand: None }
-    }
-
-    pub fn msvc(cleanuppad: ValueRef) -> LandingPad {
-        LandingPad {
-            cleanuppad: Some(cleanuppad),
-            operand: Some(OperandBundleDef::new("funclet", &[cleanuppad])),
+impl Funclet {
+    pub fn new(cleanuppad: ValueRef) -> Funclet {
+        Funclet {
+            cleanuppad: cleanuppad,
+            operand: OperandBundleDef::new("funclet", &[cleanuppad]),
         }
     }
 
-    pub fn bundle(&self) -> Option<&OperandBundleDef> {
-        self.operand.as_ref()
-    }
-
-    pub fn cleanuppad(&self) -> Option<ValueRef> {
+    pub fn cleanuppad(&self) -> ValueRef {
         self.cleanuppad
     }
-}
 
-impl Clone for LandingPad {
-    fn clone(&self) -> LandingPad {
-        LandingPad {
-            cleanuppad: self.cleanuppad,
-            operand: self.cleanuppad.map(|p| {
-                OperandBundleDef::new("funclet", &[p])
-            }),
-        }
+    pub fn bundle(&self) -> &OperandBundleDef {
+        &self.operand
     }
 }
 
-pub struct Result<'blk, 'tcx: 'blk> {
-    pub bcx: Block<'blk, 'tcx>,
-    pub val: ValueRef
-}
-
-impl<'b, 'tcx> Result<'b, 'tcx> {
-    pub fn new(bcx: Block<'b, 'tcx>, val: ValueRef) -> Result<'b, 'tcx> {
-        Result {
-            bcx: bcx,
-            val: val,
+impl Clone for Funclet {
+    fn clone(&self) -> Funclet {
+        Funclet {
+            cleanuppad: self.cleanuppad,
+            operand: OperandBundleDef::new("funclet", &[self.cleanuppad]),
         }
     }
 }
@@ -1016,43 +702,42 @@ pub fn langcall(tcx: TyCtxt,
 // all shifts). For 32- and 64-bit types, this matches the semantics
 // of Java. (See related discussion on #1877 and #10183.)
 
-pub fn build_unchecked_lshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                          lhs: ValueRef,
-                                          rhs: ValueRef,
-                                          binop_debug_loc: DebugLoc) -> ValueRef {
+pub fn build_unchecked_lshift<'a, 'tcx>(
+    bcx: &BlockAndBuilder<'a, 'tcx>,
+    lhs: ValueRef,
+    rhs: ValueRef
+) -> ValueRef {
     let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShl, lhs, rhs);
     // #1877, #10183: Ensure that input is always valid
-    let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc);
-    build::Shl(bcx, lhs, rhs, binop_debug_loc)
+    let rhs = shift_mask_rhs(bcx, rhs);
+    bcx.shl(lhs, rhs)
 }
 
-pub fn build_unchecked_rshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                          lhs_t: Ty<'tcx>,
-                                          lhs: ValueRef,
-                                          rhs: ValueRef,
-                                          binop_debug_loc: DebugLoc) -> ValueRef {
+pub fn build_unchecked_rshift<'a, 'tcx>(
+    bcx: &BlockAndBuilder<'a, 'tcx>, lhs_t: Ty<'tcx>, lhs: ValueRef, rhs: ValueRef
+) -> ValueRef {
     let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShr, lhs, rhs);
     // #1877, #10183: Ensure that input is always valid
-    let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc);
+    let rhs = shift_mask_rhs(bcx, rhs);
     let is_signed = lhs_t.is_signed();
     if is_signed {
-        build::AShr(bcx, lhs, rhs, binop_debug_loc)
+        bcx.ashr(lhs, rhs)
     } else {
-        build::LShr(bcx, lhs, rhs, binop_debug_loc)
+        bcx.lshr(lhs, rhs)
     }
 }
 
-fn shift_mask_rhs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                              rhs: ValueRef,
-                              debug_loc: DebugLoc) -> ValueRef {
+fn shift_mask_rhs<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>, rhs: ValueRef) -> ValueRef {
     let rhs_llty = val_ty(rhs);
-    build::And(bcx, rhs, shift_mask_val(bcx, rhs_llty, rhs_llty, false), debug_loc)
+    bcx.and(rhs, shift_mask_val(bcx, rhs_llty, rhs_llty, false))
 }
 
-pub fn shift_mask_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                              llty: Type,
-                              mask_llty: Type,
-                              invert: bool) -> ValueRef {
+pub fn shift_mask_val<'a, 'tcx>(
+    bcx: &BlockAndBuilder<'a, 'tcx>,
+    llty: Type,
+    mask_llty: Type,
+    invert: bool
+) -> ValueRef {
     let kind = llty.kind();
     match kind {
         TypeKind::Integer => {
@@ -1066,7 +751,7 @@ pub fn shift_mask_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         },
         TypeKind::Vector => {
             let mask = shift_mask_val(bcx, llty.element_type(), mask_llty.element_type(), invert);
-            build::VectorSplat(bcx, mask_llty.vector_length(), mask)
+            bcx.vector_splat(mask_llty.vector_length(), mask)
         },
         _ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind),
     }
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 730a4025a59..2e2644d91bb 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -16,7 +16,7 @@ use rustc_const_eval::ConstEvalErr;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map as hir_map;
 use {debuginfo, machine};
-use base::{self, push_ctxt};
+use base;
 use trans_item::TransItem;
 use common::{CrateContext, val_ty};
 use declare;
@@ -221,7 +221,6 @@ pub fn trans_static(ccx: &CrateContext,
                     attrs: &[ast::Attribute])
                     -> Result<ValueRef, ConstEvalErr> {
     unsafe {
-        let _icx = push_ctxt("trans_static");
         let def_id = ccx.tcx().map.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 8b98eb57814..f292a709650 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -9,17 +9,16 @@
 // except according to those terms.
 
 use llvm;
-use llvm::{ContextRef, ModuleRef, ValueRef, BuilderRef};
-use rustc::dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig,
-                       WorkProduct};
+use llvm::{ContextRef, ModuleRef, ValueRef};
+use rustc::dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig, WorkProduct};
 use middle::cstore::LinkMeta;
+use rustc::hir;
 use rustc::hir::def::ExportMap;
 use rustc::hir::def_id::DefId;
 use rustc::traits;
-use base;
-use builder::Builder;
-use common::BuilderRef_res;
 use debuginfo;
+use callee::Callee;
+use base;
 use declare;
 use glue::DropGlueKind;
 use monomorphize::Instance;
@@ -40,11 +39,13 @@ use std::ffi::{CStr, CString};
 use std::cell::{Cell, RefCell};
 use std::marker::PhantomData;
 use std::ptr;
+use std::iter;
 use std::rc::Rc;
 use std::str;
 use syntax::ast;
 use syntax::symbol::InternedString;
-use abi::FnType;
+use syntax_pos::DUMMY_SP;
+use abi::{Abi, FnType};
 
 pub struct Stats {
     pub n_glues_created: Cell<usize>,
@@ -71,6 +72,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
     exported_symbols: NodeSet,
     link_meta: LinkMeta,
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    empty_param_env: ty::ParameterEnvironment<'tcx>,
     stats: Stats,
     check_overflow: bool,
 
@@ -140,7 +142,6 @@ pub struct LocalCrateContext<'tcx> {
     int_type: Type,
     opaque_vec_type: Type,
     str_slice_type: Type,
-    builder: BuilderRef_res,
 
     /// Holds the LLVM values for closure IDs.
     closure_vals: RefCell<FxHashMap<Instance<'tcx>, ValueRef>>,
@@ -153,11 +154,6 @@ pub struct LocalCrateContext<'tcx> {
 
     intrinsics: RefCell<FxHashMap<&'static str, ValueRef>>,
 
-    /// Number of LLVM instructions translated into this `LocalCrateContext`.
-    /// This is used to perform some basic load-balancing to keep all LLVM
-    /// contexts around the same size.
-    n_llvm_insns: Cell<usize>,
-
     /// Depth of the current type-of computation - used to bail out
     type_of_depth: Cell<usize>,
 
@@ -316,38 +312,6 @@ impl<'a, 'tcx> Iterator for CrateContextIterator<'a,'tcx> {
     }
 }
 
-/// The iterator produced by `CrateContext::maybe_iter`.
-pub struct CrateContextMaybeIterator<'a, 'tcx: 'a> {
-    shared: &'a SharedCrateContext<'a, 'tcx>,
-    local_ccxs: &'a [LocalCrateContext<'tcx>],
-    index: usize,
-    single: bool,
-    origin: usize,
-}
-
-impl<'a, 'tcx> Iterator for CrateContextMaybeIterator<'a, 'tcx> {
-    type Item = (CrateContext<'a, 'tcx>, bool);
-
-    fn next(&mut self) -> Option<(CrateContext<'a, 'tcx>, bool)> {
-        if self.index >= self.local_ccxs.len() {
-            return None;
-        }
-
-        let index = self.index;
-        self.index += 1;
-        if self.single {
-            self.index = self.local_ccxs.len();
-        }
-
-        let ccx = CrateContext {
-            shared: self.shared,
-            index: index,
-            local_ccxs: self.local_ccxs
-        };
-        Some((ccx, index == self.origin))
-    }
-}
-
 pub fn get_reloc_model(sess: &Session) -> llvm::RelocMode {
     let reloc_model_arg = match sess.opts.cg.relocation_model {
         Some(ref s) => &s[..],
@@ -496,6 +460,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
             export_map: export_map,
             exported_symbols: exported_symbols,
             link_meta: link_meta,
+            empty_param_env: tcx.empty_parameter_environment(),
             tcx: tcx,
             stats: Stats {
                 n_glues_created: Cell::new(0),
@@ -516,6 +481,14 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
         }
     }
 
+    pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
+        self.tcx.type_needs_drop_given_env(ty, &self.empty_param_env)
+    }
+
+    pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
+        ty.is_sized(self.tcx, &self.empty_param_env, DUMMY_SP)
+    }
+
     pub fn metadata_llmod(&self) -> ModuleRef {
         self.metadata_llmod
     }
@@ -638,14 +611,12 @@ impl<'tcx> LocalCrateContext<'tcx> {
                 int_type: Type::from_ref(ptr::null_mut()),
                 opaque_vec_type: Type::from_ref(ptr::null_mut()),
                 str_slice_type: Type::from_ref(ptr::null_mut()),
-                builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
                 closure_vals: RefCell::new(FxHashMap()),
                 dbg_cx: dbg_cx,
                 eh_personality: Cell::new(None),
                 eh_unwind_resume: Cell::new(None),
                 rust_try_fn: Cell::new(None),
                 intrinsics: RefCell::new(FxHashMap()),
-                n_llvm_insns: Cell::new(0),
                 type_of_depth: Cell::new(0),
                 symbol_map: symbol_map,
                 local_gen_sym_counter: Cell::new(0),
@@ -671,10 +642,6 @@ impl<'tcx> LocalCrateContext<'tcx> {
             local_ccx.opaque_vec_type = opaque_vec_type;
             local_ccx.str_slice_type = str_slice_ty;
 
-            if shared.tcx.sess.count_llvm_insns() {
-                base::init_insn_ctxt()
-            }
-
             local_ccx
         }
     }
@@ -703,26 +670,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         self.shared
     }
 
-    pub fn local(&self) -> &'b LocalCrateContext<'tcx> {
+    fn local(&self) -> &'b LocalCrateContext<'tcx> {
         &self.local_ccxs[self.index]
     }
 
-    /// Either iterate over only `self`, or iterate over all `CrateContext`s in
-    /// the `SharedCrateContext`.  The iterator produces `(ccx, is_origin)`
-    /// pairs, where `is_origin` is `true` if `ccx` is `self` and `false`
-    /// otherwise.  This method is useful for avoiding code duplication in
-    /// cases where it may or may not be necessary to translate code into every
-    /// context.
-    pub fn maybe_iter(&self, iter_all: bool) -> CrateContextMaybeIterator<'b, 'tcx> {
-        CrateContextMaybeIterator {
-            shared: self.shared,
-            index: if iter_all { 0 } else { self.index },
-            single: !iter_all,
-            origin: self.index,
-            local_ccxs: self.local_ccxs,
-        }
-    }
-
     pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
         self.shared.tcx
     }
@@ -731,14 +682,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         &self.shared.tcx.sess
     }
 
-    pub fn builder<'a>(&'a self) -> Builder<'a, 'tcx> {
-        Builder::new(self)
-    }
-
-    pub fn raw_builder<'a>(&'a self) -> BuilderRef {
-        self.local().builder.b
-    }
-
     pub fn get_intrinsic(&self, key: &str) -> ValueRef {
         if let Some(v) = self.intrinsics().borrow().get(key).cloned() {
             return v;
@@ -886,14 +829,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         &self.local().dbg_cx
     }
 
-    pub fn eh_personality<'a>(&'a self) -> &'a Cell<Option<ValueRef>> {
-        &self.local().eh_personality
-    }
-
-    pub fn eh_unwind_resume<'a>(&'a self) -> &'a Cell<Option<ValueRef>> {
-        &self.local().eh_unwind_resume
-    }
-
     pub fn rust_try_fn<'a>(&'a self) -> &'a Cell<Option<ValueRef>> {
         &self.local().rust_try_fn
     }
@@ -902,10 +837,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         &self.local().intrinsics
     }
 
-    pub fn count_llvm_insn(&self) {
-        self.local().n_llvm_insns.set(self.local().n_llvm_insns.get() + 1);
-    }
-
     pub fn obj_size_bound(&self) -> u64 {
         self.tcx().data_layout.obj_size_bound()
     }
@@ -971,9 +902,85 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         let mut name = String::with_capacity(prefix.len() + 6);
         name.push_str(prefix);
         name.push_str(".");
-        base_n::push_str(idx as u64, base_n::MAX_BASE, &mut name);
+        base_n::push_str(idx as u64, base_n::ALPHANUMERIC_ONLY, &mut name);
         name
     }
+
+    pub fn eh_personality(&self) -> ValueRef {
+        // The exception handling personality function.
+        //
+        // If our compilation unit has the `eh_personality` lang item somewhere
+        // within it, then we just need to translate that. Otherwise, we're
+        // building an rlib which will depend on some upstream implementation of
+        // this function, so we just codegen a generic reference to it. We don't
+        // specify any of the types for the function, we just make it a symbol
+        // that LLVM can later use.
+        //
+        // Note that MSVC is a little special here in that we don't use the
+        // `eh_personality` lang item at all. Currently LLVM has support for
+        // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the
+        // *name of the personality function* to decide what kind of unwind side
+        // tables/landing pads to emit. It looks like Dwarf is used by default,
+        // injecting a dependency on the `_Unwind_Resume` symbol for resuming
+        // an "exception", but for MSVC we want to force SEH. This means that we
+        // can't actually have the personality function be our standard
+        // `rust_eh_personality` function, but rather we wired it up to the
+        // CRT's custom personality function, which forces LLVM to consider
+        // landing pads as "landing pads for SEH".
+        if let Some(llpersonality) = self.local().eh_personality.get() {
+            return llpersonality
+        }
+        let tcx = self.tcx();
+        let llfn = match tcx.lang_items.eh_personality() {
+            Some(def_id) if !base::wants_msvc_seh(self.sess()) => {
+                Callee::def(self, def_id, tcx.intern_substs(&[])).reify(self)
+            }
+            _ => {
+                let name = if base::wants_msvc_seh(self.sess()) {
+                    "__CxxFrameHandler3"
+                } else {
+                    "rust_eh_personality"
+                };
+                let fty = Type::variadic_func(&[], &Type::i32(self));
+                declare::declare_cfn(self, name, fty)
+            }
+        };
+        self.local().eh_personality.set(Some(llfn));
+        llfn
+    }
+
+    // Returns a ValueRef of the "eh_unwind_resume" lang item if one is defined,
+    // otherwise declares it as an external function.
+    pub fn eh_unwind_resume(&self) -> ValueRef {
+        use attributes;
+        let unwresume = &self.local().eh_unwind_resume;
+        if let Some(llfn) = unwresume.get() {
+            return llfn;
+        }
+
+        let tcx = self.tcx();
+        assert!(self.sess().target.target.options.custom_unwind_resume);
+        if let Some(def_id) = tcx.lang_items.eh_unwind_resume() {
+            let llfn = Callee::def(self, def_id, tcx.intern_substs(&[])).reify(self);
+            unwresume.set(Some(llfn));
+            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 llfn = declare::declare_fn(self, "rust_eh_unwind_resume", ty);
+        attributes::unwind(llfn, true);
+        unwresume.set(Some(llfn));
+        llfn
+    }
 }
 
 pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>);
diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs
index e0c1a80be39..f5a8eeacf38 100644
--- a/src/librustc_trans/debuginfo/create_scope_map.rs
+++ b/src/librustc_trans/debuginfo/create_scope_map.rs
@@ -44,8 +44,8 @@ impl MirDebugScope {
 
 /// Produce DIScope DIEs for each MIR Scope which has variables defined in it.
 /// If debuginfo is disabled, the returned vector is empty.
-pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec<VisibilityScope, MirDebugScope> {
-    let mir = fcx.mir();
+pub fn create_mir_scopes(fcx: &FunctionContext, mir: &Mir, debug_context: &FunctionDebugContext)
+    -> IndexVec<VisibilityScope, MirDebugScope> {
     let null_scope = MirDebugScope {
         scope_metadata: ptr::null_mut(),
         file_start_pos: BytePos(0),
@@ -53,8 +53,8 @@ pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec<VisibilityScope, Mir
     };
     let mut scopes = IndexVec::from_elem(null_scope, &mir.visibility_scopes);
 
-    let fn_metadata = match fcx.debug_context {
-        FunctionDebugContext::RegularContext(box ref data) => data.fn_metadata,
+    let fn_metadata = match *debug_context {
+        FunctionDebugContext::RegularContext(ref data) => data.fn_metadata,
         FunctionDebugContext::DebugInfoDisabled |
         FunctionDebugContext::FunctionWithoutDebugInfo => {
             return scopes;
diff --git a/src/librustc_trans/debuginfo/gdb.rs b/src/librustc_trans/debuginfo/gdb.rs
index 8f937d3fe25..e8728a39993 100644
--- a/src/librustc_trans/debuginfo/gdb.rs
+++ b/src/librustc_trans/debuginfo/gdb.rs
@@ -13,37 +13,26 @@
 use llvm;
 
 use common::{C_bytes, CrateContext, C_i32};
+use builder::Builder;
 use declare;
 use type_::Type;
 use session::config::NoDebugInfo;
 
-use std::ffi::CString;
 use std::ptr;
 use syntax::attr;
 
 
 /// Inserts a side-effect free instruction sequence that makes sure that the
 /// .debug_gdb_scripts global is referenced, so it isn't removed by the linker.
-pub fn insert_reference_to_gdb_debug_scripts_section_global(ccx: &CrateContext) {
+pub fn insert_reference_to_gdb_debug_scripts_section_global(ccx: &CrateContext, builder: &Builder) {
     if needs_gdb_debug_scripts_section(ccx) {
-        let empty = CString::new("").unwrap();
-        let gdb_debug_scripts_section_global =
-            get_or_insert_gdb_debug_scripts_section_global(ccx);
+        let gdb_debug_scripts_section_global = get_or_insert_gdb_debug_scripts_section_global(ccx);
+        // Load just the first byte as that's all that's necessary to force
+        // LLVM to keep around the reference to the global.
+        let indices = [C_i32(ccx, 0), C_i32(ccx, 0)];
+        let element = builder.inbounds_gep(gdb_debug_scripts_section_global, &indices);
+        let volative_load_instruction = builder.volatile_load(element);
         unsafe {
-            // Load just the first byte as that's all that's necessary to force
-            // LLVM to keep around the reference to the global.
-            let indices = [C_i32(ccx, 0), C_i32(ccx, 0)];
-            let element =
-                llvm::LLVMBuildInBoundsGEP(ccx.raw_builder(),
-                                           gdb_debug_scripts_section_global,
-                                           indices.as_ptr(),
-                                           indices.len() as ::libc::c_uint,
-                                           empty.as_ptr());
-            let volative_load_instruction =
-                llvm::LLVMBuildLoad(ccx.raw_builder(),
-                                    element,
-                                    empty.as_ptr());
-            llvm::LLVMSetVolatile(volative_load_instruction, llvm::True);
             llvm::LLVMSetAlignment(volative_load_instruction, 1);
         }
     }
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index cda9fa46f17..511c9d3c13f 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -31,7 +31,7 @@ use rustc::ty::fold::TypeVisitor;
 use rustc::ty::subst::Substs;
 use rustc::ty::util::TypeIdHasher;
 use rustc::hir;
-use rustc_data_structures::blake2b::Blake2bHasher;
+use rustc_data_structures::ToHex;
 use {type_of, machine, monomorphize};
 use common::CrateContext;
 use type_::Type;
@@ -42,7 +42,6 @@ use util::common::path2cstr;
 
 use libc::{c_uint, c_longlong};
 use std::ffi::CString;
-use std::fmt::Write;
 use std::path::Path;
 use std::ptr;
 use syntax::ast;
@@ -147,21 +146,11 @@ impl<'tcx> TypeMap<'tcx> {
 
         // The hasher we are using to generate the UniqueTypeId. We want
         // something that provides more than the 64 bits of the DefaultHasher.
-        const TYPE_ID_HASH_LENGTH: usize = 20;
 
-        let mut type_id_hasher = TypeIdHasher::new(cx.tcx(),
-                                                   Blake2bHasher::new(TYPE_ID_HASH_LENGTH, &[]));
+        let mut type_id_hasher = TypeIdHasher::<[u8; 20]>::new(cx.tcx());
         type_id_hasher.visit_ty(type_);
-        let mut hash_state = type_id_hasher.into_inner();
-        let hash: &[u8] = hash_state.finalize();
-        debug_assert!(hash.len() == TYPE_ID_HASH_LENGTH);
-
-        let mut unique_type_id = String::with_capacity(TYPE_ID_HASH_LENGTH * 2);
-
-        for byte in hash.into_iter() {
-            write!(&mut unique_type_id, "{:x}", byte).unwrap();
-        }
 
+        let unique_type_id = type_id_hasher.finish().to_hex();
         let key = self.unique_id_interner.intern(&unique_type_id);
         self.type_to_unique_id.insert(type_, UniqueTypeId(key));
 
@@ -881,25 +870,28 @@ impl<'tcx> MemberDescriptionFactory<'tcx> {
 
 // Creates MemberDescriptions for the fields of a struct
 struct StructMemberDescriptionFactory<'tcx> {
+    ty: Ty<'tcx>,
     variant: &'tcx ty::VariantDef,
     substs: &'tcx Substs<'tcx>,
-    is_simd: bool,
     span: Span,
 }
 
 impl<'tcx> StructMemberDescriptionFactory<'tcx> {
     fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
                                       -> Vec<MemberDescription> {
-        let field_size = if self.is_simd {
-            let fty = monomorphize::field_ty(cx.tcx(),
-                                             self.substs,
-                                             &self.variant.fields[0]);
-            Some(machine::llsize_of_alloc(
-                cx,
-                type_of::type_of(cx, fty)
-            ) as usize)
-        } else {
-            None
+        let layout = cx.layout_of(self.ty);
+
+        let tmp;
+        let offsets = match *layout {
+            layout::Univariant { ref variant, .. } => &variant.offsets,
+            layout::Vector { element, count } => {
+                let element_size = element.size(&cx.tcx().data_layout).bytes();
+                tmp = (0..count).
+                  map(|i| layout::Size::from_bytes(i*element_size))
+                  .collect::<Vec<layout::Size>>();
+                &tmp
+            }
+            _ => bug!("{} is not a struct", self.ty)
         };
 
         self.variant.fields.iter().enumerate().map(|(i, f)| {
@@ -910,11 +902,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> {
             };
             let fty = monomorphize::field_ty(cx.tcx(), self.substs, f);
 
-            let offset = if self.is_simd {
-                FixedMemberOffset { bytes: i * field_size.unwrap() }
-            } else {
-                ComputedMemberOffset
-            };
+            let offset = FixedMemberOffset { bytes: offsets[i].bytes() as usize};
 
             MemberDescription {
                 name: name,
@@ -956,9 +944,9 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         struct_metadata_stub,
         struct_llvm_type,
         StructMDF(StructMemberDescriptionFactory {
+            ty: struct_type,
             variant: variant,
             substs: substs,
-            is_simd: struct_type.is_simd(),
             span: span,
         })
     )
@@ -970,6 +958,7 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
 // Creates MemberDescriptions for the fields of a tuple
 struct TupleMemberDescriptionFactory<'tcx> {
+    ty: Ty<'tcx>,
     component_types: Vec<Ty<'tcx>>,
     span: Span,
 }
@@ -977,6 +966,13 @@ struct TupleMemberDescriptionFactory<'tcx> {
 impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
     fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
                                       -> Vec<MemberDescription> {
+        let layout = cx.layout_of(self.ty);
+        let offsets = if let layout::Univariant { ref variant, .. } = *layout {
+            &variant.offsets
+        } else {
+            bug!("{} is not a tuple", self.ty);
+        };
+
         self.component_types
             .iter()
             .enumerate()
@@ -985,7 +981,7 @@ impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
                 name: format!("__{}", i),
                 llvm_type: type_of::type_of(cx, component_type),
                 type_metadata: type_metadata(cx, component_type, self.span),
-                offset: ComputedMemberOffset,
+                offset: FixedMemberOffset { bytes: offsets[i].bytes() as usize },
                 flags: DIFlags::FlagZero,
             }
         }).collect()
@@ -1012,6 +1008,7 @@ fn prepare_tuple_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                            NO_SCOPE_METADATA),
         tuple_llvm_type,
         TupleMDF(TupleMemberDescriptionFactory {
+            ty: tuple_type,
             component_types: component_types.to_vec(),
             span: span,
         })
@@ -1250,7 +1247,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
             },
             layout::StructWrappedNullablePointer { nonnull: ref struct_def,
                                                 nndiscr,
-                                                ref discrfield, ..} => {
+                                                ref discrfield_source, ..} => {
                 // Create a description of the non-null variant
                 let (variant_type_metadata, variant_llvm_type, member_description_factory) =
                     describe_enum_variant(cx,
@@ -1273,12 +1270,12 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
                 // member's name.
                 let null_variant_index = (1 - nndiscr) as usize;
                 let null_variant_name = adt.variants[null_variant_index].name;
-                let discrfield = discrfield.iter()
+                let discrfield_source = discrfield_source.iter()
                                            .skip(1)
                                            .map(|x| x.to_string())
                                            .collect::<Vec<_>>().join("$");
                 let union_member_name = format!("RUST$ENCODED$ENUM${}${}",
-                                                discrfield,
+                                                discrfield_source,
                                                 null_variant_name);
 
                 // Create the (singleton) list of descriptions of union members.
@@ -1300,6 +1297,8 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
 
 // Creates MemberDescriptions for the fields of a single enum variant.
 struct VariantMemberDescriptionFactory<'tcx> {
+    // Cloned from the layout::Struct describing the variant.
+    offsets: &'tcx [layout::Size],
     args: Vec<(String, Ty<'tcx>)>,
     discriminant_type_metadata: Option<DIType>,
     span: Span,
@@ -1316,7 +1315,7 @@ impl<'tcx> VariantMemberDescriptionFactory<'tcx> {
                     Some(metadata) if i == 0 => metadata,
                     _ => type_metadata(cx, ty, self.span)
                 },
-                offset: ComputedMemberOffset,
+                offset: FixedMemberOffset { bytes: self.offsets[i].bytes() as usize },
                 flags: DIFlags::FlagZero
             }
         }).collect()
@@ -1336,7 +1335,7 @@ enum EnumDiscriminantInfo {
 // full RecursiveTypeDescription.
 fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                    enum_type: Ty<'tcx>,
-                                   struct_def: &layout::Struct,
+                                   struct_def: &'tcx layout::Struct,
                                    variant: &'tcx ty::VariantDef,
                                    discriminant_info: EnumDiscriminantInfo,
                                    containing_scope: DIScope,
@@ -1420,6 +1419,7 @@ fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
     let member_description_factory =
         VariantMDF(VariantMemberDescriptionFactory {
+            offsets: &struct_def.offsets[..],
             args: args,
             discriminant_type_metadata: match discriminant_info {
                 RegularDiscriminant(discriminant_type_metadata) => {
@@ -1763,6 +1763,10 @@ pub fn create_global_var_metadata(cx: &CrateContext,
 
     let var_name = CString::new(var_name).unwrap();
     let linkage_name = CString::new(linkage_name).unwrap();
+
+    let ty = cx.tcx().item_type(node_def_id);
+    let global_align = type_of::align_of(cx, ty);
+
     unsafe {
         llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx),
                                                     var_scope,
@@ -1773,7 +1777,9 @@ pub fn create_global_var_metadata(cx: &CrateContext,
                                                     type_metadata,
                                                     is_local_to_unit,
                                                     global,
-                                                    ptr::null_mut());
+                                                    ptr::null_mut(),
+                                                    global_align as u64,
+        );
     }
 }
 
diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs
index aab70ab252a..86099d241df 100644
--- a/src/librustc_trans/debuginfo/mod.rs
+++ b/src/librustc_trans/debuginfo/mod.rs
@@ -27,7 +27,7 @@ use rustc::hir::def_id::DefId;
 use rustc::ty::subst::Substs;
 
 use abi::Abi;
-use common::{CrateContext, FunctionContext, Block, BlockAndBuilder};
+use common::{CrateContext, BlockAndBuilder};
 use monomorphize::{self, Instance};
 use rustc::ty::{self, Ty};
 use rustc::mir;
@@ -55,6 +55,7 @@ pub use self::create_scope_map::{create_mir_scopes, MirDebugScope};
 pub use self::source_loc::start_emitting_source_locations;
 pub use self::metadata::create_global_var_metadata;
 pub use self::metadata::extend_scope_to_file;
+pub use self::source_loc::set_source_location;
 
 #[allow(non_upper_case_globals)]
 const DW_TAG_auto_variable: c_uint = 0x100;
@@ -65,7 +66,6 @@ const DW_TAG_arg_variable: c_uint = 0x101;
 pub struct CrateDebugContext<'tcx> {
     llcontext: ContextRef,
     builder: DIBuilderRef,
-    current_debug_location: Cell<InternalDebugLocation>,
     created_files: RefCell<FxHashMap<String, DIFile>>,
     created_enum_disr_types: RefCell<FxHashMap<(DefId, layout::Integer), DIType>>,
 
@@ -83,40 +83,33 @@ impl<'tcx> CrateDebugContext<'tcx> {
         let builder = unsafe { llvm::LLVMRustDIBuilderCreate(llmod) };
         // DIBuilder inherits context from the module, so we'd better use the same one
         let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) };
-        return CrateDebugContext {
+        CrateDebugContext {
             llcontext: llcontext,
             builder: builder,
-            current_debug_location: Cell::new(InternalDebugLocation::UnknownLocation),
             created_files: RefCell::new(FxHashMap()),
             created_enum_disr_types: RefCell::new(FxHashMap()),
             type_map: RefCell::new(TypeMap::new()),
             namespace_map: RefCell::new(DefIdMap()),
             composite_types_completed: RefCell::new(FxHashSet()),
-        };
+        }
     }
 }
 
 pub enum FunctionDebugContext {
-    RegularContext(Box<FunctionDebugContextData>),
+    RegularContext(FunctionDebugContextData),
     DebugInfoDisabled,
     FunctionWithoutDebugInfo,
 }
 
 impl FunctionDebugContext {
-    fn get_ref<'a>(&'a self,
-                   span: Span)
-                   -> &'a FunctionDebugContextData {
+    fn get_ref<'a>(&'a self, span: Span) -> &'a FunctionDebugContextData {
         match *self {
-            FunctionDebugContext::RegularContext(box ref data) => data,
+            FunctionDebugContext::RegularContext(ref data) => data,
             FunctionDebugContext::DebugInfoDisabled => {
-                span_bug!(span,
-                          "{}",
-                          FunctionDebugContext::debuginfo_disabled_message());
+                span_bug!(span, "{}", FunctionDebugContext::debuginfo_disabled_message());
             }
             FunctionDebugContext::FunctionWithoutDebugInfo => {
-                span_bug!(span,
-                          "{}",
-                          FunctionDebugContext::should_be_ignored_message());
+                span_bug!(span, "{}", FunctionDebugContext::should_be_ignored_message());
             }
         }
     }
@@ -134,7 +127,6 @@ impl FunctionDebugContext {
 pub struct FunctionDebugContextData {
     fn_metadata: DISubprogram,
     source_locations_enabled: Cell<bool>,
-    source_location_override: Cell<bool>,
 }
 
 pub enum VariableAccess<'a> {
@@ -197,18 +189,6 @@ pub fn finalize(cx: &CrateContext) {
     };
 }
 
-/// Creates a function-specific debug context for a function w/o debuginfo.
-pub fn empty_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>)
-                                              -> FunctionDebugContext {
-    if cx.sess().opts.debuginfo == NoDebugInfo {
-        return FunctionDebugContext::DebugInfoDisabled;
-    }
-
-    // Clear the debug location so we don't assign them in the function prelude.
-    source_loc::set_debug_location(cx, None, UnknownLocation);
-    FunctionDebugContext::FunctionWithoutDebugInfo
-}
-
 /// Creates the function-specific debug context.
 ///
 /// Returns the FunctionDebugContext for the function which holds state needed
@@ -225,15 +205,18 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         return FunctionDebugContext::DebugInfoDisabled;
     }
 
-    // Clear the debug location so we don't assign them in the function prelude.
-    // Do this here already, in case we do an early exit from this function.
-    source_loc::set_debug_location(cx, None, UnknownLocation);
+    for attr in cx.tcx().get_attrs(instance.def).iter() {
+        if attr.check_name("no_debug") {
+            return FunctionDebugContext::FunctionWithoutDebugInfo;
+        }
+    }
 
     let containing_scope = get_containing_scope(cx, instance);
     let span = mir.span;
 
     // This can be the case for functions inlined from another crate
     if span == syntax_pos::DUMMY_SP {
+        // FIXME(simulacrum): Probably can't happen; remove.
         return FunctionDebugContext::FunctionWithoutDebugInfo;
     }
 
@@ -293,10 +276,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     };
 
     // Initialize fn debug context (including scope map and namespace map)
-    let fn_debug_context = box FunctionDebugContextData {
+    let fn_debug_context = FunctionDebugContextData {
         fn_metadata: fn_metadata,
         source_locations_enabled: Cell::new(false),
-        source_location_override: Cell::new(false),
     };
 
     return FunctionDebugContext::RegularContext(fn_debug_context);
@@ -441,14 +423,15 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     }
 }
 
-pub fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                 variable_name: ast::Name,
-                                 variable_type: Ty<'tcx>,
-                                 scope_metadata: DIScope,
-                                 variable_access: VariableAccess,
-                                 variable_kind: VariableKind,
-                                 span: Span) {
-    let cx: &CrateContext = bcx.ccx();
+pub fn declare_local<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+                               dbg_context: &FunctionDebugContext,
+                               variable_name: ast::Name,
+                               variable_type: Ty<'tcx>,
+                               scope_metadata: DIScope,
+                               variable_access: VariableAccess,
+                               variable_kind: VariableKind,
+                               span: Span) {
+    let cx = bcx.ccx;
 
     let file = span_start(cx, span).file;
     let filename = file.name.clone();
@@ -462,6 +445,7 @@ pub fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         LocalVariable    |
         CapturedVariable => (0, DW_TAG_auto_variable)
     };
+    let align = ::type_of::align_of(cx, variable_type);
 
     let name = CString::new(variable_name.as_str().as_bytes()).unwrap();
     match (variable_access, &[][..]) {
@@ -478,12 +462,14 @@ pub fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                     type_metadata,
                     cx.sess().opts.optimize != config::OptLevel::No,
                     DIFlags::FlagZero,
-                    argument_index)
+                    argument_index,
+                    align as u64,
+                )
             };
-            source_loc::set_debug_location(cx, None,
+            source_loc::set_debug_location(bcx,
                 InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize()));
             unsafe {
-                let debug_loc = llvm::LLVMGetCurrentDebugLocation(cx.raw_builder());
+                let debug_loc = llvm::LLVMGetCurrentDebugLocation(bcx.llbuilder);
                 let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
                     DIB(cx),
                     alloca,
@@ -491,38 +477,18 @@ pub fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                     address_operations.as_ptr(),
                     address_operations.len() as c_uint,
                     debug_loc,
-                    bcx.llbb);
+                    bcx.llbb());
 
-                llvm::LLVMSetInstDebugLocation(::build::B(bcx).llbuilder, instr);
+                llvm::LLVMSetInstDebugLocation(bcx.llbuilder, instr);
             }
         }
     }
 
     match variable_kind {
         ArgumentVariable(_) | CapturedVariable => {
-            assert!(!bcx.fcx
-                        .debug_context
-                        .get_ref(span)
-                        .source_locations_enabled
-                        .get());
-            source_loc::set_debug_location(cx, None, UnknownLocation);
+            assert!(!dbg_context.get_ref(span).source_locations_enabled.get());
+            source_loc::set_debug_location(bcx, UnknownLocation);
         }
         _ => { /* nothing to do */ }
     }
 }
-
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum DebugLoc {
-    ScopeAt(DIScope, Span),
-    None
-}
-
-impl DebugLoc {
-    pub fn apply(self, fcx: &FunctionContext) {
-        source_loc::set_source_location(fcx, None, self);
-    }
-
-    pub fn apply_to_bcx(self, bcx: &BlockAndBuilder) {
-        source_loc::set_source_location(bcx.fcx(), Some(bcx), self);
-    }
-}
diff --git a/src/librustc_trans/debuginfo/source_loc.rs b/src/librustc_trans/debuginfo/source_loc.rs
index 1aee27c144a..e02c8be19a2 100644
--- a/src/librustc_trans/debuginfo/source_loc.rs
+++ b/src/librustc_trans/debuginfo/source_loc.rs
@@ -11,57 +11,40 @@
 use self::InternalDebugLocation::*;
 
 use super::utils::{debug_context, span_start};
-use super::metadata::{UNKNOWN_COLUMN_NUMBER};
-use super::{FunctionDebugContext, DebugLoc};
+use super::metadata::UNKNOWN_COLUMN_NUMBER;
+use super::FunctionDebugContext;
 
 use llvm;
 use llvm::debuginfo::DIScope;
 use builder::Builder;
-use common::{CrateContext, FunctionContext};
 
 use libc::c_uint;
 use std::ptr;
-use syntax_pos::Pos;
+use syntax_pos::{Span, Pos};
 
 /// Sets the current debug location at the beginning of the span.
 ///
 /// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...).
-pub fn set_source_location(fcx: &FunctionContext,
-                           builder: Option<&Builder>,
-                           debug_loc: DebugLoc) {
-    let builder = builder.map(|b| b.llbuilder);
-    let function_debug_context = match fcx.debug_context {
+pub fn set_source_location(
+    debug_context: &FunctionDebugContext, builder: &Builder, scope: DIScope, span: Span
+) {
+    let function_debug_context = match *debug_context {
         FunctionDebugContext::DebugInfoDisabled => return,
         FunctionDebugContext::FunctionWithoutDebugInfo => {
-            set_debug_location(fcx.ccx, builder, UnknownLocation);
+            set_debug_location(builder, UnknownLocation);
             return;
         }
-        FunctionDebugContext::RegularContext(box ref data) => data
+        FunctionDebugContext::RegularContext(ref data) => data
     };
 
-    if function_debug_context.source_location_override.get() {
-        // Just ignore any attempts to set a new debug location while
-        // the override is active.
-        return;
-    }
-
     let dbg_loc = if function_debug_context.source_locations_enabled.get() {
-        let (scope, span) = match debug_loc {
-            DebugLoc::ScopeAt(scope, span) => (scope, span),
-            DebugLoc::None => {
-                set_debug_location(fcx.ccx, builder, UnknownLocation);
-                return;
-            }
-        };
-
-        debug!("set_source_location: {}",
-               fcx.ccx.sess().codemap().span_to_string(span));
-        let loc = span_start(fcx.ccx, span);
+        debug!("set_source_location: {}", builder.ccx.sess().codemap().span_to_string(span));
+        let loc = span_start(builder.ccx, span);
         InternalDebugLocation::new(scope, loc.line, loc.col.to_usize())
     } else {
         UnknownLocation
     };
-    set_debug_location(fcx.ccx, builder, dbg_loc);
+    set_debug_location(builder, dbg_loc);
 }
 
 /// Enables emitting source locations for the given functions.
@@ -70,9 +53,9 @@ pub fn set_source_location(fcx: &FunctionContext,
 /// they are disabled when beginning to translate a new function. This functions
 /// switches source location emitting on and must therefore be called before the
 /// first real statement/expression of the function is translated.
-pub fn start_emitting_source_locations(fcx: &FunctionContext) {
-    match fcx.debug_context {
-        FunctionDebugContext::RegularContext(box ref data) => {
+pub fn start_emitting_source_locations(dbg_context: &FunctionDebugContext) {
+    match *dbg_context {
+        FunctionDebugContext::RegularContext(ref data) => {
             data.source_locations_enabled.set(true)
         },
         _ => { /* safe to ignore */ }
@@ -96,15 +79,7 @@ impl InternalDebugLocation {
     }
 }
 
-pub fn set_debug_location(cx: &CrateContext,
-                          builder: Option<llvm::BuilderRef>,
-                          debug_location: InternalDebugLocation) {
-    if builder.is_none() {
-        if debug_location == debug_context(cx).current_debug_location.get() {
-            return;
-        }
-    }
-
+pub fn set_debug_location(builder: &Builder, debug_location: InternalDebugLocation) {
     let metadata_node = match debug_location {
         KnownLocation { scope, line, .. } => {
             // Always set the column to zero like Clang and GCC
@@ -113,7 +88,7 @@ pub fn set_debug_location(cx: &CrateContext,
 
             unsafe {
                 llvm::LLVMRustDIBuilderCreateDebugLocation(
-                    debug_context(cx).llcontext,
+                    debug_context(builder.ccx).llcontext,
                     line as c_uint,
                     col as c_uint,
                     scope,
@@ -126,12 +101,7 @@ pub fn set_debug_location(cx: &CrateContext,
         }
     };
 
-    if builder.is_none() {
-        debug_context(cx).current_debug_location.set(debug_location);
-    }
-
-    let builder = builder.unwrap_or_else(|| cx.raw_builder());
     unsafe {
-        llvm::LLVMSetCurrentDebugLocation(builder, metadata_node);
+        llvm::LLVMSetCurrentDebugLocation(builder.llbuilder, metadata_node);
     }
 }
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index 90bc29c39e9..3989dae553f 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -13,19 +13,19 @@
 // Code relating to drop glue.
 
 use std;
+use std::iter;
 
 use llvm;
 use llvm::{ValueRef, get_param};
-use middle::lang_items::ExchangeFreeFnLangItem;
+use middle::lang_items::BoxFreeFnLangItem;
 use rustc::ty::subst::{Substs};
 use rustc::traits;
-use rustc::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable};
-use adt;
+use rustc::ty::{self, AdtKind, Ty, TypeFoldable};
+use rustc::ty::subst::Kind;
+use adt::{self, MaybeSizedValue};
 use base::*;
-use build::*;
-use callee::{Callee};
+use callee::Callee;
 use common::*;
-use debuginfo::DebugLoc;
 use machine::*;
 use monomorphize;
 use trans_item::TransItem;
@@ -34,69 +34,34 @@ use type_of::{type_of, sizing_type_of, align_of};
 use type_::Type;
 use value::Value;
 use Disr;
+use cleanup::CleanupScope;
 
-use arena::TypedArena;
 use syntax_pos::DUMMY_SP;
 
-pub fn trans_exchange_free_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                           v: ValueRef,
-                                           size: ValueRef,
-                                           align: ValueRef,
-                                           debug_loc: DebugLoc)
-                                           -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_exchange_free");
-
-    let def_id = langcall(bcx.tcx(), None, "", ExchangeFreeFnLangItem);
-    let args = [PointerCast(bcx, v, Type::i8p(bcx.ccx())), size, align];
-    Callee::def(bcx.ccx(), def_id, bcx.tcx().intern_substs(&[]))
-        .call(bcx, debug_loc, &args, None).bcx
-}
+pub fn trans_exchange_free_ty<'a, 'tcx>(
+    bcx: &BlockAndBuilder<'a, 'tcx>,
+    ptr: MaybeSizedValue,
+    content_ty: Ty<'tcx>
+) {
+    let def_id = langcall(bcx.tcx(), None, "", BoxFreeFnLangItem);
+    let substs = bcx.tcx().mk_substs(iter::once(Kind::from(content_ty)));
+    let callee = Callee::def(bcx.ccx, def_id, substs);
 
-pub fn trans_exchange_free<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
-                                       v: ValueRef,
-                                       size: u64,
-                                       align: u32,
-                                       debug_loc: DebugLoc)
-                                       -> Block<'blk, 'tcx> {
-    trans_exchange_free_dyn(cx,
-                            v,
-                            C_uint(cx.ccx(), size),
-                            C_uint(cx.ccx(), align),
-                            debug_loc)
-}
+    let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
 
-pub fn trans_exchange_free_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                          ptr: ValueRef,
-                                          content_ty: Ty<'tcx>,
-                                          debug_loc: DebugLoc)
-                                          -> Block<'blk, 'tcx> {
-    assert!(type_is_sized(bcx.ccx().tcx(), content_ty));
-    let sizing_type = sizing_type_of(bcx.ccx(), content_ty);
-    let content_size = llsize_of_alloc(bcx.ccx(), sizing_type);
-
-    // `Box<ZeroSizeType>` does not allocate.
-    if content_size != 0 {
-        let content_align = align_of(bcx.ccx(), content_ty);
-        trans_exchange_free(bcx, ptr, content_size, content_align, debug_loc)
-    } else {
-        bcx
-    }
+    let llret = bcx.call(callee.reify(bcx.ccx),
+        &[ptr.value, ptr.meta][..1 + ptr.has_meta() as usize], None);
+    fn_ty.apply_attrs_callsite(llret);
 }
 
-pub fn type_needs_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                 ty: Ty<'tcx>) -> bool {
-    tcx.type_needs_drop_given_env(ty, &tcx.empty_parameter_environment())
-}
-
-pub fn get_drop_glue_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                    t: Ty<'tcx>) -> Ty<'tcx> {
+pub fn get_drop_glue_type<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Ty<'tcx> {
     assert!(t.is_normalized_for_trans());
 
-    let t = tcx.erase_regions(&t);
+    let t = scx.tcx().erase_regions(&t);
 
     // Even if there is no dtor for t, there might be one deeper down and we
     // might need to pass in the vtable ptr.
-    if !type_is_sized(tcx, t) {
+    if !scx.type_is_sized(t) {
         return t;
     }
 
@@ -109,17 +74,16 @@ pub fn get_drop_glue_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // returned `tcx.types.i8` does not appear unsound. The impact on
     // code quality is unknown at this time.)
 
-    if !type_needs_drop(tcx, t) {
-        return tcx.types.i8;
+    if !scx.type_needs_drop(t) {
+        return scx.tcx().types.i8;
     }
     match t.sty {
-        ty::TyBox(typ) if !type_needs_drop(tcx, typ)
-                         && type_is_sized(tcx, typ) => {
-            tcx.infer_ctxt(None, None, traits::Reveal::All).enter(|infcx| {
+        ty::TyBox(typ) if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) => {
+            scx.tcx().infer_ctxt(None, None, traits::Reveal::All).enter(|infcx| {
                 let layout = t.layout(&infcx).unwrap();
-                if layout.size(&tcx.data_layout).bytes() == 0 {
+                if layout.size(&scx.tcx().data_layout).bytes() == 0 {
                     // `Box<ZeroSizeType>` does not allocate.
-                    tcx.types.i8
+                    scx.tcx().types.i8
                 } else {
                     t
                 }
@@ -129,56 +93,36 @@ pub fn get_drop_glue_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
-pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                           v: ValueRef,
-                           t: Ty<'tcx>,
-                           debug_loc: DebugLoc) -> Block<'blk, 'tcx> {
-    drop_ty_core(bcx, v, t, debug_loc, false)
+fn drop_ty<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>, args: MaybeSizedValue, t: Ty<'tcx>) {
+    call_drop_glue(bcx, args, t, false, None)
 }
 
-pub fn drop_ty_core<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                v: ValueRef,
-                                t: Ty<'tcx>,
-                                debug_loc: DebugLoc,
-                                skip_dtor: bool)
-                                -> Block<'blk, 'tcx> {
+pub fn call_drop_glue<'a, 'tcx>(
+    bcx: &BlockAndBuilder<'a, 'tcx>,
+    mut args: MaybeSizedValue,
+    t: Ty<'tcx>,
+    skip_dtor: bool,
+    funclet: Option<&'a Funclet>,
+) {
     // NB: v is an *alias* of type t here, not a direct value.
-    debug!("drop_ty_core(t={:?}, skip_dtor={})", t, skip_dtor);
-    let _icx = push_ctxt("drop_ty");
-    if bcx.fcx.type_needs_drop(t) {
-        let ccx = bcx.ccx();
+    debug!("call_drop_glue(t={:?}, skip_dtor={})", t, skip_dtor);
+    if bcx.ccx.shared().type_needs_drop(t) {
+        let ccx = bcx.ccx;
         let g = if skip_dtor {
             DropGlueKind::TyContents(t)
         } else {
             DropGlueKind::Ty(t)
         };
         let glue = get_drop_glue_core(ccx, g);
-        let glue_type = get_drop_glue_type(ccx.tcx(), t);
-        let ptr = if glue_type != t {
-            PointerCast(bcx, v, type_of(ccx, glue_type).ptr_to())
-        } else {
-            v
-        };
+        let glue_type = get_drop_glue_type(ccx.shared(), t);
+        if glue_type != t {
+            args.value = bcx.pointercast(args.value, type_of(ccx, glue_type).ptr_to());
+        }
 
         // No drop-hint ==> call standard drop glue
-        Call(bcx, glue, &[ptr], debug_loc);
+        bcx.call(glue, &[args.value, args.meta][..1 + args.has_meta() as usize],
+            funclet.map(|b| b.bundle()));
     }
-    bcx
-}
-
-pub fn drop_ty_immediate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                     v: ValueRef,
-                                     t: Ty<'tcx>,
-                                     debug_loc: DebugLoc,
-                                     skip_dtor: bool)
-                                     -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("drop_ty_immediate");
-    let vp = alloc_ty(bcx, t, "");
-    call_lifetime_start(bcx, vp);
-    store_ty(bcx, v, vp, t);
-    let bcx = drop_ty_core(bcx, vp, t, debug_loc, skip_dtor);
-    call_lifetime_end(bcx, vp);
-    bcx
 }
 
 pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> ValueRef {
@@ -212,9 +156,8 @@ impl<'tcx> DropGlueKind<'tcx> {
     }
 }
 
-fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                g: DropGlueKind<'tcx>) -> ValueRef {
-    let g = g.map_ty(|t| get_drop_glue_type(ccx.tcx(), t));
+fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKind<'tcx>) -> ValueRef {
+    let g = g.map_ty(|t| get_drop_glue_type(ccx.shared(), t));
     match ccx.drop_glues().borrow().get(&g) {
         Some(&(glue, _)) => glue,
         None => {
@@ -226,17 +169,12 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     }
 }
 
-pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                     g: DropGlueKind<'tcx>) {
-    let tcx = ccx.tcx();
-    assert_eq!(g.ty(), get_drop_glue_type(tcx, g.ty()));
-    let (llfn, fn_ty) = ccx.drop_glues().borrow().get(&g).unwrap().clone();
-
-    let (arena, fcx): (TypedArena<_>, FunctionContext);
-    arena = TypedArena::new();
-    fcx = FunctionContext::new(ccx, llfn, fn_ty, None, &arena);
+pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKind<'tcx>) {
+    assert_eq!(g.ty(), get_drop_glue_type(ccx.shared(), g.ty()));
+    let (llfn, _) = ccx.drop_glues().borrow().get(&g).unwrap().clone();
 
-    let bcx = fcx.init(false);
+    let fcx = FunctionContext::new(ccx, llfn);
+    let mut bcx = fcx.get_entry_block();
 
     ccx.stats().n_glues_created.set(ccx.stats().n_glues_created.get() + 1);
     // All glue functions take values passed *by alias*; this is a
@@ -247,86 +185,127 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // llfn is expected be declared to take a parameter of the appropriate
     // type, so we don't need to explicitly cast the function parameter.
 
-    let bcx = make_drop_glue(bcx, get_param(llfn, 0), g);
-    fcx.finish(bcx, DebugLoc::None);
-}
-
-fn trans_custom_dtor<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                 t: Ty<'tcx>,
-                                 v0: ValueRef,
-                                 shallow_drop: bool)
-                                 -> Block<'blk, 'tcx>
-{
-    debug!("trans_custom_dtor t: {}", t);
-    let tcx = bcx.tcx();
-    let mut bcx = bcx;
-
-    let def = t.ty_adt_def().unwrap();
-
-    // Be sure to put the contents into a scope so we can use an invoke
-    // instruction to call the user destructor but still call the field
-    // destructors if the user destructor panics.
-    //
-    // FIXME (#14875) panic-in-drop semantics might be unsupported; we
-    // might well consider changing below to more direct code.
-    let contents_scope = bcx.fcx.push_custom_cleanup_scope();
-
-    // Issue #23611: schedule cleanup of contents, re-inspecting the
-    // discriminant (if any) in case of variant swap in drop code.
-    if !shallow_drop {
-        bcx.fcx.schedule_drop_adt_contents(contents_scope, v0, t);
-    }
+    // NB: v0 is an *alias* of type t here, not a direct value.
+    // Only drop the value when it ... well, we used to check for
+    // non-null, (and maybe we need to continue doing so), but we now
+    // must definitely check for special bit-patterns corresponding to
+    // the special dtor markings.
+    let t = g.ty();
 
-    let (sized_args, unsized_args);
-    let args: &[ValueRef] = if type_is_sized(tcx, t) {
-        sized_args = [v0];
-        &sized_args
+    let value = get_param(llfn, 0);
+    let ptr = if ccx.shared().type_is_sized(t) {
+        MaybeSizedValue::sized(value)
     } else {
-        // FIXME(#36457) -- we should pass unsized values to drop glue as two arguments
-        unsized_args = [
-            Load(bcx, get_dataptr(bcx, v0)),
-            Load(bcx, get_meta(bcx, v0))
-        ];
-        &unsized_args
+        MaybeSizedValue::unsized_(value, get_param(llfn, 1))
     };
 
-    let trait_ref = ty::Binder(ty::TraitRef {
-        def_id: tcx.lang_items.drop_trait().unwrap(),
-        substs: tcx.mk_substs_trait(t, &[])
-    });
-    let vtbl = match fulfill_obligation(bcx.ccx().shared(), DUMMY_SP, trait_ref) {
-        traits::VtableImpl(data) => data,
-        _ => bug!("dtor for {:?} is not an impl???", t)
+    let skip_dtor = match g {
+        DropGlueKind::Ty(_) => false,
+        DropGlueKind::TyContents(_) => true
     };
-    let dtor_did = def.destructor().unwrap();
-    bcx = Callee::def(bcx.ccx(), dtor_did, vtbl.substs)
-        .call(bcx, DebugLoc::None, args, None).bcx;
 
-    bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, contents_scope)
+    let bcx = match t.sty {
+        ty::TyBox(content_ty) => {
+            // Support for TyBox is built-in and its drop glue is
+            // special. It may move to library and have Drop impl. As
+            // a safe-guard, assert TyBox not used with TyContents.
+            assert!(!skip_dtor);
+            let ptr = if !bcx.ccx.shared().type_is_sized(content_ty) {
+                let llbox = bcx.load(get_dataptr(&bcx, ptr.value));
+                let info = bcx.load(get_meta(&bcx, ptr.value));
+                MaybeSizedValue::unsized_(llbox, info)
+            } else {
+                MaybeSizedValue::sized(bcx.load(ptr.value))
+            };
+            drop_ty(&bcx, ptr, content_ty);
+            trans_exchange_free_ty(&bcx, ptr, content_ty);
+            bcx
+        }
+        ty::TyDynamic(..) => {
+            // No support in vtable for distinguishing destroying with
+            // versus without calling Drop::drop. Assert caller is
+            // okay with always calling the Drop impl, if any.
+            assert!(!skip_dtor);
+            let dtor = bcx.load(ptr.meta);
+            bcx.call(dtor, &[ptr.value], None);
+            bcx
+        }
+        ty::TyAdt(def, ..) if def.dtor_kind().is_present() && !skip_dtor => {
+            let shallow_drop = def.is_union();
+            let tcx = bcx.tcx();
+
+            let def = t.ty_adt_def().unwrap();
+
+            // Be sure to put the contents into a scope so we can use an invoke
+            // instruction to call the user destructor but still call the field
+            // destructors if the user destructor panics.
+            //
+            // FIXME (#14875) panic-in-drop semantics might be unsupported; we
+            // might well consider changing below to more direct code.
+            // Issue #23611: schedule cleanup of contents, re-inspecting the
+            // discriminant (if any) in case of variant swap in drop code.
+            let contents_scope = if !shallow_drop {
+                bcx.fcx().schedule_drop_adt_contents(ptr, t)
+            } else {
+                CleanupScope::noop()
+            };
+
+            let trait_ref = ty::Binder(ty::TraitRef {
+                def_id: tcx.lang_items.drop_trait().unwrap(),
+                substs: tcx.mk_substs_trait(t, &[])
+            });
+            let vtbl = match fulfill_obligation(bcx.ccx.shared(), DUMMY_SP, trait_ref) {
+                traits::VtableImpl(data) => data,
+                _ => bug!("dtor for {:?} is not an impl???", t)
+            };
+            let dtor_did = def.destructor().unwrap();
+            let callee = Callee::def(bcx.ccx, dtor_did, vtbl.substs);
+            let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
+            let llret;
+            let args = &[ptr.value, ptr.meta][..1 + ptr.has_meta() as usize];
+            if let Some(landing_pad) = contents_scope.landing_pad {
+                let normal_bcx = bcx.fcx().build_new_block("normal-return");
+                llret = bcx.invoke(callee.reify(ccx), args, normal_bcx.llbb(), landing_pad, None);
+                bcx = normal_bcx;
+            } else {
+                llret = bcx.call(callee.reify(bcx.ccx), args, None);
+            }
+            fn_ty.apply_attrs_callsite(llret);
+            contents_scope.trans(&bcx);
+            bcx
+        }
+        ty::TyAdt(def, ..) if def.is_union() => {
+            bcx
+        }
+        _ => {
+            if bcx.ccx.shared().type_needs_drop(t) {
+                drop_structural_ty(bcx, ptr, t)
+            } else {
+                bcx
+            }
+        }
+    };
+    bcx.ret_void();
 }
 
-pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
-                                         t: Ty<'tcx>, info: ValueRef)
-                                         -> (ValueRef, ValueRef) {
+pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+                                       t: Ty<'tcx>, info: ValueRef)
+                                       -> (ValueRef, ValueRef) {
     debug!("calculate size of DST: {}; with lost info: {:?}",
            t, Value(info));
-    if type_is_sized(bcx.tcx(), t) {
-        let sizing_type = sizing_type_of(bcx.ccx(), t);
-        let size = llsize_of_alloc(bcx.ccx(), sizing_type);
-        let align = align_of(bcx.ccx(), t);
+    if bcx.ccx.shared().type_is_sized(t) {
+        let sizing_type = sizing_type_of(bcx.ccx, t);
+        let size = llsize_of_alloc(bcx.ccx, sizing_type);
+        let align = align_of(bcx.ccx, t);
         debug!("size_and_align_of_dst t={} info={:?} size: {} align: {}",
                t, Value(info), size, align);
-        let size = C_uint(bcx.ccx(), size);
-        let align = C_uint(bcx.ccx(), align);
+        let size = C_uint(bcx.ccx, size);
+        let align = C_uint(bcx.ccx, align);
         return (size, align);
     }
-    if bcx.is_unreachable() {
-        let llty = Type::int(bcx.ccx());
-        return (C_undef(llty), C_undef(llty));
-    }
     match t.sty {
         ty::TyAdt(def, substs) => {
-            let ccx = bcx.ccx();
+            let ccx = bcx.ccx;
             // First get the size of all statically known fields.
             // Don't use type_of::sizing_type_of because that expects t to be sized,
             // and it also rounds up to alignment, which we want to avoid,
@@ -389,7 +368,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
             //
             //   `(size + (align-1)) & -align`
 
-            let addend = bcx.sub(align, C_uint(bcx.ccx(), 1_u64));
+            let addend = bcx.sub(align, C_uint(bcx.ccx, 1_u64));
             let size = bcx.and(bcx.add(size, addend), bcx.neg(align));
 
             (size, align)
@@ -397,7 +376,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
         ty::TyDynamic(..) => {
             // info points to the vtable and the second entry in the vtable is the
             // dynamic size of the object.
-            let info = bcx.pointercast(info, Type::int(bcx.ccx()).ptr_to());
+            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), bcx.load(align_ptr))
@@ -406,194 +385,92 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
             let unit_ty = t.sequence_element_type(bcx.tcx());
             // The info in this case is the length of the str, so the size is that
             // times the unit size.
-            let llunit_ty = sizing_type_of(bcx.ccx(), unit_ty);
-            let unit_align = llalign_of_min(bcx.ccx(), llunit_ty);
-            let unit_size = llsize_of_alloc(bcx.ccx(), llunit_ty);
-            (bcx.mul(info, C_uint(bcx.ccx(), unit_size)),
-             C_uint(bcx.ccx(), unit_align))
+            let llunit_ty = sizing_type_of(bcx.ccx, unit_ty);
+            let unit_align = llalign_of_min(bcx.ccx, llunit_ty);
+            let unit_size = llsize_of_alloc(bcx.ccx, llunit_ty);
+            (bcx.mul(info, C_uint(bcx.ccx, unit_size)),
+             C_uint(bcx.ccx, unit_align))
         }
         _ => bug!("Unexpected unsized type, found {}", t)
     }
 }
 
-fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                              v0: ValueRef,
-                              g: DropGlueKind<'tcx>)
-                              -> Block<'blk, 'tcx> {
-    let t = g.ty();
-
-    let skip_dtor = match g { DropGlueKind::Ty(_) => false, DropGlueKind::TyContents(_) => true };
-    // NB: v0 is an *alias* of type t here, not a direct value.
-    let _icx = push_ctxt("make_drop_glue");
-
-    // Only drop the value when it ... well, we used to check for
-    // non-null, (and maybe we need to continue doing so), but we now
-    // must definitely check for special bit-patterns corresponding to
-    // the special dtor markings.
-
-    match t.sty {
-        ty::TyBox(content_ty) => {
-            // Support for TyBox is built-in and its drop glue is
-            // special. It may move to library and have Drop impl. As
-            // a safe-guard, assert TyBox not used with TyContents.
-            assert!(!skip_dtor);
-            if !type_is_sized(bcx.tcx(), content_ty) {
-                let llval = get_dataptr(bcx, v0);
-                let llbox = Load(bcx, llval);
-                let bcx = drop_ty(bcx, v0, content_ty, DebugLoc::None);
-                // FIXME(#36457) -- we should pass unsized values to drop glue as two arguments
-                let info = get_meta(bcx, v0);
-                let info = Load(bcx, info);
-                let (llsize, llalign) =
-                    size_and_align_of_dst(&bcx.build(), content_ty, info);
-
-                // `Box<ZeroSizeType>` does not allocate.
-                let needs_free = ICmp(bcx,
-                                        llvm::IntNE,
-                                        llsize,
-                                        C_uint(bcx.ccx(), 0u64),
-                                        DebugLoc::None);
-                with_cond(bcx, needs_free, |bcx| {
-                    trans_exchange_free_dyn(bcx, llbox, llsize, llalign, DebugLoc::None)
-                })
-            } else {
-                let llval = v0;
-                let llbox = Load(bcx, llval);
-                let bcx = drop_ty(bcx, llbox, content_ty, DebugLoc::None);
-                trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None)
-            }
-        }
-        ty::TyDynamic(..) => {
-            // No support in vtable for distinguishing destroying with
-            // versus without calling Drop::drop. Assert caller is
-            // okay with always calling the Drop impl, if any.
-            // FIXME(#36457) -- we should pass unsized values to drop glue as two arguments
-            assert!(!skip_dtor);
-            let data_ptr = get_dataptr(bcx, v0);
-            let vtable_ptr = Load(bcx, get_meta(bcx, v0));
-            let dtor = Load(bcx, vtable_ptr);
-            Call(bcx,
-                 dtor,
-                 &[PointerCast(bcx, Load(bcx, data_ptr), Type::i8p(bcx.ccx()))],
-                 DebugLoc::None);
-            bcx
-        }
-        ty::TyAdt(def, ..) if def.dtor_kind().is_present() && !skip_dtor => {
-            trans_custom_dtor(bcx, t, v0, def.is_union())
-        }
-        ty::TyAdt(def, ..) if def.is_union() => {
-            bcx
-        }
-        _ => {
-            if bcx.fcx.type_needs_drop(t) {
-                drop_structural_ty(bcx, v0, t)
-            } else {
-                bcx
-            }
-        }
-    }
-}
-
 // Iterates through the elements of a structural type, dropping them.
-fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
-                                  av: ValueRef,
-                                  t: Ty<'tcx>)
-                                  -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("drop_structural_ty");
-
-    fn iter_variant<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
-                                t: Ty<'tcx>,
-                                av: adt::MaybeSizedValue,
-                                variant: &'tcx ty::VariantDef,
-                                substs: &Substs<'tcx>)
-                                -> Block<'blk, 'tcx> {
-        let _icx = push_ctxt("iter_variant");
+fn drop_structural_ty<'a, 'tcx>(cx: BlockAndBuilder<'a, 'tcx>,
+                                ptr: MaybeSizedValue,
+                                t: Ty<'tcx>)
+                                -> BlockAndBuilder<'a, 'tcx> {
+    fn iter_variant<'a, 'tcx>(cx: &BlockAndBuilder<'a, 'tcx>,
+                              t: Ty<'tcx>,
+                              av: adt::MaybeSizedValue,
+                              variant: &'tcx ty::VariantDef,
+                              substs: &Substs<'tcx>) {
         let tcx = cx.tcx();
-        let mut cx = cx;
-
         for (i, field) in variant.fields.iter().enumerate() {
             let arg = monomorphize::field_ty(tcx, substs, field);
-            cx = drop_ty(cx,
-                         adt::trans_field_ptr(cx, t, av, Disr::from(variant.disr_val), i),
-                         arg, DebugLoc::None);
+            let field_ptr = adt::trans_field_ptr(&cx, t, av, Disr::from(variant.disr_val), i);
+            drop_ty(&cx, MaybeSizedValue::sized(field_ptr), arg);
         }
-        return cx;
     }
 
-    let value = if type_is_sized(cx.tcx(), t) {
-        adt::MaybeSizedValue::sized(av)
-    } else {
-        // FIXME(#36457) -- we should pass unsized values as two arguments
-        let data = Load(cx, get_dataptr(cx, av));
-        let info = Load(cx, get_meta(cx, av));
-        adt::MaybeSizedValue::unsized_(data, info)
-    };
-
     let mut cx = cx;
     match t.sty {
         ty::TyClosure(def_id, substs) => {
             for (i, upvar_ty) in substs.upvar_tys(def_id, cx.tcx()).enumerate() {
-                let llupvar = adt::trans_field_ptr(cx, t, value, Disr(0), i);
-                cx = drop_ty(cx, llupvar, upvar_ty, DebugLoc::None);
+                let llupvar = adt::trans_field_ptr(&cx, t, ptr, Disr(0), i);
+                drop_ty(&cx, MaybeSizedValue::sized(llupvar), upvar_ty);
             }
         }
         ty::TyArray(_, n) => {
-            let base = get_dataptr(cx, value.value);
-            let len = C_uint(cx.ccx(), n);
+            let base = get_dataptr(&cx, ptr.value);
+            let len = C_uint(cx.ccx, n);
             let unit_ty = t.sequence_element_type(cx.tcx());
-            cx = tvec::slice_for_each(cx, base, unit_ty, len,
-                |bb, vv| drop_ty(bb, vv, unit_ty, DebugLoc::None));
+            cx = tvec::slice_for_each(&cx, base, unit_ty, len,
+                |bb, vv| drop_ty(bb, MaybeSizedValue::sized(vv), unit_ty));
         }
         ty::TySlice(_) | ty::TyStr => {
             let unit_ty = t.sequence_element_type(cx.tcx());
-            cx = tvec::slice_for_each(cx, value.value, unit_ty, value.meta,
-                |bb, vv| drop_ty(bb, vv, unit_ty, DebugLoc::None));
+            cx = tvec::slice_for_each(&cx, ptr.value, unit_ty, ptr.meta,
+                |bb, vv| drop_ty(bb, MaybeSizedValue::sized(vv), unit_ty));
         }
         ty::TyTuple(ref args) => {
             for (i, arg) in args.iter().enumerate() {
-                let llfld_a = adt::trans_field_ptr(cx, t, value, Disr(0), i);
-                cx = drop_ty(cx, llfld_a, *arg, DebugLoc::None);
+                let llfld_a = adt::trans_field_ptr(&cx, t, ptr, Disr(0), i);
+                drop_ty(&cx, MaybeSizedValue::sized(llfld_a), *arg);
             }
         }
         ty::TyAdt(adt, substs) => match adt.adt_kind() {
             AdtKind::Struct => {
                 let VariantInfo { fields, discr } = VariantInfo::from_ty(cx.tcx(), t, None);
                 for (i, &Field(_, field_ty)) in fields.iter().enumerate() {
-                    let llfld_a = adt::trans_field_ptr(cx, t, value, Disr::from(discr), i);
-
-                    let val = if type_is_sized(cx.tcx(), field_ty) {
-                        llfld_a
+                    let llfld_a = adt::trans_field_ptr(&cx, t, ptr, Disr::from(discr), i);
+                    let ptr = if cx.ccx.shared().type_is_sized(field_ty) {
+                        MaybeSizedValue::sized(llfld_a)
                     } else {
-                        // FIXME(#36457) -- we should pass unsized values as two arguments
-                        let scratch = alloc_ty(cx, field_ty, "__fat_ptr_iter");
-                        Store(cx, llfld_a, get_dataptr(cx, scratch));
-                        Store(cx, value.meta, get_meta(cx, scratch));
-                        scratch
+                        MaybeSizedValue::unsized_(llfld_a, ptr.meta)
                     };
-                    cx = drop_ty(cx, val, field_ty, DebugLoc::None);
+                    drop_ty(&cx, ptr, field_ty);
                 }
             }
             AdtKind::Union => {
                 bug!("Union in `glue::drop_structural_ty`");
             }
             AdtKind::Enum => {
-                let fcx = cx.fcx;
-                let ccx = fcx.ccx;
                 let n_variants = adt.variants.len();
 
                 // NB: we must hit the discriminant first so that structural
                 // comparison know not to proceed when the discriminants differ.
 
-                match adt::trans_switch(cx, t, av, false) {
+                match adt::trans_switch(&cx, t, ptr.value, false) {
                     (adt::BranchKind::Single, None) => {
                         if n_variants != 0 {
                             assert!(n_variants == 1);
-                            cx = iter_variant(cx, t, adt::MaybeSizedValue::sized(av),
-                                            &adt.variants[0], substs);
+                            iter_variant(&cx, t, ptr, &adt.variants[0], substs);
                         }
                     }
                     (adt::BranchKind::Switch, Some(lldiscrim_a)) => {
-                        cx = drop_ty(cx, lldiscrim_a, cx.tcx().types.isize, DebugLoc::None);
+                        let tcx = cx.tcx();
+                        drop_ty(&cx, MaybeSizedValue::sized(lldiscrim_a), tcx.types.isize);
 
                         // Create a fall-through basic block for the "else" case of
                         // the switch instruction we're about to generate. Note that
@@ -608,27 +485,23 @@ fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                         // from the outer function, and any other use case will only
                         // call this for an already-valid enum in which case the `ret
                         // void` will never be hit.
-                        let ret_void_cx = fcx.new_block("enum-iter-ret-void");
-                        RetVoid(ret_void_cx, DebugLoc::None);
-                        let llswitch = Switch(cx, lldiscrim_a, ret_void_cx.llbb, n_variants);
-                        let next_cx = fcx.new_block("enum-iter-next");
+                        let ret_void_cx = cx.fcx().build_new_block("enum-iter-ret-void");
+                        ret_void_cx.ret_void();
+                        let llswitch = cx.switch(lldiscrim_a, ret_void_cx.llbb(), n_variants);
+                        let next_cx = cx.fcx().build_new_block("enum-iter-next");
 
                         for variant in &adt.variants {
-                            let variant_cx = fcx.new_block(&format!("enum-iter-variant-{}",
-                                                                        &variant.disr_val
-                                                                                .to_string()));
-                            let case_val = adt::trans_case(cx, t, Disr::from(variant.disr_val));
-                            AddCase(llswitch, case_val, variant_cx.llbb);
-                            let variant_cx = iter_variant(variant_cx,
-                                                        t,
-                                                        value,
-                                                        variant,
-                                                        substs);
-                            Br(variant_cx, next_cx.llbb, DebugLoc::None);
+                            let variant_cx_name = format!("enum-iter-variant-{}",
+                                &variant.disr_val.to_string());
+                            let variant_cx = cx.fcx().build_new_block(&variant_cx_name);
+                            let case_val = adt::trans_case(&cx, t, Disr::from(variant.disr_val));
+                            variant_cx.add_case(llswitch, case_val, variant_cx.llbb());
+                            iter_variant(&variant_cx, t, ptr, variant, substs);
+                            variant_cx.br(next_cx.llbb());
                         }
                         cx = next_cx;
                     }
-                    _ => ccx.sess().unimpl("value from adt::trans_switch in drop_structural_ty"),
+                    _ => cx.ccx.sess().unimpl("value from adt::trans_switch in drop_structural_ty"),
                 }
             }
         },
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index 577ffbad134..b7116ba1f33 100644
--- a/src/librustc_trans/intrinsic.rs
+++ b/src/librustc_trans/intrinsic.rs
@@ -10,7 +10,6 @@
 
 #![allow(non_upper_case_globals)]
 
-use arena::TypedArena;
 use intrinsics::{self, Intrinsic};
 use libc;
 use llvm;
@@ -18,9 +17,7 @@ use llvm::{ValueRef};
 use abi::{Abi, FnType};
 use adt;
 use base::*;
-use build::*;
 use common::*;
-use debuginfo::DebugLoc;
 use declare;
 use glue;
 use type_of;
@@ -33,7 +30,7 @@ use syntax::ast;
 use syntax::symbol::Symbol;
 
 use rustc::session::Session;
-use syntax_pos::{Span, DUMMY_SP};
+use syntax_pos::Span;
 
 use std::cmp::Ordering;
 use std::iter;
@@ -79,6 +76,7 @@ fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
         "roundf32" => "llvm.round.f32",
         "roundf64" => "llvm.round.f64",
         "assume" => "llvm.assume",
+        "abort" => "llvm.trap",
         _ => return None
     };
     Some(ccx.get_intrinsic(&llvm_name))
@@ -87,19 +85,15 @@ fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
 /// Remember to add all intrinsics here, in librustc_typeck/check/mod.rs,
 /// and in libcore/intrinsics.rs; if you need access to any llvm intrinsics,
 /// add them to librustc_trans/trans/context.rs
-pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
-                                            callee_ty: Ty<'tcx>,
-                                            fn_ty: &FnType,
-                                            llargs: &[ValueRef],
-                                            llresult: ValueRef,
-                                            call_debug_location: DebugLoc)
-                                            -> Result<'blk, 'tcx> {
-    let fcx = bcx.fcx;
-    let ccx = fcx.ccx;
+pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+                                      callee_ty: Ty<'tcx>,
+                                      fn_ty: &FnType,
+                                      llargs: &[ValueRef],
+                                      llresult: ValueRef,
+                                      span: Span) {
+    let ccx = bcx.ccx;
     let tcx = bcx.tcx();
 
-    let _icx = push_ctxt("trans_intrinsic_call");
-
     let (def_id, substs, fty) = match callee_ty.sty {
         ty::TyFnDef(def_id, substs, ref fty) => (def_id, substs, fty),
         _ => bug!("expected fn item type, found {}", callee_ty)
@@ -110,223 +104,150 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
     let ret_ty = sig.output();
     let name = &*tcx.item_name(def_id).as_str();
 
-    let span = match call_debug_location {
-        DebugLoc::ScopeAt(_, span) => span,
-        DebugLoc::None => {
-            span_bug!(fcx.span.unwrap_or(DUMMY_SP),
-                      "intrinsic `{}` called with missing span", name);
-        }
-    };
-
-    // These are the only intrinsic functions that diverge.
-    if name == "abort" {
-        let llfn = ccx.get_intrinsic(&("llvm.trap"));
-        Call(bcx, llfn, &[], call_debug_location);
-        Unreachable(bcx);
-        return Result::new(bcx, C_undef(Type::nil(ccx).ptr_to()));
-    } else if name == "unreachable" {
-        Unreachable(bcx);
-        return Result::new(bcx, C_nil(ccx));
-    }
-
     let llret_ty = type_of::type_of(ccx, ret_ty);
 
     let simple = get_simple_intrinsic(ccx, name);
-    let llval = match (simple, name) {
-        (Some(llfn), _) => {
-            Call(bcx, llfn, &llargs, call_debug_location)
+    let llval = match name {
+        _ if simple.is_some() => {
+            bcx.call(simple.unwrap(), &llargs, None)
         }
-        (_, "likely") => {
+        "unreachable" => {
+            return;
+        },
+        "likely" => {
             let expect = ccx.get_intrinsic(&("llvm.expect.i1"));
-            Call(bcx, expect, &[llargs[0], C_bool(ccx, true)], call_debug_location)
+            bcx.call(expect, &[llargs[0], C_bool(ccx, true)], None)
         }
-        (_, "unlikely") => {
+        "unlikely" => {
             let expect = ccx.get_intrinsic(&("llvm.expect.i1"));
-            Call(bcx, expect, &[llargs[0], C_bool(ccx, false)], call_debug_location)
+            bcx.call(expect, &[llargs[0], C_bool(ccx, false)], None)
         }
-        (_, "try") => {
-            bcx = try_intrinsic(bcx, llargs[0], llargs[1], llargs[2], llresult,
-                                call_debug_location);
+        "try" => {
+            try_intrinsic(bcx, llargs[0], llargs[1], llargs[2], llresult);
             C_nil(ccx)
         }
-        (_, "breakpoint") => {
+        "breakpoint" => {
             let llfn = ccx.get_intrinsic(&("llvm.debugtrap"));
-            Call(bcx, llfn, &[], call_debug_location)
+            bcx.call(llfn, &[], None)
         }
-        (_, "size_of") => {
+        "size_of" => {
             let tp_ty = substs.type_at(0);
             let lltp_ty = type_of::type_of(ccx, tp_ty);
             C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
         }
-        (_, "size_of_val") => {
+        "size_of_val" => {
             let tp_ty = substs.type_at(0);
-            if !type_is_sized(tcx, tp_ty) {
+            if !bcx.ccx.shared().type_is_sized(tp_ty) {
                 let (llsize, _) =
-                    glue::size_and_align_of_dst(&bcx.build(), tp_ty, llargs[1]);
+                    glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
                 llsize
             } else {
                 let lltp_ty = type_of::type_of(ccx, tp_ty);
                 C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
             }
         }
-        (_, "min_align_of") => {
+        "min_align_of" => {
             let tp_ty = substs.type_at(0);
             C_uint(ccx, type_of::align_of(ccx, tp_ty))
         }
-        (_, "min_align_of_val") => {
+        "min_align_of_val" => {
             let tp_ty = substs.type_at(0);
-            if !type_is_sized(tcx, tp_ty) {
+            if !bcx.ccx.shared().type_is_sized(tp_ty) {
                 let (_, llalign) =
-                    glue::size_and_align_of_dst(&bcx.build(), tp_ty, llargs[1]);
+                    glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
                 llalign
             } else {
                 C_uint(ccx, type_of::align_of(ccx, tp_ty))
             }
         }
-        (_, "pref_align_of") => {
+        "pref_align_of" => {
             let tp_ty = substs.type_at(0);
             let lltp_ty = type_of::type_of(ccx, tp_ty);
             C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty))
         }
-        (_, "drop_in_place") => {
-            let tp_ty = substs.type_at(0);
-            let is_sized = type_is_sized(tcx, tp_ty);
-            let ptr = if is_sized {
-                llargs[0]
-            } else {
-                // FIXME(#36457) -- we should pass unsized values as two arguments
-                let scratch = alloc_ty(bcx, tp_ty, "drop");
-                call_lifetime_start(bcx, scratch);
-                Store(bcx, llargs[0], get_dataptr(bcx, scratch));
-                Store(bcx, llargs[1], get_meta(bcx, scratch));
-                scratch
-            };
-            glue::drop_ty(bcx, ptr, tp_ty, call_debug_location);
-            if !is_sized {
-                call_lifetime_end(bcx, ptr);
-            }
-            C_nil(ccx)
-        }
-        (_, "type_name") => {
+        "type_name" => {
             let tp_ty = substs.type_at(0);
             let ty_name = Symbol::intern(&tp_ty.to_string()).as_str();
             C_str_slice(ccx, ty_name)
         }
-        (_, "type_id") => {
+        "type_id" => {
             C_u64(ccx, ccx.tcx().type_id_hash(substs.type_at(0)))
         }
-        (_, "init") => {
-            let tp_ty = substs.type_at(0);
-            if !type_is_zero_size(ccx, tp_ty) {
-                // Just zero out the stack slot. (See comment on base::memzero for explanation)
-                init_zero_mem(bcx, llresult, tp_ty);
+        "init" => {
+            let ty = substs.type_at(0);
+            if !type_is_zero_size(ccx, ty) {
+                // Just zero out the stack slot.
+                // If we store a zero constant, LLVM will drown in vreg allocation for large data
+                // structures, and the generated code will be awful. (A telltale sign of this is
+                // large quantities of `mov [byte ptr foo],0` in the generated code.)
+                memset_intrinsic(bcx, false, ty, llresult, C_u8(ccx, 0), C_uint(ccx, 1usize));
             }
             C_nil(ccx)
         }
         // Effectively no-ops
-        (_, "uninit") | (_, "forget") => {
+        "uninit" | "forget" => {
             C_nil(ccx)
         }
-        (_, "needs_drop") => {
+        "needs_drop" => {
             let tp_ty = substs.type_at(0);
 
-            C_bool(ccx, bcx.fcx.type_needs_drop(tp_ty))
+            C_bool(ccx, bcx.ccx.shared().type_needs_drop(tp_ty))
         }
-        (_, "offset") => {
+        "offset" => {
             let ptr = llargs[0];
             let offset = llargs[1];
-            InBoundsGEP(bcx, ptr, &[offset])
+            bcx.inbounds_gep(ptr, &[offset])
         }
-        (_, "arith_offset") => {
+        "arith_offset" => {
             let ptr = llargs[0];
             let offset = llargs[1];
-            GEP(bcx, ptr, &[offset])
+            bcx.gep(ptr, &[offset])
         }
 
-        (_, "copy_nonoverlapping") => {
-            copy_intrinsic(bcx,
-                           false,
-                           false,
-                           substs.type_at(0),
-                           llargs[1],
-                           llargs[0],
-                           llargs[2],
-                           call_debug_location)
+        "copy_nonoverlapping" => {
+            copy_intrinsic(bcx, false, false, substs.type_at(0), llargs[1], llargs[0], llargs[2])
         }
-        (_, "copy") => {
-            copy_intrinsic(bcx,
-                           true,
-                           false,
-                           substs.type_at(0),
-                           llargs[1],
-                           llargs[0],
-                           llargs[2],
-                           call_debug_location)
+        "copy" => {
+            copy_intrinsic(bcx, true, false, substs.type_at(0), llargs[1], llargs[0], llargs[2])
         }
-        (_, "write_bytes") => {
-            memset_intrinsic(bcx,
-                             false,
-                             substs.type_at(0),
-                             llargs[0],
-                             llargs[1],
-                             llargs[2],
-                             call_debug_location)
+        "write_bytes" => {
+            memset_intrinsic(bcx, false, substs.type_at(0), llargs[0], llargs[1], llargs[2])
         }
 
-        (_, "volatile_copy_nonoverlapping_memory") => {
-            copy_intrinsic(bcx,
-                           false,
-                           true,
-                           substs.type_at(0),
-                           llargs[0],
-                           llargs[1],
-                           llargs[2],
-                           call_debug_location)
+        "volatile_copy_nonoverlapping_memory" => {
+            copy_intrinsic(bcx, false, true, substs.type_at(0), llargs[0], llargs[1], llargs[2])
         }
-        (_, "volatile_copy_memory") => {
-            copy_intrinsic(bcx,
-                           true,
-                           true,
-                           substs.type_at(0),
-                           llargs[0],
-                           llargs[1],
-                           llargs[2],
-                           call_debug_location)
+        "volatile_copy_memory" => {
+            copy_intrinsic(bcx, true, true, substs.type_at(0), llargs[0], llargs[1], llargs[2])
         }
-        (_, "volatile_set_memory") => {
-            memset_intrinsic(bcx,
-                             true,
-                             substs.type_at(0),
-                             llargs[0],
-                             llargs[1],
-                             llargs[2],
-                             call_debug_location)
+        "volatile_set_memory" => {
+            memset_intrinsic(bcx, true, substs.type_at(0), llargs[0], llargs[1], llargs[2])
         }
-        (_, "volatile_load") => {
+        "volatile_load" => {
             let tp_ty = substs.type_at(0);
             let mut ptr = llargs[0];
             if let Some(ty) = fn_ty.ret.cast {
-                ptr = PointerCast(bcx, ptr, ty.ptr_to());
+                ptr = bcx.pointercast(ptr, ty.ptr_to());
             }
-            let load = VolatileLoad(bcx, ptr);
+            let load = bcx.volatile_load(ptr);
             unsafe {
                 llvm::LLVMSetAlignment(load, type_of::align_of(ccx, tp_ty));
             }
             to_immediate(bcx, load, tp_ty)
         },
-        (_, "volatile_store") => {
+        "volatile_store" => {
             let tp_ty = substs.type_at(0);
-            if type_is_fat_ptr(bcx.tcx(), tp_ty) {
-                VolatileStore(bcx, llargs[1], get_dataptr(bcx, llargs[0]));
-                VolatileStore(bcx, llargs[2], get_meta(bcx, llargs[0]));
+            if type_is_fat_ptr(bcx.ccx, tp_ty) {
+                bcx.volatile_store(llargs[1], get_dataptr(bcx, llargs[0]));
+                bcx.volatile_store(llargs[2], get_meta(bcx, llargs[0]));
             } else {
                 let val = if fn_ty.args[1].is_indirect() {
-                    Load(bcx, llargs[1])
+                    bcx.load(llargs[1])
                 } else {
                     from_immediate(bcx, llargs[1])
                 };
-                let ptr = PointerCast(bcx, llargs[0], val_ty(val).ptr_to());
-                let store = VolatileStore(bcx, val, ptr);
+                let ptr = bcx.pointercast(llargs[0], val_ty(val).ptr_to());
+                let store = bcx.volatile_store(val, ptr);
                 unsafe {
                     llvm::LLVMSetAlignment(store, type_of::align_of(ccx, tp_ty));
                 }
@@ -334,49 +255,58 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             C_nil(ccx)
         },
 
-        (_, "ctlz") | (_, "cttz") | (_, "ctpop") | (_, "bswap") |
-        (_, "add_with_overflow") | (_, "sub_with_overflow") | (_, "mul_with_overflow") |
-        (_, "overflowing_add") | (_, "overflowing_sub") | (_, "overflowing_mul") |
-        (_, "unchecked_div") | (_, "unchecked_rem") => {
+        "ctlz" | "cttz" | "ctpop" | "bswap" |
+        "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" |
+        "overflowing_add" | "overflowing_sub" | "overflowing_mul" |
+        "unchecked_div" | "unchecked_rem" => {
             let sty = &arg_tys[0].sty;
             match int_type_width_signed(sty, ccx) {
                 Some((width, signed)) =>
                     match name {
-                        "ctlz" => count_zeros_intrinsic(bcx, &format!("llvm.ctlz.i{}", width),
-                                                        llargs[0], call_debug_location),
-                        "cttz" => count_zeros_intrinsic(bcx, &format!("llvm.cttz.i{}", width),
-                                                        llargs[0], call_debug_location),
-                        "ctpop" => Call(bcx, ccx.get_intrinsic(&format!("llvm.ctpop.i{}", width)),
-                                        &llargs, call_debug_location),
+                        "ctlz" | "cttz" => {
+                            let y = C_bool(bcx.ccx, false);
+                            let llfn = ccx.get_intrinsic(&format!("llvm.{}.i{}", name, width));
+                            bcx.call(llfn, &[llargs[0], y], None)
+                        }
+                        "ctpop" => bcx.call(ccx.get_intrinsic(&format!("llvm.ctpop.i{}", width)),
+                                        &llargs, None),
                         "bswap" => {
                             if width == 8 {
                                 llargs[0] // byte swap a u8/i8 is just a no-op
                             } else {
-                                Call(bcx, ccx.get_intrinsic(&format!("llvm.bswap.i{}", width)),
-                                        &llargs, call_debug_location)
+                                bcx.call(ccx.get_intrinsic(&format!("llvm.bswap.i{}", width)),
+                                        &llargs, None)
                             }
                         }
                         "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => {
                             let intrinsic = format!("llvm.{}{}.with.overflow.i{}",
                                                     if signed { 's' } else { 'u' },
                                                     &name[..3], width);
-                            with_overflow_intrinsic(bcx, &intrinsic, llargs[0], llargs[1], llresult,
-                                                    call_debug_location)
+                            let llfn = bcx.ccx.get_intrinsic(&intrinsic);
+
+                            // Convert `i1` to a `bool`, and write it to the out parameter
+                            let val = bcx.call(llfn, &[llargs[0], llargs[1]], None);
+                            let result = bcx.extract_value(val, 0);
+                            let overflow = bcx.zext(bcx.extract_value(val, 1), Type::bool(ccx));
+                            bcx.store(result, bcx.struct_gep(llresult, 0));
+                            bcx.store(overflow, bcx.struct_gep(llresult, 1));
+
+                            C_nil(bcx.ccx)
                         },
-                        "overflowing_add" => Add(bcx, llargs[0], llargs[1], call_debug_location),
-                        "overflowing_sub" => Sub(bcx, llargs[0], llargs[1], call_debug_location),
-                        "overflowing_mul" => Mul(bcx, llargs[0], llargs[1], call_debug_location),
+                        "overflowing_add" => bcx.add(llargs[0], llargs[1]),
+                        "overflowing_sub" => bcx.sub(llargs[0], llargs[1]),
+                        "overflowing_mul" => bcx.mul(llargs[0], llargs[1]),
                         "unchecked_div" =>
                             if signed {
-                                SDiv(bcx, llargs[0], llargs[1], call_debug_location)
+                                bcx.sdiv(llargs[0], llargs[1])
                             } else {
-                                UDiv(bcx, llargs[0], llargs[1], call_debug_location)
+                                bcx.udiv(llargs[0], llargs[1])
                             },
                         "unchecked_rem" =>
                             if signed {
-                                SRem(bcx, llargs[0], llargs[1], call_debug_location)
+                                bcx.srem(llargs[0], llargs[1])
                             } else {
-                                URem(bcx, llargs[0], llargs[1], call_debug_location)
+                                bcx.urem(llargs[0], llargs[1])
                             },
                         _ => bug!(),
                     },
@@ -390,17 +320,16 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             }
 
         },
-        (_, "fadd_fast") | (_, "fsub_fast") | (_, "fmul_fast") | (_, "fdiv_fast") |
-        (_, "frem_fast") => {
+        "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => {
             let sty = &arg_tys[0].sty;
             match float_type_width(sty) {
                 Some(_width) =>
                     match name {
-                        "fadd_fast" => FAddFast(bcx, llargs[0], llargs[1], call_debug_location),
-                        "fsub_fast" => FSubFast(bcx, llargs[0], llargs[1], call_debug_location),
-                        "fmul_fast" => FMulFast(bcx, llargs[0], llargs[1], call_debug_location),
-                        "fdiv_fast" => FDivFast(bcx, llargs[0], llargs[1], call_debug_location),
-                        "frem_fast" => FRemFast(bcx, llargs[0], llargs[1], call_debug_location),
+                        "fadd_fast" => bcx.fadd_fast(llargs[0], llargs[1]),
+                        "fsub_fast" => bcx.fsub_fast(llargs[0], llargs[1]),
+                        "fmul_fast" => bcx.fmul_fast(llargs[0], llargs[1]),
+                        "fdiv_fast" => bcx.fdiv_fast(llargs[0], llargs[1]),
+                        "frem_fast" => bcx.frem_fast(llargs[0], llargs[1]),
                         _ => bug!(),
                     },
                 None => {
@@ -414,7 +343,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
 
         },
 
-        (_, "discriminant_value") => {
+        "discriminant_value" => {
             let val_ty = substs.type_at(0);
             match val_ty.sty {
                 ty::TyAdt(adt, ..) if adt.is_enum() => {
@@ -424,17 +353,16 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                 _ => C_null(llret_ty)
             }
         }
-        (_, name) if name.starts_with("simd_") => {
+        name if name.starts_with("simd_") => {
             generic_simd_intrinsic(bcx, name,
                                    callee_ty,
                                    &llargs,
                                    ret_ty, llret_ty,
-                                   call_debug_location,
                                    span)
         }
         // This requires that atomic intrinsics follow a specific naming pattern:
         // "atomic_<operation>[_<ordering>]", and no ordering means SeqCst
-        (_, name) if name.starts_with("atomic_") => {
+        name if name.starts_with("atomic_") => {
             use llvm::AtomicOrdering::*;
 
             let split: Vec<&str> = name.split('_').collect();
@@ -464,22 +392,25 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                 _ => ccx.sess().fatal("Atomic intrinsic not in correct format"),
             };
 
+            let invalid_monomorphization = |sty| {
+                span_invalid_monomorphization_error(tcx.sess, span,
+                    &format!("invalid monomorphization of `{}` intrinsic: \
+                              expected basic integer type, found `{}`", name, sty));
+            };
+
             match split[1] {
                 "cxchg" | "cxchgweak" => {
                     let sty = &substs.type_at(0).sty;
                     if int_type_width_signed(sty, ccx).is_some() {
                         let weak = if split[1] == "cxchgweak" { llvm::True } else { llvm::False };
-                        let val = AtomicCmpXchg(bcx, llargs[0], llargs[1], llargs[2],
-                                                order, failorder, weak);
-                        let result = ExtractValue(bcx, val, 0);
-                        let success = ZExt(bcx, ExtractValue(bcx, val, 1), Type::bool(bcx.ccx()));
-                        Store(bcx, result, StructGEP(bcx, llresult, 0));
-                        Store(bcx, success, StructGEP(bcx, llresult, 1));
+                        let val = bcx.atomic_cmpxchg(llargs[0], llargs[1], llargs[2], order,
+                            failorder, weak);
+                        let result = bcx.extract_value(val, 0);
+                        let success = bcx.zext(bcx.extract_value(val, 1), Type::bool(bcx.ccx));
+                        bcx.store(result, bcx.struct_gep(llresult, 0));
+                        bcx.store(success, bcx.struct_gep(llresult, 1));
                     } else {
-                        span_invalid_monomorphization_error(
-                            tcx.sess, span,
-                            &format!("invalid monomorphization of `{}` intrinsic: \
-                                      expected basic integer type, found `{}`", name, sty));
+                        invalid_monomorphization(sty);
                     }
                     C_nil(ccx)
                 }
@@ -487,12 +418,9 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                 "load" => {
                     let sty = &substs.type_at(0).sty;
                     if int_type_width_signed(sty, ccx).is_some() {
-                        AtomicLoad(bcx, llargs[0], order)
+                        bcx.atomic_load(llargs[0], order)
                     } else {
-                        span_invalid_monomorphization_error(
-                            tcx.sess, span,
-                            &format!("invalid monomorphization of `{}` intrinsic: \
-                                      expected basic integer type, found `{}`", name, sty));
+                        invalid_monomorphization(sty);
                         C_nil(ccx)
                     }
                 }
@@ -500,23 +428,20 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                 "store" => {
                     let sty = &substs.type_at(0).sty;
                     if int_type_width_signed(sty, ccx).is_some() {
-                        AtomicStore(bcx, llargs[1], llargs[0], order);
+                        bcx.atomic_store(llargs[1], llargs[0], order);
                     } else {
-                        span_invalid_monomorphization_error(
-                            tcx.sess, span,
-                            &format!("invalid monomorphization of `{}` intrinsic: \
-                                      expected basic integer type, found `{}`", name, sty));
+                        invalid_monomorphization(sty);
                     }
                     C_nil(ccx)
                 }
 
                 "fence" => {
-                    AtomicFence(bcx, order, llvm::SynchronizationScope::CrossThread);
+                    bcx.atomic_fence(order, llvm::SynchronizationScope::CrossThread);
                     C_nil(ccx)
                 }
 
                 "singlethreadfence" => {
-                    AtomicFence(bcx, order, llvm::SynchronizationScope::SingleThread);
+                    bcx.atomic_fence(order, llvm::SynchronizationScope::SingleThread);
                     C_nil(ccx)
                 }
 
@@ -539,20 +464,16 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
 
                     let sty = &substs.type_at(0).sty;
                     if int_type_width_signed(sty, ccx).is_some() {
-                        AtomicRMW(bcx, atom_op, llargs[0], llargs[1], order)
+                        bcx.atomic_rmw(atom_op, llargs[0], llargs[1], order)
                     } else {
-                        span_invalid_monomorphization_error(
-                            tcx.sess, span,
-                            &format!("invalid monomorphization of `{}` intrinsic: \
-                                      expected basic integer type, found `{}`", name, sty));
+                        invalid_monomorphization(sty);
                         C_nil(ccx)
                     }
                 }
             }
-
         }
 
-        (..) => {
+        _ => {
             let intr = match Intrinsic::find(&name) {
                 Some(intr) => intr,
                 None => bug!("unknown intrinsic '{}'", name),
@@ -581,18 +502,15 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                         *any_changes_needed |= llvm_elem.is_some();
 
                         let t = llvm_elem.as_ref().unwrap_or(t);
-                        let elem = one(ty_to_type(ccx, t,
-                                                  any_changes_needed));
+                        let elem = one(ty_to_type(ccx, t, any_changes_needed));
                         vec![elem.ptr_to()]
                     }
                     Vector(ref t, ref llvm_elem, length) => {
                         *any_changes_needed |= llvm_elem.is_some();
 
                         let t = llvm_elem.as_ref().unwrap_or(t);
-                        let elem = one(ty_to_type(ccx, t,
-                                                  any_changes_needed));
-                        vec![Type::vector(&elem,
-                                          length as u64)]
+                        let elem = one(ty_to_type(ccx, t, any_changes_needed));
+                        vec![Type::vector(&elem, length as u64)]
                     }
                     Aggregate(false, ref contents) => {
                         let elems = contents.iter()
@@ -613,11 +531,11 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             // qux` to be converted into `foo, bar, baz, qux`, integer
             // arguments to be truncated as needed and pointers to be
             // cast.
-            fn modify_as_needed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                            t: &intrinsics::Type,
-                                            arg_type: Ty<'tcx>,
-                                            llarg: ValueRef)
-                                            -> Vec<ValueRef>
+            fn modify_as_needed<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+                                          t: &intrinsics::Type,
+                                          arg_type: Ty<'tcx>,
+                                          llarg: ValueRef)
+                                          -> Vec<ValueRef>
             {
                 match *t {
                     intrinsics::Type::Aggregate(true, ref contents) => {
@@ -627,29 +545,27 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                         // This assumes the type is "simple", i.e. no
                         // destructors, and the contents are SIMD
                         // etc.
-                        assert!(!bcx.fcx.type_needs_drop(arg_type));
+                        assert!(!bcx.ccx.shared().type_needs_drop(arg_type));
                         let arg = adt::MaybeSizedValue::sized(llarg);
                         (0..contents.len())
                             .map(|i| {
-                                Load(bcx, adt::trans_field_ptr(bcx, arg_type, arg, Disr(0), i))
+                                bcx.load(adt::trans_field_ptr(bcx, arg_type, arg, Disr(0), i))
                             })
                             .collect()
                     }
                     intrinsics::Type::Pointer(_, Some(ref llvm_elem), _) => {
-                        let llvm_elem = one(ty_to_type(bcx.ccx(), llvm_elem, &mut false));
-                        vec![PointerCast(bcx, llarg,
-                                         llvm_elem.ptr_to())]
+                        let llvm_elem = one(ty_to_type(bcx.ccx, llvm_elem, &mut false));
+                        vec![bcx.pointercast(llarg, llvm_elem.ptr_to())]
                     }
                     intrinsics::Type::Vector(_, Some(ref llvm_elem), length) => {
-                        let llvm_elem = one(ty_to_type(bcx.ccx(), llvm_elem, &mut false));
-                        vec![BitCast(bcx, llarg,
-                                     Type::vector(&llvm_elem, length as u64))]
+                        let llvm_elem = one(ty_to_type(bcx.ccx, llvm_elem, &mut false));
+                        vec![bcx.bitcast(llarg, Type::vector(&llvm_elem, length as u64))]
                     }
                     intrinsics::Type::Integer(_, width, llvm_width) if width != llvm_width => {
                         // the LLVM intrinsic uses a smaller integer
                         // size than the C intrinsic's signature, so
                         // we have to trim it down here.
-                        vec![Trunc(bcx, llarg, Type::ix(bcx.ccx(), llvm_width as u64))]
+                        vec![bcx.trunc(llarg, Type::ix(bcx.ccx, llvm_width as u64))]
                     }
                     _ => vec![llarg],
                 }
@@ -686,7 +602,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                     let f = declare::declare_cfn(ccx,
                                                  name,
                                                  Type::func(&inputs, &outputs));
-                    Call(bcx, f, &llargs, call_debug_location)
+                    bcx.call(f, &llargs, None)
                 }
             };
 
@@ -696,8 +612,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                     assert!(!flatten);
 
                     for i in 0..elems.len() {
-                        let val = ExtractValue(bcx, val, i);
-                        Store(bcx, val, StructGEP(bcx, llresult, i));
+                        let val = bcx.extract_value(val, i);
+                        bcx.store(val, bcx.struct_gep(llresult, i));
                     }
                     C_nil(ccx)
                 }
@@ -706,11 +622,10 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         }
     };
 
-    if val_ty(llval) != Type::void(ccx) &&
-       machine::llsize_of_alloc(ccx, val_ty(llval)) != 0 {
+    if val_ty(llval) != Type::void(ccx) && machine::llsize_of_alloc(ccx, val_ty(llval)) != 0 {
         if let Some(ty) = fn_ty.ret.cast {
-            let ptr = PointerCast(bcx, llresult, ty.ptr_to());
-            let store = Store(bcx, llval, ptr);
+            let ptr = bcx.pointercast(llresult, ty.ptr_to());
+            let store = bcx.store(llval, ptr);
             unsafe {
                 llvm::LLVMSetAlignment(store, type_of::align_of(ccx, ret_ty));
             }
@@ -718,20 +633,17 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             store_ty(bcx, llval, llresult, ret_ty);
         }
     }
-
-    Result::new(bcx, llresult)
 }
 
-fn copy_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                              allow_overlap: bool,
-                              volatile: bool,
-                              tp_ty: Ty<'tcx>,
-                              dst: ValueRef,
-                              src: ValueRef,
-                              count: ValueRef,
-                              call_debug_location: DebugLoc)
-                              -> ValueRef {
-    let ccx = bcx.ccx();
+fn copy_intrinsic<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+                            allow_overlap: bool,
+                            volatile: bool,
+                            tp_ty: Ty<'tcx>,
+                            dst: ValueRef,
+                            src: ValueRef,
+                            count: ValueRef)
+                            -> ValueRef {
+    let ccx = bcx.ccx;
     let lltp_ty = type_of::type_of(ccx, tp_ty);
     let align = C_i32(ccx, type_of::align_of(ccx, tp_ty) as i32);
     let size = machine::llsize_of(ccx, lltp_ty);
@@ -745,92 +657,49 @@ fn copy_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     let name = format!("llvm.{}.p0i8.p0i8.i{}", operation, int_size);
 
-    let dst_ptr = PointerCast(bcx, dst, Type::i8p(ccx));
-    let src_ptr = PointerCast(bcx, src, Type::i8p(ccx));
+    let dst_ptr = bcx.pointercast(dst, Type::i8p(ccx));
+    let src_ptr = bcx.pointercast(src, Type::i8p(ccx));
     let llfn = ccx.get_intrinsic(&name);
 
-    Call(bcx,
-         llfn,
-         &[dst_ptr,
-           src_ptr,
-           Mul(bcx, size, count, DebugLoc::None),
-           align,
-           C_bool(ccx, volatile)],
-         call_debug_location)
+    bcx.call(llfn,
+        &[dst_ptr,
+        src_ptr,
+        bcx.mul(size, count),
+        align,
+        C_bool(ccx, volatile)],
+        None)
 }
 
-fn memset_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                volatile: bool,
-                                tp_ty: Ty<'tcx>,
-                                dst: ValueRef,
-                                val: ValueRef,
-                                count: ValueRef,
-                                call_debug_location: DebugLoc)
-                                -> ValueRef {
-    let ccx = bcx.ccx();
-    let lltp_ty = type_of::type_of(ccx, tp_ty);
-    let align = C_i32(ccx, type_of::align_of(ccx, tp_ty) as i32);
+fn memset_intrinsic<'a, 'tcx>(
+    bcx: &BlockAndBuilder<'a, 'tcx>,
+    volatile: bool,
+    ty: Ty<'tcx>,
+    dst: ValueRef,
+    val: ValueRef,
+    count: ValueRef
+) -> ValueRef {
+    let ccx = bcx.ccx;
+    let align = C_i32(ccx, type_of::align_of(ccx, ty) as i32);
+    let lltp_ty = type_of::type_of(ccx, ty);
     let size = machine::llsize_of(ccx, lltp_ty);
-    let int_size = machine::llbitsize_of_real(ccx, ccx.int_type());
-
-    let name = format!("llvm.memset.p0i8.i{}", int_size);
-
-    let dst_ptr = PointerCast(bcx, dst, Type::i8p(ccx));
-    let llfn = ccx.get_intrinsic(&name);
-
-    Call(bcx,
-         llfn,
-         &[dst_ptr,
-           val,
-           Mul(bcx, size, count, DebugLoc::None),
-           align,
-           C_bool(ccx, volatile)],
-         call_debug_location)
+    let dst = bcx.pointercast(dst, Type::i8p(ccx));
+    call_memset(bcx, dst, val, bcx.mul(size, count), align, volatile)
 }
 
-fn count_zeros_intrinsic(bcx: Block,
-                         name: &str,
-                         val: ValueRef,
-                         call_debug_location: DebugLoc)
-                         -> ValueRef {
-    let y = C_bool(bcx.ccx(), false);
-    let llfn = bcx.ccx().get_intrinsic(&name);
-    Call(bcx, llfn, &[val, y], call_debug_location)
-}
-
-fn with_overflow_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                       name: &str,
-                                       a: ValueRef,
-                                       b: ValueRef,
-                                       out: ValueRef,
-                                       call_debug_location: DebugLoc)
-                                       -> ValueRef {
-    let llfn = bcx.ccx().get_intrinsic(&name);
-
-    // Convert `i1` to a `bool`, and write it to the out parameter
-    let val = Call(bcx, llfn, &[a, b], call_debug_location);
-    let result = ExtractValue(bcx, val, 0);
-    let overflow = ZExt(bcx, ExtractValue(bcx, val, 1), Type::bool(bcx.ccx()));
-    Store(bcx, result, StructGEP(bcx, out, 0));
-    Store(bcx, overflow, StructGEP(bcx, out, 1));
-
-    C_nil(bcx.ccx())
-}
-
-fn try_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                             func: ValueRef,
-                             data: ValueRef,
-                             local_ptr: ValueRef,
-                             dest: ValueRef,
-                             dloc: DebugLoc) -> Block<'blk, 'tcx> {
+fn try_intrinsic<'a, 'tcx>(
+    bcx: &BlockAndBuilder<'a, 'tcx>,
+    func: ValueRef,
+    data: ValueRef,
+    local_ptr: ValueRef,
+    dest: ValueRef,
+) {
     if bcx.sess().no_landing_pads() {
-        Call(bcx, func, &[data], dloc);
-        Store(bcx, C_null(Type::i8p(bcx.ccx())), dest);
-        bcx
+        bcx.call(func, &[data], None);
+        bcx.store(C_null(Type::i8p(&bcx.ccx)), dest);
     } else if wants_msvc_seh(bcx.sess()) {
-        trans_msvc_try(bcx, func, data, local_ptr, dest, dloc)
+        trans_msvc_try(bcx, func, data, local_ptr, dest);
     } else {
-        trans_gnu_try(bcx, func, data, local_ptr, dest, dloc)
+        trans_gnu_try(bcx, func, data, local_ptr, dest);
     }
 }
 
@@ -841,26 +710,24 @@ fn try_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 // instructions are meant to work for all targets, as of the time of this
 // writing, however, LLVM does not recommend the usage of these new instructions
 // as the old ones are still more optimized.
-fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                              func: ValueRef,
-                              data: ValueRef,
-                              local_ptr: ValueRef,
-                              dest: ValueRef,
-                              dloc: DebugLoc) -> Block<'blk, 'tcx> {
-    let llfn = get_rust_try_fn(bcx.fcx, &mut |bcx| {
-        let ccx = bcx.ccx();
-        let dloc = DebugLoc::None;
-
-        SetPersonalityFn(bcx, bcx.fcx.eh_personality());
-
-        let normal = bcx.fcx.new_block("normal");
-        let catchswitch = bcx.fcx.new_block("catchswitch");
-        let catchpad = bcx.fcx.new_block("catchpad");
-        let caught = bcx.fcx.new_block("caught");
-
-        let func = llvm::get_param(bcx.fcx.llfn, 0);
-        let data = llvm::get_param(bcx.fcx.llfn, 1);
-        let local_ptr = llvm::get_param(bcx.fcx.llfn, 2);
+fn trans_msvc_try<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+                            func: ValueRef,
+                            data: ValueRef,
+                            local_ptr: ValueRef,
+                            dest: ValueRef) {
+    let llfn = get_rust_try_fn(bcx.fcx(), &mut |bcx| {
+        let ccx = bcx.ccx;
+
+        bcx.set_personality_fn(bcx.ccx.eh_personality());
+
+        let normal = bcx.fcx().build_new_block("normal");
+        let catchswitch = bcx.fcx().build_new_block("catchswitch");
+        let catchpad = bcx.fcx().build_new_block("catchpad");
+        let caught = bcx.fcx().build_new_block("caught");
+
+        let func = llvm::get_param(bcx.fcx().llfn, 0);
+        let data = llvm::get_param(bcx.fcx().llfn, 1);
+        let local_ptr = llvm::get_param(bcx.fcx().llfn, 2);
 
         // We're generating an IR snippet that looks like:
         //
@@ -902,37 +769,37 @@ fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         //
         // More information can be found in libstd's seh.rs implementation.
         let i64p = Type::i64(ccx).ptr_to();
-        let slot = Alloca(bcx, i64p, "slot");
-        Invoke(bcx, func, &[data], normal.llbb, catchswitch.llbb, dloc);
+        let slot = bcx.fcx().alloca(i64p, "slot");
+        bcx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(),
+            None);
 
-        Ret(normal, C_i32(ccx, 0), dloc);
+        normal.ret(C_i32(ccx, 0));
 
-        let cs = CatchSwitch(catchswitch, None, None, 1);
-        AddHandler(catchswitch, cs, catchpad.llbb);
+        let cs = catchswitch.catch_switch(None, None, 1);
+        catchswitch.add_handler(cs, catchpad.llbb());
 
         let tcx = ccx.tcx();
         let tydesc = match tcx.lang_items.msvc_try_filter() {
             Some(did) => ::consts::get_static(ccx, did),
             None => bug!("msvc_try_filter not defined"),
         };
-        let tok = CatchPad(catchpad, cs, &[tydesc, C_i32(ccx, 0), slot]);
-        let addr = Load(catchpad, slot);
-        let arg1 = Load(catchpad, addr);
+        let tok = catchpad.catch_pad(cs, &[tydesc, C_i32(ccx, 0), slot]);
+        let addr = catchpad.load(slot);
+        let arg1 = catchpad.load(addr);
         let val1 = C_i32(ccx, 1);
-        let arg2 = Load(catchpad, InBoundsGEP(catchpad, addr, &[val1]));
-        let local_ptr = BitCast(catchpad, local_ptr, i64p);
-        Store(catchpad, arg1, local_ptr);
-        Store(catchpad, arg2, InBoundsGEP(catchpad, local_ptr, &[val1]));
-        CatchRet(catchpad, tok, caught.llbb);
+        let arg2 = catchpad.load(catchpad.inbounds_gep(addr, &[val1]));
+        let local_ptr = catchpad.bitcast(local_ptr, i64p);
+        catchpad.store(arg1, local_ptr);
+        catchpad.store(arg2, catchpad.inbounds_gep(local_ptr, &[val1]));
+        catchpad.catch_ret(tok, caught.llbb());
 
-        Ret(caught, C_i32(ccx, 1), dloc);
+        caught.ret(C_i32(ccx, 1));
     });
 
     // Note that no invoke is used here because by definition this function
     // can't panic (that's what it's catching).
-    let ret = Call(bcx, llfn, &[func, data, local_ptr], dloc);
-    Store(bcx, ret, dest);
-    return bcx
+    let ret = bcx.call(llfn, &[func, data, local_ptr], None);
+    bcx.store(ret, dest);
 }
 
 // Definition of the standard "try" function for Rust using the GNU-like model
@@ -946,15 +813,13 @@ fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 // function calling it, and that function may already have other personality
 // functions in play. By calling a shim we're guaranteed that our shim will have
 // the right personality function.
-fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                             func: ValueRef,
-                             data: ValueRef,
-                             local_ptr: ValueRef,
-                             dest: ValueRef,
-                             dloc: DebugLoc) -> Block<'blk, 'tcx> {
-    let llfn = get_rust_try_fn(bcx.fcx, &mut |bcx| {
-        let ccx = bcx.ccx();
-        let dloc = DebugLoc::None;
+fn trans_gnu_try<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+                           func: ValueRef,
+                           data: ValueRef,
+                           local_ptr: ValueRef,
+                           dest: ValueRef) {
+    let llfn = get_rust_try_fn(bcx.fcx(), &mut |bcx| {
+        let ccx = bcx.ccx;
 
         // Translates the shims described above:
         //
@@ -973,14 +838,14 @@ fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         // expected to be `*mut *mut u8` for this to actually work, but that's
         // managed by the standard library.
 
-        let then = bcx.fcx.new_block("then");
-        let catch = bcx.fcx.new_block("catch");
+        let then = bcx.fcx().build_new_block("then");
+        let catch = bcx.fcx().build_new_block("catch");
 
-        let func = llvm::get_param(bcx.fcx.llfn, 0);
-        let data = llvm::get_param(bcx.fcx.llfn, 1);
-        let local_ptr = llvm::get_param(bcx.fcx.llfn, 2);
-        Invoke(bcx, func, &[data], then.llbb, catch.llbb, dloc);
-        Ret(then, C_i32(ccx, 0), dloc);
+        let func = llvm::get_param(bcx.fcx().llfn, 0);
+        let data = llvm::get_param(bcx.fcx().llfn, 1);
+        let local_ptr = llvm::get_param(bcx.fcx().llfn, 2);
+        bcx.invoke(func, &[data], then.llbb(), catch.llbb(), None);
+        then.ret(C_i32(ccx, 0));
 
         // Type indicator for the exception being thrown.
         //
@@ -990,18 +855,17 @@ fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         // rust_try ignores the selector.
         let lpad_ty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)],
                                     false);
-        let vals = LandingPad(catch, lpad_ty, bcx.fcx.eh_personality(), 1);
-        AddClause(catch, vals, C_null(Type::i8p(ccx)));
-        let ptr = ExtractValue(catch, vals, 0);
-        Store(catch, ptr, BitCast(catch, local_ptr, Type::i8p(ccx).ptr_to()));
-        Ret(catch, C_i32(ccx, 1), dloc);
+        let vals = catch.landing_pad(lpad_ty, bcx.ccx.eh_personality(), 1, catch.fcx().llfn);
+        catch.add_clause(vals, C_null(Type::i8p(ccx)));
+        let ptr = catch.extract_value(vals, 0);
+        catch.store(ptr, catch.bitcast(local_ptr, Type::i8p(ccx).ptr_to()));
+        catch.ret(C_i32(ccx, 1));
     });
 
     // Note that no invoke is used here because by definition this function
     // can't panic (that's what it's catching).
-    let ret = Call(bcx, llfn, &[func, data, local_ptr], dloc);
-    Store(bcx, ret, dest);
-    return bcx;
+    let ret = bcx.call(llfn, &[func, data, local_ptr], None);
+    bcx.store(ret, dest);
 }
 
 // Helper function to give a Block to a closure to translate a shim function.
@@ -1010,11 +874,10 @@ fn gen_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
                     name: &str,
                     inputs: Vec<Ty<'tcx>>,
                     output: Ty<'tcx>,
-                    trans: &mut for<'b> FnMut(Block<'b, 'tcx>))
+                    trans: &mut for<'b> FnMut(BlockAndBuilder<'b, 'tcx>))
                     -> ValueRef {
     let ccx = fcx.ccx;
     let sig = ccx.tcx().mk_fn_sig(inputs.into_iter(), output, false);
-    let fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
 
     let rust_fn_ty = ccx.tcx().mk_fn_ptr(ccx.tcx().mk_bare_fn(ty::BareFnTy {
         unsafety: hir::Unsafety::Unsafe,
@@ -1022,11 +885,8 @@ fn gen_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
         sig: ty::Binder(sig)
     }));
     let llfn = declare::define_internal_fn(ccx, name, rust_fn_ty);
-    let (fcx, block_arena);
-    block_arena = TypedArena::new();
-    fcx = FunctionContext::new(ccx, llfn, fn_ty, None, &block_arena);
-    trans(fcx.init(true));
-    fcx.cleanup();
+    let fcx = FunctionContext::new(ccx, llfn);
+    trans(fcx.get_entry_block());
     llfn
 }
 
@@ -1035,7 +895,7 @@ fn gen_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
 //
 // This function is only generated once and is then cached.
 fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
-                             trans: &mut for<'b> FnMut(Block<'b, 'tcx>))
+                             trans: &mut for<'b> FnMut(BlockAndBuilder<'b, 'tcx>))
                              -> ValueRef {
     let ccx = fcx.ccx;
     if let Some(llfn) = ccx.rust_try_fn().get() {
@@ -1060,16 +920,15 @@ fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
     span_err!(a, b, E0511, "{}", c);
 }
 
-fn generic_simd_intrinsic<'blk, 'tcx, 'a>
-    (bcx: Block<'blk, 'tcx>,
-     name: &str,
-     callee_ty: Ty<'tcx>,
-     llargs: &[ValueRef],
-     ret_ty: Ty<'tcx>,
-     llret_ty: Type,
-     call_debug_location: DebugLoc,
-     span: Span) -> ValueRef
-{
+fn generic_simd_intrinsic<'a, 'tcx>(
+    bcx: &BlockAndBuilder<'a, 'tcx>,
+    name: &str,
+    callee_ty: Ty<'tcx>,
+    llargs: &[ValueRef],
+    ret_ty: Ty<'tcx>,
+    llret_ty: Type,
+    span: Span
+) -> ValueRef {
     // macros for error handling:
     macro_rules! emit_error {
         ($msg: tt) => {
@@ -1087,7 +946,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>
         ($cond: expr, $($fmt: tt)*) => {
             if !$cond {
                 emit_error!($($fmt)*);
-                return C_nil(bcx.ccx())
+                return C_nil(bcx.ccx)
             }
         }
     }
@@ -1138,8 +997,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>
                                   llargs[1],
                                   in_elem,
                                   llret_ty,
-                                  cmp_op,
-                                  call_debug_location)
+                                  cmp_op)
     }
 
     if name.starts_with("simd_shuffle") {
@@ -1179,7 +1037,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>
                                     arg_idx, total_len);
                         None
                     }
-                    Some(idx) => Some(C_i32(bcx.ccx(), idx as i32)),
+                    Some(idx) => Some(C_i32(bcx.ccx, idx as i32)),
                 }
             })
             .collect();
@@ -1188,20 +1046,20 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>
             None => return C_null(llret_ty)
         };
 
-        return ShuffleVector(bcx, llargs[0], llargs[1], C_vector(&indices))
+        return bcx.shuffle_vector(llargs[0], llargs[1], C_vector(&indices))
     }
 
     if name == "simd_insert" {
         require!(in_elem == arg_tys[2],
                  "expected inserted type `{}` (element of input `{}`), found `{}`",
                  in_elem, in_ty, arg_tys[2]);
-        return InsertElement(bcx, llargs[0], llargs[2], llargs[1])
+        return bcx.insert_element(llargs[0], llargs[2], llargs[1])
     }
     if name == "simd_extract" {
         require!(ret_ty == in_elem,
                  "expected return type `{}` (element of input `{}`), found `{}`",
                  in_elem, in_ty, ret_ty);
-        return ExtractElement(bcx, llargs[0], llargs[1])
+        return bcx.extract_element(llargs[0], llargs[1])
     }
 
     if name == "simd_cast" {
@@ -1237,34 +1095,34 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>
         match (in_style, out_style) {
             (Style::Int(in_is_signed), Style::Int(_)) => {
                 return match in_width.cmp(&out_width) {
-                    Ordering::Greater => Trunc(bcx, llargs[0], llret_ty),
+                    Ordering::Greater => bcx.trunc(llargs[0], llret_ty),
                     Ordering::Equal => llargs[0],
                     Ordering::Less => if in_is_signed {
-                        SExt(bcx, llargs[0], llret_ty)
+                        bcx.sext(llargs[0], llret_ty)
                     } else {
-                        ZExt(bcx, llargs[0], llret_ty)
+                        bcx.zext(llargs[0], llret_ty)
                     }
                 }
             }
             (Style::Int(in_is_signed), Style::Float) => {
                 return if in_is_signed {
-                    SIToFP(bcx, llargs[0], llret_ty)
+                    bcx.sitofp(llargs[0], llret_ty)
                 } else {
-                    UIToFP(bcx, llargs[0], llret_ty)
+                    bcx.uitofp(llargs[0], llret_ty)
                 }
             }
             (Style::Float, Style::Int(out_is_signed)) => {
                 return if out_is_signed {
-                    FPToSI(bcx, llargs[0], llret_ty)
+                    bcx.fptosi(llargs[0], llret_ty)
                 } else {
-                    FPToUI(bcx, llargs[0], llret_ty)
+                    bcx.fptoui(llargs[0], llret_ty)
                 }
             }
             (Style::Float, Style::Float) => {
                 return match in_width.cmp(&out_width) {
-                    Ordering::Greater => FPTrunc(bcx, llargs[0], llret_ty),
+                    Ordering::Greater => bcx.fptrunc(llargs[0], llret_ty),
                     Ordering::Equal => llargs[0],
-                    Ordering::Less => FPExt(bcx, llargs[0], llret_ty)
+                    Ordering::Less => bcx.fpext(llargs[0], llret_ty)
                 }
             }
             _ => {/* Unsupported. Fallthrough. */}
@@ -1275,13 +1133,13 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>
                  ret_ty, out_elem);
     }
     macro_rules! arith {
-        ($($name: ident: $($($p: ident),* => $call: expr),*;)*) => {
+        ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => {
             $(
                 if name == stringify!($name) {
                     match in_elem.sty {
                         $(
                             $(ty::$p(_))|* => {
-                                return $call(bcx, llargs[0], llargs[1], call_debug_location)
+                                return bcx.$call(llargs[0], llargs[1])
                             }
                             )*
                         _ => {},
@@ -1294,15 +1152,15 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>
         }
     }
     arith! {
-        simd_add: TyUint, TyInt => Add, TyFloat => FAdd;
-        simd_sub: TyUint, TyInt => Sub, TyFloat => FSub;
-        simd_mul: TyUint, TyInt => Mul, TyFloat => FMul;
-        simd_div: TyFloat => FDiv;
-        simd_shl: TyUint, TyInt => Shl;
-        simd_shr: TyUint => LShr, TyInt => AShr;
-        simd_and: TyUint, TyInt => And;
-        simd_or: TyUint, TyInt => Or;
-        simd_xor: TyUint, TyInt => Xor;
+        simd_add: TyUint, TyInt => add, TyFloat => fadd;
+        simd_sub: TyUint, TyInt => sub, TyFloat => fsub;
+        simd_mul: TyUint, TyInt => mul, TyFloat => fmul;
+        simd_div: TyFloat => fdiv;
+        simd_shl: TyUint, TyInt => shl;
+        simd_shr: TyUint => lshr, TyInt => ashr;
+        simd_and: TyUint, TyInt => and;
+        simd_or: TyUint, TyInt => or;
+        simd_xor: TyUint, TyInt => xor;
     }
     span_bug!(span, "unknown SIMD intrinsic");
 }
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index e2da635b159..3a8eef131a2 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -26,7 +26,6 @@
 #![feature(associated_consts)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![feature(cell_extras)]
 #![feature(const_fn)]
 #![feature(custom_attribute)]
 #![allow(unused_attributes)]
@@ -37,6 +36,7 @@
 #![feature(slice_patterns)]
 #![feature(staged_api)]
 #![feature(unicode)]
+#![feature(conservative_impl_trait)]
 
 use rustc::dep_graph::WorkProduct;
 
@@ -96,8 +96,6 @@ mod asm;
 mod assert_module_sources;
 mod attributes;
 mod base;
-mod basic_block;
-mod build;
 mod builder;
 mod cabi_aarch64;
 mod cabi_arm;
@@ -108,6 +106,7 @@ mod cabi_msp430;
 mod cabi_powerpc;
 mod cabi_powerpc64;
 mod cabi_s390x;
+mod cabi_sparc;
 mod cabi_x86;
 mod cabi_x86_64;
 mod cabi_x86_win64;
diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs
index aa9b900fa46..cf50e7be2af 100644
--- a/src/librustc_trans/meth.rs
+++ b/src/librustc_trans/meth.rs
@@ -9,16 +9,11 @@
 // except according to those terms.
 
 use attributes;
-use arena::TypedArena;
 use llvm::{ValueRef, get_params};
 use rustc::traits;
-use abi::FnType;
-use base::*;
-use build::*;
-use callee::Callee;
+use callee::{Callee, CalleeData};
 use common::*;
 use consts;
-use debuginfo::DebugLoc;
 use declare;
 use glue;
 use machine;
@@ -32,15 +27,15 @@ use rustc::ty;
 const VTABLE_OFFSET: usize = 3;
 
 /// Extracts a method from a trait object's vtable, at the specified index.
-pub fn get_virtual_method<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                      llvtable: ValueRef,
-                                      vtable_index: usize)
-                                      -> ValueRef {
+pub fn get_virtual_method<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+                                    llvtable: ValueRef,
+                                    vtable_index: usize)
+                                    -> ValueRef {
     // Load the data pointer from the object.
     debug!("get_virtual_method(vtable_index={}, llvtable={:?})",
            vtable_index, Value(llvtable));
 
-    Load(bcx, GEPi(bcx, llvtable, &[vtable_index + VTABLE_OFFSET]))
+    bcx.load(bcx.gepi(llvtable, &[vtable_index + VTABLE_OFFSET]))
 }
 
 /// Generate a shim function that allows an object type like `SomeTrait` to
@@ -67,36 +62,47 @@ pub fn get_virtual_method<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
                                    callee: Callee<'tcx>)
                                    -> ValueRef {
-    let _icx = push_ctxt("trans_object_shim");
-    let tcx = ccx.tcx();
-
     debug!("trans_object_shim({:?})", callee);
 
-    let (sig, abi, function_name) = match callee.ty.sty {
-        ty::TyFnDef(def_id, substs, f) => {
+    let function_name = match callee.ty.sty {
+        ty::TyFnDef(def_id, substs, _) => {
             let instance = Instance::new(def_id, substs);
-            (&f.sig, f.abi, instance.symbol_name(ccx.shared()))
+            instance.symbol_name(ccx.shared())
         }
         _ => bug!()
     };
 
-    let sig = tcx.erase_late_bound_regions_and_normalize(sig);
-    let fn_ty = FnType::new(ccx, abi, &sig, &[]);
-
     let llfn = declare::define_internal_fn(ccx, &function_name, callee.ty);
     attributes::set_frame_pointer_elimination(ccx, llfn);
 
-    let (block_arena, fcx): (TypedArena<_>, FunctionContext);
-    block_arena = TypedArena::new();
-    fcx = FunctionContext::new(ccx, llfn, fn_ty, None, &block_arena);
-    let mut bcx = fcx.init(false);
-
-    let dest = fcx.llretslotptr.get();
-    let llargs = get_params(fcx.llfn);
-    bcx = callee.call(bcx, DebugLoc::None,
-                      &llargs[fcx.fn_ty.ret.is_indirect() as usize..], dest).bcx;
-
-    fcx.finish(bcx, DebugLoc::None);
+    let fcx = FunctionContext::new(ccx, llfn);
+    let bcx = fcx.get_entry_block();
+
+    let mut llargs = get_params(fcx.llfn);
+    let fn_ret = callee.ty.fn_ret();
+    let fn_ty = callee.direct_fn_type(ccx, &[]);
+
+    let fn_ptr = match callee.data {
+        CalleeData::Virtual(idx) => {
+            let fn_ptr = get_virtual_method(&bcx,
+                llargs.remove(fn_ty.ret.is_indirect() as usize + 1), idx);
+            let llty = fn_ty.llvm_type(bcx.ccx).ptr_to();
+            bcx.pointercast(fn_ptr, llty)
+        },
+        _ => bug!("trans_object_shim called with non-virtual callee"),
+    };
+    let llret = bcx.call(fn_ptr, &llargs, None);
+    fn_ty.apply_attrs_callsite(llret);
+
+    if fn_ret.0.is_never() {
+        bcx.unreachable();
+    } else {
+        if fn_ty.ret.is_indirect() || fn_ty.ret.is_ignore() {
+            bcx.ret_void();
+        } else {
+            bcx.ret(llret);
+        }
+    }
 
     llfn
 }
@@ -115,7 +121,6 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                             -> ValueRef
 {
     let tcx = ccx.tcx();
-    let _icx = push_ctxt("meth::get_vtable");
 
     debug!("get_vtable(ty={:?}, trait_ref={:?})", ty, trait_ref);
 
diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs
index e4d0533ec87..8df24da7135 100644
--- a/src/librustc_trans/mir/analyze.rs
+++ b/src/librustc_trans/mir/analyze.rs
@@ -16,31 +16,30 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use rustc::mir::{self, Location, TerminatorKind};
 use rustc::mir::visit::{Visitor, LvalueContext};
 use rustc::mir::traversal;
-use common::{self, Block, BlockAndBuilder};
-use glue;
+use common;
+use super::MirContext;
 use super::rvalue;
 
-pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>,
-                                 mir: &mir::Mir<'tcx>) -> BitVector {
-    let bcx = bcx.build();
-    let mut analyzer = LocalAnalyzer::new(mir, &bcx);
+pub fn lvalue_locals<'a, 'tcx>(mircx: &MirContext<'a, 'tcx>) -> BitVector {
+    let mir = mircx.mir;
+    let mut analyzer = LocalAnalyzer::new(mircx);
 
     analyzer.visit_mir(mir);
 
     for (index, ty) in mir.local_decls.iter().map(|l| l.ty).enumerate() {
-        let ty = bcx.monomorphize(&ty);
+        let ty = mircx.monomorphize(&ty);
         debug!("local {} has type {:?}", index, ty);
         if ty.is_scalar() ||
             ty.is_unique() ||
             ty.is_region_ptr() ||
             ty.is_simd() ||
-            common::type_is_zero_size(bcx.ccx(), ty)
+            common::type_is_zero_size(mircx.ccx, ty)
         {
             // These sorts of types are immediates that we can store
             // in an ValueRef without an alloca.
-            assert!(common::type_is_immediate(bcx.ccx(), ty) ||
-                    common::type_is_fat_ptr(bcx.tcx(), ty));
-        } else if common::type_is_imm_pair(bcx.ccx(), ty) {
+            assert!(common::type_is_immediate(mircx.ccx, ty) ||
+                    common::type_is_fat_ptr(mircx.ccx, ty));
+        } else if common::type_is_imm_pair(mircx.ccx, ty) {
             // We allow pairs and uses of any of their 2 fields.
         } else {
             // These sorts of types require an alloca. Note that
@@ -56,22 +55,18 @@ pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>,
     analyzer.lvalue_locals
 }
 
-struct LocalAnalyzer<'mir, 'bcx: 'mir, 'tcx: 'bcx> {
-    mir: &'mir mir::Mir<'tcx>,
-    bcx: &'mir BlockAndBuilder<'bcx, 'tcx>,
+struct LocalAnalyzer<'mir, 'a: 'mir, 'tcx: 'a> {
+    cx: &'mir MirContext<'a, 'tcx>,
     lvalue_locals: BitVector,
     seen_assigned: BitVector
 }
 
-impl<'mir, 'bcx, 'tcx> LocalAnalyzer<'mir, 'bcx, 'tcx> {
-    fn new(mir: &'mir mir::Mir<'tcx>,
-           bcx: &'mir BlockAndBuilder<'bcx, 'tcx>)
-           -> LocalAnalyzer<'mir, 'bcx, 'tcx> {
+impl<'mir, 'a, 'tcx> LocalAnalyzer<'mir, 'a, 'tcx> {
+    fn new(mircx: &'mir MirContext<'a, 'tcx>) -> LocalAnalyzer<'mir, 'a, 'tcx> {
         LocalAnalyzer {
-            mir: mir,
-            bcx: bcx,
-            lvalue_locals: BitVector::new(mir.local_decls.len()),
-            seen_assigned: BitVector::new(mir.local_decls.len())
+            cx: mircx,
+            lvalue_locals: BitVector::new(mircx.mir.local_decls.len()),
+            seen_assigned: BitVector::new(mircx.mir.local_decls.len())
         }
     }
 
@@ -87,7 +82,7 @@ impl<'mir, 'bcx, 'tcx> LocalAnalyzer<'mir, 'bcx, 'tcx> {
     }
 }
 
-impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> {
+impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
     fn visit_assign(&mut self,
                     block: mir::BasicBlock,
                     lvalue: &mir::Lvalue<'tcx>,
@@ -97,7 +92,7 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> {
 
         if let mir::Lvalue::Local(index) = *lvalue {
             self.mark_assigned(index);
-            if !rvalue::rvalue_creates_operand(self.mir, self.bcx, rvalue) {
+            if !rvalue::rvalue_creates_operand(rvalue) {
                 self.mark_as_lvalue(index);
             }
         } else {
@@ -117,7 +112,7 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> {
                     literal: mir::Literal::Item { def_id, .. }, ..
                 }),
                 ref args, ..
-            } if Some(def_id) == self.bcx.tcx().lang_items.box_free_fn() => {
+            } if Some(def_id) == self.cx.ccx.tcx().lang_items.box_free_fn() => {
                 // box_free(x) shares with `drop x` the property that it
                 // is not guaranteed to be statically dominated by the
                 // definition of x, so x must always be in an alloca.
@@ -140,10 +135,10 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> {
         // Allow uses of projections of immediate pair fields.
         if let mir::Lvalue::Projection(ref proj) = *lvalue {
             if let mir::Lvalue::Local(_) = proj.base {
-                let ty = proj.base.ty(self.mir, self.bcx.tcx());
+                let ty = proj.base.ty(self.cx.mir, self.cx.ccx.tcx());
 
-                let ty = self.bcx.monomorphize(&ty.to_ty(self.bcx.tcx()));
-                if common::type_is_imm_pair(self.bcx.ccx(), ty) {
+                let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
+                if common::type_is_imm_pair(self.cx.ccx, ty) {
                     if let mir::ProjectionElem::Field(..) = proj.elem {
                         if let LvalueContext::Consume = context {
                             return;
@@ -171,11 +166,11 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> {
                 }
 
                 LvalueContext::Drop => {
-                    let ty = lvalue.ty(self.mir, self.bcx.tcx());
-                    let ty = self.bcx.monomorphize(&ty.to_ty(self.bcx.tcx()));
+                    let ty = lvalue.ty(self.cx.mir, self.cx.ccx.tcx());
+                    let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
 
                     // Only need the lvalue if we're actually dropping it.
-                    if glue::type_needs_drop(self.bcx.tcx(), ty) {
+                    if self.cx.ccx.shared().type_needs_drop(ty) {
                         self.mark_as_lvalue(index);
                     }
                 }
@@ -200,10 +195,7 @@ pub enum CleanupKind {
     Internal { funclet: mir::BasicBlock }
 }
 
-pub fn cleanup_kinds<'bcx,'tcx>(_bcx: Block<'bcx,'tcx>,
-                                mir: &mir::Mir<'tcx>)
-                                -> IndexVec<mir::BasicBlock, CleanupKind>
-{
+pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec<mir::BasicBlock, CleanupKind> {
     fn discover_masters<'tcx>(result: &mut IndexVec<mir::BasicBlock, CleanupKind>,
                               mir: &mir::Mir<'tcx>) {
         for (bb, data) in mir.basic_blocks().iter_enumerated() {
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index 76f5f32b5dc..71ac7c0d252 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -8,20 +8,18 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use llvm::{self, ValueRef};
+use llvm::{self, ValueRef, BasicBlockRef};
 use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err};
 use rustc::middle::lang_items;
-use rustc::ty;
+use rustc::ty::{self, layout};
 use rustc::mir;
 use abi::{Abi, FnType, ArgType};
-use adt;
-use base;
-use build;
+use adt::{self, MaybeSizedValue};
+use base::{self, Lifetime};
 use callee::{Callee, CalleeData, Fn, Intrinsic, NamedTupleConstructor, Virtual};
-use common::{self, Block, BlockAndBuilder, LandingPad};
+use common::{self, BlockAndBuilder, Funclet};
 use common::{C_bool, C_str_slice, C_struct, C_u32, C_undef};
 use consts;
-use debuginfo::DebugLoc;
 use Disr;
 use machine::{llalign_of_min, llbitsize_of_real};
 use meth;
@@ -29,6 +27,7 @@ use type_of;
 use glue;
 use type_::Type;
 
+use rustc_data_structures::indexed_vec::IndexVec;
 use rustc_data_structures::fx::FxHashMap;
 use syntax::symbol::Symbol;
 
@@ -39,21 +38,25 @@ use super::lvalue::{LvalueRef};
 use super::operand::OperandRef;
 use super::operand::OperandValue::{Pair, Ref, Immediate};
 
-use std::cell::Ref as CellRef;
-
-impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
-    pub fn trans_block(&mut self, bb: mir::BasicBlock) {
-        let mut bcx = self.bcx(bb);
-        let data = &CellRef::clone(&self.mir)[bb];
+impl<'a, 'tcx> MirContext<'a, 'tcx> {
+    pub fn trans_block(&mut self, bb: mir::BasicBlock,
+        funclets: &IndexVec<mir::BasicBlock, Option<Funclet>>) {
+        let mut bcx = self.build_block(bb);
+        let data = &self.mir[bb];
 
         debug!("trans_block({:?}={:?})", bb, data);
 
+        let funclet = match self.cleanup_kinds[bb] {
+            CleanupKind::Internal { funclet } => funclets[funclet].as_ref(),
+            _ => funclets[bb].as_ref(),
+        };
+
         // Create the cleanup bundle, if needed.
-        let cleanup_pad = bcx.lpad().and_then(|lp| lp.cleanuppad());
-        let cleanup_bundle = bcx.lpad().and_then(|l| l.bundle());
+        let cleanup_pad = funclet.map(|lp| lp.cleanuppad());
+        let cleanup_bundle = funclet.map(|l| l.bundle());
 
         let funclet_br = |this: &Self, bcx: BlockAndBuilder, bb: mir::BasicBlock| {
-            let lltarget = this.blocks[bb].llbb;
+            let lltarget = this.blocks[bb];
             if let Some(cp) = cleanup_pad {
                 match this.cleanup_kinds[bb] {
                     CleanupKind::Funclet => {
@@ -70,7 +73,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         };
 
         let llblock = |this: &mut Self, target: mir::BasicBlock| {
-            let lltarget = this.blocks[target].llbb;
+            let lltarget = this.blocks[target];
 
             if let Some(cp) = cleanup_pad {
                 match this.cleanup_kinds[target] {
@@ -79,8 +82,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
                         debug!("llblock: creating cleanup trampoline for {:?}", target);
                         let name = &format!("{:?}_cleanup_trampoline_{:?}", bb, target);
-                        let trampoline = this.fcx.new_block(name).build();
-                        trampoline.set_personality_fn(this.fcx.eh_personality());
+                        let trampoline = this.fcx.build_new_block(name);
                         trampoline.cleanup_ret(cp, Some(lltarget));
                         trampoline.llbb()
                     }
@@ -93,7 +95,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     (this.cleanup_kinds[bb], this.cleanup_kinds[target])
                 {
                     // jump *into* cleanup - need a landing pad if GNU
-                    this.landing_pad_to(target).llbb
+                    this.landing_pad_to(target)
                 } else {
                     lltarget
                 }
@@ -108,23 +110,22 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         debug!("trans_block: terminator: {:?}", terminator);
 
         let span = terminator.source_info.span;
-        let debug_loc = self.debug_loc(terminator.source_info);
-        debug_loc.apply_to_bcx(&bcx);
-        debug_loc.apply(bcx.fcx());
+        self.set_debug_loc(&bcx, terminator.source_info);
         match terminator.kind {
             mir::TerminatorKind::Resume => {
                 if let Some(cleanup_pad) = cleanup_pad {
                     bcx.cleanup_ret(cleanup_pad, None);
                 } else {
-                    let llpersonality = bcx.fcx().eh_personality();
-                    bcx.set_personality_fn(llpersonality);
-
                     let ps = self.get_personality_slot(&bcx);
                     let lp = bcx.load(ps);
-                    bcx.with_block(|bcx| {
-                        base::call_lifetime_end(bcx, ps);
-                        base::trans_unwind_resume(bcx, lp);
-                    });
+                    Lifetime::End.call(&bcx, ps);
+                    if !bcx.sess().target.target.options.custom_unwind_resume {
+                        bcx.resume(lp);
+                    } else {
+                        let exc_ptr = bcx.extract_value(lp, 0);
+                        bcx.call(bcx.ccx.eh_unwind_resume(), &[exc_ptr], cleanup_bundle);
+                        bcx.unreachable();
+                    }
                 }
             }
 
@@ -143,9 +144,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             mir::TerminatorKind::Switch { ref discr, ref adt_def, ref targets } => {
                 let discr_lvalue = self.trans_lvalue(&bcx, discr);
                 let ty = discr_lvalue.ty.to_ty(bcx.tcx());
-                let discr = bcx.with_block(|bcx|
-                    adt::trans_get_discr(bcx, ty, discr_lvalue.llval, None, true)
-                );
+                let discr = adt::trans_get_discr(&bcx, ty, discr_lvalue.llval, None, true);
 
                 let mut bb_hist = FxHashMap();
                 for target in targets {
@@ -162,16 +161,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     // We're generating an exhaustive switch, so the else branch
                     // can't be hit.  Branching to an unreachable instruction
                     // lets LLVM know this
-                    _ => (None, self.unreachable_block().llbb)
+                    _ => (None, self.unreachable_block())
                 };
                 let switch = bcx.switch(discr, default_blk, targets.len());
                 assert_eq!(adt_def.variants.len(), targets.len());
                 for (adt_variant, &target) in adt_def.variants.iter().zip(targets) {
                     if default_bb != Some(target) {
                         let llbb = llblock(self, target);
-                        let llval = bcx.with_block(|bcx| adt::trans_case(
-                                bcx, ty, Disr::from(adt_variant.disr_val)));
-                        build::AddCase(switch, llval, llbb)
+                        let llval = adt::trans_case(&bcx, ty, Disr::from(adt_variant.disr_val));
+                        bcx.add_case(switch, llval, llbb)
                     }
                 }
             }
@@ -179,17 +177,17 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => {
                 let (otherwise, targets) = targets.split_last().unwrap();
                 let discr = bcx.load(self.trans_lvalue(&bcx, discr).llval);
-                let discr = bcx.with_block(|bcx| base::to_immediate(bcx, discr, switch_ty));
+                let discr = base::to_immediate(&bcx, discr, switch_ty);
                 let switch = bcx.switch(discr, llblock(self, *otherwise), values.len());
                 for (value, target) in values.iter().zip(targets) {
-                    let val = Const::from_constval(bcx.ccx(), value.clone(), switch_ty);
+                    let val = Const::from_constval(bcx.ccx, value.clone(), switch_ty);
                     let llbb = llblock(self, *target);
-                    build::AddCase(switch, val.llval, llbb)
+                    bcx.add_case(switch, val.llval, llbb)
                 }
             }
 
             mir::TerminatorKind::Return => {
-                let ret = bcx.fcx().fn_ty.ret;
+                let ret = self.fn_ty.ret;
                 if ret.is_ignore() || ret.is_indirect() {
                     bcx.ret_void();
                     return;
@@ -208,14 +206,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     };
                     let llslot = match op.val {
                         Immediate(_) | Pair(..) => {
-                            let llscratch = build::AllocaFcx(bcx.fcx(), ret.original_ty, "ret");
+                            let llscratch = bcx.fcx().alloca(ret.original_ty, "ret");
                             self.store_operand(&bcx, llscratch, op);
                             llscratch
                         }
                         Ref(llval) => llval
                     };
                     let load = bcx.load(bcx.pointercast(llslot, cast_ty.ptr_to()));
-                    let llalign = llalign_of_min(bcx.ccx(), ret.ty);
+                    let llalign = llalign_of_min(bcx.ccx, ret.ty);
                     unsafe {
                         llvm::LLVMSetAlignment(load, llalign);
                     }
@@ -233,48 +231,38 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
             mir::TerminatorKind::Drop { ref location, target, unwind } => {
                 let ty = location.ty(&self.mir, bcx.tcx()).to_ty(bcx.tcx());
-                let ty = bcx.monomorphize(&ty);
+                let ty = self.monomorphize(&ty);
 
                 // Double check for necessity to drop
-                if !glue::type_needs_drop(bcx.tcx(), ty) {
+                if !bcx.ccx.shared().type_needs_drop(ty) {
                     funclet_br(self, bcx, target);
                     return;
                 }
 
                 let lvalue = self.trans_lvalue(&bcx, location);
-                let drop_fn = glue::get_drop_glue(bcx.ccx(), ty);
-                let drop_ty = glue::get_drop_glue_type(bcx.tcx(), ty);
-                let is_sized = common::type_is_sized(bcx.tcx(), ty);
-                let llvalue = if is_sized {
-                    if drop_ty != ty {
-                        bcx.pointercast(lvalue.llval, type_of::type_of(bcx.ccx(), drop_ty).ptr_to())
+                let drop_fn = glue::get_drop_glue(bcx.ccx, ty);
+                let drop_ty = glue::get_drop_glue_type(bcx.ccx.shared(), ty);
+                let ptr = if bcx.ccx.shared().type_is_sized(ty) {
+                    let value = if drop_ty != ty {
+                        bcx.pointercast(lvalue.llval, type_of::type_of(bcx.ccx, drop_ty).ptr_to())
                     } else {
                         lvalue.llval
-                    }
+                    };
+                    MaybeSizedValue::sized(value)
                 } else {
-                    // FIXME(#36457) Currently drop glue takes sized
-                    // values as a `*(data, meta)`, but elsewhere in
-                    // MIR we pass `(data, meta)` as two separate
-                    // arguments. It would be better to fix drop glue,
-                    // but I am shooting for a quick fix to #35546
-                    // here that can be cleanly backported to beta, so
-                    // I want to avoid touching all of trans.
-                    bcx.with_block(|bcx| {
-                        let scratch = base::alloc_ty(bcx, ty, "drop");
-                        base::call_lifetime_start(bcx, scratch);
-                        build::Store(bcx, lvalue.llval, base::get_dataptr(bcx, scratch));
-                        build::Store(bcx, lvalue.llextra, base::get_meta(bcx, scratch));
-                        scratch
-                    })
+                    MaybeSizedValue::unsized_(lvalue.llval, lvalue.llextra)
                 };
+                let args = &[ptr.value, ptr.meta][..1 + ptr.has_meta() as usize];
                 if let Some(unwind) = unwind {
-                    bcx.invoke(drop_fn,
-                               &[llvalue],
-                               self.blocks[target].llbb,
-                               llblock(self, unwind),
-                               cleanup_bundle);
+                    bcx.invoke(
+                        drop_fn,
+                        args,
+                        self.blocks[target],
+                        llblock(self, unwind),
+                        cleanup_bundle
+                    );
                 } else {
-                    bcx.call(drop_fn, &[llvalue], cleanup_bundle);
+                    bcx.call(drop_fn, args, cleanup_bundle);
                     funclet_br(self, bcx, target);
                 }
             }
@@ -290,7 +278,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 // NOTE: Unlike binops, negation doesn't have its own
                 // checked operation, just a comparison with the minimum
                 // value, so we have to check for the assert message.
-                if !bcx.ccx().check_overflow() {
+                if !bcx.ccx.check_overflow() {
                     use rustc_const_math::ConstMathErr::Overflow;
                     use rustc_const_math::Op::Neg;
 
@@ -306,27 +294,27 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 }
 
                 // Pass the condition through llvm.expect for branch hinting.
-                let expect = bcx.ccx().get_intrinsic(&"llvm.expect.i1");
-                let cond = bcx.call(expect, &[cond, C_bool(bcx.ccx(), expected)], None);
+                let expect = bcx.ccx.get_intrinsic(&"llvm.expect.i1");
+                let cond = bcx.call(expect, &[cond, C_bool(bcx.ccx, expected)], None);
 
                 // Create the failure block and the conditional branch to it.
                 let lltarget = llblock(self, target);
-                let panic_block = self.fcx.new_block("panic");
+                let panic_block = self.fcx.build_new_block("panic");
                 if expected {
-                    bcx.cond_br(cond, lltarget, panic_block.llbb);
+                    bcx.cond_br(cond, lltarget, panic_block.llbb());
                 } else {
-                    bcx.cond_br(cond, panic_block.llbb, lltarget);
+                    bcx.cond_br(cond, panic_block.llbb(), lltarget);
                 }
 
                 // After this point, bcx is the block for the call to panic.
-                bcx = panic_block.build();
-                debug_loc.apply_to_bcx(&bcx);
+                bcx = panic_block;
+                self.set_debug_loc(&bcx, terminator.source_info);
 
                 // Get the location information.
                 let loc = bcx.sess().codemap().lookup_char_pos(span.lo);
                 let filename = Symbol::intern(&loc.file.name).as_str();
-                let filename = C_str_slice(bcx.ccx(), filename);
-                let line = C_u32(bcx.ccx(), loc.line as u32);
+                let filename = C_str_slice(bcx.ccx, filename);
+                let line = C_u32(bcx.ccx, loc.line as u32);
 
                 // Put together the arguments to the panic entry point.
                 let (lang_item, args, const_err) = match *msg {
@@ -343,9 +331,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                             })
                         });
 
-                        let file_line = C_struct(bcx.ccx(), &[filename, line], false);
-                        let align = llalign_of_min(bcx.ccx(), common::val_ty(file_line));
-                        let file_line = consts::addr_of(bcx.ccx(),
+                        let file_line = C_struct(bcx.ccx, &[filename, line], false);
+                        let align = llalign_of_min(bcx.ccx, common::val_ty(file_line));
+                        let file_line = consts::addr_of(bcx.ccx,
                                                         file_line,
                                                         align,
                                                         "panic_bounds_check_loc");
@@ -355,12 +343,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     }
                     mir::AssertMessage::Math(ref err) => {
                         let msg_str = Symbol::intern(err.description()).as_str();
-                        let msg_str = C_str_slice(bcx.ccx(), msg_str);
-                        let msg_file_line = C_struct(bcx.ccx(),
+                        let msg_str = C_str_slice(bcx.ccx, msg_str);
+                        let msg_file_line = C_struct(bcx.ccx,
                                                      &[msg_str, filename, line],
                                                      false);
-                        let align = llalign_of_min(bcx.ccx(), common::val_ty(msg_file_line));
-                        let msg_file_line = consts::addr_of(bcx.ccx(),
+                        let align = llalign_of_min(bcx.ccx, common::val_ty(msg_file_line));
+                        let msg_file_line = consts::addr_of(bcx.ccx,
                                                             msg_file_line,
                                                             align,
                                                             "panic_loc");
@@ -384,15 +372,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
                 // Obtain the panic entry point.
                 let def_id = common::langcall(bcx.tcx(), Some(span), "", lang_item);
-                let callee = Callee::def(bcx.ccx(), def_id,
-                    bcx.ccx().empty_substs_for_def_id(def_id));
-                let llfn = callee.reify(bcx.ccx());
+                let callee = Callee::def(bcx.ccx, def_id,
+                    bcx.ccx.empty_substs_for_def_id(def_id));
+                let llfn = callee.reify(bcx.ccx);
 
                 // Translate the actual panic invoke/call.
                 if let Some(unwind) = cleanup {
                     bcx.invoke(llfn,
                                &args,
-                               self.unreachable_block().llbb,
+                               self.unreachable_block(),
                                llblock(self, unwind),
                                cleanup_bundle);
                 } else {
@@ -411,7 +399,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
                 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)
+                        (Callee::def(bcx.ccx, def_id, substs), f.abi, &f.sig)
                     }
                     ty::TyFnPtr(f) => {
                         (Callee {
@@ -431,7 +419,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     }
                     _ => None
                 };
-                let intrinsic = intrinsic.as_ref().map(|s| &s[..]);
+                let mut intrinsic = intrinsic.as_ref().map(|s| &s[..]);
 
                 if intrinsic == Some("move_val_init") {
                     let &(_, target) = destination.as_ref().unwrap();
@@ -456,9 +444,29 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 let extra_args = &args[sig.inputs().len()..];
                 let extra_args = extra_args.iter().map(|op_arg| {
                     let op_ty = op_arg.ty(&self.mir, bcx.tcx());
-                    bcx.monomorphize(&op_ty)
+                    self.monomorphize(&op_ty)
                 }).collect::<Vec<_>>();
-                let fn_ty = callee.direct_fn_type(bcx.ccx(), &extra_args);
+                let fn_ty = callee.direct_fn_type(bcx.ccx, &extra_args);
+
+                if intrinsic == Some("drop_in_place") {
+                    let &(_, target) = destination.as_ref().unwrap();
+                    let ty = if let ty::TyFnDef(_, substs, _) = callee.ty.sty {
+                        substs.type_at(0)
+                    } else {
+                        bug!("Unexpected ty: {}", callee.ty);
+                    };
+
+                    // Double check for necessity to drop
+                    if !bcx.ccx.shared().type_needs_drop(ty) {
+                        funclet_br(self, bcx, target);
+                        return;
+                    }
+
+                    let drop_fn = glue::get_drop_glue(bcx.ccx, ty);
+                    let llty = fn_ty.llvm_type(bcx.ccx).ptr_to();
+                    callee.data = Fn(bcx.pointercast(drop_fn, llty));
+                    intrinsic = None;
+                }
 
                 // The arguments we'll be passing. Plus one to account for outptr, if used.
                 let arg_count = fn_ty.args.len() + fn_ty.ret.is_indirect() as usize;
@@ -519,7 +527,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 let fn_ptr = match callee.data {
                     NamedTupleConstructor(_) => {
                         // FIXME translate this like mir::Rvalue::Aggregate.
-                        callee.reify(bcx.ccx())
+                        callee.reify(bcx.ccx)
                     }
                     Intrinsic => {
                         use intrinsic::trans_intrinsic_call;
@@ -537,10 +545,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                                 bug!("Cannot use direct operand with an intrinsic call")
                         };
 
-                        bcx.with_block(|bcx| {
-                            trans_intrinsic_call(bcx, callee.ty, &fn_ty,
-                                                 &llargs, dest, debug_loc);
-                        });
+                        trans_intrinsic_call(&bcx, callee.ty, &fn_ty, &llargs, dest,
+                            terminator.source_info.span);
 
                         if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
                             // Make a fake operand for store_return
@@ -554,8 +560,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                         if let Some((_, target)) = *destination {
                             funclet_br(self, bcx, target);
                         } else {
-                            // trans_intrinsic_call already used Unreachable.
-                            // bcx.unreachable();
+                            bcx.unreachable();
                         }
 
                         return;
@@ -573,15 +578,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     };
                     let invokeret = bcx.invoke(fn_ptr,
                                                &llargs,
-                                               ret_bcx.llbb,
+                                               ret_bcx,
                                                llblock(self, cleanup),
                                                cleanup_bundle);
                     fn_ty.apply_attrs_callsite(invokeret);
 
-                    if destination.is_some() {
-                        let ret_bcx = ret_bcx.build();
+                    if let Some((_, target)) = *destination {
+                        let ret_bcx = self.build_block(target);
                         ret_bcx.at_start(|ret_bcx| {
-                            debug_loc.apply_to_bcx(ret_bcx);
+                            self.set_debug_loc(&ret_bcx, terminator.source_info);
                             let op = OperandRef {
                                 val: Immediate(invokeret),
                                 ty: sig.output(),
@@ -608,7 +613,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     }
 
     fn trans_argument(&mut self,
-                      bcx: &BlockAndBuilder<'bcx, 'tcx>,
+                      bcx: &BlockAndBuilder<'a, 'tcx>,
                       op: OperandRef<'tcx>,
                       llargs: &mut Vec<ValueRef>,
                       fn_ty: &FnType,
@@ -616,14 +621,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                       callee: &mut CalleeData) {
         if let Pair(a, b) = op.val {
             // Treat the values in a fat pointer separately.
-            if common::type_is_fat_ptr(bcx.tcx(), op.ty) {
+            if common::type_is_fat_ptr(bcx.ccx, op.ty) {
                 let (ptr, meta) = (a, b);
                 if *next_idx == 0 {
                     if let Virtual(idx) = *callee {
-                        let llfn = bcx.with_block(|bcx| {
-                            meth::get_virtual_method(bcx, meta, idx)
-                        });
-                        let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to();
+                        let llfn = meth::get_virtual_method(bcx, meta, idx);
+                        let llty = fn_ty.llvm_type(bcx.ccx).ptr_to();
                         *callee = Fn(bcx.pointercast(llfn, llty));
                     }
                 }
@@ -655,7 +658,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         let (mut llval, by_ref) = match op.val {
             Immediate(_) | Pair(..) => {
                 if arg.is_indirect() || arg.cast.is_some() {
-                    let llscratch = build::AllocaFcx(bcx.fcx(), arg.original_ty, "arg");
+                    let llscratch = bcx.fcx().alloca(arg.original_ty, "arg");
                     self.store_operand(bcx, llscratch, op);
                     (llscratch, true)
                 } else {
@@ -667,13 +670,13 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
         if by_ref && !arg.is_indirect() {
             // Have to load the argument, maybe while casting it.
-            if arg.original_ty == Type::i1(bcx.ccx()) {
+            if arg.original_ty == Type::i1(bcx.ccx) {
                 // We store bools as i8 so we need to truncate to i1.
                 llval = bcx.load_range_assert(llval, 0, 2, llvm::False);
                 llval = bcx.trunc(llval, arg.original_ty);
             } else if let Some(ty) = arg.cast {
                 llval = bcx.load(bcx.pointercast(llval, ty.ptr_to()));
-                let llalign = llalign_of_min(bcx.ccx(), arg.ty);
+                let llalign = llalign_of_min(bcx.ccx, arg.ty);
                 unsafe {
                     llvm::LLVMSetAlignment(llval, llalign);
                 }
@@ -686,7 +689,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     }
 
     fn trans_arguments_untupled(&mut self,
-                                bcx: &BlockAndBuilder<'bcx, 'tcx>,
+                                bcx: &BlockAndBuilder<'a, 'tcx>,
                                 operand: &mir::Operand<'tcx>,
                                 llargs: &mut Vec<ValueRef>,
                                 fn_ty: &FnType,
@@ -705,9 +708,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             Ref(llval) => {
                 let base = adt::MaybeSizedValue::sized(llval);
                 for (n, &ty) in arg_types.iter().enumerate() {
-                    let ptr = adt::trans_field_ptr_builder(bcx, tuple.ty, base, Disr(0), n);
-                    let val = if common::type_is_fat_ptr(bcx.tcx(), ty) {
-                        let (lldata, llextra) = base::load_fat_ptr_builder(bcx, ptr, ty);
+                    let ptr = adt::trans_field_ptr(bcx, tuple.ty, base, Disr(0), n);
+                    let val = if common::type_is_fat_ptr(bcx.ccx, ty) {
+                        let (lldata, llextra) = base::load_fat_ptr(bcx, ptr, ty);
                         Pair(lldata, llextra)
                     } else {
                         // trans_argument will load this if it needs to
@@ -722,11 +725,17 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
             }
             Immediate(llval) => {
+                let l = bcx.ccx.layout_of(tuple.ty);
+                let v = if let layout::Univariant { ref variant, .. } = *l {
+                    variant
+                } else {
+                    bug!("Not a tuple.");
+                };
                 for (n, &ty) in arg_types.iter().enumerate() {
-                    let mut elem = bcx.extract_value(llval, n);
+                    let mut elem = bcx.extract_value(llval, v.memory_index[n] as usize);
                     // Truncate bools to i1, if needed
-                    if ty.is_bool() && common::val_ty(elem) != Type::i1(bcx.ccx()) {
-                        elem = bcx.trunc(elem, Type::i1(bcx.ccx()));
+                    if ty.is_bool() && common::val_ty(elem) != Type::i1(bcx.ccx) {
+                        elem = bcx.trunc(elem, Type::i1(bcx.ccx));
                     }
                     // If the tuple is immediate, the elements are as well
                     let op = OperandRef {
@@ -741,8 +750,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 for (n, &ty) in arg_types.iter().enumerate() {
                     let mut elem = elems[n];
                     // Truncate bools to i1, if needed
-                    if ty.is_bool() && common::val_ty(elem) != Type::i1(bcx.ccx()) {
-                        elem = bcx.trunc(elem, Type::i1(bcx.ccx()));
+                    if ty.is_bool() && common::val_ty(elem) != Type::i1(bcx.ccx) {
+                        elem = bcx.trunc(elem, Type::i1(bcx.ccx));
                     }
                     // Pair is always made up of immediates
                     let op = OperandRef {
@@ -756,91 +765,61 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
     }
 
-    fn get_personality_slot(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>) -> ValueRef {
-        let ccx = bcx.ccx();
+    fn get_personality_slot(&mut self, bcx: &BlockAndBuilder<'a, 'tcx>) -> ValueRef {
+        let ccx = bcx.ccx;
         if let Some(slot) = self.llpersonalityslot {
             slot
         } else {
             let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false);
-            bcx.with_block(|bcx| {
-                let slot = base::alloca(bcx, llretty, "personalityslot");
-                self.llpersonalityslot = Some(slot);
-                base::call_lifetime_start(bcx, slot);
-                slot
-            })
+            let slot = bcx.fcx().alloca(llretty, "personalityslot");
+            self.llpersonalityslot = Some(slot);
+            Lifetime::Start.call(bcx, slot);
+            slot
         }
     }
 
     /// Return the landingpad wrapper around the given basic block
     ///
     /// No-op in MSVC SEH scheme.
-    fn landing_pad_to(&mut self, target_bb: mir::BasicBlock) -> Block<'bcx, 'tcx>
-    {
+    fn landing_pad_to(&mut self, target_bb: mir::BasicBlock) -> BasicBlockRef {
         if let Some(block) = self.landing_pads[target_bb] {
             return block;
         }
 
-        if base::wants_msvc_seh(self.fcx.ccx.sess()) {
+        if base::wants_msvc_seh(self.ccx.sess()) {
             return self.blocks[target_bb];
         }
 
-        let target = self.bcx(target_bb);
+        let target = self.build_block(target_bb);
 
-        let block = self.fcx.new_block("cleanup");
-        self.landing_pads[target_bb] = Some(block);
+        let bcx = self.fcx.build_new_block("cleanup");
+        self.landing_pads[target_bb] = Some(bcx.llbb());
 
-        let bcx = block.build();
-        let ccx = bcx.ccx();
-        let llpersonality = self.fcx.eh_personality();
+        let ccx = bcx.ccx;
+        let llpersonality = self.ccx.eh_personality();
         let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false);
         let llretval = bcx.landing_pad(llretty, llpersonality, 1, self.fcx.llfn);
         bcx.set_cleanup(llretval);
         let slot = self.get_personality_slot(&bcx);
         bcx.store(llretval, slot);
         bcx.br(target.llbb());
-        block
-    }
-
-    pub fn init_cpad(&mut self, bb: mir::BasicBlock) {
-        let bcx = self.bcx(bb);
-        let data = &self.mir[bb];
-        debug!("init_cpad({:?})", data);
-
-        match self.cleanup_kinds[bb] {
-            CleanupKind::NotCleanup => {
-                bcx.set_lpad(None)
-            }
-            _ if !base::wants_msvc_seh(bcx.sess()) => {
-                bcx.set_lpad(Some(LandingPad::gnu()))
-            }
-            CleanupKind::Internal { funclet } => {
-                // FIXME: is this needed?
-                bcx.set_personality_fn(self.fcx.eh_personality());
-                bcx.set_lpad_ref(self.bcx(funclet).lpad());
-            }
-            CleanupKind::Funclet => {
-                bcx.set_personality_fn(self.fcx.eh_personality());
-                DebugLoc::None.apply_to_bcx(&bcx);
-                let cleanup_pad = bcx.cleanup_pad(None, &[]);
-                bcx.set_lpad(Some(LandingPad::msvc(cleanup_pad)));
-            }
-        };
+        bcx.llbb()
     }
 
-    fn unreachable_block(&mut self) -> Block<'bcx, 'tcx> {
+    fn unreachable_block(&mut self) -> BasicBlockRef {
         self.unreachable_block.unwrap_or_else(|| {
-            let bl = self.fcx.new_block("unreachable");
-            bl.build().unreachable();
-            self.unreachable_block = Some(bl);
-            bl
+            let bl = self.fcx.build_new_block("unreachable");
+            bl.unreachable();
+            self.unreachable_block = Some(bl.llbb());
+            bl.llbb()
         })
     }
 
-    fn bcx(&self, bb: mir::BasicBlock) -> BlockAndBuilder<'bcx, 'tcx> {
-        self.blocks[bb].build()
+    pub fn build_block(&self, bb: mir::BasicBlock) -> BlockAndBuilder<'a, 'tcx> {
+        BlockAndBuilder::new(self.blocks[bb], self.fcx)
     }
 
-    fn make_return_dest(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>,
+    fn make_return_dest(&mut self, bcx: &BlockAndBuilder<'a, 'tcx>,
                         dest: &mir::Lvalue<'tcx>, fn_ret_ty: &ArgType,
                         llargs: &mut Vec<ValueRef>, is_intrinsic: bool) -> ReturnDest {
         // If the return is ignored, we can just return a do-nothing ReturnDest
@@ -857,18 +836,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     return if fn_ret_ty.is_indirect() {
                         // Odd, but possible, case, we have an operand temporary,
                         // but the calling convention has an indirect return.
-                        let tmp = bcx.with_block(|bcx| {
-                            base::alloc_ty(bcx, ret_ty, "tmp_ret")
-                        });
+                        let tmp = base::alloc_ty(bcx, ret_ty, "tmp_ret");
                         llargs.push(tmp);
                         ReturnDest::IndirectOperand(tmp, index)
                     } else if is_intrinsic {
                         // Currently, intrinsics always need a location to store
                         // the result. so we create a temporary alloca for the
                         // result
-                        let tmp = bcx.with_block(|bcx| {
-                            base::alloc_ty(bcx, ret_ty, "tmp_ret")
-                        });
+                        let tmp = base::alloc_ty(bcx, ret_ty, "tmp_ret");
                         ReturnDest::IndirectOperand(tmp, index)
                     } else {
                         ReturnDest::DirectOperand(index)
@@ -889,27 +864,27 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         }
     }
 
-    fn trans_transmute(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>,
+    fn trans_transmute(&mut self, bcx: &BlockAndBuilder<'a, 'tcx>,
                        src: &mir::Operand<'tcx>, dst: LvalueRef<'tcx>) {
         let mut val = self.trans_operand(bcx, src);
         if let ty::TyFnDef(def_id, substs, _) = val.ty.sty {
-            let llouttype = type_of::type_of(bcx.ccx(), dst.ty.to_ty(bcx.tcx()));
-            let out_type_size = llbitsize_of_real(bcx.ccx(), llouttype);
+            let llouttype = type_of::type_of(bcx.ccx, dst.ty.to_ty(bcx.tcx()));
+            let out_type_size = llbitsize_of_real(bcx.ccx, llouttype);
             if out_type_size != 0 {
                 // FIXME #19925 Remove this hack after a release cycle.
-                let f = Callee::def(bcx.ccx(), def_id, substs);
+                let f = Callee::def(bcx.ccx, def_id, substs);
                 let ty = match f.ty.sty {
                     ty::TyFnDef(.., f) => bcx.tcx().mk_fn_ptr(f),
                     _ => f.ty
                 };
                 val = OperandRef {
-                    val: Immediate(f.reify(bcx.ccx())),
+                    val: Immediate(f.reify(bcx.ccx)),
                     ty: ty
                 };
             }
         }
 
-        let llty = type_of::type_of(bcx.ccx(), val.ty);
+        let llty = type_of::type_of(bcx.ccx, val.ty);
         let cast_ptr = bcx.pointercast(dst.llval, llty.ptr_to());
         self.store_operand(bcx, cast_ptr, val);
     }
@@ -917,7 +892,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
     // Stores the return value of a function call into it's final location.
     fn store_return(&mut self,
-                    bcx: &BlockAndBuilder<'bcx, 'tcx>,
+                    bcx: &BlockAndBuilder<'a, 'tcx>,
                     dest: ReturnDest,
                     ret_ty: ArgType,
                     op: OperandRef<'tcx>) {
@@ -933,9 +908,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             DirectOperand(index) => {
                 // If there is a cast, we have to store and reload.
                 let op = if ret_ty.cast.is_some() {
-                    let tmp = bcx.with_block(|bcx| {
-                        base::alloc_ty(bcx, op.ty, "tmp_ret")
-                    });
+                    let tmp = base::alloc_ty(bcx, op.ty, "tmp_ret");
                     ret_ty.store(bcx, op.immediate(), tmp);
                     self.trans_load(bcx, tmp, op.ty)
                 } else {
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index bca81fa3645..08f68f8d49c 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -25,7 +25,7 @@ use rustc::ty::subst::Substs;
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use {abi, adt, base, Disr, machine};
 use callee::Callee;
-use common::{self, BlockAndBuilder, CrateContext, const_get_elt, val_ty, type_is_sized};
+use common::{self, BlockAndBuilder, CrateContext, const_get_elt, val_ty};
 use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral};
 use common::{C_null, C_struct, C_str_slice, C_undef, C_uint};
 use common::{const_to_opt_int, const_to_opt_uint};
@@ -401,7 +401,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                     .projection_ty(tcx, &projection.elem);
                 let base = tr_base.to_const(span);
                 let projected_ty = self.monomorphize(&projected_ty).to_ty(tcx);
-                let is_sized = common::type_is_sized(tcx, projected_ty);
+                let is_sized = self.ccx.shared().type_is_sized(projected_ty);
 
                 let (projected, llextra) = match projection.elem {
                     mir::ProjectionElem::Deref => {
@@ -598,11 +598,11 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                     mir::CastKind::Unsize => {
                         // unsize targets other than to a fat pointer currently
                         // can't be in constants.
-                        assert!(common::type_is_fat_ptr(tcx, cast_ty));
+                        assert!(common::type_is_fat_ptr(self.ccx, cast_ty));
 
                         let pointee_ty = operand.ty.builtin_deref(true, ty::NoPreference)
                             .expect("consts: unsizing got non-pointer type").ty;
-                        let (base, old_info) = if !common::type_is_sized(tcx, pointee_ty) {
+                        let (base, old_info) = if !self.ccx.shared().type_is_sized(pointee_ty) {
                             // Normally, the source is a thin pointer and we are
                             // adding extra info to make a fat pointer. The exception
                             // is when we are upcasting an existing object fat pointer
@@ -685,9 +685,9 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                     mir::CastKind::Misc => { // Casts from a fat-ptr.
                         let ll_cast_ty = type_of::immediate_type_of(self.ccx, cast_ty);
                         let ll_from_ty = type_of::immediate_type_of(self.ccx, operand.ty);
-                        if common::type_is_fat_ptr(tcx, operand.ty) {
+                        if common::type_is_fat_ptr(self.ccx, operand.ty) {
                             let (data_ptr, meta_ptr) = operand.get_fat_ptr();
-                            if common::type_is_fat_ptr(tcx, cast_ty) {
+                            if common::type_is_fat_ptr(self.ccx, cast_ty) {
                                 let ll_cft = ll_cast_ty.field_types();
                                 let ll_fft = ll_from_ty.field_types();
                                 let data_cast = consts::ptrcast(data_ptr, ll_cft[0]);
@@ -716,7 +716,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                 let base = match tr_lvalue.base {
                     Base::Value(llval) => {
                         // FIXME: may be wrong for &*(&simd_vec as &fmt::Debug)
-                        let align = if type_is_sized(self.ccx.tcx(), ty) {
+                        let align = if self.ccx.shared().type_is_sized(ty) {
                             type_of::align_of(self.ccx, ty)
                         } else {
                             self.ccx.tcx().data_layout.pointer_align.abi() as machine::llalign
@@ -731,7 +731,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                     Base::Static(llval) => llval
                 };
 
-                let ptr = if common::type_is_sized(tcx, ty) {
+                let ptr = if self.ccx.shared().type_is_sized(ty) {
                     base
                 } else {
                     C_struct(self.ccx, &[base, tr_lvalue.llextra], false)
@@ -945,40 +945,39 @@ pub fn const_scalar_checked_binop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
-impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
+impl<'a, 'tcx> MirContext<'a, 'tcx> {
     pub fn trans_constant(&mut self,
-                          bcx: &BlockAndBuilder<'bcx, 'tcx>,
+                          bcx: &BlockAndBuilder<'a, 'tcx>,
                           constant: &mir::Constant<'tcx>)
                           -> Const<'tcx>
     {
         debug!("trans_constant({:?})", constant);
-        let ty = bcx.monomorphize(&constant.ty);
+        let ty = self.monomorphize(&constant.ty);
         let result = match constant.literal.clone() {
             mir::Literal::Item { def_id, substs } => {
                 // Shortcut for zero-sized types, including function item
                 // types, which would not work with MirConstContext.
-                if common::type_is_zero_size(bcx.ccx(), ty) {
-                    let llty = type_of::type_of(bcx.ccx(), ty);
+                if common::type_is_zero_size(bcx.ccx, ty) {
+                    let llty = type_of::type_of(bcx.ccx, ty);
                     return Const::new(C_null(llty), ty);
                 }
 
-                let substs = bcx.monomorphize(&substs);
+                let substs = self.monomorphize(&substs);
                 let instance = Instance::new(def_id, substs);
-                MirConstContext::trans_def(bcx.ccx(), instance, IndexVec::new())
+                MirConstContext::trans_def(bcx.ccx, instance, IndexVec::new())
             }
             mir::Literal::Promoted { index } => {
                 let mir = &self.mir.promoted[index];
-                MirConstContext::new(bcx.ccx(), mir, bcx.fcx().param_substs,
-                                     IndexVec::new()).trans()
+                MirConstContext::new(bcx.ccx, mir, self.param_substs, IndexVec::new()).trans()
             }
             mir::Literal::Value { value } => {
-                Ok(Const::from_constval(bcx.ccx(), value, ty))
+                Ok(Const::from_constval(bcx.ccx, value, ty))
             }
         };
 
         let result = result.unwrap_or_else(|_| {
             // We've errored, so we don't have to produce working code.
-            let llty = type_of::type_of(bcx.ccx(), ty);
+            let llty = type_of::type_of(bcx.ccx, ty);
             Const::new(C_undef(llty), ty)
         });
 
diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs
index d28c466e230..0cd7f007c5d 100644
--- a/src/librustc_trans/mir/lvalue.rs
+++ b/src/librustc_trans/mir/lvalue.rs
@@ -44,13 +44,13 @@ impl<'tcx> LvalueRef<'tcx> {
         LvalueRef { llval: llval, llextra: ptr::null_mut(), ty: lvalue_ty }
     }
 
-    pub fn alloca<'bcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
+    pub fn alloca<'a>(bcx: &BlockAndBuilder<'a, 'tcx>,
                         ty: Ty<'tcx>,
                         name: &str)
                         -> LvalueRef<'tcx>
     {
         assert!(!ty.has_erasable_regions());
-        let lltemp = bcx.with_block(|bcx| base::alloc_ty(bcx, ty, name));
+        let lltemp = base::alloc_ty(bcx, ty, name);
         LvalueRef::new_sized(lltemp, LvalueTy::from_ty(ty))
     }
 
@@ -67,14 +67,14 @@ impl<'tcx> LvalueRef<'tcx> {
     }
 }
 
-impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
+impl<'a, 'tcx> MirContext<'a, 'tcx> {
     pub fn trans_lvalue(&mut self,
-                        bcx: &BlockAndBuilder<'bcx, 'tcx>,
+                        bcx: &BlockAndBuilder<'a, 'tcx>,
                         lvalue: &mir::Lvalue<'tcx>)
                         -> LvalueRef<'tcx> {
         debug!("trans_lvalue(lvalue={:?})", lvalue);
 
-        let ccx = bcx.ccx();
+        let ccx = bcx.ccx;
         let tcx = bcx.tcx();
 
         if let mir::Lvalue::Local(index) = *lvalue {
@@ -103,7 +103,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 let ptr = self.trans_consume(bcx, base);
                 let projected_ty = LvalueTy::from_ty(ptr.ty)
                     .projection_ty(tcx, &mir::ProjectionElem::Deref);
-                let projected_ty = bcx.monomorphize(&projected_ty);
+                let projected_ty = self.monomorphize(&projected_ty);
                 let (llptr, llextra) = match ptr.val {
                     OperandValue::Immediate(llptr) => (llptr, ptr::null_mut()),
                     OperandValue::Pair(llptr, llextra) => (llptr, llextra),
@@ -118,14 +118,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             mir::Lvalue::Projection(ref projection) => {
                 let tr_base = self.trans_lvalue(bcx, &projection.base);
                 let projected_ty = tr_base.ty.projection_ty(tcx, &projection.elem);
-                let projected_ty = bcx.monomorphize(&projected_ty);
+                let projected_ty = self.monomorphize(&projected_ty);
 
                 let project_index = |llindex| {
                     let element = if let ty::TySlice(_) = tr_base.ty.to_ty(tcx).sty {
                         // Slices already point to the array element type.
                         bcx.inbounds_gep(tr_base.llval, &[llindex])
                     } else {
-                        let zero = common::C_uint(bcx.ccx(), 0u64);
+                        let zero = common::C_uint(bcx.ccx, 0u64);
                         bcx.inbounds_gep(tr_base.llval, &[zero, llindex])
                     };
                     element
@@ -140,14 +140,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                             LvalueTy::Downcast { adt_def: _, substs: _, variant_index: v } => v,
                         };
                         let discr = discr as u64;
-                        let is_sized = common::type_is_sized(tcx, projected_ty.to_ty(tcx));
+                        let is_sized = self.ccx.shared().type_is_sized(projected_ty.to_ty(tcx));
                         let base = if is_sized {
                             adt::MaybeSizedValue::sized(tr_base.llval)
                         } else {
                             adt::MaybeSizedValue::unsized_(tr_base.llval, tr_base.llextra)
                         };
-                        let llprojected = adt::trans_field_ptr_builder(bcx, base_ty, base,
-                                                                       Disr(discr), field.index());
+                        let llprojected = adt::trans_field_ptr(bcx, base_ty, base, Disr(discr),
+                            field.index());
                         let llextra = if is_sized {
                             ptr::null_mut()
                         } else {
@@ -162,19 +162,19 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     mir::ProjectionElem::ConstantIndex { offset,
                                                          from_end: false,
                                                          min_length: _ } => {
-                        let lloffset = C_uint(bcx.ccx(), offset);
+                        let lloffset = C_uint(bcx.ccx, offset);
                         (project_index(lloffset), ptr::null_mut())
                     }
                     mir::ProjectionElem::ConstantIndex { offset,
                                                          from_end: true,
                                                          min_length: _ } => {
-                        let lloffset = C_uint(bcx.ccx(), offset);
-                        let lllen = tr_base.len(bcx.ccx());
+                        let lloffset = C_uint(bcx.ccx, offset);
+                        let lllen = tr_base.len(bcx.ccx);
                         let llindex = bcx.sub(lllen, lloffset);
                         (project_index(llindex), ptr::null_mut())
                     }
                     mir::ProjectionElem::Subslice { from, to } => {
-                        let llindex = C_uint(bcx.ccx(), from);
+                        let llindex = C_uint(bcx.ccx, from);
                         let llbase = project_index(llindex);
 
                         let base_ty = tr_base.ty.to_ty(bcx.tcx());
@@ -183,14 +183,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                                 // must cast the lvalue pointer type to the new
                                 // array type (*[%_; new_len]).
                                 let base_ty = self.monomorphized_lvalue_ty(lvalue);
-                                let llbasety = type_of::type_of(bcx.ccx(), base_ty).ptr_to();
+                                let llbasety = type_of::type_of(bcx.ccx, base_ty).ptr_to();
                                 let llbase = bcx.pointercast(llbase, llbasety);
                                 (llbase, ptr::null_mut())
                             }
                             ty::TySlice(..) => {
                                 assert!(tr_base.llextra != ptr::null_mut());
                                 let lllen = bcx.sub(tr_base.llextra,
-                                                    C_uint(bcx.ccx(), from+to));
+                                                    C_uint(bcx.ccx, from+to));
                                 (llbase, lllen)
                             }
                             _ => bug!("unexpected type {:?} in Subslice", base_ty)
@@ -214,7 +214,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     // Perform an action using the given Lvalue.
     // If the Lvalue is an empty LocalRef::Operand, then a temporary stack slot
     // is created first, then used as an operand to update the Lvalue.
-    pub fn with_lvalue_ref<F, U>(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>,
+    pub fn with_lvalue_ref<F, U>(&mut self, bcx: &BlockAndBuilder<'a, 'tcx>,
                                  lvalue: &mir::Lvalue<'tcx>, f: F) -> U
     where F: FnOnce(&mut Self, LvalueRef<'tcx>) -> U
     {
@@ -235,9 +235,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     // See comments in LocalRef::new_operand as to why
                     // we always have Some in a ZST LocalRef::Operand.
                     let ty = self.monomorphized_lvalue_ty(lvalue);
-                    if common::type_is_zero_size(bcx.ccx(), ty) {
+                    if common::type_is_zero_size(bcx.ccx, ty) {
                         // Pass an undef pointer as no stores can actually occur.
-                        let llptr = C_undef(type_of(bcx.ccx(), ty).ptr_to());
+                        let llptr = C_undef(type_of(bcx.ccx, ty).ptr_to());
                         f(self, LvalueRef::new_sized(llptr, LvalueTy::from_ty(ty)))
                     } else {
                         bug!("Lvalue local already set");
@@ -255,13 +255,13 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     ///
     /// nmatsakis: is this still necessary? Not sure.
     fn prepare_index(&mut self,
-                     bcx: &BlockAndBuilder<'bcx, 'tcx>,
+                     bcx: &BlockAndBuilder<'a, 'tcx>,
                      llindex: ValueRef)
                      -> ValueRef
     {
-        let ccx = bcx.ccx();
-        let index_size = machine::llbitsize_of_real(bcx.ccx(), common::val_ty(llindex));
-        let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type());
+        let ccx = bcx.ccx;
+        let index_size = machine::llbitsize_of_real(bcx.ccx, common::val_ty(llindex));
+        let int_size = machine::llbitsize_of_real(bcx.ccx, ccx.int_type());
         if index_size < int_size {
             bcx.zext(llindex, ccx.int_type())
         } else if index_size > int_size {
@@ -272,8 +272,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     }
 
     pub fn monomorphized_lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
-        let tcx = self.fcx.ccx.tcx();
+        let tcx = self.ccx.tcx();
         let lvalue_ty = lvalue.ty(&self.mir, tcx);
-        self.fcx.monomorphize(&lvalue_ty.to_ty(tcx))
+        self.monomorphize(&lvalue_ty.to_ty(tcx))
     }
 }
diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs
index 12cbfcef7d2..7a50e5cbe8c 100644
--- a/src/librustc_trans/mir/mod.rs
+++ b/src/librustc_trans/mir/mod.rs
@@ -9,41 +9,50 @@
 // except according to those terms.
 
 use libc::c_uint;
-use llvm::{self, ValueRef};
-use rustc::ty;
-use rustc::mir;
+use llvm::{self, ValueRef, BasicBlockRef};
+use llvm::debuginfo::DIScope;
+use rustc::ty::{self, layout};
+use rustc::mir::{self, Mir};
 use rustc::mir::tcx::LvalueTy;
+use rustc::ty::subst::Substs;
+use rustc::infer::TransNormalize;
+use rustc::ty::TypeFoldable;
 use session::config::FullDebugInfo;
 use base;
-use common::{self, Block, BlockAndBuilder, CrateContext, FunctionContext, C_null};
-use debuginfo::{self, declare_local, DebugLoc, VariableAccess, VariableKind, FunctionDebugContext};
-use machine;
+use common::{self, BlockAndBuilder, CrateContext, FunctionContext, C_null, Funclet};
+use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext};
+use monomorphize::{self, Instance};
+use abi::FnType;
 use type_of;
 
-use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos};
+use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, Span};
 use syntax::symbol::keywords;
+use syntax::abi::Abi;
 
-use std::cell::Ref;
 use std::iter;
 
-use basic_block::BasicBlock;
-
 use rustc_data_structures::bitvec::BitVector;
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 
 pub use self::constant::trans_static_initializer;
 
+use self::analyze::CleanupKind;
 use self::lvalue::{LvalueRef};
 use rustc::mir::traversal;
 
 use self::operand::{OperandRef, OperandValue};
 
 /// Master context for translating MIR.
-pub struct MirContext<'bcx, 'tcx:'bcx> {
-    mir: Ref<'tcx, mir::Mir<'tcx>>,
+pub struct MirContext<'a, 'tcx:'a> {
+    mir: &'a mir::Mir<'tcx>,
+
+    debug_context: debuginfo::FunctionDebugContext,
+
+    fcx: &'a common::FunctionContext<'a, 'tcx>,
 
-    /// Function context
-    fcx: &'bcx common::FunctionContext<'bcx, 'tcx>,
+    ccx: &'a CrateContext<'a, 'tcx>,
+
+    fn_ty: FnType,
 
     /// When unwinding is initiated, we have to store this personality
     /// value somewhere so that we can load it and re-use it in the
@@ -55,17 +64,17 @@ pub struct MirContext<'bcx, 'tcx:'bcx> {
     llpersonalityslot: Option<ValueRef>,
 
     /// A `Block` for each MIR `BasicBlock`
-    blocks: IndexVec<mir::BasicBlock, Block<'bcx, 'tcx>>,
+    blocks: IndexVec<mir::BasicBlock, BasicBlockRef>,
 
     /// The funclet status of each basic block
     cleanup_kinds: IndexVec<mir::BasicBlock, analyze::CleanupKind>,
 
     /// This stores the landing-pad block for a given BB, computed lazily on GNU
     /// and eagerly on MSVC.
-    landing_pads: IndexVec<mir::BasicBlock, Option<Block<'bcx, 'tcx>>>,
+    landing_pads: IndexVec<mir::BasicBlock, Option<BasicBlockRef>>,
 
     /// Cached unreachable block
-    unreachable_block: Option<Block<'bcx, 'tcx>>,
+    unreachable_block: Option<BasicBlockRef>,
 
     /// The location where each MIR arg/var/tmp/ret is stored. This is
     /// usually an `LvalueRef` representing an alloca, but not always:
@@ -86,18 +95,28 @@ pub struct MirContext<'bcx, 'tcx:'bcx> {
 
     /// Debug information for MIR scopes.
     scopes: IndexVec<mir::VisibilityScope, debuginfo::MirDebugScope>,
+
+    /// If this function is being monomorphized, this contains the type substitutions used.
+    param_substs: &'tcx Substs<'tcx>,
 }
 
-impl<'blk, 'tcx> MirContext<'blk, 'tcx> {
-    pub fn debug_loc(&mut self, source_info: mir::SourceInfo) -> DebugLoc {
+impl<'a, 'tcx> MirContext<'a, 'tcx> {
+    pub fn monomorphize<T>(&self, value: &T) -> T
+        where T: TransNormalize<'tcx> {
+        monomorphize::apply_param_substs(self.ccx.shared(), self.param_substs, value)
+    }
+
+    pub fn set_debug_loc(&mut self, bcx: &BlockAndBuilder, source_info: mir::SourceInfo) {
+        let (scope, span) = self.debug_loc(source_info);
+        debuginfo::set_source_location(&self.debug_context, bcx, scope, span);
+    }
+
+    pub fn debug_loc(&mut self, source_info: mir::SourceInfo) -> (DIScope, Span) {
         // Bail out if debug info emission is not enabled.
-        match self.fcx.debug_context {
+        match self.debug_context {
             FunctionDebugContext::DebugInfoDisabled |
             FunctionDebugContext::FunctionWithoutDebugInfo => {
-                // Can't return DebugLoc::None here because intrinsic::trans_intrinsic_call()
-                // relies on debug location to obtain span of the call site.
-                return DebugLoc::ScopeAt(self.scopes[source_info.scope].scope_metadata,
-                                         source_info.span);
+                return (self.scopes[source_info.scope].scope_metadata, source_info.span);
             }
             FunctionDebugContext::RegularContext(_) =>{}
         }
@@ -107,13 +126,12 @@ impl<'blk, 'tcx> MirContext<'blk, 'tcx> {
         // (unless the crate is being compiled with `-Z debug-macros`).
         if source_info.span.expn_id == NO_EXPANSION ||
             source_info.span.expn_id == COMMAND_LINE_EXPN ||
-            self.fcx.ccx.sess().opts.debugging_opts.debug_macros {
+            self.ccx.sess().opts.debugging_opts.debug_macros {
 
-            let scope_metadata = self.scope_metadata_for_loc(source_info.scope,
-                                                             source_info.span.lo);
-            DebugLoc::ScopeAt(scope_metadata, source_info.span)
+            let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo);
+            (scope, source_info.span)
         } else {
-            let cm = self.fcx.ccx.sess().codemap();
+            let cm = self.ccx.sess().codemap();
             // Walk up the macro expansion chain until we reach a non-expanded span.
             let mut span = source_info.span;
             while span.expn_id != NO_EXPANSION && span.expn_id != COMMAND_LINE_EXPN {
@@ -124,9 +142,9 @@ impl<'blk, 'tcx> MirContext<'blk, 'tcx> {
                     break;
                 }
             }
-            let scope_metadata = self.scope_metadata_for_loc(source_info.scope, span.lo);
+            let scope = self.scope_metadata_for_loc(source_info.scope, span.lo);
             // Use span of the outermost call site, while keeping the original lexical scope
-            DebugLoc::ScopeAt(scope_metadata, span)
+            (scope, span)
         }
     }
 
@@ -139,10 +157,8 @@ impl<'blk, 'tcx> MirContext<'blk, 'tcx> {
         let scope_metadata = self.scopes[scope_id].scope_metadata;
         if pos < self.scopes[scope_id].file_start_pos ||
            pos >= self.scopes[scope_id].file_end_pos {
-            let cm = self.fcx.ccx.sess().codemap();
-            debuginfo::extend_scope_to_file(self.fcx.ccx,
-                                            scope_metadata,
-                                            &cm.lookup_char_pos(pos).file)
+            let cm = self.ccx.sess().codemap();
+            debuginfo::extend_scope_to_file(self.ccx, scope_metadata, &cm.lookup_char_pos(pos).file)
         } else {
             scope_metadata
         }
@@ -155,7 +171,7 @@ enum LocalRef<'tcx> {
 }
 
 impl<'tcx> LocalRef<'tcx> {
-    fn new_operand<'bcx>(ccx: &CrateContext<'bcx, 'tcx>,
+    fn new_operand<'a>(ccx: &CrateContext<'a, 'tcx>,
                          ty: ty::Ty<'tcx>) -> LocalRef<'tcx> {
         if common::type_is_zero_size(ccx, ty) {
             // Zero-size temporaries aren't always initialized, which
@@ -181,19 +197,22 @@ impl<'tcx> LocalRef<'tcx> {
 
 ///////////////////////////////////////////////////////////////////////////
 
-pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
-    let bcx = fcx.init(true).build();
-    let mir = bcx.mir();
+pub fn trans_mir<'a, 'tcx: 'a>(
+    fcx: &'a FunctionContext<'a, 'tcx>,
+    fn_ty: FnType,
+    mir: &'a Mir<'tcx>,
+    instance: Instance<'tcx>,
+    sig: &ty::FnSig<'tcx>,
+    abi: Abi,
+) {
+    let debug_context =
+        debuginfo::create_function_debug_context(fcx.ccx, instance, sig, abi, fcx.llfn, mir);
+    let bcx = fcx.get_entry_block();
 
-    // Analyze the temps to determine which must be lvalues
-    // FIXME
-    let (lvalue_locals, cleanup_kinds) = bcx.with_block(|bcx| {
-        (analyze::lvalue_locals(bcx, &mir),
-         analyze::cleanup_kinds(bcx, &mir))
-    });
+    let cleanup_kinds = analyze::cleanup_kinds(&mir);
 
     // Allocate a `Block` for every basic block
-    let block_bcxs: IndexVec<mir::BasicBlock, Block<'blk,'tcx>> =
+    let block_bcxs: IndexVec<mir::BasicBlock, BasicBlockRef> =
         mir.basic_blocks().indices().map(|bb| {
             if bb == mir::START_BLOCK {
                 fcx.new_block("start")
@@ -203,11 +222,13 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
         }).collect();
 
     // Compute debuginfo scopes from MIR scopes.
-    let scopes = debuginfo::create_mir_scopes(fcx);
+    let scopes = debuginfo::create_mir_scopes(fcx, mir, &debug_context);
 
     let mut mircx = MirContext {
-        mir: Ref::clone(&mir),
+        mir: mir,
         fcx: fcx,
+        fn_ty: fn_ty,
+        ccx: fcx.ccx,
         llpersonalityslot: None,
         blocks: block_bcxs,
         unreachable_block: None,
@@ -215,15 +236,22 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
         landing_pads: IndexVec::from_elem(None, mir.basic_blocks()),
         scopes: scopes,
         locals: IndexVec::new(),
+        debug_context: debug_context,
+        param_substs: {
+            assert!(!instance.substs.needs_infer());
+            instance.substs
+        },
     };
 
+    let lvalue_locals = analyze::lvalue_locals(&mircx);
+
     // Allocate variable and temp allocas
     mircx.locals = {
-        let args = arg_local_refs(&bcx, &mir, &mircx.scopes, &lvalue_locals);
+        let args = arg_local_refs(&bcx, &mircx, &mircx.scopes, &lvalue_locals);
 
         let mut allocate_local = |local| {
             let decl = &mir.local_decls[local];
-            let ty = bcx.monomorphize(&decl.ty);
+            let ty = mircx.monomorphize(&decl.ty);
 
             if let Some(name) = decl.name {
                 // User variable
@@ -233,27 +261,21 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
 
                 if !lvalue_locals.contains(local.index()) && !dbg {
                     debug!("alloc: {:?} ({}) -> operand", local, name);
-                    return LocalRef::new_operand(bcx.ccx(), ty);
+                    return LocalRef::new_operand(bcx.ccx, ty);
                 }
 
                 debug!("alloc: {:?} ({}) -> lvalue", local, name);
                 let lvalue = LvalueRef::alloca(&bcx, ty, &name.as_str());
                 if dbg {
-                    let dbg_loc = mircx.debug_loc(source_info);
-                    if let DebugLoc::ScopeAt(scope, span) = dbg_loc {
-                        bcx.with_block(|bcx| {
-                            declare_local(bcx, name, ty, scope,
-                                        VariableAccess::DirectVariable { alloca: lvalue.llval },
-                                        VariableKind::LocalVariable, span);
-                        });
-                    } else {
-                        panic!("Unexpected");
-                    }
+                    let (scope, span) = mircx.debug_loc(source_info);
+                    declare_local(&bcx, &mircx.debug_context, name, ty, scope,
+                        VariableAccess::DirectVariable { alloca: lvalue.llval },
+                        VariableKind::LocalVariable, span);
                 }
                 LocalRef::Lvalue(lvalue)
             } else {
                 // Temporary or return pointer
-                if local == mir::RETURN_POINTER && fcx.fn_ty.ret.is_indirect() {
+                if local == mir::RETURN_POINTER && mircx.fn_ty.ret.is_indirect() {
                     debug!("alloc: {:?} (return pointer) -> lvalue", local);
                     let llretptr = llvm::get_param(fcx.llfn, 0);
                     LocalRef::Lvalue(LvalueRef::new_sized(llretptr, LvalueTy::from_ty(ty)))
@@ -265,7 +287,7 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
                     // alloca in advance. Instead we wait until we see the
                     // definition and update the operand there.
                     debug!("alloc: {:?} -> operand", local);
-                    LocalRef::new_operand(bcx.ccx(), ty)
+                    LocalRef::new_operand(bcx.ccx, ty)
                 }
             }
         };
@@ -279,57 +301,61 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
 
     // Branch to the START block
     let start_bcx = mircx.blocks[mir::START_BLOCK];
-    bcx.br(start_bcx.llbb);
+    bcx.br(start_bcx);
 
     // Up until here, IR instructions for this function have explicitly not been annotated with
     // source code location, so we don't step into call setup code. From here on, source location
     // emitting should be enabled.
-    debuginfo::start_emitting_source_locations(fcx);
-
-    let mut visited = BitVector::new(mir.basic_blocks().len());
+    debuginfo::start_emitting_source_locations(&mircx.debug_context);
+
+    let funclets: IndexVec<mir::BasicBlock, Option<Funclet>> =
+    mircx.cleanup_kinds.iter_enumerated().map(|(bb, cleanup_kind)| {
+        if let CleanupKind::Funclet = *cleanup_kind {
+            let bcx = mircx.build_block(bb);
+            bcx.set_personality_fn(mircx.ccx.eh_personality());
+            if base::wants_msvc_seh(fcx.ccx.sess()) {
+                return Some(Funclet::new(bcx.cleanup_pad(None, &[])));
+            }
+        }
 
-    let mut rpo = traversal::reverse_postorder(&mir);
+        None
+    }).collect();
 
-    // Prepare each block for translation.
-    for (bb, _) in rpo.by_ref() {
-        mircx.init_cpad(bb);
-    }
-    rpo.reset();
+    let rpo = traversal::reverse_postorder(&mir);
+    let mut visited = BitVector::new(mir.basic_blocks().len());
 
     // Translate the body of each block using reverse postorder
     for (bb, _) in rpo {
         visited.insert(bb.index());
-        mircx.trans_block(bb);
+        mircx.trans_block(bb, &funclets);
     }
 
     // Remove blocks that haven't been visited, or have no
     // predecessors.
     for bb in mir.basic_blocks().indices() {
-        let block = mircx.blocks[bb];
-        let block = BasicBlock(block.llbb);
         // Unreachable block
         if !visited.contains(bb.index()) {
             debug!("trans_mir: block {:?} was not visited", bb);
-            block.delete();
+            unsafe {
+                llvm::LLVMDeleteBasicBlock(mircx.blocks[bb]);
+            }
         }
     }
-
-    DebugLoc::None.apply(fcx);
-    fcx.cleanup();
 }
 
 /// Produce, for each argument, a `ValueRef` pointing at the
 /// argument's value. As arguments are lvalues, these are always
 /// indirect.
-fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
-                              mir: &mir::Mir<'tcx>,
-                              scopes: &IndexVec<mir::VisibilityScope, debuginfo::MirDebugScope>,
-                              lvalue_locals: &BitVector)
-                              -> Vec<LocalRef<'tcx>> {
+fn arg_local_refs<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+                            mircx: &MirContext<'a, 'tcx>,
+                            scopes: &IndexVec<mir::VisibilityScope, debuginfo::MirDebugScope>,
+                            lvalue_locals: &BitVector)
+                            -> Vec<LocalRef<'tcx>> {
+    let mir = mircx.mir;
     let fcx = bcx.fcx();
     let tcx = bcx.tcx();
     let mut idx = 0;
-    let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize;
+    let mut llarg_idx = mircx.fn_ty.ret.is_indirect() as usize;
 
     // Get the argument scope, if it exists and if we need it.
     let arg_scope = scopes[mir::ARGUMENT_VISIBILITY_SCOPE];
@@ -341,7 +367,7 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
 
     mir.args_iter().enumerate().map(|(arg_index, local)| {
         let arg_decl = &mir.local_decls[local];
-        let arg_ty = bcx.monomorphize(&arg_decl.ty);
+        let arg_ty = mircx.monomorphize(&arg_decl.ty);
 
         if Some(local) == mir.spread_arg {
             // This argument (e.g. the last argument in the "rust-call" ABI)
@@ -354,22 +380,18 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
                 _ => bug!("spread argument isn't a tuple?!")
             };
 
-            let lltemp = bcx.with_block(|bcx| {
-                base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index))
-            });
+            let lltemp = base::alloc_ty(&bcx, arg_ty, &format!("arg{}", arg_index));
             for (i, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() {
                 let dst = bcx.struct_gep(lltemp, i);
-                let arg = &fcx.fn_ty.args[idx];
+                let arg = &mircx.fn_ty.args[idx];
                 idx += 1;
-                if common::type_is_fat_ptr(tcx, tupled_arg_ty) {
+                if common::type_is_fat_ptr(bcx.ccx, tupled_arg_ty) {
                     // We pass fat pointers as two words, but inside the tuple
                     // they are the two sub-fields of a single aggregate field.
-                    let meta = &fcx.fn_ty.args[idx];
+                    let meta = &mircx.fn_ty.args[idx];
                     idx += 1;
-                    arg.store_fn_arg(bcx, &mut llarg_idx,
-                                     base::get_dataptr_builder(bcx, dst));
-                    meta.store_fn_arg(bcx, &mut llarg_idx,
-                                      base::get_meta_builder(bcx, dst));
+                    arg.store_fn_arg(bcx, &mut llarg_idx, base::get_dataptr(bcx, dst));
+                    meta.store_fn_arg(bcx, &mut llarg_idx, base::get_meta(bcx, dst));
                 } else {
                     arg.store_fn_arg(bcx, &mut llarg_idx, dst);
                 }
@@ -377,20 +399,25 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
 
             // Now that we have one alloca that contains the aggregate value,
             // we can create one debuginfo entry for the argument.
-            bcx.with_block(|bcx| arg_scope.map(|scope| {
+            arg_scope.map(|scope| {
                 let variable_access = VariableAccess::DirectVariable {
                     alloca: lltemp
                 };
-                declare_local(bcx, arg_decl.name.unwrap_or(keywords::Invalid.name()),
-                              arg_ty, scope, variable_access,
-                              VariableKind::ArgumentVariable(arg_index + 1),
-                              bcx.fcx().span.unwrap_or(DUMMY_SP));
-            }));
+                declare_local(
+                    bcx,
+                    &mircx.debug_context,
+                    arg_decl.name.unwrap_or(keywords::Invalid.name()),
+                    arg_ty, scope,
+                    variable_access,
+                    VariableKind::ArgumentVariable(arg_index + 1),
+                    DUMMY_SP
+                );
+            });
 
             return LocalRef::Lvalue(LvalueRef::new_sized(lltemp, LvalueTy::from_ty(arg_ty)));
         }
 
-        let arg = &fcx.fn_ty.args[idx];
+        let arg = &mircx.fn_ty.args[idx];
         idx += 1;
         let llval = if arg.is_indirect() && bcx.sess().opts.debuginfo != FullDebugInfo {
             // Don't copy an indirect argument to an alloca, the caller
@@ -407,7 +434,7 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
                   !arg.is_indirect() && arg.cast.is_none() &&
                   arg_scope.is_none() {
             if arg.is_ignore() {
-                return LocalRef::new_operand(bcx.ccx(), arg_ty);
+                return LocalRef::new_operand(bcx.ccx, arg_ty);
             }
 
             // We don't have to cast or keep the argument in the alloca.
@@ -418,8 +445,8 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
             }
             let llarg = llvm::get_param(fcx.llfn, llarg_idx as c_uint);
             llarg_idx += 1;
-            let val = if common::type_is_fat_ptr(tcx, arg_ty) {
-                let meta = &fcx.fn_ty.args[idx];
+            let val = if common::type_is_fat_ptr(bcx.ccx, arg_ty) {
+                let meta = &mircx.fn_ty.args[idx];
                 idx += 1;
                 assert_eq!((meta.cast, meta.pad), (None, None));
                 let llmeta = llvm::get_param(fcx.llfn, llarg_idx as c_uint);
@@ -434,19 +461,15 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
             };
             return LocalRef::Operand(Some(operand.unpack_if_pair(bcx)));
         } else {
-            let lltemp = bcx.with_block(|bcx| {
-                base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index))
-            });
-            if common::type_is_fat_ptr(tcx, arg_ty) {
+            let lltemp = base::alloc_ty(&bcx, arg_ty, &format!("arg{}", arg_index));
+            if common::type_is_fat_ptr(bcx.ccx, arg_ty) {
                 // we pass fat pointers as two words, but we want to
                 // represent them internally as a pointer to two words,
                 // so make an alloca to store them in.
-                let meta = &fcx.fn_ty.args[idx];
+                let meta = &mircx.fn_ty.args[idx];
                 idx += 1;
-                arg.store_fn_arg(bcx, &mut llarg_idx,
-                                 base::get_dataptr_builder(bcx, lltemp));
-                meta.store_fn_arg(bcx, &mut llarg_idx,
-                                  base::get_meta_builder(bcx, lltemp));
+                arg.store_fn_arg(bcx, &mut llarg_idx, base::get_dataptr(bcx, lltemp));
+                meta.store_fn_arg(bcx, &mut llarg_idx, base::get_meta(bcx, lltemp));
             } else  {
                 // otherwise, arg is passed by value, so make a
                 // temporary and store it there
@@ -454,13 +477,19 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
             }
             lltemp
         };
-        bcx.with_block(|bcx| arg_scope.map(|scope| {
+        arg_scope.map(|scope| {
             // Is this a regular argument?
             if arg_index > 0 || mir.upvar_decls.is_empty() {
-                declare_local(bcx, arg_decl.name.unwrap_or(keywords::Invalid.name()), arg_ty,
-                              scope, VariableAccess::DirectVariable { alloca: llval },
-                              VariableKind::ArgumentVariable(arg_index + 1),
-                              bcx.fcx().span.unwrap_or(DUMMY_SP));
+                declare_local(
+                    bcx,
+                    &mircx.debug_context,
+                    arg_decl.name.unwrap_or(keywords::Invalid.name()),
+                    arg_ty,
+                    scope,
+                    VariableAccess::DirectVariable { alloca: llval },
+                    VariableKind::ArgumentVariable(arg_index + 1),
+                    DUMMY_SP
+                );
                 return;
             }
 
@@ -484,20 +513,21 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
             // doesn't actually strip the offset when splitting the closure
             // environment into its components so it ends up out of bounds.
             let env_ptr = if !env_ref {
-                use base::*;
-                use build::*;
-                use common::*;
-                let alloc = alloca(bcx, val_ty(llval), "__debuginfo_env_ptr");
-                Store(bcx, llval, alloc);
+                let alloc = bcx.fcx().alloca(common::val_ty(llval), "__debuginfo_env_ptr");
+                bcx.store(llval, alloc);
                 alloc
             } else {
                 llval
             };
 
-            let llclosurety = type_of::type_of(bcx.ccx(), closure_ty);
+            let layout = bcx.ccx.layout_of(closure_ty);
+            let offsets = match *layout {
+                layout::Univariant { ref variant, .. } => &variant.offsets[..],
+                _ => bug!("Closures are only supposed to be Univariant")
+            };
+
             for (i, (decl, ty)) in mir.upvar_decls.iter().zip(upvar_tys).enumerate() {
-                let byte_offset_of_var_in_env =
-                    machine::llelement_offset(bcx.ccx(), llclosurety, i);
+                let byte_offset_of_var_in_env = offsets[i].bytes();
 
                 let ops = unsafe {
                     [llvm::LLVMRustDIBuilderCreateOpDeref(),
@@ -523,11 +553,18 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
                     alloca: env_ptr,
                     address_operations: &ops
                 };
-                declare_local(bcx, decl.debug_name, ty, scope, variable_access,
-                              VariableKind::CapturedVariable,
-                              bcx.fcx().span.unwrap_or(DUMMY_SP));
+                declare_local(
+                    bcx,
+                    &mircx.debug_context,
+                    decl.debug_name,
+                    ty,
+                    scope,
+                    variable_access,
+                    VariableKind::CapturedVariable,
+                    DUMMY_SP
+                );
             }
-        }));
+        });
         LocalRef::Lvalue(LvalueRef::new_sized(llval, LvalueTy::from_ty(arg_ty)))
     }).collect()
 }
diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs
index 62eda56e2e1..a15d51d9da6 100644
--- a/src/librustc_trans/mir/operand.rs
+++ b/src/librustc_trans/mir/operand.rs
@@ -14,7 +14,7 @@ use rustc::mir;
 use rustc_data_structures::indexed_vec::Idx;
 
 use base;
-use common::{self, Block, BlockAndBuilder};
+use common::{self, BlockAndBuilder};
 use value::Value;
 use type_of;
 use type_::Type;
@@ -73,7 +73,7 @@ impl<'tcx> fmt::Debug for OperandRef<'tcx> {
     }
 }
 
-impl<'bcx, 'tcx> OperandRef<'tcx> {
+impl<'a, 'tcx> OperandRef<'tcx> {
     /// Asserts that this operand refers to a scalar and returns
     /// a reference to its value.
     pub fn immediate(self) -> ValueRef {
@@ -85,18 +85,18 @@ impl<'bcx, 'tcx> OperandRef<'tcx> {
 
     /// If this operand is a Pair, we return an
     /// Immediate aggregate with the two values.
-    pub fn pack_if_pair(mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>)
+    pub fn pack_if_pair(mut self, bcx: &BlockAndBuilder<'a, 'tcx>)
                         -> OperandRef<'tcx> {
         if let OperandValue::Pair(a, b) = self.val {
             // Reconstruct the immediate aggregate.
-            let llty = type_of::type_of(bcx.ccx(), self.ty);
+            let llty = type_of::type_of(bcx.ccx, self.ty);
             let mut llpair = common::C_undef(llty);
             let elems = [a, b];
             for i in 0..2 {
                 let mut elem = elems[i];
                 // Extend boolean i1's to i8.
-                if common::val_ty(elem) == Type::i1(bcx.ccx()) {
-                    elem = bcx.zext(elem, Type::i8(bcx.ccx()));
+                if common::val_ty(elem) == Type::i1(bcx.ccx) {
+                    elem = bcx.zext(elem, Type::i8(bcx.ccx));
                 }
                 llpair = bcx.insert_value(llpair, elem, i);
             }
@@ -107,23 +107,23 @@ impl<'bcx, 'tcx> OperandRef<'tcx> {
 
     /// If this operand is a pair in an Immediate,
     /// we return a Pair with the two halves.
-    pub fn unpack_if_pair(mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>)
+    pub fn unpack_if_pair(mut self, bcx: &BlockAndBuilder<'a, 'tcx>)
                           -> OperandRef<'tcx> {
         if let OperandValue::Immediate(llval) = self.val {
             // Deconstruct the immediate aggregate.
-            if common::type_is_imm_pair(bcx.ccx(), self.ty) {
+            if common::type_is_imm_pair(bcx.ccx, self.ty) {
                 debug!("Operand::unpack_if_pair: unpacking {:?}", self);
 
                 let mut a = bcx.extract_value(llval, 0);
                 let mut b = bcx.extract_value(llval, 1);
 
-                let pair_fields = common::type_pair_fields(bcx.ccx(), self.ty);
+                let pair_fields = common::type_pair_fields(bcx.ccx, self.ty);
                 if let Some([a_ty, b_ty]) = pair_fields {
                     if a_ty.is_bool() {
-                        a = bcx.trunc(a, Type::i1(bcx.ccx()));
+                        a = bcx.trunc(a, Type::i1(bcx.ccx));
                     }
                     if b_ty.is_bool() {
-                        b = bcx.trunc(b, Type::i1(bcx.ccx()));
+                        b = bcx.trunc(b, Type::i1(bcx.ccx));
                     }
                 }
 
@@ -134,29 +134,29 @@ impl<'bcx, 'tcx> OperandRef<'tcx> {
     }
 }
 
-impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
+impl<'a, 'tcx> MirContext<'a, 'tcx> {
     pub fn trans_load(&mut self,
-                      bcx: &BlockAndBuilder<'bcx, 'tcx>,
+                      bcx: &BlockAndBuilder<'a, 'tcx>,
                       llval: ValueRef,
                       ty: Ty<'tcx>)
                       -> OperandRef<'tcx>
     {
         debug!("trans_load: {:?} @ {:?}", Value(llval), ty);
 
-        let val = if common::type_is_fat_ptr(bcx.tcx(), ty) {
-            let (lldata, llextra) = base::load_fat_ptr_builder(bcx, llval, ty);
+        let val = if common::type_is_fat_ptr(bcx.ccx, ty) {
+            let (lldata, llextra) = base::load_fat_ptr(bcx, llval, ty);
             OperandValue::Pair(lldata, llextra)
-        } else if common::type_is_imm_pair(bcx.ccx(), ty) {
-            let [a_ty, b_ty] = common::type_pair_fields(bcx.ccx(), ty).unwrap();
+        } else if common::type_is_imm_pair(bcx.ccx, ty) {
+            let [a_ty, b_ty] = common::type_pair_fields(bcx.ccx, ty).unwrap();
             let a_ptr = bcx.struct_gep(llval, 0);
             let b_ptr = bcx.struct_gep(llval, 1);
 
             OperandValue::Pair(
-                base::load_ty_builder(bcx, a_ptr, a_ty),
-                base::load_ty_builder(bcx, b_ptr, b_ty)
+                base::load_ty(bcx, a_ptr, a_ty),
+                base::load_ty(bcx, b_ptr, b_ty)
             )
-        } else if common::type_is_immediate(bcx.ccx(), ty) {
-            OperandValue::Immediate(base::load_ty_builder(bcx, llval, ty))
+        } else if common::type_is_immediate(bcx.ccx, ty) {
+            OperandValue::Immediate(base::load_ty(bcx, llval, ty))
         } else {
             OperandValue::Ref(llval)
         };
@@ -165,7 +165,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     }
 
     pub fn trans_consume(&mut self,
-                         bcx: &BlockAndBuilder<'bcx, 'tcx>,
+                         bcx: &BlockAndBuilder<'a, 'tcx>,
                          lvalue: &mir::Lvalue<'tcx>)
                          -> OperandRef<'tcx>
     {
@@ -197,7 +197,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                             let llval = [a, b][f.index()];
                             let op = OperandRef {
                                 val: OperandValue::Immediate(llval),
-                                ty: bcx.monomorphize(&ty)
+                                ty: self.monomorphize(&ty)
                             };
 
                             // Handle nested pairs.
@@ -217,7 +217,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     }
 
     pub fn trans_operand(&mut self,
-                         bcx: &BlockAndBuilder<'bcx, 'tcx>,
+                         bcx: &BlockAndBuilder<'a, 'tcx>,
                          operand: &mir::Operand<'tcx>)
                          -> OperandRef<'tcx>
     {
@@ -230,7 +230,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
             mir::Operand::Constant(ref constant) => {
                 let val = self.trans_constant(bcx, constant);
-                let operand = val.to_operand(bcx.ccx());
+                let operand = val.to_operand(bcx.ccx);
                 if let OperandValue::Ref(ptr) = operand.val {
                     // If this is a OperandValue::Ref to an immediate constant, load it.
                     self.trans_load(bcx, ptr, operand.ty)
@@ -242,33 +242,23 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     }
 
     pub fn store_operand(&mut self,
-                         bcx: &BlockAndBuilder<'bcx, 'tcx>,
+                         bcx: &BlockAndBuilder<'a, 'tcx>,
                          lldest: ValueRef,
-                         operand: OperandRef<'tcx>)
-    {
+                         operand: OperandRef<'tcx>) {
         debug!("store_operand: operand={:?}", operand);
-        bcx.with_block(|bcx| self.store_operand_direct(bcx, lldest, operand))
-    }
-
-    pub fn store_operand_direct(&mut self,
-                                bcx: Block<'bcx, 'tcx>,
-                                lldest: ValueRef,
-                                operand: OperandRef<'tcx>)
-    {
         // Avoid generating stores of zero-sized values, because the only way to have a zero-sized
         // value is through `undef`, and store itself is useless.
-        if common::type_is_zero_size(bcx.ccx(), operand.ty) {
+        if common::type_is_zero_size(bcx.ccx, operand.ty) {
             return;
         }
         match operand.val {
             OperandValue::Ref(r) => base::memcpy_ty(bcx, lldest, r, operand.ty),
             OperandValue::Immediate(s) => base::store_ty(bcx, s, lldest, operand.ty),
             OperandValue::Pair(a, b) => {
-                use build::*;
                 let a = base::from_immediate(bcx, a);
                 let b = base::from_immediate(bcx, b);
-                Store(bcx, a, StructGEP(bcx, lldest, 0));
-                Store(bcx, b, StructGEP(bcx, lldest, 1));
+                bcx.store(a, bcx.struct_gep(lldest, 0));
+                bcx.store(b, bcx.struct_gep(lldest, 1));
             }
         }
     }
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index 15cbbc720d6..b17550087ed 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -13,13 +13,13 @@ use rustc::ty::{self, Ty};
 use rustc::ty::cast::{CastTy, IntTy};
 use rustc::ty::layout::Layout;
 use rustc::mir;
+use middle::lang_items::ExchangeMallocFnLangItem;
 
 use asm;
 use base;
 use callee::Callee;
-use common::{self, val_ty, C_bool, C_null, C_uint, BlockAndBuilder, Result};
+use common::{self, val_ty, C_bool, C_null, C_uint, BlockAndBuilder};
 use common::{C_integral};
-use debuginfo::DebugLoc;
 use adt;
 use machine;
 use type_::Type;
@@ -33,13 +33,12 @@ use super::constant::const_scalar_checked_binop;
 use super::operand::{OperandRef, OperandValue};
 use super::lvalue::{LvalueRef};
 
-impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
+impl<'a, 'tcx> MirContext<'a, 'tcx> {
     pub fn trans_rvalue(&mut self,
-                        bcx: BlockAndBuilder<'bcx, 'tcx>,
+                        bcx: BlockAndBuilder<'a, 'tcx>,
                         dest: LvalueRef<'tcx>,
-                        rvalue: &mir::Rvalue<'tcx>,
-                        debug_loc: DebugLoc)
-                        -> BlockAndBuilder<'bcx, 'tcx>
+                        rvalue: &mir::Rvalue<'tcx>)
+                        -> BlockAndBuilder<'a, 'tcx>
     {
         debug!("trans_rvalue(dest.llval={:?}, rvalue={:?})",
                Value(dest.llval), rvalue);
@@ -54,12 +53,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
            }
 
             mir::Rvalue::Cast(mir::CastKind::Unsize, ref source, cast_ty) => {
-                let cast_ty = bcx.monomorphize(&cast_ty);
+                let cast_ty = self.monomorphize(&cast_ty);
 
-                if common::type_is_fat_ptr(bcx.tcx(), cast_ty) {
+                if common::type_is_fat_ptr(bcx.ccx, cast_ty) {
                     // into-coerce of a thin pointer to a fat pointer - just
                     // use the operand path.
-                    let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue, debug_loc);
+                    let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
                     self.store_operand(&bcx, dest.llval, temp);
                     return bcx;
                 }
@@ -70,76 +69,74 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 // so the (generic) MIR may not be able to expand it.
                 let operand = self.trans_operand(&bcx, source);
                 let operand = operand.pack_if_pair(&bcx);
-                bcx.with_block(|bcx| {
-                    match operand.val {
-                        OperandValue::Pair(..) => bug!(),
-                        OperandValue::Immediate(llval) => {
-                            // unsize from an immediate structure. We don't
-                            // really need a temporary alloca here, but
-                            // avoiding it would require us to have
-                            // `coerce_unsized_into` use extractvalue to
-                            // index into the struct, and this case isn't
-                            // important enough for it.
-                            debug!("trans_rvalue: creating ugly alloca");
-                            let lltemp = base::alloc_ty(bcx, operand.ty, "__unsize_temp");
-                            base::store_ty(bcx, llval, lltemp, operand.ty);
-                            base::coerce_unsized_into(bcx,
-                                                      lltemp, operand.ty,
-                                                      dest.llval, cast_ty);
-                        }
-                        OperandValue::Ref(llref) => {
-                            base::coerce_unsized_into(bcx,
-                                                      llref, operand.ty,
-                                                      dest.llval, cast_ty);
-                        }
+                let llref = match operand.val {
+                    OperandValue::Pair(..) => bug!(),
+                    OperandValue::Immediate(llval) => {
+                        // unsize from an immediate structure. We don't
+                        // really need a temporary alloca here, but
+                        // avoiding it would require us to have
+                        // `coerce_unsized_into` use extractvalue to
+                        // index into the struct, and this case isn't
+                        // important enough for it.
+                        debug!("trans_rvalue: creating ugly alloca");
+                        let lltemp = base::alloc_ty(&bcx, operand.ty, "__unsize_temp");
+                        base::store_ty(&bcx, llval, lltemp, operand.ty);
+                        lltemp
                     }
-                });
+                    OperandValue::Ref(llref) => llref
+                };
+                base::coerce_unsized_into(&bcx, llref, operand.ty, dest.llval, cast_ty);
                 bcx
             }
 
             mir::Rvalue::Repeat(ref elem, ref count) => {
                 let tr_elem = self.trans_operand(&bcx, elem);
                 let size = count.value.as_u64(bcx.tcx().sess.target.uint_type);
-                let size = C_uint(bcx.ccx(), size);
-                let base = base::get_dataptr_builder(&bcx, dest.llval);
-                let bcx = bcx.map_block(|block| {
-                    tvec::slice_for_each(block, base, tr_elem.ty, size, |block, llslot| {
-                        self.store_operand_direct(block, llslot, tr_elem);
-                        block
-                    })
-                });
-                bcx
+                let size = C_uint(bcx.ccx, size);
+                let base = base::get_dataptr(&bcx, dest.llval);
+                tvec::slice_for_each(&bcx, base, tr_elem.ty, size, |bcx, llslot| {
+                    self.store_operand(bcx, llslot, tr_elem);
+                })
             }
 
             mir::Rvalue::Aggregate(ref kind, ref operands) => {
                 match *kind {
                     mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
                         let disr = Disr::from(adt_def.variants[variant_index].disr_val);
-                        bcx.with_block(|bcx| {
-                            adt::trans_set_discr(bcx,
-                                dest.ty.to_ty(bcx.tcx()), dest.llval, Disr::from(disr));
-                        });
+                        let dest_ty = dest.ty.to_ty(bcx.tcx());
+                        adt::trans_set_discr(&bcx, dest_ty, dest.llval, Disr::from(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.
-                            if !common::type_is_zero_size(bcx.ccx(), op.ty) {
+                            if !common::type_is_zero_size(bcx.ccx, op.ty) {
                                 let val = adt::MaybeSizedValue::sized(dest.llval);
                                 let field_index = active_field_index.unwrap_or(i);
-                                let lldest_i = adt::trans_field_ptr_builder(&bcx,
-                                    dest.ty.to_ty(bcx.tcx()),
-                                    val, disr, field_index);
+                                let lldest_i = adt::trans_field_ptr(&bcx, dest_ty, val, disr,
+                                    field_index);
                                 self.store_operand(&bcx, lldest_i, op);
                             }
                         }
                     },
                     _ => {
+                        // If this is a tuple or closure, we need to translate GEP indices.
+                        let layout = bcx.ccx.layout_of(dest.ty.to_ty(bcx.tcx()));
+                        let translation = if let Layout::Univariant { ref variant, .. } = *layout {
+                            Some(&variant.memory_index)
+                        } else {
+                            None
+                        };
                         for (i, operand) in operands.iter().enumerate() {
                             let op = self.trans_operand(&bcx, operand);
                             // Do not generate stores and GEPis for zero-sized fields.
-                            if !common::type_is_zero_size(bcx.ccx(), op.ty) {
+                            if !common::type_is_zero_size(bcx.ccx, op.ty) {
                                 // Note: perhaps this should be StructGep, but
                                 // note that in some cases the values here will
                                 // not be structs but arrays.
+                                let i = if let Some(ref t) = translation {
+                                    t[i] as usize
+                                } else {
+                                    i
+                                };
                                 let dest = bcx.gepi(dest.llval, &[0, i]);
                                 self.store_operand(&bcx, dest, op);
                             }
@@ -159,16 +156,13 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     self.trans_operand(&bcx, input).immediate()
                 }).collect();
 
-                bcx.with_block(|bcx| {
-                    asm::trans_inline_asm(bcx, asm, outputs, input_vals);
-                });
-
+                asm::trans_inline_asm(&bcx, asm, outputs, input_vals);
                 bcx
             }
 
             _ => {
-                assert!(rvalue_creates_operand(&self.mir, &bcx, rvalue));
-                let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue, debug_loc);
+                assert!(rvalue_creates_operand(rvalue));
+                let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
                 self.store_operand(&bcx, dest.llval, temp);
                 bcx
             }
@@ -176,27 +170,25 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     }
 
     pub fn trans_rvalue_operand(&mut self,
-                                bcx: BlockAndBuilder<'bcx, 'tcx>,
-                                rvalue: &mir::Rvalue<'tcx>,
-                                debug_loc: DebugLoc)
-                                -> (BlockAndBuilder<'bcx, 'tcx>, OperandRef<'tcx>)
+                                bcx: BlockAndBuilder<'a, 'tcx>,
+                                rvalue: &mir::Rvalue<'tcx>)
+                                -> (BlockAndBuilder<'a, 'tcx>, OperandRef<'tcx>)
     {
-        assert!(rvalue_creates_operand(&self.mir, &bcx, rvalue),
-                "cannot trans {:?} to operand", rvalue);
+        assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue);
 
         match *rvalue {
             mir::Rvalue::Cast(ref kind, ref source, cast_ty) => {
                 let operand = self.trans_operand(&bcx, source);
                 debug!("cast operand is {:?}", operand);
-                let cast_ty = bcx.monomorphize(&cast_ty);
+                let cast_ty = self.monomorphize(&cast_ty);
 
                 let val = match *kind {
                     mir::CastKind::ReifyFnPointer => {
                         match operand.ty.sty {
                             ty::TyFnDef(def_id, substs, _) => {
                                 OperandValue::Immediate(
-                                    Callee::def(bcx.ccx(), def_id, substs)
-                                        .reify(bcx.ccx()))
+                                    Callee::def(bcx.ccx, def_id, substs)
+                                        .reify(bcx.ccx))
                             }
                             _ => {
                                 bug!("{} cannot be reified to a fn ptr", operand.ty)
@@ -210,7 +202,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     mir::CastKind::Unsize => {
                         // unsize targets other than to a fat pointer currently
                         // can't be operands.
-                        assert!(common::type_is_fat_ptr(bcx.tcx(), cast_ty));
+                        assert!(common::type_is_fat_ptr(bcx.ccx, cast_ty));
 
                         match operand.val {
                             OperandValue::Pair(lldata, llextra) => {
@@ -220,16 +212,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                                 //   &'a fmt::Debug+Send => &'a fmt::Debug,
                                 // So we need to pointercast the base to ensure
                                 // the types match up.
-                                let llcast_ty = type_of::fat_ptr_base_ty(bcx.ccx(), cast_ty);
+                                let llcast_ty = type_of::fat_ptr_base_ty(bcx.ccx, cast_ty);
                                 let lldata = bcx.pointercast(lldata, llcast_ty);
                                 OperandValue::Pair(lldata, llextra)
                             }
                             OperandValue::Immediate(lldata) => {
                                 // "standard" unsize
-                                let (lldata, llextra) = bcx.with_block(|bcx| {
-                                    base::unsize_thin_ptr(bcx, lldata,
-                                                          operand.ty, cast_ty)
-                                });
+                                let (lldata, llextra) = base::unsize_thin_ptr(&bcx, lldata,
+                                    operand.ty, cast_ty);
                                 OperandValue::Pair(lldata, llextra)
                             }
                             OperandValue::Ref(_) => {
@@ -238,11 +228,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                             }
                         }
                     }
-                    mir::CastKind::Misc if common::type_is_fat_ptr(bcx.tcx(), operand.ty) => {
-                        let ll_cast_ty = type_of::immediate_type_of(bcx.ccx(), cast_ty);
-                        let ll_from_ty = type_of::immediate_type_of(bcx.ccx(), operand.ty);
+                    mir::CastKind::Misc if common::type_is_fat_ptr(bcx.ccx, operand.ty) => {
+                        let ll_cast_ty = type_of::immediate_type_of(bcx.ccx, cast_ty);
+                        let ll_from_ty = type_of::immediate_type_of(bcx.ccx, operand.ty);
                         if let OperandValue::Pair(data_ptr, meta_ptr) = operand.val {
-                            if common::type_is_fat_ptr(bcx.tcx(), cast_ty) {
+                            if common::type_is_fat_ptr(bcx.ccx, cast_ty) {
                                 let ll_cft = ll_cast_ty.field_types();
                                 let ll_fft = ll_from_ty.field_types();
                                 let data_cast = bcx.pointercast(data_ptr, ll_cft[0]);
@@ -259,19 +249,17 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                         }
                     }
                     mir::CastKind::Misc => {
-                        debug_assert!(common::type_is_immediate(bcx.ccx(), cast_ty));
+                        debug_assert!(common::type_is_immediate(bcx.ccx, cast_ty));
                         let r_t_in = CastTy::from_ty(operand.ty).expect("bad input type for cast");
                         let r_t_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
-                        let ll_t_in = type_of::immediate_type_of(bcx.ccx(), operand.ty);
-                        let ll_t_out = type_of::immediate_type_of(bcx.ccx(), cast_ty);
+                        let ll_t_in = type_of::immediate_type_of(bcx.ccx, operand.ty);
+                        let ll_t_out = type_of::immediate_type_of(bcx.ccx, cast_ty);
                         let (llval, signed) = if let CastTy::Int(IntTy::CEnum) = r_t_in {
-                            let l = bcx.ccx().layout_of(operand.ty);
+                            let l = bcx.ccx.layout_of(operand.ty);
                             let discr = match operand.val {
                                 OperandValue::Immediate(llval) => llval,
                                 OperandValue::Ref(llptr) => {
-                                    bcx.with_block(|bcx| {
-                                        adt::trans_get_discr(bcx, operand.ty, llptr, None, true)
-                                    })
+                                    adt::trans_get_discr(&bcx, operand.ty, llptr, None, true)
                                 }
                                 OperandValue::Pair(..) => bug!("Unexpected Pair operand")
                             };
@@ -364,7 +352,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
                 // Note: lvalues are indirect, so storing the `llval` into the
                 // destination effectively creates a reference.
-                let operand = if common::type_is_sized(bcx.tcx(), ty) {
+                let operand = if bcx.ccx.shared().type_is_sized(ty) {
                     OperandRef {
                         val: OperandValue::Immediate(tr_lvalue.llval),
                         ty: ref_ty,
@@ -382,7 +370,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             mir::Rvalue::Len(ref lvalue) => {
                 let tr_lvalue = self.trans_lvalue(&bcx, lvalue);
                 let operand = OperandRef {
-                    val: OperandValue::Immediate(tr_lvalue.len(bcx.ccx())),
+                    val: OperandValue::Immediate(tr_lvalue.len(bcx.ccx)),
                     ty: bcx.tcx().types.usize,
                 };
                 (bcx, operand)
@@ -391,7 +379,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
                 let lhs = self.trans_operand(&bcx, lhs);
                 let rhs = self.trans_operand(&bcx, rhs);
-                let llresult = if common::type_is_fat_ptr(bcx.tcx(), lhs.ty) {
+                let llresult = if common::type_is_fat_ptr(bcx.ccx, lhs.ty) {
                     match (lhs.val, rhs.val) {
                         (OperandValue::Pair(lhs_addr, lhs_extra),
                          OperandValue::Pair(rhs_addr, rhs_extra)) => {
@@ -449,26 +437,27 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             }
 
             mir::Rvalue::Box(content_ty) => {
-                let content_ty: Ty<'tcx> = bcx.monomorphize(&content_ty);
-                let llty = type_of::type_of(bcx.ccx(), content_ty);
-                let llsize = machine::llsize_of(bcx.ccx(), llty);
-                let align = type_of::align_of(bcx.ccx(), content_ty);
-                let llalign = C_uint(bcx.ccx(), align);
+                let content_ty: Ty<'tcx> = self.monomorphize(&content_ty);
+                let llty = type_of::type_of(bcx.ccx, content_ty);
+                let llsize = machine::llsize_of(bcx.ccx, llty);
+                let align = type_of::align_of(bcx.ccx, content_ty);
+                let llalign = C_uint(bcx.ccx, align);
                 let llty_ptr = llty.ptr_to();
                 let box_ty = bcx.tcx().mk_box(content_ty);
-                let mut llval = None;
-                let bcx = bcx.map_block(|bcx| {
-                    let Result { bcx, val } = base::malloc_raw_dyn(bcx,
-                                                                   llty_ptr,
-                                                                   box_ty,
-                                                                   llsize,
-                                                                   llalign,
-                                                                   debug_loc);
-                    llval = Some(val);
-                    bcx
-                });
+
+                // Allocate space:
+                let def_id = match bcx.tcx().lang_items.require(ExchangeMallocFnLangItem) {
+                    Ok(id) => id,
+                    Err(s) => {
+                        bcx.sess().fatal(&format!("allocation of `{}` {}", box_ty, s));
+                    }
+                };
+                let r = Callee::def(bcx.ccx, def_id, bcx.tcx().intern_substs(&[]))
+                    .reify(bcx.ccx);
+                let val = bcx.pointercast(bcx.call(r, &[llsize, llalign], None), llty_ptr);
+
                 let operand = OperandRef {
-                    val: OperandValue::Immediate(llval.unwrap()),
+                    val: OperandValue::Immediate(val),
                     ty: box_ty,
                 };
                 (bcx, operand)
@@ -488,7 +477,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     }
 
     pub fn trans_scalar_binop(&mut self,
-                              bcx: &BlockAndBuilder<'bcx, 'tcx>,
+                              bcx: &BlockAndBuilder<'a, 'tcx>,
                               op: mir::BinOp,
                               lhs: ValueRef,
                               rhs: ValueRef,
@@ -530,26 +519,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             mir::BinOp::BitOr => bcx.or(lhs, rhs),
             mir::BinOp::BitAnd => bcx.and(lhs, rhs),
             mir::BinOp::BitXor => bcx.xor(lhs, rhs),
-            mir::BinOp::Shl => {
-                bcx.with_block(|bcx| {
-                    common::build_unchecked_lshift(bcx,
-                                                   lhs,
-                                                   rhs,
-                                                   DebugLoc::None)
-                })
-            }
-            mir::BinOp::Shr => {
-                bcx.with_block(|bcx| {
-                    common::build_unchecked_rshift(bcx,
-                                                   input_ty,
-                                                   lhs,
-                                                   rhs,
-                                                   DebugLoc::None)
-                })
-            }
+            mir::BinOp::Shl => common::build_unchecked_lshift(bcx, lhs, rhs),
+            mir::BinOp::Shr => common::build_unchecked_rshift(bcx, input_ty, lhs, rhs),
             mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt |
             mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => if is_nil {
-                C_bool(bcx.ccx(), match op {
+                C_bool(bcx.ccx, match op {
                     mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt => false,
                     mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => true,
                     _ => unreachable!()
@@ -563,8 +537,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 let (lhs, rhs) = if is_bool {
                     // FIXME(#36856) -- extend the bools into `i8` because
                     // LLVM's i1 comparisons are broken.
-                    (bcx.zext(lhs, Type::i8(bcx.ccx())),
-                     bcx.zext(rhs, Type::i8(bcx.ccx())))
+                    (bcx.zext(lhs, Type::i8(bcx.ccx)),
+                     bcx.zext(rhs, Type::i8(bcx.ccx)))
                 } else {
                     (lhs, rhs)
                 };
@@ -578,7 +552,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     }
 
     pub fn trans_fat_ptr_binop(&mut self,
-                               bcx: &BlockAndBuilder<'bcx, 'tcx>,
+                               bcx: &BlockAndBuilder<'a, 'tcx>,
                                op: mir::BinOp,
                                lhs_addr: ValueRef,
                                lhs_extra: ValueRef,
@@ -625,7 +599,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     }
 
     pub fn trans_scalar_checked_binop(&mut self,
-                                      bcx: &BlockAndBuilder<'bcx, 'tcx>,
+                                      bcx: &BlockAndBuilder<'a, 'tcx>,
                                       op: mir::BinOp,
                                       lhs: ValueRef,
                                       rhs: ValueRef,
@@ -634,9 +608,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         // with #[rustc_inherit_overflow_checks] and inlined from
         // another crate (mostly core::num generic/#[inline] fns),
         // while the current crate doesn't use overflow checks.
-        if !bcx.ccx().check_overflow() {
+        if !bcx.ccx.check_overflow() {
             let val = self.trans_scalar_binop(bcx, op, lhs, rhs, input_ty);
-            return OperandValue::Pair(val, C_bool(bcx.ccx(), false));
+            return OperandValue::Pair(val, C_bool(bcx.ccx, false));
         }
 
         // First try performing the operation on constants, which
@@ -644,7 +618,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         // This is necessary to determine when an overflow Assert
         // will always panic at runtime, and produce a warning.
         if let Some((val, of)) = const_scalar_checked_binop(bcx.tcx(), op, lhs, rhs, input_ty) {
-            return OperandValue::Pair(val, C_bool(bcx.ccx(), of));
+            return OperandValue::Pair(val, C_bool(bcx.ccx, of));
         }
 
         let (val, of) = match op {
@@ -665,9 +639,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             mir::BinOp::Shl | mir::BinOp::Shr => {
                 let lhs_llty = val_ty(lhs);
                 let rhs_llty = val_ty(rhs);
-                let invert_mask = bcx.with_block(|bcx| {
-                    common::shift_mask_val(bcx, lhs_llty, rhs_llty, true)
-                });
+                let invert_mask = common::shift_mask_val(&bcx, lhs_llty, rhs_llty, true);
                 let outer_bits = bcx.and(rhs, invert_mask);
 
                 let of = bcx.icmp(llvm::IntNE, outer_bits, C_null(rhs_llty));
@@ -684,9 +656,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     }
 }
 
-pub fn rvalue_creates_operand<'bcx, 'tcx>(_mir: &mir::Mir<'tcx>,
-                                          _bcx: &BlockAndBuilder<'bcx, 'tcx>,
-                                          rvalue: &mir::Rvalue<'tcx>) -> bool {
+pub fn rvalue_creates_operand(rvalue: &mir::Rvalue) -> bool {
     match *rvalue {
         mir::Rvalue::Ref(..) |
         mir::Rvalue::Len(..) |
@@ -777,5 +747,5 @@ fn get_overflow_intrinsic(oop: OverflowOp, bcx: &BlockAndBuilder, ty: Ty) -> Val
         },
     };
 
-    bcx.ccx().get_intrinsic(&name)
+    bcx.ccx.get_intrinsic(&name)
 }
diff --git a/src/librustc_trans/mir/statement.rs b/src/librustc_trans/mir/statement.rs
index 296a0e8049e..cc85f68c197 100644
--- a/src/librustc_trans/mir/statement.rs
+++ b/src/librustc_trans/mir/statement.rs
@@ -18,57 +18,52 @@ use super::LocalRef;
 use super::super::adt;
 use super::super::disr::Disr;
 
-impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
+impl<'a, 'tcx> MirContext<'a, 'tcx> {
     pub fn trans_statement(&mut self,
-                           bcx: BlockAndBuilder<'bcx, 'tcx>,
+                           bcx: BlockAndBuilder<'a, 'tcx>,
                            statement: &mir::Statement<'tcx>)
-                           -> BlockAndBuilder<'bcx, 'tcx> {
+                           -> BlockAndBuilder<'a, 'tcx> {
         debug!("trans_statement(statement={:?})", statement);
 
-        let debug_loc = self.debug_loc(statement.source_info);
-        debug_loc.apply_to_bcx(&bcx);
-        debug_loc.apply(bcx.fcx());
+        self.set_debug_loc(&bcx, statement.source_info);
         match statement.kind {
             mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
                 if let mir::Lvalue::Local(index) = *lvalue {
                     match self.locals[index] {
                         LocalRef::Lvalue(tr_dest) => {
-                            self.trans_rvalue(bcx, tr_dest, rvalue, debug_loc)
+                            self.trans_rvalue(bcx, tr_dest, rvalue)
                         }
                         LocalRef::Operand(None) => {
-                            let (bcx, operand) = self.trans_rvalue_operand(bcx, rvalue,
-                                                                           debug_loc);
+                            let (bcx, operand) = self.trans_rvalue_operand(bcx, rvalue);
                             self.locals[index] = LocalRef::Operand(Some(operand));
                             bcx
                         }
                         LocalRef::Operand(Some(_)) => {
                             let ty = self.monomorphized_lvalue_ty(lvalue);
 
-                            if !common::type_is_zero_size(bcx.ccx(), ty) {
+                            if !common::type_is_zero_size(bcx.ccx, ty) {
                                 span_bug!(statement.source_info.span,
                                           "operand {:?} already assigned",
                                           rvalue);
                             } else {
                                 // If the type is zero-sized, it's already been set here,
                                 // but we still need to make sure we translate the operand
-                                self.trans_rvalue_operand(bcx, rvalue, debug_loc).0
+                                self.trans_rvalue_operand(bcx, rvalue).0
                             }
                         }
                     }
                 } else {
                     let tr_dest = self.trans_lvalue(&bcx, lvalue);
-                    self.trans_rvalue(bcx, tr_dest, rvalue, debug_loc)
+                    self.trans_rvalue(bcx, tr_dest, rvalue)
                 }
             }
             mir::StatementKind::SetDiscriminant{ref lvalue, variant_index} => {
                 let ty = self.monomorphized_lvalue_ty(lvalue);
                 let lvalue_transed = self.trans_lvalue(&bcx, lvalue);
-                bcx.with_block(|bcx|
-                    adt::trans_set_discr(bcx,
-                                         ty,
-                                        lvalue_transed.llval,
-                                        Disr::from(variant_index))
-                );
+                adt::trans_set_discr(&bcx,
+                    ty,
+                    lvalue_transed.llval,
+                    Disr::from(variant_index));
                 bcx
             }
             mir::StatementKind::StorageLive(ref lvalue) => {
@@ -82,10 +77,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     }
 
     fn trans_storage_liveness(&self,
-                              bcx: BlockAndBuilder<'bcx, 'tcx>,
+                              bcx: BlockAndBuilder<'a, 'tcx>,
                               lvalue: &mir::Lvalue<'tcx>,
                               intrinsic: base::Lifetime)
-                              -> BlockAndBuilder<'bcx, 'tcx> {
+                              -> BlockAndBuilder<'a, 'tcx> {
         if let mir::Lvalue::Local(index) = *lvalue {
             if let LocalRef::Lvalue(tr_lval) = self.locals[index] {
                 intrinsic.call(&bcx, tr_lval.llval);
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 214eaeb817f..6e0d8d08e70 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -184,15 +184,14 @@ impl<'a, 'tcx> TransItem<'tcx> {
                            linkage: llvm::Linkage,
                            symbol_name: &str) {
         let tcx = ccx.tcx();
-        assert_eq!(dg.ty(), glue::get_drop_glue_type(tcx, dg.ty()));
+        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(tcx.types.i8)), tcx.mk_nil(), false);
+        let sig = tcx.mk_fn_sig(iter::once(tcx.mk_mut_ptr(t)), tcx.mk_nil(), false);
 
-        // Create a FnType for fn(*mut i8) and substitute the real type in
-        // later - that prevents FnType from splitting fat pointers up.
-        let mut fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
-        fn_ty.args[0].original_ty = type_of::type_of(ccx, t).ptr_to();
+        debug!("predefine_drop_glue: sig={}", sig);
+
+        let fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
         let llfnty = fn_ty.llvm_type(ccx);
 
         assert!(declare::get_defined_value(ccx, symbol_name).is_none());
diff --git a/src/librustc_trans/tvec.rs b/src/librustc_trans/tvec.rs
index cf897fc5a15..c09726fda08 100644
--- a/src/librustc_trans/tvec.rs
+++ b/src/librustc_trans/tvec.rs
@@ -8,56 +8,46 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_camel_case_types)]
-
 use llvm;
 use llvm::ValueRef;
-use base::*;
-use build::*;
 use common::*;
-use debuginfo::DebugLoc;
 use rustc::ty::Ty;
 
-pub fn slice_for_each<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
-                                     data_ptr: ValueRef,
-                                     unit_ty: Ty<'tcx>,
-                                     len: ValueRef,
-                                     f: F)
-                                     -> Block<'blk, 'tcx> where
-    F: FnOnce(Block<'blk, 'tcx>, ValueRef) -> Block<'blk, 'tcx>,
-{
-    let _icx = push_ctxt("tvec::slice_for_each");
-    let fcx = bcx.fcx;
-
+pub fn slice_for_each<'a, 'tcx, F>(
+    bcx: &BlockAndBuilder<'a, 'tcx>,
+    data_ptr: ValueRef,
+    unit_ty: Ty<'tcx>,
+    len: ValueRef,
+    f: F
+) -> BlockAndBuilder<'a, 'tcx> where F: FnOnce(&BlockAndBuilder<'a, 'tcx>, ValueRef) {
     // Special-case vectors with elements of size 0  so they don't go out of bounds (#9890)
-    let zst = type_is_zero_size(bcx.ccx(), unit_ty);
-    let add = |bcx, a, b| if zst {
-        Add(bcx, a, b, DebugLoc::None)
+    let zst = type_is_zero_size(bcx.ccx, unit_ty);
+    let add = |bcx: &BlockAndBuilder, a, b| if zst {
+        bcx.add(a, b)
     } else {
-        InBoundsGEP(bcx, a, &[b])
+        bcx.inbounds_gep(a, &[b])
     };
 
-    let header_bcx = fcx.new_block("slice_loop_header");
-    let body_bcx = fcx.new_block("slice_loop_body");
-    let next_bcx = fcx.new_block("slice_loop_next");
+    let body_bcx = bcx.fcx().build_new_block("slice_loop_body");
+    let next_bcx = bcx.fcx().build_new_block("slice_loop_next");
+    let header_bcx = bcx.fcx().build_new_block("slice_loop_header");
 
     let start = if zst {
-        C_uint(bcx.ccx(), 0 as usize)
+        C_uint(bcx.ccx, 0usize)
     } else {
         data_ptr
     };
-    let end = add(bcx, start, len);
+    let end = add(&bcx, start, len);
 
-    Br(bcx, header_bcx.llbb, DebugLoc::None);
-    let current = Phi(header_bcx, val_ty(start), &[start], &[bcx.llbb]);
+    bcx.br(header_bcx.llbb());
+    let current = header_bcx.phi(val_ty(start), &[start], &[bcx.llbb()]);
 
-    let keep_going =
-        ICmp(header_bcx, llvm::IntNE, current, end, DebugLoc::None);
-    CondBr(header_bcx, keep_going, body_bcx.llbb, next_bcx.llbb, DebugLoc::None);
+    let keep_going = header_bcx.icmp(llvm::IntNE, current, end);
+    header_bcx.cond_br(keep_going, body_bcx.llbb(), next_bcx.llbb());
 
-    let body_bcx = f(body_bcx, if zst { data_ptr } else { current });
-    let next = add(body_bcx, current, C_uint(bcx.ccx(), 1usize));
-    AddIncomingToPhi(current, next, body_bcx.llbb);
-    Br(body_bcx, header_bcx.llbb, DebugLoc::None);
+    f(&body_bcx, if zst { data_ptr } else { current });
+    let next = add(&body_bcx, current, C_uint(bcx.ccx, 1usize));
+    header_bcx.add_incoming_to_phi(current, next, body_bcx.llbb());
+    body_bcx.br(header_bcx.llbb());
     next_bcx
 }
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index 22c405fe254..469214b466e 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_camel_case_types)]
-
 use abi::FnType;
 use adt;
 use common::*;
@@ -41,7 +39,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
     let _recursion_lock = cx.enter_type_of(t);
 
     let llsizingty = match t.sty {
-        _ if !type_is_sized(cx.tcx(), t) => {
+        _ if !cx.shared().type_is_sized(t) => {
             Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, t)], false)
         }
 
@@ -55,7 +53,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
         ty::TyBox(ty) |
         ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
         ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => {
-            if type_is_sized(cx.tcx(), ty) {
+            if cx.shared().type_is_sized(ty) {
                 Type::i8p(cx)
             } else {
                 Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, ty)], false)
@@ -104,7 +102,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
 
     // FIXME(eddyb) Temporary sanity check for ty::layout.
     let layout = cx.layout_of(t);
-    if !type_is_sized(cx.tcx(), t) {
+    if !cx.shared().type_is_sized(t) {
         if !layout.is_unsized() {
             bug!("layout should be unsized for type `{}` / {:#?}",
                  t, layout);
@@ -135,7 +133,7 @@ pub fn fat_ptr_base_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) ->
     match ty.sty {
         ty::TyBox(t) |
         ty::TyRef(_, ty::TypeAndMut { ty: t, .. }) |
-        ty::TyRawPtr(ty::TypeAndMut { ty: t, .. }) if !type_is_sized(ccx.tcx(), t) => {
+        ty::TyRawPtr(ty::TypeAndMut { ty: t, .. }) if !ccx.shared().type_is_sized(t) => {
             in_memory_type_of(ccx, t).ptr_to()
         }
         _ => bug!("expected fat ptr ty but got {:?}", ty)
@@ -172,7 +170,7 @@ pub fn immediate_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
 /// is too large for it to be placed in SSA value (by our rules).
 /// For the raw type without far pointer indirection, see `in_memory_type_of`.
 pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
-    let ty = if !type_is_sized(cx.tcx(), ty) {
+    let ty = if !cx.shared().type_is_sized(ty) {
         cx.tcx().mk_imm_ptr(ty)
     } else {
         ty
@@ -232,7 +230,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
       ty::TyBox(ty) |
       ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
       ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => {
-          if !type_is_sized(cx.tcx(), ty) {
+          if !cx.shared().type_is_sized(ty) {
               if let ty::TyStr = ty.sty {
                   // This means we get a nicer name in the output (str is always
                   // unsized).
diff --git a/src/librustc_trans/value.rs b/src/librustc_trans/value.rs
index 79e0c11515f..287ad87caac 100644
--- a/src/librustc_trans/value.rs
+++ b/src/librustc_trans/value.rs
@@ -9,16 +9,11 @@
 // except according to those terms.
 
 use llvm;
-use llvm::{UseRef, ValueRef};
-use basic_block::BasicBlock;
-use common::Block;
 
 use std::fmt;
 
-use libc::c_uint;
-
 #[derive(Copy, Clone, PartialEq)]
-pub struct Value(pub ValueRef);
+pub struct Value(pub llvm::ValueRef);
 
 impl fmt::Debug for Value {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -27,152 +22,3 @@ impl fmt::Debug for Value {
         }).expect("nun-UTF8 value description from LLVM"))
     }
 }
-
-macro_rules! opt_val { ($e:expr) => (
-    unsafe {
-        match $e {
-            p if !p.is_null() => Some(Value(p)),
-            _ => None
-        }
-    }
-) }
-
-/// Wrapper for LLVM ValueRef
-impl Value {
-    /// Returns the native ValueRef
-    pub fn get(&self) -> ValueRef {
-        let Value(v) = *self; v
-    }
-
-    /// Returns the BasicBlock that contains this value
-    pub fn get_parent(self) -> Option<BasicBlock> {
-        unsafe {
-            match llvm::LLVMGetInstructionParent(self.get()) {
-                p if !p.is_null() => Some(BasicBlock(p)),
-                _ => None
-            }
-        }
-    }
-
-    /// Removes this value from its containing BasicBlock
-    pub fn erase_from_parent(self) {
-        unsafe {
-            llvm::LLVMInstructionEraseFromParent(self.get());
-        }
-    }
-
-    /// Returns the single dominating store to this value, if any
-    /// This only performs a search for a trivially dominating store. The store
-    /// must be the only user of this value, and there must not be any conditional
-    /// branches between the store and the given block.
-    pub fn get_dominating_store(self, bcx: Block) -> Option<Value> {
-        match self.get_single_user().and_then(|user| user.as_store_inst()) {
-            Some(store) => {
-                store.get_parent().and_then(|store_bb| {
-                    let mut bb = BasicBlock(bcx.llbb);
-                    let mut ret = Some(store);
-                    while bb.get() != store_bb.get() {
-                        match bb.get_single_predecessor() {
-                            Some(pred) => bb = pred,
-                            None => { ret = None; break }
-                        }
-                    }
-                    ret
-                })
-            }
-            _ => None
-        }
-    }
-
-    /// Returns the first use of this value, if any
-    pub fn get_first_use(self) -> Option<Use> {
-        unsafe {
-            match llvm::LLVMGetFirstUse(self.get()) {
-                u if !u.is_null() => Some(Use(u)),
-                _ => None
-            }
-        }
-    }
-
-    /// Tests if there are no uses of this value
-    pub fn has_no_uses(self) -> bool {
-        self.get_first_use().is_none()
-    }
-
-    /// Returns the single user of this value
-    /// If there are no users or multiple users, this returns None
-    pub fn get_single_user(self) -> Option<Value> {
-        let mut iter = self.user_iter();
-        match (iter.next(), iter.next()) {
-            (Some(first), None) => Some(first),
-            _ => None
-        }
-    }
-
-    /// Returns an iterator for the users of this value
-    pub fn user_iter(self) -> Users {
-        Users {
-            next: self.get_first_use()
-        }
-    }
-
-    /// Returns the requested operand of this instruction
-    /// Returns None, if there's no operand at the given index
-    pub fn get_operand(self, i: usize) -> Option<Value> {
-        opt_val!(llvm::LLVMGetOperand(self.get(), i as c_uint))
-    }
-
-    /// Returns the Store represent by this value, if any
-    pub fn as_store_inst(self) -> Option<Value> {
-        opt_val!(llvm::LLVMIsAStoreInst(self.get()))
-    }
-
-    /// Tests if this value is a terminator instruction
-    pub fn is_a_terminator_inst(self) -> bool {
-        unsafe {
-            !llvm::LLVMIsATerminatorInst(self.get()).is_null()
-        }
-    }
-}
-
-/// Wrapper for LLVM UseRef
-#[derive(Copy, Clone)]
-pub struct Use(UseRef);
-
-impl Use {
-    pub fn get(&self) -> UseRef {
-        let Use(v) = *self; v
-    }
-
-    pub fn get_user(self) -> Value {
-        unsafe {
-            Value(llvm::LLVMGetUser(self.get()))
-        }
-    }
-
-    pub fn get_next_use(self) -> Option<Use> {
-        unsafe {
-            match llvm::LLVMGetNextUse(self.get()) {
-                u if !u.is_null() => Some(Use(u)),
-                _ => None
-            }
-        }
-    }
-}
-
-/// Iterator for the users of a value
-pub struct Users {
-    next: Option<Use>
-}
-
-impl Iterator for Users {
-    type Item = Value;
-
-    fn next(&mut self) -> Option<Value> {
-        let current = self.next;
-
-        self.next = current.and_then(|u| u.get_next_use());
-
-        current.map(|u| u.get_user())
-    }
-}
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 71270963f80..598003a3925 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1519,14 +1519,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 self.set_tainted_by_errors();
                 return self.tcx().types.err;
             }
-            _ => {
-                struct_span_err!(tcx.sess, span, E0248,
-                           "found value `{}` used as a type",
-                            tcx.item_path_str(path.def.def_id()))
-                           .span_label(span, &format!("value used as a type"))
-                           .emit();
-                return self.tcx().types.err;
-            }
+            _ => span_bug!(span, "unexpected definition: {:?}", path.def)
         }
     }
 
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 624201eaab6..ff50ee11b39 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -481,7 +481,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     } else {
                         (result_ty, arm_ty)
                     };
-                    self.report_mismatched_types(&cause, expected, found, e);
+                    self.report_mismatched_types(&cause, expected, found, e).emit();
                     self.tcx.types.err
                 }
             };
diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs
index e72dba858c5..b4647df3f4f 100644
--- a/src/librustc_typeck/check/autoderef.rs
+++ b/src/librustc_typeck/check/autoderef.rs
@@ -131,10 +131,18 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
         Some(self.fcx.resolve_type_vars_if_possible(&normalized.value))
     }
 
+    /// Returns the final type, generating an error if it is an
+    /// unresolved inference variable.
     pub fn unambiguous_final_ty(&self) -> Ty<'tcx> {
         self.fcx.structurally_resolved_type(self.span, self.cur_ty)
     }
 
+    /// Returns the final type we ended up with, which may well be an
+    /// inference variable (we will resolve it first, if possible).
+    pub fn maybe_ambiguous_final_ty(&self) -> Ty<'tcx> {
+        self.fcx.resolve_type_vars_if_possible(&self.cur_ty)
+    }
+
     pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I)
         where I: IntoIterator<Item = &'b hir::Expr>
     {
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index f2c8ef46a7e..265dcada1f8 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -142,20 +142,21 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
     fn report_cast_error(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, e: CastError) {
         match e {
             CastError::NeedDeref => {
+                let error_span = self.span;
                 let cast_ty = fcx.ty_to_string(self.cast_ty);
-                let mut err = fcx.type_error_struct(self.cast_span,
+                let mut err = fcx.type_error_struct(error_span,
                                        |actual| {
                                            format!("casting `{}` as `{}` is invalid",
                                                    actual,
                                                    cast_ty)
                                        },
                                        self.expr_ty);
-                err.span_label(self.expr.span,
+                err.span_label(error_span,
                                &format!("cannot cast `{}` as `{}`",
                                         fcx.ty_to_string(self.expr_ty),
                                         cast_ty));
                 if let Ok(snippet) = fcx.sess().codemap().span_to_snippet(self.expr.span) {
-                    err.span_label(self.expr.span,
+                    err.span_help(self.expr.span,
                                    &format!("did you mean `*{}`?", snippet));
                 }
                 err.emit();
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index ef1c08bdab5..393d9341a08 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -14,8 +14,13 @@ use rustc::ty::Ty;
 use rustc::infer::{InferOk};
 use rustc::traits::ObligationCause;
 
-use syntax_pos::Span;
+use syntax::ast;
+use syntax_pos::{self, Span};
 use rustc::hir;
+use rustc::hir::def::Def;
+use rustc::ty::{self, AssociatedItem};
+
+use super::method::probe;
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     // Requires that the two types unify, and prints an error message if
@@ -27,7 +32,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.register_predicates(obligations);
             },
             Err(e) => {
-                self.report_mismatched_types(&cause, expected, actual, e);
+                self.report_mismatched_types(&cause, expected, actual, e).emit();
             }
         }
     }
@@ -46,7 +51,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.register_predicates(obligations);
             },
             Err(e) => {
-                self.report_mismatched_types(cause, expected, actual, e);
+                self.report_mismatched_types(cause, expected, actual, e).emit();
             }
         }
     }
@@ -57,7 +62,65 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         if let Err(e) = self.try_coerce(expr, checked_ty, expected) {
             let cause = self.misc(expr.span);
             let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
-            self.report_mismatched_types(&cause, expected, expr_ty, e);
+            let mode = probe::Mode::MethodCall;
+            let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
+                                                         mode,
+                                                         expected,
+                                                         checked_ty,
+                                                         ast::DUMMY_NODE_ID);
+            let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
+            if suggestions.len() > 0 {
+                err.help(&format!("here are some functions which \
+                                   might fulfill your needs:\n - {}",
+                                  self.get_best_match(&suggestions)));
+            };
+            err.emit();
+        }
+    }
+
+    fn format_method_suggestion(&self, method: &AssociatedItem) -> String {
+        format!(".{}({})",
+                method.name,
+                if self.has_no_input_arg(method) {
+                    ""
+                } else {
+                    "..."
+                })
+    }
+
+    fn display_suggested_methods(&self, methods: &[AssociatedItem]) -> String {
+        methods.iter()
+               .take(5)
+               .map(|method| self.format_method_suggestion(&*method))
+               .collect::<Vec<String>>()
+               .join("\n - ")
+    }
+
+    fn get_best_match(&self, methods: &[AssociatedItem]) -> String {
+        let no_argument_methods: Vec<_> =
+            methods.iter()
+                   .filter(|ref x| self.has_no_input_arg(&*x))
+                   .map(|x| x.clone())
+                   .collect();
+        if no_argument_methods.len() > 0 {
+            self.display_suggested_methods(&no_argument_methods)
+        } else {
+            self.display_suggested_methods(&methods)
+        }
+    }
+
+    // This function checks if the method isn't static and takes other arguments than `self`.
+    fn has_no_input_arg(&self, method: &AssociatedItem) -> bool {
+        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
+                    }
+                    _ => false,
+                }
+            }
+            _ => false,
         }
     }
 }
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index b29eab780e0..9b8e77301e5 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -30,9 +30,11 @@ pub use self::CandidateSource::*;
 pub use self::suggest::AllTraitsVec;
 
 mod confirm;
-mod probe;
+pub mod probe;
 mod suggest;
 
+use self::probe::IsSuggestion;
+
 pub enum MethodError<'tcx> {
     // Did not find an applicable method, but we did find various near-misses that may work.
     NoMatch(NoMatchData<'tcx>),
@@ -91,7 +93,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                          allow_private: bool)
                          -> bool {
         let mode = probe::Mode::MethodCall;
-        match self.probe_method(span, mode, method_name, self_ty, call_expr_id) {
+        match self.probe_for_name(span, mode, method_name, IsSuggestion(false),
+                                  self_ty, call_expr_id) {
             Ok(..) => true,
             Err(NoMatch(..)) => false,
             Err(Ambiguity(..)) => true,
@@ -130,7 +133,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         let mode = probe::Mode::MethodCall;
         let self_ty = self.resolve_type_vars_if_possible(&self_ty);
-        let pick = self.probe_method(span, mode, method_name, self_ty, call_expr.id)?;
+        let pick = self.probe_for_name(span, mode, method_name, IsSuggestion(false),
+                                       self_ty, call_expr.id)?;
 
         if let Some(import_id) = pick.import_id {
             self.tcx.used_trait_imports.borrow_mut().insert(import_id);
@@ -328,7 +332,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         expr_id: ast::NodeId)
                         -> Result<Def, MethodError<'tcx>> {
         let mode = probe::Mode::Path;
-        let pick = self.probe_method(span, mode, method_name, self_ty, expr_id)?;
+        let pick = self.probe_for_name(span, mode, method_name, IsSuggestion(false),
+                                       self_ty, expr_id)?;
 
         if let Some(import_id) = pick.import_id {
             self.tcx.used_trait_imports.borrow_mut().insert(import_id);
@@ -339,7 +344,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.tcx.check_stability(def.def_id(), expr_id, span);
 
         if let probe::InherentImplPick = pick.kind {
-            if !pick.item.vis.is_accessible_from(self.body_id, &self.tcx.map) {
+            if !self.tcx.vis_is_accessible_from(pick.item.vis, self.body_id) {
                 let msg = format!("{} `{}` is private", def.kind_name(), method_name);
                 self.tcx.sess.span_err(span, &msg);
             }
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 5cb0804b1bc..1962534c397 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -16,12 +16,12 @@ use super::suggest;
 use check::FnCtxt;
 use hir::def_id::DefId;
 use hir::def::Def;
-use rustc::infer::InferOk;
 use rustc::ty::subst::{Subst, Substs};
 use rustc::traits::{self, ObligationCause};
 use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable};
 use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::util::nodemap::FxHashSet;
+use rustc::infer::{self, InferOk};
 use syntax::ast;
 use syntax_pos::Span;
 use rustc::hir;
@@ -32,11 +32,24 @@ use std::rc::Rc;
 use self::CandidateKind::*;
 pub use self::PickKind::*;
 
+pub enum LookingFor<'tcx> {
+    /// looking for methods with the given name; this is the normal case
+    MethodName(ast::Name),
+
+    /// looking for methods that return a given type; this is used to
+    /// assemble suggestions
+    ReturnType(Ty<'tcx>),
+}
+
+/// Boolean flag used to indicate if this search is for a suggestion
+/// or not.  If true, we can allow ambiguity and so forth.
+pub struct IsSuggestion(pub bool);
+
 struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
     span: Span,
     mode: Mode,
-    item_name: ast::Name,
+    looking_for: LookingFor<'tcx>,
     steps: Rc<Vec<CandidateStep<'tcx>>>,
     opt_simplified_steps: Option<Vec<ty::fast_reject::SimplifiedType>>,
     inherent_candidates: Vec<Candidate<'tcx>>,
@@ -144,18 +157,72 @@ pub enum Mode {
 }
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    pub fn probe_method(&self,
-                        span: Span,
-                        mode: Mode,
-                        item_name: ast::Name,
-                        self_ty: Ty<'tcx>,
-                        scope_expr_id: ast::NodeId)
-                        -> PickResult<'tcx> {
+    /// This is used to offer suggestions to users. It returns methods
+    /// that could have been called which have the desired return
+    /// type. Some effort is made to rule out methods that, if called,
+    /// would result in an error (basically, the same criteria we
+    /// would use to decide if a method is a plausible fit for
+    /// ambiguity purposes).
+    pub fn probe_for_return_type(&self,
+                                 span: Span,
+                                 mode: Mode,
+                                 return_type: Ty<'tcx>,
+                                 self_ty: Ty<'tcx>,
+                                 scope_expr_id: ast::NodeId)
+                                 -> Vec<ty::AssociatedItem> {
+        debug!("probe(self_ty={:?}, return_type={}, scope_expr_id={})",
+               self_ty,
+               return_type,
+               scope_expr_id);
+        let method_names =
+            self.probe_op(span, mode, LookingFor::ReturnType(return_type), IsSuggestion(true),
+                          self_ty, scope_expr_id,
+                          |probe_cx| Ok(probe_cx.candidate_method_names()))
+                .unwrap_or(vec![]);
+        method_names
+            .iter()
+            .flat_map(|&method_name| {
+                match self.probe_for_name(span, mode, method_name, IsSuggestion(true), self_ty,
+                                          scope_expr_id) {
+                    Ok(pick) => Some(pick.item),
+                    Err(_) => None,
+                }
+            })
+            .collect()
+    }
+
+    pub fn probe_for_name(&self,
+                          span: Span,
+                          mode: Mode,
+                          item_name: ast::Name,
+                          is_suggestion: IsSuggestion,
+                          self_ty: Ty<'tcx>,
+                          scope_expr_id: ast::NodeId)
+                          -> PickResult<'tcx> {
         debug!("probe(self_ty={:?}, item_name={}, scope_expr_id={})",
                self_ty,
                item_name,
                scope_expr_id);
+        self.probe_op(span,
+                      mode,
+                      LookingFor::MethodName(item_name),
+                      is_suggestion,
+                      self_ty,
+                      scope_expr_id,
+                      |probe_cx| probe_cx.pick())
+    }
 
+    fn probe_op<OP,R>(&'a self,
+                      span: Span,
+                      mode: Mode,
+                      looking_for: LookingFor<'tcx>,
+                      is_suggestion: IsSuggestion,
+                      self_ty: Ty<'tcx>,
+                      scope_expr_id: ast::NodeId,
+                      op: OP)
+                      -> Result<R, MethodError<'tcx>>
+        where OP: FnOnce(ProbeContext<'a, 'gcx, 'tcx>) -> Result<R, MethodError<'tcx>>
+    {
         // FIXME(#18741) -- right now, creating the steps involves evaluating the
         // `*` operator, which registers obligations that then escape into
         // the global fulfillment context and thus has global
@@ -164,7 +231,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // think cause spurious errors. Really though this part should
         // take place in the `self.probe` below.
         let steps = if mode == Mode::MethodCall {
-            match self.create_steps(span, self_ty) {
+            match self.create_steps(span, self_ty, is_suggestion) {
                 Some(steps) => steps,
                 None => {
                     return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(),
@@ -207,14 +274,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // that we create during the probe process are removed later
         self.probe(|_| {
             let mut probe_cx =
-                ProbeContext::new(self, span, mode, item_name, steps, opt_simplified_steps);
+                ProbeContext::new(self, span, mode, looking_for,
+                                  steps, opt_simplified_steps);
             probe_cx.assemble_inherent_candidates();
             probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)?;
-            probe_cx.pick()
+            op(probe_cx)
         })
     }
 
-    fn create_steps(&self, span: Span, self_ty: Ty<'tcx>) -> Option<Vec<CandidateStep<'tcx>>> {
+    fn create_steps(&self,
+                    span: Span,
+                    self_ty: Ty<'tcx>,
+                    is_suggestion: IsSuggestion)
+                    -> Option<Vec<CandidateStep<'tcx>>> {
         // FIXME: we don't need to create the entire steps in one pass
 
         let mut autoderef = self.autoderef(span, self_ty);
@@ -228,8 +300,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             })
             .collect();
 
-        let final_ty = autoderef.unambiguous_final_ty();
+        let final_ty = autoderef.maybe_ambiguous_final_ty();
         match final_ty.sty {
+            ty::TyInfer(ty::TyVar(_)) => {
+                // Ended in an inference variable. If we are doing
+                // a real method lookup, this is a hard error (it's an
+                // ambiguity and we can't make progress).
+                if !is_suggestion.0 {
+                    let t = self.structurally_resolved_type(span, final_ty);
+                    assert_eq!(t, self.tcx.types.err);
+                    return None
+                } else {
+                    // If we're just looking for suggestions,
+                    // though, ambiguity is no big thing, we can
+                    // just ignore it.
+                }
+            }
             ty::TyArray(elem_ty, _) => {
                 let dereferences = steps.len() - 1;
 
@@ -253,7 +339,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
            span: Span,
            mode: Mode,
-           item_name: ast::Name,
+           looking_for: LookingFor<'tcx>,
            steps: Vec<CandidateStep<'tcx>>,
            opt_simplified_steps: Option<Vec<ty::fast_reject::SimplifiedType>>)
            -> ProbeContext<'a, 'gcx, 'tcx> {
@@ -261,7 +347,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
             fcx: fcx,
             span: span,
             mode: mode,
-            item_name: item_name,
+            looking_for: looking_for,
             inherent_candidates: Vec::new(),
             extension_candidates: Vec::new(),
             impl_dups: FxHashSet(),
@@ -410,44 +496,40 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
         debug!("assemble_inherent_impl_probe {:?}", impl_def_id);
 
-        let item = match self.associated_item(impl_def_id) {
-            Some(m) => m,
-            None => {
-                return;
-            } // No method with correct name on this impl
-        };
+        for item in self.impl_or_trait_item(impl_def_id) {
+            if !self.has_applicable_self(&item) {
+                // No receiver declared. Not a candidate.
+                self.record_static_candidate(ImplSource(impl_def_id));
+                continue
+            }
 
-        if !self.has_applicable_self(&item) {
-            // No receiver declared. Not a candidate.
-            return self.record_static_candidate(ImplSource(impl_def_id));
-        }
+            if !self.tcx.vis_is_accessible_from(item.vis, self.body_id) {
+                self.private_candidate = Some(item.def());
+                continue
+            }
 
-        if !item.vis.is_accessible_from(self.body_id, &self.tcx.map) {
-            self.private_candidate = Some(item.def());
-            return;
-        }
+            let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
+            let impl_ty = impl_ty.subst(self.tcx, impl_substs);
 
-        let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
-        let impl_ty = impl_ty.subst(self.tcx, impl_substs);
-
-        // Determine the receiver type that the method itself expects.
-        let xform_self_ty = self.xform_self_ty(&item, impl_ty, impl_substs);
-
-        // We can't use normalize_associated_types_in as it will pollute the
-        // fcx's fulfillment context after this probe is over.
-        let cause = traits::ObligationCause::misc(self.span, self.body_id);
-        let mut selcx = &mut traits::SelectionContext::new(self.fcx);
-        let traits::Normalized { value: xform_self_ty, obligations } =
-            traits::normalize(selcx, cause, &xform_self_ty);
-        debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}",
-               xform_self_ty);
-
-        self.inherent_candidates.push(Candidate {
-            xform_self_ty: xform_self_ty,
-            item: item,
-            kind: InherentImplCandidate(impl_substs, obligations),
-            import_id: self.import_id,
-        });
+            // Determine the receiver type that the method itself expects.
+            let xform_self_ty = self.xform_self_ty(&item, impl_ty, impl_substs);
+
+            // We can't use normalize_associated_types_in as it will pollute the
+            // fcx's fulfillment context after this probe is over.
+            let cause = traits::ObligationCause::misc(self.span, self.body_id);
+            let mut selcx = &mut traits::SelectionContext::new(self.fcx);
+            let traits::Normalized { value: xform_self_ty, obligations } =
+                traits::normalize(selcx, cause, &xform_self_ty);
+            debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}",
+                   xform_self_ty);
+
+            self.inherent_candidates.push(Candidate {
+                xform_self_ty: xform_self_ty,
+                item: item,
+                kind: InherentImplCandidate(impl_substs, obligations),
+                import_id: self.import_id,
+            });
+        }
     }
 
     fn assemble_inherent_candidates_from_object(&mut self,
@@ -540,17 +622,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
         let tcx = self.tcx;
         for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
-            let item = match self.associated_item(bound_trait_ref.def_id()) {
-                Some(v) => v,
-                None => {
-                    continue;
+            for item in self.impl_or_trait_item(bound_trait_ref.def_id()) {
+                if !self.has_applicable_self(&item) {
+                    self.record_static_candidate(TraitSource(bound_trait_ref.def_id()));
+                } else {
+                    mk_cand(self, bound_trait_ref, item);
                 }
-            };
-
-            if !self.has_applicable_self(&item) {
-                self.record_static_candidate(TraitSource(bound_trait_ref.def_id()));
-            } else {
-                mk_cand(self, bound_trait_ref, item);
             }
         }
     }
@@ -584,36 +661,45 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         Ok(())
     }
 
+    pub fn matches_return_type(&self, method: &ty::AssociatedItem,
+                               expected: ty::Ty<'tcx>) -> bool {
+        match method.def() {
+            Def::Method(def_id) => {
+                let fty = self.tcx.item_type(def_id).fn_sig();
+                self.probe(|_| {
+                    let substs = self.fresh_substs_for_item(self.span, method.def_id);
+                    let output = fty.output().subst(self.tcx, substs);
+                    let (output, _) = self.replace_late_bound_regions_with_fresh_var(
+                        self.span, infer::FnCall, &output);
+                    self.can_sub_types(output, expected).is_ok()
+                })
+            }
+            _ => false,
+        }
+    }
+
     fn assemble_extension_candidates_for_trait(&mut self,
                                                trait_def_id: DefId)
                                                -> Result<(), MethodError<'tcx>> {
         debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})",
                trait_def_id);
 
-        // Check whether `trait_def_id` defines a method with suitable name:
-        let maybe_item = self.tcx.associated_items(trait_def_id)
-                             .find(|item| item.name == self.item_name);
-        let item = match maybe_item {
-            Some(i) => i,
-            None => {
-                return Ok(());
+        for item in self.impl_or_trait_item(trait_def_id) {
+            // Check whether `trait_def_id` defines a method with suitable name:
+            if !self.has_applicable_self(&item) {
+                debug!("method has inapplicable self");
+                self.record_static_candidate(TraitSource(trait_def_id));
+                continue;
             }
-        };
 
-        // Check whether `trait_def_id` defines a method with suitable name:
-        if !self.has_applicable_self(&item) {
-            debug!("method has inapplicable self");
-            self.record_static_candidate(TraitSource(trait_def_id));
-            return Ok(());
-        }
+            self.assemble_extension_candidates_for_trait_impls(trait_def_id, item.clone());
 
-        self.assemble_extension_candidates_for_trait_impls(trait_def_id, item.clone());
+            self.assemble_closure_candidates(trait_def_id, item.clone())?;
 
-        self.assemble_closure_candidates(trait_def_id, item.clone())?;
+            self.assemble_projection_candidates(trait_def_id, item.clone());
 
-        self.assemble_projection_candidates(trait_def_id, item.clone());
-
-        self.assemble_where_clause_candidates(trait_def_id, item.clone());
+            self.assemble_where_clause_candidates(trait_def_id, item.clone());
+        }
 
         Ok(())
     }
@@ -833,10 +919,30 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         }
     }
 
+    fn candidate_method_names(&self) -> Vec<ast::Name> {
+        let mut set = FxHashSet();
+        let mut names: Vec<_> =
+            self.inherent_candidates
+                .iter()
+                .chain(&self.extension_candidates)
+                .map(|candidate| candidate.item.name)
+                .filter(|&name| set.insert(name))
+                .collect();
+
+        // sort them by the name so we have a stable result
+        names.sort_by_key(|n| n.as_str());
+        names
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // THE ACTUAL SEARCH
 
     fn pick(mut self) -> PickResult<'tcx> {
+        assert!(match self.looking_for {
+            LookingFor::MethodName(_) => true,
+            LookingFor::ReturnType(_) => false,
+        });
+
         if let Some(r) = self.pick_core() {
             return r;
         }
@@ -855,6 +961,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
         let out_of_scope_traits = match self.pick_core() {
             Some(Ok(p)) => vec![p.item.container.id()],
+            //Some(Ok(p)) => p.iter().map(|p| p.item.container().id()).collect(),
             Some(Err(MethodError::Ambiguity(v))) => {
                 v.into_iter()
                     .map(|source| {
@@ -1257,10 +1364,20 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         self.tcx.erase_late_bound_regions(value)
     }
 
-    /// Find item with name `item_name` defined in impl/trait `def_id`
-    /// and return it, or `None`, if no such item was defined there.
-    fn associated_item(&self, def_id: DefId) -> Option<ty::AssociatedItem> {
-        self.fcx.associated_item(def_id, self.item_name)
+    /// Find the method with the appropriate name (or return type, as the case may be).
+    fn impl_or_trait_item(&self, def_id: DefId) -> Vec<ty::AssociatedItem> {
+        match self.looking_for {
+            LookingFor::MethodName(name) => {
+                self.fcx.associated_item(def_id, name).map_or(Vec::new(), |x| vec![x])
+            }
+            LookingFor::ReturnType(return_ty) => {
+                self.tcx
+                    .associated_items(def_id)
+                    .map(|did| self.tcx.associated_item(did.def_id))
+                    .filter(|m| self.matches_return_type(m, return_ty))
+                    .collect()
+            }
+        }
     }
 }
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 58dff935a16..a2dceed8d26 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2986,7 +2986,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             }
             Err(e) => {
-                self.report_mismatched_types(&cause, expected_ty, found_ty, e);
+                self.report_mismatched_types(&cause, expected_ty, found_ty, e).emit();
                 self.tcx.types.err
             }
         }
@@ -3009,7 +3009,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     debug!("struct named {:?}",  base_t);
                     if let Some(field) = base_def.struct_variant().find_field_named(field.node) {
                         let field_ty = self.field_ty(expr.span, field, substs);
-                        if field.vis.is_accessible_from(self.body_id, &self.tcx().map) {
+                        if self.tcx.vis_is_accessible_from(field.vis, self.body_id) {
                             autoderef.finalize(lvalue_pref, Some(base));
                             self.write_autoderef_adjustment(base.id, autoderefs, base_t);
 
@@ -3116,7 +3116,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     base_def.struct_variant().fields.get(idx.node).and_then(|field| {
                         let field_ty = self.field_ty(expr.span, field, substs);
                         private_candidate = Some((base_def.did, field_ty));
-                        if field.vis.is_accessible_from(self.body_id, &self.tcx().map) {
+                        if self.tcx.vis_is_accessible_from(field.vis, self.body_id) {
                             self.tcx.check_stability(field.did, expr.id, expr.span);
                             Some(field_ty)
                         } else {
@@ -3697,7 +3697,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 match result {
                     Ok(ty) => ctxt.unified = ty,
                     Err(err) => {
-                        self.report_mismatched_types(&cause, ctxt.unified, e_ty, err);
+                        self.report_mismatched_types(&cause, ctxt.unified, e_ty, err).emit();
                     }
                 }
 
@@ -3880,7 +3880,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 match result {
                     Ok(ty) => unified = ty,
                     Err(e) => {
-                        self.report_mismatched_types(&cause, unified, e_ty, e);
+                        self.report_mismatched_types(&cause, unified, e_ty, e).emit();
                     }
                 }
             }
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index f575d4d8bab..0e5a16987c1 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -356,7 +356,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
                         infcx.report_mismatched_types(&cause,
                                                       mk_ptr(mt_b.ty),
                                                       target,
-                                                      ty::error::TypeError::Mutability);
+                                                      ty::error::TypeError::Mutability).emit();
                     }
                     (mt_a.ty, mt_b.ty, unsize_trait, None)
                 };
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 71507063ffc..cea3ad43a95 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -1378,8 +1378,8 @@ let x = |_| {}; // error: cannot determine a type for this expression
 
 You have two possibilities to solve this situation:
 
- * Give an explicit definition of the expression
- * Infer the expression
+* Give an explicit definition of the expression
+* Infer the expression
 
 Examples:
 
@@ -2861,25 +2861,6 @@ struct Bar<S, T> { x: Foo<S, T> }
 ```
 "##,
 
-E0248: r##"
-This error indicates an attempt to use a value where a type is expected. For
-example:
-
-```compile_fail,E0248
-enum Foo {
-    Bar(u32)
-}
-
-fn do_something(x: Foo::Bar) { }
-```
-
-In this example, we're attempting to take a type of `Foo::Bar` in the
-do_something function. This is not legal: `Foo::Bar` is a value of type `Foo`,
-not a distinct static type. Likewise, it's not legal to attempt to
-`impl Foo::Bar`: instead, you must `impl Foo` and then pattern match to specify
-behavior for specific enum variants.
-"##,
-
 E0569: r##"
 If an impl has a generic parameter with the `#[may_dangle]` attribute, then
 that impl must be declared as an `unsafe impl. For example:
@@ -4247,6 +4228,7 @@ register_diagnostics! {
     E0245, // not a trait
 //  E0246, // invalid recursive type
 //  E0247,
+//  E0248, // value used as a type, now reported earlier during resolution as E0412
 //  E0249,
 //  E0319, // trait impls for defaulted traits allowed just for structs/enums
     E0320, // recursive overflow during dropck
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 50d4c3cd0c9..ec17813ed2a 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -185,7 +185,7 @@ fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 true
             }
             Err(err) => {
-                infcx.report_mismatched_types(cause, expected, actual, err);
+                infcx.report_mismatched_types(cause, expected, actual, err).emit();
                 false
             }
         }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 28ca92f5db6..fdbd2f3647c 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1737,7 +1737,6 @@ impl Clean<Type> for hir::Ty {
                 segments.pop();
                 let trait_path = hir::Path {
                     span: p.span,
-                    global: p.global,
                     def: Def::Trait(cx.tcx.associated_item(p.def.def_id()).container.id()),
                     segments: segments.into(),
                 };
@@ -1756,7 +1755,6 @@ impl Clean<Type> for hir::Ty {
                 }
                 let trait_path = hir::Path {
                     span: self.span,
-                    global: false,
                     def: def,
                     segments: vec![].into(),
                 };
@@ -2213,9 +2211,9 @@ impl Path {
 impl Clean<Path> for hir::Path {
     fn clean(&self, cx: &DocContext) -> Path {
         Path {
-            global: self.global,
+            global: self.is_global(),
             def: self.def,
-            segments: self.segments.clean(cx),
+            segments: if self.is_global() { &self.segments[1..] } else { &self.segments }.clean(cx),
         }
     }
 }
@@ -2270,24 +2268,19 @@ impl Clean<PathSegment> for hir::PathSegment {
 }
 
 fn qpath_to_string(p: &hir::QPath) -> String {
-    let (segments, global) = match *p {
-        hir::QPath::Resolved(_, ref path) => {
-            (&path.segments, path.global)
-        }
-        hir::QPath::TypeRelative(_, ref segment) => {
-            return segment.name.to_string()
-        }
+    let segments = match *p {
+        hir::QPath::Resolved(_, ref path) => &path.segments,
+        hir::QPath::TypeRelative(_, ref segment) => return segment.name.to_string(),
     };
 
     let mut s = String::new();
-    let mut first = true;
-    for i in segments.iter().map(|x| x.name.as_str()) {
-        if !first || global {
+    for (i, seg) in segments.iter().enumerate() {
+        if i > 0 {
             s.push_str("::");
-        } else {
-            first = false;
         }
-        s.push_str(&i);
+        if seg.name != keywords::CrateRoot.name() {
+            s.push_str(&*seg.name.as_str());
+        }
     }
     s
 }
@@ -2801,7 +2794,7 @@ impl Clean<Item> for doctree::Macro {
             visibility: Some(Public),
             stability: self.stab.clean(cx),
             deprecation: self.depr.clean(cx),
-            def_id: cx.tcx.map.local_def_id(self.id),
+            def_id: self.def_id,
             inner: MacroItem(Macro {
                 source: format!("macro_rules! {} {{\n{}}}",
                                 name,
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index 21fc135eaad..31e10fbd3b7 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -233,9 +233,11 @@ pub struct DefaultImpl {
     pub whence: Span,
 }
 
+// For Macro we store the DefId instead of the NodeId, since we also create
+// these imported macro_rules (which only have a DUMMY_NODE_ID).
 pub struct Macro {
     pub name: Name,
-    pub id: ast::NodeId,
+    pub def_id: hir::def_id::DefId,
     pub attrs: hir::HirVec<ast::Attribute>,
     pub whence: Span,
     pub matchers: hir::HirVec<Span>,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 6dc6e80dae0..796a3a93068 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -207,7 +207,7 @@ impl<'a> fmt::Display for WhereClause<'a> {
         if !f.alternate() {
             clause.push_str("</span>");
             let plain = format!("{:#}", self);
-            if plain.len() > 80 {
+            if plain.len() + pad > 80 {
                 //break it onto its own line regardless, but make sure method impls and trait
                 //blocks keep their fixed padding (2 and 9, respectively)
                 let padding = if pad > 10 {
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 5353642e294..06a81641296 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -46,6 +46,7 @@ r##"<!DOCTYPE html>
 
     <title>{title}</title>
 
+    <link rel="stylesheet" type="text/css" href="{root_path}normalize.css">
     <link rel="stylesheet" type="text/css" href="{root_path}rustdoc.css">
     <link rel="stylesheet" type="text/css" href="{root_path}main.css">
     {css_extension}
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index e21898499a3..1d7fb2cd238 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -591,7 +591,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
                 ty: item.type_(),
                 name: item.name.clone().unwrap(),
                 path: fqp[..fqp.len() - 1].join("::"),
-                desc: Escape(&shorter(item.doc_value())).to_string(),
+                desc: plain_summary_line(item.doc_value()),
                 parent: Some(did),
                 parent_idx: None,
                 search_type: get_index_search_type(&item),
@@ -629,7 +629,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
     }
 
     let crate_doc = krate.module.as_ref().map(|module| {
-        Escape(&shorter(module.doc_value())).to_string()
+        plain_summary_line(module.doc_value())
     }).unwrap_or(String::new());
 
     let mut crate_data = BTreeMap::new();
@@ -1064,7 +1064,7 @@ impl DocFolder for Cache {
                             ty: item.type_(),
                             name: s.to_string(),
                             path: path.join("::").to_string(),
-                            desc: Escape(&shorter(item.doc_value())).to_string(),
+                            desc: plain_summary_line(item.doc_value()),
                             parent: parent,
                             parent_idx: None,
                             search_type: get_index_search_type(&item),
@@ -1468,6 +1468,13 @@ impl<'a> Item<'a> {
                 return None;
             }
         } else {
+            // Macros from other libraries get special filenames which we can
+            // safely ignore.
+            if self.item.source.filename.starts_with("<") &&
+               self.item.source.filename.ends_with("macros>") {
+                return None;
+            }
+
             let (krate, src_root) = match cache.extern_locations.get(&self.item.def_id.krate) {
                 Some(&(ref name, ref src, Local)) => (name, src),
                 Some(&(ref name, ref src, Remote(ref s))) => {
@@ -1655,8 +1662,13 @@ fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
 }
 
 fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Result {
-    for stability in short_stability(item, cx, true) {
-        write!(w, "<div class='stability'>{}</div>", stability)?;
+    let stabilities = short_stability(item, cx, true);
+    if !stabilities.is_empty() {
+        write!(w, "<div class='stability'>")?;
+        for stability in stabilities {
+            write!(w, "{}", stability)?;
+        }
+        write!(w, "</div>")?;
     }
     Ok(())
 }
@@ -1855,7 +1867,7 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<S
                 String::new()
             };
             let text = format!("Deprecated{}{}", since, MarkdownHtml(&deprecated_reason));
-            stability.push(format!("<em class='stab deprecated'>{}</em>", text))
+            stability.push(format!("<div class='stab deprecated'>{}</div>", text))
         };
 
         if stab.level == stability::Unstable {
@@ -1880,7 +1892,7 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<S
                 String::new()
             };
             let text = format!("Unstable{}{}", unstable_extra, MarkdownHtml(&unstable_reason));
-            stability.push(format!("<em class='stab unstable'>{}</em>", text))
+            stability.push(format!("<div class='stab unstable'>{}</div>", text))
         };
     } else if let Some(depr) = item.deprecation.as_ref() {
         let note = if show_reason && !depr.note.is_empty() {
@@ -1895,7 +1907,7 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<S
         };
 
         let text = format!("Deprecated{}{}", since, MarkdownHtml(&note));
-        stability.push(format!("<em class='stab deprecated'>{}</em>", text))
+        stability.push(format!("<div class='stab deprecated'>{}</div>", text))
     }
 
     stability
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 6ea25fa1241..c12e1e7d608 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -609,7 +609,7 @@
                               displayPath + '<span class="' + type + '">' +
                               name + '</span></a></td><td>' +
                               '<a href="' + href + '">' +
-                              '<span class="desc">' + item.desc +
+                              '<span class="desc">' + escape(item.desc) +
                               '&nbsp;</span></a></td></tr>';
                 });
             } else {
@@ -807,14 +807,6 @@
             search();
         }
 
-        function plainSummaryLine(markdown) {
-            markdown.replace(/\n/g, ' ')
-            .replace(/'/g, "\'")
-            .replace(/^#+? (.+?)/, "$1")
-            .replace(/\[(.*?)\]\(.*?\)/g, "$1")
-            .replace(/\[(.*?)\]\[.*?\]/g, "$1");
-        }
-
         index = buildIndex(rawSearchIndex);
         startSearch();
 
@@ -836,13 +828,10 @@
                 if (crates[i] === window.currentCrate) {
                     klass += ' current';
                 }
-                if (rawSearchIndex[crates[i]].items[0]) {
-                    var desc = rawSearchIndex[crates[i]].items[0][3];
-                    var link = $('<a>', {'href': '../' + crates[i] + '/index.html',
-                                         'title': plainSummaryLine(desc),
-                                         'class': klass}).text(crates[i]);
-                    ul.append($('<li>').append(link));
-                }
+                var link = $('<a>', {'href': '../' + crates[i] + '/index.html',
+                                     'title': rawSearchIndex[crates[i]].doc,
+                                     'class': klass}).text(crates[i]);
+                ul.append($('<li>').append(link));
             }
             sidebar.append(div);
         }
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index 7ee184c089c..0ca4f7ea36f 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -1,5 +1,3 @@
-@import "normalize.css";
-
 /**
  * Copyright 2013 The Rust Project Developers. See the COPYRIGHT
  * file at the top-level directory of this distribution and at
@@ -52,13 +50,15 @@
 	font-family: 'Source Code Pro';
 	font-style: normal;
 	font-weight: 400;
-	src: local('Source Code Pro'), url("SourceCodePro-Regular.woff") format('woff');
+	/* Avoid using locally installed font because bad versions are in circulation:
+	 * see https://github.com/rust-lang/rust/issues/24355 */
+	src: url("SourceCodePro-Regular.woff") format('woff');
 }
 @font-face {
 	font-family: 'Source Code Pro';
 	font-style: normal;
 	font-weight: 600;
-	src: local('Source Code Pro Semibold'), url("SourceCodePro-Semibold.woff") format('woff');
+	src: url("SourceCodePro-Semibold.woff") format('woff');
 }
 
 * {
@@ -523,20 +523,20 @@ body.blur > :not(#help) {
 	padding: 20px;
 }
 
-em.stab {
-	display: inline-block;
+.stab {
+	display: table;
 	border-width: 1px;
 	border-style: solid;
 	padding: 3px;
 	margin-bottom: 5px;
 	font-size: 90%;
-	font-style: normal;
 }
-em.stab p {
+.stab p {
 	display: inline;
 }
 
 .module-item .stab {
+	display: inline;
 	border-width: 0;
 	padding: 0;
 	margin: 0;
diff --git a/src/librustdoc/html/static/styles/main.css b/src/librustdoc/html/static/styles/main.css
index 6a9a24f6996..862d6d12b9a 100644
--- a/src/librustdoc/html/static/styles/main.css
+++ b/src/librustdoc/html/static/styles/main.css
@@ -30,10 +30,6 @@ h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.t
     background-color: white;
 }
 
-div.stability > em > code {
-    background-color: initial;
-}
-
 .docblock code, .docblock-short code {
     background-color: #F5F5F5;
 }
@@ -129,5 +125,5 @@ a.test-arrow {
     background-color: white;
 }
 
-em.stab.unstable { background: #FFF5D6; border-color: #FFC600; }
-em.stab.deprecated { background: #F3DFFF; border-color: #7F0087; }
+.stab.unstable { background: #FFF5D6; border-color: #FFC600; }
+.stab.deprecated { background: #F3DFFF; border-color: #7F0087; }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 74c7bc10194..835825d31ee 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -54,6 +54,9 @@ extern crate serialize as rustc_serialize; // used by deriving
 use std::collections::{BTreeMap, BTreeSet};
 use std::default::Default;
 use std::env;
+use std::fmt::Display;
+use std::io;
+use std::io::Write;
 use std::path::PathBuf;
 use std::process;
 use std::sync::mpsc::channel;
@@ -183,7 +186,7 @@ pub fn main_args(args: &[String]) -> isize {
     let matches = match getopts::getopts(&args[1..], &all_groups) {
         Ok(m) => m,
         Err(err) => {
-            println!("{}", err);
+            print_error(err);
             return 1;
         }
     };
@@ -211,11 +214,11 @@ pub fn main_args(args: &[String]) -> isize {
     }
 
     if matches.free.is_empty() {
-        println!("expected an input file to act on");
+        print_error("missing file operand");
         return 1;
     }
     if matches.free.len() > 1 {
-        println!("only one input file may be specified");
+        print_error("too many file operands");
         return 1;
     }
     let input = &matches.free[0];
@@ -227,7 +230,7 @@ pub fn main_args(args: &[String]) -> isize {
     let externs = match parse_externs(&matches) {
         Ok(ex) => ex,
         Err(err) => {
-            println!("{}", err);
+            print_error(err);
             return 1;
         }
     };
@@ -247,7 +250,10 @@ pub fn main_args(args: &[String]) -> isize {
 
     if let Some(ref p) = css_file_extension {
         if !p.is_file() {
-            println!("{}", "--extend-css option must take a css file as input");
+            writeln!(
+                &mut io::stderr(),
+                "rustdoc: option --extend-css argument must be a file."
+            ).unwrap();
             return 1;
         }
     }
@@ -257,7 +263,7 @@ pub fn main_args(args: &[String]) -> isize {
             &matches.opt_strs("html-before-content"),
             &matches.opt_strs("html-after-content")) {
         Some(eh) => eh,
-        None => return 3
+        None => return 3,
     };
     let crate_name = matches.opt_str("crate-name");
     let playground_url = matches.opt_str("playground-url");
@@ -291,17 +297,26 @@ pub fn main_args(args: &[String]) -> isize {
                 0
             }
             Some(s) => {
-                println!("unknown output format: {}", s);
+                print_error(format!("unknown output format: {}", s));
                 1
             }
         }
     });
     res.unwrap_or_else(|s| {
-        println!("input error: {}", s);
+        print_error(format!("input error: {}", s));
         1
     })
 }
 
+/// Prints an uniformised error message on the standard error output
+fn print_error<T>(error_message: T) where T: Display {
+    writeln!(
+        &mut io::stderr(),
+        "rustdoc: {}\nTry 'rustdoc --help' for more information.",
+        error_message
+    ).unwrap();
+}
+
 /// Looks inside the command line arguments to extract the relevant input format
 /// and files and then generates the necessary rustdoc output for formatting.
 fn acquire_input<R, F>(input: &str,
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 29267960a4a..9dbc9d30e60 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -71,7 +71,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
     let mut out = match File::create(&output) {
         Err(e) => {
             let _ = writeln!(&mut io::stderr(),
-                             "error opening `{}` for writing: {}",
+                             "rustdoc: {}: {}",
                              output.display(), e);
             return 4;
         }
@@ -80,8 +80,10 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
 
     let (metadata, text) = extract_leading_metadata(&input_str);
     if metadata.is_empty() {
-        let _ = writeln!(&mut io::stderr(),
-                         "invalid markdown file: expecting initial line with `% ...TITLE...`");
+        let _ = writeln!(
+            &mut io::stderr(),
+            "rustdoc: invalid markdown file: expecting initial line with `% ...TITLE...`"
+        );
         return 5;
     }
     let title = metadata[0];
@@ -132,7 +134,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
     match err {
         Err(e) => {
             let _ = writeln!(&mut io::stderr(),
-                             "error writing to `{}`: {}",
+                             "rustdoc: cannot write to `{}`: {}",
                              output.display(), e);
             6
         }
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 4087b9a761f..c93112657b9 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -85,7 +85,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                                               None);
         // attach the crate's exported macros to the top-level module:
         let macro_exports: Vec<_> =
-            krate.exported_macros.iter().map(|def| self.visit_macro(def)).collect();
+            krate.exported_macros.iter().map(|def| self.visit_local_macro(def)).collect();
         self.module.macros.extend(macro_exports);
         self.module.is_crate = true;
     }
@@ -201,6 +201,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     if def_id.krate == LOCAL_CRATE {
                         continue // These are `krate.exported_macros`, handled in `self.visit()`.
                     }
+                    let imported_from = self.cx.sess().cstore.original_crate_name(def_id.krate);
                     let def = match self.cx.sess().cstore.load_macro(def_id, self.cx.sess()) {
                         LoadedMacro::MacroRules(macro_rules) => macro_rules,
                         // FIXME(jseyfried): document proc macro reexports
@@ -210,14 +211,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     // FIXME(jseyfried) merge with `self.visit_macro()`
                     let matchers = def.body.chunks(4).map(|arm| arm[0].get_span()).collect();
                     om.macros.push(Macro {
-                        id: def.id,
+                        def_id: def_id,
                         attrs: def.attrs.clone().into(),
                         name: def.ident.name,
                         whence: def.span,
                         matchers: matchers,
                         stab: self.stability(def.id),
                         depr: self.deprecation(def.id),
-                        imported_from: def.imported_from.map(|ident| ident.name),
+                        imported_from: Some(imported_from),
                     })
                 }
             }
@@ -513,19 +514,19 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
     }
 
     // convert each exported_macro into a doc item
-    fn visit_macro(&self, def: &hir::MacroDef) -> Macro {
+    fn visit_local_macro(&self, def: &hir::MacroDef) -> Macro {
         // Extract the spans of all matchers. They represent the "interface" of the macro.
         let matchers = def.body.chunks(4).map(|arm| arm[0].get_span()).collect();
 
         Macro {
-            id: def.id,
+            def_id: self.cx.tcx.map.local_def_id(def.id),
             attrs: def.attrs.clone(),
             name: def.name,
             whence: def.span,
             matchers: matchers,
             stab: self.stability(def.id),
             depr: self.deprecation(def.id),
-            imported_from: def.imported_from,
+            imported_from: None,
         }
     }
 }
diff --git a/src/libserialize/leb128.rs b/src/libserialize/leb128.rs
index 8e8e03f1f8e..5b72c6d46ac 100644
--- a/src/libserialize/leb128.rs
+++ b/src/libserialize/leb128.rs
@@ -9,18 +9,26 @@
 // except according to those terms.
 
 #[inline]
-pub fn write_to_vec(vec: &mut Vec<u8>, position: &mut usize, byte: u8) {
-    if *position == vec.len() {
+fn write_to_vec(vec: &mut Vec<u8>, position: usize, byte: u8) {
+    if position == vec.len() {
         vec.push(byte);
     } else {
-        vec[*position] = byte;
+        vec[position] = byte;
     }
-
-    *position += 1;
 }
 
-pub fn write_unsigned_leb128(out: &mut Vec<u8>, start_position: usize, mut value: u64) -> usize {
-    let mut position = start_position;
+#[inline]
+/// encodes an integer using unsigned leb128 encoding and stores
+/// the result using a callback function.
+///
+/// The callback `write` is called once for each position
+/// that is to be written to with the byte to be encoded
+/// at that position.
+pub fn write_unsigned_leb128_to<W>(mut value: u64, mut write: W) -> usize
+    where W: FnMut(usize, u8)
+{
+    let mut position = 0;
+
     loop {
         let mut byte = (value & 0x7F) as u8;
         value >>= 7;
@@ -28,14 +36,19 @@ pub fn write_unsigned_leb128(out: &mut Vec<u8>, start_position: usize, mut value
             byte |= 0x80;
         }
 
-        write_to_vec(out, &mut position, byte);
+        write(position, byte);
+        position += 1;
 
         if value == 0 {
             break;
         }
     }
 
-    return position - start_position;
+    position
+}
+
+pub fn write_unsigned_leb128(out: &mut Vec<u8>, start_position: usize, value: u64) -> usize {
+    write_unsigned_leb128_to(value, |i, v| write_to_vec(out, start_position+i, v))
 }
 
 #[inline]
@@ -56,9 +69,17 @@ pub fn read_unsigned_leb128(data: &[u8], start_position: usize) -> (u64, usize)
     (result, position - start_position)
 }
 
-
-pub fn write_signed_leb128(out: &mut Vec<u8>, start_position: usize, mut value: i64) -> usize {
-    let mut position = start_position;
+#[inline]
+/// encodes an integer using signed leb128 encoding and stores
+/// the result using a callback function.
+///
+/// The callback `write` is called once for each position
+/// that is to be written to with the byte to be encoded
+/// at that position.
+pub fn write_signed_leb128_to<W>(mut value: i64, mut write: W) -> usize
+    where W: FnMut(usize, u8)
+{
+    let mut position = 0;
 
     loop {
         let mut byte = (value as u8) & 0x7f;
@@ -69,14 +90,19 @@ pub fn write_signed_leb128(out: &mut Vec<u8>, start_position: usize, mut value:
             byte |= 0x80; // Mark this byte to show that more bytes will follow.
         }
 
-        write_to_vec(out, &mut position, byte);
+        write(position, byte);
+        position += 1;
 
         if !more {
             break;
         }
     }
 
-    return position - start_position;
+    position
+}
+
+pub fn write_signed_leb128(out: &mut Vec<u8>, start_position: usize, value: i64) -> usize {
+    write_signed_leb128_to(value, |i, v| write_to_vec(out, start_position+i, v))
 }
 
 #[inline]
diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs
index a063b856468..f5e9ec6d89d 100644
--- a/src/libstd/ascii.rs
+++ b/src/libstd/ascii.rs
@@ -12,6 +12,7 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+use fmt;
 use mem;
 use ops::Range;
 use iter::FusedIterator;
@@ -370,6 +371,13 @@ impl ExactSizeIterator for EscapeDefault {}
 #[unstable(feature = "fused", issue = "35602")]
 impl FusedIterator for EscapeDefault {}
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for EscapeDefault {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("EscapeDefault { .. }")
+    }
+}
+
 
 static ASCII_LOWERCASE_MAP: [u8; 256] = [
     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
diff --git a/src/libstd/build.rs b/src/libstd/build.rs
index 1087d1f2447..5e1c3a28515 100644
--- a/src/libstd/build.rs
+++ b/src/libstd/build.rs
@@ -26,7 +26,7 @@ fn main() {
     let target = env::var("TARGET").expect("TARGET was not set");
     let host = env::var("HOST").expect("HOST was not set");
     if cfg!(feature = "backtrace") && !target.contains("apple") && !target.contains("msvc") &&
-        !target.contains("emscripten") && !target.contains("fuchsia") {
+        !target.contains("emscripten") && !target.contains("fuchsia") && !target.contains("redox") {
         build_libbacktrace(&host, &target);
     }
 
@@ -104,7 +104,7 @@ fn build_libbacktrace(host: &str, target: &str) {
                 .env("AR", &ar)
                 .env("RANLIB", format!("{} s", ar.display()))
                 .env("CFLAGS", cflags));
-    run(Command::new("make")
+    run(Command::new(build_helper::make(host))
                 .current_dir(&build_dir)
                 .arg(format!("INCDIR={}", src_dir.display()))
                 .arg("-j").arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set")));
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index 0b310eb2585..2fa3a9c4844 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -1276,6 +1276,15 @@ impl<'a, K, V> Clone for Iter<'a, K, V> {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a, K: Debug, V: Debug> fmt::Debug for Iter<'a, K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_list()
+            .entries(self.clone())
+            .finish()
+    }
+}
+
 /// HashMap mutable values iterator.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IterMut<'a, K: 'a, V: 'a> {
@@ -1285,7 +1294,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> {
 /// HashMap move iterator.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IntoIter<K, V> {
-    inner: table::IntoIter<K, V>,
+    pub(super) inner: table::IntoIter<K, V>,
 }
 
 /// HashMap keys iterator.
@@ -1302,6 +1311,15 @@ impl<'a, K, V> Clone for Keys<'a, K, V> {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a, K: Debug, V: Debug> fmt::Debug for Keys<'a, K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_list()
+            .entries(self.clone())
+            .finish()
+    }
+}
+
 /// HashMap values iterator.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Values<'a, K: 'a, V: 'a> {
@@ -1316,10 +1334,19 @@ impl<'a, K, V> Clone for Values<'a, K, V> {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a, K: Debug, V: Debug> fmt::Debug for Values<'a, K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_list()
+            .entries(self.clone())
+            .finish()
+    }
+}
+
 /// HashMap drain iterator.
 #[stable(feature = "drain", since = "1.6.0")]
 pub struct Drain<'a, K: 'a, V: 'a> {
-    inner: table::Drain<'a, K, V>,
+    pub(super) inner: table::Drain<'a, K, V>,
 }
 
 /// Mutable HashMap values iterator.
@@ -1557,6 +1584,18 @@ impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> {
 #[unstable(feature = "fused", issue = "35602")]
 impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {}
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a, K, V> fmt::Debug for IterMut<'a, K, V>
+    where K: fmt::Debug,
+          V: fmt::Debug,
+{
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_list()
+            .entries(self.inner.iter())
+            .finish()
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<K, V> Iterator for IntoIter<K, V> {
     type Item = (K, V);
@@ -1580,6 +1619,15 @@ impl<K, V> ExactSizeIterator for IntoIter<K, V> {
 #[unstable(feature = "fused", issue = "35602")]
 impl<K, V> FusedIterator for IntoIter<K, V> {}
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<K: Debug, V: Debug> fmt::Debug for IntoIter<K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_list()
+            .entries(self.inner.iter())
+            .finish()
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> Iterator for Keys<'a, K, V> {
     type Item = &'a K;
@@ -1649,6 +1697,18 @@ impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> {
 #[unstable(feature = "fused", issue = "35602")]
 impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {}
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a, K, V> fmt::Debug for ValuesMut<'a, K, V>
+    where K: fmt::Debug,
+          V: fmt::Debug,
+{
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_list()
+            .entries(self.inner.inner.iter())
+            .finish()
+    }
+}
+
 #[stable(feature = "drain", since = "1.6.0")]
 impl<'a, K, V> Iterator for Drain<'a, K, V> {
     type Item = (K, V);
@@ -1672,6 +1732,18 @@ impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> {
 #[unstable(feature = "fused", issue = "35602")]
 impl<'a, K, V> FusedIterator for Drain<'a, K, V> {}
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a, K, V> fmt::Debug for Drain<'a, K, V>
+    where K: fmt::Debug,
+          V: fmt::Debug,
+{
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_list()
+            .entries(self.inner.iter())
+            .finish()
+    }
+}
+
 impl<'a, K, V> Entry<'a, K, V> {
     #[stable(feature = "rust1", since = "1.0.0")]
     /// Ensures a value is in the entry by inserting the default if empty, and returns
@@ -2148,6 +2220,13 @@ impl Default for RandomState {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for RandomState {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("RandomState { .. }")
+    }
+}
+
 impl<K, S, Q: ?Sized> super::Recover<Q> for HashMap<K, (), S>
     where K: Eq + Hash + Borrow<Q>,
           S: BuildHasher,
diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs
index 72af612f569..341b050862f 100644
--- a/src/libstd/collections/hash/set.rs
+++ b/src/libstd/collections/hash/set.rs
@@ -948,6 +948,15 @@ impl<'a, K> ExactSizeIterator for Iter<'a, K> {
 #[unstable(feature = "fused", issue = "35602")]
 impl<'a, K> FusedIterator for Iter<'a, K> {}
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a, K: fmt::Debug> fmt::Debug for Iter<'a, K> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_list()
+            .entries(self.clone())
+            .finish()
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<K> Iterator for IntoIter<K> {
     type Item = K;
@@ -968,6 +977,16 @@ impl<K> ExactSizeIterator for IntoIter<K> {
 #[unstable(feature = "fused", issue = "35602")]
 impl<K> FusedIterator for IntoIter<K> {}
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<K: fmt::Debug> fmt::Debug for IntoIter<K> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let entries_iter = self.iter.inner.iter().map(|(k, _)| k);
+        f.debug_list()
+            .entries(entries_iter)
+            .finish()
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K> Iterator for Drain<'a, K> {
     type Item = K;
@@ -988,6 +1007,16 @@ impl<'a, K> ExactSizeIterator for Drain<'a, K> {
 #[unstable(feature = "fused", issue = "35602")]
 impl<'a, K> FusedIterator for Drain<'a, K> {}
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a, K: fmt::Debug> fmt::Debug for Drain<'a, K> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let entries_iter = self.iter.inner.iter().map(|(k, _)| k);
+        f.debug_list()
+            .entries(entries_iter)
+            .finish()
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T, S> Clone for Intersection<'a, T, S> {
     fn clone(&self) -> Intersection<'a, T, S> {
@@ -1021,6 +1050,18 @@ impl<'a, T, S> Iterator for Intersection<'a, T, S>
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a, T, S> fmt::Debug for Intersection<'a, T, S>
+    where T: fmt::Debug + Eq + Hash,
+          S: BuildHasher,
+{
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_list()
+            .entries(self.clone())
+            .finish()
+    }
+}
+
 #[unstable(feature = "fused", issue = "35602")]
 impl<'a, T, S> FusedIterator for Intersection<'a, T, S>
     where T: Eq + Hash,
@@ -1068,6 +1109,18 @@ impl<'a, T, S> FusedIterator for Difference<'a, T, S>
 {
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a, T, S> fmt::Debug for Difference<'a, T, S>
+    where T: fmt::Debug + Eq + Hash,
+          S: BuildHasher,
+{
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_list()
+            .entries(self.clone())
+            .finish()
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T, S> Clone for SymmetricDifference<'a, T, S> {
     fn clone(&self) -> SymmetricDifference<'a, T, S> {
@@ -1097,6 +1150,18 @@ impl<'a, T, S> FusedIterator for SymmetricDifference<'a, T, S>
 {
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a, T, S> fmt::Debug for SymmetricDifference<'a, T, S>
+    where T: fmt::Debug + Eq + Hash,
+          S: BuildHasher,
+{
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_list()
+            .entries(self.clone())
+            .finish()
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T, S> Clone for Union<'a, T, S> {
     fn clone(&self) -> Union<'a, T, S> {
@@ -1111,6 +1176,18 @@ impl<'a, T, S> FusedIterator for Union<'a, T, S>
 {
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a, T, S> fmt::Debug for Union<'a, T, S>
+    where T: fmt::Debug + Eq + Hash,
+          S: BuildHasher,
+{
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_list()
+            .entries(self.clone())
+            .finish()
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T, S> Iterator for Union<'a, T, S>
     where T: Eq + Hash,
diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs
index a784d8e50f9..2cd9362a657 100644
--- a/src/libstd/collections/hash/table.rs
+++ b/src/libstd/collections/hash/table.rs
@@ -882,6 +882,15 @@ unsafe impl<'a, K: Sync, V: Sync> Sync for IterMut<'a, K, V> {}
 // but Send is the more useful bound
 unsafe impl<'a, K: Send, V: Send> Send for IterMut<'a, K, V> {}
 
+impl<'a, K: 'a, V: 'a> IterMut<'a, K, V> {
+    pub fn iter(&self) -> Iter<K, V> {
+        Iter {
+            iter: self.iter.clone(),
+            elems_left: self.elems_left,
+        }
+    }
+}
+
 /// Iterator over the entries in a table, consuming the table.
 pub struct IntoIter<K, V> {
     table: RawTable<K, V>,
@@ -891,6 +900,15 @@ pub struct IntoIter<K, V> {
 unsafe impl<K: Sync, V: Sync> Sync for IntoIter<K, V> {}
 unsafe impl<K: Send, V: Send> Send for IntoIter<K, V> {}
 
+impl<K, V> IntoIter<K, V> {
+    pub fn iter(&self) -> Iter<K, V> {
+        Iter {
+            iter: self.iter.clone(),
+            elems_left: self.table.size,
+        }
+    }
+}
+
 /// Iterator over the entries in a table, clearing the table.
 pub struct Drain<'a, K: 'a, V: 'a> {
     table: Shared<RawTable<K, V>>,
@@ -901,6 +919,17 @@ pub struct Drain<'a, K: 'a, V: 'a> {
 unsafe impl<'a, K: Sync, V: Sync> Sync for Drain<'a, K, V> {}
 unsafe impl<'a, K: Send, V: Send> Send for Drain<'a, K, V> {}
 
+impl<'a, K, V> Drain<'a, K, V> {
+    pub fn iter(&self) -> Iter<K, V> {
+        unsafe {
+            Iter {
+                iter: self.iter.clone(),
+                elems_left: (**self.table).size,
+            }
+        }
+    }
+}
+
 impl<'a, K, V> Iterator for Iter<'a, K, V> {
     type Item = (&'a K, &'a V);
 
diff --git a/src/libstd/env.rs b/src/libstd/env.rs
index ee6a907f616..0521f301321 100644
--- a/src/libstd/env.rs
+++ b/src/libstd/env.rs
@@ -143,6 +143,13 @@ impl Iterator for Vars {
     fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for Vars {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Vars { .. }")
+    }
+}
+
 #[stable(feature = "env", since = "1.0.0")]
 impl Iterator for VarsOs {
     type Item = (OsString, OsString);
@@ -150,6 +157,13 @@ impl Iterator for VarsOs {
     fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for VarsOs {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("VarsOs { .. }")
+    }
+}
+
 /// Fetches the environment variable `key` from the current process.
 ///
 /// The returned result is `Ok(s)` if the environment variable is present and is
@@ -364,6 +378,13 @@ impl<'a> Iterator for SplitPaths<'a> {
     fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a> fmt::Debug for SplitPaths<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("SplitPaths { .. }")
+    }
+}
+
 /// Error type returned from `std::env::join_paths` when paths fail to be
 /// joined.
 #[derive(Debug)]
@@ -640,6 +661,13 @@ impl DoubleEndedIterator for Args {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for Args {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Args { .. }")
+    }
+}
+
 #[stable(feature = "env", since = "1.0.0")]
 impl Iterator for ArgsOs {
     type Item = OsString;
@@ -657,6 +685,14 @@ impl ExactSizeIterator for ArgsOs {
 impl DoubleEndedIterator for ArgsOs {
     fn next_back(&mut self) -> Option<OsString> { self.inner.next_back() }
 }
+
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for ArgsOs {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("ArgsOs { .. }")
+    }
+}
+
 /// Constants associated with the current target
 #[stable(feature = "env", since = "1.0.0")]
 pub mod consts {
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index e91e808c548..41934dc057e 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -35,21 +35,53 @@ use time::SystemTime;
 ///
 /// # Examples
 ///
+/// Create a new file and write bytes to it:
+///
 /// ```no_run
+/// use std::fs::File;
 /// use std::io::prelude::*;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// let mut file = try!(File::create("foo.txt"));
+/// try!(file.write_all(b"Hello, world!"));
+/// # Ok(())
+/// # }
+/// ```
+///
+/// Read the contents of a file into a `String`:
+///
+/// ```no_run
 /// use std::fs::File;
+/// use std::io::prelude::*;
 ///
 /// # fn foo() -> std::io::Result<()> {
-/// let mut f = try!(File::create("foo.txt"));
-/// try!(f.write_all(b"Hello, world!"));
+/// let mut file = try!(File::open("foo.txt"));
+/// let mut contents = String::new();
+/// try!(file.read_to_string(&mut contents));
+/// assert_eq!(contents, "Hello, world!");
+/// # Ok(())
+/// # }
+/// ```
 ///
-/// let mut f = try!(File::open("foo.txt"));
-/// let mut s = String::new();
-/// try!(f.read_to_string(&mut s));
-/// assert_eq!(s, "Hello, world!");
+/// It can be more efficient to read the contents of a file with a buffered
+/// [`Read`]er. This can be accomplished with [`BufReader<R>`]:
+///
+/// ```no_run
+/// use std::fs::File;
+/// use std::io::BufReader;
+/// use std::io::prelude::*;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// let file = try!(File::open("foo.txt"));
+/// let mut buf_reader = BufReader::new(file);
+/// let mut contents = String::new();
+/// try!(buf_reader.read_to_string(&mut contents));
+/// assert_eq!(contents, "Hello, world!");
 /// # Ok(())
 /// # }
 /// ```
+///
+/// [`BufReader`]: ../io/struct.BufReader.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct File {
     inner: fs_imp::File,
@@ -140,7 +172,7 @@ pub struct DirEntry(fs_imp::DirEntry);
 ///             .create(true)
 ///             .open("foo.txt");
 /// ```
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct OpenOptions(fs_imp::OpenOptions);
 
@@ -168,6 +200,7 @@ pub struct FileType(fs_imp::FileType);
 ///
 /// This builder also supports platform-specific options.
 #[stable(feature = "dir_builder", since = "1.6.0")]
+#[derive(Debug)]
 pub struct DirBuilder {
     inner: fs_imp::DirBuilder,
     recursive: bool,
@@ -834,6 +867,21 @@ impl Metadata {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for Metadata {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Metadata")
+            .field("file_type", &self.file_type())
+            .field("is_dir", &self.is_dir())
+            .field("is_file", &self.is_file())
+            .field("permissions", &self.permissions())
+            .field("modified", &self.modified())
+            .field("accessed", &self.accessed())
+            .field("created", &self.created())
+            .finish()
+    }
+}
+
 impl AsInner<fs_imp::FileAttr> for Metadata {
     fn as_inner(&self) -> &fs_imp::FileAttr { &self.0 }
 }
@@ -1751,6 +1799,16 @@ mod tests {
         }
     ) }
 
+    #[cfg(windows)]
+    macro_rules! error { ($e:expr, $s:expr) => (
+        match $e {
+            Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
+            Err(ref err) => assert!(err.raw_os_error() == Some($s),
+                                    format!("`{}` did not have a code of `{}`", err, $s))
+        }
+    ) }
+
+    #[cfg(unix)]
     macro_rules! error { ($e:expr, $s:expr) => (
         match $e {
             Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
@@ -1771,12 +1829,9 @@ mod tests {
 
         match symlink_file(r"nonexisting_target", link) {
             Ok(_) => true,
-            Err(ref err) =>
-                if err.to_string().contains("A required privilege is not held by the client.") {
-                    false
-                } else {
-                    true
-                }
+            // ERROR_PRIVILEGE_NOT_HELD = 1314
+            Err(ref err) if err.raw_os_error() == Some(1314) => false,
+            Err(_) => true,
         }
     }
 
@@ -1807,12 +1862,10 @@ mod tests {
         let filename = &tmpdir.join("file_that_does_not_exist.txt");
         let result = File::open(filename);
 
-        if cfg!(unix) {
-            error!(result, "No such file or directory");
-        }
-        if cfg!(windows) {
-            error!(result, "The system cannot find the file specified");
-        }
+        #[cfg(unix)]
+        error!(result, "No such file or directory");
+        #[cfg(windows)]
+        error!(result, 2); // ERROR_FILE_NOT_FOUND
     }
 
     #[test]
@@ -1822,12 +1875,10 @@ mod tests {
 
         let result = fs::remove_file(filename);
 
-        if cfg!(unix) {
-            error!(result, "No such file or directory");
-        }
-        if cfg!(windows) {
-            error!(result, "The system cannot find the file specified");
-        }
+        #[cfg(unix)]
+        error!(result, "No such file or directory");
+        #[cfg(windows)]
+        error!(result, 2); // ERROR_FILE_NOT_FOUND
     }
 
     #[test]
@@ -2582,8 +2633,10 @@ mod tests {
         let mut a = OO::new(); a.append(true);
         let mut ra = OO::new(); ra.read(true).append(true);
 
-        let invalid_options = if cfg!(windows) { "The parameter is incorrect" }
-                              else { "Invalid argument" };
+        #[cfg(windows)]
+        let invalid_options = 87; // ERROR_INVALID_PARAMETER
+        #[cfg(unix)]
+        let invalid_options = "Invalid argument";
 
         // Test various combinations of creation modes and access modes.
         //
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index cd7a50d07e2..c15a1c8328c 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -652,6 +652,7 @@ impl<W> fmt::Display for IntoInnerError<W> {
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct LineWriter<W: Write> {
     inner: BufWriter<W>,
+    need_flush: bool,
 }
 
 impl<W: Write> LineWriter<W> {
@@ -692,7 +693,10 @@ impl<W: Write> LineWriter<W> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_capacity(cap: usize, inner: W) -> LineWriter<W> {
-        LineWriter { inner: BufWriter::with_capacity(cap, inner) }
+        LineWriter {
+            inner: BufWriter::with_capacity(cap, inner),
+            need_flush: false,
+        }
     }
 
     /// Gets a reference to the underlying writer.
@@ -759,7 +763,10 @@ impl<W: Write> LineWriter<W> {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> {
         self.inner.into_inner().map_err(|IntoInnerError(buf, e)| {
-            IntoInnerError(LineWriter { inner: buf }, e)
+            IntoInnerError(LineWriter {
+                inner: buf,
+                need_flush: false,
+            }, e)
         })
     }
 }
@@ -767,20 +774,46 @@ impl<W: Write> LineWriter<W> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<W: Write> Write for LineWriter<W> {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        match memchr::memrchr(b'\n', buf) {
-            Some(i) => {
-                let n = self.inner.write(&buf[..i + 1])?;
-                if n != i + 1 || self.inner.flush().is_err() {
-                    // Do not return errors on partial writes.
-                    return Ok(n);
-                }
-                self.inner.write(&buf[i + 1..]).map(|i| n + i)
-            }
-            None => self.inner.write(buf),
+        if self.need_flush {
+            self.flush()?;
+        }
+
+        // Find the last newline character in the buffer provided. If found then
+        // we're going to write all the data up to that point and then flush,
+        // otherewise we just write the whole block to the underlying writer.
+        let i = match memchr::memrchr(b'\n', buf) {
+            Some(i) => i,
+            None => return self.inner.write(buf),
+        };
+
+
+        // Ok, we're going to write a partial amount of the data given first
+        // followed by flushing the newline. After we've successfully written
+        // some data then we *must* report that we wrote that data, so future
+        // errors are ignored. We set our internal `need_flush` flag, though, in
+        // case flushing fails and we need to try it first next time.
+        let n = self.inner.write(&buf[..i + 1])?;
+        self.need_flush = true;
+        if self.flush().is_err() || n != i + 1 {
+            return Ok(n)
+        }
+
+        // At this point we successfully wrote `i + 1` bytes and flushed it out,
+        // meaning that the entire line is now flushed out on the screen. While
+        // we can attempt to finish writing the rest of the data provided.
+        // Remember though that we ignore errors here as we've successfully
+        // written data, so we need to report that.
+        match self.inner.write(&buf[i + 1..]) {
+            Ok(i) => Ok(n + i),
+            Err(_) => Ok(n),
         }
     }
 
-    fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
+    fn flush(&mut self) -> io::Result<()> {
+        self.inner.flush()?;
+        self.need_flush = false;
+        Ok(())
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1153,4 +1186,44 @@ mod tests {
             BufWriter::new(io::sink())
         });
     }
+
+    struct AcceptOneThenFail {
+        written: bool,
+        flushed: bool,
+    }
+
+    impl Write for AcceptOneThenFail {
+        fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+            if !self.written {
+                assert_eq!(data, b"a\nb\n");
+                self.written = true;
+                Ok(data.len())
+            } else {
+                Err(io::Error::new(io::ErrorKind::NotFound, "test"))
+            }
+        }
+
+        fn flush(&mut self) -> io::Result<()> {
+            assert!(self.written);
+            assert!(!self.flushed);
+            self.flushed = true;
+            Err(io::Error::new(io::ErrorKind::Other, "test"))
+        }
+    }
+
+    #[test]
+    fn erroneous_flush_retried() {
+        let a = AcceptOneThenFail {
+            written: false,
+            flushed: false,
+        };
+
+        let mut l = LineWriter::new(a);
+        assert_eq!(l.write(b"a\nb\na").unwrap(), 4);
+        assert!(l.get_ref().written);
+        assert!(l.get_ref().flushed);
+        l.get_mut().flushed = false;
+
+        assert_eq!(l.write(b"a").unwrap_err().kind(), io::ErrorKind::Other)
+    }
 }
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index b3b89213df1..5450a10c9bd 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -1425,6 +1425,12 @@ pub trait BufRead: Read {
     ///     println!("{}", line.unwrap());
     /// }
     /// ```
+    ///
+    /// # Errors
+    ///
+    /// Each line of the iterator has the same error semantics as [`BufRead::read_line()`].
+    ///
+    /// [`BufRead::read_line()`]: trait.BufRead.html#method.read_line
     #[stable(feature = "rust1", since = "1.0.0")]
     fn lines(self) -> Lines<Self> where Self: Sized {
         Lines { buf: self }
@@ -1444,6 +1450,16 @@ pub struct Chain<T, U> {
     done_first: bool,
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<T: fmt::Debug, U: fmt::Debug> fmt::Debug for Chain<T, U> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Chain")
+            .field("t", &self.first)
+            .field("u", &self.second)
+            .finish()
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Read, U: Read> Read for Chain<T, U> {
     fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
@@ -1485,6 +1501,7 @@ impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
 ///
 /// [`take()`]: trait.Read.html#method.take
 #[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug)]
 pub struct Take<T> {
     inner: T,
     limit: u64,
@@ -1526,8 +1543,6 @@ impl<T> Take<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(io_take_into_inner)]
-    ///
     /// use std::io;
     /// use std::io::prelude::*;
     /// use std::fs::File;
@@ -1543,7 +1558,7 @@ impl<T> Take<T> {
     /// # Ok(())
     /// # }
     /// ```
-    #[unstable(feature = "io_take_into_inner", issue = "23755")]
+    #[stable(feature = "io_take_into_inner", since = "1.15.0")]
     pub fn into_inner(self) -> T {
         self.inner
     }
@@ -1604,6 +1619,7 @@ fn read_one_byte(reader: &mut Read) -> Option<Result<u8>> {
 ///
 /// [`bytes()`]: trait.Read.html#method.bytes
 #[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug)]
 pub struct Bytes<R> {
     inner: R,
 }
@@ -1625,6 +1641,7 @@ impl<R: Read> Iterator for Bytes<R> {
 /// [chars]: trait.Read.html#method.chars
 #[unstable(feature = "io", reason = "awaiting stability of Read::chars",
            issue = "27802")]
+#[derive(Debug)]
 pub struct Chars<R> {
     inner: R,
 }
@@ -1714,6 +1731,7 @@ impl fmt::Display for CharsError {
 ///
 /// [split]: trait.BufRead.html#method.split
 #[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug)]
 pub struct Split<B> {
     buf: B,
     delim: u8,
@@ -1745,6 +1763,7 @@ impl<B: BufRead> Iterator for Split<B> {
 ///
 /// [lines]: trait.BufRead.html#method.lines
 #[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug)]
 pub struct Lines<B> {
     buf: B,
 }
diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs
index e8b812daed8..9d1c8942f8c 100644
--- a/src/libstd/io/stdio.rs
+++ b/src/libstd/io/stdio.rs
@@ -10,7 +10,7 @@
 
 use io::prelude::*;
 
-use cell::{RefCell, BorrowState};
+use cell::RefCell;
 use fmt;
 use io::lazy::Lazy;
 use io::{self, BufReader, LineWriter};
@@ -81,11 +81,11 @@ impl Read for StdinRaw {
 }
 impl Write for StdoutRaw {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
-    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+    fn flush(&mut self) -> io::Result<()> { self.0.flush() }
 }
 impl Write for StderrRaw {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
-    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+    fn flush(&mut self) -> io::Result<()> { self.0.flush() }
 }
 
 enum Maybe<T> {
@@ -282,6 +282,13 @@ impl Stdin {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for Stdin {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Stdin { .. }")
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Read for Stdin {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
@@ -314,6 +321,13 @@ impl<'a> BufRead for StdinLock<'a> {
     fn consume(&mut self, n: usize) { self.inner.consume(n) }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a> fmt::Debug for StdinLock<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("StdinLock { .. }")
+    }
+}
+
 /// A handle to the global standard output stream of the current process.
 ///
 /// Each handle shares a global buffer of data to be written to the standard
@@ -424,6 +438,13 @@ impl Stdout {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for Stdout {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Stdout { .. }")
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Write for Stdout {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
@@ -449,6 +470,13 @@ impl<'a> Write for StdoutLock<'a> {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a> fmt::Debug for StdoutLock<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("StdoutLock { .. }")
+    }
+}
+
 /// A handle to the standard error stream of a process.
 ///
 /// For more information, see the [`io::stderr`] method.
@@ -545,6 +573,13 @@ impl Stderr {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for Stderr {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Stderr { .. }")
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Write for Stderr {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
@@ -570,6 +605,13 @@ impl<'a> Write for StderrLock<'a> {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a> fmt::Debug for StderrLock<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("StderrLock { .. }")
+    }
+}
+
 /// Resets the thread-local stderr handle to the specified writer
 ///
 /// This will replace the current thread's stderr handle, returning the old
@@ -638,8 +680,8 @@ pub fn _print(args: fmt::Arguments) {
         LocalKeyState::Destroyed => stdout().write_fmt(args),
         LocalKeyState::Valid => {
             LOCAL_STDOUT.with(|s| {
-                if s.borrow_state() == BorrowState::Unused {
-                    if let Some(w) = s.borrow_mut().as_mut() {
+                if let Ok(mut borrowed) = s.try_borrow_mut() {
+                    if let Some(w) = borrowed.as_mut() {
                         return w.write_fmt(args);
                     }
                 }
diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs
index 2c6880281b5..436511031ef 100644
--- a/src/libstd/io/util.rs
+++ b/src/libstd/io/util.rs
@@ -10,6 +10,7 @@
 
 #![allow(missing_copy_implementations)]
 
+use fmt;
 use io::{self, Read, Write, ErrorKind, BufRead};
 
 /// Copies the entire contents of a reader into a writer.
@@ -97,6 +98,13 @@ impl BufRead for Empty {
     fn consume(&mut self, _n: usize) {}
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for Empty {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Empty { .. }")
+    }
+}
+
 /// A reader which yields one byte over and over and over and over and over and...
 ///
 /// This struct is generally created by calling [`repeat()`][repeat]. Please
@@ -133,6 +141,13 @@ impl Read for Repeat {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for Repeat {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Repeat { .. }")
+    }
+}
+
 /// A writer which will move data into the void.
 ///
 /// This struct is generally created by calling [`sink()`][sink]. Please
@@ -165,6 +180,13 @@ impl Write for Sink {
     fn flush(&mut self) -> io::Result<()> { Ok(()) }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for Sink {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Sink { .. }")
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use io::prelude::*;
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 414f25fa5eb..fc5c6968544 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -214,6 +214,7 @@
 #![no_std]
 
 #![deny(missing_docs)]
+#![deny(missing_debug_implementations)]
 
 // Tell the compiler to link to either panic_abort or panic_unwind
 #![needs_panic_runtime]
@@ -276,6 +277,7 @@
 #![feature(panic_unwind)]
 #![feature(placement_in_syntax)]
 #![feature(prelude_import)]
+#![feature(pub_restricted)]
 #![feature(rand)]
 #![feature(raw)]
 #![feature(repr_simd)]
diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs
index c1e610f33fb..6aab7486004 100644
--- a/src/libstd/net/ip.rs
+++ b/src/libstd/net/ip.rs
@@ -1068,6 +1068,14 @@ impl From<[u8; 16]> for Ipv6Addr {
     }
 }
 
+#[stable(feature = "ipv6_from_segments", since = "1.15.0")]
+impl From<[u16; 8]> for Ipv6Addr {
+    fn from(segments: [u16; 8]) -> Ipv6Addr {
+        let [a, b, c, d, e, f, g, h] = segments;
+        Ipv6Addr::new(a, b, c, d, e, f, g, h)
+    }
+}
+
 // Tests for this module
 #[cfg(all(test, not(target_os = "emscripten")))]
 mod tests {
@@ -1413,11 +1421,29 @@ mod tests {
     }
 
     #[test]
-    fn ipv4_from_u32_slice() {
+    fn ipv4_from_octets() {
         assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1))
     }
 
     #[test]
+    fn ipv6_from_segments() {
+        let from_u16s = Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677,
+                                        0x8899, 0xaabb, 0xccdd, 0xeeff]);
+        let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677,
+                                0x8899, 0xaabb, 0xccdd, 0xeeff);
+        assert_eq!(new, from_u16s);
+    }
+
+    #[test]
+    fn ipv6_from_octets() {
+        let from_u16s = Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677,
+                                        0x8899, 0xaabb, 0xccdd, 0xeeff]);
+        let from_u8s = Ipv6Addr::from([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+                                       0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]);
+        assert_eq!(from_u16s, from_u8s);
+    }
+
+    #[test]
     fn ord() {
         assert!(Ipv4Addr::new(100, 64, 3, 3) < Ipv4Addr::new(192, 0, 2, 2));
         assert!("2001:db8:f00::1002".parse::<Ipv6Addr>().unwrap() <
diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs
index 56286fbe253..cadf87f32b1 100644
--- a/src/libstd/net/mod.rs
+++ b/src/libstd/net/mod.rs
@@ -12,6 +12,7 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+use fmt;
 use io::{self, Error, ErrorKind};
 use sys_common::net as net_imp;
 
@@ -105,6 +106,13 @@ impl Iterator for LookupHost {
     fn next(&mut self) -> Option<SocketAddr> { self.0.next() }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for LookupHost {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("LookupHost { .. }")
+    }
+}
+
 /// Resolve the host specified by `host` as a number of `SocketAddr` instances.
 ///
 /// This method may perform a DNS query to resolve `host` and may also inspect
diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs
index be9636a0a19..63817c9f10f 100644
--- a/src/libstd/net/tcp.rs
+++ b/src/libstd/net/tcp.rs
@@ -76,6 +76,7 @@ pub struct TcpListener(net_imp::TcpListener);
 /// [`incoming`]: struct.TcpListener.html#method.incoming
 /// [`TcpListener`]: struct.TcpListener.html
 #[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug)]
 pub struct Incoming<'a> { listener: &'a TcpListener }
 
 impl TcpStream {
diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs
index b280f466dd4..f8a5ec0b379 100644
--- a/src/libstd/net/udp.rs
+++ b/src/libstd/net/udp.rs
@@ -499,6 +499,19 @@ impl UdpSocket {
     /// This will retrieve the stored error in the underlying socket, clearing
     /// the field in the process. This can be useful for checking errors between
     /// calls.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::net::UdpSocket;
+    ///
+    /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+    /// match socket.take_error() {
+    ///     Ok(Some(error)) => println!("UdpSocket error: {:?}", error),
+    ///     Ok(None) => println!("No error"),
+    ///     Err(error) => println!("UdpSocket.take_error failed: {:?}", error),
+    /// }
+    /// ```
     #[stable(feature = "net2_mutators", since = "1.9.0")]
     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
         self.0.take_error()
@@ -507,6 +520,15 @@ impl UdpSocket {
     /// Connects this UDP socket to a remote address, allowing the `send` and
     /// `recv` syscalls to be used to send data and also applies filters to only
     /// receive data from the specified address.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::net::UdpSocket;
+    ///
+    /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+    /// socket.connect("127.0.0.1:8080").expect("connect function failed");
+    /// ```
     #[stable(feature = "net2_mutators", since = "1.9.0")]
     pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
         super::each_addr(addr, |addr| self.0.connect(addr))
@@ -514,8 +536,20 @@ impl UdpSocket {
 
     /// Sends data on the socket to the remote address to which it is connected.
     ///
-    /// The `connect` method will connect this socket to a remote address. This
+    /// The [`connect()`] method will connect this socket to a remote address. This
     /// method will fail if the socket is not connected.
+    ///
+    /// [`connect()`]: #method.connect
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::net::UdpSocket;
+    ///
+    /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+    /// socket.connect("127.0.0.1:8080").expect("connect function failed");
+    /// socket.send(&[0, 1, 2]).expect("couldn't send message");
+    /// ```
     #[stable(feature = "net2_mutators", since = "1.9.0")]
     pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
         self.0.send(buf)
@@ -526,6 +560,20 @@ impl UdpSocket {
     ///
     /// The `connect` method will connect this socket to a remote address. This
     /// method will fail if the socket is not connected.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::net::UdpSocket;
+    ///
+    /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+    /// socket.connect("127.0.0.1:8080").expect("connect function failed");
+    /// let mut buf = [0; 10];
+    /// match socket.recv(&mut buf) {
+    ///     Ok(received) => println!("received {} bytes", received),
+    ///     Err(e) => println!("recv function failed: {:?}", e),
+    /// }
+    /// ```
     #[stable(feature = "net2_mutators", since = "1.9.0")]
     pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
         self.0.recv(buf)
@@ -535,6 +583,15 @@ impl UdpSocket {
     ///
     /// On Unix this corresponds to calling fcntl, and on Windows this
     /// corresponds to calling ioctlsocket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::net::UdpSocket;
+    ///
+    /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
+    /// socket.set_nonblocking(true).expect("set_nonblocking call failed");
+    /// ```
     #[stable(feature = "net2_mutators", since = "1.9.0")]
     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
         self.0.set_nonblocking(nonblocking)
diff --git a/src/libstd/os/linux/raw.rs b/src/libstd/os/linux/raw.rs
index e6a95bc831f..7c9274d0601 100644
--- a/src/libstd/os/linux/raw.rs
+++ b/src/libstd/os/linux/raw.rs
@@ -17,6 +17,7 @@
                               crates.io should be used instead for the correct \
                               definitions")]
 #![allow(deprecated)]
+#![allow(missing_debug_implementations)]
 
 use os::raw::c_ulong;
 
diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs
index 366a1674156..e45af867055 100644
--- a/src/libstd/os/mod.rs
+++ b/src/libstd/os/mod.rs
@@ -11,9 +11,9 @@
 //! OS-specific functionality.
 
 #![stable(feature = "os", since = "1.0.0")]
-#![allow(missing_docs, bad_style)]
+#![allow(missing_docs, bad_style, missing_debug_implementations)]
 
-#[cfg(unix)]
+#[cfg(any(target_os = "redox", unix))]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use sys::ext as unix;
 #[cfg(windows)]
diff --git a/src/libstd/os/raw.rs b/src/libstd/os/raw.rs
index 2a918d8aeb7..cc154f7ab41 100644
--- a/src/libstd/os/raw.rs
+++ b/src/libstd/os/raw.rs
@@ -12,6 +12,8 @@
 
 #![stable(feature = "raw_os", since = "1.1.0")]
 
+use fmt;
+
 #[cfg(any(target_os = "android",
           target_os = "emscripten",
           all(target_os = "linux", any(target_arch = "aarch64",
@@ -71,6 +73,13 @@ pub enum c_void {
     #[doc(hidden)] __variant2,
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for c_void {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("c_void")
+    }
+}
+
 #[cfg(test)]
 #[allow(unused_imports)]
 mod tests {
diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs
index a7e8c4fab37..faf4949e861 100644
--- a/src/libstd/panic.rs
+++ b/src/libstd/panic.rs
@@ -14,6 +14,7 @@
 
 use any::Any;
 use cell::UnsafeCell;
+use fmt;
 use ops::{Deref, DerefMut};
 use panicking;
 use ptr::{Unique, Shared};
@@ -296,6 +297,15 @@ impl<R, F: FnOnce() -> R> FnOnce<()> for AssertUnwindSafe<F> {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<T: fmt::Debug> fmt::Debug for AssertUnwindSafe<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_tuple("AssertUnwindSafe")
+            .field(&self.0)
+            .finish()
+    }
+}
+
 /// Invokes a closure, capturing the cause of an unwinding panic if one occurs.
 ///
 /// This function will return `Ok` with the closure's result if the closure
diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs
index 45a10d24528..e5edea241e1 100644
--- a/src/libstd/panicking.rs
+++ b/src/libstd/panicking.rs
@@ -177,6 +177,7 @@ pub fn take_hook() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> {
 /// panic!("Normal panic");
 /// ```
 #[stable(feature = "panic_hooks", since = "1.10.0")]
+#[derive(Debug)]
 pub struct PanicInfo<'a> {
     payload: &'a (Any + Send),
     location: Location<'a>,
@@ -256,6 +257,7 @@ impl<'a> PanicInfo<'a> {
 ///
 /// panic!("Normal panic");
 /// ```
+#[derive(Debug)]
 #[stable(feature = "panic_hooks", since = "1.10.0")]
 pub struct Location<'a> {
     file: &'a str,
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index 858537dd2de..e15c37aaf24 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -114,6 +114,17 @@ impl IntoInner<imp::Process> for Child {
     fn into_inner(self) -> imp::Process { self.handle }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for Child {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Child")
+            .field("stdin", &self.stdin)
+            .field("stdout", &self.stdout)
+            .field("stderr", &self.stderr)
+            .finish()
+    }
+}
+
 /// A handle to a child process's stdin. This struct is used in the [`stdin`]
 /// field on [`Child`].
 ///
@@ -149,6 +160,13 @@ impl FromInner<AnonPipe> for ChildStdin {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for ChildStdin {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("ChildStdin { .. }")
+    }
+}
+
 /// A handle to a child process's stdout. This struct is used in the [`stdout`]
 /// field on [`Child`].
 ///
@@ -183,6 +201,13 @@ impl FromInner<AnonPipe> for ChildStdout {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for ChildStdout {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("ChildStdout { .. }")
+    }
+}
+
 /// A handle to a child process's stderr. This struct is used in the [`stderr`]
 /// field on [`Child`].
 ///
@@ -217,6 +242,13 @@ impl FromInner<AnonPipe> for ChildStderr {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for ChildStderr {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("ChildStderr { .. }")
+    }
+}
+
 /// A process builder, providing fine-grained control
 /// over how a new process should be spawned.
 ///
@@ -622,6 +654,13 @@ impl FromInner<imp::Stdio> for Stdio {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for Stdio {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Stdio { .. }")
+    }
+}
+
 /// Describes the result of a process after it has terminated.
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
 #[stable(feature = "process", since = "1.0.0")]
@@ -828,6 +867,12 @@ impl Child {
 /// this function at a known point where there are no more destructors left
 /// to run.
 ///
+/// ## Platform-specific behavior
+///
+/// **Unix**: On Unix-like platforms, it is unlikely that all 32 bits of `exit`
+/// will be visible to a parent process inspecting the exit code. On most
+/// Unix-like platforms, only the eight least-significant bits are considered.
+///
 /// # Examples
 ///
 /// ```
@@ -835,6 +880,17 @@ impl Child {
 ///
 /// process::exit(0);
 /// ```
+///
+/// Due to [platform-specific behavior], the exit code for this example will be
+/// `0` on Linux, but `256` on Windows:
+///
+/// ```no_run
+/// use std::process;
+///
+/// process::exit(0x0f00);
+/// ```
+///
+/// [platform-specific behavior]: #platform-specific-behavior
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn exit(code: i32) -> ! {
     ::sys_common::cleanup();
diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs
index f48325218fb..b853e83de5d 100644
--- a/src/libstd/rand/mod.rs
+++ b/src/libstd/rand/mod.rs
@@ -59,6 +59,7 @@
 #![unstable(feature = "rand", issue = "0")]
 
 use cell::RefCell;
+use fmt;
 use io;
 use mem;
 use rc::Rc;
@@ -143,6 +144,12 @@ pub struct ThreadRng {
     rng: Rc<RefCell<ThreadRngInner>>,
 }
 
+impl fmt::Debug for ThreadRng {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("ThreadRng { .. }")
+    }
+}
+
 /// Retrieve the lazily-initialized thread-local random number
 /// generator, seeded by the system. Intended to be used in method
 /// chaining style, e.g. `thread_rng().gen::<isize>()`.
diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs
index f46eab68484..b8e83dced8d 100644
--- a/src/libstd/sync/barrier.rs
+++ b/src/libstd/sync/barrier.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use fmt;
 use sync::{Mutex, Condvar};
 
 /// A barrier enables multiple threads to synchronize the beginning
@@ -54,6 +55,13 @@ struct BarrierState {
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BarrierWaitResult(bool);
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for Barrier {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Barrier { .. }")
+    }
+}
+
 impl Barrier {
     /// Creates a new barrier that can block a given number of threads.
     ///
@@ -102,6 +110,15 @@ impl Barrier {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for BarrierWaitResult {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("BarrierWaitResult")
+            .field("is_leader", &self.is_leader())
+            .finish()
+    }
+}
+
 impl BarrierWaitResult {
     /// Returns whether this thread from `wait` is the "leader thread".
     ///
diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs
index a983ae716a4..8ab30c51b28 100644
--- a/src/libstd/sync/condvar.rs
+++ b/src/libstd/sync/condvar.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use fmt;
 use sync::atomic::{AtomicUsize, Ordering};
 use sync::{mutex, MutexGuard, PoisonError};
 use sys_common::condvar as sys;
@@ -239,6 +240,13 @@ impl Condvar {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for Condvar {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Condvar { .. }")
+    }
+}
+
 #[stable(feature = "condvar_default", since = "1.9.0")]
 impl Default for Condvar {
     /// Creates a `Condvar` which is ready to be waited on and notified.
diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs
index ca6e46eb15a..aeeab170dea 100644
--- a/src/libstd/sync/mpsc/mod.rs
+++ b/src/libstd/sync/mpsc/mod.rs
@@ -306,6 +306,7 @@ impl<T> !Sync for Receiver<T> { }
 /// whenever `next` is called, waiting for a new message, and `None` will be
 /// returned when the corresponding channel has hung up.
 #[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug)]
 pub struct Iter<'a, T: 'a> {
     rx: &'a Receiver<T>
 }
@@ -316,7 +317,8 @@ pub struct Iter<'a, T: 'a> {
 ///
 /// This Iterator will never block the caller in order to wait for data to
 /// become available. Instead, it will return `None`.
-#[unstable(feature = "receiver_try_iter", issue = "34931")]
+#[stable(feature = "receiver_try_iter", since = "1.15.0")]
+#[derive(Debug)]
 pub struct TryIter<'a, T: 'a> {
     rx: &'a Receiver<T>
 }
@@ -325,6 +327,7 @@ pub struct TryIter<'a, T: 'a> {
 /// whenever `next` is called, waiting for a new message, and `None` will be
 /// returned when the corresponding channel has hung up.
 #[stable(feature = "receiver_into_iter", since = "1.1.0")]
+#[derive(Debug)]
 pub struct IntoIter<T> {
     rx: Receiver<T>
 }
@@ -348,7 +351,7 @@ impl<T> !Sync for Sender<T> { }
 /// owned by one thread, but it can be cloned to send to other threads.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct SyncSender<T> {
-    inner: Arc<UnsafeCell<sync::Packet<T>>>,
+    inner: Arc<sync::Packet<T>>,
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -426,10 +429,10 @@ pub enum TrySendError<T> {
 }
 
 enum Flavor<T> {
-    Oneshot(Arc<UnsafeCell<oneshot::Packet<T>>>),
-    Stream(Arc<UnsafeCell<stream::Packet<T>>>),
-    Shared(Arc<UnsafeCell<shared::Packet<T>>>),
-    Sync(Arc<UnsafeCell<sync::Packet<T>>>),
+    Oneshot(Arc<oneshot::Packet<T>>),
+    Stream(Arc<stream::Packet<T>>),
+    Shared(Arc<shared::Packet<T>>),
+    Sync(Arc<sync::Packet<T>>),
 }
 
 #[doc(hidden)]
@@ -454,10 +457,16 @@ impl<T> UnsafeFlavor<T> for Receiver<T> {
 }
 
 /// Creates a new asynchronous channel, returning the sender/receiver halves.
-///
 /// All data sent on the sender will become available on the receiver, and no
 /// send will block the calling thread (this channel has an "infinite buffer").
 ///
+/// If the [`Receiver`] is disconnected while trying to [`send()`] with the
+/// [`Sender`], the [`send()`] method will return an error.
+///
+/// [`send()`]: ../../../std/sync/mpsc/struct.Sender.html#method.send
+/// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html
+/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html
+///
 /// # Examples
 ///
 /// ```
@@ -481,24 +490,29 @@ impl<T> UnsafeFlavor<T> for Receiver<T> {
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
-    let a = Arc::new(UnsafeCell::new(oneshot::Packet::new()));
+    let a = Arc::new(oneshot::Packet::new());
     (Sender::new(Flavor::Oneshot(a.clone())), Receiver::new(Flavor::Oneshot(a)))
 }
 
 /// Creates a new synchronous, bounded channel.
 ///
-/// Like asynchronous channels, the `Receiver` will block until a message
+/// Like asynchronous channels, the [`Receiver`] will block until a message
 /// becomes available. These channels differ greatly in the semantics of the
 /// sender from asynchronous channels, however.
 ///
-/// This channel has an internal buffer on which messages will be queued. `bound`
-/// specifies the buffer size. When the internal buffer becomes full, future sends
-/// will *block* waiting for the buffer to open up. Note that a buffer size of 0
-/// is valid, in which case this becomes  "rendezvous channel" where each send will
-/// not return until a recv is paired with it.
+/// This channel has an internal buffer on which messages will be queued.
+/// `bound` specifies the buffer size. When the internal buffer becomes full,
+/// future sends will *block* waiting for the buffer to open up. Note that a
+/// buffer size of 0 is valid, in which case this becomes "rendezvous channel"
+/// where each [`send()`] will not return until a recv is paired with it.
 ///
-/// As with asynchronous channels, all senders will panic in `send` if the
-/// `Receiver` has been destroyed.
+/// Like asynchronous channels, if the [`Receiver`] is disconnected while
+/// trying to [`send()`] with the [`SyncSender`], the [`send()`] method will
+/// return an error.
+///
+/// [`send()`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send
+/// [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html
+/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html
 ///
 /// # Examples
 ///
@@ -521,7 +535,7 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
-    let a = Arc::new(UnsafeCell::new(sync::Packet::new(bound)));
+    let a = Arc::new(sync::Packet::new(bound));
     (SyncSender::new(a.clone()), Receiver::new(Flavor::Sync(a)))
 }
 
@@ -567,38 +581,30 @@ impl<T> Sender<T> {
     pub fn send(&self, t: T) -> Result<(), SendError<T>> {
         let (new_inner, ret) = match *unsafe { self.inner() } {
             Flavor::Oneshot(ref p) => {
-                unsafe {
-                    let p = p.get();
-                    if !(*p).sent() {
-                        return (*p).send(t).map_err(SendError);
-                    } else {
-                        let a =
-                            Arc::new(UnsafeCell::new(stream::Packet::new()));
-                        let rx = Receiver::new(Flavor::Stream(a.clone()));
-                        match (*p).upgrade(rx) {
-                            oneshot::UpSuccess => {
-                                let ret = (*a.get()).send(t);
-                                (a, ret)
-                            }
-                            oneshot::UpDisconnected => (a, Err(t)),
-                            oneshot::UpWoke(token) => {
-                                // This send cannot panic because the thread is
-                                // asleep (we're looking at it), so the receiver
-                                // can't go away.
-                                (*a.get()).send(t).ok().unwrap();
-                                token.signal();
-                                (a, Ok(()))
-                            }
+                if !p.sent() {
+                    return p.send(t).map_err(SendError);
+                } else {
+                    let a = Arc::new(stream::Packet::new());
+                    let rx = Receiver::new(Flavor::Stream(a.clone()));
+                    match p.upgrade(rx) {
+                        oneshot::UpSuccess => {
+                            let ret = a.send(t);
+                            (a, ret)
+                        }
+                        oneshot::UpDisconnected => (a, Err(t)),
+                        oneshot::UpWoke(token) => {
+                            // This send cannot panic because the thread is
+                            // asleep (we're looking at it), so the receiver
+                            // can't go away.
+                            a.send(t).ok().unwrap();
+                            token.signal();
+                            (a, Ok(()))
                         }
                     }
                 }
             }
-            Flavor::Stream(ref p) => return unsafe {
-                (*p.get()).send(t).map_err(SendError)
-            },
-            Flavor::Shared(ref p) => return unsafe {
-                (*p.get()).send(t).map_err(SendError)
-            },
+            Flavor::Stream(ref p) => return p.send(t).map_err(SendError),
+            Flavor::Shared(ref p) => return p.send(t).map_err(SendError),
             Flavor::Sync(..) => unreachable!(),
         };
 
@@ -613,41 +619,43 @@ impl<T> Sender<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Clone for Sender<T> {
     fn clone(&self) -> Sender<T> {
-        let (packet, sleeper, guard) = match *unsafe { self.inner() } {
+        let packet = match *unsafe { self.inner() } {
             Flavor::Oneshot(ref p) => {
-                let a = Arc::new(UnsafeCell::new(shared::Packet::new()));
-                unsafe {
-                    let guard = (*a.get()).postinit_lock();
+                let a = Arc::new(shared::Packet::new());
+                {
+                    let guard = a.postinit_lock();
                     let rx = Receiver::new(Flavor::Shared(a.clone()));
-                    match (*p.get()).upgrade(rx) {
+                    let sleeper = match p.upgrade(rx) {
                         oneshot::UpSuccess |
-                        oneshot::UpDisconnected => (a, None, guard),
-                        oneshot::UpWoke(task) => (a, Some(task), guard)
-                    }
+                        oneshot::UpDisconnected => None,
+                        oneshot::UpWoke(task) => Some(task),
+                    };
+                    a.inherit_blocker(sleeper, guard);
                 }
+                a
             }
             Flavor::Stream(ref p) => {
-                let a = Arc::new(UnsafeCell::new(shared::Packet::new()));
-                unsafe {
-                    let guard = (*a.get()).postinit_lock();
+                let a = Arc::new(shared::Packet::new());
+                {
+                    let guard = a.postinit_lock();
                     let rx = Receiver::new(Flavor::Shared(a.clone()));
-                    match (*p.get()).upgrade(rx) {
+                    let sleeper = match p.upgrade(rx) {
                         stream::UpSuccess |
-                        stream::UpDisconnected => (a, None, guard),
-                        stream::UpWoke(task) => (a, Some(task), guard),
-                    }
+                        stream::UpDisconnected => None,
+                        stream::UpWoke(task) => Some(task),
+                    };
+                    a.inherit_blocker(sleeper, guard);
                 }
+                a
             }
             Flavor::Shared(ref p) => {
-                unsafe { (*p.get()).clone_chan(); }
+                p.clone_chan();
                 return Sender::new(Flavor::Shared(p.clone()));
             }
             Flavor::Sync(..) => unreachable!(),
         };
 
         unsafe {
-            (*packet.get()).inherit_blocker(sleeper, guard);
-
             let tmp = Sender::new(Flavor::Shared(packet.clone()));
             mem::swap(self.inner_mut(), tmp.inner_mut());
         }
@@ -658,10 +666,10 @@ impl<T> Clone for Sender<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Drop for Sender<T> {
     fn drop(&mut self) {
-        match *unsafe { self.inner_mut() } {
-            Flavor::Oneshot(ref mut p) => unsafe { (*p.get()).drop_chan(); },
-            Flavor::Stream(ref mut p) => unsafe { (*p.get()).drop_chan(); },
-            Flavor::Shared(ref mut p) => unsafe { (*p.get()).drop_chan(); },
+        match *unsafe { self.inner() } {
+            Flavor::Oneshot(ref p) => p.drop_chan(),
+            Flavor::Stream(ref p) => p.drop_chan(),
+            Flavor::Shared(ref p) => p.drop_chan(),
             Flavor::Sync(..) => unreachable!(),
         }
     }
@@ -679,7 +687,7 @@ impl<T> fmt::Debug for Sender<T> {
 ////////////////////////////////////////////////////////////////////////////////
 
 impl<T> SyncSender<T> {
-    fn new(inner: Arc<UnsafeCell<sync::Packet<T>>>) -> SyncSender<T> {
+    fn new(inner: Arc<sync::Packet<T>>) -> SyncSender<T> {
         SyncSender { inner: inner }
     }
 
@@ -699,7 +707,7 @@ impl<T> SyncSender<T> {
     /// information.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn send(&self, t: T) -> Result<(), SendError<T>> {
-        unsafe { (*self.inner.get()).send(t).map_err(SendError) }
+        self.inner.send(t).map_err(SendError)
     }
 
     /// Attempts to send a value on this channel without blocking.
@@ -713,14 +721,14 @@ impl<T> SyncSender<T> {
     /// receiver has received the data or not if this function is successful.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> {
-        unsafe { (*self.inner.get()).try_send(t) }
+        self.inner.try_send(t)
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Clone for SyncSender<T> {
     fn clone(&self) -> SyncSender<T> {
-        unsafe { (*self.inner.get()).clone_chan(); }
+        self.inner.clone_chan();
         SyncSender::new(self.inner.clone())
     }
 }
@@ -728,7 +736,7 @@ impl<T> Clone for SyncSender<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Drop for SyncSender<T> {
     fn drop(&mut self) {
-        unsafe { (*self.inner.get()).drop_chan(); }
+        self.inner.drop_chan();
     }
 }
 
@@ -761,7 +769,7 @@ impl<T> Receiver<T> {
         loop {
             let new_port = match *unsafe { self.inner() } {
                 Flavor::Oneshot(ref p) => {
-                    match unsafe { (*p.get()).try_recv() } {
+                    match p.try_recv() {
                         Ok(t) => return Ok(t),
                         Err(oneshot::Empty) => return Err(TryRecvError::Empty),
                         Err(oneshot::Disconnected) => {
@@ -771,7 +779,7 @@ impl<T> Receiver<T> {
                     }
                 }
                 Flavor::Stream(ref p) => {
-                    match unsafe { (*p.get()).try_recv() } {
+                    match p.try_recv() {
                         Ok(t) => return Ok(t),
                         Err(stream::Empty) => return Err(TryRecvError::Empty),
                         Err(stream::Disconnected) => {
@@ -781,7 +789,7 @@ impl<T> Receiver<T> {
                     }
                 }
                 Flavor::Shared(ref p) => {
-                    match unsafe { (*p.get()).try_recv() } {
+                    match p.try_recv() {
                         Ok(t) => return Ok(t),
                         Err(shared::Empty) => return Err(TryRecvError::Empty),
                         Err(shared::Disconnected) => {
@@ -790,7 +798,7 @@ impl<T> Receiver<T> {
                     }
                 }
                 Flavor::Sync(ref p) => {
-                    match unsafe { (*p.get()).try_recv() } {
+                    match p.try_recv() {
                         Ok(t) => return Ok(t),
                         Err(sync::Empty) => return Err(TryRecvError::Empty),
                         Err(sync::Disconnected) => {
@@ -864,7 +872,7 @@ impl<T> Receiver<T> {
         loop {
             let new_port = match *unsafe { self.inner() } {
                 Flavor::Oneshot(ref p) => {
-                    match unsafe { (*p.get()).recv(None) } {
+                    match p.recv(None) {
                         Ok(t) => return Ok(t),
                         Err(oneshot::Disconnected) => return Err(RecvError),
                         Err(oneshot::Upgraded(rx)) => rx,
@@ -872,7 +880,7 @@ impl<T> Receiver<T> {
                     }
                 }
                 Flavor::Stream(ref p) => {
-                    match unsafe { (*p.get()).recv(None) } {
+                    match p.recv(None) {
                         Ok(t) => return Ok(t),
                         Err(stream::Disconnected) => return Err(RecvError),
                         Err(stream::Upgraded(rx)) => rx,
@@ -880,15 +888,13 @@ impl<T> Receiver<T> {
                     }
                 }
                 Flavor::Shared(ref p) => {
-                    match unsafe { (*p.get()).recv(None) } {
+                    match p.recv(None) {
                         Ok(t) => return Ok(t),
                         Err(shared::Disconnected) => return Err(RecvError),
                         Err(shared::Empty) => unreachable!(),
                     }
                 }
-                Flavor::Sync(ref p) => return unsafe {
-                    (*p.get()).recv(None).map_err(|_| RecvError)
-                }
+                Flavor::Sync(ref p) => return p.recv(None).map_err(|_| RecvError),
             };
             unsafe {
                 mem::swap(self.inner_mut(), new_port.inner_mut());
@@ -941,7 +947,7 @@ impl<T> Receiver<T> {
         loop {
             let port_or_empty = match *unsafe { self.inner() } {
                 Flavor::Oneshot(ref p) => {
-                    match unsafe { (*p.get()).recv(Some(deadline)) } {
+                    match p.recv(Some(deadline)) {
                         Ok(t) => return Ok(t),
                         Err(oneshot::Disconnected) => return Err(Disconnected),
                         Err(oneshot::Upgraded(rx)) => Some(rx),
@@ -949,7 +955,7 @@ impl<T> Receiver<T> {
                     }
                 }
                 Flavor::Stream(ref p) => {
-                    match unsafe { (*p.get()).recv(Some(deadline)) } {
+                    match p.recv(Some(deadline)) {
                         Ok(t) => return Ok(t),
                         Err(stream::Disconnected) => return Err(Disconnected),
                         Err(stream::Upgraded(rx)) => Some(rx),
@@ -957,14 +963,14 @@ impl<T> Receiver<T> {
                     }
                 }
                 Flavor::Shared(ref p) => {
-                    match unsafe { (*p.get()).recv(Some(deadline)) } {
+                    match p.recv(Some(deadline)) {
                         Ok(t) => return Ok(t),
                         Err(shared::Disconnected) => return Err(Disconnected),
                         Err(shared::Empty) => None,
                     }
                 }
                 Flavor::Sync(ref p) => {
-                    match unsafe { (*p.get()).recv(Some(deadline)) } {
+                    match p.recv(Some(deadline)) {
                         Ok(t) => return Ok(t),
                         Err(sync::Disconnected) => return Err(Disconnected),
                         Err(sync::Empty) => None,
@@ -997,7 +1003,7 @@ impl<T> Receiver<T> {
     /// It will return `None` if there are no more pending values or if the
     /// channel has hung up. The iterator will never `panic!` or block the
     /// user by waiting for values.
-    #[unstable(feature = "receiver_try_iter", issue = "34931")]
+    #[stable(feature = "receiver_try_iter", since = "1.15.0")]
     pub fn try_iter(&self) -> TryIter<T> {
         TryIter { rx: self }
     }
@@ -1009,23 +1015,19 @@ impl<T> select::Packet for Receiver<T> {
         loop {
             let new_port = match *unsafe { self.inner() } {
                 Flavor::Oneshot(ref p) => {
-                    match unsafe { (*p.get()).can_recv() } {
+                    match p.can_recv() {
                         Ok(ret) => return ret,
                         Err(upgrade) => upgrade,
                     }
                 }
                 Flavor::Stream(ref p) => {
-                    match unsafe { (*p.get()).can_recv() } {
+                    match p.can_recv() {
                         Ok(ret) => return ret,
                         Err(upgrade) => upgrade,
                     }
                 }
-                Flavor::Shared(ref p) => {
-                    return unsafe { (*p.get()).can_recv() };
-                }
-                Flavor::Sync(ref p) => {
-                    return unsafe { (*p.get()).can_recv() };
-                }
+                Flavor::Shared(ref p) => return p.can_recv(),
+                Flavor::Sync(ref p) => return p.can_recv(),
             };
             unsafe {
                 mem::swap(self.inner_mut(),
@@ -1038,25 +1040,21 @@ impl<T> select::Packet for Receiver<T> {
         loop {
             let (t, new_port) = match *unsafe { self.inner() } {
                 Flavor::Oneshot(ref p) => {
-                    match unsafe { (*p.get()).start_selection(token) } {
+                    match p.start_selection(token) {
                         oneshot::SelSuccess => return Installed,
                         oneshot::SelCanceled => return Abort,
                         oneshot::SelUpgraded(t, rx) => (t, rx),
                     }
                 }
                 Flavor::Stream(ref p) => {
-                    match unsafe { (*p.get()).start_selection(token) } {
+                    match p.start_selection(token) {
                         stream::SelSuccess => return Installed,
                         stream::SelCanceled => return Abort,
                         stream::SelUpgraded(t, rx) => (t, rx),
                     }
                 }
-                Flavor::Shared(ref p) => {
-                    return unsafe { (*p.get()).start_selection(token) };
-                }
-                Flavor::Sync(ref p) => {
-                    return unsafe { (*p.get()).start_selection(token) };
-                }
+                Flavor::Shared(ref p) => return p.start_selection(token),
+                Flavor::Sync(ref p) => return p.start_selection(token),
             };
             token = t;
             unsafe {
@@ -1069,16 +1067,10 @@ impl<T> select::Packet for Receiver<T> {
         let mut was_upgrade = false;
         loop {
             let result = match *unsafe { self.inner() } {
-                Flavor::Oneshot(ref p) => unsafe { (*p.get()).abort_selection() },
-                Flavor::Stream(ref p) => unsafe {
-                    (*p.get()).abort_selection(was_upgrade)
-                },
-                Flavor::Shared(ref p) => return unsafe {
-                    (*p.get()).abort_selection(was_upgrade)
-                },
-                Flavor::Sync(ref p) => return unsafe {
-                    (*p.get()).abort_selection()
-                },
+                Flavor::Oneshot(ref p) => p.abort_selection(),
+                Flavor::Stream(ref p) => p.abort_selection(was_upgrade),
+                Flavor::Shared(ref p) => return p.abort_selection(was_upgrade),
+                Flavor::Sync(ref p) => return p.abort_selection(),
             };
             let new_port = match result { Ok(b) => return b, Err(p) => p };
             was_upgrade = true;
@@ -1097,7 +1089,7 @@ impl<'a, T> Iterator for Iter<'a, T> {
     fn next(&mut self) -> Option<T> { self.rx.recv().ok() }
 }
 
-#[unstable(feature = "receiver_try_iter", issue = "34931")]
+#[stable(feature = "receiver_try_iter", since = "1.15.0")]
 impl<'a, T> Iterator for TryIter<'a, T> {
     type Item = T;
 
@@ -1131,11 +1123,11 @@ impl <T> IntoIterator for Receiver<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Drop for Receiver<T> {
     fn drop(&mut self) {
-        match *unsafe { self.inner_mut() } {
-            Flavor::Oneshot(ref mut p) => unsafe { (*p.get()).drop_port(); },
-            Flavor::Stream(ref mut p) => unsafe { (*p.get()).drop_port(); },
-            Flavor::Shared(ref mut p) => unsafe { (*p.get()).drop_port(); },
-            Flavor::Sync(ref mut p) => unsafe { (*p.get()).drop_port(); },
+        match *unsafe { self.inner() } {
+            Flavor::Oneshot(ref p) => p.drop_port(),
+            Flavor::Stream(ref p) => p.drop_port(),
+            Flavor::Shared(ref p) => p.drop_port(),
+            Flavor::Sync(ref p) => p.drop_port(),
         }
     }
 }
diff --git a/src/libstd/sync/mpsc/oneshot.rs b/src/libstd/sync/mpsc/oneshot.rs
index 767e9f96ac8..b8e50c9297b 100644
--- a/src/libstd/sync/mpsc/oneshot.rs
+++ b/src/libstd/sync/mpsc/oneshot.rs
@@ -39,7 +39,8 @@ use self::MyUpgrade::*;
 
 use sync::mpsc::Receiver;
 use sync::mpsc::blocking::{self, SignalToken};
-use core::mem;
+use cell::UnsafeCell;
+use ptr;
 use sync::atomic::{AtomicUsize, Ordering};
 use time::Instant;
 
@@ -57,10 +58,10 @@ pub struct Packet<T> {
     // Internal state of the chan/port pair (stores the blocked thread as well)
     state: AtomicUsize,
     // One-shot data slot location
-    data: Option<T>,
+    data: UnsafeCell<Option<T>>,
     // when used for the second time, a oneshot channel must be upgraded, and
     // this contains the slot for the upgrade
-    upgrade: MyUpgrade<T>,
+    upgrade: UnsafeCell<MyUpgrade<T>>,
 }
 
 pub enum Failure<T> {
@@ -90,42 +91,44 @@ enum MyUpgrade<T> {
 impl<T> Packet<T> {
     pub fn new() -> Packet<T> {
         Packet {
-            data: None,
-            upgrade: NothingSent,
+            data: UnsafeCell::new(None),
+            upgrade: UnsafeCell::new(NothingSent),
             state: AtomicUsize::new(EMPTY),
         }
     }
 
-    pub fn send(&mut self, t: T) -> Result<(), T> {
-        // Sanity check
-        match self.upgrade {
-            NothingSent => {}
-            _ => panic!("sending on a oneshot that's already sent on "),
-        }
-        assert!(self.data.is_none());
-        self.data = Some(t);
-        self.upgrade = SendUsed;
-
-        match self.state.swap(DATA, Ordering::SeqCst) {
-            // Sent the data, no one was waiting
-            EMPTY => Ok(()),
-
-            // Couldn't send the data, the port hung up first. Return the data
-            // back up the stack.
-            DISCONNECTED => {
-                self.state.swap(DISCONNECTED, Ordering::SeqCst);
-                self.upgrade = NothingSent;
-                Err(self.data.take().unwrap())
+    pub fn send(&self, t: T) -> Result<(), T> {
+        unsafe {
+            // Sanity check
+            match *self.upgrade.get() {
+                NothingSent => {}
+                _ => panic!("sending on a oneshot that's already sent on "),
             }
+            assert!((*self.data.get()).is_none());
+            ptr::write(self.data.get(), Some(t));
+            ptr::write(self.upgrade.get(), SendUsed);
+
+            match self.state.swap(DATA, Ordering::SeqCst) {
+                // Sent the data, no one was waiting
+                EMPTY => Ok(()),
+
+                // Couldn't send the data, the port hung up first. Return the data
+                // back up the stack.
+                DISCONNECTED => {
+                    self.state.swap(DISCONNECTED, Ordering::SeqCst);
+                    ptr::write(self.upgrade.get(), NothingSent);
+                    Err((&mut *self.data.get()).take().unwrap())
+                }
 
-            // Not possible, these are one-use channels
-            DATA => unreachable!(),
+                // Not possible, these are one-use channels
+                DATA => unreachable!(),
 
-            // There is a thread waiting on the other end. We leave the 'DATA'
-            // state inside so it'll pick it up on the other end.
-            ptr => unsafe {
-                SignalToken::cast_from_usize(ptr).signal();
-                Ok(())
+                // There is a thread waiting on the other end. We leave the 'DATA'
+                // state inside so it'll pick it up on the other end.
+                ptr => {
+                    SignalToken::cast_from_usize(ptr).signal();
+                    Ok(())
+                }
             }
         }
     }
@@ -133,13 +136,15 @@ impl<T> Packet<T> {
     // Just tests whether this channel has been sent on or not, this is only
     // safe to use from the sender.
     pub fn sent(&self) -> bool {
-        match self.upgrade {
-            NothingSent => false,
-            _ => true,
+        unsafe {
+            match *self.upgrade.get() {
+                NothingSent => false,
+                _ => true,
+            }
         }
     }
 
-    pub fn recv(&mut self, deadline: Option<Instant>) -> Result<T, Failure<T>> {
+    pub fn recv(&self, deadline: Option<Instant>) -> Result<T, Failure<T>> {
         // Attempt to not block the thread (it's a little expensive). If it looks
         // like we're not empty, then immediately go through to `try_recv`.
         if self.state.load(Ordering::SeqCst) == EMPTY {
@@ -167,73 +172,77 @@ impl<T> Packet<T> {
         self.try_recv()
     }
 
-    pub fn try_recv(&mut self) -> Result<T, Failure<T>> {
-        match self.state.load(Ordering::SeqCst) {
-            EMPTY => Err(Empty),
-
-            // We saw some data on the channel, but the channel can be used
-            // again to send us an upgrade. As a result, we need to re-insert
-            // into the channel that there's no data available (otherwise we'll
-            // just see DATA next time). This is done as a cmpxchg because if
-            // the state changes under our feet we'd rather just see that state
-            // change.
-            DATA => {
-                self.state.compare_and_swap(DATA, EMPTY, Ordering::SeqCst);
-                match self.data.take() {
-                    Some(data) => Ok(data),
-                    None => unreachable!(),
+    pub fn try_recv(&self) -> Result<T, Failure<T>> {
+        unsafe {
+            match self.state.load(Ordering::SeqCst) {
+                EMPTY => Err(Empty),
+
+                // We saw some data on the channel, but the channel can be used
+                // again to send us an upgrade. As a result, we need to re-insert
+                // into the channel that there's no data available (otherwise we'll
+                // just see DATA next time). This is done as a cmpxchg because if
+                // the state changes under our feet we'd rather just see that state
+                // change.
+                DATA => {
+                    self.state.compare_and_swap(DATA, EMPTY, Ordering::SeqCst);
+                    match (&mut *self.data.get()).take() {
+                        Some(data) => Ok(data),
+                        None => unreachable!(),
+                    }
                 }
-            }
 
-            // There's no guarantee that we receive before an upgrade happens,
-            // and an upgrade flags the channel as disconnected, so when we see
-            // this we first need to check if there's data available and *then*
-            // we go through and process the upgrade.
-            DISCONNECTED => {
-                match self.data.take() {
-                    Some(data) => Ok(data),
-                    None => {
-                        match mem::replace(&mut self.upgrade, SendUsed) {
-                            SendUsed | NothingSent => Err(Disconnected),
-                            GoUp(upgrade) => Err(Upgraded(upgrade))
+                // There's no guarantee that we receive before an upgrade happens,
+                // and an upgrade flags the channel as disconnected, so when we see
+                // this we first need to check if there's data available and *then*
+                // we go through and process the upgrade.
+                DISCONNECTED => {
+                    match (&mut *self.data.get()).take() {
+                        Some(data) => Ok(data),
+                        None => {
+                            match ptr::replace(self.upgrade.get(), SendUsed) {
+                                SendUsed | NothingSent => Err(Disconnected),
+                                GoUp(upgrade) => Err(Upgraded(upgrade))
+                            }
                         }
                     }
                 }
-            }
 
-            // We are the sole receiver; there cannot be a blocking
-            // receiver already.
-            _ => unreachable!()
+                // We are the sole receiver; there cannot be a blocking
+                // receiver already.
+                _ => unreachable!()
+            }
         }
     }
 
     // Returns whether the upgrade was completed. If the upgrade wasn't
     // completed, then the port couldn't get sent to the other half (it will
     // never receive it).
-    pub fn upgrade(&mut self, up: Receiver<T>) -> UpgradeResult {
-        let prev = match self.upgrade {
-            NothingSent => NothingSent,
-            SendUsed => SendUsed,
-            _ => panic!("upgrading again"),
-        };
-        self.upgrade = GoUp(up);
-
-        match self.state.swap(DISCONNECTED, Ordering::SeqCst) {
-            // If the channel is empty or has data on it, then we're good to go.
-            // Senders will check the data before the upgrade (in case we
-            // plastered over the DATA state).
-            DATA | EMPTY => UpSuccess,
-
-            // If the other end is already disconnected, then we failed the
-            // upgrade. Be sure to trash the port we were given.
-            DISCONNECTED => { self.upgrade = prev; UpDisconnected }
-
-            // If someone's waiting, we gotta wake them up
-            ptr => UpWoke(unsafe { SignalToken::cast_from_usize(ptr) })
+    pub fn upgrade(&self, up: Receiver<T>) -> UpgradeResult {
+        unsafe {
+            let prev = match *self.upgrade.get() {
+                NothingSent => NothingSent,
+                SendUsed => SendUsed,
+                _ => panic!("upgrading again"),
+            };
+            ptr::write(self.upgrade.get(), GoUp(up));
+
+            match self.state.swap(DISCONNECTED, Ordering::SeqCst) {
+                // If the channel is empty or has data on it, then we're good to go.
+                // Senders will check the data before the upgrade (in case we
+                // plastered over the DATA state).
+                DATA | EMPTY => UpSuccess,
+
+                // If the other end is already disconnected, then we failed the
+                // upgrade. Be sure to trash the port we were given.
+                DISCONNECTED => { ptr::replace(self.upgrade.get(), prev); UpDisconnected }
+
+                // If someone's waiting, we gotta wake them up
+                ptr => UpWoke(SignalToken::cast_from_usize(ptr))
+            }
         }
     }
 
-    pub fn drop_chan(&mut self) {
+    pub fn drop_chan(&self) {
         match self.state.swap(DISCONNECTED, Ordering::SeqCst) {
             DATA | DISCONNECTED | EMPTY => {}
 
@@ -244,7 +253,7 @@ impl<T> Packet<T> {
         }
     }
 
-    pub fn drop_port(&mut self) {
+    pub fn drop_port(&self) {
         match self.state.swap(DISCONNECTED, Ordering::SeqCst) {
             // An empty channel has nothing to do, and a remotely disconnected
             // channel also has nothing to do b/c we're about to run the drop
@@ -254,7 +263,7 @@ impl<T> Packet<T> {
             // There's data on the channel, so make sure we destroy it promptly.
             // This is why not using an arc is a little difficult (need the box
             // to stay valid while we take the data).
-            DATA => { self.data.take().unwrap(); }
+            DATA => unsafe { (&mut *self.data.get()).take().unwrap(); },
 
             // We're the only ones that can block on this port
             _ => unreachable!()
@@ -267,62 +276,66 @@ impl<T> Packet<T> {
 
     // If Ok, the value is whether this port has data, if Err, then the upgraded
     // port needs to be checked instead of this one.
-    pub fn can_recv(&mut self) -> Result<bool, Receiver<T>> {
-        match self.state.load(Ordering::SeqCst) {
-            EMPTY => Ok(false), // Welp, we tried
-            DATA => Ok(true),   // we have some un-acquired data
-            DISCONNECTED if self.data.is_some() => Ok(true), // we have data
-            DISCONNECTED => {
-                match mem::replace(&mut self.upgrade, SendUsed) {
-                    // The other end sent us an upgrade, so we need to
-                    // propagate upwards whether the upgrade can receive
-                    // data
-                    GoUp(upgrade) => Err(upgrade),
-
-                    // If the other end disconnected without sending an
-                    // upgrade, then we have data to receive (the channel is
-                    // disconnected).
-                    up => { self.upgrade = up; Ok(true) }
+    pub fn can_recv(&self) -> Result<bool, Receiver<T>> {
+        unsafe {
+            match self.state.load(Ordering::SeqCst) {
+                EMPTY => Ok(false), // Welp, we tried
+                DATA => Ok(true),   // we have some un-acquired data
+                DISCONNECTED if (*self.data.get()).is_some() => Ok(true), // we have data
+                DISCONNECTED => {
+                    match ptr::replace(self.upgrade.get(), SendUsed) {
+                        // The other end sent us an upgrade, so we need to
+                        // propagate upwards whether the upgrade can receive
+                        // data
+                        GoUp(upgrade) => Err(upgrade),
+
+                        // If the other end disconnected without sending an
+                        // upgrade, then we have data to receive (the channel is
+                        // disconnected).
+                        up => { ptr::write(self.upgrade.get(), up); Ok(true) }
+                    }
                 }
+                _ => unreachable!(), // we're the "one blocker"
             }
-            _ => unreachable!(), // we're the "one blocker"
         }
     }
 
     // Attempts to start selection on this port. This can either succeed, fail
     // because there is data, or fail because there is an upgrade pending.
-    pub fn start_selection(&mut self, token: SignalToken) -> SelectionResult<T> {
-        let ptr = unsafe { token.cast_to_usize() };
-        match self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) {
-            EMPTY => SelSuccess,
-            DATA => {
-                drop(unsafe { SignalToken::cast_from_usize(ptr) });
-                SelCanceled
-            }
-            DISCONNECTED if self.data.is_some() => {
-                drop(unsafe { SignalToken::cast_from_usize(ptr) });
-                SelCanceled
-            }
-            DISCONNECTED => {
-                match mem::replace(&mut self.upgrade, SendUsed) {
-                    // The other end sent us an upgrade, so we need to
-                    // propagate upwards whether the upgrade can receive
-                    // data
-                    GoUp(upgrade) => {
-                        SelUpgraded(unsafe { SignalToken::cast_from_usize(ptr) }, upgrade)
-                    }
+    pub fn start_selection(&self, token: SignalToken) -> SelectionResult<T> {
+        unsafe {
+            let ptr = token.cast_to_usize();
+            match self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) {
+                EMPTY => SelSuccess,
+                DATA => {
+                    drop(SignalToken::cast_from_usize(ptr));
+                    SelCanceled
+                }
+                DISCONNECTED if (*self.data.get()).is_some() => {
+                    drop(SignalToken::cast_from_usize(ptr));
+                    SelCanceled
+                }
+                DISCONNECTED => {
+                    match ptr::replace(self.upgrade.get(), SendUsed) {
+                        // The other end sent us an upgrade, so we need to
+                        // propagate upwards whether the upgrade can receive
+                        // data
+                        GoUp(upgrade) => {
+                            SelUpgraded(SignalToken::cast_from_usize(ptr), upgrade)
+                        }
 
-                    // If the other end disconnected without sending an
-                    // upgrade, then we have data to receive (the channel is
-                    // disconnected).
-                    up => {
-                        self.upgrade = up;
-                        drop(unsafe { SignalToken::cast_from_usize(ptr) });
-                        SelCanceled
+                        // If the other end disconnected without sending an
+                        // upgrade, then we have data to receive (the channel is
+                        // disconnected).
+                        up => {
+                            ptr::write(self.upgrade.get(), up);
+                            drop(SignalToken::cast_from_usize(ptr));
+                            SelCanceled
+                        }
                     }
                 }
+                _ => unreachable!(), // we're the "one blocker"
             }
-            _ => unreachable!(), // we're the "one blocker"
         }
     }
 
@@ -330,7 +343,7 @@ impl<T> Packet<T> {
     // blocked thread will no longer be visible to any other threads.
     //
     // The return value indicates whether there's data on this port.
-    pub fn abort_selection(&mut self) -> Result<bool, Receiver<T>> {
+    pub fn abort_selection(&self) -> Result<bool, Receiver<T>> {
         let state = match self.state.load(Ordering::SeqCst) {
             // Each of these states means that no further activity will happen
             // with regard to abortion selection
@@ -356,16 +369,16 @@ impl<T> Packet<T> {
             //
             // We then need to check to see if there was an upgrade requested,
             // and if so, the upgraded port needs to have its selection aborted.
-            DISCONNECTED => {
-                if self.data.is_some() {
+            DISCONNECTED => unsafe {
+                if (*self.data.get()).is_some() {
                     Ok(true)
                 } else {
-                    match mem::replace(&mut self.upgrade, SendUsed) {
+                    match ptr::replace(self.upgrade.get(), SendUsed) {
                         GoUp(port) => Err(port),
                         _ => Ok(true),
                     }
                 }
-            }
+            },
 
             // We woke ourselves up from select.
             ptr => unsafe {
diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs
index 2a9618251ff..f9e02904164 100644
--- a/src/libstd/sync/mpsc/shared.rs
+++ b/src/libstd/sync/mpsc/shared.rs
@@ -24,6 +24,8 @@ use core::cmp;
 use core::intrinsics::abort;
 use core::isize;
 
+use cell::UnsafeCell;
+use ptr;
 use sync::atomic::{AtomicUsize, AtomicIsize, AtomicBool, Ordering};
 use sync::mpsc::blocking::{self, SignalToken};
 use sync::mpsc::mpsc_queue as mpsc;
@@ -44,7 +46,7 @@ const MAX_STEALS: isize = 1 << 20;
 pub struct Packet<T> {
     queue: mpsc::Queue<T>,
     cnt: AtomicIsize, // How many items are on this channel
-    steals: isize, // How many times has a port received without blocking?
+    steals: UnsafeCell<isize>, // How many times has a port received without blocking?
     to_wake: AtomicUsize, // SignalToken for wake up
 
     // The number of channels which are currently using this packet.
@@ -72,7 +74,7 @@ impl<T> Packet<T> {
         Packet {
             queue: mpsc::Queue::new(),
             cnt: AtomicIsize::new(0),
-            steals: 0,
+            steals: UnsafeCell::new(0),
             to_wake: AtomicUsize::new(0),
             channels: AtomicUsize::new(2),
             port_dropped: AtomicBool::new(false),
@@ -95,7 +97,7 @@ impl<T> Packet<T> {
     // threads in select().
     //
     // This can only be called at channel-creation time
-    pub fn inherit_blocker(&mut self,
+    pub fn inherit_blocker(&self,
                            token: Option<SignalToken>,
                            guard: MutexGuard<()>) {
         token.map(|token| {
@@ -122,7 +124,7 @@ impl<T> Packet<T> {
             // To offset this bad increment, we initially set the steal count to
             // -1. You'll find some special code in abort_selection() as well to
             // ensure that this -1 steal count doesn't escape too far.
-            self.steals = -1;
+            unsafe { *self.steals.get() = -1; }
         });
 
         // When the shared packet is constructed, we grabbed this lock. The
@@ -133,7 +135,7 @@ impl<T> Packet<T> {
         drop(guard);
     }
 
-    pub fn send(&mut self, t: T) -> Result<(), T> {
+    pub fn send(&self, t: T) -> Result<(), T> {
         // See Port::drop for what's going on
         if self.port_dropped.load(Ordering::SeqCst) { return Err(t) }
 
@@ -218,7 +220,7 @@ impl<T> Packet<T> {
         Ok(())
     }
 
-    pub fn recv(&mut self, deadline: Option<Instant>) -> Result<T, Failure> {
+    pub fn recv(&self, deadline: Option<Instant>) -> Result<T, Failure> {
         // This code is essentially the exact same as that found in the stream
         // case (see stream.rs)
         match self.try_recv() {
@@ -239,37 +241,38 @@ impl<T> Packet<T> {
         }
 
         match self.try_recv() {
-            data @ Ok(..) => { self.steals -= 1; data }
+            data @ Ok(..) => unsafe { *self.steals.get() -= 1; data },
             data => data,
         }
     }
 
     // Essentially the exact same thing as the stream decrement function.
     // Returns true if blocking should proceed.
-    fn decrement(&mut self, token: SignalToken) -> StartResult {
-        assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
-        let ptr = unsafe { token.cast_to_usize() };
-        self.to_wake.store(ptr, Ordering::SeqCst);
-
-        let steals = self.steals;
-        self.steals = 0;
-
-        match self.cnt.fetch_sub(1 + steals, Ordering::SeqCst) {
-            DISCONNECTED => { self.cnt.store(DISCONNECTED, Ordering::SeqCst); }
-            // If we factor in our steals and notice that the channel has no
-            // data, we successfully sleep
-            n => {
-                assert!(n >= 0);
-                if n - steals <= 0 { return Installed }
+    fn decrement(&self, token: SignalToken) -> StartResult {
+        unsafe {
+            assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+            let ptr = token.cast_to_usize();
+            self.to_wake.store(ptr, Ordering::SeqCst);
+
+            let steals = ptr::replace(self.steals.get(), 0);
+
+            match self.cnt.fetch_sub(1 + steals, Ordering::SeqCst) {
+                DISCONNECTED => { self.cnt.store(DISCONNECTED, Ordering::SeqCst); }
+                // If we factor in our steals and notice that the channel has no
+                // data, we successfully sleep
+                n => {
+                    assert!(n >= 0);
+                    if n - steals <= 0 { return Installed }
+                }
             }
-        }
 
-        self.to_wake.store(0, Ordering::SeqCst);
-        drop(unsafe { SignalToken::cast_from_usize(ptr) });
-        Abort
+            self.to_wake.store(0, Ordering::SeqCst);
+            drop(SignalToken::cast_from_usize(ptr));
+            Abort
+        }
     }
 
-    pub fn try_recv(&mut self) -> Result<T, Failure> {
+    pub fn try_recv(&self) -> Result<T, Failure> {
         let ret = match self.queue.pop() {
             mpsc::Data(t) => Some(t),
             mpsc::Empty => None,
@@ -303,23 +306,23 @@ impl<T> Packet<T> {
         match ret {
             // See the discussion in the stream implementation for why we
             // might decrement steals.
-            Some(data) => {
-                if self.steals > MAX_STEALS {
+            Some(data) => unsafe {
+                if *self.steals.get() > MAX_STEALS {
                     match self.cnt.swap(0, Ordering::SeqCst) {
                         DISCONNECTED => {
                             self.cnt.store(DISCONNECTED, Ordering::SeqCst);
                         }
                         n => {
-                            let m = cmp::min(n, self.steals);
-                            self.steals -= m;
+                            let m = cmp::min(n, *self.steals.get());
+                            *self.steals.get() -= m;
                             self.bump(n - m);
                         }
                     }
-                    assert!(self.steals >= 0);
+                    assert!(*self.steals.get() >= 0);
                 }
-                self.steals += 1;
+                *self.steals.get() += 1;
                 Ok(data)
-            }
+            },
 
             // See the discussion in the stream implementation for why we try
             // again.
@@ -341,7 +344,7 @@ impl<T> Packet<T> {
 
     // Prepares this shared packet for a channel clone, essentially just bumping
     // a refcount.
-    pub fn clone_chan(&mut self) {
+    pub fn clone_chan(&self) {
         let old_count = self.channels.fetch_add(1, Ordering::SeqCst);
 
         // See comments on Arc::clone() on why we do this (for `mem::forget`).
@@ -355,7 +358,7 @@ impl<T> Packet<T> {
     // Decrement the reference count on a channel. This is called whenever a
     // Chan is dropped and may end up waking up a receiver. It's the receiver's
     // responsibility on the other end to figure out that we've disconnected.
-    pub fn drop_chan(&mut self) {
+    pub fn drop_chan(&self) {
         match self.channels.fetch_sub(1, Ordering::SeqCst) {
             1 => {}
             n if n > 1 => return,
@@ -371,9 +374,9 @@ impl<T> Packet<T> {
 
     // See the long discussion inside of stream.rs for why the queue is drained,
     // and why it is done in this fashion.
-    pub fn drop_port(&mut self) {
+    pub fn drop_port(&self) {
         self.port_dropped.store(true, Ordering::SeqCst);
-        let mut steals = self.steals;
+        let mut steals = unsafe { *self.steals.get() };
         while {
             let cnt = self.cnt.compare_and_swap(steals, DISCONNECTED, Ordering::SeqCst);
             cnt != DISCONNECTED && cnt != steals
@@ -390,7 +393,7 @@ impl<T> Packet<T> {
     }
 
     // Consumes ownership of the 'to_wake' field.
-    fn take_to_wake(&mut self) -> SignalToken {
+    fn take_to_wake(&self) -> SignalToken {
         let ptr = self.to_wake.load(Ordering::SeqCst);
         self.to_wake.store(0, Ordering::SeqCst);
         assert!(ptr != 0);
@@ -406,13 +409,13 @@ impl<T> Packet<T> {
     //
     // This is different than the stream version because there's no need to peek
     // at the queue, we can just look at the local count.
-    pub fn can_recv(&mut self) -> bool {
+    pub fn can_recv(&self) -> bool {
         let cnt = self.cnt.load(Ordering::SeqCst);
-        cnt == DISCONNECTED || cnt - self.steals > 0
+        cnt == DISCONNECTED || cnt - unsafe { *self.steals.get() } > 0
     }
 
     // increment the count on the channel (used for selection)
-    fn bump(&mut self, amt: isize) -> isize {
+    fn bump(&self, amt: isize) -> isize {
         match self.cnt.fetch_add(amt, Ordering::SeqCst) {
             DISCONNECTED => {
                 self.cnt.store(DISCONNECTED, Ordering::SeqCst);
@@ -427,7 +430,7 @@ impl<T> Packet<T> {
     //
     // The code here is the same as in stream.rs, except that it doesn't need to
     // peek at the channel to see if an upgrade is pending.
-    pub fn start_selection(&mut self, token: SignalToken) -> StartResult {
+    pub fn start_selection(&self, token: SignalToken) -> StartResult {
         match self.decrement(token) {
             Installed => Installed,
             Abort => {
@@ -443,7 +446,7 @@ impl<T> Packet<T> {
     //
     // This is similar to the stream implementation (hence fewer comments), but
     // uses a different value for the "steals" variable.
-    pub fn abort_selection(&mut self, _was_upgrade: bool) -> bool {
+    pub fn abort_selection(&self, _was_upgrade: bool) -> bool {
         // Before we do anything else, we bounce on this lock. The reason for
         // doing this is to ensure that any upgrade-in-progress is gone and
         // done with. Without this bounce, we can race with inherit_blocker
@@ -477,12 +480,15 @@ impl<T> Packet<T> {
                     thread::yield_now();
                 }
             }
-            // if the number of steals is -1, it was the pre-emptive -1 steal
-            // count from when we inherited a blocker. This is fine because
-            // we're just going to overwrite it with a real value.
-            assert!(self.steals == 0 || self.steals == -1);
-            self.steals = steals;
-            prev >= 0
+            unsafe {
+                // if the number of steals is -1, it was the pre-emptive -1 steal
+                // count from when we inherited a blocker. This is fine because
+                // we're just going to overwrite it with a real value.
+                let old = self.steals.get();
+                assert!(*old == 0 || *old == -1);
+                *old = steals;
+                prev >= 0
+            }
         }
     }
 }
diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs
index 61c8316467d..47cd8977fda 100644
--- a/src/libstd/sync/mpsc/stream.rs
+++ b/src/libstd/sync/mpsc/stream.rs
@@ -22,8 +22,10 @@ pub use self::UpgradeResult::*;
 pub use self::SelectionResult::*;
 use self::Message::*;
 
+use cell::UnsafeCell;
 use core::cmp;
 use core::isize;
+use ptr;
 use thread;
 use time::Instant;
 
@@ -42,7 +44,7 @@ pub struct Packet<T> {
     queue: spsc::Queue<Message<T>>, // internal queue for all message
 
     cnt: AtomicIsize, // How many items are on this channel
-    steals: isize, // How many times has a port received without blocking?
+    steals: UnsafeCell<isize>, // How many times has a port received without blocking?
     to_wake: AtomicUsize, // SignalToken for the blocked thread to wake up
 
     port_dropped: AtomicBool, // flag if the channel has been destroyed.
@@ -79,14 +81,14 @@ impl<T> Packet<T> {
             queue: unsafe { spsc::Queue::new(128) },
 
             cnt: AtomicIsize::new(0),
-            steals: 0,
+            steals: UnsafeCell::new(0),
             to_wake: AtomicUsize::new(0),
 
             port_dropped: AtomicBool::new(false),
         }
     }
 
-    pub fn send(&mut self, t: T) -> Result<(), T> {
+    pub fn send(&self, t: T) -> Result<(), T> {
         // If the other port has deterministically gone away, then definitely
         // must return the data back up the stack. Otherwise, the data is
         // considered as being sent.
@@ -99,7 +101,7 @@ impl<T> Packet<T> {
         Ok(())
     }
 
-    pub fn upgrade(&mut self, up: Receiver<T>) -> UpgradeResult {
+    pub fn upgrade(&self, up: Receiver<T>) -> UpgradeResult {
         // If the port has gone away, then there's no need to proceed any
         // further.
         if self.port_dropped.load(Ordering::SeqCst) { return UpDisconnected }
@@ -107,7 +109,7 @@ impl<T> Packet<T> {
         self.do_send(GoUp(up))
     }
 
-    fn do_send(&mut self, t: Message<T>) -> UpgradeResult {
+    fn do_send(&self, t: Message<T>) -> UpgradeResult {
         self.queue.push(t);
         match self.cnt.fetch_add(1, Ordering::SeqCst) {
             // As described in the mod's doc comment, -1 == wakeup
@@ -141,7 +143,7 @@ impl<T> Packet<T> {
     }
 
     // Consumes ownership of the 'to_wake' field.
-    fn take_to_wake(&mut self) -> SignalToken {
+    fn take_to_wake(&self) -> SignalToken {
         let ptr = self.to_wake.load(Ordering::SeqCst);
         self.to_wake.store(0, Ordering::SeqCst);
         assert!(ptr != 0);
@@ -151,13 +153,12 @@ impl<T> Packet<T> {
     // Decrements the count on the channel for a sleeper, returning the sleeper
     // back if it shouldn't sleep. Note that this is the location where we take
     // steals into account.
-    fn decrement(&mut self, token: SignalToken) -> Result<(), SignalToken> {
+    fn decrement(&self, token: SignalToken) -> Result<(), SignalToken> {
         assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
         let ptr = unsafe { token.cast_to_usize() };
         self.to_wake.store(ptr, Ordering::SeqCst);
 
-        let steals = self.steals;
-        self.steals = 0;
+        let steals = unsafe { ptr::replace(self.steals.get(), 0) };
 
         match self.cnt.fetch_sub(1 + steals, Ordering::SeqCst) {
             DISCONNECTED => { self.cnt.store(DISCONNECTED, Ordering::SeqCst); }
@@ -173,7 +174,7 @@ impl<T> Packet<T> {
         Err(unsafe { SignalToken::cast_from_usize(ptr) })
     }
 
-    pub fn recv(&mut self, deadline: Option<Instant>) -> Result<T, Failure<T>> {
+    pub fn recv(&self, deadline: Option<Instant>) -> Result<T, Failure<T>> {
         // Optimistic preflight check (scheduling is expensive).
         match self.try_recv() {
             Err(Empty) => {}
@@ -199,16 +200,16 @@ impl<T> Packet<T> {
             // a steal, so offset the decrement here (we already have our
             // "steal" factored into the channel count above).
             data @ Ok(..) |
-            data @ Err(Upgraded(..)) => {
-                self.steals -= 1;
+            data @ Err(Upgraded(..)) => unsafe {
+                *self.steals.get() -= 1;
                 data
-            }
+            },
 
             data => data,
         }
     }
 
-    pub fn try_recv(&mut self) -> Result<T, Failure<T>> {
+    pub fn try_recv(&self) -> Result<T, Failure<T>> {
         match self.queue.pop() {
             // If we stole some data, record to that effect (this will be
             // factored into cnt later on).
@@ -221,26 +222,26 @@ impl<T> Packet<T> {
             // a pretty slow operation, of swapping 0 into cnt, taking steals
             // down as much as possible (without going negative), and then
             // adding back in whatever we couldn't factor into steals.
-            Some(data) => {
-                if self.steals > MAX_STEALS {
+            Some(data) => unsafe {
+                if *self.steals.get() > MAX_STEALS {
                     match self.cnt.swap(0, Ordering::SeqCst) {
                         DISCONNECTED => {
                             self.cnt.store(DISCONNECTED, Ordering::SeqCst);
                         }
                         n => {
-                            let m = cmp::min(n, self.steals);
-                            self.steals -= m;
+                            let m = cmp::min(n, *self.steals.get());
+                            *self.steals.get() -= m;
                             self.bump(n - m);
                         }
                     }
-                    assert!(self.steals >= 0);
+                    assert!(*self.steals.get() >= 0);
                 }
-                self.steals += 1;
+                *self.steals.get() += 1;
                 match data {
                     Data(t) => Ok(t),
                     GoUp(up) => Err(Upgraded(up)),
                 }
-            }
+            },
 
             None => {
                 match self.cnt.load(Ordering::SeqCst) {
@@ -269,7 +270,7 @@ impl<T> Packet<T> {
         }
     }
 
-    pub fn drop_chan(&mut self) {
+    pub fn drop_chan(&self) {
         // Dropping a channel is pretty simple, we just flag it as disconnected
         // and then wakeup a blocker if there is one.
         match self.cnt.swap(DISCONNECTED, Ordering::SeqCst) {
@@ -279,7 +280,7 @@ impl<T> Packet<T> {
         }
     }
 
-    pub fn drop_port(&mut self) {
+    pub fn drop_port(&self) {
         // Dropping a port seems like a fairly trivial thing. In theory all we
         // need to do is flag that we're disconnected and then everything else
         // can take over (we don't have anyone to wake up).
@@ -309,7 +310,7 @@ impl<T> Packet<T> {
         // continue to fail while active senders send data while we're dropping
         // data, but eventually we're guaranteed to break out of this loop
         // (because there is a bounded number of senders).
-        let mut steals = self.steals;
+        let mut steals = unsafe { *self.steals.get() };
         while {
             let cnt = self.cnt.compare_and_swap(
                             steals, DISCONNECTED, Ordering::SeqCst);
@@ -332,7 +333,7 @@ impl<T> Packet<T> {
     // Tests to see whether this port can receive without blocking. If Ok is
     // returned, then that's the answer. If Err is returned, then the returned
     // port needs to be queried instead (an upgrade happened)
-    pub fn can_recv(&mut self) -> Result<bool, Receiver<T>> {
+    pub fn can_recv(&self) -> Result<bool, Receiver<T>> {
         // We peek at the queue to see if there's anything on it, and we use
         // this return value to determine if we should pop from the queue and
         // upgrade this channel immediately. If it looks like we've got an
@@ -351,7 +352,7 @@ impl<T> Packet<T> {
     }
 
     // increment the count on the channel (used for selection)
-    fn bump(&mut self, amt: isize) -> isize {
+    fn bump(&self, amt: isize) -> isize {
         match self.cnt.fetch_add(amt, Ordering::SeqCst) {
             DISCONNECTED => {
                 self.cnt.store(DISCONNECTED, Ordering::SeqCst);
@@ -363,7 +364,7 @@ impl<T> Packet<T> {
 
     // Attempts to start selecting on this port. Like a oneshot, this can fail
     // immediately because of an upgrade.
-    pub fn start_selection(&mut self, token: SignalToken) -> SelectionResult<T> {
+    pub fn start_selection(&self, token: SignalToken) -> SelectionResult<T> {
         match self.decrement(token) {
             Ok(()) => SelSuccess,
             Err(token) => {
@@ -387,7 +388,7 @@ impl<T> Packet<T> {
     }
 
     // Removes a previous thread from being blocked in this port
-    pub fn abort_selection(&mut self,
+    pub fn abort_selection(&self,
                            was_upgrade: bool) -> Result<bool, Receiver<T>> {
         // If we're aborting selection after upgrading from a oneshot, then
         // we're guarantee that no one is waiting. The only way that we could
@@ -403,7 +404,7 @@ impl<T> Packet<T> {
         // this end. This is fine because we know it's a small bounded windows
         // of time until the data is actually sent.
         if was_upgrade {
-            assert_eq!(self.steals, 0);
+            assert_eq!(unsafe { *self.steals.get() }, 0);
             assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
             return Ok(true)
         }
@@ -444,8 +445,10 @@ impl<T> Packet<T> {
                     thread::yield_now();
                 }
             }
-            assert_eq!(self.steals, 0);
-            self.steals = steals;
+            unsafe {
+                assert_eq!(*self.steals.get(), 0);
+                *self.steals.get() = steals;
+            }
 
             // if we were previously positive, then there's surely data to
             // receive
diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs
index df4a3746a49..f6dbe01d7bd 100644
--- a/src/libstd/sync/mutex.rs
+++ b/src/libstd/sync/mutex.rs
@@ -351,6 +351,15 @@ impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'a, T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("MutexGuard")
+            .field("lock", &self.__lock)
+            .finish()
+    }
+}
+
 pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
     &guard.__lock.inner
 }
diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs
index 71e163321ae..a9747639aac 100644
--- a/src/libstd/sync/once.rs
+++ b/src/libstd/sync/once.rs
@@ -64,6 +64,7 @@
 // You'll find a few more details in the implementation, but that's the gist of
 // it!
 
+use fmt;
 use marker;
 use ptr;
 use sync::atomic::{AtomicUsize, AtomicBool, Ordering};
@@ -103,6 +104,7 @@ unsafe impl Send for Once {}
 /// State yielded to the `call_once_force` method which can be used to query
 /// whether the `Once` was previously poisoned or not.
 #[unstable(feature = "once_poison", issue = "33577")]
+#[derive(Debug)]
 pub struct OnceState {
     poisoned: bool,
 }
@@ -328,6 +330,13 @@ impl Once {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for Once {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Once { .. }")
+    }
+}
+
 impl Drop for Finish {
     fn drop(&mut self) {
         // Swap out our state with however we finished. We should only ever see
diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs
index f83cf7ba9c2..0a11c71706b 100644
--- a/src/libstd/sync/rwlock.rs
+++ b/src/libstd/sync/rwlock.rs
@@ -362,6 +362,24 @@ impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a, T: fmt::Debug> fmt::Debug for RwLockReadGuard<'a, T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("RwLockReadGuard")
+            .field("lock", &self.__lock)
+            .finish()
+    }
+}
+
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<'a, T: fmt::Debug> fmt::Debug for RwLockWriteGuard<'a, T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("RwLockWriteGuard")
+            .field("lock", &self.__lock)
+            .finish()
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'rwlock, T: ?Sized> Deref for RwLockReadGuard<'rwlock, T> {
     type Target = T;
diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs
index 0c45ab8a887..14da376efa9 100644
--- a/src/libstd/sys/mod.rs
+++ b/src/libstd/sys/mod.rs
@@ -30,8 +30,14 @@
 //! inter-dependencies within `std` that will be a challenging goal to
 //! achieve.
 
+#![allow(missing_debug_implementations)]
+
 pub use self::imp::*;
 
+#[cfg(target_os = "redox")]
+#[path = "redox/mod.rs"]
+mod imp;
+
 #[cfg(unix)]
 #[path = "unix/mod.rs"]
 mod imp;
diff --git a/src/libstd/sys/redox/args.rs b/src/libstd/sys/redox/args.rs
new file mode 100644
index 00000000000..f6fea2f1076
--- /dev/null
+++ b/src/libstd/sys/redox/args.rs
@@ -0,0 +1,109 @@
+// 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.
+
+//! Global initialization and retreival of command line arguments.
+//!
+//! On some platforms these are stored during runtime startup,
+//! and on some they are retrieved from the system on demand.
+
+#![allow(dead_code)] // runtime init functions not used during testing
+
+use ffi::OsString;
+use marker::PhantomData;
+use vec;
+
+/// One-time global initialization.
+pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
+
+/// One-time global cleanup.
+pub unsafe fn cleanup() { imp::cleanup() }
+
+/// Returns the command line arguments
+pub fn args() -> Args {
+    imp::args()
+}
+
+pub struct Args {
+    iter: vec::IntoIter<OsString>,
+    _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Iterator for Args {
+    type Item = OsString;
+    fn next(&mut self) -> Option<OsString> { self.iter.next() }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+impl ExactSizeIterator for Args {
+    fn len(&self) -> usize { self.iter.len() }
+}
+
+impl DoubleEndedIterator for Args {
+    fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
+}
+
+mod imp {
+    use os::unix::prelude::*;
+    use mem;
+    use ffi::OsString;
+    use marker::PhantomData;
+    use slice;
+    use str;
+    use super::Args;
+
+    use sys_common::mutex::Mutex;
+
+    static mut GLOBAL_ARGS_PTR: usize = 0;
+    static LOCK: Mutex = Mutex::new();
+
+    pub unsafe fn init(argc: isize, argv: *const *const u8) {
+        let mut args: Vec<Vec<u8>> = Vec::new();
+        for i in 0..argc {
+            let len = *(argv.offset(i * 2)) as usize;
+            let ptr = *(argv.offset(i * 2 + 1));
+            args.push(slice::from_raw_parts(ptr, len).to_vec());
+        }
+
+        LOCK.lock();
+        let ptr = get_global_ptr();
+        assert!((*ptr).is_none());
+        (*ptr) = Some(box args);
+        LOCK.unlock();
+    }
+
+    pub unsafe fn cleanup() {
+        LOCK.lock();
+        *get_global_ptr() = None;
+        LOCK.unlock();
+    }
+
+    pub fn args() -> Args {
+        let bytes = clone().unwrap_or(Vec::new());
+        let v: Vec<OsString> = bytes.into_iter().map(|v| {
+            OsStringExt::from_vec(v)
+        }).collect();
+        Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
+    }
+
+    fn clone() -> Option<Vec<Vec<u8>>> {
+        unsafe {
+            LOCK.lock();
+            let ptr = get_global_ptr();
+            let ret = (*ptr).as_ref().map(|s| (**s).clone());
+            LOCK.unlock();
+            return ret
+        }
+    }
+
+    fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
+        unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
+    }
+
+}
diff --git a/src/libstd/sys/redox/backtrace.rs b/src/libstd/sys/redox/backtrace.rs
new file mode 100644
index 00000000000..6f53841502a
--- /dev/null
+++ b/src/libstd/sys/redox/backtrace.rs
@@ -0,0 +1,18 @@
+// 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 libc;
+use io;
+use sys_common::backtrace::output;
+
+#[inline(never)]
+pub fn write(w: &mut io::Write) -> io::Result<()> {
+    output(w, 0, 0 as *mut libc::c_void, None)
+}
diff --git a/src/libstd/sys/redox/condvar.rs b/src/libstd/sys/redox/condvar.rs
new file mode 100644
index 00000000000..0ca0987b245
--- /dev/null
+++ b/src/libstd/sys/redox/condvar.rs
@@ -0,0 +1,106 @@
+// 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 cell::UnsafeCell;
+use intrinsics::{atomic_cxchg, atomic_xadd, atomic_xchg};
+use ptr;
+use time::Duration;
+
+use sys::mutex::{mutex_lock, mutex_unlock, Mutex};
+use sys::syscall::{futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE};
+
+pub struct Condvar {
+    lock: UnsafeCell<*mut i32>,
+    seq: UnsafeCell<i32>
+}
+
+impl Condvar {
+    pub const fn new() -> Condvar {
+        Condvar {
+            lock: UnsafeCell::new(ptr::null_mut()),
+            seq: UnsafeCell::new(0)
+        }
+    }
+
+    #[inline]
+    pub unsafe fn init(&self) {
+        *self.lock.get() = ptr::null_mut();
+        *self.seq.get() = 0;
+    }
+
+    #[inline]
+    pub fn notify_one(&self) {
+        unsafe {
+            let seq = self.seq.get();
+
+            atomic_xadd(seq, 1);
+
+            let _ = futex(seq, FUTEX_WAKE, 1, 0, ptr::null_mut());
+        }
+    }
+
+    #[inline]
+    pub fn notify_all(&self) {
+        unsafe {
+            let lock = self.lock.get();
+            let seq = self.seq.get();
+
+            if *lock == ptr::null_mut() {
+                return;
+            }
+
+            atomic_xadd(seq, 1);
+
+            let _ = futex(seq, FUTEX_REQUEUE, 1, ::usize::MAX, *lock);
+        }
+    }
+
+    #[inline]
+    pub fn wait(&self, mutex: &Mutex) {
+        unsafe {
+            let lock = self.lock.get();
+            let seq = self.seq.get();
+
+            if *lock != mutex.lock.get() {
+                if *lock != ptr::null_mut() {
+                    panic!("Condvar used with more than one Mutex");
+                }
+
+                atomic_cxchg(lock as *mut usize, 0, mutex.lock.get() as usize);
+            }
+
+            mutex_unlock(*lock);
+
+            let _ = futex(seq, FUTEX_WAIT, *seq, 0, ptr::null_mut());
+
+            while atomic_xchg(*lock, 2) != 0 {
+                let _ = futex(*lock, FUTEX_WAIT, 2, 0, ptr::null_mut());
+            }
+
+            mutex_lock(*lock);
+        }
+    }
+
+    #[inline]
+    pub fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
+        ::sys_common::util::dumb_print(format_args!("condvar wait_timeout\n"));
+        unimplemented!();
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {
+        *self.lock.get() = ptr::null_mut();
+        *self.seq.get() = 0;
+    }
+}
+
+unsafe impl Send for Condvar {}
+
+unsafe impl Sync for Condvar {}
diff --git a/src/libstd/sys/redox/env.rs b/src/libstd/sys/redox/env.rs
new file mode 100644
index 00000000000..669b7520df8
--- /dev/null
+++ b/src/libstd/sys/redox/env.rs
@@ -0,0 +1,19 @@
+// 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.
+
+pub mod os {
+    pub const FAMILY: &'static str = "redox";
+    pub const OS: &'static str = "redox";
+    pub const DLL_PREFIX: &'static str = "lib";
+    pub const DLL_SUFFIX: &'static str = ".so";
+    pub const DLL_EXTENSION: &'static str = "so";
+    pub const EXE_SUFFIX: &'static str = "";
+    pub const EXE_EXTENSION: &'static str = "";
+}
diff --git a/src/libstd/sys/redox/ext/ffi.rs b/src/libstd/sys/redox/ext/ffi.rs
new file mode 100644
index 00000000000..d59b4fc0b70
--- /dev/null
+++ b/src/libstd/sys/redox/ext/ffi.rs
@@ -0,0 +1,61 @@
+// 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.
+
+//! Unix-specific extension to the primitives in the `std::ffi` module
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use ffi::{OsStr, OsString};
+use mem;
+use sys::os_str::Buf;
+use sys_common::{FromInner, IntoInner, AsInner};
+
+/// Unix-specific extensions to `OsString`.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStringExt {
+    /// Creates an `OsString` from a byte vector.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn from_vec(vec: Vec<u8>) -> Self;
+
+    /// Yields the underlying byte vector of this `OsString`.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn into_vec(self) -> Vec<u8>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStringExt for OsString {
+    fn from_vec(vec: Vec<u8>) -> OsString {
+        FromInner::from_inner(Buf { inner: vec })
+    }
+    fn into_vec(self) -> Vec<u8> {
+        self.into_inner().inner
+    }
+}
+
+/// Unix-specific extensions to `OsStr`.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStrExt {
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn from_bytes(slice: &[u8]) -> &Self;
+
+    /// Gets the underlying byte view of the `OsStr` slice.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn as_bytes(&self) -> &[u8];
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStrExt for OsStr {
+    fn from_bytes(slice: &[u8]) -> &OsStr {
+        unsafe { mem::transmute(slice) }
+    }
+    fn as_bytes(&self) -> &[u8] {
+        &self.as_inner().inner
+    }
+}
diff --git a/src/libstd/sys/redox/ext/fs.rs b/src/libstd/sys/redox/ext/fs.rs
new file mode 100644
index 00000000000..b4e220971fd
--- /dev/null
+++ b/src/libstd/sys/redox/ext/fs.rs
@@ -0,0 +1,298 @@
+// 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.
+
+//! Unix-specific extensions to primitives in the `std::fs` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use fs::{self, Permissions, OpenOptions};
+use io;
+use path::Path;
+use sys;
+use sys_common::{FromInner, AsInner, AsInnerMut};
+
+/// Unix-specific extensions to `Permissions`
+#[stable(feature = "fs_ext", since = "1.1.0")]
+pub trait PermissionsExt {
+    /// Returns the underlying raw `mode_t` bits that are the standard Unix
+    /// permissions for this file.
+    ///
+    /// # Examples
+    ///
+    /// ```rust,ignore
+    /// use std::fs::File;
+    /// use std::os::unix::fs::PermissionsExt;
+    ///
+    /// let f = try!(File::create("foo.txt"));
+    /// let metadata = try!(f.metadata());
+    /// let permissions = metadata.permissions();
+    ///
+    /// println!("permissions: {}", permissions.mode());
+    /// ```
+    #[stable(feature = "fs_ext", since = "1.1.0")]
+    fn mode(&self) -> u32;
+
+    /// Sets the underlying raw bits for this set of permissions.
+    ///
+    /// # Examples
+    ///
+    /// ```rust,ignore
+    /// use std::fs::File;
+    /// use std::os::unix::fs::PermissionsExt;
+    ///
+    /// let f = try!(File::create("foo.txt"));
+    /// let metadata = try!(f.metadata());
+    /// let mut permissions = metadata.permissions();
+    ///
+    /// permissions.set_mode(0o644); // Read/write for owner and read for others.
+    /// assert_eq!(permissions.mode(), 0o644);
+    /// ```
+    #[stable(feature = "fs_ext", since = "1.1.0")]
+    fn set_mode(&mut self, mode: u32);
+
+    /// Creates a new instance of `Permissions` from the given set of Unix
+    /// permission bits.
+    ///
+    /// # Examples
+    ///
+    /// ```rust,ignore
+    /// use std::fs::Permissions;
+    /// use std::os::unix::fs::PermissionsExt;
+    ///
+    /// // Read/write for owner and read for others.
+    /// let permissions = Permissions::from_mode(0o644);
+    /// assert_eq!(permissions.mode(), 0o644);
+    /// ```
+    #[stable(feature = "fs_ext", since = "1.1.0")]
+    fn from_mode(mode: u32) -> Self;
+}
+
+#[stable(feature = "fs_ext", since = "1.1.0")]
+impl PermissionsExt for Permissions {
+    fn mode(&self) -> u32 {
+        self.as_inner().mode()
+    }
+
+    fn set_mode(&mut self, mode: u32) {
+        *self = Permissions::from_inner(FromInner::from_inner(mode));
+    }
+
+    fn from_mode(mode: u32) -> Permissions {
+        Permissions::from_inner(FromInner::from_inner(mode))
+    }
+}
+
+/// Unix-specific extensions to `OpenOptions`
+#[stable(feature = "fs_ext", since = "1.1.0")]
+pub trait OpenOptionsExt {
+    /// Sets the mode bits that a new file will be created with.
+    ///
+    /// If a new file is created as part of a `File::open_opts` call then this
+    /// specified `mode` will be used as the permission bits for the new file.
+    /// If no `mode` is set, the default of `0o666` will be used.
+    /// The operating system masks out bits with the systems `umask`, to produce
+    /// the final permissions.
+    ///
+    /// # Examples
+    ///
+    /// ```rust,ignore
+    /// extern crate libc;
+    /// use std::fs::OpenOptions;
+    /// use std::os::unix::fs::OpenOptionsExt;
+    ///
+    /// let mut options = OpenOptions::new();
+    /// options.mode(0o644); // Give read/write for owner and read for others.
+    /// let file = options.open("foo.txt");
+    /// ```
+    #[stable(feature = "fs_ext", since = "1.1.0")]
+    fn mode(&mut self, mode: u32) -> &mut Self;
+
+    /// Pass custom flags to the `flags` agument of `open`.
+    ///
+    /// The bits that define the access mode are masked out with `O_ACCMODE`, to
+    /// ensure they do not interfere with the access mode set by Rusts options.
+    ///
+    /// Custom flags can only set flags, not remove flags set by Rusts options.
+    /// This options overwrites any previously set custom flags.
+    ///
+    /// # Examples
+    ///
+    /// ```rust,ignore
+    /// extern crate libc;
+    /// use std::fs::OpenOptions;
+    /// use std::os::unix::fs::OpenOptionsExt;
+    ///
+    /// let mut options = OpenOptions::new();
+    /// options.write(true);
+    /// if cfg!(unix) {
+    ///     options.custom_flags(libc::O_NOFOLLOW);
+    /// }
+    /// let file = options.open("foo.txt");
+    /// ```
+    #[stable(feature = "open_options_ext", since = "1.10.0")]
+    fn custom_flags(&mut self, flags: i32) -> &mut Self;
+}
+
+#[stable(feature = "fs_ext", since = "1.1.0")]
+impl OpenOptionsExt for OpenOptions {
+    fn mode(&mut self, mode: u32) -> &mut OpenOptions {
+        self.as_inner_mut().mode(mode); self
+    }
+
+    fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
+        self.as_inner_mut().custom_flags(flags); self
+    }
+}
+
+// Hm, why are there casts here to the returned type, shouldn't the types always
+// be the same? Right you are! Turns out, however, on android at least the types
+// in the raw `stat` structure are not the same as the types being returned. Who
+// knew!
+//
+// As a result to make sure this compiles for all platforms we do the manual
+// casts and rely on manual lowering to `stat` if the raw type is desired.
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn mode(&self) -> u32;
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn uid(&self) -> u32;
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn gid(&self) -> u32;
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn size(&self) -> u64;
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn atime(&self) -> i64;
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn atime_nsec(&self) -> i64;
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn mtime(&self) -> i64;
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn mtime_nsec(&self) -> i64;
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn ctime(&self) -> i64;
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn ctime_nsec(&self) -> i64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for fs::Metadata {
+    fn mode(&self) -> u32 {
+        self.as_inner().as_inner().st_mode as u32
+    }
+    fn uid(&self) -> u32 {
+        self.as_inner().as_inner().st_uid as u32
+    }
+    fn gid(&self) -> u32 {
+        self.as_inner().as_inner().st_gid as u32
+    }
+    fn size(&self) -> u64 {
+        self.as_inner().as_inner().st_size as u64
+    }
+    fn atime(&self) -> i64 {
+        self.as_inner().as_inner().st_atime as i64
+    }
+    fn atime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_atime_nsec as i64
+    }
+    fn mtime(&self) -> i64 {
+        self.as_inner().as_inner().st_mtime as i64
+    }
+    fn mtime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_mtime_nsec as i64
+    }
+    fn ctime(&self) -> i64 {
+        self.as_inner().as_inner().st_ctime as i64
+    }
+    fn ctime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_ctime_nsec as i64
+    }
+}
+
+/// Add special unix types (block/char device, fifo and socket)
+#[stable(feature = "file_type_ext", since = "1.5.0")]
+pub trait FileTypeExt {
+    /// Returns whether this file type is a block device.
+    #[stable(feature = "file_type_ext", since = "1.5.0")]
+    fn is_block_device(&self) -> bool;
+    /// Returns whether this file type is a char device.
+    #[stable(feature = "file_type_ext", since = "1.5.0")]
+    fn is_char_device(&self) -> bool;
+    /// Returns whether this file type is a fifo.
+    #[stable(feature = "file_type_ext", since = "1.5.0")]
+    fn is_fifo(&self) -> bool;
+    /// Returns whether this file type is a socket.
+    #[stable(feature = "file_type_ext", since = "1.5.0")]
+    fn is_socket(&self) -> bool;
+}
+
+#[stable(feature = "file_type_ext", since = "1.5.0")]
+impl FileTypeExt for fs::FileType {
+    fn is_block_device(&self) -> bool { false /*FIXME: Implement block device mode*/ }
+    fn is_char_device(&self) -> bool { false /*FIXME: Implement char device mode*/ }
+    fn is_fifo(&self) -> bool { false /*FIXME: Implement fifo mode*/ }
+    fn is_socket(&self) -> bool { false /*FIXME: Implement socket mode*/ }
+}
+
+/// Creates a new symbolic link on the filesystem.
+///
+/// The `dst` path will be a symbolic link pointing to the `src` path.
+///
+/// # Note
+///
+/// On Windows, you must specify whether a symbolic link points to a file
+/// or directory.  Use `os::windows::fs::symlink_file` to create a
+/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
+/// symbolic link to a directory.  Additionally, the process must have
+/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
+/// symbolic link.
+///
+/// # Examples
+///
+/// ```
+/// use std::os::unix::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// try!(fs::symlink("a.txt", "b.txt"));
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "symlink", since = "1.1.0")]
+pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
+{
+    sys::fs::symlink(src.as_ref(), dst.as_ref())
+}
+
+#[stable(feature = "dir_builder", since = "1.6.0")]
+/// An extension trait for `fs::DirBuilder` for unix-specific options.
+pub trait DirBuilderExt {
+    /// Sets the mode to create new directories with. This option defaults to
+    /// 0o777.
+    ///
+    /// # Examples
+    ///
+    /// ```ignore
+    /// use std::fs::DirBuilder;
+    /// use std::os::unix::fs::DirBuilderExt;
+    ///
+    /// let mut builder = DirBuilder::new();
+    /// builder.mode(0o755);
+    /// ```
+    #[stable(feature = "dir_builder", since = "1.6.0")]
+    fn mode(&mut self, mode: u32) -> &mut Self;
+}
+
+#[stable(feature = "dir_builder", since = "1.6.0")]
+impl DirBuilderExt for fs::DirBuilder {
+    fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
+        self.as_inner_mut().set_mode(mode);
+        self
+    }
+}
diff --git a/src/libstd/sys/redox/ext/io.rs b/src/libstd/sys/redox/ext/io.rs
new file mode 100644
index 00000000000..8e7cc593dbd
--- /dev/null
+++ b/src/libstd/sys/redox/ext/io.rs
@@ -0,0 +1,151 @@
+// 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.
+
+//! Unix-specific extensions to general I/O primitives
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use fs;
+use net;
+use sys;
+use sys_common::{self, AsInner, FromInner, IntoInner};
+
+/// Raw file descriptors.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawFd = usize;
+
+/// A trait to extract the raw unix file descriptor from an underlying
+/// object.
+///
+/// This is only available on unix platforms and must be imported in order
+/// to call the method. Windows platforms have a corresponding `AsRawHandle`
+/// and `AsRawSocket` set of traits.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawFd {
+    /// Extracts the raw file descriptor.
+    ///
+    /// This method does **not** pass ownership of the raw file descriptor
+    /// to the caller. The descriptor is only guaranteed to be valid while
+    /// the original object has not yet been destroyed.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+pub trait FromRawFd {
+    /// Constructs a new instances of `Self` from the given raw file
+    /// descriptor.
+    ///
+    /// This function **consumes ownership** of the specified file
+    /// descriptor. The returned object will take responsibility for closing
+    /// it when the object goes out of scope.
+    ///
+    /// This function is also unsafe as the primitives currently returned
+    /// have the contract that they are the sole owner of the file
+    /// descriptor they are wrapping. Usage of this function could
+    /// accidentally allow violating this contract which can cause memory
+    /// unsafety in code that relies on it being true.
+    #[stable(feature = "from_raw_os", since = "1.1.0")]
+    unsafe fn from_raw_fd(fd: RawFd) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw file descriptor.
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+pub trait IntoRawFd {
+    /// Consumes this object, returning the raw underlying file descriptor.
+    ///
+    /// This function **transfers ownership** of the underlying file descriptor
+    /// to the caller. Callers are then the unique owners of the file descriptor
+    /// and must close the descriptor once it's no longer needed.
+    #[stable(feature = "into_raw_os", since = "1.4.0")]
+    fn into_raw_fd(self) -> RawFd;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for fs::File {
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().raw()
+    }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for fs::File {
+    unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
+        fs::File::from_inner(sys::fs::File::from_inner(fd))
+    }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for fs::File {
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_fd().into_raw()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::TcpStream {
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().as_inner().fd().raw()
+    }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::TcpListener {
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().as_inner().fd().raw()
+    }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::UdpSocket {
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().as_inner().fd().raw()
+    }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::TcpStream {
+    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
+        let file = sys::fs::File::from_inner(fd);
+        net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(file))
+    }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::TcpListener {
+    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
+        let file = sys::fs::File::from_inner(fd);
+        net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(file))
+    }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::UdpSocket {
+    unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
+        let file = sys::fs::File::from_inner(fd);
+        net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(file))
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::TcpStream {
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_inner().into_fd().into_raw()
+    }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::TcpListener {
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_inner().into_fd().into_raw()
+    }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::UdpSocket {
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_inner().into_fd().into_raw()
+    }
+}
diff --git a/src/libstd/sys/redox/ext/mod.rs b/src/libstd/sys/redox/ext/mod.rs
new file mode 100644
index 00000000000..513ef272e97
--- /dev/null
+++ b/src/libstd/sys/redox/ext/mod.rs
@@ -0,0 +1,50 @@
+// 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.
+
+//! Experimental extensions to `std` for Unix platforms.
+//!
+//! For now, this module is limited to extracting file descriptors,
+//! but its functionality will grow over time.
+//!
+//! # Example
+//!
+//! ```no_run
+//! use std::fs::File;
+//! use std::os::unix::prelude::*;
+//!
+//! fn main() {
+//!     let f = File::create("foo.txt").unwrap();
+//!     let fd = f.as_raw_fd();
+//!
+//!     // use fd with native unix bindings
+//! }
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+pub mod ffi;
+pub mod fs;
+pub mod io;
+pub mod process;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
+    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::ffi::{OsStrExt, OsStringExt};
+    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::fs::{FileTypeExt, PermissionsExt, OpenOptionsExt, MetadataExt};
+    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::process::{CommandExt, ExitStatusExt};
+}
diff --git a/src/libstd/sys/redox/ext/process.rs b/src/libstd/sys/redox/ext/process.rs
new file mode 100644
index 00000000000..c59524974bf
--- /dev/null
+++ b/src/libstd/sys/redox/ext/process.rs
@@ -0,0 +1,183 @@
+// 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.
+
+//! Unix-specific extensions to primitives in the `std::process` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use io;
+use os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd};
+use process;
+use sys;
+use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};
+
+/// Unix-specific extensions to the `std::process::Command` builder
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait CommandExt {
+    /// Sets the child process's user id. This translates to a
+    /// `setuid` call in the child process. Failure in the `setuid`
+    /// call will cause the spawn to fail.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn uid(&mut self, id: u32) -> &mut process::Command;
+
+    /// Similar to `uid`, but sets the group id of the child process. This has
+    /// the same semantics as the `uid` field.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn gid(&mut self, id: u32) -> &mut process::Command;
+
+    /// Schedules a closure to be run just before the `exec` function is
+    /// invoked.
+    ///
+    /// The closure is allowed to return an I/O error whose OS error code will
+    /// be communicated back to the parent and returned as an error from when
+    /// the spawn was requested.
+    ///
+    /// Multiple closures can be registered and they will be called in order of
+    /// their registration. If a closure returns `Err` then no further closures
+    /// will be called and the spawn operation will immediately return with a
+    /// failure.
+    ///
+    /// # Notes
+    ///
+    /// This closure will be run in the context of the child process after a
+    /// `fork`. This primarily means that any modificatons made to memory on
+    /// behalf of this closure will **not** be visible to the parent process.
+    /// This is often a very constrained environment where normal operations
+    /// like `malloc` or acquiring a mutex are not guaranteed to work (due to
+    /// other threads perhaps still running when the `fork` was run).
+    ///
+    /// When this closure is run, aspects such as the stdio file descriptors and
+    /// working directory have successfully been changed, so output to these
+    /// locations may not appear where intended.
+    #[stable(feature = "process_exec", since = "1.15.0")]
+    fn before_exec<F>(&mut self, f: F) -> &mut process::Command
+        where F: FnMut() -> io::Result<()> + Send + Sync + 'static;
+
+    /// Performs all the required setup by this `Command`, followed by calling
+    /// the `execvp` syscall.
+    ///
+    /// On success this function will not return, and otherwise it will return
+    /// an error indicating why the exec (or another part of the setup of the
+    /// `Command`) failed.
+    ///
+    /// This function, unlike `spawn`, will **not** `fork` the process to create
+    /// a new child. Like spawn, however, the default behavior for the stdio
+    /// descriptors will be to inherited from the current process.
+    ///
+    /// # Notes
+    ///
+    /// The process may be in a "broken state" if this function returns in
+    /// error. For example the working directory, environment variables, signal
+    /// handling settings, various user/group information, or aspects of stdio
+    /// file descriptors may have changed. If a "transactional spawn" is
+    /// required to gracefully handle errors it is recommended to use the
+    /// cross-platform `spawn` instead.
+    #[stable(feature = "process_exec2", since = "1.9.0")]
+    fn exec(&mut self) -> io::Error;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl CommandExt for process::Command {
+    fn uid(&mut self, id: u32) -> &mut process::Command {
+        self.as_inner_mut().uid(id);
+        self
+    }
+
+    fn gid(&mut self, id: u32) -> &mut process::Command {
+        self.as_inner_mut().gid(id);
+        self
+    }
+
+    fn before_exec<F>(&mut self, f: F) -> &mut process::Command
+        where F: FnMut() -> io::Result<()> + Send + Sync + 'static
+    {
+        self.as_inner_mut().before_exec(Box::new(f));
+        self
+    }
+
+    fn exec(&mut self) -> io::Error {
+        self.as_inner_mut().exec(sys::process::Stdio::Inherit)
+    }
+}
+
+/// Unix-specific extensions to `std::process::ExitStatus`
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait ExitStatusExt {
+    /// Creates a new `ExitStatus` from the raw underlying `i32` return value of
+    /// a process.
+    #[stable(feature = "exit_status_from", since = "1.12.0")]
+    fn from_raw(raw: i32) -> Self;
+
+    /// If the process was terminated by a signal, returns that signal.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn signal(&self) -> Option<i32>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ExitStatusExt for process::ExitStatus {
+    fn from_raw(raw: i32) -> Self {
+        process::ExitStatus::from_inner(From::from(raw))
+    }
+
+    fn signal(&self) -> Option<i32> {
+        self.as_inner().signal()
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl FromRawFd for process::Stdio {
+    unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
+        let fd = sys::fd::FileDesc::new(fd);
+        let io = sys::process::Stdio::Fd(fd);
+        process::Stdio::from_inner(io)
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdin {
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().raw()
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdout {
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().raw()
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStderr {
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().raw()
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdin {
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_fd().into_raw()
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdout {
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_fd().into_raw()
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStderr {
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_fd().into_raw()
+    }
+}
diff --git a/src/libstd/sys/redox/fast_thread_local.rs b/src/libstd/sys/redox/fast_thread_local.rs
new file mode 100644
index 00000000000..6eeae2d90ea
--- /dev/null
+++ b/src/libstd/sys/redox/fast_thread_local.rs
@@ -0,0 +1,116 @@
+// 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.
+
+#![cfg(target_thread_local)]
+#![unstable(feature = "thread_local_internals", issue = "0")]
+
+use cell::{Cell, UnsafeCell};
+use intrinsics;
+use ptr;
+
+pub struct Key<T> {
+    inner: UnsafeCell<Option<T>>,
+
+    // Metadata to keep track of the state of the destructor. Remember that
+    // these variables are thread-local, not global.
+    dtor_registered: Cell<bool>,
+    dtor_running: Cell<bool>,
+}
+
+unsafe impl<T> ::marker::Sync for Key<T> { }
+
+impl<T> Key<T> {
+    pub const fn new() -> Key<T> {
+        Key {
+            inner: UnsafeCell::new(None),
+            dtor_registered: Cell::new(false),
+            dtor_running: Cell::new(false)
+        }
+    }
+
+    pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
+        unsafe {
+            if intrinsics::needs_drop::<T>() && self.dtor_running.get() {
+                return None
+            }
+            self.register_dtor();
+        }
+        Some(&self.inner)
+    }
+
+    unsafe fn register_dtor(&self) {
+        if !intrinsics::needs_drop::<T>() || self.dtor_registered.get() {
+            return
+        }
+
+        register_dtor(self as *const _ as *mut u8,
+                      destroy_value::<T>);
+        self.dtor_registered.set(true);
+    }
+}
+
+unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
+    // The fallback implementation uses a vanilla OS-based TLS key to track
+    // the list of destructors that need to be run for this thread. The key
+    // then has its own destructor which runs all the other destructors.
+    //
+    // The destructor for DTORS is a little special in that it has a `while`
+    // loop to continuously drain the list of registered destructors. It
+    // *should* be the case that this loop always terminates because we
+    // provide the guarantee that a TLS key cannot be set after it is
+    // flagged for destruction.
+    use sys_common::thread_local as os;
+
+    static DTORS: os::StaticKey = os::StaticKey::new(Some(run_dtors));
+    type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>;
+    if DTORS.get().is_null() {
+        let v: Box<List> = box Vec::new();
+        DTORS.set(Box::into_raw(v) as *mut u8);
+    }
+    let list: &mut List = &mut *(DTORS.get() as *mut List);
+    list.push((t, dtor));
+
+    unsafe extern fn run_dtors(mut ptr: *mut u8) {
+        while !ptr.is_null() {
+            let list: Box<List> = Box::from_raw(ptr as *mut List);
+            for &(ptr, dtor) in list.iter() {
+                dtor(ptr);
+            }
+            ptr = DTORS.get();
+            DTORS.set(ptr::null_mut());
+        }
+    }
+}
+
+pub unsafe extern fn destroy_value<T>(ptr: *mut u8) {
+    let ptr = ptr as *mut Key<T>;
+    // Right before we run the user destructor be sure to flag the
+    // destructor as running for this thread so calls to `get` will return
+    // `None`.
+    (*ptr).dtor_running.set(true);
+
+    // The OSX implementation of TLS apparently had an odd aspect to it
+    // where the pointer we have may be overwritten while this destructor
+    // is running. Specifically if a TLS destructor re-accesses TLS it may
+    // trigger a re-initialization of all TLS variables, paving over at
+    // least some destroyed ones with initial values.
+    //
+    // This means that if we drop a TLS value in place on OSX that we could
+    // revert the value to its original state halfway through the
+    // destructor, which would be bad!
+    //
+    // Hence, we use `ptr::read` on OSX (to move to a "safe" location)
+    // instead of drop_in_place.
+    if cfg!(target_os = "macos") {
+        ptr::read((*ptr).inner.get());
+    } else {
+        ptr::drop_in_place((*ptr).inner.get());
+    }
+}
diff --git a/src/libstd/sys/redox/fd.rs b/src/libstd/sys/redox/fd.rs
new file mode 100644
index 00000000000..b6de68a9dc1
--- /dev/null
+++ b/src/libstd/sys/redox/fd.rs
@@ -0,0 +1,100 @@
+// 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.
+
+#![unstable(reason = "not public", issue = "0", feature = "fd")]
+
+use io::{self, Read};
+use mem;
+use sys::{cvt, syscall};
+use sys_common::AsInner;
+use sys_common::io::read_to_end_uninitialized;
+
+pub struct FileDesc {
+    fd: usize,
+}
+
+impl FileDesc {
+    pub fn new(fd: usize) -> FileDesc {
+        FileDesc { fd: fd }
+    }
+
+    pub fn raw(&self) -> usize { self.fd }
+
+    /// Extracts the actual filedescriptor without closing it.
+    pub fn into_raw(self) -> usize {
+        let fd = self.fd;
+        mem::forget(self);
+        fd
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        cvt(syscall::read(self.fd, buf))
+    }
+
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        let mut me = self;
+        (&mut me).read_to_end(buf)
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        cvt(syscall::write(self.fd, buf))
+    }
+
+    pub fn duplicate(&self) -> io::Result<FileDesc> {
+        let new_fd = cvt(syscall::dup(self.fd, &[]))?;
+        Ok(FileDesc::new(new_fd))
+    }
+
+    pub fn nonblocking(&self) -> io::Result<bool> {
+        let flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFL, 0))?;
+        Ok(flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK)
+    }
+
+    pub fn set_cloexec(&self) -> io::Result<()> {
+        let mut flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFL, 0))?;
+        flags |= syscall::O_CLOEXEC;
+        cvt(syscall::fcntl(self.fd, syscall::F_SETFL, flags)).and(Ok(()))
+    }
+
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        let mut flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFL, 0))?;
+        if nonblocking {
+            flags |= syscall::O_NONBLOCK;
+        } else {
+            flags &= !syscall::O_NONBLOCK;
+        }
+        cvt(syscall::fcntl(self.fd, syscall::F_SETFL, flags)).and(Ok(()))
+    }
+}
+
+impl<'a> Read for &'a FileDesc {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        (**self).read(buf)
+    }
+
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        unsafe { read_to_end_uninitialized(self, buf) }
+    }
+}
+
+impl AsInner<usize> for FileDesc {
+    fn as_inner(&self) -> &usize { &self.fd }
+}
+
+impl Drop for FileDesc {
+    fn drop(&mut self) {
+        // Note that errors are ignored when closing a file descriptor. The
+        // reason for this is that if an error occurs we don't actually know if
+        // the file descriptor was closed or not, and if we retried (for
+        // something like EINTR), we might close another valid file descriptor
+        // (opened after we closed ours.
+        let _ = syscall::close(self.fd);
+    }
+}
diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs
new file mode 100644
index 00000000000..a8391d2b898
--- /dev/null
+++ b/src/libstd/sys/redox/fs.rs
@@ -0,0 +1,470 @@
+// 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 os::unix::prelude::*;
+
+use ffi::{OsString, OsStr};
+use fmt;
+use io::{self, Error, ErrorKind, SeekFrom};
+use path::{Path, PathBuf};
+use sync::Arc;
+use sys::fd::FileDesc;
+use sys::time::SystemTime;
+use sys::{cvt, syscall};
+use sys_common::{AsInner, FromInner};
+
+pub struct File(FileDesc);
+
+#[derive(Clone)]
+pub struct FileAttr {
+    stat: syscall::Stat,
+}
+
+pub struct ReadDir {
+    data: Vec<u8>,
+    i: usize,
+    root: Arc<PathBuf>,
+}
+
+struct Dir(FileDesc);
+
+unsafe impl Send for Dir {}
+unsafe impl Sync for Dir {}
+
+pub struct DirEntry {
+    root: Arc<PathBuf>,
+    name: Box<[u8]>
+}
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions {
+    // generic
+    read: bool,
+    write: bool,
+    append: bool,
+    truncate: bool,
+    create: bool,
+    create_new: bool,
+    // system-specific
+    custom_flags: i32,
+    mode: u16,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct FilePermissions { mode: u16 }
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub struct FileType { mode: u16 }
+
+#[derive(Debug)]
+pub struct DirBuilder { mode: u16 }
+
+impl FileAttr {
+    pub fn size(&self) -> u64 { self.stat.st_size as u64 }
+    pub fn perm(&self) -> FilePermissions {
+        FilePermissions { mode: (self.stat.st_mode as u16) & 0o777 }
+    }
+
+    pub fn file_type(&self) -> FileType {
+        FileType { mode: self.stat.st_mode as u16 }
+    }
+}
+
+impl FileAttr {
+    pub fn modified(&self) -> io::Result<SystemTime> {
+        Ok(SystemTime::from(syscall::TimeSpec {
+            tv_sec: self.stat.st_mtime as i64,
+            tv_nsec: self.stat.st_mtime_nsec as i32,
+        }))
+    }
+
+    pub fn accessed(&self) -> io::Result<SystemTime> {
+        Ok(SystemTime::from(syscall::TimeSpec {
+            tv_sec: self.stat.st_atime as i64,
+            tv_nsec: self.stat.st_atime_nsec as i32,
+        }))
+    }
+
+    pub fn created(&self) -> io::Result<SystemTime> {
+        Ok(SystemTime::from(syscall::TimeSpec {
+            tv_sec: self.stat.st_ctime as i64,
+            tv_nsec: self.stat.st_ctime_nsec as i32,
+        }))
+    }
+}
+
+impl AsInner<syscall::Stat> for FileAttr {
+    fn as_inner(&self) -> &syscall::Stat { &self.stat }
+}
+
+impl FilePermissions {
+    pub fn readonly(&self) -> bool { self.mode & 0o222 == 0 }
+    pub fn set_readonly(&mut self, readonly: bool) {
+        if readonly {
+            self.mode &= !0o222;
+        } else {
+            self.mode |= 0o222;
+        }
+    }
+    pub fn mode(&self) -> u32 { self.mode as u32 }
+}
+
+impl FileType {
+    pub fn is_dir(&self) -> bool { self.is(syscall::MODE_DIR) }
+    pub fn is_file(&self) -> bool { self.is(syscall::MODE_FILE) }
+    pub fn is_symlink(&self) -> bool { false /*FIXME: Implement symlink mode*/ }
+
+    pub fn is(&self, mode: u16) -> bool {
+        self.mode & (syscall::MODE_DIR | syscall::MODE_FILE) == mode
+    }
+}
+
+impl FromInner<u32> for FilePermissions {
+    fn from_inner(mode: u32) -> FilePermissions {
+        FilePermissions { mode: mode as u16 }
+    }
+}
+
+impl fmt::Debug for ReadDir {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
+        // Thus the result will be e g 'ReadDir("/home")'
+        fmt::Debug::fmt(&*self.root, f)
+    }
+}
+
+impl Iterator for ReadDir {
+    type Item = io::Result<DirEntry>;
+
+    fn next(&mut self) -> Option<io::Result<DirEntry>> {
+        loop {
+            let start = self.i;
+            let mut i = self.i;
+            while i < self.data.len() {
+                self.i += 1;
+                if self.data[i] == b'\n' {
+                    break;
+                }
+                i += 1;
+            }
+            if start < self.i {
+                let ret = DirEntry {
+                    name: self.data[start .. i].to_owned().into_boxed_slice(),
+                    root: self.root.clone()
+                };
+                if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
+                    return Some(Ok(ret))
+                }
+            } else {
+                return None;
+            }
+        }
+    }
+}
+
+impl DirEntry {
+    pub fn path(&self) -> PathBuf {
+        self.root.join(OsStr::from_bytes(self.name_bytes()))
+    }
+
+    pub fn file_name(&self) -> OsString {
+        OsStr::from_bytes(self.name_bytes()).to_os_string()
+    }
+
+    pub fn metadata(&self) -> io::Result<FileAttr> {
+        lstat(&self.path())
+    }
+
+    pub fn file_type(&self) -> io::Result<FileType> {
+        lstat(&self.path()).map(|m| m.file_type())
+    }
+
+    fn name_bytes(&self) -> &[u8] {
+        &*self.name
+    }
+}
+
+impl OpenOptions {
+    pub fn new() -> OpenOptions {
+        OpenOptions {
+            // generic
+            read: false,
+            write: false,
+            append: false,
+            truncate: false,
+            create: false,
+            create_new: false,
+            // system-specific
+            custom_flags: 0,
+            mode: 0o666,
+        }
+    }
+
+    pub fn read(&mut self, read: bool) { self.read = read; }
+    pub fn write(&mut self, write: bool) { self.write = write; }
+    pub fn append(&mut self, append: bool) { self.append = append; }
+    pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; }
+    pub fn create(&mut self, create: bool) { self.create = create; }
+    pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; }
+
+    pub fn custom_flags(&mut self, flags: i32) { self.custom_flags = flags; }
+    pub fn mode(&mut self, mode: u32) { self.mode = mode as u16; }
+
+    fn get_access_mode(&self) -> io::Result<usize> {
+        match (self.read, self.write, self.append) {
+            (true,  false, false) => Ok(syscall::O_RDONLY),
+            (false, true,  false) => Ok(syscall::O_WRONLY),
+            (true,  true,  false) => Ok(syscall::O_RDWR),
+            (false, _,     true)  => Ok(syscall::O_WRONLY | syscall::O_APPEND),
+            (true,  _,     true)  => Ok(syscall::O_RDWR | syscall::O_APPEND),
+            (false, false, false) => Err(Error::from_raw_os_error(syscall::EINVAL)),
+        }
+    }
+
+    fn get_creation_mode(&self) -> io::Result<usize> {
+        match (self.write, self.append) {
+            (true, false) => {}
+            (false, false) =>
+                if self.truncate || self.create || self.create_new {
+                    return Err(Error::from_raw_os_error(syscall::EINVAL));
+                },
+            (_, true) =>
+                if self.truncate && !self.create_new {
+                    return Err(Error::from_raw_os_error(syscall::EINVAL));
+                },
+        }
+
+        Ok(match (self.create, self.truncate, self.create_new) {
+                (false, false, false) => 0,
+                (true,  false, false) => syscall::O_CREAT,
+                (false, true,  false) => syscall::O_TRUNC,
+                (true,  true,  false) => syscall::O_CREAT | syscall::O_TRUNC,
+                (_,      _,    true)  => syscall::O_CREAT | syscall::O_EXCL,
+           })
+    }
+}
+
+impl File {
+    pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
+        let flags = syscall::O_CLOEXEC |
+                    opts.get_access_mode()? as usize |
+                    opts.get_creation_mode()? as usize |
+                    (opts.custom_flags as usize & !syscall::O_ACCMODE);
+        let fd = cvt(syscall::open(path.to_str().unwrap(), flags | opts.mode as usize))?;
+        Ok(File(FileDesc::new(fd)))
+    }
+
+    pub fn file_attr(&self) -> io::Result<FileAttr> {
+        let mut stat = syscall::Stat::default();
+        cvt(syscall::fstat(self.0.raw(), &mut stat))?;
+        Ok(FileAttr { stat: stat })
+    }
+
+    pub fn fsync(&self) -> io::Result<()> {
+        cvt(syscall::fsync(self.0.raw()))?;
+        Ok(())
+    }
+
+    pub fn datasync(&self) -> io::Result<()> {
+        self.fsync()
+    }
+
+    pub fn truncate(&self, size: u64) -> io::Result<()> {
+        cvt(syscall::ftruncate(self.0.raw(), size as usize))?;
+        Ok(())
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.read(buf)
+    }
+
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.0.read_to_end(buf)
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        self.0.write(buf)
+    }
+
+    pub fn flush(&self) -> io::Result<()> { Ok(()) }
+
+    pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
+        let (whence, pos) = match pos {
+            // Casting to `i64` is fine, too large values will end up as
+            // negative which will cause an error in `lseek64`.
+            SeekFrom::Start(off) => (syscall::SEEK_SET, off as i64),
+            SeekFrom::End(off) => (syscall::SEEK_END, off),
+            SeekFrom::Current(off) => (syscall::SEEK_CUR, off),
+        };
+        let n = cvt(syscall::lseek(self.0.raw(), pos as isize, whence))?;
+        Ok(n as u64)
+    }
+
+    pub fn duplicate(&self) -> io::Result<File> {
+        self.0.duplicate().map(File)
+    }
+
+    pub fn dup(&self, buf: &[u8]) -> io::Result<File> {
+        let fd = cvt(syscall::dup(*self.fd().as_inner() as usize, buf))?;
+        Ok(File(FileDesc::new(fd)))
+    }
+
+    pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
+        set_perm(&self.path()?, perm)
+    }
+
+    pub fn path(&self) -> io::Result<PathBuf> {
+        let mut buf: [u8; 4096] = [0; 4096];
+        let count = cvt(syscall::fpath(*self.fd().as_inner() as usize, &mut buf))?;
+        Ok(PathBuf::from(unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }))
+    }
+
+    pub fn fd(&self) -> &FileDesc { &self.0 }
+
+    pub fn into_fd(self) -> FileDesc { self.0 }
+}
+
+impl DirBuilder {
+    pub fn new() -> DirBuilder {
+        DirBuilder { mode: 0o777 }
+    }
+
+    pub fn mkdir(&self, p: &Path) -> io::Result<()> {
+        let flags = syscall::O_CREAT | syscall::O_CLOEXEC | syscall::O_DIRECTORY | syscall::O_EXCL;
+        let fd = cvt(syscall::open(p.to_str().unwrap(), flags | (self.mode as usize & 0o777)))?;
+        let _ = syscall::close(fd);
+        Ok(())
+    }
+
+    pub fn set_mode(&mut self, mode: u32) {
+        self.mode = mode as u16;
+    }
+}
+
+impl FromInner<usize> for File {
+    fn from_inner(fd: usize) -> File {
+        File(FileDesc::new(fd))
+    }
+}
+
+impl fmt::Debug for File {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let mut b = f.debug_struct("File");
+        b.field("fd", &self.0.raw());
+        if let Ok(path) = self.path() {
+            b.field("path", &path);
+        }
+        /*
+        if let Some((read, write)) = get_mode(fd) {
+            b.field("read", &read).field("write", &write);
+        }
+        */
+        b.finish()
+    }
+}
+
+pub fn readdir(p: &Path) -> io::Result<ReadDir> {
+    let root = Arc::new(p.to_path_buf());
+
+    let flags = syscall::O_CLOEXEC | syscall::O_RDONLY | syscall::O_DIRECTORY;
+    let fd = cvt(syscall::open(p.to_str().unwrap(), flags))?;
+    let file = FileDesc::new(fd);
+    let mut data = Vec::new();
+    file.read_to_end(&mut data)?;
+
+    Ok(ReadDir { data: data, i: 0, root: root })
+}
+
+pub fn unlink(p: &Path) -> io::Result<()> {
+    cvt(syscall::unlink(p.to_str().unwrap()))?;
+    Ok(())
+}
+
+pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
+    ::sys_common::util::dumb_print(format_args!("Rename\n"));
+    unimplemented!();
+}
+
+pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
+    cvt(syscall::chmod(p.to_str().unwrap(), perm.mode as usize))?;
+    Ok(())
+}
+
+pub fn rmdir(p: &Path) -> io::Result<()> {
+    cvt(syscall::rmdir(p.to_str().unwrap()))?;
+    Ok(())
+}
+
+pub fn remove_dir_all(path: &Path) -> io::Result<()> {
+    let filetype = lstat(path)?.file_type();
+    if filetype.is_symlink() {
+        unlink(path)
+    } else {
+        remove_dir_all_recursive(path)
+    }
+}
+
+fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
+    for child in readdir(path)? {
+        let child = child?;
+        if child.file_type()?.is_dir() {
+            remove_dir_all_recursive(&child.path())?;
+        } else {
+            unlink(&child.path())?;
+        }
+    }
+    rmdir(path)
+}
+
+pub fn readlink(p: &Path) -> io::Result<PathBuf> {
+    canonicalize(p)
+}
+
+pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
+    ::sys_common::util::dumb_print(format_args!("Symlink\n"));
+    unimplemented!();
+}
+
+pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
+    ::sys_common::util::dumb_print(format_args!("Link\n"));
+    unimplemented!();
+}
+
+pub fn stat(p: &Path) -> io::Result<FileAttr> {
+    let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_CLOEXEC | syscall::O_STAT))?;
+    let file = File(FileDesc::new(fd));
+    file.file_attr()
+}
+
+pub fn lstat(p: &Path) -> io::Result<FileAttr> {
+    stat(p)
+}
+
+pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
+    let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_CLOEXEC | syscall::O_STAT))?;
+    let file = File(FileDesc::new(fd));
+    file.path()
+}
+
+pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
+    use fs::{File, set_permissions};
+    if !from.is_file() {
+        return Err(Error::new(ErrorKind::InvalidInput,
+                              "the source path is not an existing regular file"))
+    }
+
+    let mut reader = File::open(from)?;
+    let mut writer = File::create(to)?;
+    let perm = reader.metadata()?.permissions();
+
+    let ret = io::copy(&mut reader, &mut writer)?;
+    set_permissions(to, perm)?;
+    Ok(ret)
+}
diff --git a/src/test/compile-fail/issue-23305.rs b/src/libstd/sys/redox/memchr.rs
index 4acb1f70d34..4c314b7a472 100644
--- a/src/test/compile-fail/issue-23305.rs
+++ b/src/libstd/sys/redox/memchr.rs
@@ -7,12 +7,8 @@
 // <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.
+//
+// Original implementation taken from rust-memchr
+// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
 
-pub trait ToNbt<T> {
-    fn new(val: T) -> Self;
-}
-
-impl ToNbt<Self> {} //~ ERROR use of `Self` outside of an impl or trait
-//~^ ERROR the trait `ToNbt` cannot be made into an object
-
-fn main() {}
+pub use sys_common::memchr::fallback::{memchr, memrchr};
diff --git a/src/libstd/sys/redox/mod.rs b/src/libstd/sys/redox/mod.rs
new file mode 100644
index 00000000000..5982bdd6549
--- /dev/null
+++ b/src/libstd/sys/redox/mod.rs
@@ -0,0 +1,95 @@
+// 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.
+
+#![allow(dead_code, missing_docs, bad_style)]
+
+use io::{self, ErrorKind};
+
+pub mod args;
+#[cfg(any(not(cargobuild), feature = "backtrace"))]
+pub mod backtrace;
+pub mod condvar;
+pub mod env;
+pub mod ext;
+pub mod fast_thread_local;
+pub mod fd;
+pub mod fs;
+pub mod memchr;
+pub mod mutex;
+pub mod net;
+pub mod os;
+pub mod os_str;
+pub mod path;
+pub mod pipe;
+pub mod process;
+pub mod rand;
+pub mod rwlock;
+pub mod stack_overflow;
+pub mod stdio;
+pub mod syscall;
+pub mod thread;
+pub mod thread_local;
+pub mod time;
+
+#[cfg(not(test))]
+pub fn init() {
+    use alloc::oom;
+
+    oom::set_oom_handler(oom_handler);
+
+    // A nicer handler for out-of-memory situations than the default one. This
+    // one prints a message to stderr before aborting. It is critical that this
+    // code does not allocate any memory since we are in an OOM situation. Any
+    // errors are ignored while printing since there's nothing we can do about
+    // them and we are about to exit anyways.
+    fn oom_handler() -> ! {
+        use intrinsics;
+        let msg = "fatal runtime error: out of memory\n";
+        unsafe {
+            let _ = syscall::write(2, msg.as_bytes());
+            intrinsics::abort();
+        }
+    }
+}
+
+pub fn decode_error_kind(errno: i32) -> ErrorKind {
+    match errno {
+        syscall::ECONNREFUSED => ErrorKind::ConnectionRefused,
+        syscall::ECONNRESET => ErrorKind::ConnectionReset,
+        syscall::EPERM | syscall::EACCES => ErrorKind::PermissionDenied,
+        syscall::EPIPE => ErrorKind::BrokenPipe,
+        syscall::ENOTCONN => ErrorKind::NotConnected,
+        syscall::ECONNABORTED => ErrorKind::ConnectionAborted,
+        syscall::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
+        syscall::EADDRINUSE => ErrorKind::AddrInUse,
+        syscall::ENOENT => ErrorKind::NotFound,
+        syscall::EINTR => ErrorKind::Interrupted,
+        syscall::EINVAL => ErrorKind::InvalidInput,
+        syscall::ETIMEDOUT => ErrorKind::TimedOut,
+        syscall::EEXIST => ErrorKind::AlreadyExists,
+
+        // These two constants can have the same value on some systems,
+        // but different values on others, so we can't use a match
+        // clause
+        x if x == syscall::EAGAIN || x == syscall::EWOULDBLOCK =>
+            ErrorKind::WouldBlock,
+
+        _ => ErrorKind::Other,
+    }
+}
+
+pub fn cvt(result: Result<usize, syscall::Error>) -> io::Result<usize> {
+    result.map_err(|err| io::Error::from_raw_os_error(err.errno))
+}
+
+/// On Redox, use an illegal instruction to abort
+pub unsafe fn abort_internal() -> ! {
+    ::core::intrinsics::abort();
+}
diff --git a/src/libstd/sys/redox/mutex.rs b/src/libstd/sys/redox/mutex.rs
new file mode 100644
index 00000000000..a995f597fc4
--- /dev/null
+++ b/src/libstd/sys/redox/mutex.rs
@@ -0,0 +1,179 @@
+// 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 cell::UnsafeCell;
+use intrinsics::{atomic_cxchg, atomic_xchg};
+use ptr;
+
+use sys::syscall::{futex, getpid, FUTEX_WAIT, FUTEX_WAKE};
+
+pub unsafe fn mutex_try_lock(m: *mut i32) -> bool {
+    atomic_cxchg(m, 0, 1).0 == 0
+}
+
+pub unsafe fn mutex_lock(m: *mut i32) {
+    let mut c = 0;
+    //Set to larger value for longer spin test
+    for _i in 0..100 {
+        c = atomic_cxchg(m, 0, 1).0;
+        if c == 0 {
+            break;
+        }
+        //cpu_relax()
+    }
+    if c == 1 {
+        c = atomic_xchg(m, 2);
+    }
+    while c != 0 {
+        let _ = futex(m, FUTEX_WAIT, 2, 0, ptr::null_mut());
+        c = atomic_xchg(m, 2);
+    }
+}
+
+pub unsafe fn mutex_unlock(m: *mut i32) {
+    if *m == 2 {
+        *m = 0;
+    } else if atomic_xchg(m, 0) == 1 {
+        return;
+    }
+    //Set to larger value for longer spin test
+    for _i in 0..100 {
+        if *m != 0 {
+            if atomic_cxchg(m, 1, 2).0 != 0 {
+                return;
+            }
+        }
+        //cpu_relax()
+    }
+    let _ = futex(m, FUTEX_WAKE, 1, 0, ptr::null_mut());
+}
+
+pub struct Mutex {
+    pub lock: UnsafeCell<i32>,
+}
+
+impl Mutex {
+    /// Create a new mutex.
+    pub const fn new() -> Self {
+        Mutex {
+            lock: UnsafeCell::new(0),
+        }
+    }
+
+    #[inline]
+    pub unsafe fn init(&self) {
+        *self.lock.get() = 0;
+    }
+
+    /// Try to lock the mutex
+    #[inline]
+    pub unsafe fn try_lock(&self) -> bool {
+        mutex_try_lock(self.lock.get())
+    }
+
+    /// Lock the mutex
+    #[inline]
+    pub unsafe fn lock(&self) {
+        mutex_lock(self.lock.get());
+    }
+
+    /// Unlock the mutex
+    #[inline]
+    pub unsafe fn unlock(&self) {
+        mutex_unlock(self.lock.get());
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {
+        *self.lock.get() = 0;
+    }
+}
+
+unsafe impl Send for Mutex {}
+
+unsafe impl Sync for Mutex {}
+
+pub struct ReentrantMutex {
+    pub lock: UnsafeCell<i32>,
+    pub owner: UnsafeCell<usize>,
+    pub own_count: UnsafeCell<usize>,
+}
+
+impl ReentrantMutex {
+    pub const fn uninitialized() -> Self {
+        ReentrantMutex {
+            lock: UnsafeCell::new(0),
+            owner: UnsafeCell::new(0),
+            own_count: UnsafeCell::new(0),
+        }
+    }
+
+    #[inline]
+    pub unsafe fn init(&mut self) {
+        *self.lock.get() = 0;
+        *self.owner.get() = 0;
+        *self.own_count.get() = 0;
+    }
+
+    /// Try to lock the mutex
+    #[inline]
+    pub unsafe fn try_lock(&self) -> bool {
+        let pid = getpid().unwrap();
+        if *self.own_count.get() > 0 && *self.owner.get() == pid {
+            *self.own_count.get() += 1;
+            true
+        } else {
+            if mutex_try_lock(self.lock.get()) {
+                *self.owner.get() = pid;
+                *self.own_count.get() = 1;
+                true
+            } else {
+                false
+            }
+        }
+    }
+
+    /// Lock the mutex
+    #[inline]
+    pub unsafe fn lock(&self) {
+        let pid = getpid().unwrap();
+        if *self.own_count.get() > 0 && *self.owner.get() == pid {
+            *self.own_count.get() += 1;
+        } else {
+            mutex_lock(self.lock.get());
+            *self.owner.get() = pid;
+            *self.own_count.get() = 1;
+        }
+    }
+
+    /// Unlock the mutex
+    #[inline]
+    pub unsafe fn unlock(&self) {
+        let pid = getpid().unwrap();
+        if *self.own_count.get() > 0 && *self.owner.get() == pid {
+            *self.own_count.get() -= 1;
+            if *self.own_count.get() == 0 {
+                *self.owner.get() = 0;
+                mutex_unlock(self.lock.get());
+            }
+        }
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {
+        *self.lock.get() = 0;
+        *self.owner.get() = 0;
+        *self.own_count.get() = 0;
+    }
+}
+
+unsafe impl Send for ReentrantMutex {}
+
+unsafe impl Sync for ReentrantMutex {}
diff --git a/src/libstd/sys/redox/net/dns/answer.rs b/src/libstd/sys/redox/net/dns/answer.rs
new file mode 100644
index 00000000000..8e6aaeb0293
--- /dev/null
+++ b/src/libstd/sys/redox/net/dns/answer.rs
@@ -0,0 +1,22 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use string::String;
+use vec::Vec;
+
+#[derive(Clone, Debug)]
+pub struct DnsAnswer {
+    pub name: String,
+    pub a_type: u16,
+    pub a_class: u16,
+    pub ttl_a: u16,
+    pub ttl_b: u16,
+    pub data: Vec<u8>
+}
diff --git a/src/libstd/sys/redox/net/dns/mod.rs b/src/libstd/sys/redox/net/dns/mod.rs
new file mode 100644
index 00000000000..43c4fe7ac9d
--- /dev/null
+++ b/src/libstd/sys/redox/net/dns/mod.rs
@@ -0,0 +1,217 @@
+// 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.
+
+pub use self::answer::DnsAnswer;
+pub use self::query::DnsQuery;
+
+use slice;
+use u16;
+use string::String;
+use vec::Vec;
+
+mod answer;
+mod query;
+
+#[unstable(feature = "n16", issue="0")]
+#[allow(non_camel_case_types)]
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(packed)]
+pub struct n16 {
+    inner: u16
+}
+
+impl n16 {
+    #[unstable(feature = "n16", issue="0")]
+    pub fn as_bytes(&self) -> &[u8] {
+        unsafe { slice::from_raw_parts((&self.inner as *const u16) as *const u8, 2) }
+    }
+
+    #[unstable(feature = "n16", issue="0")]
+    pub fn from_bytes(bytes: &[u8]) -> Self {
+        n16 {
+            inner: unsafe { slice::from_raw_parts(bytes.as_ptr() as *const u16, bytes.len()/2)[0] }
+        }
+    }
+}
+
+#[unstable(feature = "n16", issue="0")]
+impl From<u16> for n16 {
+    fn from(value: u16) -> Self {
+        n16 {
+            inner: value.to_be()
+        }
+    }
+}
+
+#[unstable(feature = "n16", issue="0")]
+impl From<n16> for u16 {
+    fn from(value: n16) -> Self {
+        u16::from_be(value.inner)
+    }
+}
+
+#[derive(Clone, Debug)]
+pub struct Dns {
+    pub transaction_id: u16,
+    pub flags: u16,
+    pub queries: Vec<DnsQuery>,
+    pub answers: Vec<DnsAnswer>
+}
+
+impl Dns {
+    pub fn compile(&self) -> Vec<u8> {
+        let mut data = Vec::new();
+
+        macro_rules! push_u8 {
+            ($value:expr) => {
+                data.push($value);
+            };
+        };
+
+        macro_rules! push_n16 {
+            ($value:expr) => {
+                data.extend_from_slice(n16::from($value).as_bytes());
+            };
+        };
+
+        push_n16!(self.transaction_id);
+        push_n16!(self.flags);
+        push_n16!(self.queries.len() as u16);
+        push_n16!(self.answers.len() as u16);
+        push_n16!(0);
+        push_n16!(0);
+
+        for query in self.queries.iter() {
+            for part in query.name.split('.') {
+                push_u8!(part.len() as u8);
+                data.extend_from_slice(part.as_bytes());
+            }
+            push_u8!(0);
+            push_n16!(query.q_type);
+            push_n16!(query.q_class);
+        }
+
+        data
+    }
+
+    pub fn parse(data: &[u8]) -> Result<Self, String> {
+        let mut i = 0;
+
+        macro_rules! pop_u8 {
+            () => {
+                {
+                    i += 1;
+                    if i > data.len() {
+                        return Err(format!("{}: {}: pop_u8", file!(), line!()));
+                    }
+                    data[i - 1]
+                }
+            };
+        };
+
+        macro_rules! pop_n16 {
+            () => {
+                {
+                    i += 2;
+                    if i > data.len() {
+                        return Err(format!("{}: {}: pop_n16", file!(), line!()));
+                    }
+                    u16::from(n16::from_bytes(&data[i - 2 .. i]))
+                }
+            };
+        };
+
+        macro_rules! pop_data {
+            () => {
+                {
+                    let mut data = Vec::new();
+
+                    let data_len = pop_n16!();
+                    for _data_i in 0..data_len {
+                        data.push(pop_u8!());
+                    }
+
+                    data
+                }
+            };
+        };
+
+        macro_rules! pop_name {
+            () => {
+                {
+                    let mut name = String::new();
+
+                    loop {
+                        let name_len = pop_u8!();
+                        if name_len == 0 {
+                            break;
+                        }
+                        if ! name.is_empty() {
+                            name.push('.');
+                        }
+                        for _name_i in 0..name_len {
+                            name.push(pop_u8!() as char);
+                        }
+                    }
+
+                    name
+                }
+            };
+        };
+
+        let transaction_id = pop_n16!();
+        let flags = pop_n16!();
+        let queries_len = pop_n16!();
+        let answers_len = pop_n16!();
+        pop_n16!();
+        pop_n16!();
+
+        let mut queries = Vec::new();
+        for _query_i in 0..queries_len {
+            queries.push(DnsQuery {
+                name: pop_name!(),
+                q_type: pop_n16!(),
+                q_class: pop_n16!()
+            });
+        }
+
+        let mut answers = Vec::new();
+        for _answer_i in 0..answers_len {
+            let name_ind = 0b11000000;
+            let name_test = pop_u8!();
+            i -= 1;
+
+            answers.push(DnsAnswer {
+                name: if name_test & name_ind == name_ind {
+                    let name_off = pop_n16!() - ((name_ind as u16) << 8);
+                    let old_i = i;
+                    i = name_off as usize;
+                    let name = pop_name!();
+                    i = old_i;
+                    name
+                } else {
+                    pop_name!()
+                },
+                a_type: pop_n16!(),
+                a_class: pop_n16!(),
+                ttl_a: pop_n16!(),
+                ttl_b: pop_n16!(),
+                data: pop_data!()
+            });
+        }
+
+        Ok(Dns {
+            transaction_id: transaction_id,
+            flags: flags,
+            queries: queries,
+            answers: answers,
+        })
+    }
+}
diff --git a/src/libstd/sys/redox/net/dns/query.rs b/src/libstd/sys/redox/net/dns/query.rs
new file mode 100644
index 00000000000..b0dcdcb624a
--- /dev/null
+++ b/src/libstd/sys/redox/net/dns/query.rs
@@ -0,0 +1,18 @@
+// 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 string::String;
+
+#[derive(Clone, Debug)]
+pub struct DnsQuery {
+    pub name: String,
+    pub q_type: u16,
+    pub q_class: u16
+}
diff --git a/src/libstd/sys/redox/net/mod.rs b/src/libstd/sys/redox/net/mod.rs
new file mode 100644
index 00000000000..3fdf61cfed8
--- /dev/null
+++ b/src/libstd/sys/redox/net/mod.rs
@@ -0,0 +1,113 @@
+// 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 fs::File;
+use io::{Error, Result, Read};
+use iter::Iterator;
+use net::{Ipv4Addr, SocketAddr, SocketAddrV4};
+use str::FromStr;
+use string::{String, ToString};
+use sys::syscall::EINVAL;
+use time;
+use vec::{IntoIter, Vec};
+
+use self::dns::{Dns, DnsQuery};
+
+pub use self::tcp::{TcpStream, TcpListener};
+pub use self::udp::UdpSocket;
+
+pub mod netc;
+
+mod dns;
+mod tcp;
+mod udp;
+
+pub struct LookupHost(IntoIter<SocketAddr>);
+
+impl Iterator for LookupHost {
+    type Item = SocketAddr;
+    fn next(&mut self) -> Option<Self::Item> {
+        self.0.next()
+    }
+}
+
+pub fn lookup_host(host: &str) -> Result<LookupHost> {
+    let mut ip_string = String::new();
+    File::open("/etc/net/ip")?.read_to_string(&mut ip_string)?;
+    let ip: Vec<u8> = ip_string.trim().split(".").map(|part| part.parse::<u8>()
+                               .unwrap_or(0)).collect();
+
+    let mut dns_string = String::new();
+    File::open("/etc/net/dns")?.read_to_string(&mut dns_string)?;
+    let dns: Vec<u8> = dns_string.trim().split(".").map(|part| part.parse::<u8>()
+                                 .unwrap_or(0)).collect();
+
+    if ip.len() == 4 && dns.len() == 4 {
+        let time = time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap();
+        let tid = (time.subsec_nanos() >> 16) as u16;
+
+        let packet = Dns {
+            transaction_id: tid,
+            flags: 0x0100,
+            queries: vec![DnsQuery {
+                name: host.to_string(),
+                q_type: 0x0001,
+                q_class: 0x0001,
+            }],
+            answers: vec![]
+        };
+
+        let packet_data = packet.compile();
+
+        let my_ip = Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]);
+        let dns_ip = Ipv4Addr::new(dns[0], dns[1], dns[2], dns[3]);
+        let socket = UdpSocket::bind(&SocketAddr::V4(SocketAddrV4::new(my_ip, 0)))?;
+        socket.connect(&SocketAddr::V4(SocketAddrV4::new(dns_ip, 53)))?;
+        socket.send(&packet_data)?;
+
+        let mut buf = [0; 65536];
+        let count = socket.recv(&mut buf)?;
+
+        match Dns::parse(&buf[.. count]) {
+            Ok(response) => {
+                let mut addrs = vec![];
+                for answer in response.answers.iter() {
+                    if answer.a_type == 0x0001 && answer.a_class == 0x0001
+                       && answer.data.len() == 4
+                    {
+                        let answer_ip = Ipv4Addr::new(answer.data[0],
+                                                      answer.data[1],
+                                                      answer.data[2],
+                                                      answer.data[3]);
+                        addrs.push(SocketAddr::V4(SocketAddrV4::new(answer_ip, 0)));
+                    }
+                }
+                Ok(LookupHost(addrs.into_iter()))
+            },
+            Err(_err) => Err(Error::from_raw_os_error(EINVAL))
+        }
+    } else {
+        Err(Error::from_raw_os_error(EINVAL))
+    }
+}
+
+fn path_to_peer_addr(path_str: &str) -> SocketAddr {
+    let mut parts = path_str.split('/').next().unwrap_or("").split(':').skip(1);
+    let host = Ipv4Addr::from_str(parts.next().unwrap_or("")).unwrap_or(Ipv4Addr::new(0, 0, 0, 0));
+    let port = parts.next().unwrap_or("").parse::<u16>().unwrap_or(0);
+    SocketAddr::V4(SocketAddrV4::new(host, port))
+}
+
+fn path_to_local_addr(path_str: &str) -> SocketAddr {
+    let mut parts = path_str.split('/').nth(1).unwrap_or("").split(':');
+    let host = Ipv4Addr::from_str(parts.next().unwrap_or("")).unwrap_or(Ipv4Addr::new(0, 0, 0, 0));
+    let port = parts.next().unwrap_or("").parse::<u16>().unwrap_or(0);
+    SocketAddr::V4(SocketAddrV4::new(host, port))
+}
diff --git a/src/libstd/sys/redox/net/netc.rs b/src/libstd/sys/redox/net/netc.rs
new file mode 100644
index 00000000000..03e1c9fffa4
--- /dev/null
+++ b/src/libstd/sys/redox/net/netc.rs
@@ -0,0 +1,57 @@
+// 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.
+
+pub type in_addr_t = u32;
+pub type in_port_t = u16;
+
+pub type socklen_t = u32;
+pub type sa_family_t = u16;
+
+pub const AF_INET: sa_family_t = 1;
+pub const AF_INET6: sa_family_t = 2;
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct in_addr {
+    pub s_addr: in_addr_t,
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct in6_addr {
+    pub s6_addr: [u8; 16],
+    __align: [u32; 0],
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct sockaddr {
+    pub sa_family: sa_family_t,
+    pub sa_data: [u8; 14],
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct sockaddr_in {
+    pub sin_family: sa_family_t,
+    pub sin_port: in_port_t,
+    pub sin_addr: in_addr,
+    pub sin_zero: [u8; 8],
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct sockaddr_in6 {
+    pub sin6_family: sa_family_t,
+    pub sin6_port: in_port_t,
+    pub sin6_flowinfo: u32,
+    pub sin6_addr: in6_addr,
+    pub sin6_scope_id: u32,
+}
diff --git a/src/libstd/sys/redox/net/tcp.rs b/src/libstd/sys/redox/net/tcp.rs
new file mode 100644
index 00000000000..d5362c9f131
--- /dev/null
+++ b/src/libstd/sys/redox/net/tcp.rs
@@ -0,0 +1,199 @@
+// 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 io::{Error, ErrorKind, Result};
+use net::{SocketAddr, Shutdown};
+use path::Path;
+use sys::fs::{File, OpenOptions};
+use sys_common::{AsInner, FromInner, IntoInner};
+use time::Duration;
+use vec::Vec;
+
+use super::{path_to_peer_addr, path_to_local_addr};
+
+#[derive(Debug)]
+pub struct TcpStream(File);
+
+impl TcpStream {
+    pub fn connect(addr: &SocketAddr) -> Result<TcpStream> {
+        let path = format!("tcp:{}", addr);
+        let mut options = OpenOptions::new();
+        options.read(true);
+        options.write(true);
+        Ok(TcpStream(File::open(&Path::new(path.as_str()), &options)?))
+    }
+
+    pub fn duplicate(&self) -> Result<TcpStream> {
+        Ok(TcpStream(self.0.dup(&[])?))
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
+        self.0.read(buf)
+    }
+
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
+        self.0.read_to_end(buf)
+    }
+
+    pub fn write(&self, buf: &[u8]) -> Result<usize> {
+        self.0.write(buf)
+    }
+
+    pub fn take_error(&self) -> Result<Option<Error>> {
+        Ok(None)
+    }
+
+    pub fn peer_addr(&self) -> Result<SocketAddr> {
+        let path = self.0.path()?;
+        Ok(path_to_peer_addr(path.to_str().unwrap_or("")))
+    }
+
+    pub fn socket_addr(&self) -> Result<SocketAddr> {
+        let path = self.0.path()?;
+        Ok(path_to_local_addr(path.to_str().unwrap_or("")))
+    }
+
+    pub fn shutdown(&self, _how: Shutdown) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "TcpStream::shutdown not implemented"))
+    }
+
+    pub fn nodelay(&self) -> Result<bool> {
+        Err(Error::new(ErrorKind::Other, "TcpStream::nodelay not implemented"))
+    }
+
+    pub fn nonblocking(&self) -> Result<bool> {
+        self.0.fd().nonblocking()
+    }
+
+    pub fn only_v6(&self) -> Result<bool> {
+        Err(Error::new(ErrorKind::Other, "TcpStream::only_v6 not implemented"))
+    }
+
+    pub fn ttl(&self) -> Result<u32> {
+        Err(Error::new(ErrorKind::Other, "TcpStream::ttl not implemented"))
+    }
+
+    pub fn read_timeout(&self) -> Result<Option<Duration>> {
+        Err(Error::new(ErrorKind::Other, "TcpStream::read_timeout not implemented"))
+    }
+
+    pub fn write_timeout(&self) -> Result<Option<Duration>> {
+        Err(Error::new(ErrorKind::Other, "TcpStream::write_timeout not implemented"))
+    }
+
+    pub fn set_nodelay(&self, _nodelay: bool) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "TcpStream::set_nodelay not implemented"))
+    }
+
+    pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()> {
+        self.0.fd().set_nonblocking(nonblocking)
+    }
+
+    pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "TcpStream::set_only_v6 not implemented"))
+    }
+
+    pub fn set_ttl(&self, _ttl: u32) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "TcpStream::set_ttl not implemented"))
+    }
+
+    pub fn set_read_timeout(&self, _dur: Option<Duration>) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "TcpStream::set_read_timeout not implemented"))
+    }
+
+    pub fn set_write_timeout(&self, _dur: Option<Duration>) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "TcpStream::set_write_timeout not implemented"))
+    }
+}
+
+impl AsInner<File> for TcpStream {
+    fn as_inner(&self) -> &File { &self.0 }
+}
+
+impl FromInner<File> for TcpStream {
+    fn from_inner(file: File) -> TcpStream {
+        TcpStream(file)
+    }
+}
+
+impl IntoInner<File> for TcpStream {
+    fn into_inner(self) -> File { self.0 }
+}
+
+#[derive(Debug)]
+pub struct TcpListener(File);
+
+impl TcpListener {
+    pub fn bind(addr: &SocketAddr) -> Result<TcpListener> {
+        let path = format!("tcp:/{}", addr);
+        let mut options = OpenOptions::new();
+        options.read(true);
+        options.write(true);
+        Ok(TcpListener(File::open(&Path::new(path.as_str()), &options)?))
+    }
+
+    pub fn accept(&self) -> Result<(TcpStream, SocketAddr)> {
+        let file = self.0.dup(b"listen")?;
+        let path = file.path()?;
+        let peer_addr = path_to_peer_addr(path.to_str().unwrap_or(""));
+        Ok((TcpStream(file), peer_addr))
+    }
+
+    pub fn duplicate(&self) -> Result<TcpListener> {
+        Ok(TcpListener(self.0.dup(&[])?))
+    }
+
+    pub fn take_error(&self) -> Result<Option<Error>> {
+        Ok(None)
+    }
+
+    pub fn socket_addr(&self) -> Result<SocketAddr> {
+        let path = self.0.path()?;
+        Ok(path_to_local_addr(path.to_str().unwrap_or("")))
+    }
+
+    pub fn nonblocking(&self) -> Result<bool> {
+        Err(Error::new(ErrorKind::Other, "TcpListener::nonblocking not implemented"))
+    }
+
+    pub fn only_v6(&self) -> Result<bool> {
+        Err(Error::new(ErrorKind::Other, "TcpListener::only_v6 not implemented"))
+    }
+
+    pub fn ttl(&self) -> Result<u32> {
+        Err(Error::new(ErrorKind::Other, "TcpListener::ttl not implemented"))
+    }
+
+    pub fn set_nonblocking(&self, _nonblocking: bool) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "TcpListener::set_nonblocking not implemented"))
+    }
+
+    pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "TcpListener::set_only_v6 not implemented"))
+    }
+
+    pub fn set_ttl(&self, _ttl: u32) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "TcpListener::set_ttl not implemented"))
+    }
+}
+
+impl AsInner<File> for TcpListener {
+    fn as_inner(&self) -> &File { &self.0 }
+}
+
+impl FromInner<File> for TcpListener {
+    fn from_inner(file: File) -> TcpListener {
+        TcpListener(file)
+    }
+}
+
+impl IntoInner<File> for TcpListener {
+    fn into_inner(self) -> File { self.0 }
+}
diff --git a/src/libstd/sys/redox/net/udp.rs b/src/libstd/sys/redox/net/udp.rs
new file mode 100644
index 00000000000..607c66c2ba7
--- /dev/null
+++ b/src/libstd/sys/redox/net/udp.rs
@@ -0,0 +1,188 @@
+// 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 cell::UnsafeCell;
+use io::{Error, ErrorKind, Result};
+use net::{SocketAddr, Ipv4Addr, Ipv6Addr};
+use path::Path;
+use sys::fs::{File, OpenOptions};
+use sys_common::{AsInner, FromInner, IntoInner};
+use time::Duration;
+
+use super::{path_to_peer_addr, path_to_local_addr};
+
+#[derive(Debug)]
+pub struct UdpSocket(File, UnsafeCell<Option<SocketAddr>>);
+
+impl UdpSocket {
+    pub fn bind(addr: &SocketAddr) -> Result<UdpSocket> {
+        let path = format!("udp:/{}", addr);
+        let mut options = OpenOptions::new();
+        options.read(true);
+        options.write(true);
+        Ok(UdpSocket(File::open(&Path::new(path.as_str()), &options)?, UnsafeCell::new(None)))
+    }
+
+    fn get_conn(&self) -> &mut Option<SocketAddr> {
+        unsafe { &mut *(self.1.get()) }
+    }
+
+    pub fn connect(&self, addr: &SocketAddr) -> Result<()> {
+        unsafe { *self.1.get() = Some(*addr) };
+        Ok(())
+    }
+
+    pub fn duplicate(&self) -> Result<UdpSocket> {
+        let new_bind = self.0.dup(&[])?;
+        let new_conn = *self.get_conn();
+        Ok(UdpSocket(new_bind, UnsafeCell::new(new_conn)))
+    }
+
+    pub fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)> {
+        let from = self.0.dup(b"listen")?;
+        let path = from.path()?;
+        let peer_addr = path_to_peer_addr(path.to_str().unwrap_or(""));
+        let count = from.read(buf)?;
+        Ok((count, peer_addr))
+    }
+
+    pub fn recv(&self, buf: &mut [u8]) -> Result<usize> {
+        if let Some(addr) = *self.get_conn() {
+            let from = self.0.dup(format!("{}", addr).as_bytes())?;
+            from.read(buf)
+        } else {
+            Err(Error::new(ErrorKind::Other, "UdpSocket::recv not connected"))
+        }
+    }
+
+    pub fn send_to(&self, buf: &[u8], addr: &SocketAddr) -> Result<usize> {
+        let to = self.0.dup(format!("{}", addr).as_bytes())?;
+        to.write(buf)
+    }
+
+    pub fn send(&self, buf: &[u8]) -> Result<usize> {
+        if let Some(addr) = *self.get_conn() {
+            self.send_to(buf, &addr)
+        } else {
+            Err(Error::new(ErrorKind::Other, "UdpSocket::send not connected"))
+        }
+    }
+
+    pub fn take_error(&self) -> Result<Option<Error>> {
+        Ok(None)
+    }
+
+    pub fn socket_addr(&self) -> Result<SocketAddr> {
+        let path = self.0.path()?;
+        Ok(path_to_local_addr(path.to_str().unwrap_or("")))
+    }
+
+    pub fn broadcast(&self) -> Result<bool> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::broadcast not implemented"))
+    }
+
+    pub fn multicast_loop_v4(&self) -> Result<bool> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::multicast_loop_v4 not implemented"))
+    }
+
+    pub fn multicast_loop_v6(&self) -> Result<bool> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::multicast_loop_v6 not implemented"))
+    }
+
+    pub fn multicast_ttl_v4(&self) -> Result<u32> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::multicast_ttl_v4 not implemented"))
+    }
+
+    pub fn nonblocking(&self) -> Result<bool> {
+        self.0.fd().nonblocking()
+    }
+
+    pub fn only_v6(&self) -> Result<bool> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::only_v6 not implemented"))
+    }
+
+    pub fn ttl(&self) -> Result<u32> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::ttl not implemented"))
+    }
+
+    pub fn read_timeout(&self) -> Result<Option<Duration>> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::read_timeout not implemented"))
+    }
+
+    pub fn write_timeout(&self) -> Result<Option<Duration>> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::write_timeout not implemented"))
+    }
+
+    pub fn set_broadcast(&self, _broadcast: bool) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::set_broadcast not implemented"))
+    }
+
+    pub fn set_multicast_loop_v4(&self, _multicast_loop_v4: bool) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::set_multicast_loop_v4 not implemented"))
+    }
+
+    pub fn set_multicast_loop_v6(&self, _multicast_loop_v6: bool) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::set_multicast_loop_v6 not implemented"))
+    }
+
+    pub fn set_multicast_ttl_v4(&self, _multicast_ttl_v4: u32) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::set_multicast_ttl_v4 not implemented"))
+    }
+
+    pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()> {
+        self.0.fd().set_nonblocking(nonblocking)
+    }
+
+    pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::set_only_v6 not implemented"))
+    }
+
+    pub fn set_ttl(&self, _ttl: u32) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::set_ttl not implemented"))
+    }
+
+    pub fn set_read_timeout(&self, _dur: Option<Duration>) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::set_read_timeout not implemented"))
+    }
+
+    pub fn set_write_timeout(&self, _dur: Option<Duration>) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::set_write_timeout not implemented"))
+    }
+
+    pub fn join_multicast_v4(&self, _multiaddr: &Ipv4Addr, _interface: &Ipv4Addr) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::join_multicast_v4 not implemented"))
+    }
+
+    pub fn join_multicast_v6(&self, _multiaddr: &Ipv6Addr, _interface: u32) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::join_multicast_v6 not implemented"))
+    }
+
+    pub fn leave_multicast_v4(&self, _multiaddr: &Ipv4Addr, _interface: &Ipv4Addr) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::leave_multicast_v4 not implemented"))
+    }
+
+    pub fn leave_multicast_v6(&self, _multiaddr: &Ipv6Addr, _interface: u32) -> Result<()> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::leave_multicast_v6 not implemented"))
+    }
+}
+
+impl AsInner<File> for UdpSocket {
+    fn as_inner(&self) -> &File { &self.0 }
+}
+
+impl FromInner<File> for UdpSocket {
+    fn from_inner(file: File) -> UdpSocket {
+        UdpSocket(file, UnsafeCell::new(None))
+    }
+}
+
+impl IntoInner<File> for UdpSocket {
+    fn into_inner(self) -> File { self.0 }
+}
diff --git a/src/libstd/sys/redox/os.rs b/src/libstd/sys/redox/os.rs
new file mode 100644
index 00000000000..135e972bca4
--- /dev/null
+++ b/src/libstd/sys/redox/os.rs
@@ -0,0 +1,204 @@
+// 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.
+
+//! Implementation of `std::os` functionality for unix systems
+
+#![allow(unused_imports)] // lots of cfg code here
+
+use os::unix::prelude::*;
+
+use error::Error as StdError;
+use ffi::{OsString, OsStr};
+use fmt;
+use io::{self, Read, Write};
+use iter;
+use marker::PhantomData;
+use mem;
+use memchr;
+use path::{self, PathBuf};
+use ptr;
+use slice;
+use str;
+use sys_common::mutex::Mutex;
+use sys::{cvt, fd, syscall};
+use vec;
+
+const TMPBUF_SZ: usize = 128;
+static ENV_LOCK: Mutex = Mutex::new();
+
+/// Returns the platform-specific value of errno
+pub fn errno() -> i32 {
+    0
+}
+
+/// Gets a detailed string description for the given error number.
+pub fn error_string(errno: i32) -> String {
+    if let Some(string) = syscall::STR_ERROR.get(errno as usize) {
+        string.to_string()
+    } else {
+        "unknown error".to_string()
+    }
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+    let mut buf = [0; 4096];
+    let count = cvt(syscall::getcwd(&mut buf))?;
+    Ok(PathBuf::from(OsString::from_vec(buf[.. count].to_vec())))
+}
+
+pub fn chdir(p: &path::Path) -> io::Result<()> {
+    cvt(syscall::chdir(p.to_str().unwrap())).and(Ok(()))
+}
+
+pub struct SplitPaths<'a> {
+    iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>,
+                    fn(&'a [u8]) -> PathBuf>,
+}
+
+pub fn split_paths(unparsed: &OsStr) -> SplitPaths {
+    fn bytes_to_path(b: &[u8]) -> PathBuf {
+        PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
+    }
+    fn is_colon(b: &u8) -> bool { *b == b':' }
+    let unparsed = unparsed.as_bytes();
+    SplitPaths {
+        iter: unparsed.split(is_colon as fn(&u8) -> bool)
+                      .map(bytes_to_path as fn(&[u8]) -> PathBuf)
+    }
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+    type Item = PathBuf;
+    fn next(&mut self) -> Option<PathBuf> { self.iter.next() }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
+    where I: Iterator<Item=T>, T: AsRef<OsStr>
+{
+    let mut joined = Vec::new();
+    let sep = b':';
+
+    for (i, path) in paths.enumerate() {
+        let path = path.as_ref().as_bytes();
+        if i > 0 { joined.push(sep) }
+        if path.contains(&sep) {
+            return Err(JoinPathsError)
+        }
+        joined.extend_from_slice(path);
+    }
+    Ok(OsStringExt::from_vec(joined))
+}
+
+impl fmt::Display for JoinPathsError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        "path segment contains separator `:`".fmt(f)
+    }
+}
+
+impl StdError for JoinPathsError {
+    fn description(&self) -> &str { "failed to join paths" }
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+    use fs::File;
+
+    let mut file = File::open("sys:exe")?;
+
+    let mut path = String::new();
+    file.read_to_string(&mut path)?;
+
+    if path.ends_with('\n') {
+        path.pop();
+    }
+
+    Ok(PathBuf::from(path))
+}
+
+pub struct Env {
+    iter: vec::IntoIter<(OsString, OsString)>,
+    _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Iterator for Env {
+    type Item = (OsString, OsString);
+    fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+/// Returns a vector of (variable, value) byte-vector pairs for all the
+/// environment variables of the current process.
+pub fn env() -> Env {
+    let mut variables: Vec<(OsString, OsString)> = Vec::new();
+    if let Ok(mut file) = ::fs::File::open("env:") {
+        let mut string = String::new();
+        if file.read_to_string(&mut string).is_ok() {
+            for line in string.lines() {
+                let mut parts = line.splitn(2, '=');
+                if let Some(name) = parts.next() {
+                    let value = parts.next().unwrap_or("");
+                    variables.push((OsString::from(name.to_string()),
+                                    OsString::from(value.to_string())));
+                }
+            }
+        }
+    }
+    Env { iter: variables.into_iter(), _dont_send_or_sync_me: PhantomData }
+}
+
+pub fn getenv(key: &OsStr) -> io::Result<Option<OsString>> {
+    if ! key.is_empty() {
+        if let Ok(mut file) = ::fs::File::open(&("env:".to_owned() + key.to_str().unwrap())) {
+            let mut string = String::new();
+            file.read_to_string(&mut string)?;
+            Ok(Some(OsString::from(string)))
+        } else {
+            Ok(None)
+        }
+    } else {
+        Ok(None)
+    }
+}
+
+pub fn setenv(key: &OsStr, value: &OsStr) -> io::Result<()> {
+    if ! key.is_empty() {
+        let mut file = ::fs::File::open(&("env:".to_owned() + key.to_str().unwrap()))?;
+        file.write_all(value.as_bytes())?;
+        file.set_len(value.len() as u64)?;
+    }
+    Ok(())
+}
+
+pub fn unsetenv(key: &OsStr) -> io::Result<()> {
+    ::fs::remove_file(&("env:".to_owned() + key.to_str().unwrap()))?;
+    Ok(())
+}
+
+pub fn page_size() -> usize {
+    4096
+}
+
+pub fn temp_dir() -> PathBuf {
+    ::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
+        PathBuf::from("/tmp")
+    })
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+    return ::env::var_os("HOME").map(PathBuf::from);
+}
+
+pub fn exit(code: i32) -> ! {
+    let _ = syscall::exit(code as usize);
+    unreachable!();
+}
diff --git a/src/libstd/sys/redox/os_str.rs b/src/libstd/sys/redox/os_str.rs
new file mode 100644
index 00000000000..8922bf04f56
--- /dev/null
+++ b/src/libstd/sys/redox/os_str.rs
@@ -0,0 +1,119 @@
+// 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.
+
+/// The underlying OsString/OsStr implementation on Unix systems: just
+/// a `Vec<u8>`/`[u8]`.
+
+use borrow::Cow;
+use fmt::{self, Debug};
+use str;
+use mem;
+use sys_common::{AsInner, IntoInner};
+
+#[derive(Clone, Hash)]
+pub struct Buf {
+    pub inner: Vec<u8>
+}
+
+pub struct Slice {
+    pub inner: [u8]
+}
+
+impl Debug for Slice {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+        self.to_string_lossy().fmt(formatter)
+    }
+}
+
+impl Debug for Buf {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+        self.as_slice().fmt(formatter)
+    }
+}
+
+impl IntoInner<Vec<u8>> for Buf {
+    fn into_inner(self) -> Vec<u8> {
+        self.inner
+    }
+}
+
+impl AsInner<[u8]> for Buf {
+    fn as_inner(&self) -> &[u8] {
+        &self.inner
+    }
+}
+
+
+impl Buf {
+    pub fn from_string(s: String) -> Buf {
+        Buf { inner: s.into_bytes() }
+    }
+
+    #[inline]
+    pub fn with_capacity(capacity: usize) -> Buf {
+        Buf {
+            inner: Vec::with_capacity(capacity)
+        }
+    }
+
+    #[inline]
+    pub fn clear(&mut self) {
+        self.inner.clear()
+    }
+
+    #[inline]
+    pub fn capacity(&self) -> usize {
+        self.inner.capacity()
+    }
+
+    #[inline]
+    pub fn reserve(&mut self, additional: usize) {
+        self.inner.reserve(additional)
+    }
+
+    #[inline]
+    pub fn reserve_exact(&mut self, additional: usize) {
+        self.inner.reserve_exact(additional)
+    }
+
+    pub fn as_slice(&self) -> &Slice {
+        unsafe { mem::transmute(&*self.inner) }
+    }
+
+    pub fn into_string(self) -> Result<String, Buf> {
+        String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } )
+    }
+
+    pub fn push_slice(&mut self, s: &Slice) {
+        self.inner.extend_from_slice(&s.inner)
+    }
+}
+
+impl Slice {
+    fn from_u8_slice(s: &[u8]) -> &Slice {
+        unsafe { mem::transmute(s) }
+    }
+
+    pub fn from_str(s: &str) -> &Slice {
+        Slice::from_u8_slice(s.as_bytes())
+    }
+
+    pub fn to_str(&self) -> Option<&str> {
+        str::from_utf8(&self.inner).ok()
+    }
+
+    pub fn to_string_lossy(&self) -> Cow<str> {
+        String::from_utf8_lossy(&self.inner)
+    }
+
+    pub fn to_owned(&self) -> Buf {
+        Buf { inner: self.inner.to_vec() }
+    }
+}
diff --git a/src/libstd/sys/redox/path.rs b/src/libstd/sys/redox/path.rs
new file mode 100644
index 00000000000..e6a267dd5d9
--- /dev/null
+++ b/src/libstd/sys/redox/path.rs
@@ -0,0 +1,39 @@
+// 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 ffi::OsStr;
+use path::Prefix;
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+    b == b'/'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+    b == b'/'
+}
+
+pub fn parse_prefix(path: &OsStr) -> Option<Prefix> {
+    if let Some(path_str) = path.to_str() {
+        if let Some(_i) = path_str.find(':') {
+            // FIXME: Redox specific prefix
+            // Some(Prefix::Verbatim(OsStr::new(&path_str[..i])))
+            None
+        } else {
+            None
+        }
+    } else {
+        None
+    }
+}
+
+pub const MAIN_SEP_STR: &'static str = "/";
+pub const MAIN_SEP: char = '/';
diff --git a/src/libstd/sys/redox/pipe.rs b/src/libstd/sys/redox/pipe.rs
new file mode 100644
index 00000000000..e7240fbe7bf
--- /dev/null
+++ b/src/libstd/sys/redox/pipe.rs
@@ -0,0 +1,107 @@
+// 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 io;
+use sys::{cvt, syscall};
+use sys::fd::FileDesc;
+
+////////////////////////////////////////////////////////////////////////////////
+// Anonymous pipes
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct AnonPipe(FileDesc);
+
+pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
+    let mut fds = [0; 2];
+    cvt(syscall::pipe2(&mut fds, syscall::O_CLOEXEC))?;
+    Ok((AnonPipe(FileDesc::new(fds[0])), AnonPipe(FileDesc::new(fds[1]))))
+}
+
+impl AnonPipe {
+    pub fn from_fd(fd: FileDesc) -> io::Result<AnonPipe> {
+        fd.set_cloexec()?;
+        Ok(AnonPipe(fd))
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.read(buf)
+    }
+
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.0.read_to_end(buf)
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        self.0.write(buf)
+    }
+
+    pub fn fd(&self) -> &FileDesc { &self.0 }
+    pub fn into_fd(self) -> FileDesc { self.0 }
+}
+
+pub fn read2(p1: AnonPipe,
+             v1: &mut Vec<u8>,
+             p2: AnonPipe,
+             v2: &mut Vec<u8>) -> io::Result<()> {
+    //FIXME: Use event based I/O multiplexing
+    //unimplemented!()
+
+    p1.read_to_end(v1)?;
+    p2.read_to_end(v2)?;
+
+    Ok(())
+
+    /*
+    // Set both pipes into nonblocking mode as we're gonna be reading from both
+    // in the `select` loop below, and we wouldn't want one to block the other!
+    let p1 = p1.into_fd();
+    let p2 = p2.into_fd();
+    p1.set_nonblocking(true)?;
+    p2.set_nonblocking(true)?;
+
+    loop {
+        // wait for either pipe to become readable using `select`
+        cvt_r(|| unsafe {
+            let mut read: libc::fd_set = mem::zeroed();
+            libc::FD_SET(p1.raw(), &mut read);
+            libc::FD_SET(p2.raw(), &mut read);
+            libc::select(max + 1, &mut read, ptr::null_mut(), ptr::null_mut(),
+                         ptr::null_mut())
+        })?;
+
+        // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
+        // EAGAIN. If we hit EOF, then this will happen because the underlying
+        // reader will return Ok(0), in which case we'll see `Ok` ourselves. In
+        // this case we flip the other fd back into blocking mode and read
+        // whatever's leftover on that file descriptor.
+        let read = |fd: &FileDesc, dst: &mut Vec<u8>| {
+            match fd.read_to_end(dst) {
+                Ok(_) => Ok(true),
+                Err(e) => {
+                    if e.raw_os_error() == Some(libc::EWOULDBLOCK) ||
+                       e.raw_os_error() == Some(libc::EAGAIN) {
+                        Ok(false)
+                    } else {
+                        Err(e)
+                    }
+                }
+            }
+        };
+        if read(&p1, v1)? {
+            p2.set_nonblocking(false)?;
+            return p2.read_to_end(v2).map(|_| ());
+        }
+        if read(&p2, v2)? {
+            p1.set_nonblocking(false)?;
+            return p1.read_to_end(v1).map(|_| ());
+        }
+    }
+    */
+}
diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs
new file mode 100644
index 00000000000..849f51013e6
--- /dev/null
+++ b/src/libstd/sys/redox/process.rs
@@ -0,0 +1,504 @@
+// 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 collections::hash_map::HashMap;
+use env;
+use ffi::OsStr;
+use fmt;
+use io::{self, Error, ErrorKind};
+use path::Path;
+use sys::fd::FileDesc;
+use sys::fs::{File, OpenOptions};
+use sys::pipe::{self, AnonPipe};
+use sys::{cvt, syscall};
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Command {
+    // Currently we try hard to ensure that the call to `.exec()` doesn't
+    // actually allocate any memory. While many platforms try to ensure that
+    // memory allocation works after a fork in a multithreaded process, it's
+    // been observed to be buggy and somewhat unreliable, so we do our best to
+    // just not do it at all!
+    //
+    // Along those lines, the `argv` and `envp` raw pointers here are exactly
+    // what's gonna get passed to `execvp`. The `argv` array starts with the
+    // `program` and ends with a NULL, and the `envp` pointer, if present, is
+    // also null-terminated.
+    //
+    // Right now we don't support removing arguments, so there's no much fancy
+    // support there, but we support adding and removing environment variables,
+    // so a side table is used to track where in the `envp` array each key is
+    // located. Whenever we add a key we update it in place if it's already
+    // present, and whenever we remove a key we update the locations of all
+    // other keys.
+    program: String,
+    args: Vec<String>,
+    env: HashMap<String, String>,
+
+    cwd: Option<String>,
+    uid: Option<u32>,
+    gid: Option<u32>,
+    saw_nul: bool,
+    closures: Vec<Box<FnMut() -> io::Result<()> + Send + Sync>>,
+    stdin: Option<Stdio>,
+    stdout: Option<Stdio>,
+    stderr: Option<Stdio>,
+}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+    pub stdin: Option<AnonPipe>,
+    pub stdout: Option<AnonPipe>,
+    pub stderr: Option<AnonPipe>,
+}
+
+// passed to do_exec() with configuration of what the child stdio should look
+// like
+struct ChildPipes {
+    stdin: ChildStdio,
+    stdout: ChildStdio,
+    stderr: ChildStdio,
+}
+
+enum ChildStdio {
+    Inherit,
+    Explicit(usize),
+    Owned(FileDesc),
+}
+
+pub enum Stdio {
+    Inherit,
+    Null,
+    MakePipe,
+    Fd(FileDesc),
+}
+
+impl Command {
+    pub fn new(program: &OsStr) -> Command {
+        Command {
+            program: program.to_str().unwrap().to_owned(),
+            args: Vec::new(),
+            env: HashMap::new(),
+            cwd: None,
+            uid: None,
+            gid: None,
+            saw_nul: false,
+            closures: Vec::new(),
+            stdin: None,
+            stdout: None,
+            stderr: None,
+        }
+    }
+
+    pub fn arg(&mut self, arg: &OsStr) {
+        self.args.push(arg.to_str().unwrap().to_owned());
+    }
+
+    pub fn env(&mut self, key: &OsStr, val: &OsStr) {
+        self.env.insert(key.to_str().unwrap().to_owned(), val.to_str().unwrap().to_owned());
+    }
+
+    pub fn env_remove(&mut self, key: &OsStr) {
+        self.env.remove(key.to_str().unwrap());
+    }
+
+    pub fn env_clear(&mut self) {
+        self.env.clear();
+    }
+
+    pub fn cwd(&mut self, dir: &OsStr) {
+        self.cwd = Some(dir.to_str().unwrap().to_owned());
+    }
+    pub fn uid(&mut self, id: u32) {
+        self.uid = Some(id);
+    }
+    pub fn gid(&mut self, id: u32) {
+        self.gid = Some(id);
+    }
+
+    pub fn before_exec(&mut self,
+                       f: Box<FnMut() -> io::Result<()> + Send + Sync>) {
+        self.closures.push(f);
+    }
+
+    pub fn stdin(&mut self, stdin: Stdio) {
+        self.stdin = Some(stdin);
+    }
+    pub fn stdout(&mut self, stdout: Stdio) {
+        self.stdout = Some(stdout);
+    }
+    pub fn stderr(&mut self, stderr: Stdio) {
+        self.stderr = Some(stderr);
+    }
+
+    pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
+                 -> io::Result<(Process, StdioPipes)> {
+         const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";
+
+         if self.saw_nul {
+             return Err(io::Error::new(ErrorKind::InvalidInput,
+                                       "nul byte found in provided data"));
+         }
+
+         let (ours, theirs) = self.setup_io(default, needs_stdin)?;
+         let (input, output) = pipe::anon_pipe()?;
+
+         let pid = unsafe {
+             match cvt(syscall::clone(0))? {
+                 0 => {
+                     drop(input);
+                     let err = self.do_exec(theirs);
+                     let errno = err.raw_os_error().unwrap_or(syscall::EINVAL) as u32;
+                     let bytes = [
+                         (errno >> 24) as u8,
+                         (errno >> 16) as u8,
+                         (errno >>  8) as u8,
+                         (errno >>  0) as u8,
+                         CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1],
+                         CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3]
+                     ];
+                     // pipe I/O up to PIPE_BUF bytes should be atomic, and then
+                     // we want to be sure we *don't* run at_exit destructors as
+                     // we're being torn down regardless
+                     assert!(output.write(&bytes).is_ok());
+                     let _ = syscall::exit(1);
+                     panic!("failed to exit");
+                 }
+                 n => n,
+             }
+         };
+
+         let mut p = Process { pid: pid, status: None };
+         drop(output);
+         let mut bytes = [0; 8];
+
+         // loop to handle EINTR
+         loop {
+             match input.read(&mut bytes) {
+                 Ok(0) => return Ok((p, ours)),
+                 Ok(8) => {
+                     assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]),
+                             "Validation on the CLOEXEC pipe failed: {:?}", bytes);
+                     let errno = combine(&bytes[0.. 4]);
+                     assert!(p.wait().is_ok(),
+                             "wait() should either return Ok or panic");
+                     return Err(Error::from_raw_os_error(errno))
+                 }
+                 Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+                 Err(e) => {
+                     assert!(p.wait().is_ok(),
+                             "wait() should either return Ok or panic");
+                     panic!("the CLOEXEC pipe failed: {:?}", e)
+                 },
+                 Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic
+                     assert!(p.wait().is_ok(),
+                             "wait() should either return Ok or panic");
+                     panic!("short read on the CLOEXEC pipe")
+                 }
+             }
+         }
+
+         fn combine(arr: &[u8]) -> i32 {
+             let a = arr[0] as u32;
+             let b = arr[1] as u32;
+             let c = arr[2] as u32;
+             let d = arr[3] as u32;
+
+             ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32
+         }
+    }
+
+    pub fn exec(&mut self, default: Stdio) -> io::Error {
+        if self.saw_nul {
+            return io::Error::new(ErrorKind::InvalidInput,
+                                  "nul byte found in provided data")
+        }
+
+        match self.setup_io(default, true) {
+            Ok((_, theirs)) => unsafe { self.do_exec(theirs) },
+            Err(e) => e,
+        }
+    }
+
+    // And at this point we've reached a special time in the life of the
+    // child. The child must now be considered hamstrung and unable to
+    // do anything other than syscalls really. Consider the following
+    // scenario:
+    //
+    //      1. Thread A of process 1 grabs the malloc() mutex
+    //      2. Thread B of process 1 forks(), creating thread C
+    //      3. Thread C of process 2 then attempts to malloc()
+    //      4. The memory of process 2 is the same as the memory of
+    //         process 1, so the mutex is locked.
+    //
+    // This situation looks a lot like deadlock, right? It turns out
+    // that this is what pthread_atfork() takes care of, which is
+    // presumably implemented across platforms. The first thing that
+    // threads to *before* forking is to do things like grab the malloc
+    // mutex, and then after the fork they unlock it.
+    //
+    // Despite this information, libnative's spawn has been witnessed to
+    // deadlock on both OSX and FreeBSD. I'm not entirely sure why, but
+    // all collected backtraces point at malloc/free traffic in the
+    // child spawned process.
+    //
+    // For this reason, the block of code below should contain 0
+    // invocations of either malloc of free (or their related friends).
+    //
+    // As an example of not having malloc/free traffic, we don't close
+    // this file descriptor by dropping the FileDesc (which contains an
+    // allocation). Instead we just close it manually. This will never
+    // have the drop glue anyway because this code never returns (the
+    // child will either exec() or invoke syscall::exit)
+    unsafe fn do_exec(&mut self, stdio: ChildPipes) -> io::Error {
+        macro_rules! t {
+            ($e:expr) => (match $e {
+                Ok(e) => e,
+                Err(e) => return e,
+            })
+        }
+
+        if let Some(fd) = stdio.stderr.fd() {
+            let _ = syscall::close(2);
+            t!(cvt(syscall::dup(fd, &[])));
+            let _ = syscall::close(fd);
+        }
+        if let Some(fd) = stdio.stdout.fd() {
+            let _ = syscall::close(1);
+            t!(cvt(syscall::dup(fd, &[])));
+            let _ = syscall::close(fd);
+        }
+        if let Some(fd) = stdio.stdin.fd() {
+            let _ = syscall::close(0);
+            t!(cvt(syscall::dup(fd, &[])));
+            let _ = syscall::close(fd);
+        }
+
+        if let Some(g) = self.gid {
+            t!(cvt(syscall::setregid(g as usize, g as usize)));
+        }
+        if let Some(u) = self.uid {
+            t!(cvt(syscall::setreuid(u as usize, u as usize)));
+        }
+        if let Some(ref cwd) = self.cwd {
+            t!(cvt(syscall::chdir(cwd)));
+        }
+
+        for callback in self.closures.iter_mut() {
+            t!(callback());
+        }
+
+        let mut args: Vec<[usize; 2]> = Vec::new();
+        args.push([self.program.as_ptr() as usize, self.program.len()]);
+        for arg in self.args.iter() {
+            args.push([arg.as_ptr() as usize, arg.len()]);
+        }
+
+        for (key, val) in self.env.iter() {
+            env::set_var(key, val);
+        }
+
+        let program = if self.program.contains(':') || self.program.contains('/') {
+            self.program.to_owned()
+        } else {
+            let mut path_env = ::env::var("PATH").unwrap_or(".".to_string());
+
+            if ! path_env.ends_with('/') {
+                path_env.push('/');
+            }
+
+            path_env.push_str(&self.program);
+
+            path_env
+        };
+
+        if let Err(err) = syscall::execve(&program, &args) {
+            io::Error::from_raw_os_error(err.errno as i32)
+        } else {
+            panic!("return from exec without err");
+        }
+    }
+
+
+    fn setup_io(&self, default: Stdio, needs_stdin: bool)
+                -> io::Result<(StdioPipes, ChildPipes)> {
+        let null = Stdio::Null;
+        let default_stdin = if needs_stdin {&default} else {&null};
+        let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
+        let stdout = self.stdout.as_ref().unwrap_or(&default);
+        let stderr = self.stderr.as_ref().unwrap_or(&default);
+        let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
+        let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
+        let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
+        let ours = StdioPipes {
+            stdin: our_stdin,
+            stdout: our_stdout,
+            stderr: our_stderr,
+        };
+        let theirs = ChildPipes {
+            stdin: their_stdin,
+            stdout: their_stdout,
+            stderr: their_stderr,
+        };
+        Ok((ours, theirs))
+    }
+}
+
+impl Stdio {
+    fn to_child_stdio(&self, readable: bool)
+                      -> io::Result<(ChildStdio, Option<AnonPipe>)> {
+        match *self {
+            Stdio::Inherit => Ok((ChildStdio::Inherit, None)),
+
+            // Make sure that the source descriptors are not an stdio
+            // descriptor, otherwise the order which we set the child's
+            // descriptors may blow away a descriptor which we are hoping to
+            // save. For example, suppose we want the child's stderr to be the
+            // parent's stdout, and the child's stdout to be the parent's
+            // stderr. No matter which we dup first, the second will get
+            // overwritten prematurely.
+            Stdio::Fd(ref fd) => {
+                if fd.raw() <= 2 {
+                    Ok((ChildStdio::Owned(fd.duplicate()?), None))
+                } else {
+                    Ok((ChildStdio::Explicit(fd.raw()), None))
+                }
+            }
+
+            Stdio::MakePipe => {
+                let (reader, writer) = pipe::anon_pipe()?;
+                let (ours, theirs) = if readable {
+                    (writer, reader)
+                } else {
+                    (reader, writer)
+                };
+                Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours)))
+            }
+
+            Stdio::Null => {
+                let mut opts = OpenOptions::new();
+                opts.read(readable);
+                opts.write(!readable);
+                let fd = File::open(&Path::new("null:"), &opts)?;
+                Ok((ChildStdio::Owned(fd.into_fd()), None))
+            }
+        }
+    }
+}
+
+impl ChildStdio {
+    fn fd(&self) -> Option<usize> {
+        match *self {
+            ChildStdio::Inherit => None,
+            ChildStdio::Explicit(fd) => Some(fd),
+            ChildStdio::Owned(ref fd) => Some(fd.raw()),
+        }
+    }
+}
+
+impl fmt::Debug for Command {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{:?}", self.program)?;
+        for arg in &self.args {
+            write!(f, " {:?}", arg)?;
+        }
+        Ok(())
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Processes
+////////////////////////////////////////////////////////////////////////////////
+
+/// Unix exit statuses
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitStatus(i32);
+
+impl ExitStatus {
+    fn exited(&self) -> bool {
+        self.0 & 0x7F == 0
+    }
+
+    pub fn success(&self) -> bool {
+        self.code() == Some(0)
+    }
+
+    pub fn code(&self) -> Option<i32> {
+        if self.exited() {
+            Some((self.0 >> 8) & 0xFF)
+        } else {
+            None
+        }
+    }
+
+    pub fn signal(&self) -> Option<i32> {
+        if !self.exited() {
+            Some(self.0 & 0x7F)
+        } else {
+            None
+        }
+    }
+}
+
+impl From<i32> for ExitStatus {
+    fn from(a: i32) -> ExitStatus {
+        ExitStatus(a)
+    }
+}
+
+impl fmt::Display for ExitStatus {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if let Some(code) = self.code() {
+            write!(f, "exit code: {}", code)
+        } else {
+            let signal = self.signal().unwrap();
+            write!(f, "signal: {}", signal)
+        }
+    }
+}
+
+/// The unique id of the process (this should never be negative).
+pub struct Process {
+    pid: usize,
+    status: Option<ExitStatus>,
+}
+
+impl Process {
+    pub fn id(&self) -> u32 {
+        self.pid as u32
+    }
+
+    pub fn kill(&mut self) -> io::Result<()> {
+        // If we've already waited on this process then the pid can be recycled
+        // and used for another process, and we probably shouldn't be killing
+        // random processes, so just return an error.
+        if self.status.is_some() {
+            Err(Error::new(ErrorKind::InvalidInput,
+                           "invalid argument: can't kill an exited process"))
+        } else {
+            cvt(syscall::kill(self.pid, syscall::SIGKILL))?;
+            Ok(())
+        }
+    }
+
+    pub fn wait(&mut self) -> io::Result<ExitStatus> {
+        if let Some(status) = self.status {
+            return Ok(status)
+        }
+        let mut status = 0;
+        cvt(syscall::waitpid(self.pid, &mut status, 0))?;
+        self.status = Some(ExitStatus(status as i32));
+        Ok(ExitStatus(status as i32))
+    }
+}
diff --git a/src/libstd/sys/redox/rand.rs b/src/libstd/sys/redox/rand.rs
new file mode 100644
index 00000000000..eb28eca38bc
--- /dev/null
+++ b/src/libstd/sys/redox/rand.rs
@@ -0,0 +1,57 @@
+// 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 io;
+use rand::Rng;
+
+// FIXME: Use rand:
+pub struct OsRng {
+    state: [u64; 2]
+}
+
+impl OsRng {
+    /// Create a new `OsRng`.
+    pub fn new() -> io::Result<OsRng> {
+        Ok(OsRng {
+            state: [0xBADF00D1, 0xDEADBEEF]
+        })
+    }
+}
+
+impl Rng for OsRng {
+    fn next_u32(&mut self) -> u32 {
+        self.next_u64() as u32
+    }
+    fn next_u64(&mut self) -> u64 {
+        // Store the first and second part.
+        let mut x = self.state[0];
+        let y = self.state[1];
+
+        // Put the second part into the first slot.
+        self.state[0] = y;
+        // Twist the first slot.
+        x ^= x << 23;
+        // Update the second slot.
+        self.state[1] = x ^ y ^ (x >> 17) ^ (y >> 26);
+
+        // Generate the final integer.
+        self.state[1].wrapping_add(y)
+
+    }
+    fn fill_bytes(&mut self, buf: &mut [u8]) {
+        for chunk in buf.chunks_mut(8) {
+            let mut rand: u64 = self.next_u64();
+            for b in chunk.iter_mut() {
+                *b = rand as u8;
+                rand = rand >> 8;
+            }
+        }
+    }
+}
diff --git a/src/libstd/sys/redox/rwlock.rs b/src/libstd/sys/redox/rwlock.rs
new file mode 100644
index 00000000000..d74b614ba47
--- /dev/null
+++ b/src/libstd/sys/redox/rwlock.rs
@@ -0,0 +1,61 @@
+// 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 super::mutex::Mutex;
+
+pub struct RWLock {
+    mutex: Mutex
+}
+
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {}
+
+impl RWLock {
+    pub const fn new() -> RWLock {
+        RWLock {
+            mutex: Mutex::new()
+        }
+    }
+
+    #[inline]
+    pub unsafe fn read(&self) {
+        self.mutex.lock();
+    }
+
+    #[inline]
+    pub unsafe fn try_read(&self) -> bool {
+        self.mutex.try_lock()
+    }
+
+    #[inline]
+    pub unsafe fn write(&self) {
+        self.mutex.lock();
+    }
+
+    #[inline]
+    pub unsafe fn try_write(&self) -> bool {
+        self.mutex.try_lock()
+    }
+
+    #[inline]
+    pub unsafe fn read_unlock(&self) {
+        self.mutex.unlock();
+    }
+
+    #[inline]
+    pub unsafe fn write_unlock(&self) {
+        self.mutex.unlock();
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {
+        self.mutex.destroy();
+    }
+}
diff --git a/src/libstd/sys/redox/stack_overflow.rs b/src/libstd/sys/redox/stack_overflow.rs
new file mode 100644
index 00000000000..760fe06c57f
--- /dev/null
+++ b/src/libstd/sys/redox/stack_overflow.rs
@@ -0,0 +1,27 @@
+// 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.
+
+#![cfg_attr(test, allow(dead_code))]
+
+pub struct Handler;
+
+impl Handler {
+    pub unsafe fn new() -> Handler {
+        Handler
+    }
+}
+
+pub unsafe fn init() {
+
+}
+
+pub unsafe fn cleanup() {
+
+}
diff --git a/src/libstd/sys/redox/stdio.rs b/src/libstd/sys/redox/stdio.rs
new file mode 100644
index 00000000000..607eef051d6
--- /dev/null
+++ b/src/libstd/sys/redox/stdio.rs
@@ -0,0 +1,81 @@
+// 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 io;
+use sys::{cvt, syscall};
+use sys::fd::FileDesc;
+
+pub struct Stdin(());
+pub struct Stdout(());
+pub struct Stderr(());
+
+impl Stdin {
+    pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) }
+
+    pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
+        let fd = FileDesc::new(0);
+        let ret = fd.read(data);
+        fd.into_raw();
+        ret
+    }
+
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        let fd = FileDesc::new(0);
+        let ret = fd.read_to_end(buf);
+        fd.into_raw();
+        ret
+    }
+}
+
+impl Stdout {
+    pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) }
+
+    pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+        let fd = FileDesc::new(1);
+        let ret = fd.write(data);
+        fd.into_raw();
+        ret
+    }
+
+    pub fn flush(&self) -> io::Result<()> {
+        cvt(syscall::fsync(1)).and(Ok(()))
+    }
+}
+
+impl Stderr {
+    pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) }
+
+    pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+        let fd = FileDesc::new(2);
+        let ret = fd.write(data);
+        fd.into_raw();
+        ret
+    }
+
+    pub fn flush(&self) -> io::Result<()> {
+        cvt(syscall::fsync(2)).and(Ok(()))
+    }
+}
+
+// FIXME: right now this raw stderr handle is used in a few places because
+//        std::io::stderr_raw isn't exposed, but once that's exposed this impl
+//        should go away
+impl io::Write for Stderr {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+        Stderr::write(self, data)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Stderr::flush(self)
+    }
+}
+
+pub const EBADF_ERR: i32 = ::sys::syscall::EBADF;
+pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
diff --git a/src/libstd/sys/redox/syscall/arch/arm.rs b/src/libstd/sys/redox/syscall/arch/arm.rs
new file mode 100644
index 00000000000..9fb3961486d
--- /dev/null
+++ b/src/libstd/sys/redox/syscall/arch/arm.rs
@@ -0,0 +1,83 @@
+// 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 super::error::{Error, Result};
+
+pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
+    asm!("swi $$0"
+        : "={r0}"(a)
+        : "{r7}"(a)
+        : "memory"
+        : "volatile");
+
+    Error::demux(a)
+}
+
+pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
+    asm!("swi $$0"
+        : "={r0}"(a)
+        : "{r7}"(a), "{r0}"(b)
+        : "memory"
+        : "volatile");
+
+    Error::demux(a)
+}
+
+// Clobbers all registers - special for clone
+pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
+    asm!("swi $$0"
+        : "={r0}"(a)
+        : "{r7}"(a), "{r0}"(b)
+        : "memory", "r0", "r1", "r2", "r3", "r4"
+        : "volatile");
+
+    Error::demux(a)
+}
+
+pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
+    asm!("swi $$0"
+        : "={r0}"(a)
+        : "{r7}"(a), "{r0}"(b), "{r1}"(c)
+        : "memory"
+        : "volatile");
+
+    Error::demux(a)
+}
+
+pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
+    asm!("swi $$0"
+        : "={r0}"(a)
+        : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d)
+        : "memory"
+        : "volatile");
+
+    Error::demux(a)
+}
+
+pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
+    asm!("swi $$0"
+        : "={r0}"(a)
+        : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d), "{r3}"(e)
+        : "memory"
+        : "volatile");
+
+    Error::demux(a)
+}
+
+pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
+                       -> Result<usize> {
+    asm!("swi $$0"
+        : "={r0}"(a)
+        : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d), "{r3}"(e), "{r4}"(f)
+        : "memory"
+        : "volatile");
+
+    Error::demux(a)
+}
diff --git a/src/libstd/sys/redox/syscall/arch/x86.rs b/src/libstd/sys/redox/syscall/arch/x86.rs
new file mode 100644
index 00000000000..724a6b927f4
--- /dev/null
+++ b/src/libstd/sys/redox/syscall/arch/x86.rs
@@ -0,0 +1,83 @@
+// 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 super::error::{Error, Result};
+
+pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
+    asm!("int 0x80"
+        : "={eax}"(a)
+        : "{eax}"(a)
+        : "memory"
+        : "intel", "volatile");
+
+    Error::demux(a)
+}
+
+pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
+    asm!("int 0x80"
+        : "={eax}"(a)
+        : "{eax}"(a), "{ebx}"(b)
+        : "memory"
+        : "intel", "volatile");
+
+    Error::demux(a)
+}
+
+// Clobbers all registers - special for clone
+pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
+    asm!("int 0x80"
+        : "={eax}"(a)
+        : "{eax}"(a), "{ebx}"(b)
+        : "memory", "ebx", "ecx", "edx", "esi", "edi"
+        : "intel", "volatile");
+
+    Error::demux(a)
+}
+
+pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
+    asm!("int 0x80"
+        : "={eax}"(a)
+        : "{eax}"(a), "{ebx}"(b), "{ecx}"(c)
+        : "memory"
+        : "intel", "volatile");
+
+    Error::demux(a)
+}
+
+pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
+    asm!("int 0x80"
+        : "={eax}"(a)
+        : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d)
+        : "memory"
+        : "intel", "volatile");
+
+    Error::demux(a)
+}
+
+pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
+    asm!("int 0x80"
+        : "={eax}"(a)
+        : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e)
+        : "memory"
+        : "intel", "volatile");
+
+    Error::demux(a)
+}
+
+pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
+                       -> Result<usize> {
+    asm!("int 0x80"
+        : "={eax}"(a)
+        : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e), "{edi}"(f)
+        : "memory"
+        : "intel", "volatile");
+
+    Error::demux(a)
+}
diff --git a/src/libstd/sys/redox/syscall/arch/x86_64.rs b/src/libstd/sys/redox/syscall/arch/x86_64.rs
new file mode 100644
index 00000000000..a321c31f207
--- /dev/null
+++ b/src/libstd/sys/redox/syscall/arch/x86_64.rs
@@ -0,0 +1,84 @@
+// 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 super::error::{Error, Result};
+
+pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
+    asm!("int 0x80"
+        : "={rax}"(a)
+        : "{rax}"(a)
+        : "memory"
+        : "intel", "volatile");
+
+    Error::demux(a)
+}
+
+pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
+    asm!("int 0x80"
+        : "={rax}"(a)
+        : "{rax}"(a), "{rbx}"(b)
+        : "memory"
+        : "intel", "volatile");
+
+    Error::demux(a)
+}
+
+// Clobbers all registers - special for clone
+pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
+    asm!("int 0x80"
+        : "={rax}"(a)
+        : "{rax}"(a), "{rbx}"(b)
+        : "memory", "rbx", "rcx", "rdx", "rsi", "rdi", "r8",
+          "r9", "r10", "r11", "r12", "r13", "r14", "r15"
+        : "intel", "volatile");
+
+    Error::demux(a)
+}
+
+pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
+    asm!("int 0x80"
+        : "={rax}"(a)
+        : "{rax}"(a), "{rbx}"(b), "{rcx}"(c)
+        : "memory"
+        : "intel", "volatile");
+
+    Error::demux(a)
+}
+
+pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
+    asm!("int 0x80"
+        : "={rax}"(a)
+        : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d)
+        : "memory"
+        : "intel", "volatile");
+
+    Error::demux(a)
+}
+
+pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
+    asm!("int 0x80"
+        : "={rax}"(a)
+        : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d), "{rsi}"(e)
+        : "memory"
+        : "intel", "volatile");
+
+    Error::demux(a)
+}
+
+pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
+                       -> Result<usize> {
+    asm!("int 0x80"
+        : "={rax}"(a)
+        : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d), "{rsi}"(e), "{rdi}"(f)
+        : "memory"
+        : "intel", "volatile");
+
+    Error::demux(a)
+}
diff --git a/src/libstd/sys/redox/syscall/call.rs b/src/libstd/sys/redox/syscall/call.rs
new file mode 100644
index 00000000000..f58c240f31e
--- /dev/null
+++ b/src/libstd/sys/redox/syscall/call.rs
@@ -0,0 +1,300 @@
+// 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 super::arch::*;
+use super::data::{Stat, StatVfs, TimeSpec};
+use super::error::Result;
+use super::number::*;
+
+use core::mem;
+
+/// Set the end of the process's heap
+///
+/// When `addr` is `0`, this function will return the current break.
+///
+/// When `addr` is nonzero, this function will attempt to set the end of the process's
+/// heap to `addr` and return the new program break. The new program break should be
+/// checked by the allocator, it may not be exactly `addr`, as it may be aligned to a page
+/// boundary.
+///
+/// On error, `Err(ENOMEM)` will be returned indicating that no memory is available
+pub unsafe fn brk(addr: usize) -> Result<usize> {
+    syscall1(SYS_BRK, addr)
+}
+
+/// Change the process's working directory
+///
+/// This function will attempt to set the process's working directory to `path`, which can be
+/// either a relative, scheme relative, or absolute path.
+///
+/// On success, `Ok(0)` will be returned. On error, one of the following errors will be returned.
+///
+/// # Errors
+///
+/// * `EACCES` - permission is denied for one of the components of `path`, or `path`
+/// * `EFAULT` - `path` does not point to the process's addressible memory
+/// * `EIO` - an I/O error occured
+/// * `ENOENT` - `path` does not exit
+/// * `ENOTDIR` - `path` is not a directory
+pub fn chdir(path: &str) -> Result<usize> {
+    unsafe { syscall2(SYS_CHDIR, path.as_ptr() as usize, path.len()) }
+}
+
+pub fn chmod(path: &str, mode: usize) -> Result<usize> {
+    unsafe { syscall3(SYS_CHMOD, path.as_ptr() as usize, path.len(), mode) }
+}
+
+/// Produce a fork of the current process, or a new process thread
+pub unsafe fn clone(flags: usize) -> Result<usize> {
+    syscall1_clobber(SYS_CLONE, flags)
+}
+
+/// Close a file
+pub fn close(fd: usize) -> Result<usize> {
+    unsafe { syscall1(SYS_CLOSE, fd) }
+}
+
+/// Get the current system time
+pub fn clock_gettime(clock: usize, tp: &mut TimeSpec) -> Result<usize> {
+    unsafe { syscall2(SYS_CLOCK_GETTIME, clock, tp as *mut TimeSpec as usize) }
+}
+
+/// Copy and transform a file descriptor
+pub fn dup(fd: usize, buf: &[u8]) -> Result<usize> {
+    unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) }
+}
+
+/// Replace the current process with a new executable
+pub fn execve(path: &str, args: &[[usize; 2]]) -> Result<usize> {
+    unsafe { syscall4(SYS_EXECVE, path.as_ptr() as usize, path.len(),
+                                  args.as_ptr() as usize, args.len()) }
+}
+
+/// Exit the current process
+pub fn exit(status: usize) -> Result<usize> {
+    unsafe { syscall1(SYS_EXIT, status) }
+}
+
+/// Register a file for event-based I/O
+pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result<usize> {
+    unsafe { syscall3(SYS_FCNTL, fd, cmd, arg) }
+}
+
+/// Register a file for event-based I/O
+pub fn fevent(fd: usize, flags: usize) -> Result<usize> {
+    unsafe { syscall2(SYS_FEVENT, fd, flags) }
+}
+
+/// Map a file into memory
+pub unsafe fn fmap(fd: usize, offset: usize, size: usize) -> Result<usize> {
+    syscall3(SYS_FMAP, fd, offset, size)
+}
+
+/// Unmap a memory-mapped file
+pub unsafe fn funmap(addr: usize) -> Result<usize> {
+    syscall1(SYS_FUNMAP, addr)
+}
+
+/// Retrieve the canonical path of a file
+pub fn fpath(fd: usize, buf: &mut [u8]) -> Result<usize> {
+    unsafe { syscall3(SYS_FPATH, fd, buf.as_mut_ptr() as usize, buf.len()) }
+}
+
+/// Get metadata about a file
+pub fn fstat(fd: usize, stat: &mut Stat) -> Result<usize> {
+    unsafe { syscall3(SYS_FSTAT, fd, stat as *mut Stat as usize, mem::size_of::<Stat>()) }
+}
+
+/// Get metadata about a filesystem
+pub fn fstatvfs(fd: usize, stat: &mut StatVfs) -> Result<usize> {
+    unsafe { syscall3(SYS_FSTATVFS, fd, stat as *mut StatVfs as usize, mem::size_of::<StatVfs>()) }
+}
+
+/// Sync a file descriptor to its underlying medium
+pub fn fsync(fd: usize) -> Result<usize> {
+    unsafe { syscall1(SYS_FSYNC, fd) }
+}
+
+/// Truncate or extend a file to a specified length
+pub fn ftruncate(fd: usize, len: usize) -> Result<usize> {
+    unsafe { syscall2(SYS_FTRUNCATE, fd, len) }
+}
+
+/// Fast userspace mutex
+pub unsafe fn futex(addr: *mut i32, op: usize, val: i32, val2: usize, addr2: *mut i32)
+                    -> Result<usize> {
+    syscall5(SYS_FUTEX, addr as usize, op, (val as isize) as usize, val2, addr2 as usize)
+}
+
+/// Get the current working directory
+pub fn getcwd(buf: &mut [u8]) -> Result<usize> {
+    unsafe { syscall2(SYS_GETCWD, buf.as_mut_ptr() as usize, buf.len()) }
+}
+
+/// Get the effective group ID
+pub fn getegid() -> Result<usize> {
+    unsafe { syscall0(SYS_GETEGID) }
+}
+
+/// Get the effective namespace
+pub fn getens() -> Result<usize> {
+    unsafe { syscall0(SYS_GETENS) }
+}
+
+/// Get the effective user ID
+pub fn geteuid() -> Result<usize> {
+    unsafe { syscall0(SYS_GETEUID) }
+}
+
+/// Get the current group ID
+pub fn getgid() -> Result<usize> {
+    unsafe { syscall0(SYS_GETGID) }
+}
+
+/// Get the current namespace
+pub fn getns() -> Result<usize> {
+    unsafe { syscall0(SYS_GETNS) }
+}
+
+/// Get the current process ID
+pub fn getpid() -> Result<usize> {
+    unsafe { syscall0(SYS_GETPID) }
+}
+
+/// Get the current user ID
+pub fn getuid() -> Result<usize> {
+    unsafe { syscall0(SYS_GETUID) }
+}
+
+/// Set the I/O privilege level
+pub unsafe fn iopl(level: usize) -> Result<usize> {
+    syscall1(SYS_IOPL, level)
+}
+
+/// Send a signal `sig` to the process identified by `pid`
+pub fn kill(pid: usize, sig: usize) -> Result<usize> {
+    unsafe { syscall2(SYS_KILL, pid, sig) }
+}
+
+/// Create a link to a file
+pub unsafe fn link(old: *const u8, new: *const u8) -> Result<usize> {
+    syscall2(SYS_LINK, old as usize, new as usize)
+}
+
+/// Seek to `offset` bytes in a file descriptor
+pub fn lseek(fd: usize, offset: isize, whence: usize) -> Result<usize> {
+    unsafe { syscall3(SYS_LSEEK, fd, offset as usize, whence) }
+}
+
+/// Make a new scheme namespace
+pub fn mkns(schemes: &[[usize; 2]]) -> Result<usize> {
+    unsafe { syscall2(SYS_MKNS, schemes.as_ptr() as usize, schemes.len()) }
+}
+
+/// Sleep for the time specified in `req`
+pub fn nanosleep(req: &TimeSpec, rem: &mut TimeSpec) -> Result<usize> {
+    unsafe { syscall2(SYS_NANOSLEEP, req as *const TimeSpec as usize,
+                                     rem as *mut TimeSpec as usize) }
+}
+
+/// Open a file
+pub fn open(path: &str, flags: usize) -> Result<usize> {
+    unsafe { syscall3(SYS_OPEN, path.as_ptr() as usize, path.len(), flags) }
+}
+
+/// Allocate pages, linearly in physical memory
+pub unsafe fn physalloc(size: usize) -> Result<usize> {
+    syscall1(SYS_PHYSALLOC, size)
+}
+
+/// Free physically allocated pages
+pub unsafe fn physfree(physical_address: usize, size: usize) -> Result<usize> {
+    syscall2(SYS_PHYSFREE, physical_address, size)
+}
+
+/// Map physical memory to virtual memory
+pub unsafe fn physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> {
+    syscall3(SYS_PHYSMAP, physical_address, size, flags)
+}
+
+/// Unmap previously mapped physical memory
+pub unsafe fn physunmap(virtual_address: usize) -> Result<usize> {
+    syscall1(SYS_PHYSUNMAP, virtual_address)
+}
+
+/// Create a pair of file descriptors referencing the read and write ends of a pipe
+pub fn pipe2(fds: &mut [usize; 2], flags: usize) -> Result<usize> {
+    unsafe { syscall2(SYS_PIPE2, fds.as_ptr() as usize, flags) }
+}
+
+/// Read from a file descriptor into a buffer
+pub fn read(fd: usize, buf: &mut [u8]) -> Result<usize> {
+    unsafe { syscall3(SYS_READ, fd, buf.as_mut_ptr() as usize, buf.len()) }
+}
+
+/// Remove a directory
+pub fn rmdir(path: &str) -> Result<usize> {
+    unsafe { syscall2(SYS_RMDIR, path.as_ptr() as usize, path.len()) }
+}
+
+/// Set the current process group IDs
+pub fn setregid(rgid: usize, egid: usize) -> Result<usize> {
+    unsafe { syscall2(SYS_SETREGID, rgid, egid) }
+}
+
+/// Make a new scheme namespace
+pub fn setrens(rns: usize, ens: usize) -> Result<usize> {
+    unsafe { syscall2(SYS_SETRENS, rns, ens) }
+}
+
+/// Set the current process user IDs
+pub fn setreuid(ruid: usize, euid: usize) -> Result<usize> {
+    unsafe { syscall2(SYS_SETREUID, ruid, euid) }
+}
+
+/// Remove a file
+pub fn unlink(path: &str) -> Result<usize> {
+    unsafe { syscall2(SYS_UNLINK, path.as_ptr() as usize, path.len()) }
+}
+
+/// Convert a virtual address to a physical one
+pub unsafe fn virttophys(virtual_address: usize) -> Result<usize> {
+    syscall1(SYS_VIRTTOPHYS, virtual_address)
+}
+
+/// Check if a child process has exited or received a signal
+pub fn waitpid(pid: usize, status: &mut usize, options: usize) -> Result<usize> {
+    unsafe { syscall3(SYS_WAITPID, pid, status as *mut usize as usize, options) }
+}
+
+/// Write a buffer to a file descriptor
+///
+/// The kernel will attempt to write the bytes in `buf` to the file descriptor `fd`, returning
+/// either an `Err`, explained below, or `Ok(count)` where `count` is the number of bytes which
+/// were written.
+///
+/// # Errors
+///
+/// * `EAGAIN` - the file descriptor was opened with `O_NONBLOCK` and writing would block
+/// * `EBADF` - the file descriptor is not valid or is not open for writing
+/// * `EFAULT` - `buf` does not point to the process's addressible memory
+/// * `EIO` - an I/O error occured
+/// * `ENOSPC` - the device containing the file descriptor has no room for data
+/// * `EPIPE` - the file descriptor refers to a pipe or socket whose reading end is closed
+pub fn write(fd: usize, buf: &[u8]) -> Result<usize> {
+    unsafe { syscall3(SYS_WRITE, fd, buf.as_ptr() as usize, buf.len()) }
+}
+
+/// Yield the process's time slice to the kernel
+///
+/// This function will return Ok(0) on success
+pub fn sched_yield() -> Result<usize> {
+    unsafe { syscall0(SYS_YIELD) }
+}
diff --git a/src/libstd/sys/redox/syscall/data.rs b/src/libstd/sys/redox/syscall/data.rs
new file mode 100644
index 00000000000..ac3946672a3
--- /dev/null
+++ b/src/libstd/sys/redox/syscall/data.rs
@@ -0,0 +1,86 @@
+// 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 core::ops::{Deref, DerefMut};
+use core::{mem, slice};
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(packed)]
+pub struct Stat {
+    pub st_dev: u64,
+    pub st_ino: u64,
+    pub st_mode: u16,
+    pub st_nlink: u32,
+    pub st_uid: u32,
+    pub st_gid: u32,
+    pub st_size: u64,
+    pub st_blksize: u32,
+    pub st_blocks: u64,
+    pub st_mtime: u64,
+    pub st_mtime_nsec: u32,
+    pub st_atime: u64,
+    pub st_atime_nsec: u32,
+    pub st_ctime: u64,
+    pub st_ctime_nsec: u32,
+}
+
+impl Deref for Stat {
+    type Target = [u8];
+    fn deref(&self) -> &[u8] {
+        unsafe {
+            slice::from_raw_parts(self as *const Stat as *const u8,
+                                  mem::size_of::<Stat>()) as &[u8]
+        }
+    }
+}
+
+impl DerefMut for Stat {
+    fn deref_mut(&mut self) -> &mut [u8] {
+        unsafe {
+            slice::from_raw_parts_mut(self as *mut Stat as *mut u8,
+                                      mem::size_of::<Stat>()) as &mut [u8]
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(packed)]
+pub struct StatVfs {
+    pub f_bsize: u32,
+    pub f_blocks: u64,
+    pub f_bfree: u64,
+    pub f_bavail: u64,
+}
+
+impl Deref for StatVfs {
+    type Target = [u8];
+    fn deref(&self) -> &[u8] {
+        unsafe {
+            slice::from_raw_parts(self as *const StatVfs as *const u8,
+                                  mem::size_of::<StatVfs>()) as &[u8]
+        }
+    }
+}
+
+impl DerefMut for StatVfs {
+    fn deref_mut(&mut self) -> &mut [u8] {
+        unsafe {
+            slice::from_raw_parts_mut(self as *mut StatVfs as *mut u8,
+                                      mem::size_of::<StatVfs>()) as &mut [u8]
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(packed)]
+pub struct TimeSpec {
+    pub tv_sec: i64,
+    pub tv_nsec: i32,
+}
diff --git a/src/libstd/sys/redox/syscall/error.rs b/src/libstd/sys/redox/syscall/error.rs
new file mode 100644
index 00000000000..d8d78d55016
--- /dev/null
+++ b/src/libstd/sys/redox/syscall/error.rs
@@ -0,0 +1,325 @@
+// 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 core::{fmt, result};
+
+#[derive(Eq, PartialEq)]
+pub struct Error {
+    pub errno: i32,
+}
+
+pub type Result<T> = result::Result<T, Error>;
+
+impl Error {
+    pub fn new(errno: i32) -> Error {
+        Error { errno: errno }
+    }
+
+    pub fn mux(result: Result<usize>) -> usize {
+        match result {
+            Ok(value) => value,
+            Err(error) => -error.errno as usize,
+        }
+    }
+
+    pub fn demux(value: usize) -> Result<usize> {
+        let errno = -(value as i32);
+        if errno >= 1 && errno < STR_ERROR.len() as i32 {
+            Err(Error::new(errno))
+        } else {
+            Ok(value)
+        }
+    }
+
+    pub fn text(&self) -> &str {
+        if let Some(description) = STR_ERROR.get(self.errno as usize) {
+            description
+        } else {
+            "Unknown Error"
+        }
+    }
+}
+
+impl fmt::Debug for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
+        f.write_str(self.text())
+    }
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
+        f.write_str(self.text())
+    }
+}
+
+pub const EPERM: i32 = 1;  /* Operation not permitted */
+pub const ENOENT: i32 = 2;  /* No such file or directory */
+pub const ESRCH: i32 = 3;  /* No such process */
+pub const EINTR: i32 = 4;  /* Interrupted system call */
+pub const EIO: i32 = 5;  /* I/O error */
+pub const ENXIO: i32 = 6;  /* No such device or address */
+pub const E2BIG: i32 = 7;  /* Argument list too long */
+pub const ENOEXEC: i32 = 8;  /* Exec format error */
+pub const EBADF: i32 = 9;  /* Bad file number */
+pub const ECHILD: i32 = 10;  /* No child processes */
+pub const EAGAIN: i32 = 11;  /* Try again */
+pub const ENOMEM: i32 = 12;  /* Out of memory */
+pub const EACCES: i32 = 13;  /* Permission denied */
+pub const EFAULT: i32 = 14;  /* Bad address */
+pub const ENOTBLK: i32 = 15;  /* Block device required */
+pub const EBUSY: i32 = 16;  /* Device or resource busy */
+pub const EEXIST: i32 = 17;  /* File exists */
+pub const EXDEV: i32 = 18;  /* Cross-device link */
+pub const ENODEV: i32 = 19;  /* No such device */
+pub const ENOTDIR: i32 = 20;  /* Not a directory */
+pub const EISDIR: i32 = 21;  /* Is a directory */
+pub const EINVAL: i32 = 22;  /* Invalid argument */
+pub const ENFILE: i32 = 23;  /* File table overflow */
+pub const EMFILE: i32 = 24;  /* Too many open files */
+pub const ENOTTY: i32 = 25;  /* Not a typewriter */
+pub const ETXTBSY: i32 = 26;  /* Text file busy */
+pub const EFBIG: i32 = 27;  /* File too large */
+pub const ENOSPC: i32 = 28;  /* No space left on device */
+pub const ESPIPE: i32 = 29;  /* Illegal seek */
+pub const EROFS: i32 = 30;  /* Read-only file system */
+pub const EMLINK: i32 = 31;  /* Too many links */
+pub const EPIPE: i32 = 32;  /* Broken pipe */
+pub const EDOM: i32 = 33;  /* Math argument out of domain of func */
+pub const ERANGE: i32 = 34;  /* Math result not representable */
+pub const EDEADLK: i32 = 35;  /* Resource deadlock would occur */
+pub const ENAMETOOLONG: i32 = 36;  /* File name too long */
+pub const ENOLCK: i32 = 37;  /* No record locks available */
+pub const ENOSYS: i32 = 38;  /* Function not implemented */
+pub const ENOTEMPTY: i32 = 39;  /* Directory not empty */
+pub const ELOOP: i32 = 40;  /* Too many symbolic links encountered */
+pub const EWOULDBLOCK: i32 = 41;  /* Operation would block */
+pub const ENOMSG: i32 = 42;  /* No message of desired type */
+pub const EIDRM: i32 = 43;  /* Identifier removed */
+pub const ECHRNG: i32 = 44;  /* Channel number out of range */
+pub const EL2NSYNC: i32 = 45;  /* Level 2 not synchronized */
+pub const EL3HLT: i32 = 46;  /* Level 3 halted */
+pub const EL3RST: i32 = 47;  /* Level 3 reset */
+pub const ELNRNG: i32 = 48;  /* Link number out of range */
+pub const EUNATCH: i32 = 49;  /* Protocol driver not attached */
+pub const ENOCSI: i32 = 50;  /* No CSI structure available */
+pub const EL2HLT: i32 = 51;  /* Level 2 halted */
+pub const EBADE: i32 = 52;  /* Invalid exchange */
+pub const EBADR: i32 = 53;  /* Invalid request descriptor */
+pub const EXFULL: i32 = 54;  /* Exchange full */
+pub const ENOANO: i32 = 55;  /* No anode */
+pub const EBADRQC: i32 = 56;  /* Invalid request code */
+pub const EBADSLT: i32 = 57;  /* Invalid slot */
+pub const EDEADLOCK: i32 = 58; /* Resource deadlock would occur */
+pub const EBFONT: i32 = 59;  /* Bad font file format */
+pub const ENOSTR: i32 = 60;  /* Device not a stream */
+pub const ENODATA: i32 = 61;  /* No data available */
+pub const ETIME: i32 = 62;  /* Timer expired */
+pub const ENOSR: i32 = 63;  /* Out of streams resources */
+pub const ENONET: i32 = 64;  /* Machine is not on the network */
+pub const ENOPKG: i32 = 65;  /* Package not installed */
+pub const EREMOTE: i32 = 66;  /* Object is remote */
+pub const ENOLINK: i32 = 67;  /* Link has been severed */
+pub const EADV: i32 = 68;  /* Advertise error */
+pub const ESRMNT: i32 = 69;  /* Srmount error */
+pub const ECOMM: i32 = 70;  /* Communication error on send */
+pub const EPROTO: i32 = 71;  /* Protocol error */
+pub const EMULTIHOP: i32 = 72;  /* Multihop attempted */
+pub const EDOTDOT: i32 = 73;  /* RFS specific error */
+pub const EBADMSG: i32 = 74;  /* Not a data message */
+pub const EOVERFLOW: i32 = 75;  /* Value too large for defined data type */
+pub const ENOTUNIQ: i32 = 76;  /* Name not unique on network */
+pub const EBADFD: i32 = 77;  /* File descriptor in bad state */
+pub const EREMCHG: i32 = 78;  /* Remote address changed */
+pub const ELIBACC: i32 = 79;  /* Can not access a needed shared library */
+pub const ELIBBAD: i32 = 80;  /* Accessing a corrupted shared library */
+pub const ELIBSCN: i32 = 81;  /* .lib section in a.out corrupted */
+pub const ELIBMAX: i32 = 82;  /* Attempting to link in too many shared libraries */
+pub const ELIBEXEC: i32 = 83;  /* Cannot exec a shared library directly */
+pub const EILSEQ: i32 = 84;  /* Illegal byte sequence */
+pub const ERESTART: i32 = 85;  /* Interrupted system call should be restarted */
+pub const ESTRPIPE: i32 = 86;  /* Streams pipe error */
+pub const EUSERS: i32 = 87;  /* Too many users */
+pub const ENOTSOCK: i32 = 88;  /* Socket operation on non-socket */
+pub const EDESTADDRREQ: i32 = 89;  /* Destination address required */
+pub const EMSGSIZE: i32 = 90;  /* Message too long */
+pub const EPROTOTYPE: i32 = 91;  /* Protocol wrong type for socket */
+pub const ENOPROTOOPT: i32 = 92;  /* Protocol not available */
+pub const EPROTONOSUPPORT: i32 = 93;  /* Protocol not supported */
+pub const ESOCKTNOSUPPORT: i32 = 94;  /* Socket type not supported */
+pub const EOPNOTSUPP: i32 = 95;  /* Operation not supported on transport endpoint */
+pub const EPFNOSUPPORT: i32 = 96;  /* Protocol family not supported */
+pub const EAFNOSUPPORT: i32 = 97;  /* Address family not supported by protocol */
+pub const EADDRINUSE: i32 = 98;  /* Address already in use */
+pub const EADDRNOTAVAIL: i32 = 99;  /* Cannot assign requested address */
+pub const ENETDOWN: i32 = 100; /* Network is down */
+pub const ENETUNREACH: i32 = 101; /* Network is unreachable */
+pub const ENETRESET: i32 = 102; /* Network dropped connection because of reset */
+pub const ECONNABORTED: i32 = 103; /* Software caused connection abort */
+pub const ECONNRESET: i32 = 104; /* Connection reset by peer */
+pub const ENOBUFS: i32 = 105; /* No buffer space available */
+pub const EISCONN: i32 = 106; /* Transport endpoint is already connected */
+pub const ENOTCONN: i32 = 107; /* Transport endpoint is not connected */
+pub const ESHUTDOWN: i32 = 108; /* Cannot send after transport endpoint shutdown */
+pub const ETOOMANYREFS: i32 = 109; /* Too many references: cannot splice */
+pub const ETIMEDOUT: i32 = 110; /* Connection timed out */
+pub const ECONNREFUSED: i32 = 111; /* Connection refused */
+pub const EHOSTDOWN: i32 = 112; /* Host is down */
+pub const EHOSTUNREACH: i32 = 113; /* No route to host */
+pub const EALREADY: i32 = 114; /* Operation already in progress */
+pub const EINPROGRESS: i32 = 115; /* Operation now in progress */
+pub const ESTALE: i32 = 116; /* Stale NFS file handle */
+pub const EUCLEAN: i32 = 117; /* Structure needs cleaning */
+pub const ENOTNAM: i32 = 118; /* Not a XENIX named type file */
+pub const ENAVAIL: i32 = 119; /* No XENIX semaphores available */
+pub const EISNAM: i32 = 120; /* Is a named type file */
+pub const EREMOTEIO: i32 = 121; /* Remote I/O error */
+pub const EDQUOT: i32 = 122; /* Quota exceeded */
+pub const ENOMEDIUM: i32 = 123; /* No medium found */
+pub const EMEDIUMTYPE: i32 = 124; /* Wrong medium type */
+pub const ECANCELED: i32 = 125; /* Operation Canceled */
+pub const ENOKEY: i32 = 126; /* Required key not available */
+pub const EKEYEXPIRED: i32 = 127; /* Key has expired */
+pub const EKEYREVOKED: i32 = 128; /* Key has been revoked */
+pub const EKEYREJECTED: i32 = 129; /* Key was rejected by service */
+pub const EOWNERDEAD: i32 = 130; /* Owner died */
+pub const ENOTRECOVERABLE: i32 = 131; /* State not recoverable */
+
+pub static STR_ERROR: [&'static str; 132] = ["Success",
+                                             "Operation not permitted",
+                                             "No such file or directory",
+                                             "No such process",
+                                             "Interrupted system call",
+                                             "I/O error",
+                                             "No such device or address",
+                                             "Argument list too long",
+                                             "Exec format error",
+                                             "Bad file number",
+                                             "No child processes",
+                                             "Try again",
+                                             "Out of memory",
+                                             "Permission denied",
+                                             "Bad address",
+                                             "Block device required",
+                                             "Device or resource busy",
+                                             "File exists",
+                                             "Cross-device link",
+                                             "No such device",
+                                             "Not a directory",
+                                             "Is a directory",
+                                             "Invalid argument",
+                                             "File table overflow",
+                                             "Too many open files",
+                                             "Not a typewriter",
+                                             "Text file busy",
+                                             "File too large",
+                                             "No space left on device",
+                                             "Illegal seek",
+                                             "Read-only file system",
+                                             "Too many links",
+                                             "Broken pipe",
+                                             "Math argument out of domain of func",
+                                             "Math result not representable",
+                                             "Resource deadlock would occur",
+                                             "File name too long",
+                                             "No record locks available",
+                                             "Function not implemented",
+                                             "Directory not empty",
+                                             "Too many symbolic links encountered",
+                                             "Operation would block",
+                                             "No message of desired type",
+                                             "Identifier removed",
+                                             "Channel number out of range",
+                                             "Level 2 not synchronized",
+                                             "Level 3 halted",
+                                             "Level 3 reset",
+                                             "Link number out of range",
+                                             "Protocol driver not attached",
+                                             "No CSI structure available",
+                                             "Level 2 halted",
+                                             "Invalid exchange",
+                                             "Invalid request descriptor",
+                                             "Exchange full",
+                                             "No anode",
+                                             "Invalid request code",
+                                             "Invalid slot",
+                                             "Resource deadlock would occur",
+                                             "Bad font file format",
+                                             "Device not a stream",
+                                             "No data available",
+                                             "Timer expired",
+                                             "Out of streams resources",
+                                             "Machine is not on the network",
+                                             "Package not installed",
+                                             "Object is remote",
+                                             "Link has been severed",
+                                             "Advertise error",
+                                             "Srmount error",
+                                             "Communication error on send",
+                                             "Protocol error",
+                                             "Multihop attempted",
+                                             "RFS specific error",
+                                             "Not a data message",
+                                             "Value too large for defined data type",
+                                             "Name not unique on network",
+                                             "File descriptor in bad state",
+                                             "Remote address changed",
+                                             "Can not access a needed shared library",
+                                             "Accessing a corrupted shared library",
+                                             ".lib section in a.out corrupted",
+                                             "Attempting to link in too many shared libraries",
+                                             "Cannot exec a shared library directly",
+                                             "Illegal byte sequence",
+                                             "Interrupted system call should be restarted",
+                                             "Streams pipe error",
+                                             "Too many users",
+                                             "Socket operation on non-socket",
+                                             "Destination address required",
+                                             "Message too long",
+                                             "Protocol wrong type for socket",
+                                             "Protocol not available",
+                                             "Protocol not supported",
+                                             "Socket type not supported",
+                                             "Operation not supported on transport endpoint",
+                                             "Protocol family not supported",
+                                             "Address family not supported by protocol",
+                                             "Address already in use",
+                                             "Cannot assign requested address",
+                                             "Network is down",
+                                             "Network is unreachable",
+                                             "Network dropped connection because of reset",
+                                             "Software caused connection abort",
+                                             "Connection reset by peer",
+                                             "No buffer space available",
+                                             "Transport endpoint is already connected",
+                                             "Transport endpoint is not connected",
+                                             "Cannot send after transport endpoint shutdown",
+                                             "Too many references: cannot splice",
+                                             "Connection timed out",
+                                             "Connection refused",
+                                             "Host is down",
+                                             "No route to host",
+                                             "Operation already in progress",
+                                             "Operation now in progress",
+                                             "Stale NFS file handle",
+                                             "Structure needs cleaning",
+                                             "Not a XENIX named type file",
+                                             "No XENIX semaphores available",
+                                             "Is a named type file",
+                                             "Remote I/O error",
+                                             "Quota exceeded",
+                                             "No medium found",
+                                             "Wrong medium type",
+                                             "Operation Canceled",
+                                             "Required key not available",
+                                             "Key has expired",
+                                             "Key has been revoked",
+                                             "Key was rejected by service",
+                                             "Owner died",
+                                             "State not recoverable"];
diff --git a/src/libstd/sys/redox/syscall/flag.rs b/src/libstd/sys/redox/syscall/flag.rs
new file mode 100644
index 00000000000..9f0d3e6f779
--- /dev/null
+++ b/src/libstd/sys/redox/syscall/flag.rs
@@ -0,0 +1,94 @@
+// 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.
+
+pub const CLONE_VM: usize = 0x100;
+pub const CLONE_FS: usize = 0x200;
+pub const CLONE_FILES: usize = 0x400;
+pub const CLONE_VFORK: usize = 0x4000;
+
+pub const CLOCK_REALTIME: usize = 1;
+pub const CLOCK_MONOTONIC: usize = 4;
+
+pub const EVENT_NONE: usize = 0;
+pub const EVENT_READ: usize = 1;
+pub const EVENT_WRITE: usize = 2;
+
+pub const F_GETFL: usize = 1;
+pub const F_SETFL: usize = 2;
+
+pub const FUTEX_WAIT: usize = 0;
+pub const FUTEX_WAKE: usize = 1;
+pub const FUTEX_REQUEUE: usize = 2;
+
+pub const MAP_WRITE: usize = 1;
+pub const MAP_WRITE_COMBINE: usize = 2;
+
+pub const MODE_TYPE: u16 = 0xF000;
+pub const MODE_DIR: u16 = 0x4000;
+pub const MODE_FILE: u16 = 0x8000;
+
+pub const MODE_PERM: u16 = 0x0FFF;
+pub const MODE_SETUID: u16 = 0o4000;
+pub const MODE_SETGID: u16 = 0o2000;
+
+pub const O_RDONLY: usize =     0x0001_0000;
+pub const O_WRONLY: usize =     0x0002_0000;
+pub const O_RDWR: usize =       0x0003_0000;
+pub const O_NONBLOCK: usize =   0x0004_0000;
+pub const O_APPEND: usize =     0x0008_0000;
+pub const O_SHLOCK: usize =     0x0010_0000;
+pub const O_EXLOCK: usize =     0x0020_0000;
+pub const O_ASYNC: usize =      0x0040_0000;
+pub const O_FSYNC: usize =      0x0080_0000;
+pub const O_CLOEXEC: usize =    0x0100_0000;
+pub const O_CREAT: usize =      0x0200_0000;
+pub const O_TRUNC: usize =      0x0400_0000;
+pub const O_EXCL: usize =       0x0800_0000;
+pub const O_DIRECTORY: usize =  0x1000_0000;
+pub const O_STAT: usize =       0x2000_0000;
+pub const O_ACCMODE: usize =    O_RDONLY | O_WRONLY | O_RDWR;
+
+pub const SEEK_SET: usize = 0;
+pub const SEEK_CUR: usize = 1;
+pub const SEEK_END: usize = 2;
+
+pub const SIGHUP: usize =   1;
+pub const SIGINT: usize =   2;
+pub const SIGQUIT: usize =  3;
+pub const SIGILL: usize =   4;
+pub const SIGTRAP: usize =  5;
+pub const SIGABRT: usize =  6;
+pub const SIGBUS: usize =   7;
+pub const SIGFPE: usize =   8;
+pub const SIGKILL: usize =  9;
+pub const SIGUSR1: usize =  10;
+pub const SIGSEGV: usize =  11;
+pub const SIGUSR2: usize =  12;
+pub const SIGPIPE: usize =  13;
+pub const SIGALRM: usize =  14;
+pub const SIGTERM: usize =  15;
+pub const SIGSTKFLT: usize= 16;
+pub const SIGCHLD: usize =  17;
+pub const SIGCONT: usize =  18;
+pub const SIGSTOP: usize =  19;
+pub const SIGTSTP: usize =  20;
+pub const SIGTTIN: usize =  21;
+pub const SIGTTOU: usize =  22;
+pub const SIGURG: usize =   23;
+pub const SIGXCPU: usize =  24;
+pub const SIGXFSZ: usize =  25;
+pub const SIGVTALRM: usize= 26;
+pub const SIGPROF: usize =  27;
+pub const SIGWINCH: usize = 28;
+pub const SIGIO: usize =    29;
+pub const SIGPWR: usize =   30;
+pub const SIGSYS: usize =   31;
+
+pub const WNOHANG: usize = 1;
diff --git a/src/libstd/sys/redox/syscall/mod.rs b/src/libstd/sys/redox/syscall/mod.rs
new file mode 100644
index 00000000000..ce789c269a7
--- /dev/null
+++ b/src/libstd/sys/redox/syscall/mod.rs
@@ -0,0 +1,43 @@
+// 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.
+
+pub use self::arch::*;
+pub use self::call::*;
+pub use self::data::*;
+pub use self::error::*;
+pub use self::flag::*;
+pub use self::number::*;
+
+#[cfg(target_arch = "arm")]
+#[path="arch/arm.rs"]
+mod arch;
+
+#[cfg(target_arch = "x86")]
+#[path="arch/x86.rs"]
+mod arch;
+
+#[cfg(target_arch = "x86_64")]
+#[path="arch/x86_64.rs"]
+mod arch;
+
+/// Function definitions
+pub mod call;
+
+/// Complex structures that are used for some system calls
+pub mod data;
+
+/// All errors that can be generated by a system call
+pub mod error;
+
+/// Flags used as an argument to many system calls
+pub mod flag;
+
+/// Call numbers used by each system call
+pub mod number;
diff --git a/src/libstd/sys/redox/syscall/number.rs b/src/libstd/sys/redox/syscall/number.rs
new file mode 100644
index 00000000000..358746cd20a
--- /dev/null
+++ b/src/libstd/sys/redox/syscall/number.rs
@@ -0,0 +1,73 @@
+// 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.
+
+pub const SYS_CLASS: usize =    0xF000_0000;
+pub const SYS_CLASS_PATH: usize=0x1000_0000;
+pub const SYS_CLASS_FILE: usize=0x2000_0000;
+
+pub const SYS_ARG: usize =      0x0F00_0000;
+pub const SYS_ARG_SLICE: usize =0x0100_0000;
+pub const SYS_ARG_MSLICE: usize=0x0200_0000;
+pub const SYS_ARG_PATH: usize = 0x0300_0000;
+
+pub const SYS_RET: usize =      0x00F0_0000;
+pub const SYS_RET_FILE: usize = 0x0010_0000;
+
+pub const SYS_LINK: usize =     SYS_CLASS_PATH | SYS_ARG_PATH | 9;
+pub const SYS_OPEN: usize =     SYS_CLASS_PATH | SYS_RET_FILE | 5;
+pub const SYS_CHMOD: usize =    SYS_CLASS_PATH | 15;
+pub const SYS_RMDIR: usize =    SYS_CLASS_PATH | 84;
+pub const SYS_UNLINK: usize =   SYS_CLASS_PATH | 10;
+
+pub const SYS_CLOSE: usize =    SYS_CLASS_FILE | 6;
+pub const SYS_DUP: usize =      SYS_CLASS_FILE | SYS_RET_FILE | 41;
+pub const SYS_READ: usize =     SYS_CLASS_FILE | SYS_ARG_MSLICE | 3;
+pub const SYS_WRITE: usize =    SYS_CLASS_FILE | SYS_ARG_SLICE | 4;
+pub const SYS_LSEEK: usize =    SYS_CLASS_FILE | 19;
+pub const SYS_FCNTL: usize =    SYS_CLASS_FILE | 55;
+pub const SYS_FEVENT: usize =   SYS_CLASS_FILE | 927;
+pub const SYS_FMAP: usize =     SYS_CLASS_FILE | 90;
+pub const SYS_FUNMAP: usize =   SYS_CLASS_FILE | 91;
+pub const SYS_FPATH: usize =    SYS_CLASS_FILE | SYS_ARG_MSLICE | 928;
+pub const SYS_FSTAT: usize =    SYS_CLASS_FILE | SYS_ARG_MSLICE | 28;
+pub const SYS_FSTATVFS: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 100;
+pub const SYS_FSYNC: usize =    SYS_CLASS_FILE | 118;
+pub const SYS_FTRUNCATE: usize =SYS_CLASS_FILE | 93;
+
+pub const SYS_BRK: usize =      45;
+pub const SYS_CHDIR: usize =    12;
+pub const SYS_CLOCK_GETTIME: usize = 265;
+pub const SYS_CLONE: usize =    120;
+pub const SYS_EXECVE: usize =   11;
+pub const SYS_EXIT: usize =     1;
+pub const SYS_FUTEX: usize =    240;
+pub const SYS_GETCWD: usize =   183;
+pub const SYS_GETEGID: usize =  202;
+pub const SYS_GETENS: usize =   951;
+pub const SYS_GETEUID: usize =  201;
+pub const SYS_GETGID: usize =   200;
+pub const SYS_GETNS: usize =    950;
+pub const SYS_GETPID: usize =   20;
+pub const SYS_GETUID: usize =   199;
+pub const SYS_IOPL: usize =     110;
+pub const SYS_KILL: usize =     37;
+pub const SYS_MKNS: usize =     984;
+pub const SYS_NANOSLEEP: usize =162;
+pub const SYS_PHYSALLOC: usize =945;
+pub const SYS_PHYSFREE: usize = 946;
+pub const SYS_PHYSMAP: usize =  947;
+pub const SYS_PHYSUNMAP: usize =948;
+pub const SYS_VIRTTOPHYS: usize=949;
+pub const SYS_PIPE2: usize =    331;
+pub const SYS_SETREGID: usize = 204;
+pub const SYS_SETRENS: usize =  952;
+pub const SYS_SETREUID: usize = 203;
+pub const SYS_WAITPID: usize =  7;
+pub const SYS_YIELD: usize =    158;
diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs
new file mode 100644
index 00000000000..b2c0e285f06
--- /dev/null
+++ b/src/libstd/sys/redox/thread.rs
@@ -0,0 +1,91 @@
+// 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 alloc::boxed::FnBox;
+use ffi::CStr;
+use io;
+use mem;
+use sys_common::thread::start_thread;
+use sys::{cvt, syscall};
+use time::Duration;
+
+pub struct Thread {
+    id: usize,
+}
+
+// Some platforms may have pthread_t as a pointer in which case we still want
+// a thread to be Send/Sync
+unsafe impl Send for Thread {}
+unsafe impl Sync for Thread {}
+
+impl Thread {
+    pub unsafe fn new<'a>(_stack: usize, p: Box<FnBox() + 'a>) -> io::Result<Thread> {
+        let p = box p;
+
+        let id = cvt(syscall::clone(syscall::CLONE_VM | syscall::CLONE_FS | syscall::CLONE_FILES))?;
+        if id == 0 {
+            start_thread(&*p as *const _ as *mut _);
+            let _ = syscall::exit(0);
+            panic!("thread failed to exit");
+        } else {
+            mem::forget(p);
+            Ok(Thread { id: id })
+        }
+    }
+
+    pub fn yield_now() {
+        let ret = syscall::sched_yield().expect("failed to sched_yield");
+        debug_assert_eq!(ret, 0);
+    }
+
+    pub fn set_name(_name: &CStr) {
+
+    }
+
+    pub fn sleep(dur: Duration) {
+        let mut secs = dur.as_secs();
+        let mut nsecs = dur.subsec_nanos() as i32;
+
+        // If we're awoken with a signal then the return value will be -1 and
+        // nanosleep will fill in `ts` with the remaining time.
+        while secs > 0 || nsecs > 0 {
+            let req = syscall::TimeSpec {
+                tv_sec: secs as i64,
+                tv_nsec: nsecs,
+            };
+            secs -= req.tv_sec as u64;
+            let mut rem = syscall::TimeSpec::default();
+            if syscall::nanosleep(&req, &mut rem).is_err() {
+                secs += rem.tv_sec as u64;
+                nsecs = rem.tv_nsec;
+            } else {
+                nsecs = 0;
+            }
+        }
+    }
+
+    pub fn join(self) {
+        let mut status = 0;
+        syscall::waitpid(self.id, &mut status, 0).unwrap();
+    }
+
+    pub fn id(&self) -> usize { self.id }
+
+    pub fn into_id(self) -> usize {
+        let id = self.id;
+        mem::forget(self);
+        id
+    }
+}
+
+pub mod guard {
+    pub unsafe fn current() -> Option<usize> { None }
+    pub unsafe fn init() -> Option<usize> { None }
+}
diff --git a/src/libstd/sys/redox/thread_local.rs b/src/libstd/sys/redox/thread_local.rs
new file mode 100644
index 00000000000..abdd9ace795
--- /dev/null
+++ b/src/libstd/sys/redox/thread_local.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.
+
+#![allow(dead_code)] // not used on all platforms
+
+use collections::BTreeMap;
+use ptr;
+use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+
+pub type Key = usize;
+
+type Dtor = unsafe extern fn(*mut u8);
+
+static NEXT_KEY: AtomicUsize = ATOMIC_USIZE_INIT;
+
+static mut KEYS: *mut BTreeMap<Key, Option<Dtor>> = ptr::null_mut();
+
+#[thread_local]
+static mut LOCALS: *mut BTreeMap<Key, *mut u8> = ptr::null_mut();
+
+unsafe fn keys() -> &'static mut BTreeMap<Key, Option<Dtor>> {
+    if KEYS == ptr::null_mut() {
+        KEYS = Box::into_raw(Box::new(BTreeMap::new()));
+    }
+    &mut *KEYS
+}
+
+unsafe fn locals() -> &'static mut BTreeMap<Key, *mut u8> {
+    if LOCALS == ptr::null_mut() {
+        LOCALS = Box::into_raw(Box::new(BTreeMap::new()));
+    }
+    &mut *LOCALS
+}
+
+#[inline]
+pub unsafe fn create(dtor: Option<Dtor>) -> Key {
+    let key = NEXT_KEY.fetch_add(1, Ordering::SeqCst);
+    keys().insert(key, dtor);
+    key
+}
+
+#[inline]
+pub unsafe fn get(key: Key) -> *mut u8 {
+    if let Some(&entry) = locals().get(&key) {
+        entry
+    } else {
+        ptr::null_mut()
+    }
+}
+
+#[inline]
+pub unsafe fn set(key: Key, value: *mut u8) {
+    locals().insert(key, value);
+}
+
+#[inline]
+pub unsafe fn destroy(key: Key) {
+    keys().remove(&key);
+}
diff --git a/src/libstd/sys/redox/time.rs b/src/libstd/sys/redox/time.rs
new file mode 100644
index 00000000000..dea406efe6c
--- /dev/null
+++ b/src/libstd/sys/redox/time.rs
@@ -0,0 +1,198 @@
+// 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 cmp::Ordering;
+use fmt;
+use sys::{cvt, syscall};
+use time::Duration;
+
+const NSEC_PER_SEC: u64 = 1_000_000_000;
+
+#[derive(Copy, Clone)]
+struct Timespec {
+    t: syscall::TimeSpec,
+}
+
+impl Timespec {
+    fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
+        if self >= other {
+            Ok(if self.t.tv_nsec >= other.t.tv_nsec {
+                Duration::new((self.t.tv_sec - other.t.tv_sec) as u64,
+                              (self.t.tv_nsec - other.t.tv_nsec) as u32)
+            } else {
+                Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64,
+                              self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) -
+                              other.t.tv_nsec as u32)
+            })
+        } else {
+            match other.sub_timespec(self) {
+                Ok(d) => Err(d),
+                Err(d) => Ok(d),
+            }
+        }
+    }
+
+    fn add_duration(&self, other: &Duration) -> Timespec {
+        let secs = (self.t.tv_sec as i64).checked_add(other.as_secs() as i64);
+        let mut secs = secs.expect("overflow when adding duration to time");
+
+        // Nano calculations can't overflow because nanos are <1B which fit
+        // in a u32.
+        let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
+        if nsec >= NSEC_PER_SEC as u32 {
+            nsec -= NSEC_PER_SEC as u32;
+            secs = secs.checked_add(1).expect("overflow when adding \
+                                               duration to time");
+        }
+        Timespec {
+            t: syscall::TimeSpec {
+                tv_sec: secs as i64,
+                tv_nsec: nsec as i32,
+            },
+        }
+    }
+
+    fn sub_duration(&self, other: &Duration) -> Timespec {
+        let secs = (self.t.tv_sec as i64).checked_sub(other.as_secs() as i64);
+        let mut secs = secs.expect("overflow when subtracting duration \
+                                    from time");
+
+        // Similar to above, nanos can't overflow.
+        let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
+        if nsec < 0 {
+            nsec += NSEC_PER_SEC as i32;
+            secs = secs.checked_sub(1).expect("overflow when subtracting \
+                                               duration from time");
+        }
+        Timespec {
+            t: syscall::TimeSpec {
+                tv_sec: secs as i64,
+                tv_nsec: nsec as i32,
+            },
+        }
+    }
+}
+
+impl PartialEq for Timespec {
+    fn eq(&self, other: &Timespec) -> bool {
+        self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
+    }
+}
+
+impl Eq for Timespec {}
+
+impl PartialOrd for Timespec {
+    fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for Timespec {
+    fn cmp(&self, other: &Timespec) -> Ordering {
+        let me = (self.t.tv_sec, self.t.tv_nsec);
+        let other = (other.t.tv_sec, other.t.tv_nsec);
+        me.cmp(&other)
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Instant {
+    t: Timespec,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct SystemTime {
+    t: Timespec,
+}
+
+pub const UNIX_EPOCH: SystemTime = SystemTime {
+    t: Timespec {
+        t: syscall::TimeSpec {
+            tv_sec: 0,
+            tv_nsec: 0,
+        },
+    },
+};
+
+impl Instant {
+    pub fn now() -> Instant {
+        Instant { t: now(syscall::CLOCK_MONOTONIC) }
+    }
+
+    pub fn sub_instant(&self, other: &Instant) -> Duration {
+        self.t.sub_timespec(&other.t).unwrap_or_else(|_| {
+            panic!("other was less than the current instant")
+        })
+    }
+
+    pub fn add_duration(&self, other: &Duration) -> Instant {
+        Instant { t: self.t.add_duration(other) }
+    }
+
+    pub fn sub_duration(&self, other: &Duration) -> Instant {
+        Instant { t: self.t.sub_duration(other) }
+    }
+}
+
+impl fmt::Debug for Instant {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Instant")
+         .field("tv_sec", &self.t.t.tv_sec)
+         .field("tv_nsec", &self.t.t.tv_nsec)
+         .finish()
+    }
+}
+
+impl SystemTime {
+    pub fn now() -> SystemTime {
+        SystemTime { t: now(syscall::CLOCK_REALTIME) }
+    }
+
+    pub fn sub_time(&self, other: &SystemTime)
+                    -> Result<Duration, Duration> {
+        self.t.sub_timespec(&other.t)
+    }
+
+    pub fn add_duration(&self, other: &Duration) -> SystemTime {
+        SystemTime { t: self.t.add_duration(other) }
+    }
+
+    pub fn sub_duration(&self, other: &Duration) -> SystemTime {
+        SystemTime { t: self.t.sub_duration(other) }
+    }
+}
+
+impl From<syscall::TimeSpec> for SystemTime {
+    fn from(t: syscall::TimeSpec) -> SystemTime {
+        SystemTime { t: Timespec { t: t } }
+    }
+}
+
+impl fmt::Debug for SystemTime {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("SystemTime")
+         .field("tv_sec", &self.t.t.tv_sec)
+         .field("tv_nsec", &self.t.t.tv_nsec)
+         .finish()
+    }
+}
+
+pub type clock_t = usize;
+
+fn now(clock: clock_t) -> Timespec {
+    let mut t = Timespec {
+        t: syscall::TimeSpec {
+            tv_sec: 0,
+            tv_nsec: 0,
+        }
+    };
+    cvt(syscall::clock_gettime(clock, &mut t.t)).unwrap();
+    t
+}
diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs
index fcfab051588..900f463fa83 100644
--- a/src/libstd/sys/unix/ext/fs.rs
+++ b/src/libstd/sys/unix/ext/fs.rs
@@ -21,7 +21,7 @@ use sys_common::{FromInner, AsInner, AsInnerMut};
 use sys::platform::fs::MetadataExt as UnixMetadataExt;
 
 /// Unix-specific extensions to `File`
-#[unstable(feature = "file_offset", issue = "35918")]
+#[stable(feature = "file_offset", since = "1.15.0")]
 pub trait FileExt {
     /// Reads a number of bytes starting from a given offset.
     ///
@@ -34,7 +34,7 @@ pub trait FileExt {
     ///
     /// Note that similar to `File::read`, it is not an error to return with a
     /// short read.
-    #[unstable(feature = "file_offset", issue = "35918")]
+    #[stable(feature = "file_offset", since = "1.15.0")]
     fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
 
     /// Writes a number of bytes starting from a given offset.
@@ -51,11 +51,11 @@ pub trait FileExt {
     ///
     /// Note that similar to `File::write`, it is not an error to return a
     /// short write.
-    #[unstable(feature = "file_offset", issue = "35918")]
+    #[stable(feature = "file_offset", since = "1.15.0")]
     fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
 }
 
-#[unstable(feature = "file_offset", issue = "35918")]
+#[stable(feature = "file_offset", since = "1.15.0")]
 impl FileExt for fs::File {
     fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
         self.as_inner().read_at(buf, offset)
diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs
index b2483f4e209..1be9f11b92c 100644
--- a/src/libstd/sys/unix/ext/mod.rs
+++ b/src/libstd/sys/unix/ext/mod.rs
@@ -50,7 +50,7 @@ pub mod prelude {
     pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt};
     #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
     pub use super::fs::DirEntryExt;
-    #[doc(no_inline)] #[unstable(feature = "file_offset", issue = "35918")]
+    #[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")]
     pub use super::fs::FileExt;
     #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
     pub use super::thread::JoinHandleExt;
diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs
index 80f53da1cef..1ba4a104e51 100644
--- a/src/libstd/sys/unix/ext/net.rs
+++ b/src/libstd/sys/unix/ext/net.rs
@@ -85,6 +85,21 @@ enum AddressKind<'a> {
 }
 
 /// An address associated with a Unix socket.
+///
+/// # Examples
+///
+/// ```
+/// use std::os::unix::net::UnixListener;
+///
+/// let socket = match UnixListener::bind("/tmp/sock") {
+///     Ok(sock) => sock,
+///     Err(e) => {
+///         println!("Couldn't bind: {:?}", e);
+///         return
+///     }
+/// };
+/// let addr = socket.local_addr().expect("Couldn't get local address");
+/// ```
 #[derive(Clone)]
 #[stable(feature = "unix_socket", since = "1.10.0")]
 pub struct SocketAddr {
@@ -121,6 +136,28 @@ impl SocketAddr {
     }
 
     /// Returns true if and only if the address is unnamed.
+    ///
+    /// # Examples
+    ///
+    /// A named address:
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let socket = UnixListener::bind("/tmp/sock").unwrap();
+    /// let addr = socket.local_addr().expect("Couldn't get local address");
+    /// assert_eq!(addr.is_unnamed(), false);
+    /// ```
+    ///
+    /// An unnamed address:
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let socket = UnixDatagram::unbound().unwrap();
+    /// let addr = socket.local_addr().expect("Couldn't get local address");
+    /// assert_eq!(addr.is_unnamed(), true);
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn is_unnamed(&self) -> bool {
         if let AddressKind::Unnamed = self.address() {
@@ -131,6 +168,29 @@ impl SocketAddr {
     }
 
     /// Returns the contents of this address if it is a `pathname` address.
+    ///
+    /// # Examples
+    ///
+    /// With a pathname:
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    /// use std::path::Path;
+    ///
+    /// let socket = UnixListener::bind("/tmp/sock").unwrap();
+    /// let addr = socket.local_addr().expect("Couldn't get local address");
+    /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock")));
+    /// ```
+    ///
+    /// Without a pathname:
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let socket = UnixDatagram::unbound().unwrap();
+    /// let addr = socket.local_addr().expect("Couldn't get local address");
+    /// assert_eq!(addr.as_pathname(), None);
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn as_pathname(&self) -> Option<&Path> {
         if let AddressKind::Pathname(path) = self.address() {
@@ -182,7 +242,7 @@ impl<'a> fmt::Display for AsciiEscaped<'a> {
 ///
 /// # Examples
 ///
-/// ```rust,no_run
+/// ```no_run
 /// use std::os::unix::net::UnixStream;
 /// use std::io::prelude::*;
 ///
@@ -212,6 +272,20 @@ impl fmt::Debug for UnixStream {
 
 impl UnixStream {
     /// Connects to the socket named by `path`.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = match UnixStream::connect("/tmp/sock") {
+    ///     Ok(sock) => sock,
+    ///     Err(e) => {
+    ///         println!("Couldn't connect: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
         fn inner(path: &Path) -> io::Result<UnixStream> {
@@ -229,6 +303,20 @@ impl UnixStream {
     /// Creates an unnamed pair of connected sockets.
     ///
     /// Returns two `UnixStream`s which are connected to each other.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let (sock1, sock2) = match UnixStream::pair() {
+    ///     Ok((sock1, sock2)) => (sock1, sock2),
+    ///     Err(e) => {
+    ///         println!("Couldn't create a pair of sockets: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
         let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?;
@@ -241,18 +329,45 @@ impl UnixStream {
     /// object references. Both handles will read and write the same stream of
     /// data, and options set on one stream will be propogated to the other
     /// stream.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// let sock_copy = socket.try_clone().expect("Couldn't clone socket");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn try_clone(&self) -> io::Result<UnixStream> {
         self.0.duplicate().map(UnixStream)
     }
 
     /// Returns the socket address of the local half of this connection.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// let addr = socket.local_addr().expect("Couldn't get local address");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn local_addr(&self) -> io::Result<SocketAddr> {
         SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
     }
 
     /// Returns the socket address of the remote half of this connection.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// let addr = socket.peer_addr().expect("Couldn't get peer address");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
         SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
@@ -260,9 +375,23 @@ impl UnixStream {
 
     /// Sets the read timeout for the socket.
     ///
-    /// If the provided value is `None`, then `read` calls will block
-    /// indefinitely. It is an error to pass the zero `Duration` to this
+    /// If the provided value is [`None`], then [`read()`] calls will block
+    /// indefinitely. It is an error to pass the zero [`Duration`] to this
     /// method.
+    ///
+    /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+    /// [`read()`]: ../../../../std/io/trait.Read.html#tymethod.read
+    /// [`Duration`]: ../../../../std/time/struct.Duration.html
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
         self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
@@ -270,33 +399,89 @@ impl UnixStream {
 
     /// Sets the write timeout for the socket.
     ///
-    /// If the provided value is `None`, then `write` calls will block
-    /// indefinitely. It is an error to pass the zero `Duration` to this
+    /// If the provided value is [`None`], then [`write()`] calls will block
+    /// indefinitely. It is an error to pass the zero [`Duration`] to this
     /// method.
+    ///
+    /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+    /// [`read()`]: ../../../../std/io/trait.Write.html#tymethod.write
+    /// [`Duration`]: ../../../../std/time/struct.Duration.html
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
         self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
     }
 
     /// Returns the read timeout of this socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
+    /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0)));
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
         self.0.timeout(libc::SO_RCVTIMEO)
     }
 
     /// Returns the write timeout of this socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
+    /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0)));
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
         self.0.timeout(libc::SO_SNDTIMEO)
     }
 
     /// Moves the socket into or out of nonblocking mode.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// socket.set_nonblocking(true).expect("Couldn't set nonblocking");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
         self.0.set_nonblocking(nonblocking)
     }
 
     /// Returns the value of the `SO_ERROR` option.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// if let Ok(Some(err)) = socket.take_error() {
+    ///     println!("Got error: {:?}", err);
+    /// }
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
         self.0.take_error()
@@ -306,7 +491,19 @@ impl UnixStream {
     ///
     /// This function will cause all pending and future I/O calls on the
     /// specified portions to immediately return with an appropriate value
-    /// (see the documentation of `Shutdown`).
+    /// (see the documentation of [`Shutdown`]).
+    ///
+    /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::net::Shutdown;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// socket.shutdown(Shutdown::Both).expect("shutdown function failed");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
         self.0.shutdown(how)
@@ -382,7 +579,7 @@ impl IntoRawFd for UnixStream {
 ///
 /// # Examples
 ///
-/// ```rust,no_run
+/// ```no_run
 /// use std::thread;
 /// use std::os::unix::net::{UnixStream, UnixListener};
 ///
@@ -405,9 +602,6 @@ impl IntoRawFd for UnixStream {
 ///         }
 ///     }
 /// }
-///
-/// // close the listener socket
-/// drop(listener);
 /// ```
 #[stable(feature = "unix_socket", since = "1.10.0")]
 pub struct UnixListener(Socket);
@@ -426,6 +620,20 @@ impl fmt::Debug for UnixListener {
 
 impl UnixListener {
     /// Creates a new `UnixListener` bound to the specified socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = match UnixListener::bind("/path/to/the/socket") {
+    ///     Ok(sock) => sock,
+    ///     Err(e) => {
+    ///         println!("Couldn't connect: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
         fn inner(path: &Path) -> io::Result<UnixListener> {
@@ -445,8 +653,23 @@ impl UnixListener {
     /// Accepts a new incoming connection to this listener.
     ///
     /// This function will block the calling thread until a new Unix connection
-    /// is established. When established, the corersponding `UnixStream` and
+    /// is established. When established, the corersponding [`UnixStream`] and
     /// the remote peer's address will be returned.
+    ///
+    /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+    ///
+    /// match listener.accept() {
+    ///     Ok((socket, addr)) => println!("Got a client: {:?}", addr),
+    ///     Err(e) => println!("accept function failed: {:?}", e),
+    /// }
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
         let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() };
@@ -461,24 +684,66 @@ impl UnixListener {
     /// The returned `UnixListener` is a reference to the same socket that this
     /// object references. Both handles can be used to accept incoming
     /// connections and options set on one listener will affect the other.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+    ///
+    /// let listener_copy = listener.try_clone().expect("try_clone failed");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn try_clone(&self) -> io::Result<UnixListener> {
         self.0.duplicate().map(UnixListener)
     }
 
     /// Returns the local socket address of this listener.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+    ///
+    /// let addr = listener.local_addr().expect("Couldn't get local address");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn local_addr(&self) -> io::Result<SocketAddr> {
         SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
     }
 
     /// Moves the socket into or out of nonblocking mode.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+    ///
+    /// listener.set_nonblocking(true).expect("Couldn't set non blocking");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
         self.0.set_nonblocking(nonblocking)
     }
 
     /// Returns the value of the `SO_ERROR` option.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = UnixListener::bind("/tmp/sock").unwrap();
+    ///
+    /// if let Ok(Some(err)) = listener.take_error() {
+    ///     println!("Got error: {:?}", err);
+    /// }
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
         self.0.take_error()
@@ -486,8 +751,35 @@ impl UnixListener {
 
     /// Returns an iterator over incoming connections.
     ///
-    /// The iterator will never return `None` and will also not yield the
-    /// peer's `SocketAddr` structure.
+    /// The iterator will never return [`None`] and will also not yield the
+    /// peer's [`SocketAddr`] structure.
+    ///
+    /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+    /// [`SocketAddr`]: struct.SocketAddr.html
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::thread;
+    /// use std::os::unix::net::{UnixStream, UnixListener};
+    ///
+    /// fn handle_client(stream: UnixStream) {
+    ///     // ...
+    /// }
+    ///
+    /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+    ///
+    /// for stream in listener.incoming() {
+    ///     match stream {
+    ///         Ok(stream) => {
+    ///             thread::spawn(|| handle_client(stream));
+    ///         }
+    ///         Err(err) => {
+    ///             break;
+    ///         }
+    ///     }
+    /// }
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn incoming<'a>(&'a self) -> Incoming<'a> {
         Incoming { listener: self }
@@ -525,9 +817,36 @@ impl<'a> IntoIterator for &'a UnixListener {
     }
 }
 
-/// An iterator over incoming connections to a `UnixListener`.
+/// An iterator over incoming connections to a [`UnixListener`].
+///
+/// It will never return [`None`].
+///
+/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+/// [`UnixListener`]: struct.UnixListener.html
+///
+/// # Examples
 ///
-/// It will never return `None`.
+/// ```no_run
+/// use std::thread;
+/// use std::os::unix::net::{UnixStream, UnixListener};
+///
+/// fn handle_client(stream: UnixStream) {
+///     // ...
+/// }
+///
+/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+///
+/// for stream in listener.incoming() {
+///     match stream {
+///         Ok(stream) => {
+///             thread::spawn(|| handle_client(stream));
+///         }
+///         Err(err) => {
+///             break;
+///         }
+///     }
+/// }
+/// ```
 #[derive(Debug)]
 #[stable(feature = "unix_socket", since = "1.10.0")]
 pub struct Incoming<'a> {
@@ -551,7 +870,7 @@ impl<'a> Iterator for Incoming<'a> {
 ///
 /// # Examples
 ///
-/// ```rust,no_run
+/// ```no_run
 /// use std::os::unix::net::UnixDatagram;
 ///
 /// let socket = UnixDatagram::bind("/path/to/my/socket").unwrap();
@@ -580,6 +899,20 @@ impl fmt::Debug for UnixDatagram {
 
 impl UnixDatagram {
     /// Creates a Unix datagram socket bound to the given path.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = match UnixDatagram::bind("/path/to/the/socket") {
+    ///     Ok(sock) => sock,
+    ///     Err(e) => {
+    ///         println!("Couldn't bind: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> {
         fn inner(path: &Path) -> io::Result<UnixDatagram> {
@@ -596,6 +929,20 @@ impl UnixDatagram {
     }
 
     /// Creates a Unix Datagram socket which is not bound to any address.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = match UnixDatagram::unbound() {
+    ///     Ok(sock) => sock,
+    ///     Err(e) => {
+    ///         println!("Couldn't unbound: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn unbound() -> io::Result<UnixDatagram> {
         let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?;
@@ -605,6 +952,20 @@ impl UnixDatagram {
     /// Create an unnamed pair of connected sockets.
     ///
     /// Returns two `UnixDatagrams`s which are connected to each other.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let (sock1, sock2) = match UnixDatagram::pair() {
+    ///     Ok((sock1, sock2)) => (sock1, sock2),
+    ///     Err(e) => {
+    ///         println!("Couldn't unbound: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> {
         let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?;
@@ -613,8 +974,27 @@ impl UnixDatagram {
 
     /// Connects the socket to the specified address.
     ///
-    /// The `send` method may be used to send data to the specified address.
-    /// `recv` and `recv_from` will only receive data from that address.
+    /// The [`send()`] method may be used to send data to the specified address.
+    /// [`recv()`] and [`recv_from()`] will only receive data from that address.
+    ///
+    /// [`send()`]: #method.send
+    /// [`recv()`]: #method.recv
+    /// [`recv_from()`]: #method.recv_from
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// match sock.connect("/path/to/the/socket") {
+    ///     Ok(sock) => sock,
+    ///     Err(e) => {
+    ///         println!("Couldn't connect: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn connect<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
         fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> {
@@ -631,15 +1011,35 @@ impl UnixDatagram {
 
     /// Creates a new independently owned handle to the underlying socket.
     ///
-    /// The returned `UnixListener` is a reference to the same socket that this
+    /// The returned `UnixDatagram` is a reference to the same socket that this
     /// object references. Both handles can be used to accept incoming
-    /// connections and options set on one listener will affect the other.
+    /// connections and options set on one side will affect the other.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap();
+    ///
+    /// let sock_copy = sock.try_clone().expect("try_clone failed");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn try_clone(&self) -> io::Result<UnixDatagram> {
         self.0.duplicate().map(UnixDatagram)
     }
 
     /// Returns the address of this socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap();
+    ///
+    /// let addr = sock.local_addr().expect("Couldn't get local address");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn local_addr(&self) -> io::Result<SocketAddr> {
         SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
@@ -647,7 +1047,20 @@ impl UnixDatagram {
 
     /// Returns the address of this socket's peer.
     ///
-    /// The `connect` method will connect the socket to a peer.
+    /// The [`connect()`] method will connect the socket to a peer.
+    ///
+    /// [`connect()`]: #method.connect
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// sock.connect("/path/to/the/socket").unwrap();
+    ///
+    /// let addr = sock.peer_addr().expect("Couldn't get peer address");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
         SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
@@ -657,6 +1070,19 @@ impl UnixDatagram {
     ///
     /// On success, returns the number of bytes read and the address from
     /// whence the data came.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// let mut buf = vec![0; 10];
+    /// match sock.recv_from(buf.as_mut_slice()) {
+    ///     Ok((size, sender)) => println!("received {} bytes from {:?}", size, sender),
+    ///     Err(e) => println!("recv_from function failed: {:?}", e),
+    /// }
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
         let mut count = 0;
@@ -684,6 +1110,16 @@ impl UnixDatagram {
     /// Receives data from the socket.
     ///
     /// On success, returns the number of bytes read.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap();
+    /// let mut buf = vec![0; 10];
+    /// sock.recv(buf.as_mut_slice()).expect("recv function failed");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
         self.0.read(buf)
@@ -692,6 +1128,15 @@ impl UnixDatagram {
     /// Sends data on the socket to the specified address.
     ///
     /// On success, returns the number of bytes written.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> {
         fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result<usize> {
@@ -716,6 +1161,16 @@ impl UnixDatagram {
     /// will return an error if the socket has not already been connected.
     ///
     /// On success, returns the number of bytes written.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// sock.connect("/some/sock").expect("Couldn't connect");
+    /// sock.send(b"omelette au fromage").expect("send_to function failed");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
@@ -723,9 +1178,24 @@ impl UnixDatagram {
 
     /// Sets the read timeout for the socket.
     ///
-    /// If the provided value is `None`, then `recv` and `recv_from` calls will
-    /// block indefinitely. It is an error to pass the zero `Duration` to this
+    /// If the provided value is [`None`], then [`recv()`] and [`recv_from()`] calls will
+    /// block indefinitely. It is an error to pass the zero [`Duration`] to this
     /// method.
+    ///
+    /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+    /// [`recv()`]: #method.recv
+    /// [`recv_from()`]: #method.recv_from
+    /// [`Duration`]: ../../../../std/time/struct.Duration.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::time::Duration;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
         self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
@@ -733,33 +1203,92 @@ impl UnixDatagram {
 
     /// Sets the write timeout for the socket.
     ///
-    /// If the provided value is `None`, then `send` and `send_to` calls will
-    /// block indefinitely. It is an error to pass the zero `Duration` to this
+    /// If the provided value is [`None`], then [`send()`] and [`send_to()`] calls will
+    /// block indefinitely. It is an error to pass the zero [`Duration`] to this
     /// method.
+    ///
+    /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+    /// [`send()`]: #method.send
+    /// [`send_to()`]: #method.send_to
+    /// [`Duration`]: ../../../../std/time/struct.Duration.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::time::Duration;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// sock.set_write_timeout(Some(Duration::new(1, 0)))
+    ///     .expect("set_write_timeout function failed");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
         self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
     }
 
     /// Returns the read timeout of this socket.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::time::Duration;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed");
+    /// assert_eq!(sock.read_timeout().unwrap(), Some(Duration::new(1, 0)));
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
         self.0.timeout(libc::SO_RCVTIMEO)
     }
 
     /// Returns the write timeout of this socket.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::time::Duration;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// sock.set_write_timeout(Some(Duration::new(1, 0)))
+    ///     .expect("set_write_timeout function failed");
+    /// assert_eq!(sock.write_timeout().unwrap(), Some(Duration::new(1, 0)));
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
         self.0.timeout(libc::SO_SNDTIMEO)
     }
 
     /// Moves the socket into or out of nonblocking mode.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// sock.set_nonblocking(true).expect("set_nonblocking function failed");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
         self.0.set_nonblocking(nonblocking)
     }
 
     /// Returns the value of the `SO_ERROR` option.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// if let Ok(Some(err)) = sock.take_error() {
+    ///     println!("Got error: {:?}", err);
+    /// }
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
         self.0.take_error()
@@ -769,7 +1298,17 @@ impl UnixDatagram {
     ///
     /// This function will cause all pending and future I/O calls on the
     /// specified portions to immediately return with an appropriate value
-    /// (see the documentation of `Shutdown`).
+    /// (see the documentation of [`Shutdown`]).
+    ///
+    /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::net::Shutdown;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// sock.shutdown(Shutdown::Both).expect("shutdown function failed");
+    /// ```
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
         self.0.shutdown(how)
diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs
index 3a7c59d4e6d..585dcbb9a34 100644
--- a/src/libstd/sys/unix/ext/process.rs
+++ b/src/libstd/sys/unix/ext/process.rs
@@ -56,7 +56,7 @@ pub trait CommandExt {
     /// When this closure is run, aspects such as the stdio file descriptors and
     /// working directory have successfully been changed, so output to these
     /// locations may not appear where intended.
-    #[unstable(feature = "process_exec", issue = "31398")]
+    #[stable(feature = "process_exec", since = "1.15.0")]
     fn before_exec<F>(&mut self, f: F) -> &mut process::Command
         where F: FnMut() -> io::Result<()> + Send + Sync + 'static;
 
diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs
index 0c625e7add9..f4f73646e1b 100644
--- a/src/libstd/sys/unix/fast_thread_local.rs
+++ b/src/libstd/sys/unix/fast_thread_local.rs
@@ -12,6 +12,7 @@
 #![unstable(feature = "thread_local_internals", issue = "0")]
 
 use cell::{Cell, UnsafeCell};
+use fmt;
 use intrinsics;
 use ptr;
 
@@ -24,6 +25,12 @@ pub struct Key<T> {
     dtor_running: Cell<bool>,
 }
 
+impl<T> fmt::Debug for Key<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Key { .. }")
+    }
+}
+
 unsafe impl<T> ::marker::Sync for Key<T> { }
 
 impl<T> Key<T> {
diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs
index 61eb60da486..2384d959881 100644
--- a/src/libstd/sys/unix/fd.rs
+++ b/src/libstd/sys/unix/fd.rs
@@ -18,6 +18,7 @@ use sys::cvt;
 use sys_common::AsInner;
 use sys_common::io::read_to_end_uninitialized;
 
+#[derive(Debug)]
 pub struct FileDesc {
     fd: c_int,
 }
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
index 9ee0458b5da..8b5c0c04276 100644
--- a/src/libstd/sys/unix/fs.rs
+++ b/src/libstd/sys/unix/fs.rs
@@ -66,7 +66,7 @@ pub struct DirEntry {
     name: Box<[u8]>
 }
 
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub struct OpenOptions {
     // generic
     read: bool,
@@ -86,6 +86,7 @@ pub struct FilePermissions { mode: mode_t }
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub struct FileType { mode: mode_t }
 
+#[derive(Debug)]
 pub struct DirBuilder { mode: mode_t }
 
 impl FileAttr {
diff --git a/src/libstd/sys/unix/process/magenta.rs b/src/libstd/sys/unix/process/magenta.rs
index 319fbce35cd..2bb005be4ec 100644
--- a/src/libstd/sys/unix/process/magenta.rs
+++ b/src/libstd/sys/unix/process/magenta.rs
@@ -23,7 +23,6 @@ pub type mx_rights_t = u32;
 pub type mx_status_t = i32;
 
 pub type mx_size_t = usize;
-pub type mx_ssize_t = isize;
 
 pub const MX_HANDLE_INVALID: mx_handle_t = 0;
 
diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs
index 273341b1918..6d38b00b39e 100644
--- a/src/libstd/sys/unix/stdio.rs
+++ b/src/libstd/sys/unix/stdio.rs
@@ -43,6 +43,10 @@ impl Stdout {
         fd.into_raw();
         ret
     }
+
+    pub fn flush(&self) -> io::Result<()> {
+        Ok(())
+    }
 }
 
 impl Stderr {
@@ -54,6 +58,10 @@ impl Stderr {
         fd.into_raw();
         ret
     }
+
+    pub fn flush(&self) -> io::Result<()> {
+        Ok(())
+    }
 }
 
 // FIXME: right now this raw stderr handle is used in a few places because
@@ -63,7 +71,10 @@ impl io::Write for Stderr {
     fn write(&mut self, data: &[u8]) -> io::Result<usize> {
         Stderr::write(self, data)
     }
-    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Stderr::flush(self)
+    }
 }
 
 pub const EBADF_ERR: i32 = ::libc::EBADF as i32;
diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs
index 1a563127f7f..d1c404195bc 100644
--- a/src/libstd/sys/windows/c.rs
+++ b/src/libstd/sys/windows/c.rs
@@ -47,7 +47,9 @@ pub type CHAR = c_char;
 pub type HCRYPTPROV = LONG_PTR;
 pub type ULONG_PTR = c_ulonglong;
 pub type ULONG = c_ulong;
+#[cfg(target_arch = "x86_64")]
 pub type ULONGLONG = u64;
+#[cfg(target_arch = "x86_64")]
 pub type DWORDLONG = ULONGLONG;
 
 pub type LPBOOL = *mut BOOL;
@@ -66,7 +68,6 @@ pub type LPVOID = *mut c_void;
 pub type LPWCH = *mut WCHAR;
 pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW;
 pub type LPWSADATA = *mut WSADATA;
-pub type LPWSAPROTOCOLCHAIN = *mut WSAPROTOCOLCHAIN;
 pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO;
 pub type LPWSTR = *mut WCHAR;
 pub type LPFILETIME = *mut FILETIME;
@@ -311,8 +312,6 @@ pub struct WSADATA {
     pub szSystemStatus: [u8; WSASYS_STATUS_LEN + 1],
 }
 
-pub type WSAEVENT = HANDLE;
-
 #[repr(C)]
 pub struct WSAPROTOCOL_INFO {
     pub dwServiceFlags1: DWORD,
@@ -819,6 +818,16 @@ pub enum EXCEPTION_DISPOSITION {
     ExceptionCollidedUnwind
 }
 
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct CONSOLE_READCONSOLE_CONTROL {
+    pub nLength: ULONG,
+    pub nInitialChars: ULONG,
+    pub dwCtrlWakeupMask: ULONG,
+    pub dwControlKeyState: ULONG,
+}
+pub type PCONSOLE_READCONSOLE_CONTROL = *mut CONSOLE_READCONSOLE_CONTROL;
+
 #[link(name = "ws2_32")]
 #[link(name = "userenv")]
 #[link(name = "shell32")]
@@ -849,12 +858,11 @@ extern "system" {
     pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
     pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
 
-    // FIXME - pInputControl should be PCONSOLE_READCONSOLE_CONTROL
     pub fn ReadConsoleW(hConsoleInput: HANDLE,
                         lpBuffer: LPVOID,
                         nNumberOfCharsToRead: DWORD,
                         lpNumberOfCharsRead: LPDWORD,
-                        pInputControl: LPVOID) -> BOOL;
+                        pInputControl: PCONSOLE_READCONSOLE_CONTROL) -> BOOL;
 
     pub fn WriteConsoleW(hConsoleOutput: HANDLE,
                          lpBuffer: LPCVOID,
diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs
index 1e2b8bf38fa..7fc04ad69d6 100644
--- a/src/libstd/sys/windows/ext/fs.rs
+++ b/src/libstd/sys/windows/ext/fs.rs
@@ -19,7 +19,7 @@ use sys;
 use sys_common::{AsInnerMut, AsInner};
 
 /// Windows-specific extensions to `File`
-#[unstable(feature = "file_offset", issue = "35918")]
+#[stable(feature = "file_offset", since = "1.15.0")]
 pub trait FileExt {
     /// Seeks to a given position and reads a number of bytes.
     ///
@@ -35,7 +35,7 @@ pub trait FileExt {
     /// Note that similar to `File::read`, it is not an error to return with a
     /// short read. When returning from such a short read, the file pointer is
     /// still updated.
-    #[unstable(feature = "file_offset", issue = "35918")]
+    #[stable(feature = "file_offset", since = "1.15.0")]
     fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
 
     /// Seeks to a given position and writes a number of bytes.
@@ -52,11 +52,11 @@ pub trait FileExt {
     /// Note that similar to `File::write`, it is not an error to return a
     /// short write. When returning from such a short write, the file pointer
     /// is still updated.
-    #[unstable(feature = "file_offset", issue = "35918")]
+    #[stable(feature = "file_offset", since = "1.15.0")]
     fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
 }
 
-#[unstable(feature = "file_offset", issue = "35918")]
+#[stable(feature = "file_offset", since = "1.15.0")]
 impl FileExt for fs::File {
     fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
         self.as_inner().read_at(buf, offset)
diff --git a/src/libstd/sys/windows/ext/mod.rs b/src/libstd/sys/windows/ext/mod.rs
index 932bb5e9564..f12e50cc923 100644
--- a/src/libstd/sys/windows/ext/mod.rs
+++ b/src/libstd/sys/windows/ext/mod.rs
@@ -36,6 +36,6 @@ pub mod prelude {
     pub use super::ffi::{OsStrExt, OsStringExt};
     #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
     pub use super::fs::{OpenOptionsExt, MetadataExt};
-    #[doc(no_inline)] #[unstable(feature = "file_offset", issue = "35918")]
+    #[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")]
     pub use super::fs::FileExt;
 }
diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs
index 7d7d78bbd87..c410fcd1ee0 100644
--- a/src/libstd/sys/windows/fs.rs
+++ b/src/libstd/sys/windows/fs.rs
@@ -58,7 +58,7 @@ pub struct DirEntry {
     data: c::WIN32_FIND_DATAW,
 }
 
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub struct OpenOptions {
     // generic
     read: bool,
@@ -79,6 +79,7 @@ pub struct OpenOptions {
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct FilePermissions { attrs: c::DWORD }
 
+#[derive(Debug)]
 pub struct DirBuilder;
 
 impl fmt::Debug for ReadDir {
diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs
index 72788776ded..b1a57c349fb 100644
--- a/src/libstd/sys/windows/stdio.rs
+++ b/src/libstd/sys/windows/stdio.rs
@@ -111,19 +111,27 @@ impl Stdin {
         if utf8.position() as usize == utf8.get_ref().len() {
             let mut utf16 = vec![0u16; 0x1000];
             let mut num = 0;
+            let mut input_control = readconsole_input_control(CTRL_Z_MASK);
             cvt(unsafe {
                 c::ReadConsoleW(handle,
                                 utf16.as_mut_ptr() as c::LPVOID,
                                 utf16.len() as u32,
                                 &mut num,
-                                ptr::null_mut())
+                                &mut input_control as c::PCONSOLE_READCONSOLE_CONTROL)
             })?;
             utf16.truncate(num as usize);
             // FIXME: what to do about this data that has already been read?
-            let data = match String::from_utf16(&utf16) {
+            let mut data = match String::from_utf16(&utf16) {
                 Ok(utf8) => utf8.into_bytes(),
                 Err(..) => return Err(invalid_encoding()),
             };
+            if let Output::Console(_) = self.handle {
+                if let Some(&last_byte) = data.last() {
+                    if last_byte == CTRL_Z {
+                        data.pop();
+                    }
+                }
+            }
             *utf8 = Cursor::new(data);
         }
 
@@ -156,6 +164,10 @@ impl Stdout {
     pub fn write(&self, data: &[u8]) -> io::Result<usize> {
         write(&self.0, data)
     }
+
+    pub fn flush(&self) -> io::Result<()> {
+        Ok(())
+    }
 }
 
 impl Stderr {
@@ -166,6 +178,10 @@ impl Stderr {
     pub fn write(&self, data: &[u8]) -> io::Result<usize> {
         write(&self.0, data)
     }
+
+    pub fn flush(&self) -> io::Result<()> {
+        Ok(())
+    }
 }
 
 // FIXME: right now this raw stderr handle is used in a few places because
@@ -175,7 +191,10 @@ impl io::Write for Stderr {
     fn write(&mut self, data: &[u8]) -> io::Result<usize> {
         Stderr::write(self, data)
     }
-    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Stderr::flush(self)
+    }
 }
 
 impl NoClose {
@@ -206,6 +225,18 @@ fn invalid_encoding() -> io::Error {
     io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode")
 }
 
+fn readconsole_input_control(wakeup_mask: c::ULONG) -> c::CONSOLE_READCONSOLE_CONTROL {
+    c::CONSOLE_READCONSOLE_CONTROL {
+        nLength: ::mem::size_of::<c::CONSOLE_READCONSOLE_CONTROL>() as c::ULONG,
+        nInitialChars: 0,
+        dwCtrlWakeupMask: wakeup_mask,
+        dwControlKeyState: 0,
+    }
+}
+
+const CTRL_Z: u8 = 0x1A;
+const CTRL_Z_MASK: c::ULONG = 0x4000000; //1 << 0x1A
+
 pub const EBADF_ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32;
 // The default buffer capacity is 64k, but apparently windows
 // doesn't like 64k reads on stdin. See #13304 for details, but the
diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs
index fe17d8cb5e5..634d6258885 100644
--- a/src/libstd/sys_common/mod.rs
+++ b/src/libstd/sys_common/mod.rs
@@ -23,6 +23,7 @@
 //! `std::sys` from the standard library.
 
 #![allow(missing_docs)]
+#![allow(missing_debug_implementations)]
 
 use sync::Once;
 use sys;
@@ -34,7 +35,6 @@ pub mod condvar;
 pub mod io;
 pub mod memchr;
 pub mod mutex;
-pub mod net;
 pub mod poison;
 pub mod remutex;
 pub mod rwlock;
@@ -44,6 +44,12 @@ pub mod thread_local;
 pub mod util;
 pub mod wtf8;
 
+#[cfg(target_os = "redox")]
+pub use sys::net;
+
+#[cfg(not(target_os = "redox"))]
+pub mod net;
+
 #[cfg(any(not(cargobuild), feature = "backtrace"))]
 #[cfg(any(all(unix, not(any(target_os = "macos", target_os = "ios", target_os = "emscripten"))),
           all(windows, target_env = "gnu")))]
diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs
index f74dd592495..01584979aab 100644
--- a/src/libstd/thread/local.rs
+++ b/src/libstd/thread/local.rs
@@ -13,6 +13,7 @@
 #![unstable(feature = "thread_local_internals", issue = "0")]
 
 use cell::UnsafeCell;
+use fmt;
 use mem;
 
 /// A thread local storage key which owns its contents.
@@ -98,6 +99,13 @@ pub struct LocalKey<T: 'static> {
     init: fn() -> T,
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<T: 'static> fmt::Debug for LocalKey<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("LocalKey { .. }")
+    }
+}
+
 /// Declare a new thread local storage key of type `std::thread::LocalKey`.
 ///
 /// # Syntax
@@ -184,7 +192,7 @@ macro_rules! __thread_local_inner {
 #[unstable(feature = "thread_local_state",
            reason = "state querying was recently added",
            issue = "27716")]
-#[derive(Eq, PartialEq, Copy, Clone)]
+#[derive(Debug, Eq, PartialEq, Copy, Clone)]
 pub enum LocalKeyState {
     /// All keys are in this state whenever a thread starts. Keys will
     /// transition to the `Valid` state once the first call to `with` happens
@@ -313,6 +321,7 @@ impl<T: 'static> LocalKey<T> {
 #[doc(hidden)]
 pub mod os {
     use cell::{Cell, UnsafeCell};
+    use fmt;
     use marker;
     use ptr;
     use sys_common::thread_local::StaticKey as OsStaticKey;
@@ -323,6 +332,13 @@ pub mod os {
         marker: marker::PhantomData<Cell<T>>,
     }
 
+    #[stable(feature = "std_debug", since = "1.15.0")]
+    impl<T> fmt::Debug for Key<T> {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            f.pad("Key { .. }")
+        }
+    }
+
     unsafe impl<T> ::marker::Sync for Key<T> { }
 
     struct Value<T: 'static> {
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index 255cd2a9bc0..6d8b3cc93d9 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -17,13 +17,11 @@
 //! provide some built-in support for low-level synchronization.
 //!
 //! Communication between threads can be done through
-//! [channels](../../std/sync/mpsc/index.html), Rust's message-passing
-//! types, along with [other forms of thread
+//! [channels], Rust's message-passing types, along with [other forms of thread
 //! synchronization](../../std/sync/index.html) and shared-memory data
 //! structures. In particular, types that are guaranteed to be
 //! threadsafe are easily shared between threads using the
-//! atomically-reference-counted container,
-//! [`Arc`](../../std/sync/struct.Arc.html).
+//! atomically-reference-counted container, [`Arc`].
 //!
 //! Fatal logic errors in Rust cause *thread panic*, during which
 //! a thread will unwind the stack, running destructors and freeing
@@ -40,7 +38,7 @@
 //!
 //! ## Spawning a thread
 //!
-//! A new thread can be spawned using the `thread::spawn` function:
+//! A new thread can be spawned using the [`thread::spawn`][`spawn`] function:
 //!
 //! ```rust
 //! use std::thread;
@@ -55,7 +53,7 @@
 //! it), unless this parent is the main thread.
 //!
 //! The parent thread can also wait on the completion of the child
-//! thread; a call to `spawn` produces a `JoinHandle`, which provides
+//! thread; a call to [`spawn`] produces a [`JoinHandle`], which provides
 //! a `join` method for waiting:
 //!
 //! ```rust
@@ -68,13 +66,13 @@
 //! let res = child.join();
 //! ```
 //!
-//! The `join` method returns a `Result` containing `Ok` of the final
-//! value produced by the child thread, or `Err` of the value given to
-//! a call to `panic!` if the child panicked.
+//! The [`join`] method returns a [`Result`] containing [`Ok`] of the final
+//! value produced by the child thread, or [`Err`] of the value given to
+//! a call to [`panic!`] if the child panicked.
 //!
 //! ## Configuring threads
 //!
-//! A new thread can be configured before it is spawned via the `Builder` type,
+//! A new thread can be configured before it is spawned via the [`Builder`] type,
 //! which currently allows you to set the name and stack size for the child thread:
 //!
 //! ```rust
@@ -88,43 +86,43 @@
 //!
 //! ## The `Thread` type
 //!
-//! Threads are represented via the `Thread` type, which you can get in one of
+//! Threads are represented via the [`Thread`] type, which you can get in one of
 //! two ways:
 //!
-//! * By spawning a new thread, e.g. using the `thread::spawn` function, and
-//!   calling `thread()` on the `JoinHandle`.
-//! * By requesting the current thread, using the `thread::current` function.
+//! * By spawning a new thread, e.g. using the [`thread::spawn`][`spawn`]
+//!   function, and calling [`thread()`] on the [`JoinHandle`].
+//! * By requesting the current thread, using the [`thread::current()`] function.
 //!
-//! The `thread::current()` function is available even for threads not spawned
+//! The [`thread::current()`] function is available even for threads not spawned
 //! by the APIs of this module.
 //!
 //! ## Blocking support: park and unpark
 //!
 //! Every thread is equipped with some basic low-level blocking support, via the
-//! `thread::park()` function and `thread::Thread::unpark()` method. `park()`
-//! blocks the current thread, which can then be resumed from another thread by
-//! calling the `unpark()` method on the blocked thread's handle.
+//! [`thread::park()`][`park()`] function and [`thread::Thread::unpark()`][`unpark()`]
+//! method. [`park()`] blocks the current thread, which can then be resumed from
+//! another thread by calling the [`unpark()`] method on the blocked thread's handle.
 //!
-//! Conceptually, each `Thread` handle has an associated token, which is
+//! Conceptually, each [`Thread`] handle has an associated token, which is
 //! initially not present:
 //!
-//! * The `thread::park()` function blocks the current thread unless or until
+//! * The [`thread::park()`][`park()`] function blocks the current thread unless or until
 //!   the token is available for its thread handle, at which point it atomically
 //!   consumes the token. It may also return *spuriously*, without consuming the
-//!   token. `thread::park_timeout()` does the same, but allows specifying a
+//!   token. [`thread::park_timeout()`] does the same, but allows specifying a
 //!   maximum time to block the thread for.
 //!
-//! * The `unpark()` method on a `Thread` atomically makes the token available
+//! * The [`unpark()`] method on a [`Thread`] atomically makes the token available
 //!   if it wasn't already.
 //!
-//! In other words, each `Thread` acts a bit like a semaphore with initial count
+//! In other words, each [`Thread`] acts a bit like a semaphore with initial count
 //! 0, except that the semaphore is *saturating* (the count cannot go above 1),
 //! and can return spuriously.
 //!
 //! The API is typically used by acquiring a handle to the current thread,
 //! placing that handle in a shared data structure so that other threads can
 //! find it, and then `park`ing. When some desired condition is met, another
-//! thread calls `unpark` on the handle.
+//! thread calls [`unpark()`] on the handle.
 //!
 //! The motivation for this design is twofold:
 //!
@@ -149,6 +147,22 @@
 //! will want to make use of some form of **interior mutability** through the
 //! [`Cell`] or [`RefCell`] types.
 //!
+//! [channels]: ../../std/sync/mpsc/index.html
+//! [`Arc`]: ../../std/sync/struct.Arc.html
+//! [`spawn`]: ../../std/thread/fn.spawn.html
+//! [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html
+//! [`thread()`]: ../../std/thread/struct.JoinHandle.html#method.thread
+//! [`join`]: ../../std/thread/struct.JoinHandle.html#method.join
+//! [`Result`]: ../../std/result/enum.Result.html
+//! [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
+//! [`Err`]: ../../std/result/enum.Result.html#variant.Err
+//! [`panic!`]: ../../std/macro.panic.html
+//! [`Builder`]: ../../std/thread/struct.Builder.html
+//! [`thread::current()`]: ../../std/thread/fn.spawn.html
+//! [`Thread`]: ../../std/thread/struct.Thread.html
+//! [`park()`]: ../../std/thread/fn.park.html
+//! [`unpark()`]: ../../std/thread/struct.Thread.html#method.unpark
+//! [`thread::park_timeout()`]: ../../std/thread/fn.park_timeout.html
 //! [`Cell`]: ../cell/struct.Cell.html
 //! [`RefCell`]: ../cell/struct.RefCell.html
 //! [`thread_local!`]: ../macro.thread_local.html
@@ -203,6 +217,7 @@ pub use self::local::{LocalKey, LocalKeyState};
 /// Thread configuration. Provides detailed control over the properties
 /// and behavior of new threads.
 #[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug)]
 pub struct Builder {
     // A name for the thread-to-be, for identification in panic messages
     name: Option<String>,
@@ -303,20 +318,38 @@ impl Builder {
 // Free functions
 ////////////////////////////////////////////////////////////////////////////////
 
-/// Spawns a new thread, returning a `JoinHandle` for it.
+/// Spawns a new thread, returning a [`JoinHandle`] for it.
 ///
 /// The join handle will implicitly *detach* the child thread upon being
 /// dropped. In this case, the child thread may outlive the parent (unless
 /// the parent thread is the main thread; the whole process is terminated when
-/// the main thread finishes.) Additionally, the join handle provides a `join`
+/// the main thread finishes). Additionally, the join handle provides a [`join`]
 /// method that can be used to join the child thread. If the child thread
-/// panics, `join` will return an `Err` containing the argument given to
-/// `panic`.
+/// panics, [`join`] will return an [`Err`] containing the argument given to
+/// [`panic`].
 ///
 /// # Panics
 ///
-/// Panics if the OS fails to create a thread; use `Builder::spawn`
+/// Panics if the OS fails to create a thread; use [`Builder::spawn`]
 /// to recover from such errors.
+///
+/// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html
+/// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join
+/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+/// [`panic!`]: ../../std/macro.panic.html
+/// [`Builder::spawn`]: ../../std/thread/struct.Builder.html#method.spawn
+///
+/// # Examples
+///
+/// ```
+/// use std::thread;
+///
+/// let handler = thread::spawn(|| {
+///     // thread code
+/// });
+///
+/// handler.join().unwrap();
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn spawn<F, T>(f: F) -> JoinHandle<T> where
     F: FnOnce() -> T, F: Send + 'static, T: Send + 'static
@@ -326,7 +359,7 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T> where
 
 /// Gets a handle to the thread that invokes it.
 ///
-/// #Examples
+/// # Examples
 ///
 /// Getting a handle to the current thread with `thread::current()`:
 ///
@@ -351,6 +384,14 @@ pub fn current() -> Thread {
 }
 
 /// Cooperatively gives up a timeslice to the OS scheduler.
+///
+/// # Examples
+///
+/// ```
+/// use std::thread;
+///
+/// thread::yield_now();
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn yield_now() {
     imp::Thread::yield_now()
@@ -360,7 +401,7 @@ pub fn yield_now() {
 ///
 /// # Examples
 ///
-/// ```rust,should_panic
+/// ```should_panic
 /// use std::thread;
 ///
 /// struct SomeStruct;
@@ -398,6 +439,15 @@ pub fn panicking() -> bool {
 /// specifics or platform-dependent functionality. Note that on unix platforms
 /// this function will not return early due to a signal being received or a
 /// spurious wakeup.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+///
+/// // Let's sleep for 2 seconds:
+/// thread::sleep_ms(2000);
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::sleep`")]
 pub fn sleep_ms(ms: u32) {
@@ -418,7 +468,7 @@ pub fn sleep_ms(ms: u32) {
 ///
 /// # Examples
 ///
-/// ```rust,no_run
+/// ```no_run
 /// use std::{thread, time};
 ///
 /// let ten_millis = time::Duration::from_millis(10);
@@ -573,6 +623,13 @@ impl ThreadId {
     }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl fmt::Debug for ThreadId {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("ThreadId { .. }")
+    }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Thread
 ////////////////////////////////////////////////////////////////////////////////
@@ -727,7 +784,7 @@ impl<T> JoinInner<T> {
 ///
 /// A `JoinHandle` *detaches* the child thread when it is dropped.
 ///
-/// Due to platform restrictions, it is not possible to `Clone` this
+/// Due to platform restrictions, it is not possible to [`Clone`] this
 /// handle: the ability to join a child thread is a uniquely-owned
 /// permission.
 ///
@@ -738,7 +795,7 @@ impl<T> JoinInner<T> {
 ///
 /// Creation from [`thread::spawn`]:
 ///
-/// ```rust
+/// ```
 /// use std::thread;
 ///
 /// let join_handle: thread::JoinHandle<_> = thread::spawn(|| {
@@ -748,7 +805,7 @@ impl<T> JoinInner<T> {
 ///
 /// Creation from [`thread::Builder::spawn`]:
 ///
-/// ```rust
+/// ```
 /// use std::thread;
 ///
 /// let builder = thread::Builder::new();
@@ -758,13 +815,31 @@ impl<T> JoinInner<T> {
 /// }).unwrap();
 /// ```
 ///
+/// [`Clone`]: ../../std/clone/trait.Clone.html
 /// [`thread::spawn`]: fn.spawn.html
 /// [`thread::Builder::spawn`]: struct.Builder.html#method.spawn
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct JoinHandle<T>(JoinInner<T>);
 
 impl<T> JoinHandle<T> {
-    /// Extracts a handle to the underlying thread
+    /// Extracts a handle to the underlying thread.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(thread_id)]
+    ///
+    /// use std::thread;
+    ///
+    /// let builder = thread::Builder::new();
+    ///
+    /// let join_handle: thread::JoinHandle<_> = builder.spawn(|| {
+    ///     // some work here
+    /// }).unwrap();
+    ///
+    /// let thread = join_handle.thread();
+    /// println!("thread id: {:?}", thread.id());
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn thread(&self) -> &Thread {
         &self.0.thread
@@ -772,8 +847,24 @@ impl<T> JoinHandle<T> {
 
     /// Waits for the associated thread to finish.
     ///
-    /// If the child thread panics, `Err` is returned with the parameter given
-    /// to `panic`.
+    /// If the child thread panics, [`Err`] is returned with the parameter given
+    /// to [`panic`].
+    ///
+    /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+    /// [`panic!`]: ../../std/macro.panic.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::thread;
+    ///
+    /// let builder = thread::Builder::new();
+    ///
+    /// let join_handle: thread::JoinHandle<_> = builder.spawn(|| {
+    ///     // some work here
+    /// }).unwrap();
+    /// join_handle.join().expect("Couldn't join on the associated thread");
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn join(mut self) -> Result<T> {
         self.0.join()
@@ -788,6 +879,13 @@ impl<T> IntoInner<imp::Thread> for JoinHandle<T> {
     fn into_inner(self) -> imp::Thread { self.0.native.unwrap() }
 }
 
+#[stable(feature = "std_debug", since = "1.15.0")]
+impl<T> fmt::Debug for JoinHandle<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("JoinHandle { .. }")
+    }
+}
+
 fn _assert_sync_and_send() {
     fn _assert_both<T: Send + Sync>() {}
     _assert_both::<JoinHandle<()>>();
diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs
index 41d675b6f88..162ce530f17 100644
--- a/src/libstd/time/duration.rs
+++ b/src/libstd/time/duration.rs
@@ -14,16 +14,19 @@ const NANOS_PER_SEC: u32 = 1_000_000_000;
 const NANOS_PER_MILLI: u32 = 1_000_000;
 const MILLIS_PER_SEC: u64 = 1_000;
 
-/// A duration type to represent a span of time, typically used for system
+/// A `Duration` type to represent a span of time, typically used for system
 /// timeouts.
 ///
-/// Each duration is composed of a number of seconds and nanosecond precision.
+/// Each `Duration` is composed of a number of seconds and nanosecond precision.
 /// APIs binding a system timeout will typically round up the nanosecond
 /// precision if the underlying system does not support that level of precision.
 ///
-/// Durations implement many common traits, including `Add`, `Sub`, and other
-/// ops traits. Currently a duration may only be inspected for its number of
-/// seconds and its nanosecond precision.
+/// `Duration`s implement many common traits, including [`Add`], [`Sub`], and other
+/// [`ops`] traits.
+///
+/// [`Add`]: ../../std/ops/trait.Add.html
+/// [`Sub`]: ../../std/ops/trait.Sub.html
+/// [`ops`]: ../../std/ops/index.html
 ///
 /// # Examples
 ///
@@ -56,6 +59,14 @@ impl Duration {
     ///
     /// This constructor will panic if the carry from the nanoseconds overflows
     /// the seconds counter.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::time::Duration;
+    ///
+    /// let five_seconds = Duration::new(5, 0);
+    /// ```
     #[stable(feature = "duration", since = "1.3.0")]
     #[inline]
     pub fn new(secs: u64, nanos: u32) -> Duration {
@@ -66,6 +77,14 @@ impl Duration {
     }
 
     /// Creates a new `Duration` from the specified number of seconds.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::time::Duration;
+    ///
+    /// let five_seconds = Duration::from_secs(5);
+    /// ```
     #[stable(feature = "duration", since = "1.3.0")]
     #[inline]
     pub fn from_secs(secs: u64) -> Duration {
@@ -73,6 +92,14 @@ impl Duration {
     }
 
     /// Creates a new `Duration` from the specified number of milliseconds.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::time::Duration;
+    ///
+    /// let five_seconds = Duration::from_millis(5000);
+    /// ```
     #[stable(feature = "duration", since = "1.3.0")]
     #[inline]
     pub fn from_millis(millis: u64) -> Duration {
@@ -81,26 +108,46 @@ impl Duration {
         Duration { secs: secs, nanos: nanos }
     }
 
-    /// Returns the number of whole seconds represented by this duration.
+    /// Returns the number of whole seconds represented by this `Duration`.
     ///
     /// The extra precision represented by this duration is ignored (i.e. extra
     /// nanoseconds are not represented in the returned value).
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::time::Duration;
+    ///
+    /// let five_seconds = Duration::new(5, 0);
+    /// assert_eq!(five_seconds.as_secs(), 5);
+    /// ```
     #[stable(feature = "duration", since = "1.3.0")]
     #[inline]
     pub fn as_secs(&self) -> u64 { self.secs }
 
-    /// Returns the nanosecond precision represented by this duration.
+    /// Returns the nanosecond precision represented by this `Duration`.
     ///
     /// This method does **not** return the length of the duration when
     /// represented by nanoseconds. The returned number always represents a
     /// fractional portion of a second (i.e. it is less than one billion).
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::time::Duration;
+    ///
+    /// let duration = Duration::from_millis(5010);
+    /// assert_eq!(duration.subsec_nanos(), 10000000);
+    /// ```
     #[stable(feature = "duration", since = "1.3.0")]
     #[inline]
     pub fn subsec_nanos(&self) -> u32 { self.nanos }
 
-    /// Checked duration addition. Computes `self + other`, returning `None`
+    /// Checked `Duration` addition. Computes `self + other`, returning [`None`]
     /// if overflow occurred.
     ///
+    /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -136,9 +183,11 @@ impl Duration {
         }
     }
 
-    /// Checked duration subtraction. Computes `self + other`, returning `None`
+    /// Checked `Duration` subtraction. Computes `self - other`, returning [`None`]
     /// if the result would be negative or if underflow occurred.
     ///
+    /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -172,8 +221,10 @@ impl Duration {
         }
     }
 
-    /// Checked duration multiplication. Computes `self * other`, returning
-    /// `None` if underflow or overflow occurred.
+    /// Checked `Duration` multiplication. Computes `self * other`, returning
+    /// [`None`] if overflow occurred.
+    ///
+    /// [`None`]: ../../std/option/enum.Option.html#variant.None
     ///
     /// # Examples
     ///
@@ -207,8 +258,10 @@ impl Duration {
         }
     }
 
-    /// Checked duration division. Computes `self / other`, returning `None`
-    /// if `other == 0` or the operation results in underflow or overflow.
+    /// Checked `Duration` division. Computes `self / other`, returning [`None`]
+    /// if `other == 0`.
+    ///
+    /// [`None`]: ../../std/option/enum.Option.html#variant.None
     ///
     /// # Examples
     ///
diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs
index 94599216db6..53dafadb5d5 100644
--- a/src/libstd_unicode/char.rs
+++ b/src/libstd_unicode/char.rs
@@ -448,8 +448,6 @@ impl char {
     /// In both of these examples, 'ß' takes two bytes to encode.
     ///
     /// ```
-    /// #![feature(unicode)]
-    ///
     /// let mut b = [0; 2];
     ///
     /// let result = 'ß'.encode_utf8(&mut b);
@@ -462,7 +460,6 @@ impl char {
     /// A buffer that's too small:
     ///
     /// ```
-    /// #![feature(unicode)]
     /// use std::thread;
     ///
     /// let result = thread::spawn(|| {
@@ -474,9 +471,7 @@ impl char {
     ///
     /// assert!(result.is_err());
     /// ```
-    #[unstable(feature = "unicode",
-               reason = "pending decision about Iterator/Writer/Reader",
-               issue = "27784")]
+    #[stable(feature = "unicode_encode_char", since = "1.15.0")]
     #[inline]
     pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str {
         C::encode_utf8(self, dst)
@@ -495,8 +490,6 @@ impl char {
     /// In both of these examples, '𝕊' takes two `u16`s to encode.
     ///
     /// ```
-    /// #![feature(unicode)]
-    ///
     /// let mut b = [0; 2];
     ///
     /// let result = '𝕊'.encode_utf16(&mut b);
@@ -507,7 +500,6 @@ impl char {
     /// A buffer that's too small:
     ///
     /// ```
-    /// #![feature(unicode)]
     /// use std::thread;
     ///
     /// let result = thread::spawn(|| {
@@ -519,9 +511,7 @@ impl char {
     ///
     /// assert!(result.is_err());
     /// ```
-    #[unstable(feature = "unicode",
-               reason = "pending decision about Iterator/Writer/Reader",
-               issue = "27784")]
+    #[stable(feature = "unicode_encode_char", since = "1.15.0")]
     #[inline]
     pub fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] {
         C::encode_utf16(self, dst)
diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs
index b086658ee0d..11724e74cda 100644
--- a/src/libstd_unicode/lib.rs
+++ b/src/libstd_unicode/lib.rs
@@ -39,7 +39,6 @@
 #![feature(lang_items)]
 #![feature(staged_api)]
 #![feature(try_from)]
-#![feature(unicode)]
 
 mod tables;
 mod u_str;
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 2a911aceb9d..a5abdd922d6 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -47,10 +47,14 @@ impl Ident {
         Ident { name: name, ctxt: SyntaxContext::empty() }
     }
 
-   /// Maps a string to an identifier with an empty syntax context.
-   pub fn from_str(s: &str) -> Ident {
-       Ident::with_empty_ctxt(Symbol::intern(s))
-   }
+    /// Maps a string to an identifier with an empty syntax context.
+    pub fn from_str(s: &str) -> Ident {
+        Ident::with_empty_ctxt(Symbol::intern(s))
+    }
+
+    pub fn unhygienize(&self) -> Ident {
+        Ident { name: self.name, ctxt: SyntaxContext::empty() }
+    }
 }
 
 impl fmt::Debug for Ident {
@@ -107,10 +111,8 @@ pub struct LifetimeDef {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
 pub struct Path {
     pub span: Span,
-    /// A `::foo` path, is relative to the crate root rather than current
-    /// module (like paths in an import).
-    pub global: bool,
     /// The segments in the path: the things separated by `::`.
+    /// Global paths begin with `keywords::CrateRoot`.
     pub segments: Vec<PathSegment>,
 }
 
@@ -132,14 +134,21 @@ impl Path {
     pub fn from_ident(s: Span, identifier: Ident) -> Path {
         Path {
             span: s,
-            global: false,
-            segments: vec![
-                PathSegment {
-                    identifier: identifier,
-                    parameters: PathParameters::none()
-                }
-            ],
+            segments: vec![identifier.into()],
+        }
+    }
+
+    pub fn default_to_global(mut self) -> Path {
+        let name = self.segments[0].identifier.name;
+        if !self.is_global() && name != "$crate" &&
+           name != keywords::SelfValue.name() && name != keywords::Super.name() {
+            self.segments.insert(0, PathSegment::crate_root());
         }
+        self
+    }
+
+    pub fn is_global(&self) -> bool {
+        !self.segments.is_empty() && self.segments[0].identifier.name == keywords::CrateRoot.name()
     }
 }
 
@@ -156,7 +165,24 @@ pub struct PathSegment {
     /// this is more than just simple syntactic sugar; the use of
     /// parens affects the region binding rules, so we preserve the
     /// distinction.
-    pub parameters: PathParameters,
+    /// The `Option<P<..>>` wrapper is purely a size optimization;
+    /// `None` is used to represent both `Path` and `Path<>`.
+    pub parameters: Option<P<PathParameters>>,
+}
+
+impl From<Ident> for PathSegment {
+    fn from(id: Ident) -> Self {
+        PathSegment { identifier: id, parameters: None }
+    }
+}
+
+impl PathSegment {
+    pub fn crate_root() -> Self {
+        PathSegment {
+            identifier: keywords::CrateRoot.ident(),
+            parameters: None,
+        }
+    }
 }
 
 /// Parameters of a path segment.
@@ -170,79 +196,8 @@ pub enum PathParameters {
     Parenthesized(ParenthesizedParameterData),
 }
 
-impl PathParameters {
-    pub fn none() -> PathParameters {
-        PathParameters::AngleBracketed(AngleBracketedParameterData {
-            lifetimes: Vec::new(),
-            types: P::new(),
-            bindings: P::new(),
-        })
-    }
-
-    pub fn is_empty(&self) -> bool {
-        match *self {
-            PathParameters::AngleBracketed(ref data) => data.is_empty(),
-
-            // Even if the user supplied no types, something like
-            // `X()` is equivalent to `X<(),()>`.
-            PathParameters::Parenthesized(..) => false,
-        }
-    }
-
-    pub fn has_lifetimes(&self) -> bool {
-        match *self {
-            PathParameters::AngleBracketed(ref data) => !data.lifetimes.is_empty(),
-            PathParameters::Parenthesized(_) => false,
-        }
-    }
-
-    pub fn has_types(&self) -> bool {
-        match *self {
-            PathParameters::AngleBracketed(ref data) => !data.types.is_empty(),
-            PathParameters::Parenthesized(..) => true,
-        }
-    }
-
-    /// Returns the types that the user wrote. Note that these do not necessarily map to the type
-    /// parameters in the parenthesized case.
-    pub fn types(&self) -> Vec<&P<Ty>> {
-        match *self {
-            PathParameters::AngleBracketed(ref data) => {
-                data.types.iter().collect()
-            }
-            PathParameters::Parenthesized(ref data) => {
-                data.inputs.iter()
-                    .chain(data.output.iter())
-                    .collect()
-            }
-        }
-    }
-
-    pub fn lifetimes(&self) -> Vec<&Lifetime> {
-        match *self {
-            PathParameters::AngleBracketed(ref data) => {
-                data.lifetimes.iter().collect()
-            }
-            PathParameters::Parenthesized(_) => {
-                Vec::new()
-            }
-        }
-    }
-
-    pub fn bindings(&self) -> Vec<&TypeBinding> {
-        match *self {
-            PathParameters::AngleBracketed(ref data) => {
-                data.bindings.iter().collect()
-            }
-            PathParameters::Parenthesized(_) => {
-                Vec::new()
-            }
-        }
-    }
-}
-
 /// A path like `Foo<'a, T>`
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Default)]
 pub struct AngleBracketedParameterData {
     /// The lifetime parameters for this path segment.
     pub lifetimes: Vec<Lifetime>,
@@ -254,9 +209,10 @@ pub struct AngleBracketedParameterData {
     pub bindings: P<[TypeBinding]>,
 }
 
-impl AngleBracketedParameterData {
-    fn is_empty(&self) -> bool {
-        self.lifetimes.is_empty() && self.types.is_empty() && self.bindings.is_empty()
+impl Into<Option<P<PathParameters>>> for AngleBracketedParameterData {
+    fn into(self) -> Option<P<PathParameters>> {
+        let empty = self.lifetimes.is_empty() && self.types.is_empty() && self.bindings.is_empty();
+        if empty { None } else { Some(P(PathParameters::AngleBracketed(self))) }
     }
 }
 
@@ -1822,10 +1778,6 @@ impl VariantData {
     }
 }
 
-/*
-  FIXME (#3300): Should allow items to be anonymous. Right now
-  we just use dummy names for anon items.
- */
 /// An item
 ///
 /// The name might be a dummy name in case of anonymous items
@@ -1968,8 +1920,6 @@ pub struct MacroDef {
     pub attrs: Vec<Attribute>,
     pub id: NodeId,
     pub span: Span,
-    pub imported_from: Option<Ident>,
-    pub allow_internal_unstable: bool,
     pub body: Vec<TokenTree>,
 }
 
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 45c120e0b95..c31bcfbd869 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -29,7 +29,6 @@ use symbol::Symbol;
 use util::ThinVec;
 
 use std::cell::{RefCell, Cell};
-use std::collections::HashSet;
 
 thread_local! {
     static USED_ATTRS: RefCell<Vec<u64>> = RefCell::new(Vec::new());
@@ -372,16 +371,6 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute
     }
 }
 
-pub fn mk_doc_attr_outer(id: AttrId, item: MetaItem, is_sugared_doc: bool) -> Attribute {
-    Attribute {
-        id: id,
-        style: ast::AttrStyle::Outer,
-        value: item,
-        is_sugared_doc: is_sugared_doc,
-        span: DUMMY_SP,
-    }
-}
-
 pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, lo: BytePos, hi: BytePos)
                            -> Attribute {
     let style = doc_comment_style(&text.as_str());
@@ -421,13 +410,6 @@ pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str) -> Option<S
         .and_then(|at| at.value_str())
 }
 
-pub fn last_meta_item_value_str_by_name(items: &[MetaItem], name: &str) -> Option<Symbol> {
-    items.iter()
-         .rev()
-         .find(|mi| mi.check_name(name))
-         .and_then(|i| i.value_str())
-}
-
 /* Higher-level applications */
 
 pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
@@ -856,18 +838,6 @@ pub fn find_deprecation(diagnostic: &Handler, attrs: &[Attribute],
     find_deprecation_generic(diagnostic, attrs.iter(), item_sp)
 }
 
-pub fn require_unique_names(diagnostic: &Handler, metas: &[MetaItem]) {
-    let mut set = HashSet::new();
-    for meta in metas {
-        let name = meta.name();
-
-        if !set.insert(name.clone()) {
-            panic!(diagnostic.span_fatal(meta.span,
-                                         &format!("duplicate meta item `{}`", name)));
-        }
-    }
-}
-
 
 /// Parse #[repr(...)] forms.
 ///
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index ddbca47429d..68d261c64f8 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -217,8 +217,7 @@ pub trait IdentMacroExpander {
                    cx: &'cx mut ExtCtxt,
                    sp: Span,
                    ident: ast::Ident,
-                   token_tree: Vec<tokenstream::TokenTree>,
-                   attrs: Vec<ast::Attribute>)
+                   token_tree: Vec<tokenstream::TokenTree>)
                    -> Box<MacResult+'cx>;
 }
 
@@ -234,8 +233,7 @@ impl<F> IdentMacroExpander for F
                    cx: &'cx mut ExtCtxt,
                    sp: Span,
                    ident: ast::Ident,
-                   token_tree: Vec<tokenstream::TokenTree>,
-                   _attrs: Vec<ast::Attribute>)
+                   token_tree: Vec<tokenstream::TokenTree>)
                    -> Box<MacResult+'cx>
     {
         (*self)(cx, sp, ident, token_tree)
@@ -518,9 +516,9 @@ pub trait Resolver {
     fn next_node_id(&mut self) -> ast::NodeId;
     fn get_module_scope(&mut self, id: ast::NodeId) -> Mark;
     fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item>;
+    fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool;
 
     fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion);
-    fn add_macro(&mut self, scope: Mark, def: ast::MacroDef, export: bool);
     fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>);
     fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
 
@@ -542,9 +540,9 @@ impl Resolver for DummyResolver {
     fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID }
     fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() }
     fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> { item }
+    fn is_whitelisted_legacy_custom_derive(&self, _name: Name) -> bool { false }
 
     fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {}
-    fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef, _export: bool) {}
     fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
     fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {}
 
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index a208b934d79..7584fa3916d 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -11,7 +11,7 @@
 use abi::Abi;
 use ast::{self, Ident, Generics, Expr, BlockCheckMode, UnOp, PatKind};
 use attr;
-use syntax_pos::{Span, DUMMY_SP, Pos};
+use syntax_pos::{Span, DUMMY_SP};
 use codemap::{dummy_spanned, respan, Spanned};
 use ext::base::ExtCtxt;
 use ptr::P;
@@ -322,24 +322,24 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
                 bindings: Vec<ast::TypeBinding> )
                 -> ast::Path {
         let last_identifier = idents.pop().unwrap();
-        let mut segments: Vec<ast::PathSegment> = idents.into_iter()
-                                                      .map(|ident| {
-            ast::PathSegment {
-                identifier: ident,
-                parameters: ast::PathParameters::none(),
-            }
-        }).collect();
-        segments.push(ast::PathSegment {
-            identifier: last_identifier,
-            parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData {
+        let mut segments: Vec<ast::PathSegment> = Vec::new();
+        if global {
+            segments.push(ast::PathSegment::crate_root());
+        }
+
+        segments.extend(idents.into_iter().map(Into::into));
+        let parameters = if lifetimes.is_empty() && types.is_empty() && bindings.is_empty() {
+            None
+        } else {
+            Some(P(ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData {
                 lifetimes: lifetimes,
                 types: P::from_vec(types),
                 bindings: P::from_vec(bindings),
-            })
-        });
+            })))
+        };
+        segments.push(ast::PathSegment { identifier: last_identifier, parameters: parameters });
         ast::Path {
             span: sp,
-            global: global,
             segments: segments,
         }
     }
@@ -367,13 +367,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
                  bindings: Vec<ast::TypeBinding>)
                  -> (ast::QSelf, ast::Path) {
         let mut path = trait_path;
+        let parameters = ast::AngleBracketedParameterData {
+            lifetimes: lifetimes,
+            types: P::from_vec(types),
+            bindings: P::from_vec(bindings),
+        };
         path.segments.push(ast::PathSegment {
             identifier: ident,
-            parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData {
-                lifetimes: lifetimes,
-                types: P::from_vec(types),
-                bindings: P::from_vec(bindings),
-            })
+            parameters: Some(P(ast::PathParameters::AngleBracketed(parameters))),
         });
 
         (ast::QSelf {
@@ -659,23 +660,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     }
 
     fn expr_field_access(&self, sp: Span, expr: P<ast::Expr>, ident: ast::Ident) -> P<ast::Expr> {
-        let field_span = Span {
-            lo: sp.lo - Pos::from_usize(ident.name.as_str().len()),
-            hi: sp.hi,
-            expn_id: sp.expn_id,
-        };
-
-        let id = Spanned { node: ident, span: field_span };
+        let id = Spanned { node: ident, span: sp };
         self.expr(sp, ast::ExprKind::Field(expr, id))
     }
     fn expr_tup_field_access(&self, sp: Span, expr: P<ast::Expr>, idx: usize) -> P<ast::Expr> {
-        let field_span = Span {
-            lo: sp.lo - Pos::from_usize(idx.to_string().len()),
-            hi: sp.hi,
-            expn_id: sp.expn_id,
-        };
-
-        let id = Spanned { node: idx, span: field_span };
+        let id = Spanned { node: idx, span: sp };
         self.expr(sp, ast::ExprKind::TupField(expr, id))
     }
     fn expr_addr_of(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> {
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index e3979926680..5d62175fbf2 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -158,7 +158,6 @@ pub struct Invocation {
 
 pub enum InvocationKind {
     Bang {
-        attrs: Vec<ast::Attribute>,
         mac: ast::Mac,
         ident: Option<Ident>,
         span: Span,
@@ -276,7 +275,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             if expansions.len() < depth {
                 expansions.push(Vec::new());
             }
-            expansions[depth - 1].push((mark.as_u32(), expansion));
+            expansions[depth - 1].push((mark, expansion));
             if !self.cx.ecfg.single_step {
                 invocations.extend(new_invocations.into_iter().rev());
             }
@@ -287,7 +286,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
         while let Some(expansions) = expansions.pop() {
             for (mark, expansion) in expansions.into_iter().rev() {
-                placeholder_expander.add(ast::NodeId::from_u32(mark), expansion);
+                placeholder_expander.add(mark.as_placeholder_id(), expansion);
             }
         }
 
@@ -386,20 +385,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     /// Expand a macro invocation. Returns the result of expansion.
     fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
         let (mark, kind) = (invoc.expansion_data.mark, invoc.expansion_kind);
-        let (attrs, mac, ident, span) = match invoc.kind {
-            InvocationKind::Bang { attrs, mac, ident, span } => (attrs, mac, ident, span),
+        let (mac, ident, span) = match invoc.kind {
+            InvocationKind::Bang { mac, ident, span } => (mac, ident, span),
             _ => unreachable!(),
         };
         let Mac_ { path, tts, .. } = mac.node;
 
-        // Detect use of feature-gated or invalid attributes on macro invoations
-        // since they will not be detected after macro expansion.
-        for attr in attrs.iter() {
-            feature_gate::check_attribute(&attr, &self.cx.parse_sess,
-                                          &self.cx.parse_sess.codemap(),
-                                          &self.cx.ecfg.features.unwrap());
-        }
-
         let extname = path.segments.last().unwrap().identifier.name;
         let ident = ident.unwrap_or(keywords::Invalid.ident());
         let marked_tts = mark_tts(&tts, mark);
@@ -440,7 +431,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     }
                 });
 
-                kind.make_from(expander.expand(self.cx, span, ident, marked_tts, attrs))
+                kind.make_from(expander.expand(self.cx, span, ident, marked_tts))
             }
 
             MultiDecorator(..) | MultiModifier(..) | SyntaxExtension::AttrProcMacro(..) => {
@@ -595,13 +586,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                 ..self.cx.current_expansion.clone()
             },
         });
-        placeholder(expansion_kind, ast::NodeId::from_u32(mark.as_u32()))
+        placeholder(expansion_kind, mark.as_placeholder_id())
     }
 
-    fn collect_bang(
-        &mut self, mac: ast::Mac, attrs: Vec<ast::Attribute>, span: Span, kind: ExpansionKind,
-    ) -> Expansion {
-        self.collect(kind, InvocationKind::Bang { attrs: attrs, mac: mac, ident: None, span: span })
+    fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: ExpansionKind) -> Expansion {
+        self.collect(kind, InvocationKind::Bang { mac: mac, ident: None, span: span })
     }
 
     fn collect_attr(&mut self, attr: ast::Attribute, item: Annotatable, kind: ExpansionKind)
@@ -622,6 +611,16 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
     fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
         self.cfg.configure(node)
     }
+
+    // Detect use of feature-gated or invalid attributes on macro invocations
+    // since they will not be detected after macro expansion.
+    fn check_attributes(&mut self, attrs: &[ast::Attribute]) {
+        let codemap = &self.cx.parse_sess.codemap();
+        let features = self.cx.ecfg.features.unwrap();
+        for attr in attrs.iter() {
+            feature_gate::check_attribute(&attr, &self.cx.parse_sess, codemap, features);
+        }
+    }
 }
 
 // These are pretty nasty. Ideally, we would keep the tokens around, linked from
@@ -650,7 +649,7 @@ fn string_to_tts(text: String, parse_sess: &ParseSess) -> Vec<TokenTree> {
                             .new_filemap(String::from("<macro expansion>"), None, text);
 
     let lexer = lexer::StringReader::new(&parse_sess.span_diagnostic, filemap);
-    let mut parser = Parser::new(parse_sess, Box::new(lexer));
+    let mut parser = Parser::new(parse_sess, Box::new(lexer), None, false);
     panictry!(parser.parse_all_token_trees())
 }
 
@@ -660,7 +659,8 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
         expr.node = self.cfg.configure_expr_kind(expr.node);
 
         if let ast::ExprKind::Mac(mac) = expr.node {
-            self.collect_bang(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr).make_expr()
+            self.check_attributes(&expr.attrs);
+            self.collect_bang(mac, expr.span, ExpansionKind::Expr).make_expr()
         } else {
             P(noop_fold_expr(expr, self))
         }
@@ -671,8 +671,8 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
         expr.node = self.cfg.configure_expr_kind(expr.node);
 
         if let ast::ExprKind::Mac(mac) = expr.node {
-            self.collect_bang(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr)
-                .make_opt_expr()
+            self.check_attributes(&expr.attrs);
+            self.collect_bang(mac, expr.span, ExpansionKind::OptExpr).make_opt_expr()
         } else {
             Some(P(noop_fold_expr(expr, self)))
         }
@@ -685,8 +685,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
         }
 
         pat.and_then(|pat| match pat.node {
-            PatKind::Mac(mac) =>
-                self.collect_bang(mac, Vec::new(), pat.span, ExpansionKind::Pat).make_pat(),
+            PatKind::Mac(mac) => self.collect_bang(mac, pat.span, ExpansionKind::Pat).make_pat(),
             _ => unreachable!(),
         })
     }
@@ -707,8 +706,8 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
             }).collect()
         };
 
-        let mut placeholder =
-            self.collect_bang(mac, attrs.into(), stmt.span, ExpansionKind::Stmts).make_stmts();
+        self.check_attributes(&attrs);
+        let mut placeholder = self.collect_bang(mac, stmt.span, ExpansionKind::Stmts).make_stmts();
 
         // If this is a macro invocation with a semicolon, then apply that
         // semicolon to the final statement produced by expansion.
@@ -740,18 +739,21 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
 
         match item.node {
             ast::ItemKind::Mac(..) => {
-                if match item.node {
-                    ItemKind::Mac(ref mac) => mac.node.path.segments.is_empty(),
-                    _ => unreachable!(),
-                } {
-                    return SmallVector::one(item);
-                }
+                self.check_attributes(&item.attrs);
+                let is_macro_def = if let ItemKind::Mac(ref mac) = item.node {
+                    mac.node.path.segments[0].identifier.name == "macro_rules"
+                } else {
+                    unreachable!()
+                };
 
-                item.and_then(|item| match item.node {
+                item.and_then(|mut item| match item.node {
+                    ItemKind::Mac(_) if is_macro_def => {
+                        item.id = Mark::fresh().as_placeholder_id();
+                        SmallVector::one(P(item))
+                    }
                     ItemKind::Mac(mac) => {
                         self.collect(ExpansionKind::Items, InvocationKind::Bang {
                             mac: mac,
-                            attrs: item.attrs,
                             ident: Some(item.ident),
                             span: item.span,
                         }).make_items()
@@ -823,7 +825,8 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
         match item.node {
             ast::TraitItemKind::Macro(mac) => {
                 let ast::TraitItem { attrs, span, .. } = item;
-                self.collect_bang(mac, attrs, span, ExpansionKind::TraitItems).make_trait_items()
+                self.check_attributes(&attrs);
+                self.collect_bang(mac, span, ExpansionKind::TraitItems).make_trait_items()
             }
             _ => fold::noop_fold_trait_item(item, self),
         }
@@ -841,7 +844,8 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
         match item.node {
             ast::ImplItemKind::Macro(mac) => {
                 let ast::ImplItem { attrs, span, .. } = item;
-                self.collect_bang(mac, attrs, span, ExpansionKind::ImplItems).make_impl_items()
+                self.check_attributes(&attrs);
+                self.collect_bang(mac, span, ExpansionKind::ImplItems).make_impl_items()
             }
             _ => fold::noop_fold_impl_item(item, self),
         }
@@ -854,8 +858,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
         };
 
         match ty.node {
-            ast::TyKind::Mac(mac) =>
-                self.collect_bang(mac, Vec::new(), ty.span, ExpansionKind::Ty).make_ty(),
+            ast::TyKind::Mac(mac) => self.collect_bang(mac, ty.span, ExpansionKind::Ty).make_ty(),
             _ => unreachable!(),
         }
     }
diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs
index 0fd72277cca..2af5c2ea999 100644
--- a/src/libsyntax/ext/hygiene.rs
+++ b/src/libsyntax/ext/hygiene.rs
@@ -51,7 +51,11 @@ impl Mark {
         Mark(id.as_u32())
     }
 
-    pub fn as_u32(&self) -> u32 {
+    pub fn as_placeholder_id(self) -> NodeId {
+        NodeId::from_u32(self.0)
+    }
+
+    pub fn as_u32(self) -> u32 {
         self.0
     }
 }
@@ -115,12 +119,12 @@ impl SyntaxContext {
         })
     }
 
-   /// If `ident` is macro expanded, return the source ident from the macro definition
-   /// and the mark of the expansion that created the macro definition.
-   pub fn source(self) -> (Self /* source context */, Mark /* source macro */) {
-        let macro_def_ctxt = self.data().prev_ctxt.data();
-        (macro_def_ctxt.prev_ctxt, macro_def_ctxt.outer_mark)
-   }
+    /// If `ident` is macro expanded, return the source ident from the macro definition
+    /// and the mark of the expansion that created the macro definition.
+    pub fn source(self) -> (Self /* source context */, Mark /* source macro */) {
+         let macro_def_ctxt = self.data().prev_ctxt.data();
+         (macro_def_ctxt.prev_ctxt, macro_def_ctxt.outer_mark)
+    }
 }
 
 impl fmt::Debug for SyntaxContext {
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs
index 4fe57a8345e..66555d7d95d 100644
--- a/src/libsyntax/ext/placeholders.rs
+++ b/src/libsyntax/ext/placeholders.rs
@@ -12,9 +12,10 @@ use ast;
 use codemap::{DUMMY_SP, dummy_spanned};
 use ext::base::ExtCtxt;
 use ext::expand::{Expansion, ExpansionKind};
+use ext::hygiene::Mark;
 use fold::*;
 use ptr::P;
-use symbol::{Symbol, keywords};
+use symbol::keywords;
 use util::move_map::MoveMap;
 use util::small_vector::SmallVector;
 
@@ -24,7 +25,7 @@ use std::mem;
 pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion {
     fn mac_placeholder() -> ast::Mac {
         dummy_spanned(ast::Mac_ {
-            path: ast::Path { span: DUMMY_SP, global: false, segments: Vec::new() },
+            path: ast::Path { span: DUMMY_SP, segments: Vec::new() },
             tts: Vec::new(),
         })
     }
@@ -68,10 +69,6 @@ pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion {
     }
 }
 
-pub fn macro_scope_placeholder() -> Expansion {
-    placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID)
-}
-
 pub struct PlaceholderExpander<'a, 'b: 'a> {
     expansions: HashMap<ast::NodeId, Expansion>,
     cx: &'a mut ExtCtxt<'b>,
@@ -100,11 +97,12 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
 impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
     fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
         match item.node {
-            // Scope placeholder
-            ast::ItemKind::Mac(_) if item.id == ast::DUMMY_NODE_ID => SmallVector::one(item),
-            ast::ItemKind::Mac(_) => self.remove(item.id).make_items(),
-            _ => noop_fold_item(item, self),
+            ast::ItemKind::Mac(ref mac) if !mac.node.path.segments.is_empty() => {}
+            ast::ItemKind::Mac(_) => return self.remove(item.id).make_items(),
+            _ => {}
         }
+
+        noop_fold_item(item, self)
     }
 
     fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector<ast::TraitItem> {
@@ -172,10 +170,10 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
             block.stmts = block.stmts.move_flat_map(|mut stmt| {
                 remaining_stmts -= 1;
 
-                // Scope placeholder
+                // `macro_rules!` macro definition
                 if let ast::StmtKind::Item(ref item) = stmt.node {
-                    if let ast::ItemKind::Mac(..) = item.node {
-                        macros.push(item.ident.ctxt.data().outer_mark);
+                    if let ast::ItemKind::Mac(_) = item.node {
+                        macros.push(Mark::from_placeholder_id(item.id));
                         return None;
                     }
                 }
@@ -208,33 +206,13 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
     fn fold_mod(&mut self, module: ast::Mod) -> ast::Mod {
         let mut module = noop_fold_mod(module, self);
         module.items = module.items.move_flat_map(|item| match item.node {
-            ast::ItemKind::Mac(_) => None, // remove scope placeholders from modules
+            ast::ItemKind::Mac(_) if !self.cx.ecfg.keep_macs => None, // remove macro definitions
             _ => Some(item),
         });
         module
     }
-}
 
-pub fn reconstructed_macro_rules(def: &ast::MacroDef) -> Expansion {
-    Expansion::Items(SmallVector::one(P(ast::Item {
-        ident: def.ident,
-        attrs: def.attrs.clone(),
-        id: ast::DUMMY_NODE_ID,
-        node: ast::ItemKind::Mac(ast::Mac {
-            span: def.span,
-            node: ast::Mac_ {
-                path: ast::Path {
-                    span: DUMMY_SP,
-                    global: false,
-                    segments: vec![ast::PathSegment {
-                        identifier: ast::Ident::with_empty_ctxt(Symbol::intern("macro_rules")),
-                        parameters: ast::PathParameters::none(),
-                    }],
-                },
-                tts: def.body.clone(),
-            }
-        }),
-        vis: ast::Visibility::Inherited,
-        span: def.span,
-    })))
+    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
+        mac
+    }
 }
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index 39ffab4dc17..2de31166070 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -83,7 +83,7 @@ use syntax_pos::{self, BytePos, mk_sp, Span};
 use codemap::Spanned;
 use errors::FatalError;
 use parse::lexer::*; //resolve bug?
-use parse::ParseSess;
+use parse::{Directory, ParseSess};
 use parse::parser::{PathStyle, Parser};
 use parse::token::{DocComment, MatchNt, SubstNt};
 use parse::token::{Token, Nonterminal};
@@ -407,8 +407,9 @@ fn inner_parse_loop(cur_eis: &mut SmallVector<Box<MatcherPos>>,
     Success(())
 }
 
-pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseResult {
-    let mut parser = Parser::new_with_doc_flag(sess, Box::new(rdr), true);
+pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree], directory: Option<Directory>)
+             -> NamedParseResult {
+    let mut parser = Parser::new(sess, Box::new(rdr), directory, true);
     let mut cur_eis = SmallVector::one(initial_matcher_pos(ms.to_owned(), parser.span.lo));
     let mut next_eis = Vec::new(); // or proceed normally
 
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 4164b4a93ec..3abd24b50ba 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -10,14 +10,13 @@
 
 use {ast, attr};
 use syntax_pos::{Span, DUMMY_SP};
-use ext::base::{DummyResult, ExtCtxt, MacEager, MacResult, SyntaxExtension};
-use ext::base::{IdentMacroExpander, NormalTT, TTMacroExpander};
+use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension};
+use ext::base::{NormalTT, TTMacroExpander};
 use ext::expand::{Expansion, ExpansionKind};
-use ext::placeholders;
 use ext::tt::macro_parser::{Success, Error, Failure};
 use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
 use ext::tt::macro_parser::{parse, parse_failure_msg};
-use parse::ParseSess;
+use parse::{Directory, ParseSess};
 use parse::lexer::new_tt_reader;
 use parse::parser::Parser;
 use parse::token::{self, NtTT, Token};
@@ -116,12 +115,13 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                 // rhs has holes ( `$id` and `$(...)` that need filled)
                 let trncbr =
                     new_tt_reader(&cx.parse_sess.span_diagnostic, Some(named_matches), rhs);
-                let mut p = Parser::new(cx.parse_sess(), Box::new(trncbr));
-                let module = &cx.current_expansion.module;
-                p.directory.path = module.directory.clone();
-                p.directory.ownership = cx.current_expansion.directory_ownership;
-                p.root_module_name =
-                    module.mod_path.last().map(|id| (*id.name.as_str()).to_owned());
+                let directory = Directory {
+                    path: cx.current_expansion.module.directory.clone(),
+                    ownership: cx.current_expansion.directory_ownership,
+                };
+                let mut p = Parser::new(cx.parse_sess(), Box::new(trncbr), Some(directory), false);
+                p.root_module_name = cx.current_expansion.module.mod_path.last()
+                    .map(|id| (*id.name.as_str()).to_owned());
 
                 p.check_unknown_macro_variable();
                 // Let the context choose how to interpret the result.
@@ -150,38 +150,6 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
     cx.span_fatal(best_fail_spot.substitute_dummy(sp), &best_fail_msg);
 }
 
-pub struct MacroRulesExpander;
-impl IdentMacroExpander for MacroRulesExpander {
-    fn expand(&self,
-              cx: &mut ExtCtxt,
-              span: Span,
-              ident: ast::Ident,
-              tts: Vec<tokenstream::TokenTree>,
-              attrs: Vec<ast::Attribute>)
-              -> Box<MacResult> {
-        let export = attr::contains_name(&attrs, "macro_export");
-        let def = ast::MacroDef {
-            ident: ident,
-            id: ast::DUMMY_NODE_ID,
-            span: span,
-            imported_from: None,
-            body: tts,
-            allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
-            attrs: attrs,
-        };
-
-        // If keep_macs is true, expands to a MacEager::items instead.
-        let result = if cx.ecfg.keep_macs {
-            MacEager::items(placeholders::reconstructed_macro_rules(&def).make_items())
-        } else {
-            MacEager::items(placeholders::macro_scope_placeholder().make_items())
-        };
-
-        cx.resolver.add_macro(cx.current_expansion.mark, def, export);
-        result
-    }
-}
-
 // Note that macro-by-example's input is also matched against a token tree:
 //                   $( $lhs:tt => $rhs:tt );+
 //
@@ -222,7 +190,7 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
     // Parse the macro_rules! invocation (`none` is for no interpolations):
     let arg_reader = new_tt_reader(&sess.span_diagnostic, None, def.body.clone());
 
-    let argument_map = match parse(sess, arg_reader, &argument_gram) {
+    let argument_map = match parse(sess, arg_reader, &argument_gram, None) {
         Success(m) => m,
         Failure(sp, tok) => {
             let s = parse_failure_msg(tok);
@@ -281,7 +249,7 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
         valid: valid,
     });
 
-    NormalTT(exp, Some(def.span), def.allow_internal_unstable)
+    NormalTT(exp, Some(def.span), attr::contains_name(&def.attrs, "allow_internal_unstable"))
 }
 
 fn check_lhs_nt_follows(sess: &ParseSess, lhs: &TokenTree) -> bool {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 77c53542dcb..e04cc11f15e 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -304,6 +304,7 @@ declare_features! (
     // Allows using `Self` and associated types in struct expressions and patterns.
     (active, more_struct_aliases, "1.14.0", Some(37544)),
 
+
     // Allows #[link(..., cfg(..))]
     (active, link_cfg, "1.14.0", Some(37406)),
 
@@ -314,6 +315,9 @@ declare_features! (
 
     // Allows #[target_feature(...)]
     (active, target_feature, "1.15.0", None),
+
+    // Allow safe suggestions for potential type conversions.
+    (active, safe_suggestion, "1.0.0", Some(37384)),
 );
 
 declare_features! (
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 6af8efb2a19..9797e0003fc 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -302,23 +302,22 @@ pub fn noop_fold_view_path<T: Folder>(view_path: P<ViewPath>, fld: &mut T) -> P<
     view_path.map(|Spanned {node, span}| Spanned {
         node: match node {
             ViewPathSimple(ident, path) => {
-                ViewPathSimple(ident, fld.fold_path(path))
+                ViewPathSimple(fld.fold_ident(ident), fld.fold_path(path))
             }
             ViewPathGlob(path) => {
                 ViewPathGlob(fld.fold_path(path))
             }
             ViewPathList(path, path_list_idents) => {
-                ViewPathList(fld.fold_path(path),
-                             path_list_idents.move_map(|path_list_ident| {
-                                Spanned {
-                                    node: PathListItem_ {
-                                        id: fld.new_id(path_list_ident.node.id),
-                                        rename: path_list_ident.node.rename,
-                                        name: path_list_ident.node.name,
-                                    },
-                                    span: fld.new_span(path_list_ident.span)
-                                }
-                             }))
+                let path = fld.fold_path(path);
+                let path_list_idents = path_list_idents.move_map(|path_list_ident| Spanned {
+                    node: PathListItem_ {
+                        id: fld.new_id(path_list_ident.node.id),
+                        rename: path_list_ident.node.rename.map(|ident| fld.fold_ident(ident)),
+                        name: fld.fold_ident(path_list_ident.node.name),
+                    },
+                    span: fld.new_span(path_list_ident.span)
+                });
+                ViewPathList(path, path_list_idents)
             }
         },
         span: fld.new_span(span)
@@ -345,7 +344,7 @@ pub fn noop_fold_arm<T: Folder>(Arm {attrs, pats, guard, body}: Arm, fld: &mut T
 pub fn noop_fold_ty_binding<T: Folder>(b: TypeBinding, fld: &mut T) -> TypeBinding {
     TypeBinding {
         id: fld.new_id(b.id),
-        ident: b.ident,
+        ident: fld.fold_ident(b.ident),
         ty: fld.fold_ty(b.ty),
         span: fld.new_span(b.span),
     }
@@ -433,12 +432,11 @@ pub fn noop_fold_usize<T: Folder>(i: usize, _: &mut T) -> usize {
     i
 }
 
-pub fn noop_fold_path<T: Folder>(Path {global, segments, span}: Path, fld: &mut T) -> Path {
+pub fn noop_fold_path<T: Folder>(Path { segments, span }: Path, fld: &mut T) -> Path {
     Path {
-        global: global,
         segments: segments.move_map(|PathSegment {identifier, parameters}| PathSegment {
             identifier: fld.fold_ident(identifier),
-            parameters: fld.fold_path_parameters(parameters),
+            parameters: parameters.map(|ps| ps.map(|ps| fld.fold_path_parameters(ps))),
         }),
         span: fld.new_span(span)
     }
@@ -673,7 +671,7 @@ pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam {
             .collect::<Vec<_>>()
             .into(),
         id: fld.new_id(id),
-        ident: ident,
+        ident: fld.fold_ident(ident),
         bounds: fld.fold_bounds(bounds),
         default: default.map(|x| fld.fold_ty(x)),
         span: span
@@ -1088,7 +1086,7 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
                 let fs = fields.move_map(|f| {
                     Spanned { span: folder.new_span(f.span),
                               node: ast::FieldPat {
-                                  ident: f.node.ident,
+                                  ident: folder.fold_ident(f.node.ident),
                                   pat: folder.fold_pat(f.node.pat),
                                   is_shorthand: f.node.is_shorthand,
                               }}
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index e5b66f88958..24178e1f675 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -222,14 +222,14 @@ pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>)
     // it appears to me that the cfg doesn't matter here... indeed,
     // parsing tt's probably shouldn't require a parser at all.
     let srdr = lexer::StringReader::new(&sess.span_diagnostic, filemap);
-    let mut p1 = Parser::new(sess, Box::new(srdr));
+    let mut p1 = Parser::new(sess, Box::new(srdr), None, false);
     panictry!(p1.parse_all_token_trees())
 }
 
 /// Given tts and the ParseSess, produce a parser
 pub fn tts_to_parser<'a>(sess: &'a ParseSess, tts: Vec<tokenstream::TokenTree>) -> Parser<'a> {
     let trdr = lexer::new_tt_reader(&sess.span_diagnostic, None, tts);
-    let mut p = Parser::new(sess, Box::new(trdr));
+    let mut p = Parser::new(sess, Box::new(trdr), None, false);
     p.check_unknown_macro_variable();
     p
 }
@@ -633,13 +633,7 @@ mod tests {
                     id: ast::DUMMY_NODE_ID,
                     node: ast::ExprKind::Path(None, ast::Path {
                         span: sp(0, 1),
-                        global: false,
-                        segments: vec![
-                            ast::PathSegment {
-                                identifier: Ident::from_str("a"),
-                                parameters: ast::PathParameters::none(),
-                            }
-                        ],
+                        segments: vec![Ident::from_str("a").into()],
                     }),
                     span: sp(0, 1),
                     attrs: ThinVec::new(),
@@ -651,19 +645,11 @@ mod tests {
                    P(ast::Expr {
                     id: ast::DUMMY_NODE_ID,
                     node: ast::ExprKind::Path(None, ast::Path {
-                            span: sp(0, 6),
-                            global: true,
-                            segments: vec![
-                                ast::PathSegment {
-                                    identifier: Ident::from_str("a"),
-                                    parameters: ast::PathParameters::none(),
-                                },
-                                ast::PathSegment {
-                                    identifier: Ident::from_str("b"),
-                                    parameters: ast::PathParameters::none(),
-                                }
-                            ]
-                        }),
+                        span: sp(0, 6),
+                        segments: vec![ast::PathSegment::crate_root(),
+                                       Ident::from_str("a").into(),
+                                       Ident::from_str("b").into()]
+                    }),
                     span: sp(0, 6),
                     attrs: ThinVec::new(),
                    }))
@@ -771,13 +757,7 @@ mod tests {
                         id: ast::DUMMY_NODE_ID,
                         node:ast::ExprKind::Path(None, ast::Path{
                             span: sp(7, 8),
-                            global: false,
-                            segments: vec![
-                                ast::PathSegment {
-                                    identifier: Ident::from_str("d"),
-                                    parameters: ast::PathParameters::none(),
-                                }
-                            ],
+                            segments: vec![Ident::from_str("d").into()],
                         }),
                         span:sp(7,8),
                         attrs: ThinVec::new(),
@@ -794,13 +774,7 @@ mod tests {
                            id: ast::DUMMY_NODE_ID,
                            node: ast::ExprKind::Path(None, ast::Path {
                                span:sp(0,1),
-                               global:false,
-                               segments: vec![
-                                ast::PathSegment {
-                                    identifier: Ident::from_str("b"),
-                                    parameters: ast::PathParameters::none(),
-                                }
-                               ],
+                               segments: vec![Ident::from_str("b").into()],
                             }),
                            span: sp(0,1),
                            attrs: ThinVec::new()})),
@@ -841,13 +815,7 @@ mod tests {
                                     ty: P(ast::Ty{id: ast::DUMMY_NODE_ID,
                                                   node: ast::TyKind::Path(None, ast::Path{
                                         span:sp(10,13),
-                                        global:false,
-                                        segments: vec![
-                                            ast::PathSegment {
-                                                identifier: Ident::from_str("i32"),
-                                                parameters: ast::PathParameters::none(),
-                                            }
-                                        ],
+                                        segments: vec![Ident::from_str("i32").into()],
                                         }),
                                         span:sp(10,13)
                                     }),
@@ -889,14 +857,7 @@ mod tests {
                                                 node: ast::ExprKind::Path(None,
                                                       ast::Path{
                                                         span:sp(17,18),
-                                                        global:false,
-                                                        segments: vec![
-                                                            ast::PathSegment {
-                                                                identifier: Ident::from_str("b"),
-                                                                parameters:
-                                                                ast::PathParameters::none(),
-                                                            }
-                                                        ],
+                                                        segments: vec![Ident::from_str("b").into()],
                                                       }),
                                                 span: sp(17,18),
                                                 attrs: ThinVec::new()})),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index bdd1606805f..a0ed50b33a4 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -267,12 +267,11 @@ impl From<P<Expr>> for LhsExpr {
 }
 
 impl<'a> Parser<'a> {
-    pub fn new(sess: &'a ParseSess, rdr: Box<Reader+'a>) -> Self {
-        Parser::new_with_doc_flag(sess, rdr, false)
-    }
-
-    pub fn new_with_doc_flag(sess: &'a ParseSess, rdr: Box<Reader+'a>, desugar_doc_comments: bool)
-                             -> Self {
+    pub fn new(sess: &'a ParseSess,
+               rdr: Box<Reader+'a>,
+               directory: Option<Directory>,
+               desugar_doc_comments: bool)
+               -> Self {
         let mut parser = Parser {
             reader: rdr,
             sess: sess,
@@ -298,7 +297,9 @@ impl<'a> Parser<'a> {
         let tok = parser.next_tok();
         parser.token = tok.tok;
         parser.span = tok.sp;
-        if parser.span != syntax_pos::DUMMY_SP {
+        if let Some(directory) = directory {
+            parser.directory = directory;
+        } else if parser.span != syntax_pos::DUMMY_SP {
             parser.directory.path = PathBuf::from(sess.codemap().span_to_filename(parser.span));
             parser.directory.path.pop();
         }
@@ -1613,7 +1614,6 @@ impl<'a> Parser<'a> {
         } else {
             ast::Path {
                 span: span,
-                global: false,
                 segments: vec![]
             }
         };
@@ -1657,7 +1657,7 @@ impl<'a> Parser<'a> {
         // Parse any number of segments and bound sets. A segment is an
         // identifier followed by an optional lifetime and a set of types.
         // A bound set is a set of type parameter bounds.
-        let segments = match mode {
+        let mut segments = match mode {
             PathStyle::Type => {
                 self.parse_path_segments_without_colons()?
             }
@@ -1669,13 +1669,16 @@ impl<'a> Parser<'a> {
             }
         };
 
+        if is_global {
+            segments.insert(0, ast::PathSegment::crate_root());
+        }
+
         // Assemble the span.
         let span = mk_sp(lo, self.prev_span.hi);
 
         // Assemble the result.
         Ok(ast::Path {
             span: span,
-            global: is_global,
             segments: segments,
         })
     }
@@ -1704,12 +1707,11 @@ impl<'a> Parser<'a> {
             // Parse types, optionally.
             let parameters = if self.eat_lt() {
                 let (lifetimes, types, bindings) = self.parse_generic_values_after_lt()?;
-
-                ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData {
+                ast::AngleBracketedParameterData {
                     lifetimes: lifetimes,
                     types: P::from_vec(types),
                     bindings: P::from_vec(bindings),
-                })
+                }.into()
             } else if self.eat(&token::OpenDelim(token::Paren)) {
                 let lo = self.prev_span.lo;
 
@@ -1726,18 +1728,17 @@ impl<'a> Parser<'a> {
 
                 let hi = self.prev_span.hi;
 
-                ast::PathParameters::Parenthesized(ast::ParenthesizedParameterData {
+                Some(P(ast::PathParameters::Parenthesized(ast::ParenthesizedParameterData {
                     span: mk_sp(lo, hi),
                     inputs: inputs,
                     output: output_ty,
-                })
+                })))
             } else {
-                ast::PathParameters::none()
+                None
             };
 
             // Assemble and push the result.
-            segments.push(ast::PathSegment { identifier: identifier,
-                                             parameters: parameters });
+            segments.push(ast::PathSegment { identifier: identifier, parameters: parameters });
 
             // Continue only if we see a `::`
             if !self.eat(&token::ModSep) {
@@ -1756,10 +1757,7 @@ impl<'a> Parser<'a> {
 
             // If we do not see a `::`, stop.
             if !self.eat(&token::ModSep) {
-                segments.push(ast::PathSegment {
-                    identifier: identifier,
-                    parameters: ast::PathParameters::none()
-                });
+                segments.push(identifier.into());
                 return Ok(segments);
             }
 
@@ -1767,14 +1765,13 @@ impl<'a> Parser<'a> {
             if self.eat_lt() {
                 // Consumed `a::b::<`, go look for types
                 let (lifetimes, types, bindings) = self.parse_generic_values_after_lt()?;
-                let parameters = ast::AngleBracketedParameterData {
-                    lifetimes: lifetimes,
-                    types: P::from_vec(types),
-                    bindings: P::from_vec(bindings),
-                };
                 segments.push(ast::PathSegment {
                     identifier: identifier,
-                    parameters: ast::PathParameters::AngleBracketed(parameters),
+                    parameters: ast::AngleBracketedParameterData {
+                        lifetimes: lifetimes,
+                        types: P::from_vec(types),
+                        bindings: P::from_vec(bindings),
+                    }.into(),
                 });
 
                 // Consumed `a::b::<T,U>`, check for `::` before proceeding
@@ -1783,10 +1780,7 @@ impl<'a> Parser<'a> {
                 }
             } else {
                 // Consumed `a::`, go look for `b`
-                segments.push(ast::PathSegment {
-                    identifier: identifier,
-                    parameters: ast::PathParameters::none(),
-                });
+                segments.push(identifier.into());
             }
         }
     }
@@ -1801,10 +1795,7 @@ impl<'a> Parser<'a> {
             let identifier = self.parse_path_segment_ident()?;
 
             // Assemble and push the result.
-            segments.push(ast::PathSegment {
-                identifier: identifier,
-                parameters: ast::PathParameters::none()
-            });
+            segments.push(identifier.into());
 
             // If we do not see a `::` or see `::{`/`::*`, stop.
             if !self.check(&token::ModSep) || self.is_import_coupler() {
@@ -4173,7 +4164,7 @@ impl<'a> Parser<'a> {
                     }));
                     self.bump();
                 }
-                token::ModSep | token::Ident(..) => {
+                _ if self.token.is_path_start() || self.token.is_keyword(keywords::For) => {
                     let poly_trait_ref = self.parse_poly_trait_ref()?;
                     let modifier = if ate_question {
                         TraitBoundModifier::Maybe
@@ -4377,6 +4368,23 @@ impl<'a> Parser<'a> {
             return Ok(where_clause);
         }
 
+        // This is a temporary hack.
+        //
+        // We are considering adding generics to the `where` keyword as an alternative higher-rank
+        // parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking
+        // change, for now we refuse to parse `where < (ident | lifetime) (> | , | :)`.
+        if token::Lt == self.token {
+            let ident_or_lifetime = self.look_ahead(1, |t| t.is_ident() || t.is_lifetime());
+            if ident_or_lifetime {
+                let gt_comma_or_colon = self.look_ahead(2, |t| {
+                    *t == token::Gt || *t == token::Comma || *t == token::Colon
+                });
+                if gt_comma_or_colon {
+                    self.span_err(self.span, "syntax `where<T>` is reserved for future use");
+                }
+            }
+        }
+
         let mut parsed_something = false;
         loop {
             let lo = self.span.lo;
@@ -5191,7 +5199,7 @@ impl<'a> Parser<'a> {
         } else if self.eat_keyword(keywords::Crate) {
             pub_crate(self)
         } else {
-            let path = self.parse_path(PathStyle::Mod)?;
+            let path = self.parse_path(PathStyle::Mod)?.default_to_global();
             self.expect(&token::CloseDelim(token::Paren))?;
             Ok(Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID })
         }
@@ -6079,9 +6087,9 @@ impl<'a> Parser<'a> {
         if self.check(&token::OpenDelim(token::Brace)) || self.check(&token::BinOp(token::Star)) ||
            self.is_import_coupler() {
             // `{foo, bar}`, `::{foo, bar}`, `*`, or `::*`.
+            self.eat(&token::ModSep);
             let prefix = ast::Path {
-                global: self.eat(&token::ModSep),
-                segments: Vec::new(),
+                segments: vec![ast::PathSegment::crate_root()],
                 span: mk_sp(lo, self.span.hi),
             };
             let view_path_kind = if self.eat(&token::BinOp(token::Star)) {
@@ -6091,7 +6099,7 @@ impl<'a> Parser<'a> {
             };
             Ok(P(spanned(lo, self.span.hi, view_path_kind)))
         } else {
-            let prefix = self.parse_path(PathStyle::Mod)?;
+            let prefix = self.parse_path(PathStyle::Mod)?.default_to_global();
             if self.is_import_coupler() {
                 // `foo::bar::{a, b}` or `foo::bar::*`
                 self.bump();
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index c28b9d00501..7558f0256da 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -371,7 +371,7 @@ pub fn fn_block_to_string(p: &ast::FnDecl) -> String {
 }
 
 pub fn path_to_string(p: &ast::Path) -> String {
-    to_string(|s| s.print_path(p, false, 0))
+    to_string(|s| s.print_path(p, false, 0, false))
 }
 
 pub fn ident_to_string(id: ast::Ident) -> String {
@@ -435,7 +435,8 @@ pub fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
     match *vis {
         ast::Visibility::Public => format!("pub {}", s),
         ast::Visibility::Crate(_) => format!("pub(crate) {}", s),
-        ast::Visibility::Restricted { ref path, .. } => format!("pub({}) {}", path, s),
+        ast::Visibility::Restricted { ref path, .. } =>
+            format!("pub({}) {}", to_string(|s| s.print_path(path, false, 0, true)), s),
         ast::Visibility::Inherited => s.to_string()
     }
 }
@@ -1021,7 +1022,7 @@ impl<'a> State<'a> {
                                  &generics));
             }
             ast::TyKind::Path(None, ref path) => {
-                try!(self.print_path(path, false, 0));
+                try!(self.print_path(path, false, 0, false));
             }
             ast::TyKind::Path(Some(ref qself), ref path) => {
                 try!(self.print_qpath(path, qself, false))
@@ -1332,7 +1333,7 @@ impl<'a> State<'a> {
             }
             ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => {
                 try!(self.print_visibility(&item.vis));
-                try!(self.print_path(&node.path, false, 0));
+                try!(self.print_path(&node.path, false, 0, false));
                 try!(word(&mut self.s, "! "));
                 try!(self.print_ident(item.ident));
                 try!(self.cbox(INDENT_UNIT));
@@ -1347,7 +1348,7 @@ impl<'a> State<'a> {
     }
 
     fn print_trait_ref(&mut self, t: &ast::TraitRef) -> io::Result<()> {
-        self.print_path(&t.path, false, 0)
+        self.print_path(&t.path, false, 0, false)
     }
 
     fn print_formal_lifetime_list(&mut self, lifetimes: &[ast::LifetimeDef]) -> io::Result<()> {
@@ -1405,8 +1406,10 @@ impl<'a> State<'a> {
         match *vis {
             ast::Visibility::Public => self.word_nbsp("pub"),
             ast::Visibility::Crate(_) => self.word_nbsp("pub(crate)"),
-            ast::Visibility::Restricted { ref path, .. } =>
-                self.word_nbsp(&format!("pub({})", path)),
+            ast::Visibility::Restricted { ref path, .. } => {
+                let path = to_string(|s| s.print_path(path, false, 0, true));
+                self.word_nbsp(&format!("pub({})", path))
+            }
             ast::Visibility::Inherited => Ok(())
         }
     }
@@ -1571,7 +1574,7 @@ impl<'a> State<'a> {
             }
             ast::TraitItemKind::Macro(codemap::Spanned { ref node, .. }) => {
                 // code copied from ItemKind::Mac:
-                self.print_path(&node.path, false, 0)?;
+                self.print_path(&node.path, false, 0, false)?;
                 word(&mut self.s, "! ")?;
                 self.cbox(INDENT_UNIT)?;
                 self.popen()?;
@@ -1607,7 +1610,7 @@ impl<'a> State<'a> {
             }
             ast::ImplItemKind::Macro(codemap::Spanned { ref node, .. }) => {
                 // code copied from ItemKind::Mac:
-                try!(self.print_path(&node.path, false, 0));
+                try!(self.print_path(&node.path, false, 0, false));
                 try!(word(&mut self.s, "! "));
                 try!(self.cbox(INDENT_UNIT));
                 try!(self.popen());
@@ -1793,7 +1796,7 @@ impl<'a> State<'a> {
 
     pub fn print_mac(&mut self, m: &ast::Mac, delim: token::DelimToken)
                      -> io::Result<()> {
-        try!(self.print_path(&m.node.path, false, 0));
+        try!(self.print_path(&m.node.path, false, 0, false));
         try!(word(&mut self.s, "!"));
         match delim {
             token::Paren => try!(self.popen()),
@@ -1885,7 +1888,7 @@ impl<'a> State<'a> {
                          fields: &[ast::Field],
                          wth: &Option<P<ast::Expr>>,
                          attrs: &[Attribute]) -> io::Result<()> {
-        try!(self.print_path(path, true, 0));
+        try!(self.print_path(path, true, 0, false));
         try!(word(&mut self.s, "{"));
         try!(self.print_inner_attributes_inline(attrs));
         try!(self.commasep_cmnt(
@@ -2186,7 +2189,7 @@ impl<'a> State<'a> {
                 }
             }
             ast::ExprKind::Path(None, ref path) => {
-                try!(self.print_path(path, true, 0))
+                try!(self.print_path(path, true, 0, false))
             }
             ast::ExprKind::Path(Some(ref qself), ref path) => {
                 try!(self.print_qpath(path, qself, true))
@@ -2334,22 +2337,27 @@ impl<'a> State<'a> {
     fn print_path(&mut self,
                   path: &ast::Path,
                   colons_before_params: bool,
-                  depth: usize)
+                  depth: usize,
+                  defaults_to_global: bool)
                   -> io::Result<()>
     {
         try!(self.maybe_print_comment(path.span.lo));
 
-        let mut first = !path.global;
-        for segment in &path.segments[..path.segments.len()-depth] {
-            if first {
-                first = false
-            } else {
+        let mut segments = path.segments[..path.segments.len()-depth].iter();
+        if defaults_to_global && path.is_global() {
+            segments.next();
+        }
+        for (i, segment) in segments.enumerate() {
+            if i > 0 {
                 try!(word(&mut self.s, "::"))
             }
-
-            try!(self.print_ident(segment.identifier));
-
-            try!(self.print_path_parameters(&segment.parameters, colons_before_params));
+            if segment.identifier.name != keywords::CrateRoot.name() &&
+               segment.identifier.name != "$crate" {
+                try!(self.print_ident(segment.identifier));
+                if let Some(ref parameters) = segment.parameters {
+                    try!(self.print_path_parameters(parameters, colons_before_params));
+                }
+            }
         }
 
         Ok(())
@@ -2367,13 +2375,16 @@ impl<'a> State<'a> {
             try!(space(&mut self.s));
             try!(self.word_space("as"));
             let depth = path.segments.len() - qself.position;
-            try!(self.print_path(&path, false, depth));
+            try!(self.print_path(&path, false, depth, false));
         }
         try!(word(&mut self.s, ">"));
         try!(word(&mut self.s, "::"));
         let item_segment = path.segments.last().unwrap();
         try!(self.print_ident(item_segment.identifier));
-        self.print_path_parameters(&item_segment.parameters, colons_before_params)
+        match item_segment.parameters {
+            Some(ref parameters) => self.print_path_parameters(parameters, colons_before_params),
+            None => Ok(()),
+        }
     }
 
     fn print_path_parameters(&mut self,
@@ -2381,10 +2392,6 @@ impl<'a> State<'a> {
                              colons_before_params: bool)
                              -> io::Result<()>
     {
-        if parameters.is_empty() {
-            return Ok(());
-        }
-
         if colons_before_params {
             try!(word(&mut self.s, "::"))
         }
@@ -2471,7 +2478,7 @@ impl<'a> State<'a> {
                 }
             }
             PatKind::TupleStruct(ref path, ref elts, ddpos) => {
-                try!(self.print_path(path, true, 0));
+                try!(self.print_path(path, true, 0, false));
                 try!(self.popen());
                 if let Some(ddpos) = ddpos {
                     try!(self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p)));
@@ -2489,13 +2496,13 @@ impl<'a> State<'a> {
                 try!(self.pclose());
             }
             PatKind::Path(None, ref path) => {
-                try!(self.print_path(path, true, 0));
+                try!(self.print_path(path, true, 0, false));
             }
             PatKind::Path(Some(ref qself), ref path) => {
                 try!(self.print_qpath(path, qself, false));
             }
             PatKind::Struct(ref path, ref fields, etc) => {
-                try!(self.print_path(path, true, 0));
+                try!(self.print_path(path, true, 0, false));
                 try!(self.nbsp());
                 try!(self.word_space("{"));
                 try!(self.commasep_cmnt(
@@ -2842,7 +2849,7 @@ impl<'a> State<'a> {
                     try!(self.print_lifetime_bounds(lifetime, bounds));
                 }
                 ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => {
-                    try!(self.print_path(path, false, 0));
+                    try!(self.print_path(path, false, 0, false));
                     try!(space(&mut self.s));
                     try!(self.word_space("="));
                     try!(self.print_type(&ty));
@@ -2856,7 +2863,7 @@ impl<'a> State<'a> {
     pub fn print_view_path(&mut self, vp: &ast::ViewPath) -> io::Result<()> {
         match vp.node {
             ast::ViewPathSimple(ident, ref path) => {
-                try!(self.print_path(path, false, 0));
+                try!(self.print_path(path, false, 0, true));
 
                 if path.segments.last().unwrap().identifier.name !=
                         ident.name {
@@ -2869,7 +2876,7 @@ impl<'a> State<'a> {
             }
 
             ast::ViewPathGlob(ref path) => {
-                try!(self.print_path(path, false, 0));
+                try!(self.print_path(path, false, 0, true));
                 word(&mut self.s, "::*")
             }
 
@@ -2877,7 +2884,7 @@ impl<'a> State<'a> {
                 if path.segments.is_empty() {
                     try!(word(&mut self.s, "{"));
                 } else {
-                    try!(self.print_path(path, false, 0));
+                    try!(self.print_path(path, false, 0, true));
                     try!(word(&mut self.s, "::{"));
                 }
                 try!(self.commasep(Inconsistent, &idents[..], |s, w| {
diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs
index 6a291ad9c40..68d807b24a7 100644
--- a/src/libsyntax/std_inject.rs
+++ b/src/libsyntax/std_inject.rs
@@ -80,10 +80,8 @@ pub fn maybe_inject_crates_ref(sess: &ParseSess,
         }],
         vis: ast::Visibility::Inherited,
         node: ast::ItemKind::Use(P(codemap::dummy_spanned(ast::ViewPathGlob(ast::Path {
-            global: false,
-            segments: vec![name, "prelude", "v1"].into_iter().map(|name| ast::PathSegment {
-                identifier: ast::Ident::from_str(name),
-                parameters: ast::PathParameters::none(),
+            segments: ["{{root}}", name, "prelude", "v1"].into_iter().map(|name| {
+                ast::Ident::from_str(name).into()
             }).collect(),
             span: span,
         })))),
diff --git a/src/libsyntax/symbol.rs b/src/libsyntax/symbol.rs
index fe9a176179c..c2123ea5a07 100644
--- a/src/libsyntax/symbol.rs
+++ b/src/libsyntax/symbol.rs
@@ -221,6 +221,9 @@ declare_keywords! {
     (53, Default,        "default")
     (54, StaticLifetime, "'static")
     (55, Union,          "union")
+
+    // A virtual keyword that resolves to the crate root when used in a lexical scope.
+    (56, CrateRoot, "{{root}}")
 }
 
 // If an interner exists in TLS, return it. Otherwise, prepare a fresh one.
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index fca89e265e4..b8e0b938814 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -579,11 +579,7 @@ fn nospan<T>(t: T) -> codemap::Spanned<T> {
 fn path_node(ids: Vec<Ident>) -> ast::Path {
     ast::Path {
         span: DUMMY_SP,
-        global: false,
-        segments: ids.into_iter().map(|identifier| ast::PathSegment {
-            identifier: identifier,
-            parameters: ast::PathParameters::none(),
-        }).collect()
+        segments: ids.into_iter().map(Into::into).collect(),
     }
 }
 
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index 0d5dcaf339f..e352e7853c7 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -31,7 +31,7 @@ use ext::base;
 use ext::tt::macro_parser;
 use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
 use parse::lexer;
-use parse;
+use parse::{self, Directory};
 use parse::token::{self, Token, Lit, Nonterminal};
 use print::pprust;
 use symbol::Symbol;
@@ -218,7 +218,11 @@ impl TokenTree {
         let diag = &cx.parse_sess().span_diagnostic;
         // `None` is because we're not interpolating
         let arg_rdr = lexer::new_tt_reader(diag, None, tts.iter().cloned().collect());
-        macro_parser::parse(cx.parse_sess(), arg_rdr, mtch)
+        let directory = Directory {
+            path: cx.current_expansion.module.directory.clone(),
+            ownership: cx.current_expansion.directory_ownership,
+        };
+        macro_parser::parse(cx.parse_sess(), arg_rdr, mtch, Some(directory))
     }
 
     /// Check if this TokenTree is equal to the other, regardless of span information.
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 3e0353d532d..ad29cb50a84 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -178,7 +178,6 @@ pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) {
 
 pub fn walk_macro_def<'a, V: Visitor<'a>>(visitor: &mut V, macro_def: &'a MacroDef) {
     visitor.visit_ident(macro_def.span, macro_def.ident);
-    walk_opt_ident(visitor, macro_def.span, macro_def.imported_from);
     walk_list!(visitor, visit_attribute, &macro_def.attrs);
 }
 
@@ -384,7 +383,9 @@ pub fn walk_path_segment<'a, V: Visitor<'a>>(visitor: &mut V,
                                              path_span: Span,
                                              segment: &'a PathSegment) {
     visitor.visit_ident(path_span, segment.identifier);
-    visitor.visit_path_parameters(path_span, &segment.parameters);
+    if let Some(ref parameters) = segment.parameters {
+        visitor.visit_path_parameters(path_span, parameters);
+    }
 }
 
 pub fn walk_path_parameters<'a, V>(visitor: &mut V,
diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs
index b26e33eb384..1fc1bdff593 100644
--- a/src/libsyntax_ext/concat_idents.rs
+++ b/src/libsyntax_ext/concat_idents.rs
@@ -59,14 +59,9 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt,
 
     impl Result {
         fn path(&self) -> ast::Path {
-            let segment = ast::PathSegment {
-                identifier: self.ident,
-                parameters: ast::PathParameters::none(),
-            };
             ast::Path {
                 span: self.span,
-                global: false,
-                segments: vec![segment],
+                segments: vec![self.ident.into()],
             }
         }
     }
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index 51199819dfc..7f187d8d1c1 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -363,15 +363,12 @@ fn find_type_parameters(ty: &ast::Ty,
 
     impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> {
         fn visit_ty(&mut self, ty: &'a ast::Ty) {
-            match ty.node {
-                ast::TyKind::Path(_, ref path) if !path.global => {
-                    if let Some(segment) = path.segments.first() {
-                        if self.ty_param_names.contains(&segment.identifier.name) {
-                            self.types.push(P(ty.clone()));
-                        }
+            if let ast::TyKind::Path(_, ref path) = ty.node {
+                if let Some(segment) = path.segments.first() {
+                    if self.ty_param_names.contains(&segment.identifier.name) {
+                        self.types.push(P(ty.clone()));
                     }
                 }
-                _ => {}
             }
 
             visit::walk_ty(self, ty)
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index 535d7de19e3..0511b0d252b 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -175,8 +175,10 @@ pub fn expand_derive(cx: &mut ExtCtxt,
                                            feature_gate::GateIssue::Language,
                                            feature_gate::EXPLAIN_CUSTOM_DERIVE);
         } else {
-            cx.span_warn(titem.span, feature_gate::EXPLAIN_DEPR_CUSTOM_DERIVE);
             let name = Symbol::intern(&format!("derive_{}", tname));
+            if !cx.resolver.is_whitelisted_legacy_custom_derive(name) {
+                cx.span_warn(titem.span, feature_gate::EXPLAIN_DEPR_CUSTOM_DERIVE);
+            }
             let mitem = cx.meta_word(titem.span, name);
             new_attributes.push(cx.attribute(mitem.span, mitem));
         }
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index 66d6c0570ac..e31b29d5cc1 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -50,8 +50,7 @@ pub mod deriving;
 
 use std::rc::Rc;
 use syntax::ast;
-use syntax::ext::base::{MacroExpanderFn, NormalTT, IdentTT, MultiModifier, NamedSyntaxExtension};
-use syntax::ext::tt::macro_rules::MacroRulesExpander;
+use syntax::ext::base::{MacroExpanderFn, NormalTT, MultiModifier, NamedSyntaxExtension};
 use syntax::symbol::Symbol;
 
 pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
@@ -61,8 +60,6 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
         resolver.add_ext(ast::Ident::with_empty_ctxt(name), Rc::new(ext));
     };
 
-    register(Symbol::intern("macro_rules"), IdentTT(Box::new(MacroRulesExpander), None, false));
-
     macro_rules! register {
         ($( $name:ident: $f:expr, )*) => { $(
             register(Symbol::intern(stringify!($name)),
diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs
index 8fbd11a7a6e..5323ace79d8 100644
--- a/src/libsyntax_ext/proc_macro_registrar.rs
+++ b/src/libsyntax_ext/proc_macro_registrar.rs
@@ -108,6 +108,8 @@ impl<'a> CollectCustomDerives<'a> {
 
 impl<'a> Visitor<'a> for CollectCustomDerives<'a> {
     fn visit_item(&mut self, item: &'a ast::Item) {
+        let mut attrs = item.attrs.iter().filter(|a| a.check_name("proc_macro_derive"));
+
         // First up, make sure we're checking a bare function. If we're not then
         // we're just not interested in this item.
         //
@@ -117,10 +119,7 @@ impl<'a> Visitor<'a> for CollectCustomDerives<'a> {
             ast::ItemKind::Fn(..) => {}
             _ => {
                 // Check for invalid use of proc_macro_derive
-                let attr = item.attrs.iter()
-                    .filter(|a| a.check_name("proc_macro_derive"))
-                    .next();
-                if let Some(attr) = attr {
+                if let Some(attr) = attrs.next() {
                     self.handler.span_err(attr.span(),
                                           "the `#[proc_macro_derive]` \
                                           attribute may only be used \
@@ -132,8 +131,6 @@ impl<'a> Visitor<'a> for CollectCustomDerives<'a> {
             }
         }
 
-        let mut attrs = item.attrs.iter()
-                            .filter(|a| a.check_name("proc_macro_derive"));
         let attr = match attrs.next() {
             Some(attr) => attr,
             None => {
@@ -227,7 +224,7 @@ impl<'a> Visitor<'a> for CollectCustomDerives<'a> {
             Vec::new()
         };
 
-        if self.in_root {
+        if self.in_root && item.vis == ast::Visibility::Public {
             self.derives.push(CustomDerive {
                 span: item.span,
                 trait_name: trait_name,
@@ -235,8 +232,12 @@ impl<'a> Visitor<'a> for CollectCustomDerives<'a> {
                 attrs: proc_attrs,
             });
         } else {
-            let msg = "functions tagged with `#[proc_macro_derive]` must \
-                       currently reside in the root of the crate";
+            let msg = if !self.in_root {
+                "functions tagged with `#[proc_macro_derive]` must \
+                 currently reside in the root of the crate"
+            } else {
+                "functions tagged with `#[proc_macro_derive]` must be `pub`"
+            };
             self.handler.span_err(item.span, msg);
         }
 
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index 142ae86c6a3..82acbf93488 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -254,10 +254,16 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>) {
         Some(Err(msg)) => panic!("{:?}", msg),
         None => return,
     };
-    match run_tests_console(&opts, tests) {
-        Ok(true) => {}
-        Ok(false) => std::process::exit(101),
-        Err(e) => panic!("io error when running tests: {:?}", e),
+    if opts.list {
+        if let Err(e) = list_tests_console(&opts, tests) {
+            panic!("io error when listing tests: {:?}", e);
+        }
+    } else {
+        match run_tests_console(&opts, tests) {
+            Ok(true) => {}
+            Ok(false) => std::process::exit(101),
+            Err(e) => panic!("io error when running tests: {:?}", e),
+        }
     }
 }
 
@@ -300,7 +306,9 @@ pub enum ColorConfig {
 }
 
 pub struct TestOpts {
+    pub list: bool,
     pub filter: Option<String>,
+    pub filter_exact: bool,
     pub run_ignored: bool,
     pub run_tests: bool,
     pub bench_benchmarks: bool,
@@ -316,7 +324,9 @@ impl TestOpts {
     #[cfg(test)]
     fn new() -> TestOpts {
         TestOpts {
+            list: false,
             filter: None,
+            filter_exact: false,
             run_ignored: false,
             run_tests: false,
             bench_benchmarks: false,
@@ -338,6 +348,7 @@ fn optgroups() -> Vec<getopts::OptGroup> {
     vec![getopts::optflag("", "ignored", "Run ignored tests"),
       getopts::optflag("", "test", "Run tests and not benchmarks"),
       getopts::optflag("", "bench", "Run benchmarks instead of tests"),
+      getopts::optflag("", "list", "List all tests and benchmarks"),
       getopts::optflag("h", "help", "Display this message (longer with --help)"),
       getopts::optopt("", "logfile", "Write logs to the specified file instead \
                           of stdout", "PATH"),
@@ -348,6 +359,7 @@ fn optgroups() -> Vec<getopts::OptGroup> {
       getopts::optmulti("", "skip", "Skip tests whose names contain FILTER (this flag can \
                                      be used multiple times)","FILTER"),
       getopts::optflag("q", "quiet", "Display one character per test instead of one line"),
+      getopts::optflag("", "exact", "Exactly match filters rather than by substring"),
       getopts::optopt("", "color", "Configure coloring of output:
             auto   = colorize if stdout is a tty and tests are run on serially (default);
             always = always colorize output;
@@ -407,6 +419,8 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
 
     let run_ignored = matches.opt_present("ignored");
     let quiet = matches.opt_present("quiet");
+    let exact = matches.opt_present("exact");
+    let list = matches.opt_present("list");
 
     let logfile = matches.opt_str("logfile");
     let logfile = logfile.map(|s| PathBuf::from(&s));
@@ -447,7 +461,9 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
     };
 
     let test_opts = TestOpts {
+        list: list,
         filter: filter,
+        filter_exact: exact,
         run_ignored: run_ignored,
         run_tests: run_tests,
         bench_benchmarks: bench_benchmarks,
@@ -576,7 +592,8 @@ impl<T: Write> ConsoleTestState<T> {
         }
     }
 
-    pub fn write_plain(&mut self, s: &str) -> io::Result<()> {
+    pub fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
+        let s = s.as_ref();
         match self.out {
             Pretty(ref mut term) => {
                 term.write_all(s.as_bytes())?;
@@ -630,25 +647,28 @@ impl<T: Write> ConsoleTestState<T> {
                                   TEST_WARN_TIMEOUT_S))
     }
 
-    pub fn write_log(&mut self, test: &TestDesc, result: &TestResult) -> io::Result<()> {
+    pub fn write_log<S: AsRef<str>>(&mut self, msg: S) -> io::Result<()> {
+        let msg = msg.as_ref();
         match self.log_out {
             None => Ok(()),
-            Some(ref mut o) => {
-                let s = format!("{} {}\n",
-                                match *result {
-                                    TrOk => "ok".to_owned(),
-                                    TrFailed => "failed".to_owned(),
-                                    TrFailedMsg(ref msg) => format!("failed: {}", msg),
-                                    TrIgnored => "ignored".to_owned(),
-                                    TrMetrics(ref mm) => mm.fmt_metrics(),
-                                    TrBench(ref bs) => fmt_bench_samples(bs),
-                                },
-                                test.name);
-                o.write_all(s.as_bytes())
-            }
+            Some(ref mut o) => o.write_all(msg.as_bytes()),
         }
     }
 
+    pub fn write_log_result(&mut self, test: &TestDesc, result: &TestResult) -> io::Result<()> {
+        self.write_log(
+            format!("{} {}\n",
+                    match *result {
+                        TrOk => "ok".to_owned(),
+                        TrFailed => "failed".to_owned(),
+                        TrFailedMsg(ref msg) => format!("failed: {}", msg),
+                        TrIgnored => "ignored".to_owned(),
+                        TrMetrics(ref mm) => mm.fmt_metrics(),
+                        TrBench(ref bs) => fmt_bench_samples(bs),
+                    },
+                    test.name))
+    }
+
     pub fn write_failures(&mut self) -> io::Result<()> {
         self.write_plain("\nfailures:\n")?;
         let mut failures = Vec::new();
@@ -741,6 +761,49 @@ pub fn fmt_bench_samples(bs: &BenchSamples) -> String {
     output
 }
 
+// List the tests to console, and optionally to logfile. Filters are honored.
+pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> {
+    let mut st = ConsoleTestState::new(opts, None::<io::Stdout>)?;
+
+    let mut ntest = 0;
+    let mut nbench = 0;
+    let mut nmetric = 0;
+
+    for test in filter_tests(&opts, tests) {
+        use TestFn::*;
+
+        let TestDescAndFn { desc: TestDesc { name, .. }, testfn } = test;
+
+        let fntype = match testfn {
+            StaticTestFn(..) | DynTestFn(..) => { ntest += 1; "test" },
+            StaticBenchFn(..) | DynBenchFn(..) => { nbench += 1; "benchmark" },
+            StaticMetricFn(..) | DynMetricFn(..) => { nmetric += 1; "metric" },
+        };
+
+        st.write_plain(format!("{}: {}\n", name, fntype))?;
+        st.write_log(format!("{} {}\n", fntype, name))?;
+    }
+
+    fn plural(count: u32, s: &str) -> String {
+        match count {
+            1 => format!("{} {}", 1, s),
+            n => format!("{} {}s", n, s),
+        }
+    }
+
+    if !opts.quiet {
+        if ntest != 0 || nbench != 0 || nmetric != 0 {
+            st.write_plain("\n")?;
+        }
+        st.write_plain(format!("{}, {}, {}\n",
+            plural(ntest, "test"),
+            plural(nbench, "benchmark"),
+            plural(nmetric, "metric")))?;
+    }
+
+    Ok(())
+}
+
 // A simple console test runner
 pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<bool> {
 
@@ -750,7 +813,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu
             TeWait(ref test, padding) => st.write_test_start(test, padding),
             TeTimeout(ref test) => st.write_timeout(test),
             TeResult(test, result, stdout) => {
-                st.write_log(&test, &result)?;
+                st.write_log_result(&test, &result)?;
                 st.write_result(&result)?;
                 match result {
                     TrOk => st.passed += 1,
@@ -851,6 +914,11 @@ fn use_color(opts: &TestOpts) -> bool {
     }
 }
 
+#[cfg(target_os = "redox")]
+fn stdout_isatty() -> bool {
+    // FIXME: Implement isatty on Redox
+    false
+}
 #[cfg(unix)]
 fn stdout_isatty() -> bool {
     unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
@@ -1040,6 +1108,12 @@ fn get_concurrency() -> usize {
         }
     }
 
+    #[cfg(target_os = "redox")]
+    fn num_cpus() -> usize {
+        // FIXME: Implement num_cpus on Redox
+        1
+    }
+
     #[cfg(any(target_os = "linux",
               target_os = "macos",
               target_os = "ios",
@@ -1118,14 +1192,26 @@ pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescA
         None => filtered,
         Some(ref filter) => {
             filtered.into_iter()
-                    .filter(|test| test.desc.name.as_slice().contains(&filter[..]))
+                    .filter(|test| {
+                        if opts.filter_exact {
+                            test.desc.name.as_slice() == &filter[..]
+                        } else {
+                            test.desc.name.as_slice().contains(&filter[..])
+                        }
+                    })
                     .collect()
         }
     };
 
     // Skip tests that match any of the skip filters
     filtered = filtered.into_iter()
-        .filter(|t| !opts.skip.iter().any(|sf| t.desc.name.as_slice().contains(&sf[..])))
+        .filter(|t| !opts.skip.iter().any(|sf| {
+                if opts.filter_exact {
+                    t.desc.name.as_slice() == &sf[..]
+                } else {
+                    t.desc.name.as_slice().contains(&sf[..])
+                }
+            }))
         .collect();
 
     // Maybe pull out the ignored test and unignore them
@@ -1655,6 +1741,77 @@ mod tests {
     }
 
     #[test]
+    pub fn exact_filter_match() {
+        fn tests() -> Vec<TestDescAndFn> {
+            vec!["base",
+                 "base::test",
+                 "base::test1",
+                 "base::test2",
+            ].into_iter()
+            .map(|name| TestDescAndFn {
+                desc: TestDesc {
+                    name: StaticTestName(name),
+                    ignore: false,
+                    should_panic: ShouldPanic::No,
+                },
+                testfn: DynTestFn(Box::new(move |()| {}))
+            })
+            .collect()
+        }
+
+        let substr = filter_tests(&TestOpts {
+                filter: Some("base".into()),
+                ..TestOpts::new()
+            }, tests());
+        assert_eq!(substr.len(), 4);
+
+        let substr = filter_tests(&TestOpts {
+                filter: Some("bas".into()),
+                ..TestOpts::new()
+            }, tests());
+        assert_eq!(substr.len(), 4);
+
+        let substr = filter_tests(&TestOpts {
+                filter: Some("::test".into()),
+                ..TestOpts::new()
+            }, tests());
+        assert_eq!(substr.len(), 3);
+
+        let substr = filter_tests(&TestOpts {
+                filter: Some("base::test".into()),
+                ..TestOpts::new()
+            }, tests());
+        assert_eq!(substr.len(), 3);
+
+        let exact = filter_tests(&TestOpts {
+                filter: Some("base".into()),
+                filter_exact: true, ..TestOpts::new()
+            }, tests());
+        assert_eq!(exact.len(), 1);
+
+        let exact = filter_tests(&TestOpts {
+                filter: Some("bas".into()),
+                filter_exact: true,
+                ..TestOpts::new()
+            }, tests());
+        assert_eq!(exact.len(), 0);
+
+        let exact = filter_tests(&TestOpts {
+                filter: Some("::test".into()),
+                filter_exact: true,
+                ..TestOpts::new()
+            }, tests());
+        assert_eq!(exact.len(), 0);
+
+        let exact = filter_tests(&TestOpts {
+                filter: Some("base::test".into()),
+                filter_exact: true,
+                ..TestOpts::new()
+            }, tests());
+        assert_eq!(exact.len(), 1);
+    }
+
+    #[test]
     pub fn sort_tests() {
         let mut opts = TestOpts::new();
         opts.run_tests = true;
diff --git a/src/llvm b/src/llvm
-Subproject d7342a9a957470bb62c890cf88fc655ccfb755c
+Subproject ceb177eeefa7d67ca29230d2e7e8584f97d4fda
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index ae2ab932a61..5d5845213e2 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -150,6 +150,8 @@ from_rust(LLVMRustAttribute kind) {
       return Attribute::UWTable;
     case ZExt:
       return Attribute::ZExt;
+    case InReg:
+      return Attribute::InReg;
     default:
       llvm_unreachable("bad AttributeKind");
   }
@@ -552,8 +554,13 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateBasicType(
     uint64_t AlignInBits,
     unsigned Encoding) {
     return wrap(Builder->createBasicType(
-        Name, SizeInBits,
-        AlignInBits, Encoding));
+        Name,
+        SizeInBits,
+#if LLVM_VERSION_LE(3, 9)
+        AlignInBits,
+#endif
+        Encoding
+    ));
 }
 
 extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreatePointerType(
@@ -645,7 +652,21 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStaticVariable(
     LLVMRustMetadataRef Ty,
     bool isLocalToUnit,
     LLVMValueRef Val,
-    LLVMRustMetadataRef Decl = NULL) {
+    LLVMRustMetadataRef Decl = NULL,
+    uint64_t AlignInBits = 0) {
+    Constant *InitVal = cast<Constant>(unwrap(Val));
+
+#if LLVM_VERSION_GE(4, 0)
+    llvm::DIExpression *InitExpr = nullptr;
+    if (llvm::ConstantInt *IntVal = llvm::dyn_cast<llvm::ConstantInt>(InitVal)) {
+      InitExpr = Builder->createConstantValueExpression(
+          IntVal->getValue().getSExtValue());
+    } else if (llvm::ConstantFP *FPVal = llvm::dyn_cast<llvm::ConstantFP>(InitVal)) {
+        InitExpr = Builder->createConstantValueExpression(
+                FPVal->getValueAPF().bitcastToAPInt().getZExtValue());
+    }
+#endif
+
     return wrap(Builder->createGlobalVariable(unwrapDI<DIDescriptor>(Context),
         Name,
         LinkageName,
@@ -653,8 +674,16 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStaticVariable(
         LineNo,
         unwrapDI<DIType>(Ty),
         isLocalToUnit,
-        cast<Constant>(unwrap(Val)),
-        unwrapDIptr<MDNode>(Decl)));
+#if LLVM_VERSION_GE(4, 0)
+        InitExpr,
+#else
+        InitVal,
+#endif
+        unwrapDIptr<MDNode>(Decl)
+#if LLVM_VERSION_GE(4, 0)
+        , AlignInBits
+#endif
+    ));
 }
 
 extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVariable(
@@ -667,14 +696,23 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVariable(
     LLVMRustMetadataRef Ty,
     bool AlwaysPreserve,
     LLVMRustDIFlags Flags,
-    unsigned ArgNo) {
+    unsigned ArgNo,
+    uint64_t AlignInBits)
+{
 #if LLVM_VERSION_GE(3, 8)
     if (Tag == 0x100) { // DW_TAG_auto_variable
         return wrap(Builder->createAutoVariable(
-            unwrapDI<DIDescriptor>(Scope), Name,
+            unwrapDI<DIDescriptor>(Scope),
+            Name,
             unwrapDI<DIFile>(File),
             LineNo,
-            unwrapDI<DIType>(Ty), AlwaysPreserve, from_rust(Flags)));
+            unwrapDI<DIType>(Ty),
+            AlwaysPreserve,
+            from_rust(Flags)
+#if LLVM_VERSION_GE(4,0)
+            , AlignInBits
+#endif
+        ));
     } else {
         return wrap(Builder->createParameterVariable(
             unwrapDI<DIDescriptor>(Scope), Name, ArgNo,
diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger
index 88dd04b6172..b74f4913858 100644
--- a/src/rustllvm/llvm-auto-clean-trigger
+++ b/src/rustllvm/llvm-auto-clean-trigger
@@ -1,4 +1,4 @@
 # If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
 # The actual contents of this file do not matter, but to trigger a change on the
 # build bots then the contents should be changed so git updates the mtime.
-2016-12-08
+2016-12-19
diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h
index b8c4076f4ce..8f7e0e3d918 100644
--- a/src/rustllvm/rustllvm.h
+++ b/src/rustllvm/rustllvm.h
@@ -98,6 +98,7 @@ enum LLVMRustAttribute {
     StructRet       = 16,
     UWTable         = 17,
     ZExt            = 18,
+    InReg           = 19,
 };
 
 typedef struct OpaqueRustString *RustStringRef;
diff --git a/src/stage0.txt b/src/stage0.txt
index 223974186b1..187c56d7889 100644
--- a/src/stage0.txt
+++ b/src/stage0.txt
@@ -2,7 +2,7 @@
 # compiler itself. For the rustbuild build system, this also describes the
 # relevant Cargo revision that we're using.
 #
-# Currently Rust always bootstrap from the previous stable release, and in our
+# Currently Rust always bootstraps from the previous stable release, and in our
 # train model this means that the master branch bootstraps from beta, beta
 # bootstraps from current stable, and stable bootstraps from the previous stable
 # release.
@@ -12,5 +12,5 @@
 # tarball for a stable release you'll likely see `1.x.0-$date` where `1.x.0` was
 # released on `$date`
 
-rustc: beta-2016-11-16
-cargo: nightly-2016-11-16
+rustc: beta-2016-12-16
+cargo: fbeea902d2c9a5be6d99cc35681565d8f7832592
diff --git a/src/test/codegen/fastcall-inreg.rs b/src/test/codegen/fastcall-inreg.rs
new file mode 100644
index 00000000000..e1dda4d2be0
--- /dev/null
+++ b/src/test/codegen/fastcall-inreg.rs
@@ -0,0 +1,85 @@
+// 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.
+
+// Checks if the "fastcall" calling convention marks function arguments
+// as "inreg" like the C/C++ compilers for the platforms.
+// x86 only.
+
+// ignore-aarch64
+// ignore-aarch64_be
+// ignore-arm
+// ignore-armeb
+// ignore-avr
+// ignore-bpfel
+// ignore-bpfeb
+// ignore-hexagon
+// ignore-mips
+// ignore-mipsel
+// ignore-mips64
+// ignore-mips64el
+// ignore-msp430
+// ignore-powerpc64
+// ignore-powerpc64le
+// ignore-powerpc
+// ignore-r600
+// ignore-amdgcn
+// ignore-sparc
+// ignore-sparcv9
+// ignore-sparcel
+// ignore-s390x
+// ignore-tce
+// ignore-thumb
+// ignore-thumbeb
+// ignore-x86_64 no-ignore-x86
+// ignore-xcore
+// ignore-nvptx
+// ignore-nvptx64
+// ignore-le32
+// ignore-le64
+// ignore-amdil
+// ignore-amdil64
+// ignore-hsail
+// ignore-hsail64
+// ignore-spir
+// ignore-spir64
+// ignore-kalimba
+// ignore-shave
+// ignore-wasm32
+// ignore-wasm64
+
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+mod tests {
+    // CHECK: @f1(i32 inreg, i32 inreg, i32)
+    #[no_mangle]
+    extern "fastcall" fn f1(_: i32, _: i32, _: i32) {}
+
+    // CHECK: @f2(i32* inreg, i32* inreg, i32*)
+    #[no_mangle]
+    extern "fastcall" fn f2(_: *const i32, _: *const i32, _: *const i32) {}
+
+    // CHECK: @f3(float, i32 inreg, i32 inreg, i32)
+    #[no_mangle]
+    extern "fastcall" fn f3(_: f32, _: i32, _: i32, _: i32) {}
+
+    // CHECK: @f4(i32 inreg, float, i32 inreg, i32)
+    #[no_mangle]
+    extern "fastcall" fn f4(_: i32, _: f32, _: i32, _: i32) {}
+
+    // CHECK: @f5(i64, i32)
+    #[no_mangle]
+    extern "fastcall" fn f5(_: i64, _: i32) {}
+
+    // CHECK: @f6(i1 inreg zeroext, i32 inreg, i32)
+    #[no_mangle]
+    extern "fastcall" fn f6(_: bool, _: i32, _: i32) {}
+}
diff --git a/src/test/compile-fail-fulldeps/macro-crate-doesnt-resolve.rs b/src/test/compile-fail-fulldeps/macro-crate-doesnt-resolve.rs
index f563a1f88d0..b0a2859a5da 100644
--- a/src/test/compile-fail-fulldeps/macro-crate-doesnt-resolve.rs
+++ b/src/test/compile-fail-fulldeps/macro-crate-doesnt-resolve.rs
@@ -14,5 +14,5 @@
 extern crate macro_crate_test;
 
 fn main() {
-    macro_crate_test::foo(); //~ ERROR unresolved name
+    macro_crate_test::foo(); //~ ERROR unresolved function `macro_crate_test::foo`
 }
diff --git a/src/test/compile-fail-fulldeps/proc-macro/at-the-root.rs b/src/test/compile-fail-fulldeps/proc-macro/pub-at-crate-root.rs
index bb7478d9a5f..2bf25892c44 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/at-the-root.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/pub-at-crate-root.rs
@@ -23,3 +23,8 @@ pub mod a { //~ `proc-macro` crate types cannot export any items
     }
 }
 
+#[proc_macro_derive(B)]
+fn bar(a: proc_macro::TokenStream) -> proc_macro::TokenStream {
+//~^ ERROR: functions tagged with `#[proc_macro_derive]` must be `pub`
+    a
+}
diff --git a/src/test/compile-fail-fulldeps/proc-macro/signature.rs b/src/test/compile-fail-fulldeps/proc-macro/signature.rs
index d9b19d1d85a..b7df9489dff 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/signature.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/signature.rs
@@ -15,7 +15,7 @@
 extern crate proc_macro;
 
 #[proc_macro_derive(A)]
-unsafe extern fn foo(a: i32, b: u32) -> u32 {
+pub unsafe extern fn foo(a: i32, b: u32) -> u32 {
     //~^ ERROR: mismatched types
     //~| NOTE: expected normal fn, found unsafe fn
     //~| NOTE: expected type `fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
diff --git a/src/test/compile-fail-fulldeps/qquote.rs b/src/test/compile-fail-fulldeps/qquote.rs
index 8acab3369e4..149985717c6 100644
--- a/src/test/compile-fail-fulldeps/qquote.rs
+++ b/src/test/compile-fail-fulldeps/qquote.rs
@@ -39,6 +39,6 @@ fn main() {
 
     assert_eq!(pprust::expr_to_string(&*quote_expr!(&cx, 23)), "23");
 
-    let expr = quote_expr!(&cx, 2 - $abcd + 7); //~ ERROR unresolved name `abcd`
+    let expr = quote_expr!(&cx, 2 - $abcd + 7); //~ ERROR unresolved value `abcd`
     assert_eq!(pprust::expr_to_string(&*expr), "2 - $abcd + 7");
 }
diff --git a/src/test/compile-fail/E0033.rs b/src/test/compile-fail/E0033.rs
index 44f73e10e25..03d47472093 100644
--- a/src/test/compile-fail/E0033.rs
+++ b/src/test/compile-fail/E0033.rs
@@ -14,8 +14,8 @@ trait SomeTrait {
 
 fn main() {
     let trait_obj: &SomeTrait = SomeTrait;
-    //~^ ERROR E0425
-    //~| NOTE unresolved name
+    //~^ ERROR expected value, found trait `SomeTrait`
+    //~| NOTE not a value
     //~| ERROR E0038
     //~| method `foo` has no receiver
     //~| NOTE the trait `SomeTrait` cannot be made into an object
diff --git a/src/test/compile-fail/E0259.rs b/src/test/compile-fail/E0259.rs
index 95be48b5ff1..b2129902ef9 100644
--- a/src/test/compile-fail/E0259.rs
+++ b/src/test/compile-fail/E0259.rs
@@ -15,6 +15,6 @@ extern crate collections;
 
 extern crate libc as collections;
 //~^ ERROR E0259
-//~| NOTE `collections` was already imported
+//~| NOTE `collections` already imported
 
 fn main() {}
diff --git a/src/test/compile-fail/E0277-2.rs b/src/test/compile-fail/E0277-2.rs
new file mode 100644
index 00000000000..211c0e6f890
--- /dev/null
+++ b/src/test/compile-fail/E0277-2.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.
+
+struct Foo {
+    bar: Bar
+}
+
+struct Bar {
+    baz: Baz
+}
+
+struct Baz {
+    x: *const u8
+}
+
+fn is_send<T: Send>() { }
+
+fn main() {
+    is_send::<Foo>();
+    //~^ ERROR the trait bound `*const u8: std::marker::Send` is not satisfied in `Foo`
+    //~| NOTE within `Foo`, the trait `std::marker::Send` is not implemented for `*const u8`
+    //~| NOTE: `*const u8` cannot be sent between threads safely
+    //~| NOTE: required because it appears within the type `Baz`
+    //~| NOTE: required because it appears within the type `Bar`
+    //~| NOTE: required because it appears within the type `Foo`
+    //~| NOTE: required by `is_send`
+}
diff --git a/src/test/compile-fail/E0277.rs b/src/test/compile-fail/E0277.rs
index e4cb50cd3f2..e31fea1e458 100644
--- a/src/test/compile-fail/E0277.rs
+++ b/src/test/compile-fail/E0277.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::path::Path;
+
 trait Foo {
     fn bar(&self);
 }
@@ -16,6 +18,13 @@ fn some_func<T: Foo>(foo: T) {
     foo.bar();
 }
 
+fn f(p: Path) { }
+//~^ ERROR the trait bound `[u8]: std::marker::Sized` is not satisfied in `std::path::Path`
+//~| NOTE within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]`
+//~| NOTE `[u8]` does not have a constant size known at compile-time
+//~| NOTE required because it appears within the type `std::path::Path`
+//~| NOTE all local variables must have a statically known size
+
 fn main() {
     some_func(5i32);
     //~^ ERROR the trait bound `i32: Foo` is not satisfied
diff --git a/src/test/compile-fail/E0423.rs b/src/test/compile-fail/E0423.rs
index 98b700984a7..f5fea77cf96 100644
--- a/src/test/compile-fail/E0423.rs
+++ b/src/test/compile-fail/E0423.rs
@@ -12,5 +12,4 @@ fn main () {
     struct Foo { a: bool };
 
     let f = Foo(); //~ ERROR E0423
-                   //~^ struct called like a function
 }
diff --git a/src/test/compile-fail/E0424.rs b/src/test/compile-fail/E0424.rs
index 911007113d3..445d0c5f3ed 100644
--- a/src/test/compile-fail/E0424.rs
+++ b/src/test/compile-fail/E0424.rs
@@ -14,10 +14,7 @@ impl Foo {
     fn bar(self) {}
 
     fn foo() {
-        self.bar();
-        //~^ ERROR `self` is not available in a static method [E0424]
-        //~| NOTE not available in static method
-        //~| NOTE maybe a `self` argument is missing?
+        self.bar(); //~ ERROR E0424
     }
 }
 
diff --git a/src/test/compile-fail/E0425.rs b/src/test/compile-fail/E0425.rs
index 70f4b1107ad..3786282031f 100644
--- a/src/test/compile-fail/E0425.rs
+++ b/src/test/compile-fail/E0425.rs
@@ -10,7 +10,7 @@
 
 trait Foo {
     fn bar() {
-        Self; //~ ERROR E0425
+        elf; //~ ERROR E0425
     }
 }
 
diff --git a/src/test/compile-fail/associated-path-shl.rs b/src/test/compile-fail/associated-path-shl.rs
index 6bc110239cd..0295d4248e5 100644
--- a/src/test/compile-fail/associated-path-shl.rs
+++ b/src/test/compile-fail/associated-path-shl.rs
@@ -11,10 +11,10 @@
 // Check that associated paths starting with `<<` are successfully parsed.
 
 fn main() {
-    let _: <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
-    let _ = <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
-    let <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
-    let 0 ... <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
+    let _: <<A>::B>::C; //~ ERROR unresolved type `A`
+    let _ = <<A>::B>::C; //~ ERROR unresolved type `A`
+    let <<A>::B>::C; //~ ERROR unresolved type `A`
+    let 0 ... <<A>::B>::C; //~ ERROR unresolved type `A`
                            //~^ ERROR only char and numeric types are allowed in range patterns
-    <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
+    <<A>::B>::C; //~ ERROR unresolved type `A`
 }
diff --git a/src/test/compile-fail/associated-types-eq-1.rs b/src/test/compile-fail/associated-types-eq-1.rs
index 59d87146097..46d5633c8dd 100644
--- a/src/test/compile-fail/associated-types-eq-1.rs
+++ b/src/test/compile-fail/associated-types-eq-1.rs
@@ -17,7 +17,7 @@ pub trait Foo {
 }
 
 fn foo2<I: Foo>(x: I) {
-    let _: A = x.boo(); //~ERROR undefined or not in scope
+    let _: A = x.boo(); //~ ERROR unresolved type `A`
 }
 
 pub fn main() {}
diff --git a/src/test/compile-fail/auxiliary/lint_stability.rs b/src/test/compile-fail/auxiliary/lint_stability.rs
index 1049bcd1564..5e3cb606ce0 100644
--- a/src/test/compile-fail/auxiliary/lint_stability.rs
+++ b/src/test/compile-fail/auxiliary/lint_stability.rs
@@ -132,6 +132,10 @@ pub struct UnstableStruct {
 pub struct StableStruct {
     #[stable(feature = "test_feature", since = "1.0.0")] pub i: isize
 }
+#[unstable(feature = "test_feature", issue = "0")]
+pub enum UnstableEnum {}
+#[stable(feature = "rust1", since = "1.0.0")]
+pub enum StableEnum {}
 
 #[stable(feature = "test_feature", since = "1.0.0")]
 #[rustc_deprecated(since = "1.0.0", reason = "text")]
diff --git a/src/test/compile-fail/bad-expr-path.rs b/src/test/compile-fail/bad-expr-path.rs
index c18a3183477..05400a0eb65 100644
--- a/src/test/compile-fail/bad-expr-path.rs
+++ b/src/test/compile-fail/bad-expr-path.rs
@@ -8,8 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: unresolved name `m1::arguments`
-
 mod m1 {}
 
-fn main(arguments: Vec<String>) { log(debug, m1::arguments); }
+fn main(arguments: Vec<String>) { //~ ERROR main function has wrong type
+    log(debug, m1::arguments);
+    //~^ ERROR unresolved function `log`
+    //~| ERROR unresolved value `debug`
+    //~| ERROR unresolved value `m1::arguments`
+}
diff --git a/src/test/compile-fail/bad-expr-path2.rs b/src/test/compile-fail/bad-expr-path2.rs
index e1c1afb0049..867166134b2 100644
--- a/src/test/compile-fail/bad-expr-path2.rs
+++ b/src/test/compile-fail/bad-expr-path2.rs
@@ -8,12 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: unresolved name `m1::arguments`
-
 mod m1 {
     pub mod arguments {}
 }
 
-fn main(arguments: Vec<String>) {
+fn main(arguments: Vec<String>) { //~ ERROR main function has wrong type
     log(debug, m1::arguments);
+    //~^ ERROR unresolved function `log`
+    //~| ERROR unresolved value `debug`
+    //~| ERROR expected value, found module `m1::arguments`
 }
diff --git a/src/test/compile-fail/blind-item-item-shadow.rs b/src/test/compile-fail/blind-item-item-shadow.rs
index 853282ff014..e9df8868a1e 100644
--- a/src/test/compile-fail/blind-item-item-shadow.rs
+++ b/src/test/compile-fail/blind-item-item-shadow.rs
@@ -12,6 +12,6 @@ mod foo { pub mod foo {  } } //~ NOTE previous definition of `foo` here
 
 use foo::foo;
 //~^ ERROR a module named `foo` has already been defined in this module
-//~| was already imported
+//~| `foo` already defined
 
 fn main() {}
diff --git a/src/test/compile-fail/cast-rfc0401.rs b/src/test/compile-fail/cast-rfc0401.rs
deleted file mode 100644
index b98f464c902..00000000000
--- a/src/test/compile-fail/cast-rfc0401.rs
+++ /dev/null
@@ -1,123 +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.
-
-fn illegal_cast<U:?Sized,V:?Sized>(u: *const U) -> *const V
-{
-    u as *const V
-    //~^ ERROR casting
-    //~^^ NOTE vtable kinds
-}
-
-fn illegal_cast_2<U:?Sized>(u: *const U) -> *const str
-{
-    u as *const str
-    //~^ ERROR casting
-    //~^^ NOTE vtable kinds
-}
-
-trait Foo { fn foo(&self) {} }
-impl<T> Foo for T {}
-
-trait Bar { fn foo(&self) {} }
-impl<T> Bar for T {}
-
-enum E {
-    A, B
-}
-
-fn main()
-{
-    let f: f32 = 1.2;
-    let v = 0 as *const u8;
-    let fat_v : *const [u8] = unsafe { &*(0 as *const [u8; 1])};
-    let fat_sv : *const [i8] = unsafe { &*(0 as *const [i8; 1])};
-    let foo: &Foo = &f;
-
-    let _ = v as &u8; //~ ERROR non-scalar
-    let _ = v as E; //~ ERROR non-scalar
-    let _ = v as fn(); //~ ERROR non-scalar
-    let _ = v as (u32,); //~ ERROR non-scalar
-    let _ = Some(&v) as *const u8; //~ ERROR non-scalar
-
-    let _ = v as f32;
-    //~^ ERROR casting
-    let _ = main as f64;
-    //~^ ERROR casting
-    let _ = &v as usize;
-    //~^ ERROR casting
-    //~^^ HELP through a raw pointer first
-    let _ = f as *const u8;
-    //~^ ERROR casting
-    let _ = 3_i32 as bool;
-    //~^ ERROR cannot cast as `bool` [E0054]
-    //~| unsupported cast
-    //~| HELP compare with zero
-    let _ = E::A as bool;
-    //~^ ERROR cannot cast as `bool` [E0054]
-    //~| unsupported cast
-    //~| HELP compare with zero
-    let _ = 0x61u32 as char; //~ ERROR only `u8` can be cast
-
-    let _ = false as f32;
-    //~^ ERROR casting
-    //~^^ HELP through an integer first
-    let _ = E::A as f32;
-    //~^ ERROR casting
-    //~^^ HELP through an integer first
-    let _ = 'a' as f32;
-    //~^ ERROR casting
-    //~^^ HELP through an integer first
-
-    let _ = false as *const u8;
-    //~^ ERROR casting
-    let _ = E::A as *const u8;
-    //~^ ERROR casting
-    let _ = 'a' as *const u8;
-    //~^ ERROR casting
-
-    let _ = 42usize as *const [u8]; //~ ERROR casting
-    let _ = v as *const [u8]; //~ ERROR cannot cast
-    let _ = fat_v as *const Foo;
-    //~^ ERROR the trait bound `[u8]: std::marker::Sized` is not satisfied
-    //~| NOTE the trait `std::marker::Sized` is not implemented for `[u8]`
-    //~| NOTE `[u8]` does not have a constant size known at compile-time
-    //~| NOTE required for the cast to the object type `Foo`
-    let _ = foo as *const str; //~ ERROR casting
-    let _ = foo as *mut str; //~ ERROR casting
-    let _ = main as *mut str; //~ ERROR casting
-    let _ = &f as *mut f32; //~ ERROR casting
-    let _ = &f as *const f64; //~ ERROR casting
-    let _ = fat_sv as usize;
-    //~^ ERROR casting
-    //~^^ HELP through a thin pointer first
-
-    let a : *const str = "hello";
-    let _ = a as *const Foo;
-    //~^ ERROR the trait bound `str: std::marker::Sized` is not satisfied
-    //~| NOTE the trait `std::marker::Sized` is not implemented for `str`
-    //~| NOTE `str` does not have a constant size known at compile-time
-    //~| NOTE required for the cast to the object type `Foo`
-
-    // check no error cascade
-    let _ = main.f as *const u32; //~ no field `f` on type `fn() {main}`
-
-    let cf: *const Foo = &0;
-    let _ = cf as *const [u16];
-    //~^ ERROR casting
-    //~^^ NOTE vtable kinds
-    let _ = cf as *const Bar;
-    //~^ ERROR casting
-    //~^^ NOTE vtable kinds
-
-    vec![0.0].iter().map(|s| s as f32).collect::<Vec<f32>>();
-    //~^ ERROR casting `&{float}` as `f32` is invalid
-    //~| NOTE cannot cast `&{float}` as `f32`
-    //~| NOTE did you mean `*s`?
-}
diff --git a/src/test/compile-fail/class-missing-self.rs b/src/test/compile-fail/class-missing-self.rs
index ab76af1cbe6..cab46ec1fbf 100644
--- a/src/test/compile-fail/class-missing-self.rs
+++ b/src/test/compile-fail/class-missing-self.rs
@@ -16,8 +16,8 @@ impl cat {
     fn sleep(&self) { loop{} }
     fn meow(&self) {
       println!("Meow");
-      meows += 1; //~ ERROR unresolved name
-      sleep();     //~ ERROR unresolved name
+      meows += 1; //~ ERROR unresolved value `meows`
+      sleep();     //~ ERROR unresolved function `sleep`
     }
 
 }
diff --git a/src/test/compile-fail/coherence-error-suppression.rs b/src/test/compile-fail/coherence-error-suppression.rs
index b33f27fbc8a..7c7782b9b44 100644
--- a/src/test/compile-fail/coherence-error-suppression.rs
+++ b/src/test/compile-fail/coherence-error-suppression.rs
@@ -16,7 +16,7 @@ impl Foo for i8 {}
 impl Foo for i16 {}
 impl Foo for i32 {}
 impl Foo for i64 {}
-impl Foo for DoesNotExist {} //~ ERROR `DoesNotExist` is undefined
+impl Foo for DoesNotExist {} //~ ERROR unresolved type `DoesNotExist`
 impl Foo for u8 {}
 impl Foo for u16 {}
 impl Foo for u32 {}
diff --git a/src/test/compile-fail/derived-errors/issue-31997.rs b/src/test/compile-fail/derived-errors/issue-31997.rs
index cf283f6d3e4..2a294a4e31f 100644
--- a/src/test/compile-fail/derived-errors/issue-31997.rs
+++ b/src/test/compile-fail/derived-errors/issue-31997.rs
@@ -20,7 +20,7 @@ fn closure<F, T>(x: F) -> Result<T, ()>
 }
 
 fn foo() -> Result<(), ()> {
-    try!(closure(|| bar(0 as *mut _))); //~ ERROR unresolved name `bar`
+    try!(closure(|| bar(0 as *mut _))); //~ ERROR unresolved function `bar`
     Ok(())
 }
 
diff --git a/src/test/compile-fail/does-nothing.rs b/src/test/compile-fail/does-nothing.rs
index c0cd406f062..96e14d2fb22 100644
--- a/src/test/compile-fail/does-nothing.rs
+++ b/src/test/compile-fail/does-nothing.rs
@@ -8,5 +8,5 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: unresolved name `this_does_nothing_what_the`
 fn main() { println!("doing"); this_does_nothing_what_the; println!("boing"); }
+//~^ ERROR unresolved value `this_does_nothing_what_the`
diff --git a/src/test/compile-fail/empty-struct-braces-expr.rs b/src/test/compile-fail/empty-struct-braces-expr.rs
index 1c86af30c79..d4e85e9744d 100644
--- a/src/test/compile-fail/empty-struct-braces-expr.rs
+++ b/src/test/compile-fail/empty-struct-braces-expr.rs
@@ -22,13 +22,13 @@ enum E {
 }
 
 fn main() {
-    let e1 = Empty1; //~ ERROR `Empty1` is the name of a struct or struct variant
-    let e1 = Empty1(); //~ ERROR `Empty1` is the name of a struct or struct variant
-    let e3 = E::Empty3; //~ ERROR `E::Empty3` is the name of a struct or struct variant
-    let e3 = E::Empty3(); //~ ERROR `E::Empty3` is the name of a struct or struct variant
+    let e1 = Empty1; //~ ERROR expected value, found struct `Empty1`
+    let e1 = Empty1(); //~ ERROR expected function, found struct `Empty1`
+    let e3 = E::Empty3; //~ ERROR expected value, found struct variant `E::Empty3`
+    let e3 = E::Empty3(); //~ ERROR expected function, found struct variant `E::Empty3`
 
-    let xe1 = XEmpty1; //~ ERROR `XEmpty1` is the name of a struct or struct variant
-    let xe1 = XEmpty1(); //~ ERROR `XEmpty1` is the name of a struct or struct variant
+    let xe1 = XEmpty1; //~ ERROR expected value, found struct `XEmpty1`
+    let xe1 = XEmpty1(); //~ ERROR expected function, found struct `XEmpty1`
     let xe3 = XE::Empty3; //~ ERROR no associated item named `Empty3` found for type
     let xe3 = XE::Empty3(); //~ ERROR no associated item named `Empty3` found for type
 }
diff --git a/src/test/compile-fail/empty-struct-braces-pat-2.rs b/src/test/compile-fail/empty-struct-braces-pat-2.rs
index 4349e72c5d7..d3b13457dc6 100644
--- a/src/test/compile-fail/empty-struct-braces-pat-2.rs
+++ b/src/test/compile-fail/empty-struct-braces-pat-2.rs
@@ -22,15 +22,15 @@ fn main() {
     let xe1 = XEmpty1 {};
 
     match e1 {
-        Empty1() => () //~ ERROR unresolved tuple struct/variant `Empty1`
+        Empty1() => () //~ ERROR expected tuple struct/variant, found struct `Empty1`
     }
     match xe1 {
-        XEmpty1() => () //~ ERROR unresolved tuple struct/variant `XEmpty1`
+        XEmpty1() => () //~ ERROR expected tuple struct/variant, found struct `XEmpty1`
     }
     match e1 {
-        Empty1(..) => () //~ ERROR unresolved tuple struct/variant `Empty1`
+        Empty1(..) => () //~ ERROR expected tuple struct/variant, found struct `Empty1`
     }
     match xe1 {
-        XEmpty1(..) => () //~ ERROR unresolved tuple struct/variant `XEmpty1`
+        XEmpty1(..) => () //~ ERROR expected tuple struct/variant, found struct `XEmpty1`
     }
 }
diff --git a/src/test/compile-fail/enum-variant-type-2.rs b/src/test/compile-fail/enum-variant-type-2.rs
index eef4bea1df1..258bfd1e3ba 100644
--- a/src/test/compile-fail/enum-variant-type-2.rs
+++ b/src/test/compile-fail/enum-variant-type-2.rs
@@ -14,6 +14,6 @@ enum Foo {
     Bar
 }
 
-fn foo(x: Foo::Bar) {} //~ERROR found value `Foo::Bar` used as a type
+fn foo(x: Foo::Bar) {} //~ ERROR expected type, found variant `Foo::Bar`
 
 fn main() {}
diff --git a/src/test/compile-fail/export-fully-qualified.rs b/src/test/compile-fail/export-fully-qualified.rs
index 166ef7ab87f..19fa13f8377 100644
--- a/src/test/compile-fail/export-fully-qualified.rs
+++ b/src/test/compile-fail/export-fully-qualified.rs
@@ -8,14 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: failed to resolve. Use of undeclared type or module `foo`
-
 // In this test baz isn't resolved when called as foo.baz even though
 // it's called from inside foo. This is somewhat surprising and may
 // want to change eventually.
 
 mod foo {
-    pub fn bar() { foo::baz(); }
+    pub fn bar() { foo::baz(); } //~ ERROR failed to resolve. Use of undeclared type or module `foo`
 
     fn baz() { }
 }
diff --git a/src/test/compile-fail/export.rs b/src/test/compile-fail/export.rs
index 3a391e7c609..a412cac699f 100644
--- a/src/test/compile-fail/export.rs
+++ b/src/test/compile-fail/export.rs
@@ -8,10 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: unresolved name
 mod foo {
     pub fn x(y: isize) { log(debug, y); }
+    //~^ ERROR unresolved function `log`
+    //~| ERROR unresolved value `debug`
     fn z(y: isize) { log(debug, y); }
+    //~^ ERROR unresolved function `log`
+    //~| ERROR unresolved value `debug`
 }
 
-fn main() { foo::z(10); }
+fn main() { foo::z(10); } //~ ERROR function `z` is private
diff --git a/src/test/compile-fail/export2.rs b/src/test/compile-fail/export2.rs
index f7b1400aa45..dc96ce7f504 100644
--- a/src/test/compile-fail/export2.rs
+++ b/src/test/compile-fail/export2.rs
@@ -8,10 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: failed to resolve. Use of undeclared type or module `bar`
-
 mod foo {
-    pub fn x() { bar::x(); }
+    pub fn x() { bar::x(); } //~ ERROR failed to resolve. Use of undeclared type or module `bar`
 }
 
 mod bar {
diff --git a/src/test/compile-fail/extern-with-type-bounds.rs b/src/test/compile-fail/extern-with-type-bounds.rs
index d8bdd5974c7..0f8ad8d5388 100644
--- a/src/test/compile-fail/extern-with-type-bounds.rs
+++ b/src/test/compile-fail/extern-with-type-bounds.rs
@@ -24,7 +24,7 @@ extern "rust-intrinsic" {
 
     // Unresolved bounds should still error.
     fn align_of<T: NoSuchTrait>() -> usize;
-    //~^ ERROR trait `NoSuchTrait` is not in scope
+    //~^ ERROR unresolved trait `NoSuchTrait`
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/for-expn.rs b/src/test/compile-fail/for-expn.rs
index 43776d75a47..a051789ec98 100644
--- a/src/test/compile-fail/for-expn.rs
+++ b/src/test/compile-fail/for-expn.rs
@@ -13,7 +13,7 @@
 fn main() {
     // Odd formatting to make sure we get the right span.
     for t in &
-      foo //~ ERROR unresolved name `foo`
+      foo //~ ERROR unresolved value `foo`
     {
     }
 }
diff --git a/src/test/compile-fail/for-loop-hygiene.rs b/src/test/compile-fail/for-loop-hygiene.rs
index f06882875fd..2135ad6e73c 100644
--- a/src/test/compile-fail/for-loop-hygiene.rs
+++ b/src/test/compile-fail/for-loop-hygiene.rs
@@ -13,6 +13,6 @@
 
 fn main() {
     for _ in 0..10 {
-        iter.next();  //~ error: unresolved name `iter`
+        iter.next();  //~ ERROR unresolved value `iter`
     }
 }
diff --git a/src/test/compile-fail/glob-resolve1.rs b/src/test/compile-fail/glob-resolve1.rs
index 1e5662aa172..58e67796586 100644
--- a/src/test/compile-fail/glob-resolve1.rs
+++ b/src/test/compile-fail/glob-resolve1.rs
@@ -29,13 +29,13 @@ mod bar {
 fn foo<T>() {}
 
 fn main() {
-    fpriv(); //~ ERROR: unresolved
-    epriv(); //~ ERROR: unresolved
-    B; //~ ERROR: unresolved
-    C; //~ ERROR: unresolved
-    import(); //~ ERROR: unresolved
-
-    foo::<A>(); //~ ERROR: not in scope
-    foo::<C>(); //~ ERROR: not in scope
-    foo::<D>(); //~ ERROR: not in scope
+    fpriv(); //~ ERROR unresolved function `fpriv`
+    epriv(); //~ ERROR unresolved function `epriv`
+    B; //~ ERROR expected value, found enum `B`
+    C; //~ ERROR unresolved value `C`
+    import(); //~ ERROR: unresolved function `import`
+
+    foo::<A>(); //~ ERROR: unresolved type `A`
+    foo::<C>(); //~ ERROR: unresolved type `C`
+    foo::<D>(); //~ ERROR: unresolved type `D`
 }
diff --git a/src/test/compile-fail/import-glob-0.rs b/src/test/compile-fail/import-glob-0.rs
index 21aa811ea71..12e45cfa2cb 100644
--- a/src/test/compile-fail/import-glob-0.rs
+++ b/src/test/compile-fail/import-glob-0.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: unresolved name
-
 use module_of_many_things::*;
 
 mod module_of_many_things {
@@ -23,6 +21,6 @@ mod module_of_many_things {
 fn main() {
     f1();
     f2();
-    f999(); // 'export' currently doesn't work?
+    f999(); //~ ERROR unresolved function `f999`
     f4();
 }
diff --git a/src/test/compile-fail/imports/rfc-1560-warning-cycle.rs b/src/test/compile-fail/imports/rfc-1560-warning-cycle.rs
new file mode 100644
index 00000000000..bed10c87ae1
--- /dev/null
+++ b/src/test/compile-fail/imports/rfc-1560-warning-cycle.rs
@@ -0,0 +1,30 @@
+// 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(rustc_attrs)]
+#![allow(unused)]
+
+pub struct Foo;
+
+mod bar {
+    struct Foo;
+
+    mod baz {
+        use *; //~ NOTE `Foo` could resolve to the name imported here
+        use bar::*; //~ NOTE `Foo` could also resolve to the name imported here
+        fn f(_: Foo) {}
+        //~^ WARN `Foo` is ambiguous
+        //~| WARN hard error in a future release
+        //~| NOTE see issue #38260
+    }
+}
+
+#[rustc_error]
+fn main() {} //~ ERROR compilation successful
diff --git a/src/test/compile-fail/issue-14254.rs b/src/test/compile-fail/issue-14254.rs
deleted file mode 100644
index c7bd343bc9a..00000000000
--- a/src/test/compile-fail/issue-14254.rs
+++ /dev/null
@@ -1,137 +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.
-
-trait Foo {
-    fn bar(&self);
-    fn baz(&self) { }
-    fn bah(_: Option<&Self>) { }
-}
-
-struct BarTy {
-    x : isize,
-    y : f64,
-}
-
-impl BarTy {
-    fn a() {}
-    fn b(&self) {}
-}
-
-impl Foo for *const BarTy {
-    fn bar(&self) {
-        baz();
-        //~^ ERROR: unresolved name `baz`
-        //~| NOTE did you mean to call `self.baz`?
-        a;
-        //~^ ERROR: unresolved name `a`
-        //~| NOTE unresolved name
-    }
-}
-
-impl<'a> Foo for &'a BarTy {
-    fn bar(&self) {
-        baz();
-        //~^ ERROR: unresolved name `baz`
-        //~| NOTE did you mean to call `self.baz`?
-        x;
-        //~^ ERROR: unresolved name `x`
-        //~| NOTE did you mean `self.x`?
-        y;
-        //~^ ERROR: unresolved name `y`
-        //~| NOTE did you mean `self.y`?
-        a;
-        //~^ ERROR: unresolved name `a`
-        //~| NOTE unresolved name
-        bah;
-        //~^ ERROR: unresolved name `bah`
-        //~| NOTE did you mean to call `Foo::bah`?
-        b;
-        //~^ ERROR: unresolved name `b`
-        //~| NOTE unresolved name
-    }
-}
-
-impl<'a> Foo for &'a mut BarTy {
-    fn bar(&self) {
-        baz();
-        //~^ ERROR: unresolved name `baz`
-        //~| NOTE did you mean to call `self.baz`?
-        x;
-        //~^ ERROR: unresolved name `x`
-        //~| NOTE did you mean `self.x`?
-        y;
-        //~^ ERROR: unresolved name `y`
-        //~| NOTE did you mean `self.y`?
-        a;
-        //~^ ERROR: unresolved name `a`
-        //~| NOTE unresolved name
-        bah;
-        //~^ ERROR: unresolved name `bah`
-        //~| NOTE did you mean to call `Foo::bah`?
-        b;
-        //~^ ERROR: unresolved name `b`
-        //~| NOTE unresolved name
-    }
-}
-
-impl Foo for Box<BarTy> {
-    fn bar(&self) {
-        baz();
-        //~^ ERROR: unresolved name `baz`
-        //~| NOTE did you mean to call `self.baz`?
-        bah;
-        //~^ ERROR: unresolved name `bah`
-        //~| NOTE did you mean to call `Foo::bah`?
-    }
-}
-
-impl Foo for *const isize {
-    fn bar(&self) {
-        baz();
-        //~^ ERROR: unresolved name `baz`
-        //~| NOTE did you mean to call `self.baz`?
-        bah;
-        //~^ ERROR: unresolved name `bah`
-        //~| NOTE did you mean to call `Foo::bah`?
-    }
-}
-
-impl<'a> Foo for &'a isize {
-    fn bar(&self) {
-        baz();
-        //~^ ERROR: unresolved name `baz`
-        //~| NOTE did you mean to call `self.baz`?
-        bah;
-        //~^ ERROR: unresolved name `bah`
-        //~| NOTE did you mean to call `Foo::bah`?
-    }
-}
-
-impl<'a> Foo for &'a mut isize {
-    fn bar(&self) {
-        baz();
-        //~^ ERROR: unresolved name `baz`
-        //~| NOTE did you mean to call `self.baz`?
-        bah;
-        //~^ ERROR: unresolved name `bah`
-        //~| NOTE did you mean to call `Foo::bah`?
-    }
-}
-
-impl Foo for Box<isize> {
-    fn bar(&self) {
-        baz();
-        //~^ ERROR: unresolved name `baz`
-        //~| NOTE did you mean to call `self.baz`?
-        bah;
-        //~^ ERROR: unresolved name `bah`
-        //~| NOTE did you mean to call `Foo::bah`?
-    }
-}
diff --git a/src/test/compile-fail/issue-1476.rs b/src/test/compile-fail/issue-1476.rs
index 73a0e0c0775..b7797cf5b36 100644
--- a/src/test/compile-fail/issue-1476.rs
+++ b/src/test/compile-fail/issue-1476.rs
@@ -9,5 +9,5 @@
 // except according to those terms.
 
 fn main() {
-    println!("{}", x); //~ ERROR unresolved name `x`
+    println!("{}", x); //~ ERROR unresolved value `x`
 }
diff --git a/src/test/compile-fail/issue-15167.rs b/src/test/compile-fail/issue-15167.rs
index 2bd7da91d2c..4e77636b379 100644
--- a/src/test/compile-fail/issue-15167.rs
+++ b/src/test/compile-fail/issue-15167.rs
@@ -11,10 +11,10 @@
 // macro f should not be able to inject a reference to 'n'.
 
 macro_rules! f { () => (n) }
-//~^ ERROR unresolved name `n`
-//~| ERROR unresolved name `n`
-//~| ERROR unresolved name `n`
-//~| ERROR unresolved name `n`
+//~^ ERROR unresolved value `n`
+//~| ERROR unresolved value `n`
+//~| ERROR unresolved value `n`
+//~| ERROR unresolved value `n`
 
 fn main() -> (){
     for n in 0..1 {
diff --git a/src/test/compile-fail/issue-17546.rs b/src/test/compile-fail/issue-17546.rs
index e640ba3f00f..fe125b973d9 100644
--- a/src/test/compile-fail/issue-17546.rs
+++ b/src/test/compile-fail/issue-17546.rs
@@ -20,7 +20,7 @@ mod foo {
     }
 
     fn new() -> NoResult<MyEnum, String> {
-        //~^ ERROR: found value `foo::MyEnum::NoResult` used as a type
+        //~^ ERROR expected type, found variant `NoResult`
         unimplemented!()
     }
 }
@@ -30,18 +30,18 @@ mod bar {
     use foo;
 
     fn new() -> Result<foo::MyEnum, String> {
-        //~^ ERROR: found value `foo::MyEnum::Result` used as a type
+        //~^ ERROR expected type, found variant `Result`
         unimplemented!()
     }
 }
 
 fn new() -> Result<foo::MyEnum, String> {
-    //~^ ERROR: found value `foo::MyEnum::Result` used as a type
+    //~^ ERROR expected type, found variant `Result`
     unimplemented!()
 }
 
 fn newer() -> NoResult<foo::MyEnum, String> {
-    //~^ ERROR: found value `foo::MyEnum::NoResult` used as a type
+    //~^ ERROR expected type, found variant `NoResult`
     unimplemented!()
 }
 
diff --git a/src/test/compile-fail/issue-18058.rs b/src/test/compile-fail/issue-18058.rs
index 0447cf781ff..1611cc418fb 100644
--- a/src/test/compile-fail/issue-18058.rs
+++ b/src/test/compile-fail/issue-18058.rs
@@ -9,6 +9,6 @@
 // except according to those terms.
 
 impl Undefined {}
-//~^ ERROR type name `Undefined` is undefined or not in scope
+//~^ ERROR unresolved type `Undefined`
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-18119.rs b/src/test/compile-fail/issue-18119.rs
index f06496463e4..412f7566f47 100644
--- a/src/test/compile-fail/issue-18119.rs
+++ b/src/test/compile-fail/issue-18119.rs
@@ -13,10 +13,10 @@ static Y: u8 = 1;
 fn foo() {}
 
 impl X {}
-//~^ ERROR type name `X` is undefined or not in scope
+//~^ ERROR expected type, found constant `X`
 impl Y {}
-//~^ ERROR type name `Y` is undefined or not in scope
+//~^ ERROR expected type, found static `Y`
 impl foo {}
-//~^ ERROR type name `foo` is undefined or not in scope
+//~^ ERROR expected type, found function `foo`
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-19498.rs b/src/test/compile-fail/issue-19498.rs
index 2e2115b7110..88e804fb8aa 100644
--- a/src/test/compile-fail/issue-19498.rs
+++ b/src/test/compile-fail/issue-19498.rs
@@ -11,13 +11,13 @@
 use self::A; //~ NOTE previous import of `A` here
 use self::B; //~ NOTE previous import of `B` here
 mod A {} //~ ERROR a module named `A` has already been imported in this module
-//~| `A` was already imported
+//~| `A` already imported
 pub mod B {} //~ ERROR a module named `B` has already been imported in this module
-//~| `B` was already imported
+//~| `B` already imported
 mod C {
     use C::D; //~ NOTE previous import of `D` here
     mod D {} //~ ERROR a module named `D` has already been imported in this module
-    //~| `D` was already imported
+    //~| `D` already imported
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-19883.rs b/src/test/compile-fail/issue-19883.rs
index 3a7a1692f38..6fc5fa03c58 100644
--- a/src/test/compile-fail/issue-19883.rs
+++ b/src/test/compile-fail/issue-19883.rs
@@ -17,7 +17,7 @@ trait From<Src> {
 trait To: Sized {
     fn to<Dst: From<Self>>(self) ->
         <Dst as From<Self>>::Dst
-        //~^ ERROR associated type `From::Dst` is undefined or not in scope
+        //~^ ERROR unresolved associated type `From::Dst`
     {
         From::from(self)
     }
diff --git a/src/test/compile-fail/issue-22037.rs b/src/test/compile-fail/issue-22037.rs
index 74f1be95420..2a81b55dc7b 100644
--- a/src/test/compile-fail/issue-22037.rs
+++ b/src/test/compile-fail/issue-22037.rs
@@ -11,7 +11,7 @@
 trait A {
     type Output;
     fn a(&self) -> <Self as A>::X;
-//~^ ERROR: associated type `A::X` is undefined or not in scope
+    //~^ ERROR unresolved associated type `A::X`
 }
 
 impl A for u32 {
diff --git a/src/test/compile-fail/issue-22384.rs b/src/test/compile-fail/issue-22384.rs
index 46a43bdfcb8..ad42a7e4a97 100644
--- a/src/test/compile-fail/issue-22384.rs
+++ b/src/test/compile-fail/issue-22384.rs
@@ -14,5 +14,5 @@ trait Trait {
 
 fn main() {
     <<i32 as Copy>::foobar as Trait>::foo();
-    //~^ ERROR associated type `Copy::foobar` is undefined or not in scope
+    //~^ ERROR unresolved associated type `Copy::foobar`
 }
diff --git a/src/test/compile-fail/issue-2281-part1.rs b/src/test/compile-fail/issue-2281-part1.rs
index f59252dd315..8d21650ed6f 100644
--- a/src/test/compile-fail/issue-2281-part1.rs
+++ b/src/test/compile-fail/issue-2281-part1.rs
@@ -8,6 +8,4 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: unresolved name `foobar`
-
-fn main() { println!("{}", foobar); }
+fn main() { println!("{}", foobar); } //~ ERROR unresolved value `foobar`
diff --git a/src/test/compile-fail/issue-2330.rs b/src/test/compile-fail/issue-2330.rs
index 63f146a21d9..f1a282695ac 100644
--- a/src/test/compile-fail/issue-2330.rs
+++ b/src/test/compile-fail/issue-2330.rs
@@ -15,7 +15,7 @@ trait channel<T> {
 }
 
 // `chan` is not a trait, it's an enum
-impl chan for isize { //~ ERROR `chan` is not a trait
+impl chan for isize { //~ ERROR expected trait, found enum `chan`
     fn send(&self, v: isize) { panic!() }
 }
 
diff --git a/src/test/compile-fail/issue-2356.rs b/src/test/compile-fail/issue-2356.rs
deleted file mode 100644
index d7635d7bc94..00000000000
--- a/src/test/compile-fail/issue-2356.rs
+++ /dev/null
@@ -1,109 +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.
-
-trait Groom {
-    fn shave(other: usize);
-}
-
-pub struct cat {
-  whiskers: isize,
-}
-
-pub enum MaybeDog {
-    Dog,
-    NoDog
-}
-
-impl MaybeDog {
-  fn bark() {
-    // If this provides a suggestion, it's a bug as MaybeDog doesn't impl Groom
-    shave();
-    //~^ ERROR: unresolved name `shave`
-    //~| NOTE unresolved name
-  }
-}
-
-impl Groom for cat {
-  fn shave(other: usize) {
-    whiskers -= other;
-    //~^ ERROR: unresolved name `whiskers`
-    //~| NOTE unresolved name
-    //~| HELP this is an associated function
-    shave(4);
-    //~^ ERROR: unresolved name `shave`
-    //~| NOTE did you mean to call `Groom::shave`?
-    purr();
-    //~^ ERROR: unresolved name `purr`
-    //~| NOTE unresolved name
-  }
-}
-
-impl cat {
-    fn static_method() {}
-
-    fn purr_louder() {
-        static_method();
-        //~^ ERROR: unresolved name `static_method`
-        //~| NOTE unresolved name
-        purr();
-        //~^ ERROR: unresolved name `purr`
-        //~| NOTE unresolved name
-        purr();
-        //~^ ERROR: unresolved name `purr`
-        //~| NOTE unresolved name
-        purr();
-        //~^ ERROR: unresolved name `purr`
-        //~| NOTE unresolved name
-    }
-}
-
-impl cat {
-  fn meow() {
-    if self.whiskers > 3 {
-        //~^ ERROR `self` is not available in a static method [E0424]
-        //~| NOTE not available in static method
-        //~| NOTE maybe a `self` argument is missing?
-        println!("MEOW");
-    }
-  }
-
-  fn purr(&self) {
-    grow_older();
-    //~^ ERROR: unresolved name `grow_older`
-    //~| NOTE unresolved name
-    shave();
-    //~^ ERROR: unresolved name `shave`
-    //~| NOTE unresolved name
-  }
-
-  fn burn_whiskers(&mut self) {
-    whiskers = 0;
-    //~^ ERROR: unresolved name `whiskers`
-    //~| NOTE did you mean `self.whiskers`?
-  }
-
-  pub fn grow_older(other:usize) {
-    whiskers = 4;
-    //~^ ERROR: unresolved name `whiskers`
-    //~| NOTE unresolved name
-    //~| HELP this is an associated function
-    purr_louder();
-    //~^ ERROR: unresolved name `purr_louder`
-    //~| NOTE unresolved name
-  }
-}
-
-fn main() {
-    self += 1;
-    //~^ ERROR: unresolved name `self`
-    //~| NOTE unresolved name
-    //~| HELP: module `self`
-    // it's a bug if this suggests a missing `self` as we're not in a method
-}
diff --git a/src/test/compile-fail/issue-24081.rs b/src/test/compile-fail/issue-24081.rs
index 188716c5e93..26bb72b862f 100644
--- a/src/test/compile-fail/issue-24081.rs
+++ b/src/test/compile-fail/issue-24081.rs
@@ -15,14 +15,14 @@ use std::ops::Div; //~ NOTE previous import
 use std::ops::Rem; //~ NOTE previous import
 
 type Add = bool; //~ ERROR a trait named `Add` has already been imported in this module
-//~| was already imported
+//~| `Add` already imported
 struct Sub { x: f32 } //~ ERROR a trait named `Sub` has already been imported in this module
-//~| was already imported
+//~| `Sub` already imported
 enum Mul { A, B } //~ ERROR a trait named `Mul` has already been imported in this module
-//~| was already imported
+//~| `Mul` already imported
 mod Div { } //~ ERROR a trait named `Div` has already been imported in this module
-//~| was already imported
+//~| `Div` already imported
 trait Rem {  } //~ ERROR a trait named `Rem` has already been imported in this module
-//~| was already imported
+//~| `Rem` already imported
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-28388-1.rs b/src/test/compile-fail/issue-28388-1.rs
index ed7851ec0f1..334fdee00a0 100644
--- a/src/test/compile-fail/issue-28388-1.rs
+++ b/src/test/compile-fail/issue-28388-1.rs
@@ -10,8 +10,6 @@
 
 // Prefix in imports with empty braces should be resolved and checked privacy, stability, etc.
 
-use foo::{};
-//~^ ERROR failed to resolve. Maybe a missing `extern crate foo;`?
-//~| NOTE foo
+use foo::{}; //~ ERROR unresolved module or enum `foo`
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-28388-3.rs b/src/test/compile-fail/issue-28388-3.rs
index 4baaa16e772..12357779b51 100644
--- a/src/test/compile-fail/issue-28388-3.rs
+++ b/src/test/compile-fail/issue-28388-3.rs
@@ -14,8 +14,7 @@
 
 extern crate lint_stability;
 
-use lint_stability::UnstableStruct::{};
-//~^ ERROR use of unstable library feature 'test_feature'
-use lint_stability::StableStruct::{}; // OK
+use lint_stability::UnstableEnum::{}; //~ ERROR use of unstable library feature 'test_feature'
+use lint_stability::StableEnum::{}; // OK
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-30535.rs b/src/test/compile-fail/issue-30535.rs
index 93f3086d057..90f5220a623 100644
--- a/src/test/compile-fail/issue-30535.rs
+++ b/src/test/compile-fail/issue-30535.rs
@@ -13,7 +13,7 @@
 extern crate issue_30535 as foo;
 
 fn bar(
-    _: foo::Foo::FooV //~ ERROR value `foo::Foo::FooV` used as a type
+    _: foo::Foo::FooV //~ ERROR expected type, found variant `foo::Foo::FooV`
 ) {}
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-30589.rs b/src/test/compile-fail/issue-30589.rs
index 32765d5acb4..dd5fac9bed1 100644
--- a/src/test/compile-fail/issue-30589.rs
+++ b/src/test/compile-fail/issue-30589.rs
@@ -10,7 +10,7 @@
 
 use std::fmt;
 
-impl fmt::Display for DecoderError { //~ ERROR E0412
+impl fmt::Display for DecoderError { //~ ERROR unresolved type `DecoderError`
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "Missing data: {}", self.0)
     }
diff --git a/src/test/compile-fail/issue-31845.rs b/src/test/compile-fail/issue-31845.rs
index 344a1117254..32e004af1f3 100644
--- a/src/test/compile-fail/issue-31845.rs
+++ b/src/test/compile-fail/issue-31845.rs
@@ -14,7 +14,7 @@ fn f() {
     fn g() {}
     mod foo {
         fn h() {
-           g(); //~ ERROR unresolved name
+           g(); //~ ERROR unresolved function `g`
         }
     }
 }
diff --git a/src/test/compile-fail/issue-32119.rs b/src/test/compile-fail/issue-32119.rs
index 4743b779ef6..e630a01a593 100644
--- a/src/test/compile-fail/issue-32119.rs
+++ b/src/test/compile-fail/issue-32119.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![feature(rustc_attrs)]
+#![allow(dead_code)]
 
 pub type T = ();
 mod foo { pub use super::T; }
diff --git a/src/test/compile-fail/issue-34334.rs b/src/test/compile-fail/issue-34334.rs
index ffcd052369d..fa672557c5e 100644
--- a/src/test/compile-fail/issue-34334.rs
+++ b/src/test/compile-fail/issue-34334.rs
@@ -11,5 +11,5 @@
 fn main () {
     let sr: Vec<(u32, _, _) = vec![]; //~ ERROR expected one of `+`, `,`, or `>`, found `=`
     let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
-    //~^ ERROR unresolved name `sr`
+    //~^ ERROR unresolved value `sr`
 }
diff --git a/src/test/compile-fail/issue-35075.rs b/src/test/compile-fail/issue-35075.rs
index a70452dcbd0..39d06312aa7 100644
--- a/src/test/compile-fail/issue-35075.rs
+++ b/src/test/compile-fail/issue-35075.rs
@@ -9,11 +9,11 @@
 // except according to those terms.
 
 struct Bar<T> {
-    inner: Foo<T> //~ ERROR type name `Foo` is undefined or not in scope
+    inner: Foo<T> //~ ERROR unresolved type `Foo`
 }
 
 enum Baz<T> {
-    Foo(Foo<T>) //~ ERROR type name `Foo` is undefined or not in scope
+    Foo(Foo<T>) //~ ERROR unresolved type `Foo`
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-37534.rs b/src/test/compile-fail/issue-37534.rs
index eb676601e89..1a6d92166d7 100644
--- a/src/test/compile-fail/issue-37534.rs
+++ b/src/test/compile-fail/issue-37534.rs
@@ -9,8 +9,8 @@
 // except according to those terms.
 
 struct Foo<T: ?Hash> { }
-//~^ ERROR trait `Hash` is not in scope [E0405]
-//~^^ ERROR parameter `T` is never used [E0392]
+//~^ ERROR unresolved trait `Hash`
+//~^^ ERROR parameter `T` is never used
 //~^^^ WARN default bound relaxed for a type parameter, but this does nothing
 
 fn main() { }
diff --git a/src/test/compile-fail/issue-38458.rs b/src/test/compile-fail/issue-38458.rs
new file mode 100644
index 00000000000..56eb5f874cd
--- /dev/null
+++ b/src/test/compile-fail/issue-38458.rs
@@ -0,0 +1,15 @@
+// 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 x: () = {
+    return; //~ ERROR return statement outside of function body
+};
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-4366-2.rs b/src/test/compile-fail/issue-4366-2.rs
index a6fe719509c..687720a130c 100644
--- a/src/test/compile-fail/issue-4366-2.rs
+++ b/src/test/compile-fail/issue-4366-2.rs
@@ -23,7 +23,7 @@ mod a {
     pub mod sub {
         use a::b::*;
         fn sub() -> bar { 1 }
-        //~^ ERROR: type name `bar` is undefined or not in scope
+        //~^ ERROR unresolved type `bar`
     }
 }
 
@@ -32,5 +32,5 @@ mod m1 {
 }
 
 fn main() {
-    foo(); //~ ERROR: unresolved name
+    foo(); //~ ERROR expected function, found module `foo`
 }
diff --git a/src/test/compile-fail/issue-4366.rs b/src/test/compile-fail/issue-4366.rs
index 5625ac00c85..18e55ee3c2a 100644
--- a/src/test/compile-fail/issue-4366.rs
+++ b/src/test/compile-fail/issue-4366.rs
@@ -25,7 +25,7 @@ mod a {
     }
     pub mod sub {
         use a::b::*;
-        fn sub() -> isize { foo(); 1 } //~ ERROR: unresolved name `foo`
+        fn sub() -> isize { foo(); 1 } //~ ERROR unresolved function `foo`
     }
 }
 
diff --git a/src/test/compile-fail/issue-5099.rs b/src/test/compile-fail/issue-5099.rs
index c2e1fc615cc..e78b54bd411 100644
--- a/src/test/compile-fail/issue-5099.rs
+++ b/src/test/compile-fail/issue-5099.rs
@@ -9,6 +9,6 @@
 // except according to those terms.
 
 
-trait B < A > { fn a() -> A { this.a } } //~ ERROR unresolved name
+trait B < A > { fn a() -> A { this.a } } //~ ERROR unresolved value `this`
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-5927.rs b/src/test/compile-fail/issue-5927.rs
index 7668a2117a2..c421dbd1eb3 100644
--- a/src/test/compile-fail/issue-5927.rs
+++ b/src/test/compile-fail/issue-5927.rs
@@ -12,7 +12,7 @@
 fn main() {
     let z = match 3 {
         x(1) => x(1) //~ ERROR unresolved tuple struct/variant `x`
-        //~^ ERROR unresolved name `x`
+        //~^ ERROR unresolved function `x`
     };
     assert!(z == 3);
 }
diff --git a/src/test/compile-fail/issue-7607-1.rs b/src/test/compile-fail/issue-7607-1.rs
index 96ac2de1762..e7b7decbdb0 100644
--- a/src/test/compile-fail/issue-7607-1.rs
+++ b/src/test/compile-fail/issue-7607-1.rs
@@ -12,7 +12,7 @@ struct Foo {
     x: isize
 }
 
-impl Fo { //~ ERROR type name `Fo` is undefined or not in scope
+impl Fo { //~ ERROR unresolved type `Fo`
     fn foo() {}
 }
 
diff --git a/src/test/compile-fail/issue-8767.rs b/src/test/compile-fail/issue-8767.rs
index 1c97c0c886d..318eab92252 100644
--- a/src/test/compile-fail/issue-8767.rs
+++ b/src/test/compile-fail/issue-8767.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-impl B { //~ ERROR type name `B` is undefined or not in scope
+impl B { //~ ERROR unresolved type `B`
 }
 
 fn main() {
diff --git a/src/test/compile-fail/keyword-super-as-identifier.rs b/src/test/compile-fail/keyword-super-as-identifier.rs
index 531705563e2..62649ba8a0f 100644
--- a/src/test/compile-fail/keyword-super-as-identifier.rs
+++ b/src/test/compile-fail/keyword-super-as-identifier.rs
@@ -9,5 +9,5 @@
 // except according to those terms.
 
 fn main() {
-    let super = "foo"; //~ ERROR unresolved unit struct/variant or constant `super`
+    let super = "foo"; //~ ERROR failed to resolve. There are too many initial `super`s
 }
diff --git a/src/test/compile-fail/keyword-super.rs b/src/test/compile-fail/keyword-super.rs
index 9ac9e800c84..02047bd639f 100644
--- a/src/test/compile-fail/keyword-super.rs
+++ b/src/test/compile-fail/keyword-super.rs
@@ -9,5 +9,5 @@
 // except according to those terms.
 
 fn main() {
-    let super: isize; //~ ERROR unresolved unit struct/variant or constant `super`
+    let super: isize; //~ ERROR failed to resolve. There are too many initial `super`s
 }
diff --git a/src/test/compile-fail/lint-dead-code-type-alias.rs b/src/test/compile-fail/lint-dead-code-type-alias.rs
new file mode 100644
index 00000000000..aaa01aa6bbe
--- /dev/null
+++ b/src/test/compile-fail/lint-dead-code-type-alias.rs
@@ -0,0 +1,20 @@
+// 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.
+
+#![deny(dead_code)]
+
+type Used = u8;
+type Unused = u8; //~ ERROR type alias is never used
+
+fn id(x: Used) -> Used { x }
+
+fn main() {
+    id(0);
+}
diff --git a/src/test/compile-fail/macro-outer-attributes.rs b/src/test/compile-fail/macro-outer-attributes.rs
index 0469a9d1cc8..70a50d83904 100644
--- a/src/test/compile-fail/macro-outer-attributes.rs
+++ b/src/test/compile-fail/macro-outer-attributes.rs
@@ -25,6 +25,6 @@ test!(b,
 // test1!(#[bar])
 #[qux]
 fn main() {
-    a::bar(); //~ ERROR unresolved name `a::bar`
+    a::bar(); //~ ERROR unresolved function `a::bar`
     b::bar();
 }
diff --git a/src/test/compile-fail/macro-parameter-span.rs b/src/test/compile-fail/macro-parameter-span.rs
index 2ef69759128..dc5a2deab42 100644
--- a/src/test/compile-fail/macro-parameter-span.rs
+++ b/src/test/compile-fail/macro-parameter-span.rs
@@ -18,6 +18,6 @@ macro_rules! foo {
 // not to the macro variable '$id'
 fn main() {
     foo!(
-        x //~ ERROR unresolved name `x`
+        x //~ ERROR unresolved value `x`
         );
 }
diff --git a/src/test/compile-fail/macro-tt-matchers.rs b/src/test/compile-fail/macro-tt-matchers.rs
index 945490cefb9..969f1500717 100644
--- a/src/test/compile-fail/macro-tt-matchers.rs
+++ b/src/test/compile-fail/macro-tt-matchers.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![feature(rustc_attrs)]
+#![allow(dead_code)]
 
 macro_rules! foo {
     ($x:tt) => (type Alias = $x<i32>;)
diff --git a/src/test/compile-fail/match-join.rs b/src/test/compile-fail/match-join.rs
index 4ec426fd3aa..3f6304db957 100644
--- a/src/test/compile-fail/match-join.rs
+++ b/src/test/compile-fail/match-join.rs
@@ -16,6 +16,6 @@ fn my_panic() -> ! { panic!(); }
 fn main() {
     match true { false => { my_panic(); } true => { } }
 
-    println!("{}", x); //~ ERROR unresolved name `x`
+    println!("{}", x); //~ ERROR unresolved value `x`
     let x: isize;
 }
diff --git a/src/test/compile-fail/match-vec-mismatch.rs b/src/test/compile-fail/match-vec-mismatch.rs
index 596cec167c2..4cf8eea78cf 100644
--- a/src/test/compile-fail/match-vec-mismatch.rs
+++ b/src/test/compile-fail/match-vec-mismatch.rs
@@ -34,7 +34,7 @@ fn main() {
         [0, 1, 2, 3, x..] => {} //~ ERROR pattern requires
     };
 
-    match does_not_exist { //~ ERROR unresolved name
+    match does_not_exist { //~ ERROR unresolved value `does_not_exist`
         [] => {}
     };
 }
diff --git a/src/test/compile-fail/mod_file_correct_spans.rs b/src/test/compile-fail/mod_file_correct_spans.rs
index f8ea5dda183..c64b22a7f41 100644
--- a/src/test/compile-fail/mod_file_correct_spans.rs
+++ b/src/test/compile-fail/mod_file_correct_spans.rs
@@ -13,5 +13,5 @@
 mod mod_file_aux;
 
 fn main() {
-    assert!(mod_file_aux::bar() == 10); //~ ERROR unresolved name
+    assert!(mod_file_aux::bar() == 10); //~ ERROR unresolved function `mod_file_aux::bar`
 }
diff --git a/src/test/compile-fail/name-clash-nullary.rs b/src/test/compile-fail/name-clash-nullary.rs
index 4c76c4b8b02..359417aee52 100644
--- a/src/test/compile-fail/name-clash-nullary.rs
+++ b/src/test/compile-fail/name-clash-nullary.rs
@@ -13,6 +13,6 @@ use std::option::*;
 fn main() {
   let None: isize = 42; //~ ERROR let bindings cannot shadow unit variants
   log(debug, None);
-  //~^ ERROR unresolved name `debug`
-  //~| ERROR unresolved name `log`
+  //~^ ERROR unresolved function `log`
+  //~| ERROR unresolved value `debug`
 }
diff --git a/src/test/compile-fail/namespace-mix.rs b/src/test/compile-fail/namespace-mix.rs
index cb7894b726f..c1c724fc431 100644
--- a/src/test/compile-fail/namespace-mix.rs
+++ b/src/test/compile-fail/namespace-mix.rs
@@ -41,13 +41,13 @@ mod m2 {
 
 fn f12() {
     check(m1::S{}); //~ ERROR c::Item
-    check(m1::S); //~ ERROR unresolved name
+    check(m1::S); //~ ERROR expected value, found type alias `m1::S`
     check(m2::S{}); //~ ERROR c::S
     check(m2::S); //~ ERROR c::Item
 }
 fn xf12() {
     check(xm1::S{}); //~ ERROR c::Item
-    check(xm1::S); //~ ERROR unresolved name
+    check(xm1::S); //~ ERROR expected value, found type alias `xm1::S`
     check(xm2::S{}); //~ ERROR c::S
     check(xm2::S); //~ ERROR c::Item
 }
@@ -107,13 +107,13 @@ mod m8 {
 
 fn f78() {
     check(m7::V{}); //~ ERROR c::Item
-    check(m7::V); //~ ERROR name of a struct or struct variant
+    check(m7::V); //~ ERROR expected value, found struct variant `m7::V`
     check(m8::V{}); //~ ERROR c::E
     check(m8::V); //~ ERROR c::Item
 }
 fn xf78() {
     check(xm7::V{}); //~ ERROR c::Item
-    check(xm7::V); //~ ERROR name of a struct or struct variant
+    check(xm7::V); //~ ERROR expected value, found struct variant `xm7::V`
     check(xm8::V{}); //~ ERROR c::E
     check(xm8::V); //~ ERROR c::Item
 }
diff --git a/src/test/compile-fail/namespaced-enum-glob-import-no-impls-xcrate.rs b/src/test/compile-fail/namespaced-enum-glob-import-no-impls-xcrate.rs
index 4fcb31d3686..d92323e290b 100644
--- a/src/test/compile-fail/namespaced-enum-glob-import-no-impls-xcrate.rs
+++ b/src/test/compile-fail/namespaced-enum-glob-import-no-impls-xcrate.rs
@@ -18,8 +18,8 @@ mod m {
 pub fn main() {
     use namespaced_enums::Foo::*;
 
-    foo(); //~ ERROR unresolved name `foo`
-    m::foo(); //~ ERROR unresolved name `m::foo`
-    bar(); //~ ERROR unresolved name `bar`
-    m::bar(); //~ ERROR unresolved name `m::bar`
+    foo(); //~ ERROR unresolved function `foo`
+    m::foo(); //~ ERROR unresolved function `m::foo`
+    bar(); //~ ERROR unresolved function `bar`
+    m::bar(); //~ ERROR unresolved function `m::bar`
 }
diff --git a/src/test/compile-fail/namespaced-enum-glob-import-no-impls.rs b/src/test/compile-fail/namespaced-enum-glob-import-no-impls.rs
index 4437482fb67..b7c7397ee98 100644
--- a/src/test/compile-fail/namespaced-enum-glob-import-no-impls.rs
+++ b/src/test/compile-fail/namespaced-enum-glob-import-no-impls.rs
@@ -28,8 +28,8 @@ mod m {
 pub fn main() {
     use m2::Foo::*;
 
-    foo(); //~ ERROR unresolved name `foo`
-    m::foo(); //~ ERROR unresolved name `m::foo`
-    bar(); //~ ERROR unresolved name `bar`
-    m::bar(); //~ ERROR unresolved name `m::bar`
+    foo(); //~ ERROR unresolved function `foo`
+    m::foo(); //~ ERROR unresolved function `m::foo`
+    bar(); //~ ERROR unresolved function `bar`
+    m::bar(); //~ ERROR unresolved function `m::bar`
 }
diff --git a/src/test/compile-fail/nested-cfg-attrs.rs b/src/test/compile-fail/nested-cfg-attrs.rs
index 6010b1e695e..f3e20f4f614 100644
--- a/src/test/compile-fail/nested-cfg-attrs.rs
+++ b/src/test/compile-fail/nested-cfg-attrs.rs
@@ -11,4 +11,4 @@
 #[cfg_attr(all(), cfg_attr(all(), cfg(foo)))]
 fn f() {}
 
-fn main() { f() } //~ ERROR unresolved name `f`
+fn main() { f() } //~ ERROR unresolved function `f`
diff --git a/src/test/compile-fail/no-implicit-prelude-nested.rs b/src/test/compile-fail/no-implicit-prelude-nested.rs
index af1046bcd5d..49e2e9f34fa 100644
--- a/src/test/compile-fail/no-implicit-prelude-nested.rs
+++ b/src/test/compile-fail/no-implicit-prelude-nested.rs
@@ -18,26 +18,26 @@
 mod foo {
     mod baz {
         struct Test;
-        impl Add for Test {} //~ ERROR: not in scope
-        impl Clone for Test {} //~ ERROR: not in scope
-        impl Iterator for Test {} //~ ERROR: not in scope
-        impl ToString for Test {} //~ ERROR: not in scope
-        impl Writer for Test {} //~ ERROR: not in scope
+        impl Add for Test {} //~ ERROR unresolved trait `Add`
+        impl Clone for Test {} //~ ERROR unresolved trait `Clone`
+        impl Iterator for Test {} //~ ERROR unresolved trait `Iterator`
+        impl ToString for Test {} //~ ERROR unresolved trait `ToString`
+        impl Writer for Test {} //~ ERROR unresolved trait `Writer`
 
         fn foo() {
-            drop(2) //~ ERROR: unresolved name
+            drop(2) //~ ERROR unresolved function `drop`
         }
     }
 
     struct Test;
-    impl Add for Test {} //~ ERROR: not in scope
-    impl Clone for Test {} //~ ERROR: not in scope
-    impl Iterator for Test {} //~ ERROR: not in scope
-    impl ToString for Test {} //~ ERROR: not in scope
-    impl Writer for Test {} //~ ERROR: not in scope
+    impl Add for Test {} //~ ERROR unresolved trait `Add`
+    impl Clone for Test {} //~ ERROR unresolved trait `Clone`
+    impl Iterator for Test {} //~ ERROR unresolved trait `Iterator`
+    impl ToString for Test {} //~ ERROR unresolved trait `ToString`
+    impl Writer for Test {} //~ ERROR unresolved trait `Writer`
 
     fn foo() {
-        drop(2) //~ ERROR: unresolved name
+        drop(2) //~ ERROR unresolved function `drop`
     }
 }
 
@@ -45,14 +45,14 @@ fn qux() {
     #[no_implicit_prelude]
     mod qux_inner {
         struct Test;
-        impl Add for Test {} //~ ERROR: not in scope
-        impl Clone for Test {} //~ ERROR: not in scope
-        impl Iterator for Test {} //~ ERROR: not in scope
-        impl ToString for Test {} //~ ERROR: not in scope
-        impl Writer for Test {} //~ ERROR: not in scope
+        impl Add for Test {} //~ ERROR unresolved trait `Add`
+        impl Clone for Test {} //~ ERROR unresolved trait `Clone`
+        impl Iterator for Test {} //~ ERROR unresolved trait `Iterator`
+        impl ToString for Test {} //~ ERROR unresolved trait `ToString`
+        impl Writer for Test {} //~ ERROR unresolved trait `Writer`
 
         fn foo() {
-            drop(2) //~ ERROR: unresolved name
+            drop(2) //~ ERROR unresolved function `drop`
         }
     }
 }
diff --git a/src/test/compile-fail/no-implicit-prelude.rs b/src/test/compile-fail/no-implicit-prelude.rs
index 4693fd14e7d..b830a64fa81 100644
--- a/src/test/compile-fail/no-implicit-prelude.rs
+++ b/src/test/compile-fail/no-implicit-prelude.rs
@@ -17,12 +17,12 @@
 // fail with the same error message).
 
 struct Test;
-impl Add for Test {} //~ ERROR: not in scope
-impl Clone for Test {} //~ ERROR: not in scope
-impl Iterator for Test {} //~ ERROR: not in scope
-impl ToString for Test {} //~ ERROR: not in scope
-impl Writer for Test {} //~ ERROR: not in scope
+impl Add for Test {} //~ ERROR unresolved trait `Add`
+impl Clone for Test {} //~ ERROR unresolved trait `Clone`
+impl Iterator for Test {} //~ ERROR unresolved trait `Iterator`
+impl ToString for Test {} //~ ERROR unresolved trait `ToString`
+impl Writer for Test {} //~ ERROR unresolved trait `Writer`
 
 fn main() {
-    drop(2) //~ ERROR: unresolved name
+    drop(2) //~ ERROR unresolved function `drop`
 }
diff --git a/src/test/compile-fail/no-link.rs b/src/test/compile-fail/no-link.rs
index c4737a37399..7e4e55543cd 100644
--- a/src/test/compile-fail/no-link.rs
+++ b/src/test/compile-fail/no-link.rs
@@ -15,5 +15,5 @@ extern crate empty_struct;
 //~^ WARN custom derive crates and `#[no_link]` crates have no effect without `#[macro_use]`
 
 fn main() {
-    empty_struct::XEmpty1; //~ ERROR unresolved name
+    empty_struct::XEmpty1; //~ ERROR unresolved value `empty_struct::XEmpty1`
 }
diff --git a/src/test/compile-fail/parser-recovery-1.rs b/src/test/compile-fail/parser-recovery-1.rs
index 85b62461238..373b33c3e49 100644
--- a/src/test/compile-fail/parser-recovery-1.rs
+++ b/src/test/compile-fail/parser-recovery-1.rs
@@ -14,11 +14,11 @@
 
 trait Foo {
     fn bar() {
-        let x = foo(); //~ ERROR unresolved name `foo`
+        let x = foo(); //~ ERROR unresolved function `foo`
 
 }
 
 fn main() {
     let x = y.;  //~ ERROR unexpected token
-                 //~^ ERROR unresolved name `y`
+                 //~^ ERROR unresolved value `y`
 } //~ ERROR this file contains an un-closed delimiter
diff --git a/src/test/compile-fail/parser-recovery-2.rs b/src/test/compile-fail/parser-recovery-2.rs
index 109da6251e3..c2bbbda4011 100644
--- a/src/test/compile-fail/parser-recovery-2.rs
+++ b/src/test/compile-fail/parser-recovery-2.rs
@@ -14,11 +14,11 @@
 
 trait Foo {
     fn bar() {
-        let x = foo(); //~ ERROR unresolved name `foo`
+        let x = foo(); //~ ERROR unresolved function `foo`
     ) //~ ERROR incorrect close delimiter: `)`
 }
 
 fn main() {
     let x = y.;  //~ ERROR unexpected token
-                 //~^ ERROR unresolved name `y`
+                 //~^ ERROR unresolved value `y`
 }
diff --git a/src/test/compile-fail/pattern-macro-hygiene.rs b/src/test/compile-fail/pattern-macro-hygiene.rs
index 1c79c9a2293..24f29666172 100644
--- a/src/test/compile-fail/pattern-macro-hygiene.rs
+++ b/src/test/compile-fail/pattern-macro-hygiene.rs
@@ -12,5 +12,5 @@ macro_rules! foo { () => ( x ) }
 
 fn main() {
     let foo!() = 2;
-    x + 1; //~ ERROR unresolved name `x`
+    x + 1; //~ ERROR unresolved value `x`
 }
diff --git a/src/test/compile-fail/privacy-ns1.rs b/src/test/compile-fail/privacy-ns1.rs
index dcab3a46b0a..9c1e8250dbc 100644
--- a/src/test/compile-fail/privacy-ns1.rs
+++ b/src/test/compile-fail/privacy-ns1.rs
@@ -27,7 +27,7 @@ pub mod foo1 {
 fn test_glob1() {
     use foo1::*;
 
-    Bar();  //~ ERROR unresolved name `Bar`
+    Bar();  //~ ERROR expected function, found trait `Bar`
 }
 
 // private type, public value
@@ -42,7 +42,7 @@ pub mod foo2 {
 fn test_glob2() {
     use foo2::*;
 
-    let _x: Box<Bar>;  //~ ERROR type name `Bar` is undefined or not in scope
+    let _x: Box<Bar>;  //~ ERROR expected type, found function `Bar`
 }
 
 // neither public
@@ -57,8 +57,8 @@ pub mod foo3 {
 fn test_glob3() {
     use foo3::*;
 
-    Bar();  //~ ERROR unresolved name `Bar`
-    let _x: Box<Bar>;  //~ ERROR  type name `Bar` is undefined or not in scope
+    Bar();  //~ ERROR unresolved function `Bar`
+    let _x: Box<Bar>;  //~ ERROR unresolved type `Bar`
 }
 
 fn main() {
diff --git a/src/test/compile-fail/privacy-ns2.rs b/src/test/compile-fail/privacy-ns2.rs
index 7accf0ca820..ec9396b5e7b 100644
--- a/src/test/compile-fail/privacy-ns2.rs
+++ b/src/test/compile-fail/privacy-ns2.rs
@@ -27,13 +27,13 @@ pub mod foo1 {
 fn test_single1() {
     use foo1::Bar;
 
-    Bar(); //~ ERROR unresolved name `Bar`
+    Bar(); //~ ERROR expected function, found trait `Bar`
 }
 
 fn test_list1() {
     use foo1::{Bar,Baz};
 
-    Bar(); //~ ERROR unresolved name `Bar`
+    Bar(); //~ ERROR expected function, found trait `Bar`
 }
 
 // private type, public value
@@ -48,13 +48,13 @@ pub mod foo2 {
 fn test_single2() {
     use foo2::Bar;
 
-    let _x : Box<Bar>; //~ ERROR type name `Bar` is undefined
+    let _x : Box<Bar>; //~ ERROR expected type, found function `Bar`
 }
 
 fn test_list2() {
     use foo2::{Bar,Baz};
 
-    let _x: Box<Bar>; //~ ERROR type name `Bar` is undefined
+    let _x: Box<Bar>; //~ ERROR expected type, found function `Bar`
 }
 
 // neither public
diff --git a/src/test/compile-fail/privacy/restricted/test.rs b/src/test/compile-fail/privacy/restricted/test.rs
index 3e1bb766622..01e2c6cd7e8 100644
--- a/src/test/compile-fail/privacy/restricted/test.rs
+++ b/src/test/compile-fail/privacy/restricted/test.rs
@@ -57,6 +57,6 @@ fn main() {
 }
 
 mod pathological {
-    pub(bad::path) mod m1 {} //~ ERROR failed to resolve module path
+    pub(bad::path) mod m1 {} //~ ERROR failed to resolve. Maybe a missing `extern crate bad;`?
     pub(foo) mod m2 {} //~ ERROR visibilities can only be restricted to ancestor modules
 }
diff --git a/src/test/compile-fail/privacy/restricted/ty-params.rs b/src/test/compile-fail/privacy/restricted/ty-params.rs
index ae60c4366ee..593713a6e05 100644
--- a/src/test/compile-fail/privacy/restricted/ty-params.rs
+++ b/src/test/compile-fail/privacy/restricted/ty-params.rs
@@ -16,11 +16,11 @@ macro_rules! m {
 
 struct S<T>(T);
 m!{ S<u8> } //~ ERROR type or lifetime parameters in visibility path
-//~^ ERROR failed to resolve module path. Not a module `S`
+//~^ ERROR expected module, found struct `S`
 
 mod foo {
     struct S(pub(foo<T>) ()); //~ ERROR type or lifetime parameters in visibility path
-    //~^ ERROR type name `T` is undefined or not in scope
+    //~^ ERROR unresolved type `T`
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/recursive-reexports.rs b/src/test/compile-fail/recursive-reexports.rs
index 6fd52beeec6..48ec16a7610 100644
--- a/src/test/compile-fail/recursive-reexports.rs
+++ b/src/test/compile-fail/recursive-reexports.rs
@@ -10,6 +10,8 @@
 
 // aux-build:recursive_reexports.rs
 
-fn f() -> recursive_reexports::S {} //~ ERROR undeclared
+extern crate recursive_reexports;
+
+fn f() -> recursive_reexports::S {} //~ ERROR unresolved type `recursive_reexports::S`
 
 fn main() {}
diff --git a/src/test/compile-fail/resolve-bad-import-prefix.rs b/src/test/compile-fail/resolve-bad-import-prefix.rs
new file mode 100644
index 00000000000..6b4a5122ad0
--- /dev/null
+++ b/src/test/compile-fail/resolve-bad-import-prefix.rs
@@ -0,0 +1,24 @@
+// 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.
+
+mod m {}
+enum E {}
+struct S;
+trait Tr {}
+
+use {}; // OK
+use ::{}; // OK
+use m::{}; // OK
+use E::{}; // OK
+use S::{}; //~ ERROR expected module or enum, found struct `S`
+use Tr::{}; //~ ERROR expected module or enum, found trait `Tr`
+use Nonexistent::{}; //~ ERROR unresolved module or enum `Nonexistent`
+
+fn main () {}
diff --git a/src/test/compile-fail/resolve-bad-visibility.rs b/src/test/compile-fail/resolve-bad-visibility.rs
new file mode 100644
index 00000000000..088a4e6cd76
--- /dev/null
+++ b/src/test/compile-fail/resolve-bad-visibility.rs
@@ -0,0 +1,27 @@
+// 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(pub_restricted)]
+
+enum E {}
+trait Tr {}
+
+pub(E) struct S; //~ ERROR expected module, found enum `E`
+pub(Tr) struct Z; //~ ERROR expected module, found trait `Tr`
+pub(std::vec) struct F; //~ ERROR visibilities can only be restricted to ancestor modules
+pub(nonexistent) struct G; //~ ERROR unresolved module `nonexistent`
+pub(too_soon) struct H; //~ ERROR unresolved module `too_soon`
+
+// Visibilities are resolved eagerly without waiting for modules becoming fully populated.
+// Visibilities can only use ancestor modules legally which are always available in time,
+// so the worst thing that can happen due to eager resolution is a suboptimal error message.
+mod too_soon {}
+
+fn main () {}
diff --git a/src/test/compile-fail/resolve-conflict-item-vs-import.rs b/src/test/compile-fail/resolve-conflict-item-vs-import.rs
index 5a068ce4214..2083d98e09d 100644
--- a/src/test/compile-fail/resolve-conflict-item-vs-import.rs
+++ b/src/test/compile-fail/resolve-conflict-item-vs-import.rs
@@ -13,6 +13,6 @@ use std::mem::transmute;
 
 fn transmute() {}
 //~^ ERROR a value named `transmute` has already been imported in this module
-//~| was already imported
+//~| `transmute` already imported
 fn main() {
 }
diff --git a/src/test/compile-fail/resolve-primitive-fallback.rs b/src/test/compile-fail/resolve-primitive-fallback.rs
new file mode 100644
index 00000000000..de463cd9e6a
--- /dev/null
+++ b/src/test/compile-fail/resolve-primitive-fallback.rs
@@ -0,0 +1,20 @@
+// 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.
+
+fn main() {
+    // Make sure primitive type fallback doesn't work in value namespace
+    std::mem::size_of(u16);
+    //~^ ERROR expected value, found builtin type `u16`
+    //~| ERROR this function takes 0 parameters but 1 parameter was supplied
+
+    // Make sure primitive type fallback doesn't work with global paths
+    let _: ::u8;
+    //~^ ERROR unresolved type `u8`
+}
diff --git a/src/test/compile-fail/resolve-unknown-trait.rs b/src/test/compile-fail/resolve-unknown-trait.rs
index dae3a79832b..affafbfadcf 100644
--- a/src/test/compile-fail/resolve-unknown-trait.rs
+++ b/src/test/compile-fail/resolve-unknown-trait.rs
@@ -10,10 +10,10 @@
 
 
 trait NewTrait : SomeNonExistentTrait {}
-//~^ ERROR trait `SomeNonExistentTrait` is not in scope
+//~^ ERROR unresolved trait `SomeNonExistentTrait`
 
 impl SomeNonExistentTrait for isize {}
-//~^ ERROR trait `SomeNonExistentTrait` is not in scope
+//~^ ERROR unresolved trait `SomeNonExistentTrait`
 
 fn f<T:SomeNonExistentTrait>() {}
-//~^ ERROR trait `SomeNonExistentTrait` is not in scope
+//~^ ERROR unresolved trait `SomeNonExistentTrait`
diff --git a/src/test/compile-fail/rmeta.rs b/src/test/compile-fail/rmeta.rs
index e81e0541096..455574bbb9d 100644
--- a/src/test/compile-fail/rmeta.rs
+++ b/src/test/compile-fail/rmeta.rs
@@ -15,5 +15,5 @@
 #![crate_type="metadata"]
 
 fn main() {
-    let _ = Foo; //~ ERROR unresolved name `Foo`
+    let _ = Foo; //~ ERROR unresolved value `Foo`
 }
diff --git a/src/test/compile-fail/struct-fields-shorthand-unresolved.rs b/src/test/compile-fail/struct-fields-shorthand-unresolved.rs
index 50a43f4a276..d1555373015 100644
--- a/src/test/compile-fail/struct-fields-shorthand-unresolved.rs
+++ b/src/test/compile-fail/struct-fields-shorthand-unresolved.rs
@@ -19,6 +19,6 @@ fn main() {
     let x = 0;
     let foo = Foo {
         x,
-        y //~ ERROR unresolved name `y`
+        y //~ ERROR unresolved value `y`
     };
 }
diff --git a/src/test/compile-fail/syntax-extension-minor.rs b/src/test/compile-fail/syntax-extension-minor.rs
index f06e3544e57..0beb4f084c8 100644
--- a/src/test/compile-fail/syntax-extension-minor.rs
+++ b/src/test/compile-fail/syntax-extension-minor.rs
@@ -18,7 +18,7 @@ pub fn main() {
     // this now fails (correctly, I claim) because hygiene prevents
     // the assembled identifier from being a reference to the binding.
     assert!(concat_idents!(asd, f_f, dsa) == "<.<".to_string());
-    //~^ ERROR: unresolved name `asdf_fdsa`
+    //~^ ERROR unresolved value `asdf_fdsa`
 
     assert_eq!(stringify!(use_mention_distinction), "use_mention_distinction");
 }
diff --git a/src/test/compile-fail/test-cfg.rs b/src/test/compile-fail/test-cfg.rs
index 0709d909512..28c69e8df22 100644
--- a/src/test/compile-fail/test-cfg.rs
+++ b/src/test/compile-fail/test-cfg.rs
@@ -14,5 +14,5 @@
 fn foo() {}
 
 fn main() {
-    foo(); //~ ERROR unresolved name `foo`
+    foo(); //~ ERROR unresolved function `foo`
 }
diff --git a/src/test/compile-fail/ufcs-partially-resolved.rs b/src/test/compile-fail/ufcs-partially-resolved.rs
new file mode 100644
index 00000000000..5337272343b
--- /dev/null
+++ b/src/test/compile-fail/ufcs-partially-resolved.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(associated_type_defaults)]
+
+trait Tr {
+    type Y = u16;
+    fn Y() {}
+}
+impl Tr for u8 {}
+
+trait Dr {
+    type X = u16;
+    fn Z() {}
+}
+impl Dr for u8 {}
+
+enum E { Y }
+type A = u32;
+
+fn main() {
+    let _: <u8 as Tr>::N; //~ ERROR unresolved associated type `Tr::N`
+    let _: <u8 as E>::N; //~ ERROR unresolved associated type `E::N`
+    let _: <u8 as A>::N; //~ ERROR unresolved associated type `A::N`
+    <u8 as Tr>::N; //~ ERROR unresolved method or associated constant `Tr::N`
+    <u8 as E>::N; //~ ERROR unresolved method or associated constant `E::N`
+    <u8 as A>::N; //~ ERROR unresolved method or associated constant `A::N`
+    let _: <u8 as Tr>::Y; // OK
+    let _: <u8 as E>::Y; //~ ERROR expected associated type, found variant `E::Y`
+    <u8 as Tr>::Y; // OK
+    <u8 as E>::Y; //~ ERROR expected method or associated constant, found unit variant `E::Y`
+
+    let _: <u8 as Tr>::N::NN; //~ ERROR unresolved associated type `Tr::N`
+    let _: <u8 as E>::N::NN; //~ ERROR unresolved associated type `E::N`
+    let _: <u8 as A>::N::NN; //~ ERROR unresolved associated type `A::N`
+    <u8 as Tr>::N::NN; //~ ERROR unresolved associated type `Tr::N`
+    <u8 as E>::N::NN; //~ ERROR unresolved associated type `E::N`
+    <u8 as A>::N::NN; //~ ERROR unresolved associated type `A::N`
+    let _: <u8 as Tr>::Y::NN; //~ ERROR ambiguous associated type
+    let _: <u8 as E>::Y::NN; //~ ERROR expected associated type, found variant `E::Y`
+    <u8 as Tr>::Y::NN; //~ ERROR no associated item named `NN` found for type `<u8 as Tr>::Y`
+    <u8 as E>::Y::NN; //~ ERROR expected associated type, found variant `E::Y`
+
+    let _: <u8 as Tr::N>::NN; //~ ERROR unresolved associated type `Tr::N::NN`
+    let _: <u8 as E::N>::NN; //~ ERROR unresolved associated type `E::N::NN`
+    let _: <u8 as A::N>::NN; //~ ERROR unresolved associated type `A::N::NN`
+    <u8 as Tr::N>::NN; //~ ERROR unresolved method or associated constant `Tr::N::NN`
+    <u8 as E::N>::NN; //~ ERROR unresolved method or associated constant `E::N::NN`
+    <u8 as A::N>::NN; //~ ERROR unresolved method or associated constant `A::N::NN`
+    let _: <u8 as Tr::Y>::NN; //~ ERROR unresolved associated type `Tr::Y::NN`
+    let _: <u8 as E::Y>::NN; //~ ERROR unresolved associated type `E::Y::NN`
+    <u8 as Tr::Y>::NN; //~ ERROR unresolved method or associated constant `Tr::Y::NN`
+    <u8 as E::Y>::NN; //~ ERROR unresolved method or associated constant `E::Y::NN`
+
+    let _: <u8 as Dr>::Z; //~ ERROR expected associated type, found method `Dr::Z`
+    <u8 as Dr>::X; //~ ERROR expected method or associated constant, found associated type `Dr::X`
+    let _: <u8 as Dr>::Z::N; //~ ERROR expected associated type, found method `Dr::Z`
+    <u8 as Dr>::X::N; //~ ERROR no associated item named `N` found for type `<u8 as Dr>::X`
+}
diff --git a/src/test/compile-fail/variant-used-as-type.rs b/src/test/compile-fail/variant-used-as-type.rs
index 73defa6eef9..c889b7d28f8 100644
--- a/src/test/compile-fail/variant-used-as-type.rs
+++ b/src/test/compile-fail/variant-used-as-type.rs
@@ -15,7 +15,7 @@
 enum Ty {
     A,
     B(Ty::A),
-    //~^ ERROR: found value `Ty::A` used as a type
+    //~^ ERROR expected type, found variant `Ty::A`
 }
 
 
@@ -25,6 +25,6 @@ enum E {
 }
 
 impl E::A {}
-//~^ ERROR: found value `E::A` used as a type
+//~^ ERROR expected type, found variant `E::A`
 
 fn main() {}
diff --git a/src/test/compile-fail/xcrate-unit-struct.rs b/src/test/compile-fail/xcrate-unit-struct.rs
index 214a2a371ba..04af7133000 100644
--- a/src/test/compile-fail/xcrate-unit-struct.rs
+++ b/src/test/compile-fail/xcrate-unit-struct.rs
@@ -17,6 +17,6 @@ extern crate xcrate_unit_struct;
 
 fn main() {
     let _ = xcrate_unit_struct::StructWithFields;
-    //~^ ERROR: `xcrate_unit_struct::StructWithFields` is the name of a struct or struct variant
+    //~^ ERROR expected value, found struct `xcrate_unit_struct::StructWithFields`
     let _ = xcrate_unit_struct::Struct;
 }
diff --git a/src/test/debuginfo/borrowed-enum.rs b/src/test/debuginfo/borrowed-enum.rs
index ddc29c64302..f34fc3b20d2 100644
--- a/src/test/debuginfo/borrowed-enum.rs
+++ b/src/test/debuginfo/borrowed-enum.rs
@@ -18,11 +18,11 @@
 // gdb-command:run
 
 // gdb-command:print *the_a_ref
-// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, __0 = 0, __1 = 2088533116, __2 = 2088533116}}
+// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, [...]}}
 // gdbr-check:$1 = borrowed_enum::ABC::TheA{x: 0, y: 8970181431921507452}
 
 // gdb-command:print *the_b_ref
-// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, x = 0, y = 1229782938247303441}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
+// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, [...]}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
 // gdbr-check:$2 = borrowed_enum::ABC::TheB(0, 286331153, 286331153)
 
 // gdb-command:print *univariant_ref
diff --git a/src/test/debuginfo/by-value-non-immediate-argument.rs b/src/test/debuginfo/by-value-non-immediate-argument.rs
index 6d821dbc155..0fe08c3a227 100644
--- a/src/test/debuginfo/by-value-non-immediate-argument.rs
+++ b/src/test/debuginfo/by-value-non-immediate-argument.rs
@@ -42,7 +42,7 @@
 // gdb-command:continue
 
 // gdb-command:print x
-// gdbg-check:$7 = {{RUST$ENUM$DISR = Case1, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}}
+// gdbg-check:$7 = {{RUST$ENUM$DISR = Case1, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = Case1, [...]}}
 // gdbr-check:$7 = by_value_non_immediate_argument::Enum::Case1{x: 0, y: 8970181431921507452}
 // gdb-command:continue
 
diff --git a/src/test/debuginfo/generic-struct-style-enum.rs b/src/test/debuginfo/generic-struct-style-enum.rs
index dba9422721a..a328eec6893 100644
--- a/src/test/debuginfo/generic-struct-style-enum.rs
+++ b/src/test/debuginfo/generic-struct-style-enum.rs
@@ -17,15 +17,15 @@
 // gdb-command:run
 
 // gdb-command:print case1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, a = 0, b = 2088533116, c = 2088533116}, {RUST$ENUM$DISR = Case1, a = 0, b = 8970181431921507452}}
+// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
 // gdbr-check:$1 = generic_struct_style_enum::Regular::Case1{a: 0, b: 31868, c: 31868, d: 31868, e: 31868}
 
 // gdb-command:print case2
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, a = 0, b = 4369, c = 4369, d = 4369, e = 4369}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, a = 0, b = 1229782938247303441}}
+// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
 // gdbr-check:$2 = generic_struct_style_enum::Regular::Case2{a: 0, b: 286331153, c: 286331153}
 
 // gdb-command:print case3
-// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {RUST$ENUM$DISR = Case3, a = 0, b = 1499027801, c = 1499027801}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}}
+// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}}
 // gdbr-check:$3 = generic_struct_style_enum::Regular::Case3{a: 0, b: 6438275382588823897}
 
 // gdb-command:print univariant
diff --git a/src/test/debuginfo/generic-tuple-style-enum.rs b/src/test/debuginfo/generic-tuple-style-enum.rs
index 01d2ff4e334..9ada5fdeff7 100644
--- a/src/test/debuginfo/generic-tuple-style-enum.rs
+++ b/src/test/debuginfo/generic-tuple-style-enum.rs
@@ -19,15 +19,15 @@
 // gdb-command:run
 
 // gdb-command:print case1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452}}
+// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
 // gdbr-check:$1 = generic_tuple_style_enum::Regular::Case1(0, 31868, 31868, 31868, 31868)
 
 // gdb-command:print case2
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = 4369, __2 = 4369, __3 = 4369, __4 = 4369}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441}}
+// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
 // gdbr-check:$2 = generic_tuple_style_enum::Regular::Case2(0, 286331153, 286331153)
 
 // gdb-command:print case3
-// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, __0 = 0, __1 = 22873, __2 = 22873, __3 = 22873, __4 = 22873}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 1499027801, __2 = 1499027801}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}}
+// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}}
 // gdbr-check:$3 = generic_tuple_style_enum::Regular::Case3(0, 6438275382588823897)
 
 // gdb-command:print univariant
diff --git a/src/test/debuginfo/struct-in-enum.rs b/src/test/debuginfo/struct-in-enum.rs
index d0aceaa4f3f..ffd36ae14ad 100644
--- a/src/test/debuginfo/struct-in-enum.rs
+++ b/src/test/debuginfo/struct-in-enum.rs
@@ -19,11 +19,11 @@
 // gdb-command:run
 
 // gdb-command:print case1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = {x = 2088533116, y = 2088533116, z = 31868}}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452, __2 = 31868}}
+// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = {x = 2088533116, y = 2088533116, z = 31868}}, {RUST$ENUM$DISR = Case1, [...]}}
 // gdbr-check:$1 = struct_in_enum::Regular::Case1(0, struct_in_enum::Struct {x: 2088533116, y: 2088533116, z: 31868})
 
 // gdb-command:print case2
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = {x = 286331153, y = 286331153, z = 4369}}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441, __2 = 4369}}
+// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441, __2 = 4369}}
 // gdbr-check:$2 = struct_in_enum::Regular::Case2(0, 1229782938247303441, 4369)
 
 // gdb-command:print univariant
diff --git a/src/test/debuginfo/struct-style-enum.rs b/src/test/debuginfo/struct-style-enum.rs
index 8abc139eb11..b6196daaa46 100644
--- a/src/test/debuginfo/struct-style-enum.rs
+++ b/src/test/debuginfo/struct-style-enum.rs
@@ -19,15 +19,15 @@
 // gdb-command:run
 
 // gdb-command:print case1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, a = 0, b = 2088533116, c = 2088533116}, {RUST$ENUM$DISR = Case1, a = 0, b = 8970181431921507452}}
+// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
 // gdbr-check:$1 = struct_style_enum::Regular::Case1{a: 0, b: 31868, c: 31868, d: 31868, e: 31868}
 
 // gdb-command:print case2
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, a = 0, b = 4369, c = 4369, d = 4369, e = 4369}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, a = 0, b = 1229782938247303441}}
+// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
 // gdbr-check:$2 = struct_style_enum::Regular::Case2{a: 0, b: 286331153, c: 286331153}
 
 // gdb-command:print case3
-// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {RUST$ENUM$DISR = Case3, a = 0, b = 1499027801, c = 1499027801}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}}
+// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}}
 // gdbr-check:$3 = struct_style_enum::Regular::Case3{a: 0, b: 6438275382588823897}
 
 // gdb-command:print univariant
diff --git a/src/test/debuginfo/tuple-style-enum.rs b/src/test/debuginfo/tuple-style-enum.rs
index d05edec3e73..988f223b3bc 100644
--- a/src/test/debuginfo/tuple-style-enum.rs
+++ b/src/test/debuginfo/tuple-style-enum.rs
@@ -19,15 +19,15 @@
 // gdb-command:run
 
 // gdb-command:print case1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452}}
+// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
 // gdbr-check:$1 = tuple_style_enum::Regular::Case1(0, 31868, 31868, 31868, 31868)
 
 // gdb-command:print case2
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = 4369, __2 = 4369, __3 = 4369, __4 = 4369}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441}}
+// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
 // gdbr-check:$2 = tuple_style_enum::Regular::Case2(0, 286331153, 286331153)
 
 // gdb-command:print case3
-// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, __0 = 0, __1 = 22873, __2 = 22873, __3 = 22873, __4 = 22873}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 1499027801, __2 = 1499027801}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}}
+// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}}
 // gdbr-check:$3 = tuple_style_enum::Regular::Case3(0, 6438275382588823897)
 
 // gdb-command:print univariant
diff --git a/src/test/debuginfo/union-smoke.rs b/src/test/debuginfo/union-smoke.rs
index 26e73a08ea1..ada9e0b30cc 100644
--- a/src/test/debuginfo/union-smoke.rs
+++ b/src/test/debuginfo/union-smoke.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // min-lldb-version: 310
+// ignore-macos FIXME(#37479)
 
 // compile-flags:-g
 
diff --git a/src/test/debuginfo/unique-enum.rs b/src/test/debuginfo/unique-enum.rs
index e882544b802..cf8d90e30f1 100644
--- a/src/test/debuginfo/unique-enum.rs
+++ b/src/test/debuginfo/unique-enum.rs
@@ -18,11 +18,11 @@
 // gdb-command:run
 
 // gdb-command:print *the_a
-// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, __0 = 0, __1 = 2088533116, __2 = 2088533116}}
+// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, [...]}}
 // gdbr-check:$1 = unique_enum::ABC::TheA{x: 0, y: 8970181431921507452}
 
 // gdb-command:print *the_b
-// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, x = 0, y = 1229782938247303441}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
+// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, [...]}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
 // gdbr-check:$2 = unique_enum::ABC::TheB(0, 286331153, 286331153)
 
 // gdb-command:print *univariant
diff --git a/src/test/incremental/hashes/closure_expressions.rs b/src/test/incremental/hashes/closure_expressions.rs
new file mode 100644
index 00000000000..38fe5cdffeb
--- /dev/null
+++ b/src/test/incremental/hashes/closure_expressions.rs
@@ -0,0 +1,144 @@
+// 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.
+
+
+// This test case tests the incremental compilation hash (ICH) implementation
+// for closure expression.
+
+// The general pattern followed here is: Change one thing between rev1 and rev2
+// and make sure that the hash has changed, then change nothing between rev2 and
+// rev3 and make sure that the hash has not changed.
+
+// must-compile-successfully
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+#![crate_type="rlib"]
+
+
+// Change closure body ---------------------------------------------------------
+#[cfg(cfail1)]
+fn change_closure_body() {
+    let _ = || 1u32;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_closure_body() {
+    let _ = || 3u32;
+}
+
+
+
+// Add parameter ---------------------------------------------------------------
+#[cfg(cfail1)]
+fn add_parameter() {
+    let x = 0u32;
+    let _ = || x + 1;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn add_parameter() {
+    let x = 0u32;
+    let _ = |x: u32| x + 1;
+}
+
+
+
+// Change parameter pattern ----------------------------------------------------
+#[cfg(cfail1)]
+fn change_parameter_pattern() {
+    let _ = |x: &u32| x;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_parameter_pattern() {
+    let _ = |&x: &u32| x;
+}
+
+
+
+// Add `move` to closure -------------------------------------------------------
+#[cfg(cfail1)]
+fn add_move() {
+    let _ = || 1;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn add_move() {
+    let _ = move || 1;
+}
+
+
+
+// Add type ascription to parameter --------------------------------------------
+#[cfg(cfail1)]
+fn add_type_ascription_to_parameter() {
+    let closure = |x| x + 1u32;
+    let _: u32 = closure(1);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn add_type_ascription_to_parameter() {
+    let closure = |x: u32| x + 1u32;
+    let _: u32 = closure(1);
+}
+
+
+
+// Change parameter type -------------------------------------------------------
+#[cfg(cfail1)]
+fn change_parameter_type() {
+    let closure = |x: u32| (x as u64) + 1;
+    let _ = closure(1);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_parameter_type() {
+    let closure = |x: u16| (x as u64) + 1;
+    let _ = closure(1);
+}
diff --git a/src/test/incremental/hashes/enum_constructors.rs b/src/test/incremental/hashes/enum_constructors.rs
new file mode 100644
index 00000000000..7f991b30fc4
--- /dev/null
+++ b/src/test/incremental/hashes/enum_constructors.rs
@@ -0,0 +1,387 @@
+// 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.
+
+
+// This test case tests the incremental compilation hash (ICH) implementation
+// for struct constructor expressions.
+
+// The general pattern followed here is: Change one thing between rev1 and rev2
+// and make sure that the hash has changed, then change nothing between rev2 and
+// rev3 and make sure that the hash has not changed.
+
+// must-compile-successfully
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+#![crate_type="rlib"]
+
+
+enum Enum {
+    Struct {
+        x: i32,
+        y: i64,
+        z: i16,
+    },
+    Tuple(i32, i64, i16)
+}
+
+// Change field value (struct-like) -----------------------------------------
+#[cfg(cfail1)]
+fn change_field_value_struct_like() -> Enum {
+    Enum::Struct {
+        x: 0,
+        y: 1,
+        z: 2,
+    }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_field_value_struct_like() -> Enum {
+    Enum::Struct {
+        x: 0,
+        y: 2,
+        z: 2,
+    }
+}
+
+
+
+// Change field order (struct-like) -----------------------------------------
+#[cfg(cfail1)]
+fn change_field_order_struct_like() -> Enum {
+    Enum::Struct {
+        x: 3,
+        y: 4,
+        z: 5,
+    }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_field_order_struct_like() -> Enum {
+    Enum::Struct {
+        y: 4,
+        x: 3,
+        z: 5,
+    }
+}
+
+
+enum Enum2 {
+    Struct {
+        x: i8,
+        y: i8,
+        z: i8,
+    },
+    Struct2 {
+        x: i8,
+        y: i8,
+        z: i8,
+    },
+    Tuple(u16, u16, u16),
+    Tuple2(u64, u64, u64),
+}
+
+// Change constructor path (struct-like) ------------------------------------
+#[cfg(cfail1)]
+fn change_constructor_path_struct_like() {
+    let _ = Enum::Struct {
+        x: 0,
+        y: 1,
+        z: 2,
+    };
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_constructor_path_struct_like() {
+    let _ = Enum2::Struct {
+        x: 0,
+        y: 1,
+        z: 2,
+    };
+}
+
+
+
+// Change variant (regular struct) ------------------------------------
+#[cfg(cfail1)]
+fn change_constructor_variant_struct_like() {
+    let _ = Enum2::Struct {
+        x: 0,
+        y: 1,
+        z: 2,
+    };
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_constructor_variant_struct_like() {
+    let _ = Enum2::Struct2 {
+        x: 0,
+        y: 1,
+        z: 2,
+    };
+}
+
+
+// Change constructor path indirectly (struct-like) -------------------------
+mod change_constructor_path_indirectly_struct_like {
+    #[cfg(cfail1)]
+    use super::Enum as TheEnum;
+    #[cfg(not(cfail1))]
+    use super::Enum2 as TheEnum;
+
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[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="cfail3")]
+    fn function() -> TheEnum {
+        TheEnum::Struct {
+            x: 0,
+            y: 1,
+            z: 2,
+        }
+    }
+}
+
+
+// Change constructor variant indirectly (struct-like) ---------------------------
+mod change_constructor_variant_indirectly_struct_like {
+    use super::Enum2;
+    #[cfg(cfail1)]
+    use super::Enum2::Struct as Variant;
+    #[cfg(not(cfail1))]
+    use super::Enum2::Struct2 as Variant;
+
+    #[rustc_clean(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_dirty(label="HirBody", cfg="cfail2")]
+    #[rustc_clean(label="HirBody", cfg="cfail3")]
+    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn function() -> Enum2 {
+        Variant {
+            x: 0,
+            y: 1,
+            z: 2,
+        }
+    }
+}
+
+
+// Change field value (tuple-like) -------------------------------------------
+#[cfg(cfail1)]
+fn change_field_value_tuple_like() -> Enum {
+    Enum::Tuple(0, 1, 2)
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_field_value_tuple_like() -> Enum {
+    Enum::Tuple(0, 1, 3)
+}
+
+
+
+// Change constructor path (tuple-like) --------------------------------------
+#[cfg(cfail1)]
+fn change_constructor_path_tuple_like() {
+    let _ = Enum::Tuple(0, 1, 2);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_constructor_path_tuple_like() {
+    let _ = Enum2::Tuple(0, 1, 2);
+}
+
+
+
+// Change constructor variant (tuple-like) --------------------------------------
+#[cfg(cfail1)]
+fn change_constructor_variant_tuple_like() {
+    let _ = Enum2::Tuple(0, 1, 2);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_constructor_variant_tuple_like() {
+    let _ = Enum2::Tuple2(0, 1, 2);
+}
+
+
+// Change constructor path indirectly (tuple-like) ---------------------------
+mod change_constructor_path_indirectly_tuple_like {
+    #[cfg(cfail1)]
+    use super::Enum as TheEnum;
+    #[cfg(not(cfail1))]
+    use super::Enum2 as TheEnum;
+
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[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="cfail3")]
+    fn function() -> TheEnum {
+        TheEnum::Tuple(0, 1, 2)
+    }
+}
+
+
+
+// Change constructor variant indirectly (tuple-like) ---------------------------
+mod change_constructor_variant_indirectly_tuple_like {
+    use super::Enum2;
+    #[cfg(cfail1)]
+    use super::Enum2::Tuple as Variant;
+    #[cfg(not(cfail1))]
+    use super::Enum2::Tuple2 as Variant;
+
+    #[rustc_clean(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_dirty(label="HirBody", cfg="cfail2")]
+    #[rustc_clean(label="HirBody", cfg="cfail3")]
+    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn function() -> Enum2 {
+        Variant(0, 1, 2)
+    }
+}
+
+
+enum Clike {
+    A,
+    B,
+    C
+}
+
+enum Clike2 {
+    B,
+    C,
+    D
+}
+
+// Change constructor path (C-like) --------------------------------------
+#[cfg(cfail1)]
+fn change_constructor_path_c_like() {
+    let _ = Clike::B;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_constructor_path_c_like() {
+    let _ = Clike2::B;
+}
+
+
+
+// Change constructor variant (C-like) --------------------------------------
+#[cfg(cfail1)]
+fn change_constructor_variant_c_like() {
+    let _ = Clike::A;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_constructor_variant_c_like() {
+    let _ = Clike::C;
+}
+
+
+// Change constructor path indirectly (C-like) ---------------------------
+mod change_constructor_path_indirectly_c_like {
+    #[cfg(cfail1)]
+    use super::Clike as TheEnum;
+    #[cfg(not(cfail1))]
+    use super::Clike2 as TheEnum;
+
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[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="cfail3")]
+    fn function() -> TheEnum {
+        TheEnum::B
+    }
+}
+
+
+
+// Change constructor variant indirectly (C-like) ---------------------------
+mod change_constructor_variant_indirectly_c_like {
+    use super::Clike;
+    #[cfg(cfail1)]
+    use super::Clike::A as Variant;
+    #[cfg(not(cfail1))]
+    use super::Clike::B as Variant;
+
+    #[rustc_clean(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_dirty(label="HirBody", cfg="cfail2")]
+    #[rustc_clean(label="HirBody", cfg="cfail3")]
+    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn function() -> Clike {
+        Variant
+    }
+}
diff --git a/src/test/incremental/hashes/exported_vs_not.rs b/src/test/incremental/hashes/exported_vs_not.rs
new file mode 100644
index 00000000000..082badacc6c
--- /dev/null
+++ b/src/test/incremental/hashes/exported_vs_not.rs
@@ -0,0 +1,86 @@
+// 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.
+
+// must-compile-successfully
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+#![crate_type="rlib"]
+
+// Case 1: The function body is not exported to metadata. If the body changes,
+//         the hash of the HirBody node should change, but not the hash of
+//         either the Hir or the Metadata node.
+
+#[cfg(cfail1)]
+pub fn body_not_exported_to_metadata() -> u32 {
+    1
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+pub fn body_not_exported_to_metadata() -> u32 {
+    2
+}
+
+
+
+// Case 2: The function body *is* exported to metadata because the function is
+//         marked as #[inline]. Only the hash of the Hir depnode should be
+//         unaffected by a change to the body.
+
+#[cfg(cfail1)]
+#[inline]
+pub fn body_exported_to_metadata_because_of_inline() -> u32 {
+    1
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[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="cfail3")]
+#[inline]
+pub fn body_exported_to_metadata_because_of_inline() -> u32 {
+    2
+}
+
+
+
+// Case 2: The function body *is* exported to metadata because the function is
+//         generic. Only the hash of the Hir depnode should be
+//         unaffected by a change to the body.
+
+#[cfg(cfail1)]
+#[inline]
+pub fn body_exported_to_metadata_because_of_generic() -> u32 {
+    1
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[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="cfail3")]
+#[inline]
+pub fn body_exported_to_metadata_because_of_generic() -> u32 {
+    2
+}
+
diff --git a/src/test/incremental/hashes/indexing_expressions.rs b/src/test/incremental/hashes/indexing_expressions.rs
new file mode 100644
index 00000000000..bb31982d93f
--- /dev/null
+++ b/src/test/incremental/hashes/indexing_expressions.rs
@@ -0,0 +1,157 @@
+// 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.
+
+
+// This test case tests the incremental compilation hash (ICH) implementation
+// for closure expression.
+
+// The general pattern followed here is: Change one thing between rev1 and rev2
+// and make sure that the hash has changed, then change nothing between rev2 and
+// rev3 and make sure that the hash has not changed.
+
+// must-compile-successfully
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+#![crate_type="rlib"]
+#![feature(inclusive_range_syntax)]
+
+// Change simple index ---------------------------------------------------------
+#[cfg(cfail1)]
+fn change_simple_index(slice: &[u32]) -> u32 {
+    slice[3]
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_simple_index(slice: &[u32]) -> u32 {
+    slice[4]
+}
+
+
+
+// Change lower bound ----------------------------------------------------------
+#[cfg(cfail1)]
+fn change_lower_bound(slice: &[u32]) -> &[u32] {
+    &slice[3..5]
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_lower_bound(slice: &[u32]) -> &[u32] {
+    &slice[2..5]
+}
+
+
+
+// Change upper bound ----------------------------------------------------------
+#[cfg(cfail1)]
+fn change_upper_bound(slice: &[u32]) -> &[u32] {
+    &slice[3..5]
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_upper_bound(slice: &[u32]) -> &[u32] {
+    &slice[3..7]
+}
+
+
+
+// Add lower bound -------------------------------------------------------------
+#[cfg(cfail1)]
+fn add_lower_bound(slice: &[u32]) -> &[u32] {
+    &slice[..4]
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn add_lower_bound(slice: &[u32]) -> &[u32] {
+    &slice[3..4]
+}
+
+
+
+// Add upper bound -------------------------------------------------------------
+#[cfg(cfail1)]
+fn add_upper_bound(slice: &[u32]) -> &[u32] {
+    &slice[3..]
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn add_upper_bound(slice: &[u32]) -> &[u32] {
+    &slice[3..7]
+}
+
+
+
+// Change mutability -----------------------------------------------------------
+#[cfg(cfail1)]
+fn change_mutability(slice: &mut [u32]) -> u32 {
+    (&mut slice[3..5])[0]
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_mutability(slice: &mut [u32]) -> u32 {
+    (&slice[3..5])[0]
+}
+
+
+
+// Exclusive to inclusive range ------------------------------------------------
+#[cfg(cfail1)]
+fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] {
+    &slice[3..7]
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] {
+    &slice[3...7]
+}
diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs
index f7a390e8745..5c37bc13359 100644
--- a/src/test/incremental/hashes/inherent_impls.rs
+++ b/src/test/incremental/hashes/inherent_impls.rs
@@ -107,7 +107,7 @@ impl Foo {
     pub fn method_selfness(&self) { }
 }
 
-// Change Method Selfmutness -----------------------------------------------------------
+// Change Method Selfmutness ---------------------------------------------------
 #[cfg(cfail1)]
 impl Foo {
     pub fn method_selfmutness(&self) { }
@@ -126,3 +126,411 @@ impl Foo {
     pub fn method_selfmutness(&mut self) { }
 }
 
+
+
+// Add Method To Impl ----------------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn add_method_to_impl1(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_clean(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_clean(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn add_method_to_impl1(&self) { }
+
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn add_method_to_impl2(&self) { }
+}
+
+
+
+// Add Method Parameter --------------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn add_method_parameter(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn add_method_parameter(&self, _: i32) { }
+}
+
+
+
+// Change Method Parameter Name ------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn change_method_parameter_name(&self, a: i64) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn change_method_parameter_name(&self, b: i64) { }
+}
+
+
+
+// Change Method Return Type ---------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn change_method_return_type(&self) -> u16 { 0 }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn change_method_return_type(&self) -> u8 { 0 }
+}
+
+
+
+// Make Method #[inline] -------------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn make_method_inline(&self) -> u8 { 0 }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    #[inline]
+    pub fn make_method_inline(&self) -> u8 { 0 }
+}
+
+
+
+//  Change order of parameters -------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn change_method_parameter_order(&self, a: i64, b: i64) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn change_method_parameter_order(&self, b: i64, a: i64) { }
+}
+
+
+
+// Make method unsafe ----------------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn make_method_unsafe(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub unsafe fn make_method_unsafe(&self) { }
+}
+
+
+
+// Make method extern ----------------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn make_method_extern(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub extern fn make_method_extern(&self) { }
+}
+
+
+
+// Change method calling convention --------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub extern "C" fn change_method_calling_convention(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub extern "system" fn change_method_calling_convention(&self) { }
+}
+
+
+
+// Add Lifetime Parameter to Method --------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn add_lifetime_parameter_to_method(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn add_lifetime_parameter_to_method<'a>(&self) { }
+}
+
+
+
+// Add Type Parameter To Method ------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn add_type_parameter_to_method(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn add_type_parameter_to_method<T>(&self) { }
+}
+
+
+
+// Add Lifetime Bound to Lifetime Parameter of Method --------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn add_lifetime_bound_to_lifetime_param_of_method<'a, 'b>(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn add_lifetime_bound_to_lifetime_param_of_method<'a, 'b: 'a>(&self) { }
+}
+
+
+
+// Add Lifetime Bound to Type Parameter of Method ------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn add_lifetime_bound_to_type_param_of_method<'a, T>(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn add_lifetime_bound_to_type_param_of_method<'a, T: 'a>(&self) { }
+}
+
+
+
+// Add Trait Bound to Type Parameter of Method ------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn add_trait_bound_to_type_param_of_method<T>(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn add_trait_bound_to_type_param_of_method<T: Clone>(&self) { }
+}
+
+
+
+// Add #[no_mangle] to Method --------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn add_no_mangle_to_method(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    #[no_mangle]
+    pub fn add_no_mangle_to_method(&self) { }
+}
+
+
+
+struct Bar<T>(T);
+
+// Add Type Parameter To Impl --------------------------------------------------
+#[cfg(cfail1)]
+impl Bar<u32> {
+    pub fn add_type_parameter_to_impl(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl<T> Bar<T> {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn add_type_parameter_to_impl(&self) { }
+}
+
+
+
+// Change Self Type of Impl ----------------------------------------------------
+#[cfg(cfail1)]
+impl Bar<u32> {
+    pub fn change_impl_self_type(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Bar<u64> {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn change_impl_self_type(&self) { }
+}
+
+
+
+// Add Lifetime Bound to Impl --------------------------------------------------
+#[cfg(cfail1)]
+impl<T> Bar<T> {
+    pub fn add_lifetime_bound_to_impl_parameter(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl<T: 'static> Bar<T> {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn add_lifetime_bound_to_impl_parameter(&self) { }
+}
+
+
+
+// Add Trait Bound to Impl Parameter -------------------------------------------
+#[cfg(cfail1)]
+impl<T> Bar<T> {
+    pub fn add_trait_bound_to_impl_parameter(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl<T: Clone> Bar<T> {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn add_trait_bound_to_impl_parameter(&self) { }
+}
diff --git a/src/test/incremental/hashes/inline_asm.rs b/src/test/incremental/hashes/inline_asm.rs
new file mode 100644
index 00000000000..a1057c036d6
--- /dev/null
+++ b/src/test/incremental/hashes/inline_asm.rs
@@ -0,0 +1,265 @@
+// 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.
+
+
+// This test case tests the incremental compilation hash (ICH) implementation
+// for inline asm.
+
+// The general pattern followed here is: Change one thing between rev1 and rev2
+// and make sure that the hash has changed, then change nothing between rev2 and
+// rev3 and make sure that the hash has not changed.
+
+// must-compile-successfully
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+#![feature(asm)]
+#![crate_type="rlib"]
+
+
+
+// Change template -------------------------------------------------------------
+#[cfg(cfail1)]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_template(a: i32) -> i32 {
+    let c: i32;
+    unsafe {
+        asm!("add 1, $0"
+             : "=r"(c)
+             : "0"(a)
+             :
+             :
+             );
+    }
+    c
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_template(a: i32) -> i32 {
+    let c: i32;
+    unsafe {
+        asm!("add 2, $0"
+             : "=r"(c)
+             : "0"(a)
+             :
+             :
+             );
+    }
+    c
+}
+
+
+
+// Change output -------------------------------------------------------------
+#[cfg(cfail1)]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_output(a: i32) -> i32 {
+    let mut _out1: i32 = 0;
+    let mut _out2: i32 = 0;
+    unsafe {
+        asm!("add 1, $0"
+             : "=r"(_out1)
+             : "0"(a)
+             :
+             :
+             );
+    }
+    _out1
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_output(a: i32) -> i32 {
+    let mut _out1: i32 = 0;
+    let mut _out2: i32 = 0;
+    unsafe {
+        asm!("add 1, $0"
+             : "=r"(_out2)
+             : "0"(a)
+             :
+             :
+             );
+    }
+    _out1
+}
+
+
+
+// Change input -------------------------------------------------------------
+#[cfg(cfail1)]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_input(_a: i32, _b: i32) -> i32 {
+    let _out;
+    unsafe {
+        asm!("add 1, $0"
+             : "=r"(_out)
+             : "0"(_a)
+             :
+             :
+             );
+    }
+    _out
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_input(_a: i32, _b: i32) -> i32 {
+    let _out;
+    unsafe {
+        asm!("add 1, $0"
+             : "=r"(_out)
+             : "0"(_b)
+             :
+             :
+             );
+    }
+    _out
+}
+
+
+
+// Change input constraint -----------------------------------------------------
+#[cfg(cfail1)]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_input_constraint(_a: i32, _b: i32) -> i32 {
+    let _out;
+    unsafe {
+        asm!("add 1, $0"
+             : "=r"(_out)
+             : "0"(_a), "r"(_b)
+             :
+             :
+             );
+    }
+    _out
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_input_constraint(_a: i32, _b: i32) -> i32 {
+    let _out;
+    unsafe {
+        asm!("add 1, $0"
+             : "=r"(_out)
+             : "r"(_a), "0"(_b)
+             :
+             :
+             );
+    }
+    _out
+}
+
+
+
+// Change clobber --------------------------------------------------------------
+#[cfg(cfail1)]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_clobber(_a: i32) -> i32 {
+    let _out;
+    unsafe {
+        asm!("add 1, $0"
+             : "=r"(_out)
+             : "0"(_a)
+             :
+             :
+             );
+    }
+    _out
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_clobber(_a: i32) -> i32 {
+    let _out;
+    unsafe {
+        asm!("add 1, $0"
+             : "=r"(_out)
+             : "0"(_a)
+             : "eax"
+             :
+             );
+    }
+    _out
+}
+
+
+
+// Change options --------------------------------------------------------------
+#[cfg(cfail1)]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_options(_a: i32) -> i32 {
+    let _out;
+    unsafe {
+        asm!("add 1, $0"
+             : "=r"(_out)
+             : "0"(_a)
+             :
+             :
+             );
+    }
+    _out
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_options(_a: i32) -> i32 {
+    let _out;
+    unsafe {
+        asm!("add 1, $0"
+             : "=r"(_out)
+             : "0"(_a)
+             :
+             : "volatile"
+             );
+    }
+    _out
+}
+
+
+
diff --git a/src/test/incremental/hashes/struct_constructors.rs b/src/test/incremental/hashes/struct_constructors.rs
index 6a9f4698bf8..0e23d953baf 100644
--- a/src/test/incremental/hashes/struct_constructors.rs
+++ b/src/test/incremental/hashes/struct_constructors.rs
@@ -202,6 +202,12 @@ mod change_constructor_path_indirectly_regular_struct {
     #[cfg(not(cfail1))]
     use super::RegularStruct2 as Struct;
 
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[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="cfail3")]
     fn function() -> Struct {
         Struct {
             x: 0,
@@ -262,6 +268,12 @@ mod change_constructor_path_indirectly_tuple_struct {
     #[cfg(not(cfail1))]
     use super::TupleStruct2 as Struct;
 
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[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="cfail3")]
     fn function() -> Struct {
         Struct(0, 1, 2)
     }
diff --git a/src/test/mir-opt/copy_propagation.rs b/src/test/mir-opt/copy_propagation.rs
new file mode 100644
index 00000000000..26b042d0343
--- /dev/null
+++ b/src/test/mir-opt/copy_propagation.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.
+
+fn test(x: u32) -> u32 {
+    let y = x;
+    y
+}
+
+fn main() { }
+
+// END RUST SOURCE
+// START rustc.node4.CopyPropagation.before.mir
+//  bb0: {
+//      _2 = _1;
+//      _4 = _2;
+//      _3 = _4;
+//      _5 = _3;
+//      _0 = _5;
+//      return;
+//  }
+// END rustc.node4.CopyPropagation.before.mir
+// START rustc.node4.CopyPropagation.after.mir
+//  bb0: {
+//      _0 = _1;
+//      return;
+//  }
+// END rustc.node4.CopyPropagation.after.mir
diff --git a/src/test/parse-fail/where_with_bound.rs b/src/test/parse-fail/where_with_bound.rs
new file mode 100644
index 00000000000..cb57500df79
--- /dev/null
+++ b/src/test/parse-fail/where_with_bound.rs
@@ -0,0 +1,16 @@
+// 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: -Z parse-only
+
+fn foo<T>() where <T>::Item: ToString, T: Iterator { }
+               //~^ syntax `where<T>` is reserved for future use
+
+fn main() {}
diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp
index fdb7f9c68b9..6c74e7758c4 100644
--- a/src/test/pretty/issue-4264.pp
+++ b/src/test/pretty/issue-4264.pp
@@ -39,7 +39,7 @@ pub fn bar() ({
 
 
 
-                  (($crate::fmt::format as
+                  ((::fmt::format as
                        fn(std::fmt::Arguments<'_>) -> std::string::String {std::fmt::format})(((<::std::fmt::Arguments>::new_v1
                                                                                                    as
                                                                                                    fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})(({
diff --git a/src/test/run-make/issue-38237/Makefile b/src/test/run-make/issue-38237/Makefile
new file mode 100644
index 00000000000..0a681401b1a
--- /dev/null
+++ b/src/test/run-make/issue-38237/Makefile
@@ -0,0 +1,5 @@
+-include ../tools.mk
+
+all:
+	$(RUSTC) foo.rs; $(RUSTC) bar.rs
+	$(RUSTDOC) baz.rs -L $(TMPDIR) -o $(TMPDIR)
diff --git a/src/test/run-make/issue-38237/bar.rs b/src/test/run-make/issue-38237/bar.rs
new file mode 100644
index 00000000000..794e08c2fe3
--- /dev/null
+++ b/src/test/run-make/issue-38237/bar.rs
@@ -0,0 +1,14 @@
+// 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.
+
+#![crate_type = "lib"]
+
+#[derive(Debug)]
+pub struct S;
diff --git a/src/test/run-make/issue-38237/baz.rs b/src/test/run-make/issue-38237/baz.rs
new file mode 100644
index 00000000000..c2a2c89db01
--- /dev/null
+++ b/src/test/run-make/issue-38237/baz.rs
@@ -0,0 +1,18 @@
+// 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.
+
+extern crate foo;
+extern crate bar;
+
+pub struct Bar;
+impl ::std::ops::Deref for Bar {
+    type Target = bar::S;
+    fn deref(&self) -> &Self::Target { unimplemented!() }
+}
diff --git a/src/test/run-make/issue-38237/foo.rs b/src/test/run-make/issue-38237/foo.rs
new file mode 100644
index 00000000000..c291ffbf4e8
--- /dev/null
+++ b/src/test/run-make/issue-38237/foo.rs
@@ -0,0 +1,20 @@
+// 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.
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro, proc_macro_lib)]
+
+extern crate proc_macro;
+
+#[proc_macro_derive(A)]
+pub fn derive(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { ts }
+
+#[derive(Debug)]
+struct S;
diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs
index 07f7d6bad7b..e46e4fb3766 100644
--- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs
@@ -31,7 +31,7 @@ use rustc_plugin::Registry;
 
 #[plugin_registrar]
 pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_syntax_extension(
+    reg.register_custom_derive(
         Symbol::intern("derive_TotalSum"),
         MultiDecorator(box expand));
 }
diff --git a/src/test/run-pass/auxiliary/issue_38190.rs b/src/test/run-pass/auxiliary/issue_38190.rs
new file mode 100644
index 00000000000..7fc4390d6dc
--- /dev/null
+++ b/src/test/run-pass/auxiliary/issue_38190.rs
@@ -0,0 +1,12 @@
+// 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.
+
+#[macro_export]
+macro_rules! m { ([$i:item]) => {} }
diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs
index c438c17f51e..75c665b04a1 100644
--- a/src/test/run-pass/backtrace.rs
+++ b/src/test/run-pass/backtrace.rs
@@ -10,6 +10,7 @@
 
 // ignore-android FIXME #17520
 // ignore-emscripten spawning processes is not supported
+// ignore-openbsd no support for libbacktrace without filename
 // compile-flags:-g
 
 use std::env;
diff --git a/src/test/run-pass/closure-immediate.rs b/src/test/run-pass/closure-immediate.rs
new file mode 100644
index 00000000000..e566c105835
--- /dev/null
+++ b/src/test/run-pass/closure-immediate.rs
@@ -0,0 +1,22 @@
+// 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.
+
+
+// After the work to reoptimize structs, it became possible for immediate logic to fail.
+// This test verifies that it actually works.
+
+fn main() {
+    let c = |a: u8, b: u16, c: u8| {
+        assert_eq!(a, 1);
+        assert_eq!(b, 2);
+        assert_eq!(c, 3);
+    };
+    c(1, 2, 3);
+}
diff --git a/src/test/run-pass/enum-size-variance.rs b/src/test/run-pass/enum-size-variance.rs
index 26deb0ed72a..a3e95a15341 100644
--- a/src/test/run-pass/enum-size-variance.rs
+++ b/src/test/run-pass/enum-size-variance.rs
@@ -11,6 +11,9 @@
 #![warn(variant_size_differences)]
 #![allow(dead_code)]
 
+// Note that the following test works because all fields of the enum variants are of the same size.
+// If this test is modified and the reordering logic in librustc/ty/layout.rs kicks in, it fails.
+
 enum Enum1 { }
 
 enum Enum2 { A, B, C }
diff --git a/src/test/run-pass/extern-pass-empty.rs b/src/test/run-pass/extern-pass-empty.rs
index cce7dc5bf32..2606c928680 100644
--- a/src/test/run-pass/extern-pass-empty.rs
+++ b/src/test/run-pass/extern-pass-empty.rs
@@ -14,11 +14,13 @@
 // ignore-msvc
 // ignore-emscripten
 
+#[repr(C)]
 struct TwoU8s {
     one: u8,
     two: u8,
 }
 
+#[repr(C)]
 struct ManyInts {
     arg1: i8,
     arg2: i16,
@@ -28,6 +30,7 @@ struct ManyInts {
     arg6: TwoU8s,
 }
 
+#[repr(C)]
 struct Empty;
 
 #[link(name = "rust_test_helpers", kind = "static")]
diff --git a/src/test/compile-fail/unresolved_static_type_field.rs b/src/test/run-pass/issue-38190.rs
index 80f6108f02d..ed9bf9e8095 100644
--- a/src/test/compile-fail/unresolved_static_type_field.rs
+++ b/src/test/run-pass/issue-38190.rs
@@ -8,17 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn f(_: bool) {}
+// aux-build:issue_38190.rs
+// ignore-pretty issue #37195
 
-struct Foo {
-    cx: bool,
-}
+#[macro_use]
+extern crate issue_38190;
 
-impl Foo {
-    fn bar() {
-        f(cx); //~ ERROR E0425
-               //~| HELP this is an associated function
-    }
+mod auxiliary {
+    m!([mod issue_38190;]);
 }
 
 fn main() {}
diff --git a/src/test/run-pass/issue-38437.rs b/src/test/run-pass/issue-38437.rs
new file mode 100644
index 00000000000..a6e7df1c010
--- /dev/null
+++ b/src/test/run-pass/issue-38437.rs
@@ -0,0 +1,54 @@
+// 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.
+
+// Check that drop elaboration clears the "master" discriminant
+// drop flag even if it protects no fields.
+
+struct Good(usize);
+impl Drop for Good {
+    #[inline(never)]
+    fn drop(&mut self) {
+        println!("dropping Good({})", self.0);
+    }
+}
+
+struct Void;
+impl Drop for Void {
+    #[inline(never)]
+    fn drop(&mut self) {
+        panic!("Suddenly, a Void appears.");
+    }
+}
+
+enum E {
+    Never(Void),
+    Fine(Good)
+}
+
+fn main() {
+    let mut go = true;
+
+    loop {
+        let next;
+        match go {
+            true => next = E::Fine(Good(123)),
+            false => return,
+        }
+
+        match next {
+            E::Never(_) => return,
+            E::Fine(_good) => go = false,
+        }
+
+        // `next` is dropped and StorageDead'd here. We must reset the
+        // discriminant's drop flag to avoid random variants being
+        // dropped.
+    }
+}
diff --git a/src/test/compile-fail/E0248.rs b/src/test/run-pass/issue-38556.rs
index 25568a323e1..f6f334f650b 100644
--- a/src/test/compile-fail/E0248.rs
+++ b/src/test/run-pass/issue-38556.rs
@@ -8,11 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-enum Foo {
-    Bar(u32),
+pub struct Foo;
+
+macro_rules! reexport {
+    () => { use Foo as Bar; }
 }
 
-fn do_something(x: Foo::Bar) { } //~ ERROR E0248
-                //~| NOTE value used as a type
+reexport!();
+
 fn main() {
+    use Bar;
+    fn f(_: Bar) {}
 }
diff --git a/src/test/run-pass/issue-8521.rs b/src/test/run-pass/issue-8521.rs
new file mode 100644
index 00000000000..ce362c4bcd1
--- /dev/null
+++ b/src/test/run-pass/issue-8521.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.
+
+trait Foo1 {}
+
+trait A {}
+
+macro_rules! foo1(($t:path) => {
+    impl<T: $t> Foo1 for T {}
+});
+
+foo1!(A);
+
+trait Foo2 {}
+
+trait B<T> {}
+
+#[allow(unused)]
+struct C {}
+
+macro_rules! foo2(($t:path) => {
+    impl<T: $t> Foo2 for T {}
+});
+
+foo2!(B<C>);
+
+fn main() {}
diff --git a/src/test/run-pass/multiple-reprs.rs b/src/test/run-pass/multiple-reprs.rs
new file mode 100644
index 00000000000..c2fe943eed8
--- /dev/null
+++ b/src/test/run-pass/multiple-reprs.rs
@@ -0,0 +1,43 @@
+// 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.
+
+
+use std::mem::size_of;
+
+// The two enums that follow are designed so that bugs trigger layout optimization.
+// Specifically, if either of the following reprs used here is not detected by the compiler,
+// then the sizes will be wrong.
+
+#[repr(C, u8)]
+enum E1 {
+    A(u8, u16, u8),
+    B(u8, u16, u8)
+}
+
+#[repr(u8, C)]
+enum E2 {
+    A(u8, u16, u8),
+    B(u8, u16, u8)
+}
+
+// From pr 37429
+
+#[repr(C,packed)]
+pub struct p0f_api_query {
+    pub magic: u32,
+    pub addr_type: u8,
+    pub addr: [u8; 16],
+}
+
+pub fn main() {
+    assert_eq!(size_of::<E1>(), 6);
+    assert_eq!(size_of::<E2>(), 6);
+    assert_eq!(size_of::<p0f_api_query>(), 21);
+}
diff --git a/src/test/run-pass/nonzero-enum.rs b/src/test/run-pass/nonzero-enum.rs
index 266506e04b7..fc92c9df9f7 100644
--- a/src/test/run-pass/nonzero-enum.rs
+++ b/src/test/run-pass/nonzero-enum.rs
@@ -26,8 +26,7 @@ fn main() {
     assert_eq!(size_of::<E>(), 1);
     assert_eq!(size_of::<Option<E>>(), 1);
     assert_eq!(size_of::<Result<E, ()>>(), 1);
-    assert_eq!(size_of::<S>(), 4);
-    assert_eq!(size_of::<Option<S>>(), 4);
+    assert_eq!(size_of::<Option<S>>(), size_of::<S>());
     let enone = None::<E>;
     let esome = Some(E::A);
     if let Some(..) = enone {
diff --git a/src/test/run-pass/struct-return.rs b/src/test/run-pass/struct-return.rs
index 3d4601ad0cf..ed618cea98a 100644
--- a/src/test/run-pass/struct-return.rs
+++ b/src/test/run-pass/struct-return.rs
@@ -9,9 +9,11 @@
 // except according to those terms.
 //
 
+#[repr(C)]
 #[derive(Copy, Clone)]
 pub struct Quad { a: u64, b: u64, c: u64, d: u64 }
 
+#[repr(C)]
 #[derive(Copy, Clone)]
 pub struct Floats { a: f64, b: u8, c: f64 }
 
diff --git a/src/test/run-pass/trans-object-shim.rs b/src/test/run-pass/trans-object-shim.rs
new file mode 100644
index 00000000000..5fbfef05e10
--- /dev/null
+++ b/src/test/run-pass/trans-object-shim.rs
@@ -0,0 +1,14 @@
+// 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.
+
+fn main() {
+    assert_eq!((ToString::to_string as fn(&(ToString+'static)) -> String)(&"foo"),
+        String::from("foo"));
+}
diff --git a/src/test/run-pass/type-sizes.rs b/src/test/run-pass/type-sizes.rs
index 86159ce340b..bbb01eaaf46 100644
--- a/src/test/run-pass/type-sizes.rs
+++ b/src/test/run-pass/type-sizes.rs
@@ -26,6 +26,7 @@ enum e2 {
     a(u32), b
 }
 
+#[repr(C, u8)]
 enum e3 {
     a([u16; 0], u8), b
 }
diff --git a/src/test/rustdoc/search-index-summaries.rs b/src/test/rustdoc/search-index-summaries.rs
new file mode 100644
index 00000000000..dd195dc33e4
--- /dev/null
+++ b/src/test/rustdoc/search-index-summaries.rs
@@ -0,0 +1,20 @@
+// 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.
+
+#![crate_name = "foo"]
+
+// @has 'search-index.js' 'Foo short link.'
+// @!has - 'www.example.com'
+// @!has - 'More Foo.'
+
+/// Foo short [link](https://www.example.com/).
+///
+/// More Foo.
+pub struct Foo;
diff --git a/src/test/ui/codemap_tests/tab.stderr b/src/test/ui/codemap_tests/tab.stderr
index f865f0a5f23..73d548009dd 100644
--- a/src/test/ui/codemap_tests/tab.stderr
+++ b/src/test/ui/codemap_tests/tab.stderr
@@ -1,8 +1,8 @@
-error[E0425]: unresolved name `bar`
+error[E0425]: unresolved value `bar`
   --> $DIR/tab.rs:14:2
    |
 14 | \tbar;
-   | \t^^^ unresolved name
+   | \t^^^ no resolution found
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/codemap_tests/two_files.stderr b/src/test/ui/codemap_tests/two_files.stderr
index d05e6eb2bbe..9db43dde1ac 100644
--- a/src/test/ui/codemap_tests/two_files.stderr
+++ b/src/test/ui/codemap_tests/two_files.stderr
@@ -1,10 +1,8 @@
-error[E0404]: `Bar` is not a trait
+error[E0404]: expected trait, found type alias `Bar`
   --> $DIR/two_files.rs:15:6
    |
 15 | impl Bar for Baz { }
-   |      ^^^ expected trait, found type alias
-   |
-   = note: type aliases cannot be used for traits
+   |      ^^^ type aliases cannot be used for traits
 
 error: cannot continue compilation due to previous error
 
diff --git a/src/test/ui/macros/macro-backtrace-nested.stderr b/src/test/ui/macros/macro-backtrace-nested.stderr
index 1c7fac894f9..27514093621 100644
--- a/src/test/ui/macros/macro-backtrace-nested.stderr
+++ b/src/test/ui/macros/macro-backtrace-nested.stderr
@@ -1,17 +1,17 @@
-error[E0425]: unresolved name `fake`
+error[E0425]: unresolved value `fake`
   --> $DIR/macro-backtrace-nested.rs:15:12
    |
 15 |     () => (fake)
-   |            ^^^^ unresolved name
+   |            ^^^^ no resolution found
 ...
 27 |     1 + call_nested_expr!();
    |         ------------------- in this macro invocation
 
-error[E0425]: unresolved name `fake`
+error[E0425]: unresolved value `fake`
   --> $DIR/macro-backtrace-nested.rs:15:12
    |
 15 |     () => (fake)
-   |            ^^^^ unresolved name
+   |            ^^^^ no resolution found
 ...
 28 |     call_nested_expr_sum!();
    |     ------------------------ in this macro invocation
diff --git a/src/test/ui/macros/macro_path_as_generic_bound.rs b/src/test/ui/macros/macro_path_as_generic_bound.rs
new file mode 100644
index 00000000000..781ea30ed8b
--- /dev/null
+++ b/src/test/ui/macros/macro_path_as_generic_bound.rs
@@ -0,0 +1,19 @@
+// 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.
+
+trait Foo {}
+
+macro_rules! foo(($t:path) => {
+    impl<T: $t> Foo for T {}
+});
+
+foo!(m::m2::A);
+
+fn main() {}
diff --git a/src/test/ui/macros/macro_path_as_generic_bound.stderr b/src/test/ui/macros/macro_path_as_generic_bound.stderr
new file mode 100644
index 00000000000..96635032105
--- /dev/null
+++ b/src/test/ui/macros/macro_path_as_generic_bound.stderr
@@ -0,0 +1,11 @@
+error[E0433]: failed to resolve. Use of undeclared type or module `m`
+  --> $DIR/macro_path_as_generic_bound.rs:17:6
+   |
+17 | foo!(m::m2::A);
+   | -----^^^^^^^^--
+   | |    |
+   | |    Use of undeclared type or module `m`
+   | in this macro invocation
+
+error: cannot continue compilation due to previous error
+
diff --git a/src/test/ui/mismatched_types/cast-rfc0401.rs b/src/test/ui/mismatched_types/cast-rfc0401.rs
new file mode 100644
index 00000000000..f72be0d7054
--- /dev/null
+++ b/src/test/ui/mismatched_types/cast-rfc0401.rs
@@ -0,0 +1,82 @@
+// 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.
+
+fn illegal_cast<U:?Sized,V:?Sized>(u: *const U) -> *const V
+{
+    u as *const V
+}
+
+fn illegal_cast_2<U:?Sized>(u: *const U) -> *const str
+{
+    u as *const str
+}
+
+trait Foo { fn foo(&self) {} }
+impl<T> Foo for T {}
+
+trait Bar { fn foo(&self) {} }
+impl<T> Bar for T {}
+
+enum E {
+    A, B
+}
+
+fn main()
+{
+    let f: f32 = 1.2;
+    let v = 0 as *const u8;
+    let fat_v : *const [u8] = unsafe { &*(0 as *const [u8; 1])};
+    let fat_sv : *const [i8] = unsafe { &*(0 as *const [i8; 1])};
+    let foo: &Foo = &f;
+
+    let _ = v as &u8;
+    let _ = v as E;
+    let _ = v as fn();
+    let _ = v as (u32,);
+    let _ = Some(&v) as *const u8;
+
+    let _ = v as f32;
+    let _ = main as f64;
+    let _ = &v as usize;
+    let _ = f as *const u8;
+    let _ = 3_i32 as bool;
+    let _ = E::A as bool;
+    let _ = 0x61u32 as char;
+
+    let _ = false as f32;
+    let _ = E::A as f32;
+    let _ = 'a' as f32;
+
+    let _ = false as *const u8;
+    let _ = E::A as *const u8;
+    let _ = 'a' as *const u8;
+
+    let _ = 42usize as *const [u8];
+    let _ = v as *const [u8];
+    let _ = fat_v as *const Foo;
+    let _ = foo as *const str;
+    let _ = foo as *mut str;
+    let _ = main as *mut str;
+    let _ = &f as *mut f32;
+    let _ = &f as *const f64;
+    let _ = fat_sv as usize;
+
+    let a : *const str = "hello";
+    let _ = a as *const Foo;
+
+    // check no error cascade
+    let _ = main.f as *const u32;
+
+    let cf: *const Foo = &0;
+    let _ = cf as *const [u16];
+    let _ = cf as *const Bar;
+
+    vec![0.0].iter().map(|s| s as f32).collect::<Vec<f32>>();
+}
diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr
new file mode 100644
index 00000000000..7fd10f3cb68
--- /dev/null
+++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr
@@ -0,0 +1,240 @@
+error: casting `*const U` as `*const V` is invalid
+  --> $DIR/cast-rfc0401.rs:13:5
+   |
+13 |     u as *const V
+   |     ^^^^^^^^^^^^^
+   |
+   = note: vtable kinds may not match
+
+error: casting `*const U` as `*const str` is invalid
+  --> $DIR/cast-rfc0401.rs:18:5
+   |
+18 |     u as *const str
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: vtable kinds may not match
+
+error: no field `f` on type `fn() {main}`
+  --> $DIR/cast-rfc0401.rs:75:18
+   |
+75 |     let _ = main.f as *const u32;
+   |                  ^
+
+error: non-scalar cast: `*const u8` as `&u8`
+  --> $DIR/cast-rfc0401.rs:39:13
+   |
+39 |     let _ = v as &u8;
+   |             ^^^^^^^^
+
+error: non-scalar cast: `*const u8` as `E`
+  --> $DIR/cast-rfc0401.rs:40:13
+   |
+40 |     let _ = v as E;
+   |             ^^^^^^
+
+error: non-scalar cast: `*const u8` as `fn()`
+  --> $DIR/cast-rfc0401.rs:41:13
+   |
+41 |     let _ = v as fn();
+   |             ^^^^^^^^^
+
+error: non-scalar cast: `*const u8` as `(u32,)`
+  --> $DIR/cast-rfc0401.rs:42:13
+   |
+42 |     let _ = v as (u32,);
+   |             ^^^^^^^^^^^
+
+error: non-scalar cast: `std::option::Option<&*const u8>` as `*const u8`
+  --> $DIR/cast-rfc0401.rs:43:13
+   |
+43 |     let _ = Some(&v) as *const u8;
+   |             ^^^^^^^^^^^^^^^^^^^^^
+
+error: casting `*const u8` as `f32` is invalid
+  --> $DIR/cast-rfc0401.rs:45:13
+   |
+45 |     let _ = v as f32;
+   |             ^^^^^^^^
+
+error: casting `fn() {main}` as `f64` is invalid
+  --> $DIR/cast-rfc0401.rs:46:13
+   |
+46 |     let _ = main as f64;
+   |             ^^^^^^^^^^^
+
+error: casting `&*const u8` as `usize` is invalid
+  --> $DIR/cast-rfc0401.rs:47:13
+   |
+47 |     let _ = &v as usize;
+   |             ^^^^^^^^^^^
+   |
+   = help: cast through a raw pointer first
+
+error: casting `f32` as `*const u8` is invalid
+  --> $DIR/cast-rfc0401.rs:48:13
+   |
+48 |     let _ = f as *const u8;
+   |             ^^^^^^^^^^^^^^
+
+error[E0054]: cannot cast as `bool`
+  --> $DIR/cast-rfc0401.rs:49:13
+   |
+49 |     let _ = 3_i32 as bool;
+   |             ^^^^^^^^^^^^^ unsupported cast
+   |
+   = help: compare with zero instead
+
+error[E0054]: cannot cast as `bool`
+  --> $DIR/cast-rfc0401.rs:50:13
+   |
+50 |     let _ = E::A as bool;
+   |             ^^^^^^^^^^^^ unsupported cast
+   |
+   = help: compare with zero instead
+
+error: only `u8` can be cast as `char`, not `u32`
+  --> $DIR/cast-rfc0401.rs:51:13
+   |
+51 |     let _ = 0x61u32 as char;
+   |             ^^^^^^^^^^^^^^^
+
+error: casting `bool` as `f32` is invalid
+  --> $DIR/cast-rfc0401.rs:53:13
+   |
+53 |     let _ = false as f32;
+   |             ^^^^^^^^^^^^
+   |
+   = help: cast through an integer first
+
+error: casting `E` as `f32` is invalid
+  --> $DIR/cast-rfc0401.rs:54:13
+   |
+54 |     let _ = E::A as f32;
+   |             ^^^^^^^^^^^
+   |
+   = help: cast through an integer first
+
+error: casting `char` as `f32` is invalid
+  --> $DIR/cast-rfc0401.rs:55:13
+   |
+55 |     let _ = 'a' as f32;
+   |             ^^^^^^^^^^
+   |
+   = help: cast through an integer first
+
+error: casting `bool` as `*const u8` is invalid
+  --> $DIR/cast-rfc0401.rs:57:13
+   |
+57 |     let _ = false as *const u8;
+   |             ^^^^^^^^^^^^^^^^^^
+
+error: casting `E` as `*const u8` is invalid
+  --> $DIR/cast-rfc0401.rs:58:13
+   |
+58 |     let _ = E::A as *const u8;
+   |             ^^^^^^^^^^^^^^^^^
+
+error: casting `char` as `*const u8` is invalid
+  --> $DIR/cast-rfc0401.rs:59:13
+   |
+59 |     let _ = 'a' as *const u8;
+   |             ^^^^^^^^^^^^^^^^
+
+error: casting `usize` as `*const [u8]` is invalid
+  --> $DIR/cast-rfc0401.rs:61:13
+   |
+61 |     let _ = 42usize as *const [u8];
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+
+error: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]`
+  --> $DIR/cast-rfc0401.rs:62:13
+   |
+62 |     let _ = v as *const [u8];
+   |             ^^^^^^^^^^^^^^^^
+
+error: casting `&Foo` as `*const str` is invalid
+  --> $DIR/cast-rfc0401.rs:64:13
+   |
+64 |     let _ = foo as *const str;
+   |             ^^^^^^^^^^^^^^^^^
+
+error: casting `&Foo` as `*mut str` is invalid
+  --> $DIR/cast-rfc0401.rs:65:13
+   |
+65 |     let _ = foo as *mut str;
+   |             ^^^^^^^^^^^^^^^
+
+error: casting `fn() {main}` as `*mut str` is invalid
+  --> $DIR/cast-rfc0401.rs:66:13
+   |
+66 |     let _ = main as *mut str;
+   |             ^^^^^^^^^^^^^^^^
+
+error: casting `&f32` as `*mut f32` is invalid
+  --> $DIR/cast-rfc0401.rs:67:13
+   |
+67 |     let _ = &f as *mut f32;
+   |             ^^^^^^^^^^^^^^
+
+error: casting `&f32` as `*const f64` is invalid
+  --> $DIR/cast-rfc0401.rs:68:13
+   |
+68 |     let _ = &f as *const f64;
+   |             ^^^^^^^^^^^^^^^^
+
+error: casting `*const [i8]` as `usize` is invalid
+  --> $DIR/cast-rfc0401.rs:69:13
+   |
+69 |     let _ = fat_sv as usize;
+   |             ^^^^^^^^^^^^^^^
+   |
+   = help: cast through a thin pointer first
+
+error: casting `*const Foo` as `*const [u16]` is invalid
+  --> $DIR/cast-rfc0401.rs:78:13
+   |
+78 |     let _ = cf as *const [u16];
+   |             ^^^^^^^^^^^^^^^^^^
+   |
+   = note: vtable kinds may not match
+
+error: casting `*const Foo` as `*const Bar` is invalid
+  --> $DIR/cast-rfc0401.rs:79:13
+   |
+79 |     let _ = cf as *const Bar;
+   |             ^^^^^^^^^^^^^^^^
+   |
+   = note: vtable kinds may not match
+
+error[E0277]: the trait bound `[u8]: std::marker::Sized` is not satisfied
+  --> $DIR/cast-rfc0401.rs:63:13
+   |
+63 |     let _ = fat_v as *const Foo;
+   |             ^^^^^ the trait `std::marker::Sized` is not implemented for `[u8]`
+   |
+   = note: `[u8]` does not have a constant size known at compile-time
+   = note: required for the cast to the object type `Foo`
+
+error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
+  --> $DIR/cast-rfc0401.rs:72:13
+   |
+72 |     let _ = a as *const Foo;
+   |             ^ the trait `std::marker::Sized` is not implemented for `str`
+   |
+   = note: `str` does not have a constant size known at compile-time
+   = note: required for the cast to the object type `Foo`
+
+error: casting `&{float}` as `f32` is invalid
+  --> $DIR/cast-rfc0401.rs:81:30
+   |
+81 |     vec![0.0].iter().map(|s| s as f32).collect::<Vec<f32>>();
+   |                              ^^^^^^^^ cannot cast `&{float}` as `f32`
+   |
+help: did you mean `*s`?
+  --> $DIR/cast-rfc0401.rs:81:30
+   |
+81 |     vec![0.0].iter().map(|s| s as f32).collect::<Vec<f32>>();
+   |                              ^
+
+error: aborting due to 34 previous errors
+
diff --git a/src/test/compile-fail/auxiliary/issue-21221-3.rs b/src/test/ui/resolve/auxiliary/issue-21221-3.rs
index fae0fe16a26..fae0fe16a26 100644
--- a/src/test/compile-fail/auxiliary/issue-21221-3.rs
+++ b/src/test/ui/resolve/auxiliary/issue-21221-3.rs
diff --git a/src/test/compile-fail/auxiliary/issue-21221-4.rs b/src/test/ui/resolve/auxiliary/issue-21221-4.rs
index fffe060ee24..fffe060ee24 100644
--- a/src/test/compile-fail/auxiliary/issue-21221-4.rs
+++ b/src/test/ui/resolve/auxiliary/issue-21221-4.rs
diff --git a/src/test/compile-fail/auxiliary/issue_19452_aux.rs b/src/test/ui/resolve/auxiliary/issue_19452_aux.rs
index 205566e4b1f..205566e4b1f 100644
--- a/src/test/compile-fail/auxiliary/issue_19452_aux.rs
+++ b/src/test/ui/resolve/auxiliary/issue_19452_aux.rs
diff --git a/src/test/compile-fail/auxiliary/issue_3907.rs b/src/test/ui/resolve/auxiliary/issue_3907.rs
index 6472c08c222..6472c08c222 100644
--- a/src/test/compile-fail/auxiliary/issue_3907.rs
+++ b/src/test/ui/resolve/auxiliary/issue_3907.rs
diff --git a/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs b/src/test/ui/resolve/auxiliary/namespaced_enums.rs
index 465bddd060d..3bf39b788db 100644
--- a/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs
+++ b/src/test/ui/resolve/auxiliary/namespaced_enums.rs
@@ -8,10 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn f<F:Nonexist(isize) -> isize>(x: F) {} //~ ERROR trait `Nonexist` is not in scope
+pub enum Foo {
+    A,
+    B(isize),
+    C { a: isize },
+}
 
-type Typedef = isize;
-
-fn g<F:Typedef(isize) -> isize>(x: F) {} //~ ERROR `Typedef` is not a trait
-
-fn main() {}
+impl Foo {
+    pub fn foo() {}
+    pub fn bar(&self) {}
+}
diff --git a/src/test/compile-fail/enums-are-namespaced-xc.rs b/src/test/ui/resolve/enums-are-namespaced-xc.rs
index 02939565f69..4f55f33d7f8 100644
--- a/src/test/compile-fail/enums-are-namespaced-xc.rs
+++ b/src/test/ui/resolve/enums-are-namespaced-xc.rs
@@ -12,8 +12,13 @@
 extern crate namespaced_enums;
 
 fn main() {
-    let _ = namespaced_enums::A; //~ ERROR unresolved name
-    let _ = namespaced_enums::B(10); //~ ERROR unresolved name
+    let _ = namespaced_enums::A;
+    //~^ ERROR unresolved value `namespaced_enums::A`
+    //~| HELP you can import it into scope: `use namespaced_enums::Foo::A;`
+    let _ = namespaced_enums::B(10);
+    //~^ ERROR unresolved function `namespaced_enums::B`
+    //~| HELP you can import it into scope: `use namespaced_enums::Foo::B;`
     let _ = namespaced_enums::C { a: 10 };
     //~^ ERROR unresolved struct, variant or union type `namespaced_enums::C`
+    //~| HELP you can import it into scope: `use namespaced_enums::Foo::C;`
 }
diff --git a/src/test/ui/resolve/enums-are-namespaced-xc.stderr b/src/test/ui/resolve/enums-are-namespaced-xc.stderr
new file mode 100644
index 00000000000..fda8023b7f6
--- /dev/null
+++ b/src/test/ui/resolve/enums-are-namespaced-xc.stderr
@@ -0,0 +1,29 @@
+error[E0425]: unresolved value `namespaced_enums::A`
+  --> $DIR/enums-are-namespaced-xc.rs:15:13
+   |
+15 |     let _ = namespaced_enums::A;
+   |             ^^^^^^^^^^^^^^^^^^^ no resolution found
+   |
+   = help: possible candidate is found in another module, you can import it into scope:
+   = help:   `use namespaced_enums::Foo::A;`
+
+error[E0425]: unresolved function `namespaced_enums::B`
+  --> $DIR/enums-are-namespaced-xc.rs:18:13
+   |
+18 |     let _ = namespaced_enums::B(10);
+   |             ^^^^^^^^^^^^^^^^^^^ no resolution found
+   |
+   = help: possible candidate is found in another module, you can import it into scope:
+   = help:   `use namespaced_enums::Foo::B;`
+
+error[E0422]: unresolved struct, variant or union type `namespaced_enums::C`
+  --> $DIR/enums-are-namespaced-xc.rs:21:13
+   |
+21 |     let _ = namespaced_enums::C { a: 10 };
+   |             ^^^^^^^^^^^^^^^^^^^ no resolution found
+   |
+   = help: possible candidate is found in another module, you can import it into scope:
+   = help:   `use namespaced_enums::Foo::C;`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/resolve/issue-14254.rs b/src/test/ui/resolve/issue-14254.rs
new file mode 100644
index 00000000000..b1fc6c47720
--- /dev/null
+++ b/src/test/ui/resolve/issue-14254.rs
@@ -0,0 +1,137 @@
+// 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.
+
+trait Foo {
+    fn bar(&self);
+    fn baz(&self) { }
+    fn bah(_: Option<&Self>) { }
+}
+
+struct BarTy {
+    x : isize,
+    y : f64,
+}
+
+impl BarTy {
+    fn a() {}
+    fn b(&self) {}
+}
+
+impl Foo for *const BarTy {
+    fn bar(&self) {
+        baz();
+        //~^ ERROR unresolved function `baz`
+        //~| NOTE did you mean `self.baz(...)`?
+        a;
+        //~^ ERROR unresolved value `a`
+        //~| NOTE no resolution found
+    }
+}
+
+impl<'a> Foo for &'a BarTy {
+    fn bar(&self) {
+        baz();
+        //~^ ERROR unresolved function `baz`
+        //~| NOTE did you mean `self.baz(...)`?
+        x;
+        //~^ ERROR unresolved value `x`
+        //~| NOTE did you mean `self.x`?
+        y;
+        //~^ ERROR unresolved value `y`
+        //~| NOTE did you mean `self.y`?
+        a;
+        //~^ ERROR unresolved value `a`
+        //~| NOTE no resolution found
+        bah;
+        //~^ ERROR unresolved value `bah`
+        //~| NOTE did you mean `Self::bah`?
+        b;
+        //~^ ERROR unresolved value `b`
+        //~| NOTE no resolution found
+    }
+}
+
+impl<'a> Foo for &'a mut BarTy {
+    fn bar(&self) {
+        baz();
+        //~^ ERROR unresolved function `baz`
+        //~| NOTE did you mean `self.baz(...)`?
+        x;
+        //~^ ERROR unresolved value `x`
+        //~| NOTE did you mean `self.x`?
+        y;
+        //~^ ERROR unresolved value `y`
+        //~| NOTE did you mean `self.y`?
+        a;
+        //~^ ERROR unresolved value `a`
+        //~| NOTE no resolution found
+        bah;
+        //~^ ERROR unresolved value `bah`
+        //~| NOTE did you mean `Self::bah`?
+        b;
+        //~^ ERROR unresolved value `b`
+        //~| NOTE no resolution found
+    }
+}
+
+impl Foo for Box<BarTy> {
+    fn bar(&self) {
+        baz();
+        //~^ ERROR unresolved function `baz`
+        //~| NOTE did you mean `self.baz(...)`?
+        bah;
+        //~^ ERROR unresolved value `bah`
+        //~| NOTE did you mean `Self::bah`?
+    }
+}
+
+impl Foo for *const isize {
+    fn bar(&self) {
+        baz();
+        //~^ ERROR unresolved function `baz`
+        //~| NOTE did you mean `self.baz(...)`?
+        bah;
+        //~^ ERROR unresolved value `bah`
+        //~| NOTE did you mean `Self::bah`?
+    }
+}
+
+impl<'a> Foo for &'a isize {
+    fn bar(&self) {
+        baz();
+        //~^ ERROR unresolved function `baz`
+        //~| NOTE did you mean `self.baz(...)`?
+        bah;
+        //~^ ERROR unresolved value `bah`
+        //~| NOTE did you mean `Self::bah`?
+    }
+}
+
+impl<'a> Foo for &'a mut isize {
+    fn bar(&self) {
+        baz();
+        //~^ ERROR unresolved function `baz`
+        //~| NOTE did you mean `self.baz(...)`?
+        bah;
+        //~^ ERROR unresolved value `bah`
+        //~| NOTE did you mean `Self::bah`?
+    }
+}
+
+impl Foo for Box<isize> {
+    fn bar(&self) {
+        baz();
+        //~^ ERROR unresolved function `baz`
+        //~| NOTE did you mean `self.baz(...)`?
+        bah;
+        //~^ ERROR unresolved value `bah`
+        //~| NOTE did you mean `Self::bah`?
+    }
+}
diff --git a/src/test/ui/resolve/issue-14254.stderr b/src/test/ui/resolve/issue-14254.stderr
new file mode 100644
index 00000000000..2780c1c406f
--- /dev/null
+++ b/src/test/ui/resolve/issue-14254.stderr
@@ -0,0 +1,148 @@
+error[E0425]: unresolved function `baz`
+  --> $DIR/issue-14254.rs:29:9
+   |
+29 |         baz();
+   |         ^^^ did you mean `self.baz(...)`?
+
+error[E0425]: unresolved value `a`
+  --> $DIR/issue-14254.rs:32:9
+   |
+32 |         a;
+   |         ^ no resolution found
+
+error[E0425]: unresolved function `baz`
+  --> $DIR/issue-14254.rs:40:9
+   |
+40 |         baz();
+   |         ^^^ did you mean `self.baz(...)`?
+
+error[E0425]: unresolved value `x`
+  --> $DIR/issue-14254.rs:43:9
+   |
+43 |         x;
+   |         ^ did you mean `self.x`?
+
+error[E0425]: unresolved value `y`
+  --> $DIR/issue-14254.rs:46:9
+   |
+46 |         y;
+   |         ^ did you mean `self.y`?
+
+error[E0425]: unresolved value `a`
+  --> $DIR/issue-14254.rs:49:9
+   |
+49 |         a;
+   |         ^ no resolution found
+
+error[E0425]: unresolved value `bah`
+  --> $DIR/issue-14254.rs:52:9
+   |
+52 |         bah;
+   |         ^^^ did you mean `Self::bah`?
+
+error[E0425]: unresolved value `b`
+  --> $DIR/issue-14254.rs:55:9
+   |
+55 |         b;
+   |         ^ no resolution found
+
+error[E0425]: unresolved function `baz`
+  --> $DIR/issue-14254.rs:63:9
+   |
+63 |         baz();
+   |         ^^^ did you mean `self.baz(...)`?
+
+error[E0425]: unresolved value `x`
+  --> $DIR/issue-14254.rs:66:9
+   |
+66 |         x;
+   |         ^ did you mean `self.x`?
+
+error[E0425]: unresolved value `y`
+  --> $DIR/issue-14254.rs:69:9
+   |
+69 |         y;
+   |         ^ did you mean `self.y`?
+
+error[E0425]: unresolved value `a`
+  --> $DIR/issue-14254.rs:72:9
+   |
+72 |         a;
+   |         ^ no resolution found
+
+error[E0425]: unresolved value `bah`
+  --> $DIR/issue-14254.rs:75:9
+   |
+75 |         bah;
+   |         ^^^ did you mean `Self::bah`?
+
+error[E0425]: unresolved value `b`
+  --> $DIR/issue-14254.rs:78:9
+   |
+78 |         b;
+   |         ^ no resolution found
+
+error[E0425]: unresolved function `baz`
+  --> $DIR/issue-14254.rs:86:9
+   |
+86 |         baz();
+   |         ^^^ did you mean `self.baz(...)`?
+
+error[E0425]: unresolved value `bah`
+  --> $DIR/issue-14254.rs:89:9
+   |
+89 |         bah;
+   |         ^^^ did you mean `Self::bah`?
+
+error[E0425]: unresolved function `baz`
+  --> $DIR/issue-14254.rs:97:9
+   |
+97 |         baz();
+   |         ^^^ did you mean `self.baz(...)`?
+
+error[E0425]: unresolved value `bah`
+   --> $DIR/issue-14254.rs:100:9
+    |
+100 |         bah;
+    |         ^^^ did you mean `Self::bah`?
+
+error[E0425]: unresolved function `baz`
+   --> $DIR/issue-14254.rs:108:9
+    |
+108 |         baz();
+    |         ^^^ did you mean `self.baz(...)`?
+
+error[E0425]: unresolved value `bah`
+   --> $DIR/issue-14254.rs:111:9
+    |
+111 |         bah;
+    |         ^^^ did you mean `Self::bah`?
+
+error[E0425]: unresolved function `baz`
+   --> $DIR/issue-14254.rs:119:9
+    |
+119 |         baz();
+    |         ^^^ did you mean `self.baz(...)`?
+
+error[E0425]: unresolved value `bah`
+   --> $DIR/issue-14254.rs:122:9
+    |
+122 |         bah;
+    |         ^^^ did you mean `Self::bah`?
+
+error[E0425]: unresolved function `baz`
+   --> $DIR/issue-14254.rs:130:9
+    |
+130 |         baz();
+    |         ^^^ did you mean `self.baz(...)`?
+
+error[E0425]: unresolved value `bah`
+   --> $DIR/issue-14254.rs:133:9
+    |
+133 |         bah;
+    |         ^^^ did you mean `Self::bah`?
+
+error: main function not found
+
+error: aborting due to 25 previous errors
+
diff --git a/src/test/compile-fail/issue-16058.rs b/src/test/ui/resolve/issue-16058.rs
index 92c1e4b5f50..1f777e53632 100644
--- a/src/test/compile-fail/issue-16058.rs
+++ b/src/test/ui/resolve/issue-16058.rs
@@ -16,7 +16,12 @@ pub struct GslResult {
 
 impl GslResult {
     pub fn new() -> GslResult {
-        Result { //~ ERROR: expected struct, variant or union type, found enum `Result`
+        Result {
+//~^ ERROR expected struct, variant or union type, found enum `Result`
+//~| HELP possible better candidates are found in other modules, you can import them into scope
+//~| HELP std::fmt::Result
+//~| HELP std::io::Result
+//~| HELP std::thread::Result
             val: 0f64,
             err: 0f64
         }
diff --git a/src/test/ui/resolve/issue-16058.stderr b/src/test/ui/resolve/issue-16058.stderr
new file mode 100644
index 00000000000..6b00cfb8693
--- /dev/null
+++ b/src/test/ui/resolve/issue-16058.stderr
@@ -0,0 +1,13 @@
+error[E0574]: expected struct, variant or union type, found enum `Result`
+  --> $DIR/issue-16058.rs:19:9
+   |
+19 |         Result {
+   |         ^^^^^^ not a struct, variant or union type
+   |
+   = help: possible better candidates are found in other modules, you can import them into scope:
+   = help:   `use std::fmt::Result;`
+   = help:   `use std::io::Result;`
+   = help:   `use std::thread::Result;`
+
+error: aborting due to previous error
+
diff --git a/src/test/compile-fail/issue-17518.rs b/src/test/ui/resolve/issue-17518.rs
index 2113e38c45c..3ac9b379d18 100644
--- a/src/test/compile-fail/issue-17518.rs
+++ b/src/test/ui/resolve/issue-17518.rs
@@ -14,4 +14,5 @@ enum SomeEnum {
 
 fn main() {
     E { name: "foobar" }; //~ ERROR unresolved struct, variant or union type `E`
+                          //~^ HELP you can import it into scope: `use SomeEnum::E;`
 }
diff --git a/src/test/ui/resolve/issue-17518.stderr b/src/test/ui/resolve/issue-17518.stderr
new file mode 100644
index 00000000000..9de43728b2f
--- /dev/null
+++ b/src/test/ui/resolve/issue-17518.stderr
@@ -0,0 +1,11 @@
+error[E0422]: unresolved struct, variant or union type `E`
+  --> $DIR/issue-17518.rs:16:5
+   |
+16 |     E { name: "foobar" }; //~ ERROR unresolved struct, variant or union type `E`
+   |     ^ no resolution found
+   |
+   = help: possible candidate is found in another module, you can import it into scope:
+   = help:   `use SomeEnum::E;`
+
+error: aborting due to previous error
+
diff --git a/src/test/compile-fail/issue-18252.rs b/src/test/ui/resolve/issue-18252.rs
index 8e3faca02b7..02c6643a920 100644
--- a/src/test/compile-fail/issue-18252.rs
+++ b/src/test/ui/resolve/issue-18252.rs
@@ -14,6 +14,5 @@ enum Foo {
 
 fn main() {
     let f = Foo::Variant(42);
-    //~^ ERROR uses it like a function
-    //~| struct called like a function
+    //~^ ERROR expected function, found struct variant `Foo::Variant`
 }
diff --git a/src/test/ui/resolve/issue-18252.stderr b/src/test/ui/resolve/issue-18252.stderr
new file mode 100644
index 00000000000..edc7196d846
--- /dev/null
+++ b/src/test/ui/resolve/issue-18252.stderr
@@ -0,0 +1,8 @@
+error[E0423]: expected function, found struct variant `Foo::Variant`
+  --> $DIR/issue-18252.rs:16:13
+   |
+16 |     let f = Foo::Variant(42);
+   |             ^^^^^^^^^^^^ did you mean `Foo::Variant { /* fields */ }`?
+
+error: aborting due to previous error
+
diff --git a/src/test/compile-fail/issue-19452.rs b/src/test/ui/resolve/issue-19452.rs
index 34872b7c8c5..080fb064c9f 100644
--- a/src/test/compile-fail/issue-19452.rs
+++ b/src/test/ui/resolve/issue-19452.rs
@@ -17,10 +17,8 @@ enum Homura {
 
 fn main() {
     let homura = Homura::Madoka;
-    //~^ ERROR uses it like a function
-    //~| struct called like a function
+    //~^ ERROR expected value, found struct variant `Homura::Madoka`
 
     let homura = issue_19452_aux::Homura::Madoka;
-    //~^ ERROR uses it like a function
-    //~| struct called like a function
+    //~^ ERROR expected value, found struct variant `issue_19452_aux::Homura::Madoka`
 }
diff --git a/src/test/ui/resolve/issue-19452.stderr b/src/test/ui/resolve/issue-19452.stderr
new file mode 100644
index 00000000000..7b14d49af51
--- /dev/null
+++ b/src/test/ui/resolve/issue-19452.stderr
@@ -0,0 +1,14 @@
+error[E0423]: expected value, found struct variant `Homura::Madoka`
+  --> $DIR/issue-19452.rs:19:18
+   |
+19 |     let homura = Homura::Madoka;
+   |                  ^^^^^^^^^^^^^^ did you mean `Homura::Madoka { /* fields */ }`?
+
+error[E0423]: expected value, found struct variant `issue_19452_aux::Homura::Madoka`
+  --> $DIR/issue-19452.rs:22:18
+   |
+22 |     let homura = issue_19452_aux::Homura::Madoka;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ did you mean `issue_19452_aux::Homura::Madoka { /* fields */ }`?
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/compile-fail/issue-21221-1.rs b/src/test/ui/resolve/issue-21221-1.rs
index 2bc9ec3289a..b1266a5af35 100644
--- a/src/test/compile-fail/issue-21221-1.rs
+++ b/src/test/ui/resolve/issue-21221-1.rs
@@ -51,11 +51,11 @@ struct Foo;
 //   help:   `std::ops::Mul`
 
 impl Mul for Foo {
-//~^ ERROR trait `Mul` is not in scope
+//~^ ERROR unresolved trait `Mul`
+//~| HELP possible candidates are found in other modules, you can import them into scope
 //~| HELP `mul1::Mul`
 //~| HELP `mul2::Mul`
 //~| HELP `std::ops::Mul`
-//~| HELP you can import several candidates into scope (`use ...;`):
 }
 
 // BEFORE, we got:
@@ -70,24 +70,23 @@ impl Mul for Foo {
 //   help:   `mul4::Mul`
 //   help:   and 2 other candidates
 fn getMul() -> Mul {
-//~^ ERROR type name `Mul` is undefined or not in scope
+//~^ ERROR unresolved type `Mul`
+//~| HELP possible candidates are found in other modules, you can import them into scope
 //~| HELP `mul1::Mul`
 //~| HELP `mul2::Mul`
 //~| HELP `mul3::Mul`
 //~| HELP `mul4::Mul`
 //~| HELP and 2 other candidates
-//~| HELP you can import several candidates into scope (`use ...;`):
 }
 
 // Let's also test what happens if the trait doesn't exist:
 impl ThisTraitReallyDoesntExistInAnyModuleReally for Foo {
-//~^ ERROR trait `ThisTraitReallyDoesntExistInAnyModuleReally` is not in scope
-//~| HELP no candidates by the name of `ThisTraitReallyDoesntExistInAnyModuleReally` found
+//~^ ERROR unresolved trait `ThisTraitReallyDoesntExistInAnyModuleReally`
 }
 
 // Let's also test what happens if there's just one alternative:
 impl Div for Foo {
-//~^ ERROR trait `Div` is not in scope
+//~^ ERROR unresolved trait `Div`
 //~| HELP `use std::ops::Div;`
 }
 
diff --git a/src/test/ui/resolve/issue-21221-1.stderr b/src/test/ui/resolve/issue-21221-1.stderr
new file mode 100644
index 00000000000..17b70d2182e
--- /dev/null
+++ b/src/test/ui/resolve/issue-21221-1.stderr
@@ -0,0 +1,41 @@
+error[E0405]: unresolved trait `Mul`
+  --> $DIR/issue-21221-1.rs:53:6
+   |
+53 | impl Mul for Foo {
+   |      ^^^ no resolution found
+   |
+   = help: possible candidates are found in other modules, you can import them into scope:
+   = help:   `use mul1::Mul;`
+   = help:   `use mul2::Mul;`
+   = help:   `use std::ops::Mul;`
+
+error[E0412]: unresolved type `Mul`
+  --> $DIR/issue-21221-1.rs:72:16
+   |
+72 | fn getMul() -> Mul {
+   |                ^^^ no resolution found
+   |
+   = help: possible candidates are found in other modules, you can import them into scope:
+   = help:   `use mul1::Mul;`
+   = help:   `use mul2::Mul;`
+   = help:   `use mul3::Mul;`
+   = help:   `use mul4::Mul;`
+   = help:   and 2 other candidates
+
+error[E0405]: unresolved trait `ThisTraitReallyDoesntExistInAnyModuleReally`
+  --> $DIR/issue-21221-1.rs:83:6
+   |
+83 | impl ThisTraitReallyDoesntExistInAnyModuleReally for Foo {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no resolution found
+
+error[E0405]: unresolved trait `Div`
+  --> $DIR/issue-21221-1.rs:88:6
+   |
+88 | impl Div for Foo {
+   |      ^^^ no resolution found
+   |
+   = help: possible candidate is found in another module, you can import it into scope:
+   = help:   `use std::ops::Div;`
+
+error: cannot continue compilation due to previous error
+
diff --git a/src/test/compile-fail/issue-21221-2.rs b/src/test/ui/resolve/issue-21221-2.rs
index 861acf62d0b..15e859329c4 100644
--- a/src/test/compile-fail/issue-21221-2.rs
+++ b/src/test/ui/resolve/issue-21221-2.rs
@@ -26,5 +26,5 @@ pub mod baz {
 
 struct Foo;
 impl T for Foo { }
-//~^ ERROR trait `T` is not in scope
-//~| HELP you can import it into scope: `use foo::bar::T;`.
+//~^ ERROR unresolved trait `T`
+//~| HELP you can import it into scope: `use foo::bar::T;`
diff --git a/src/test/ui/resolve/issue-21221-2.stderr b/src/test/ui/resolve/issue-21221-2.stderr
new file mode 100644
index 00000000000..342fe12f5e5
--- /dev/null
+++ b/src/test/ui/resolve/issue-21221-2.stderr
@@ -0,0 +1,13 @@
+error[E0405]: unresolved trait `T`
+  --> $DIR/issue-21221-2.rs:28:6
+   |
+28 | impl T for Foo { }
+   |      ^ no resolution found
+   |
+   = help: possible candidate is found in another module, you can import it into scope:
+   = help:   `use foo::bar::T;`
+
+error: main function not found
+
+error: cannot continue compilation due to previous error
+
diff --git a/src/test/compile-fail/issue-21221-3.rs b/src/test/ui/resolve/issue-21221-3.rs
index 05786e69cef..5d62cb85914 100644
--- a/src/test/compile-fail/issue-21221-3.rs
+++ b/src/test/ui/resolve/issue-21221-3.rs
@@ -23,8 +23,8 @@ struct Foo;
 //   `issue_21221_3::outer::public_module::OuterTrait`
 // are hidden from the view.
 impl OuterTrait for Foo {}
-//~^ ERROR trait `OuterTrait` is not in scope
-//~| HELP you can import it into scope: `use issue_21221_3::outer::OuterTrait;`.
+//~^ ERROR unresolved trait `OuterTrait`
+//~| HELP you can import it into scope: `use issue_21221_3::outer::OuterTrait;`
 fn main() {
     println!("Hello, world!");
 }
diff --git a/src/test/ui/resolve/issue-21221-3.stderr b/src/test/ui/resolve/issue-21221-3.stderr
new file mode 100644
index 00000000000..25f57f3e3d1
--- /dev/null
+++ b/src/test/ui/resolve/issue-21221-3.stderr
@@ -0,0 +1,11 @@
+error[E0405]: unresolved trait `OuterTrait`
+  --> $DIR/issue-21221-3.rs:25:6
+   |
+25 | impl OuterTrait for Foo {}
+   |      ^^^^^^^^^^ no resolution found
+   |
+   = help: possible candidate is found in another module, you can import it into scope:
+   = help:   `use issue_21221_3::outer::OuterTrait;`
+
+error: cannot continue compilation due to previous error
+
diff --git a/src/test/compile-fail/issue-21221-4.rs b/src/test/ui/resolve/issue-21221-4.rs
index bcbee16cdcf..ff6698f8717 100644
--- a/src/test/compile-fail/issue-21221-4.rs
+++ b/src/test/ui/resolve/issue-21221-4.rs
@@ -18,8 +18,8 @@ extern crate issue_21221_4;
 struct Foo;
 
 impl T for Foo {}
-//~^ ERROR trait `T` is not in scope
-//~| HELP you can import it into scope: `use issue_21221_4::T;`.
+//~^ ERROR unresolved trait `T`
+//~| HELP you can import it into scope: `use issue_21221_4::T;`
 
 fn main() {
     println!("Hello, world!");
diff --git a/src/test/ui/resolve/issue-21221-4.stderr b/src/test/ui/resolve/issue-21221-4.stderr
new file mode 100644
index 00000000000..7ddbeebb8df
--- /dev/null
+++ b/src/test/ui/resolve/issue-21221-4.stderr
@@ -0,0 +1,11 @@
+error[E0405]: unresolved trait `T`
+  --> $DIR/issue-21221-4.rs:20:6
+   |
+20 | impl T for Foo {}
+   |      ^ no resolution found
+   |
+   = help: possible candidate is found in another module, you can import it into scope:
+   = help:   `use issue_21221_4::T;`
+
+error: cannot continue compilation due to previous error
+
diff --git a/src/test/ui/resolve/issue-23305.rs b/src/test/ui/resolve/issue-23305.rs
new file mode 100644
index 00000000000..19069f49167
--- /dev/null
+++ b/src/test/ui/resolve/issue-23305.rs
@@ -0,0 +1,22 @@
+// 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.
+
+pub trait ToNbt<T> {
+    fn new(val: T) -> Self;
+}
+
+impl ToNbt<Self> {}
+//~^ ERROR unresolved type `Self`
+//~| NOTE `Self` is only available in traits and impls
+//~| ERROR the trait `ToNbt` cannot be made into an object
+//~| NOTE the trait `ToNbt` cannot be made into an object
+//~| NOTE method `new` has no receiver
+
+fn main() {}
diff --git a/src/test/ui/resolve/issue-23305.stderr b/src/test/ui/resolve/issue-23305.stderr
new file mode 100644
index 00000000000..cd0d7d3ce16
--- /dev/null
+++ b/src/test/ui/resolve/issue-23305.stderr
@@ -0,0 +1,16 @@
+error[E0411]: unresolved type `Self`
+  --> $DIR/issue-23305.rs:15:12
+   |
+15 | impl ToNbt<Self> {}
+   |            ^^^^ `Self` is only available in traits and impls
+
+error[E0038]: the trait `ToNbt` cannot be made into an object
+  --> $DIR/issue-23305.rs:15:6
+   |
+15 | impl ToNbt<Self> {}
+   |      ^^^^^^^^^^^ the trait `ToNbt` cannot be made into an object
+   |
+   = note: method `new` has no receiver
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/resolve/issue-2356.rs b/src/test/ui/resolve/issue-2356.rs
new file mode 100644
index 00000000000..6deb598b631
--- /dev/null
+++ b/src/test/ui/resolve/issue-2356.rs
@@ -0,0 +1,125 @@
+// 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.
+
+trait Groom {
+    fn shave(other: usize);
+}
+
+pub struct cat {
+  whiskers: isize,
+}
+
+pub enum MaybeDog {
+    Dog,
+    NoDog
+}
+
+impl MaybeDog {
+  fn bark() {
+    // If this provides a suggestion, it's a bug as MaybeDog doesn't impl Groom
+    shave();
+    //~^ ERROR unresolved function `shave`
+    //~| NOTE no resolution found
+  }
+}
+
+impl Clone for cat {
+  fn clone(&self) -> Self {
+    clone();
+    //~^ ERROR unresolved function `clone`
+    //~| NOTE did you mean `self.clone(...)`?
+    loop {}
+  }
+}
+impl Default for cat {
+  fn default() -> Self {
+    default();
+    //~^ ERROR unresolved function `default`
+    //~| NOTE did you mean `Self::default`?
+    loop {}
+  }
+}
+
+impl Groom for cat {
+  fn shave(other: usize) {
+    whiskers -= other;
+    //~^ ERROR unresolved value `whiskers`
+    //~| ERROR unresolved value `whiskers`
+    //~| NOTE did you mean `self.whiskers`?
+    //~| NOTE `self` value is only available in methods with `self` parameter
+    shave(4);
+    //~^ ERROR unresolved function `shave`
+    //~| NOTE did you mean `Self::shave`?
+    purr();
+    //~^ ERROR unresolved function `purr`
+    //~| NOTE no resolution found
+  }
+}
+
+impl cat {
+    fn static_method() {}
+
+    fn purr_louder() {
+        static_method();
+        //~^ ERROR unresolved function `static_method`
+        //~| NOTE no resolution found
+        purr();
+        //~^ ERROR unresolved function `purr`
+        //~| NOTE no resolution found
+        purr();
+        //~^ ERROR unresolved function `purr`
+        //~| NOTE no resolution found
+        purr();
+        //~^ ERROR unresolved function `purr`
+        //~| NOTE no resolution found
+    }
+}
+
+impl cat {
+  fn meow() {
+    if self.whiskers > 3 {
+        //~^ ERROR expected value, found module `self`
+        //~| NOTE `self` value is only available in methods with `self` parameter
+        println!("MEOW");
+    }
+  }
+
+  fn purr(&self) {
+    grow_older();
+    //~^ ERROR unresolved function `grow_older`
+    //~| NOTE no resolution found
+    shave();
+    //~^ ERROR unresolved function `shave`
+    //~| NOTE no resolution found
+  }
+
+  fn burn_whiskers(&mut self) {
+    whiskers = 0;
+    //~^ ERROR unresolved value `whiskers`
+    //~| NOTE did you mean `self.whiskers`?
+  }
+
+  pub fn grow_older(other:usize) {
+    whiskers = 4;
+    //~^ ERROR unresolved value `whiskers`
+    //~| ERROR unresolved value `whiskers`
+    //~| NOTE did you mean `self.whiskers`?
+    //~| NOTE `self` value is only available in methods with `self` parameter
+    purr_louder();
+    //~^ ERROR unresolved function `purr_louder`
+    //~| NOTE no resolution found
+  }
+}
+
+fn main() {
+    self += 1;
+    //~^ ERROR expected value, found module `self`
+    //~| NOTE `self` value is only available in methods with `self` parameter
+}
diff --git a/src/test/ui/resolve/issue-2356.stderr b/src/test/ui/resolve/issue-2356.stderr
new file mode 100644
index 00000000000..32c1a3694d7
--- /dev/null
+++ b/src/test/ui/resolve/issue-2356.stderr
@@ -0,0 +1,110 @@
+error[E0425]: unresolved function `shave`
+  --> $DIR/issue-2356.rs:27:5
+   |
+27 |     shave();
+   |     ^^^^^ no resolution found
+
+error[E0425]: unresolved function `clone`
+  --> $DIR/issue-2356.rs:35:5
+   |
+35 |     clone();
+   |     ^^^^^ did you mean `self.clone(...)`?
+
+error[E0425]: unresolved function `default`
+  --> $DIR/issue-2356.rs:43:5
+   |
+43 |     default();
+   |     ^^^^^^^ did you mean `Self::default`?
+
+error[E0425]: unresolved value `whiskers`
+  --> $DIR/issue-2356.rs:52:5
+   |
+52 |     whiskers -= other;
+   |     ^^^^^^^^
+   |     |
+   |     did you mean `self.whiskers`?
+   |     `self` value is only available in methods with `self` parameter
+
+error[E0425]: unresolved function `shave`
+  --> $DIR/issue-2356.rs:57:5
+   |
+57 |     shave(4);
+   |     ^^^^^ did you mean `Self::shave`?
+
+error[E0425]: unresolved function `purr`
+  --> $DIR/issue-2356.rs:60:5
+   |
+60 |     purr();
+   |     ^^^^ no resolution found
+
+error[E0425]: unresolved function `static_method`
+  --> $DIR/issue-2356.rs:70:9
+   |
+70 |         static_method();
+   |         ^^^^^^^^^^^^^ no resolution found
+
+error[E0425]: unresolved function `purr`
+  --> $DIR/issue-2356.rs:73:9
+   |
+73 |         purr();
+   |         ^^^^ no resolution found
+
+error[E0425]: unresolved function `purr`
+  --> $DIR/issue-2356.rs:76:9
+   |
+76 |         purr();
+   |         ^^^^ no resolution found
+
+error[E0425]: unresolved function `purr`
+  --> $DIR/issue-2356.rs:79:9
+   |
+79 |         purr();
+   |         ^^^^ no resolution found
+
+error[E0424]: expected value, found module `self`
+  --> $DIR/issue-2356.rs:87:8
+   |
+87 |     if self.whiskers > 3 {
+   |        ^^^^ `self` value is only available in methods with `self` parameter
+
+error[E0425]: unresolved function `grow_older`
+  --> $DIR/issue-2356.rs:95:5
+   |
+95 |     grow_older();
+   |     ^^^^^^^^^^ no resolution found
+
+error[E0425]: unresolved function `shave`
+  --> $DIR/issue-2356.rs:98:5
+   |
+98 |     shave();
+   |     ^^^^^ no resolution found
+
+error[E0425]: unresolved value `whiskers`
+   --> $DIR/issue-2356.rs:104:5
+    |
+104 |     whiskers = 0;
+    |     ^^^^^^^^ did you mean `self.whiskers`?
+
+error[E0425]: unresolved value `whiskers`
+   --> $DIR/issue-2356.rs:110:5
+    |
+110 |     whiskers = 4;
+    |     ^^^^^^^^
+    |     |
+    |     did you mean `self.whiskers`?
+    |     `self` value is only available in methods with `self` parameter
+
+error[E0425]: unresolved function `purr_louder`
+   --> $DIR/issue-2356.rs:115:5
+    |
+115 |     purr_louder();
+    |     ^^^^^^^^^^^ no resolution found
+
+error[E0424]: expected value, found module `self`
+   --> $DIR/issue-2356.rs:122:5
+    |
+122 |     self += 1;
+    |     ^^^^ `self` value is only available in methods with `self` parameter
+
+error: aborting due to 17 previous errors
+
diff --git a/src/test/compile-fail/issue-24968.rs b/src/test/ui/resolve/issue-24968.rs
index f51b77b0ee5..0d562cab6b8 100644
--- a/src/test/compile-fail/issue-24968.rs
+++ b/src/test/ui/resolve/issue-24968.rs
@@ -9,7 +9,8 @@
 // except according to those terms.
 
 fn foo(_: Self) {
-    //~^ ERROR use of `Self` outside of an impl or trait
+//~^ ERROR unresolved type `Self`
+//~| NOTE `Self` is only available in traits and impls
 }
 
 fn main() {}
diff --git a/src/test/ui/resolve/issue-24968.stderr b/src/test/ui/resolve/issue-24968.stderr
new file mode 100644
index 00000000000..3050bc4eb62
--- /dev/null
+++ b/src/test/ui/resolve/issue-24968.stderr
@@ -0,0 +1,8 @@
+error[E0411]: unresolved type `Self`
+  --> $DIR/issue-24968.rs:11:11
+   |
+11 | fn foo(_: Self) {
+   |           ^^^^ `Self` is only available in traits and impls
+
+error: aborting due to previous error
+
diff --git a/src/test/compile-fail/issue-33876.rs b/src/test/ui/resolve/issue-33876.rs
index 87747d2851f..a97cc5e4101 100644
--- a/src/test/compile-fail/issue-33876.rs
+++ b/src/test/ui/resolve/issue-33876.rs
@@ -17,7 +17,6 @@ trait Bar {}
 impl Bar for Foo {}
 
 fn main() {
-    let any: &Any = &Bar; //~ ERROR E0425
-                          //~| HELP trait `Bar`
+    let any: &Any = &Bar; //~ ERROR expected value, found trait `Bar`
     if any.is::<u32>() { println!("u32"); }
 }
diff --git a/src/test/ui/resolve/issue-33876.stderr b/src/test/ui/resolve/issue-33876.stderr
new file mode 100644
index 00000000000..5dbecc4f0c5
--- /dev/null
+++ b/src/test/ui/resolve/issue-33876.stderr
@@ -0,0 +1,8 @@
+error[E0423]: expected value, found trait `Bar`
+  --> $DIR/issue-33876.rs:20:22
+   |
+20 |     let any: &Any = &Bar; //~ ERROR expected value, found trait `Bar`
+   |                      ^^^ not a value
+
+error: aborting due to previous error
+
diff --git a/src/test/compile-fail/issue-3907-2.rs b/src/test/ui/resolve/issue-3907-2.rs
index 130647966f2..130647966f2 100644
--- a/src/test/compile-fail/issue-3907-2.rs
+++ b/src/test/ui/resolve/issue-3907-2.rs
diff --git a/src/test/ui/resolve/issue-3907-2.stderr b/src/test/ui/resolve/issue-3907-2.stderr
new file mode 100644
index 00000000000..ef02250e21c
--- /dev/null
+++ b/src/test/ui/resolve/issue-3907-2.stderr
@@ -0,0 +1,10 @@
+error[E0038]: the trait `issue_3907::Foo` cannot be made into an object
+  --> $DIR/issue-3907-2.rs:20:1
+   |
+20 | fn bar(_x: Foo) {}
+   | ^^^^^^^^^^^^^^^^^^ the trait `issue_3907::Foo` cannot be made into an object
+   |
+   = note: method `bar` has no receiver
+
+error: aborting due to previous error
+
diff --git a/src/test/compile-fail/issue-3907.rs b/src/test/ui/resolve/issue-3907.rs
index 86906ed9af2..0e54e68df0d 100644
--- a/src/test/compile-fail/issue-3907.rs
+++ b/src/test/ui/resolve/issue-3907.rs
@@ -17,9 +17,7 @@ struct S {
     name: isize
 }
 
-impl Foo for S { //~ ERROR: `Foo` is not a trait
-                 //~| NOTE: expected trait, found type alias
-                 //~| NOTE: type aliases cannot be used for traits
+impl Foo for S { //~ ERROR expected trait, found type alias `Foo`
     fn bar() { }
 }
 
diff --git a/src/test/ui/resolve/issue-3907.stderr b/src/test/ui/resolve/issue-3907.stderr
new file mode 100644
index 00000000000..0a402680aa8
--- /dev/null
+++ b/src/test/ui/resolve/issue-3907.stderr
@@ -0,0 +1,11 @@
+error[E0404]: expected trait, found type alias `Foo`
+  --> $DIR/issue-3907.rs:20:6
+   |
+20 | impl Foo for S { //~ ERROR expected trait, found type alias `Foo`
+   |      ^^^ type aliases cannot be used for traits
+   |
+   = help: possible better candidate is found in another module, you can import it into scope:
+   = help:   `use issue_3907::Foo;`
+
+error: cannot continue compilation due to previous error
+
diff --git a/src/test/compile-fail/issue-5035-2.rs b/src/test/ui/resolve/issue-5035-2.rs
index 83ff95cc2ea..83ff95cc2ea 100644
--- a/src/test/compile-fail/issue-5035-2.rs
+++ b/src/test/ui/resolve/issue-5035-2.rs
diff --git a/src/test/ui/resolve/issue-5035-2.stderr b/src/test/ui/resolve/issue-5035-2.stderr
new file mode 100644
index 00000000000..72b1578e0d0
--- /dev/null
+++ b/src/test/ui/resolve/issue-5035-2.stderr
@@ -0,0 +1,11 @@
+error[E0277]: the trait bound `I + 'static: std::marker::Sized` is not satisfied
+  --> $DIR/issue-5035-2.rs:14:8
+   |
+14 | fn foo(_x: K) {} //~ ERROR: `I + 'static: std::marker::Sized` is not satisfied
+   |        ^^ the trait `std::marker::Sized` is not implemented for `I + 'static`
+   |
+   = note: `I + 'static` does not have a constant size known at compile-time
+   = note: all local variables must have a statically known size
+
+error: aborting due to previous error
+
diff --git a/src/test/compile-fail/issue-5035.rs b/src/test/ui/resolve/issue-5035.rs
index 8ebcba47134..6263e6f6db4 100644
--- a/src/test/compile-fail/issue-5035.rs
+++ b/src/test/ui/resolve/issue-5035.rs
@@ -10,9 +10,8 @@
 
 trait I {}
 type K = I;
-impl K for isize {} //~ ERROR: `K` is not a trait
-                    //~| NOTE: expected trait, found type alias
-                    //~| NOTE: aliases cannot be used for traits
+impl K for isize {} //~ ERROR expected trait, found type alias `K`
+                    //~| NOTE type aliases cannot be used for traits
 
 use ImportError; //~ ERROR unresolved import `ImportError` [E0432]
                  //~^ no `ImportError` in the root
diff --git a/src/test/ui/resolve/issue-5035.stderr b/src/test/ui/resolve/issue-5035.stderr
new file mode 100644
index 00000000000..6cb9a289379
--- /dev/null
+++ b/src/test/ui/resolve/issue-5035.stderr
@@ -0,0 +1,14 @@
+error[E0432]: unresolved import `ImportError`
+  --> $DIR/issue-5035.rs:16:5
+   |
+16 | use ImportError; //~ ERROR unresolved import `ImportError` [E0432]
+   |     ^^^^^^^^^^^ no `ImportError` in the root
+
+error[E0404]: expected trait, found type alias `K`
+  --> $DIR/issue-5035.rs:13:6
+   |
+13 | impl K for isize {} //~ ERROR expected trait, found type alias `K`
+   |      ^ type aliases cannot be used for traits
+
+error: cannot continue compilation due to previous error
+
diff --git a/src/test/compile-fail/issue-6702.rs b/src/test/ui/resolve/issue-6702.rs
index 66ed817ffa8..b391ddf3469 100644
--- a/src/test/compile-fail/issue-6702.rs
+++ b/src/test/ui/resolve/issue-6702.rs
@@ -14,6 +14,6 @@ struct Monster {
 
 
 fn main() {
-    let _m = Monster(); //~ ERROR `Monster` is the name of a struct or
-    //~^ HELP did you mean to write: `Monster { /* fields */ }`?
+    let _m = Monster(); //~ ERROR expected function, found struct `Monster`
+                        //~^ NOTE did you mean `Monster { /* fields */ }`?
 }
diff --git a/src/test/ui/resolve/issue-6702.stderr b/src/test/ui/resolve/issue-6702.stderr
new file mode 100644
index 00000000000..b50295752f2
--- /dev/null
+++ b/src/test/ui/resolve/issue-6702.stderr
@@ -0,0 +1,8 @@
+error[E0423]: expected function, found struct `Monster`
+  --> $DIR/issue-6702.rs:17:14
+   |
+17 |     let _m = Monster(); //~ ERROR expected function, found struct `Monster`
+   |              ^^^^^^^ did you mean `Monster { /* fields */ }`?
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/resolve/resolve-assoc-suggestions.rs b/src/test/ui/resolve/resolve-assoc-suggestions.rs
new file mode 100644
index 00000000000..53e26ddafec
--- /dev/null
+++ b/src/test/ui/resolve/resolve-assoc-suggestions.rs
@@ -0,0 +1,58 @@
+// 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.
+
+// Make sure associated items are recommended only in appropriate contexts.
+
+struct S {
+    field: u8,
+}
+
+trait Tr {
+    fn method(&self);
+    type Type;
+}
+
+impl Tr for S {
+    type Type = u8;
+
+    fn method(&self) {
+        let _: field;
+        //~^ ERROR unresolved type `field`
+        //~| NOTE no resolution found
+        let field(..);
+        //~^ ERROR unresolved tuple struct/variant `field`
+        //~| NOTE no resolution found
+        field;
+        //~^ ERROR unresolved value `field`
+        //~| NOTE did you mean `self.field`?
+
+        let _: Type;
+        //~^ ERROR unresolved type `Type`
+        //~| NOTE did you mean `Self::Type`?
+        let Type(..);
+        //~^ ERROR unresolved tuple struct/variant `Type`
+        //~| NOTE no resolution found
+        Type;
+        //~^ ERROR unresolved value `Type`
+        //~| NOTE no resolution found
+
+        let _: method;
+        //~^ ERROR unresolved type `method`
+        //~| NOTE no resolution found
+        let method(..);
+        //~^ ERROR unresolved tuple struct/variant `method`
+        //~| NOTE no resolution found
+        method;
+        //~^ ERROR unresolved value `method`
+        //~| NOTE did you mean `self.method(...)`?
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/resolve-assoc-suggestions.stderr b/src/test/ui/resolve/resolve-assoc-suggestions.stderr
new file mode 100644
index 00000000000..98ead713947
--- /dev/null
+++ b/src/test/ui/resolve/resolve-assoc-suggestions.stderr
@@ -0,0 +1,56 @@
+error[E0412]: unresolved type `field`
+  --> $DIR/resolve-assoc-suggestions.rs:26:16
+   |
+26 |         let _: field;
+   |                ^^^^^ no resolution found
+
+error[E0531]: unresolved tuple struct/variant `field`
+  --> $DIR/resolve-assoc-suggestions.rs:29:13
+   |
+29 |         let field(..);
+   |             ^^^^^ no resolution found
+
+error[E0425]: unresolved value `field`
+  --> $DIR/resolve-assoc-suggestions.rs:32:9
+   |
+32 |         field;
+   |         ^^^^^ did you mean `self.field`?
+
+error[E0412]: unresolved type `Type`
+  --> $DIR/resolve-assoc-suggestions.rs:36:16
+   |
+36 |         let _: Type;
+   |                ^^^^ did you mean `Self::Type`?
+
+error[E0531]: unresolved tuple struct/variant `Type`
+  --> $DIR/resolve-assoc-suggestions.rs:39:13
+   |
+39 |         let Type(..);
+   |             ^^^^ no resolution found
+
+error[E0425]: unresolved value `Type`
+  --> $DIR/resolve-assoc-suggestions.rs:42:9
+   |
+42 |         Type;
+   |         ^^^^ no resolution found
+
+error[E0412]: unresolved type `method`
+  --> $DIR/resolve-assoc-suggestions.rs:46:16
+   |
+46 |         let _: method;
+   |                ^^^^^^ no resolution found
+
+error[E0531]: unresolved tuple struct/variant `method`
+  --> $DIR/resolve-assoc-suggestions.rs:49:13
+   |
+49 |         let method(..);
+   |             ^^^^^^ no resolution found
+
+error[E0425]: unresolved value `method`
+  --> $DIR/resolve-assoc-suggestions.rs:52:9
+   |
+52 |         method;
+   |         ^^^^^^ did you mean `self.method(...)`?
+
+error: aborting due to 9 previous errors
+
diff --git a/src/test/compile-fail/resolve-hint-macro.rs b/src/test/ui/resolve/resolve-hint-macro.rs
index edaab012757..72fd9a79376 100644
--- a/src/test/compile-fail/resolve-hint-macro.rs
+++ b/src/test/ui/resolve/resolve-hint-macro.rs
@@ -10,6 +10,6 @@
 
 fn main() {
     assert(true);
-    //~^ ERROR unresolved name `assert`
-    //~| NOTE did you mean the macro `assert!`?
+    //~^ ERROR expected function, found macro `assert`
+    //~| NOTE did you mean `assert!(...)`?
 }
diff --git a/src/test/ui/resolve/resolve-hint-macro.stderr b/src/test/ui/resolve/resolve-hint-macro.stderr
new file mode 100644
index 00000000000..ffb3f848430
--- /dev/null
+++ b/src/test/ui/resolve/resolve-hint-macro.stderr
@@ -0,0 +1,8 @@
+error[E0423]: expected function, found macro `assert`
+  --> $DIR/resolve-hint-macro.rs:12:5
+   |
+12 |     assert(true);
+   |     ^^^^^^ did you mean `assert!(...)`?
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/resolve/resolve-speculative-adjustment.rs b/src/test/ui/resolve/resolve-speculative-adjustment.rs
new file mode 100644
index 00000000000..95289e23f9e
--- /dev/null
+++ b/src/test/ui/resolve/resolve-speculative-adjustment.rs
@@ -0,0 +1,44 @@
+// 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.
+
+// Make sure speculative path resolution works properly when resolution
+// adjustment happens and no extra errors is reported.
+
+struct S {
+    field: u8,
+}
+
+trait Tr {
+    fn method(&self);
+}
+
+impl Tr for S {
+    fn method(&self) {
+        fn g() {
+            // Speculative resolution of `Self` and `self` silently fails,
+            // "did you mean" messages are not printed.
+            field;
+            //~^ ERROR unresolved value `field`
+            //~| NOTE no resolution found
+            method();
+            //~^ ERROR unresolved function `method`
+            //~| NOTE no resolution found
+        }
+
+        field;
+        //~^ ERROR unresolved value `field`
+        //~| NOTE did you mean `self.field`?
+        method();
+        //~^ ERROR unresolved function `method`
+        //~| NOTE did you mean `self.method(...)`?
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/resolve-speculative-adjustment.stderr b/src/test/ui/resolve/resolve-speculative-adjustment.stderr
new file mode 100644
index 00000000000..173b6905541
--- /dev/null
+++ b/src/test/ui/resolve/resolve-speculative-adjustment.stderr
@@ -0,0 +1,26 @@
+error[E0425]: unresolved value `field`
+  --> $DIR/resolve-speculative-adjustment.rs:27:13
+   |
+27 |             field;
+   |             ^^^^^ no resolution found
+
+error[E0425]: unresolved function `method`
+  --> $DIR/resolve-speculative-adjustment.rs:30:13
+   |
+30 |             method();
+   |             ^^^^^^ no resolution found
+
+error[E0425]: unresolved value `field`
+  --> $DIR/resolve-speculative-adjustment.rs:35:9
+   |
+35 |         field;
+   |         ^^^^^ did you mean `self.field`?
+
+error[E0425]: unresolved function `method`
+  --> $DIR/resolve-speculative-adjustment.rs:38:9
+   |
+38 |         method();
+   |         ^^^^^^ did you mean `self.method(...)`?
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/compile-fail/suggest-path-instead-of-mod-dot-item.rs b/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.rs
index 4a816ea7572..789bdfb414d 100644
--- a/src/test/compile-fail/suggest-path-instead-of-mod-dot-item.rs
+++ b/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.rs
@@ -25,52 +25,52 @@ pub mod a {
 
 fn h1() -> i32 {
     a.I
-        //~^ ERROR E0425
-        //~| HELP to reference an item from the `a` module, use `a::I`
+    //~^ ERROR expected value, found module `a`
+    //~| NOTE did you mean `a::I`?
 }
 
 fn h2() -> i32 {
     a.g()
-        //~^ ERROR E0425
-        //~| HELP to call a function from the `a` module, use `a::g(..)`
+    //~^ ERROR expected value, found module `a`
+    //~| NOTE did you mean `a::g(...)`?
 }
 
 fn h3() -> i32 {
     a.b.J
-        //~^ ERROR E0425
-        //~| HELP to reference an item from the `a` module, use `a::b`
+    //~^ ERROR expected value, found module `a`
+    //~| NOTE did you mean `a::b`?
 }
 
 fn h4() -> i32 {
     a::b.J
-        //~^ ERROR E0425
-        //~| HELP to reference an item from the `a::b` module, use `a::b::J`
+    //~^ ERROR expected value, found module `a::b`
+    //~| NOTE did you mean `a::b::J`?
 }
 
 fn h5() {
     a.b.f();
-        //~^ ERROR E0425
-        //~| HELP to reference an item from the `a` module, use `a::b`
+    //~^ ERROR expected value, found module `a`
+    //~| NOTE did you mean `a::b`?
     let v = Vec::new();
     v.push(a::b);
-        //~^ ERROR E0425
-        //~| HELP module `a::b` cannot be used as an expression
+    //~^ ERROR expected value, found module `a::b`
+    //~| NOTE not a value
 }
 
 fn h6() -> i32 {
     a::b.f()
-        //~^ ERROR E0425
-        //~| HELP to call a function from the `a::b` module, use `a::b::f(..)`
+    //~^ ERROR expected value, found module `a::b`
+    //~| NOTE did you mean `a::b::f(...)`?
 }
 
 fn h7() {
     a::b
-        //~^ ERROR E0425
-        //~| HELP module `a::b` cannot be used as an expression
+    //~^ ERROR expected value, found module `a::b`
+    //~| NOTE not a value
 }
 
 fn h8() -> i32 {
     a::b()
-        //~^ ERROR E0425
-        //~| HELP module `a::b` cannot be used as an expression
+    //~^ ERROR expected function, found module `a::b`
+    //~| NOTE not a function
 }
diff --git a/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr b/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr
new file mode 100644
index 00000000000..8ace738ad6d
--- /dev/null
+++ b/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr
@@ -0,0 +1,58 @@
+error[E0423]: expected value, found module `a`
+  --> $DIR/suggest-path-instead-of-mod-dot-item.rs:27:5
+   |
+27 |     a.I
+   |     ^ did you mean `a::I`?
+
+error[E0423]: expected value, found module `a`
+  --> $DIR/suggest-path-instead-of-mod-dot-item.rs:33:5
+   |
+33 |     a.g()
+   |     ^ did you mean `a::g(...)`?
+
+error[E0423]: expected value, found module `a`
+  --> $DIR/suggest-path-instead-of-mod-dot-item.rs:39:5
+   |
+39 |     a.b.J
+   |     ^ did you mean `a::b`?
+
+error[E0423]: expected value, found module `a::b`
+  --> $DIR/suggest-path-instead-of-mod-dot-item.rs:45:5
+   |
+45 |     a::b.J
+   |     ^^^^ did you mean `a::b::J`?
+
+error[E0423]: expected value, found module `a`
+  --> $DIR/suggest-path-instead-of-mod-dot-item.rs:51:5
+   |
+51 |     a.b.f();
+   |     ^ did you mean `a::b`?
+
+error[E0423]: expected value, found module `a::b`
+  --> $DIR/suggest-path-instead-of-mod-dot-item.rs:55:12
+   |
+55 |     v.push(a::b);
+   |            ^^^^ not a value
+
+error[E0423]: expected value, found module `a::b`
+  --> $DIR/suggest-path-instead-of-mod-dot-item.rs:61:5
+   |
+61 |     a::b.f()
+   |     ^^^^ did you mean `a::b::f(...)`?
+
+error[E0423]: expected value, found module `a::b`
+  --> $DIR/suggest-path-instead-of-mod-dot-item.rs:67:5
+   |
+67 |     a::b
+   |     ^^^^ not a value
+
+error[E0423]: expected function, found module `a::b`
+  --> $DIR/suggest-path-instead-of-mod-dot-item.rs:73:5
+   |
+73 |     a::b()
+   |     ^^^^ not a function
+
+error: main function not found
+
+error: aborting due to 10 previous errors
+
diff --git a/src/test/compile-fail/token-error-correct-2.rs b/src/test/ui/resolve/token-error-correct-2.rs
index 151c1d432ed..6fa1260d180 100644
--- a/src/test/compile-fail/token-error-correct-2.rs
+++ b/src/test/ui/resolve/token-error-correct-2.rs
@@ -11,8 +11,9 @@
 // Test that we do some basic error correcton in the tokeniser (and don't ICE).
 
 fn main() {
-    if foo { //~ NOTE: unclosed delimiter
-    //~^ ERROR: unresolved name `foo`
-    //~| NOTE unresolved name
+    if foo {
+    //~^ NOTE: unclosed delimiter
+    //~| ERROR: unresolved value `foo`
+    //~| NOTE: no resolution found
     ) //~ ERROR: incorrect close delimiter: `)`
 }
diff --git a/src/test/ui/resolve/token-error-correct-2.stderr b/src/test/ui/resolve/token-error-correct-2.stderr
new file mode 100644
index 00000000000..7c422398e21
--- /dev/null
+++ b/src/test/ui/resolve/token-error-correct-2.stderr
@@ -0,0 +1,20 @@
+error: incorrect close delimiter: `)`
+  --> $DIR/token-error-correct-2.rs:18:5
+   |
+18 |     ) //~ ERROR: incorrect close delimiter: `)`
+   |     ^
+   |
+note: unclosed delimiter
+  --> $DIR/token-error-correct-2.rs:14:12
+   |
+14 |     if foo {
+   |            ^
+
+error[E0425]: unresolved value `foo`
+  --> $DIR/token-error-correct-2.rs:14:8
+   |
+14 |     if foo {
+   |        ^^^ no resolution found
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/compile-fail/token-error-correct-3.rs b/src/test/ui/resolve/token-error-correct-3.rs
index 5f21bf18d7b..f72b7adf593 100644
--- a/src/test/compile-fail/token-error-correct-3.rs
+++ b/src/test/ui/resolve/token-error-correct-3.rs
@@ -18,8 +18,8 @@ pub mod raw {
     pub fn ensure_dir_exists<P: AsRef<Path>, F: FnOnce(&Path)>(path: P,
                                                                callback: F)
                                                                -> io::Result<bool> {
-        if !is_directory(path.as_ref()) { //~ ERROR: unresolved name `is_directory`
-                                          //~| NOTE unresolved name
+        if !is_directory(path.as_ref()) { //~ ERROR: unresolved function `is_directory`
+                                          //~^ NOTE: no resolution found
             callback(path.as_ref();  //~ NOTE: unclosed delimiter
                      //~^ ERROR: expected one of
             fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types
diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr
new file mode 100644
index 00000000000..0b15c23909c
--- /dev/null
+++ b/src/test/ui/resolve/token-error-correct-3.stderr
@@ -0,0 +1,45 @@
+error: incorrect close delimiter: `}`
+  --> $DIR/token-error-correct-3.rs:29:9
+   |
+29 |         } else { //~ ERROR: incorrect close delimiter: `}`
+   |         ^
+   |
+note: unclosed delimiter
+  --> $DIR/token-error-correct-3.rs:23:21
+   |
+23 |             callback(path.as_ref();  //~ NOTE: unclosed delimiter
+   |                     ^
+
+error: expected one of `,`, `.`, `?`, or an operator, found `;`
+  --> $DIR/token-error-correct-3.rs:23:35
+   |
+23 |             callback(path.as_ref();  //~ NOTE: unclosed delimiter
+   |                                   ^
+
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)`
+  --> $DIR/token-error-correct-3.rs:29:9
+   |
+29 |         } else { //~ ERROR: incorrect close delimiter: `}`
+   |         ^
+
+error[E0425]: unresolved function `is_directory`
+  --> $DIR/token-error-correct-3.rs:21:13
+   |
+21 |         if !is_directory(path.as_ref()) { //~ ERROR: unresolved function `is_directory`
+   |             ^^^^^^^^^^^^ no resolution found
+
+error[E0308]: mismatched types
+  --> $DIR/token-error-correct-3.rs:25:13
+   |
+25 |             fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `std::result::Result`
+   |
+   = note: expected type `()`
+   = note:    found type `std::result::Result<bool, std::io::Error>`
+   = help: here are some functions which might fulfill your needs:
+ - .unwrap()
+ - .unwrap_err()
+ - .unwrap_or_default()
+
+error: aborting due to previous error
+
diff --git a/src/test/compile-fail/token-error-correct.rs b/src/test/ui/resolve/token-error-correct.rs
index 3ba9edda07f..5fd35e51336 100644
--- a/src/test/compile-fail/token-error-correct.rs
+++ b/src/test/ui/resolve/token-error-correct.rs
@@ -11,14 +11,16 @@
 // Test that we do some basic error correcton in the tokeniser.
 
 fn main() {
-    foo(bar(; //~ NOTE: unclosed delimiter
+    foo(bar(;
     //~^ NOTE: unclosed delimiter
-    //~^^ ERROR: expected expression, found `;`
-    //~^^^ ERROR: unresolved name `bar`
-    //~^^^^ ERROR: unresolved name `foo`
-    //~^^^^^ ERROR: expected one of `)`, `,`, `.`, `<`, `?`
-    //~| NOTE unresolved name
-    //~| NOTE unresolved name
-} //~ ERROR: incorrect close delimiter: `}`
+    //~| NOTE: unclosed delimiter
+    //~| ERROR: expected expression, found `;`
+    //~| ERROR: unresolved function `foo`
+    //~| NOTE: no resolution found
+    //~| ERROR: unresolved function `bar`
+    //~| NOTE: no resolution found
+    //~| ERROR: expected one of `)`, `,`, `.`, `<`, `?`
+}
 //~^ ERROR: incorrect close delimiter: `}`
-//~^^ ERROR: expected expression, found `)`
+//~| ERROR: incorrect close delimiter: `}`
+//~| ERROR: expected expression, found `)`
diff --git a/src/test/ui/resolve/token-error-correct.stderr b/src/test/ui/resolve/token-error-correct.stderr
new file mode 100644
index 00000000000..38cd95a4867
--- /dev/null
+++ b/src/test/ui/resolve/token-error-correct.stderr
@@ -0,0 +1,56 @@
+error: incorrect close delimiter: `}`
+  --> $DIR/token-error-correct.rs:23:1
+   |
+23 | }
+   | ^
+   |
+note: unclosed delimiter
+  --> $DIR/token-error-correct.rs:14:12
+   |
+14 |     foo(bar(;
+   |            ^
+
+error: incorrect close delimiter: `}`
+  --> $DIR/token-error-correct.rs:23:1
+   |
+23 | }
+   | ^
+   |
+note: unclosed delimiter
+  --> $DIR/token-error-correct.rs:14:8
+   |
+14 |     foo(bar(;
+   |        ^
+
+error: expected expression, found `;`
+  --> $DIR/token-error-correct.rs:14:13
+   |
+14 |     foo(bar(;
+   |             ^
+
+error: expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `for`, `if`, `loop`, `match`, `move`, `return`, `true`, `unsafe`, `while`, or an operator, found `;`
+  --> $DIR/token-error-correct.rs:14:13
+   |
+14 |     foo(bar(;
+   |             ^
+
+error: expected expression, found `)`
+  --> $DIR/token-error-correct.rs:23:1
+   |
+23 | }
+   | ^
+
+error[E0425]: unresolved function `foo`
+  --> $DIR/token-error-correct.rs:14:5
+   |
+14 |     foo(bar(;
+   |     ^^^ no resolution found
+
+error[E0425]: unresolved function `bar`
+  --> $DIR/token-error-correct.rs:14:9
+   |
+14 |     foo(bar(;
+   |         ^^^ no resolution found
+
+error: aborting due to 7 previous errors
+
diff --git a/src/test/ui/resolve/tuple-struct-alias.rs b/src/test/ui/resolve/tuple-struct-alias.rs
new file mode 100644
index 00000000000..c9c05202fea
--- /dev/null
+++ b/src/test/ui/resolve/tuple-struct-alias.rs
@@ -0,0 +1,28 @@
+// 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.
+
+struct S(u8, u16);
+type A = S;
+
+impl S {
+    fn f() {
+        let s = Self(0, 1);
+        match s {
+            Self(..) => {}
+        }
+    }
+}
+
+fn main() {
+    let s = A(0, 1);
+    match s {
+        A(..) => {}
+    }
+}
diff --git a/src/test/ui/resolve/tuple-struct-alias.stderr b/src/test/ui/resolve/tuple-struct-alias.stderr
new file mode 100644
index 00000000000..485c8ebbaeb
--- /dev/null
+++ b/src/test/ui/resolve/tuple-struct-alias.stderr
@@ -0,0 +1,26 @@
+error[E0423]: expected function, found self type `Self`
+  --> $DIR/tuple-struct-alias.rs:16:17
+   |
+16 |         let s = Self(0, 1);
+   |                 ^^^^ did you mean `Self { /* fields */ }`?
+
+error[E0532]: expected tuple struct/variant, found self type `Self`
+  --> $DIR/tuple-struct-alias.rs:18:13
+   |
+18 |             Self(..) => {}
+   |             ^^^^ did you mean `Self { /* fields */ }`?
+
+error[E0423]: expected function, found type alias `A`
+  --> $DIR/tuple-struct-alias.rs:24:13
+   |
+24 |     let s = A(0, 1);
+   |             ^ did you mean `A { /* fields */ }`?
+
+error[E0532]: expected tuple struct/variant, found type alias `A`
+  --> $DIR/tuple-struct-alias.rs:26:9
+   |
+26 |         A(..) => {}
+   |         ^ did you mean `A { /* fields */ }`?
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.rs b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.rs
new file mode 100644
index 00000000000..57f6ddd2d3c
--- /dev/null
+++ b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.rs
@@ -0,0 +1,21 @@
+// 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.
+
+fn f<F:Nonexist(isize) -> isize>(x: F) {}
+//~^ ERROR unresolved trait `Nonexist`
+//~| NOTE no resolution found
+
+type Typedef = isize;
+
+fn g<F:Typedef(isize) -> isize>(x: F) {}
+//~^ ERROR expected trait, found type alias `Typedef`
+//~| NOTE type aliases cannot be used for traits
+
+fn main() {}
diff --git a/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr
new file mode 100644
index 00000000000..ba90321ca2b
--- /dev/null
+++ b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr
@@ -0,0 +1,14 @@
+error[E0405]: unresolved trait `Nonexist`
+  --> $DIR/unboxed-closure-sugar-nonexistent-trait.rs:11:8
+   |
+11 | fn f<F:Nonexist(isize) -> isize>(x: F) {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^ no resolution found
+
+error[E0404]: expected trait, found type alias `Typedef`
+  --> $DIR/unboxed-closure-sugar-nonexistent-trait.rs:17:8
+   |
+17 | fn g<F:Typedef(isize) -> isize>(x: F) {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^ type aliases cannot be used for traits
+
+error: cannot continue compilation due to previous error
+
diff --git a/src/test/ui/resolve/unresolved_static_type_field.rs b/src/test/ui/resolve/unresolved_static_type_field.rs
new file mode 100644
index 00000000000..19beabd8823
--- /dev/null
+++ b/src/test/ui/resolve/unresolved_static_type_field.rs
@@ -0,0 +1,27 @@
+// 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.
+
+fn f(_: bool) {}
+
+struct Foo {
+    cx: bool,
+}
+
+impl Foo {
+    fn bar() {
+        f(cx);
+        //~^ ERROR unresolved value `cx`
+        //~| ERROR unresolved value `cx`
+        //~| NOTE did you mean `self.cx`?
+        //~| NOTE `self` value is only available in methods with `self` parameter
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/unresolved_static_type_field.stderr b/src/test/ui/resolve/unresolved_static_type_field.stderr
new file mode 100644
index 00000000000..1d0ee191175
--- /dev/null
+++ b/src/test/ui/resolve/unresolved_static_type_field.stderr
@@ -0,0 +1,11 @@
+error[E0425]: unresolved value `cx`
+  --> $DIR/unresolved_static_type_field.rs:19:11
+   |
+19 |         f(cx);
+   |           ^^
+   |           |
+   |           did you mean `self.cx`?
+   |           `self` value is only available in methods with `self` parameter
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/span/coerce-suggestions.rs b/src/test/ui/span/coerce-suggestions.rs
new file mode 100644
index 00000000000..3177e858ff4
--- /dev/null
+++ b/src/test/ui/span/coerce-suggestions.rs
@@ -0,0 +1,47 @@
+// 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)]
+
+fn test(_x: &mut String) {}
+fn test2(_x: &mut i32) {}
+
+fn main() {
+    let x: usize = String::new();
+    //~^ ERROR E0308
+    //~| NOTE expected usize, found struct `std::string::String`
+    //~| NOTE expected type `usize`
+    //~| NOTE found type `std::string::String`
+    //~| HELP here are some functions which might fulfill your needs:
+    let x: &str = String::new();
+    //~^ ERROR E0308
+    //~| NOTE expected &str, found struct `std::string::String`
+    //~| NOTE expected type `&str`
+    //~| NOTE found type `std::string::String`
+    //~| HELP try with `&String::new()`
+    let y = String::new();
+    test(&y);
+    //~^ ERROR E0308
+    //~| NOTE types differ in mutability
+    //~| NOTE expected type `&mut std::string::String`
+    //~| NOTE found type `&std::string::String`
+    //~| HELP try with `&mut y`
+    test2(&y);
+    //~^ ERROR E0308
+    //~| NOTE types differ in mutability
+    //~| NOTE expected type `&mut i32`
+    //~| NOTE found type `&std::string::String`
+    let f;
+    f = box f;
+    //~^ ERROR E0308
+    //~| NOTE cyclic type of infinite size
+    //~| NOTE expected type `_`
+    //~| NOTE found type `Box<_>`
+}
diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr
new file mode 100644
index 00000000000..e3164661507
--- /dev/null
+++ b/src/test/ui/span/coerce-suggestions.stderr
@@ -0,0 +1,55 @@
+error[E0308]: mismatched types
+  --> $DIR/coerce-suggestions.rs:17:20
+   |
+17 |     let x: usize = String::new();
+   |                    ^^^^^^^^^^^^^ expected usize, found struct `std::string::String`
+   |
+   = note: expected type `usize`
+   = note:    found type `std::string::String`
+   = help: here are some functions which might fulfill your needs:
+ - .capacity()
+ - .len()
+
+error[E0308]: mismatched types
+  --> $DIR/coerce-suggestions.rs:23:19
+   |
+23 |     let x: &str = String::new();
+   |                   ^^^^^^^^^^^^^ expected &str, found struct `std::string::String`
+   |
+   = note: expected type `&str`
+   = note:    found type `std::string::String`
+   = help: here are some functions which might fulfill your needs:
+ - .as_str()
+ - .trim()
+ - .trim_left()
+ - .trim_right()
+
+error[E0308]: mismatched types
+  --> $DIR/coerce-suggestions.rs:30:10
+   |
+30 |     test(&y);
+   |          ^^ types differ in mutability
+   |
+   = note: expected type `&mut std::string::String`
+   = note:    found type `&std::string::String`
+
+error[E0308]: mismatched types
+  --> $DIR/coerce-suggestions.rs:36:11
+   |
+36 |     test2(&y);
+   |           ^^ types differ in mutability
+   |
+   = note: expected type `&mut i32`
+   = note:    found type `&std::string::String`
+
+error[E0308]: mismatched types
+  --> $DIR/coerce-suggestions.rs:42:9
+   |
+42 |     f = box f;
+   |         ^^^^^ cyclic type of infinite size
+   |
+   = note: expected type `_`
+   = note:    found type `Box<_>`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/span/impl-wrong-item-for-trait.stderr b/src/test/ui/span/impl-wrong-item-for-trait.stderr
index 815893e0c82..717f5ee200c 100644
--- a/src/test/ui/span/impl-wrong-item-for-trait.stderr
+++ b/src/test/ui/span/impl-wrong-item-for-trait.stderr
@@ -1,3 +1,9 @@
+error[E0437]: type `bar` is not a member of trait `Foo`
+  --> $DIR/impl-wrong-item-for-trait.rs:47:5
+   |
+47 |     type bar = u64;
+   |     ^^^^^^^^^^^^^^^ not a member of trait `Foo`
+
 error[E0323]: item `bar` is an associated const, which doesn't match its trait `Foo`
   --> $DIR/impl-wrong-item-for-trait.rs:25:5
    |
diff --git a/src/test/ui/span/issue-35987.stderr b/src/test/ui/span/issue-35987.stderr
index 2370b3d6c61..764f34cabde 100644
--- a/src/test/ui/span/issue-35987.stderr
+++ b/src/test/ui/span/issue-35987.stderr
@@ -1,10 +1,11 @@
-error[E0404]: `Add` is not a trait
+error[E0404]: expected trait, found type parameter `Add`
   --> $DIR/issue-35987.rs:15:21
    |
 15 | impl<T: Clone, Add> Add for Foo<T> {
-   |                ---  ^^^ expected trait, found type parameter
-   |                |
-   |                type parameter defined here
+   |                     ^^^ not a trait
+   |
+   = help: possible better candidate is found in another module, you can import it into scope:
+   = help:   `use std::ops::Add;`
 
 error: main function not found
 
diff --git a/src/test/ui/span/typo-suggestion.stderr b/src/test/ui/span/typo-suggestion.stderr
index 5446175aa25..117c38e1db9 100644
--- a/src/test/ui/span/typo-suggestion.stderr
+++ b/src/test/ui/span/typo-suggestion.stderr
@@ -1,10 +1,10 @@
-error[E0425]: unresolved name `bar`
+error[E0425]: unresolved value `bar`
   --> $DIR/typo-suggestion.rs:15:26
    |
 15 |     println!("Hello {}", bar);
-   |                          ^^^ unresolved name
+   |                          ^^^ no resolution found
 
-error[E0425]: unresolved name `fob`
+error[E0425]: unresolved value `fob`
   --> $DIR/typo-suggestion.rs:18:26
    |
 18 |     println!("Hello {}", fob);
diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs
index 800186a926d..26a2e96f571 100644
--- a/src/tools/cargotest/main.rs
+++ b/src/tools/cargotest/main.rs
@@ -24,7 +24,7 @@ struct Test {
 const TEST_REPOS: &'static [Test] = &[Test {
                                           name: "cargo",
                                           repo: "https://github.com/rust-lang/cargo",
-                                          sha: "806e3c368a15f618244a3b4e918bf77f9c403fd0",
+                                          sha: "b7be4f2ef2cf743492edc6dfb55d087ed88f2d76",
                                           lock: None,
                                       },
                                       Test {
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 34f3837d8bb..1aeb76c0a0e 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -127,6 +127,9 @@ pub struct Config {
     // Only run tests that match this filter
     pub filter: Option<String>,
 
+    // Exactly match the filter, rather than a substring
+    pub filter_exact: bool,
+
     // Write out a parseable log of tests that were run
     pub logfile: Option<PathBuf>,
 
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index d8681c9d6ed..e4d9836c562 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -89,6 +89,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
                  "(compile-fail|parse-fail|run-fail|run-pass|\
                   run-pass-valgrind|pretty|debug-info|incremental|mir-opt)"),
           optflag("", "ignored", "run tests marked as ignored"),
+          optflag("", "exact", "filters match exactly"),
           optopt("", "runtool", "supervisor program to run tests under \
                                  (eg. emulator, valgrind)", "PROGRAM"),
           optopt("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS"),
@@ -167,6 +168,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
         mode: matches.opt_str("mode").unwrap().parse().ok().expect("invalid mode"),
         run_ignored: matches.opt_present("ignored"),
         filter: matches.free.first().cloned(),
+        filter_exact: matches.opt_present("exact"),
         logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)),
         runtool: matches.opt_str("runtool"),
         host_rustcflags: matches.opt_str("host-rustcflags"),
@@ -216,6 +218,7 @@ pub fn log_config(config: &Config) {
                     opt_str(&config.filter
                                    .as_ref()
                                    .map(|re| re.to_owned()))));
+    logv(c, format!("filter_exact: {}", config.filter_exact));
     logv(c, format!("runtool: {}", opt_str(&config.runtool)));
     logv(c, format!("host-rustcflags: {}",
                     opt_str(&config.host_rustcflags)));
@@ -309,6 +312,7 @@ pub fn run_tests(config: &Config) {
 pub fn test_opts(config: &Config) -> test::TestOpts {
     test::TestOpts {
         filter: config.filter.clone(),
+        filter_exact: config.filter_exact,
         run_ignored: config.run_ignored,
         quiet: config.quiet,
         logfile: config.logfile.clone(),
@@ -321,6 +325,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
         color: test::AutoColor,
         test_threads: None,
         skip: vec![],
+        list: false,
     }
 }
 
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 3cc14541fcd..d729deb8605 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2108,7 +2108,16 @@ actual:\n\
         }
         self.create_dir_racy(&tmpdir);
 
-        let mut cmd = Command::new("make");
+        let host = &self.config.host;
+        let make = if host.contains("bitrig") || host.contains("dragonfly") ||
+            host.contains("freebsd") || host.contains("netbsd") ||
+            host.contains("openbsd") {
+            "gmake"
+        } else {
+            "make"
+        };
+
+        let mut cmd = Command::new(make);
         cmd.current_dir(&self.testpaths.file)
            .env("TARGET", &self.config.target)
            .env("PYTHON", &self.config.docck_python)
@@ -2294,7 +2303,18 @@ actual:\n\
                 };
             }
             if !found {
-                panic!("ran out of mir dump output to match against");
+                let normalize_all = dumped_string.lines()
+                                                 .map(nocomment_mir_line)
+                                                 .filter(|l| !l.is_empty())
+                                                 .collect::<Vec<_>>()
+                                                 .join("\n");
+                panic!("ran out of mir dump output to match against.\n\
+                        Did not find expected line: {:?}\n\
+                        Expected:\n{}\n\
+                        Actual:\n{}",
+                        expected_line,
+                        expected_content.join("\n"),
+                        normalize_all);
             }
         }
     }
@@ -2439,11 +2459,14 @@ enum TargetLocation {
 }
 
 fn normalize_mir_line(line: &str) -> String {
-    let no_comments = if let Some(idx) = line.find("//") {
+    nocomment_mir_line(line).replace(char::is_whitespace, "")
+}
+
+fn nocomment_mir_line(line: &str) -> &str {
+    if let Some(idx) = line.find("//") {
         let (l, _) = line.split_at(idx);
-        l
+        l.trim_right()
     } else {
         line
-    };
-    no_comments.replace(char::is_whitespace, "")
+    }
 }
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 4ef07f7e4b8..ac5dff0980c 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -67,7 +67,7 @@ pub fn check(path: &Path, bad: &mut bool) {
         }
 
         contents.truncate(0);
-        t!(t!(File::open(file)).read_to_string(&mut contents));
+        t!(t!(File::open(&file), &file).read_to_string(&mut contents));
 
         for (i, line) in contents.lines().enumerate() {
             let mut err = |msg: &str| {
diff --git a/src/vendor/gcc/.cargo-checksum.json b/src/vendor/gcc/.cargo-checksum.json
index efe1ebb7d44..e85f4b21813 100644
--- a/src/vendor/gcc/.cargo-checksum.json
+++ b/src/vendor/gcc/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"f9b1ca6ae27d1c18215265024629a8960c31379f206d9ed20f64e0b2dcf79805",".travis.yml":"5cee7774cf6d876246a0ae0f8362cceeecec5924b751049c945faac9342565ff","Cargo.toml":"2634dedd87889b33a794e31b41a8d8d4713ef40382be3d464229707679bd83da","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"ecb2d93f4c81edbd48d8742ff7887dc0a4530a5890967839090bbc972d49bebe","appveyor.yml":"46c77d913eaa45871296942c2cd96ef092c9dcaf19201cb5c500a5107faeb06f","src/bin/gcc-shim.rs":"11edfe1fc6f932bd42ffffda5145833302bc163e0b87dc0d54f4bd0997ad4708","src/lib.rs":"5eb0e311367226ed0420f5e2dac10cc35fc0a3be639a612b6e8ea6d24f646634","src/registry.rs":"3e2a42581ebb82e325dd5600c6571cef937b35003b2927dc618967f5238a2058","src/windows_registry.rs":"906653c020ffe9d572e435f3fc3a8892d9e0a13240ba297db01ce0a288e08cdb","tests/cc_env.rs":"d92c5e3d3d43ac244e63b2cd2c93a521fcf124bf1ccf8d4c6bfa7f8333d88976","tests/support/mod.rs":"d11ed0db4dda5ecf5fb970c9b0c56428cd47421a2742f07032e2cc6b0a0f07e2","tests/test.rs":"164220f11be2eebc20315826513999970660a82feff8cc4b15b4e9d73d98324e"},"package":"553f11439bdefe755bf366b264820f1da70f3aaf3924e594b886beb9c831bcf5"}
\ No newline at end of file
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"f9b1ca6ae27d1c18215265024629a8960c31379f206d9ed20f64e0b2dcf79805",".travis.yml":"675ffe583db77282d010306f29e6d81e5070ab081deddd0300137dfbd2cb83de","Cargo.toml":"19bb617b74de761515ef5d087fd0e30912fda1d7c22fd04fa211236dab99a509","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"ecb2d93f4c81edbd48d8742ff7887dc0a4530a5890967839090bbc972d49bebe","appveyor.yml":"46c77d913eaa45871296942c2cd96ef092c9dcaf19201cb5c500a5107faeb06f","src/bin/gcc-shim.rs":"11edfe1fc6f932bd42ffffda5145833302bc163e0b87dc0d54f4bd0997ad4708","src/lib.rs":"7e7c60beccfdd145e876da81bb07dd09c5248dab0b26d93190bab4242799d51a","src/registry.rs":"3e2a42581ebb82e325dd5600c6571cef937b35003b2927dc618967f5238a2058","src/windows_registry.rs":"1f4211caec5a192b5f05c8a47efb27aa6a0ab976c659b9318a0cf603a28d6746","tests/cc_env.rs":"d92c5e3d3d43ac244e63b2cd2c93a521fcf124bf1ccf8d4c6bfa7f8333d88976","tests/support/mod.rs":"f4dad5a8133c3dd6678d9a3de057b82e624ef547b9b3e4ac9508a48962fc387b","tests/test.rs":"164220f11be2eebc20315826513999970660a82feff8cc4b15b4e9d73d98324e"},"package":"872db9e59486ef2b14f8e8c10e9ef02de2bccef6363d7f34835dedb386b3d950"}
\ No newline at end of file
diff --git a/src/vendor/gcc/.travis.yml b/src/vendor/gcc/.travis.yml
index 6b508b9d8bc..bf55f49173d 100644
--- a/src/vendor/gcc/.travis.yml
+++ b/src/vendor/gcc/.travis.yml
@@ -19,12 +19,14 @@ script:
   - cargo test --manifest-path gcc-test/Cargo.toml --target $TARGET --features parallel
   - cargo test --manifest-path gcc-test/Cargo.toml --target $TARGET --release
   - cargo doc
+  - cargo clean && cargo build
   - rustdoc --test README.md -L target/debug -L target/debug/deps
 after_success:
   - travis-cargo --only nightly doc-upload
 env:
   global:
-    secure: ilbcq9zX+UaiBcwqkBGldeanbEQus9npLsi0/nF1PUxKbQsoWSVtVOehAD8Hy92D3hX2npIRyNL8GxBn85XEcBYc1h7DiWUhLcXfZie79v8Ly/qboHCfZLXlB1ofbypbyQfouEdOE9zHf0ZILYVpAgUkliv6KuVShsrKNlbn4QE=
+    secure: "CBtqrudgE0PS8x3kTr44jKbC2D4nfnmdYVecooNm0qnER4B4TSvZpZSQoCgKK6k4BYQuOSyFTOwYx6M79w39ZMOgyCP9ytB+tyMWL0/+ZuUQL04yVg4M5vd3oJMkOaXbvG56ncgPyFrseY+FPDg+mXAzvJk/nily37YXjkQj2D0="
+
   matrix:
     - ARCH=x86_64
     - ARCH=i686
diff --git a/src/vendor/gcc/Cargo.toml b/src/vendor/gcc/Cargo.toml
index fd51ce0e9f4..7efdbf9b4b3 100644
--- a/src/vendor/gcc/Cargo.toml
+++ b/src/vendor/gcc/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 
 name = "gcc"
-version = "0.3.38"
+version = "0.3.40"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
 license = "MIT/Apache-2.0"
 repository = "https://github.com/alexcrichton/gcc-rs"
diff --git a/src/vendor/gcc/src/lib.rs b/src/vendor/gcc/src/lib.rs
index f319e9313ad..43cc371117f 100644
--- a/src/vendor/gcc/src/lib.rs
+++ b/src/vendor/gcc/src/lib.rs
@@ -353,6 +353,23 @@ impl Config {
         self.compile_objects(&src_dst);
         self.assemble(lib_name, &dst.join(output), &objects);
 
+        if self.get_target().contains("msvc") {
+            let compiler = self.get_base_compiler();
+            let atlmfc_lib = compiler.env().iter().find(|&&(ref var, _)| {
+                var == OsStr::new("LIB")
+            }).and_then(|&(_, ref lib_paths)| {
+                env::split_paths(lib_paths).find(|path| {
+                    let sub = Path::new("atlmfc/lib");
+                    path.ends_with(sub) || path.parent().map_or(false, |p| p.ends_with(sub))
+                })
+            });
+
+            if let Some(atlmfc_lib) = atlmfc_lib {
+                self.print(&format!("cargo:rustc-link-search=native={}",
+                                    atlmfc_lib.display()));
+            }
+        }
+
         self.print(&format!("cargo:rustc-link-lib=static={}",
                             &output[3..output.len() - 2]));
         self.print(&format!("cargo:rustc-link-search=native={}", dst.display()));
@@ -446,17 +463,20 @@ impl Config {
 
         if msvc {
             cmd.args.push("/nologo".into());
-            cmd.args.push("/MD".into()); // link against msvcrt.dll for now
+            let features = env::var("CARGO_CFG_TARGET_FEATURE")
+                              .unwrap_or(String::new());
+            if features.contains("crt-static") {
+                cmd.args.push("/MT".into());
+            } else {
+                cmd.args.push("/MD".into());
+            }
             match &opt_level[..] {
                 "z" | "s" => cmd.args.push("/Os".into()),
                 "2" => cmd.args.push("/O2".into()),
                 "1" => cmd.args.push("/O1".into()),
                 _ => {}
             }
-            if target.contains("i686") {
-                cmd.args.push("/SAFESEH".into());
-            } else if target.contains("i586") {
-                cmd.args.push("/SAFESEH".into());
+            if target.contains("i586") {
                 cmd.args.push("/ARCH:IA32".into());
             }
         } else if nvcc {
@@ -489,27 +509,48 @@ impl Config {
                 cmd.args.push("-Xcompiler".into());
                 cmd.args.push("\'-fPIC\'".into());
             }
+
             if target.contains("musl") {
                 cmd.args.push("-static".into());
             }
 
+            // armv7 targets get to use armv7 instructions
             if target.starts_with("armv7-unknown-linux-") {
                 cmd.args.push("-march=armv7-a".into());
             }
+
+            // On android we can guarantee some extra float instructions
+            // (specified in the android spec online)
             if target.starts_with("armv7-linux-androideabi") {
                 cmd.args.push("-march=armv7-a".into());
                 cmd.args.push("-mfpu=vfpv3-d16".into());
             }
+
+            // For us arm == armv6 by default
             if target.starts_with("arm-unknown-linux-") {
                 cmd.args.push("-march=armv6".into());
                 cmd.args.push("-marm".into());
             }
+
+            // Turn codegen down on i586 to avoid some instructions.
             if target.starts_with("i586-unknown-linux-") {
                 cmd.args.push("-march=pentium".into());
             }
+
+            // Set codegen level for i686 correctly
             if target.starts_with("i686-unknown-linux-") {
                 cmd.args.push("-march=i686".into());
             }
+
+            // Looks like `musl-gcc` makes is hard for `-m32` to make its way
+            // all the way to the linker, so we need to actually instruct the
+            // linker that we're generating 32-bit executables as well. This'll
+            // typically only be used for build scripts which transitively use
+            // these flags that try to compile executables.
+            if target == "i686-unknown-linux-musl" {
+                cmd.args.push("-Wl,-melf_i386".into());
+            }
+
             if target.starts_with("thumb") {
                 cmd.args.push("-mthumb".into());
 
@@ -518,10 +559,14 @@ impl Config {
                 }
             }
             if target.starts_with("thumbv6m") {
-                cmd.args.push("-march=armv6-m".into());
+                cmd.args.push("-march=armv6s-m".into());
             }
             if target.starts_with("thumbv7em") {
                 cmd.args.push("-march=armv7e-m".into());
+
+                if target.ends_with("eabihf") {
+                    cmd.args.push("-mfpu=fpv4-sp-d16".into())
+                }
             }
             if target.starts_with("thumbv7m") {
                 cmd.args.push("-march=armv7-m".into());
@@ -739,6 +784,7 @@ impl Config {
                     "powerpc64-unknown-linux-gnu" => Some("powerpc-linux-gnu"),
                     "powerpc64le-unknown-linux-gnu" => Some("powerpc64le-linux-gnu"),
                     "s390x-unknown-linux-gnu" => Some("s390x-linux-gnu"),
+                    "sparc64-unknown-netbsd" => Some("sparc64--netbsd"),
                     "thumbv6m-none-eabi" => Some("arm-none-eabi"),
                     "thumbv7em-none-eabi" => Some("arm-none-eabi"),
                     "thumbv7em-none-eabihf" => Some("arm-none-eabi"),
@@ -805,6 +851,8 @@ impl Config {
                 None
             } else if target.contains("darwin") {
                 Some("c++".to_string())
+            } else if target.contains("freebsd") {
+                Some("c++".to_string())
             } else {
                 Some("stdc++".to_string())
             }
diff --git a/src/vendor/gcc/src/windows_registry.rs b/src/vendor/gcc/src/windows_registry.rs
index b2c719d27ff..e16a33f2464 100644
--- a/src/vendor/gcc/src/windows_registry.rs
+++ b/src/vendor/gcc/src/windows_registry.rs
@@ -211,6 +211,11 @@ pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
             let sub = otry!(vc_lib_subdir(target));
             tool.libs.push(path.join("lib").join(sub));
             tool.include.push(path.join("include"));
+            let atlmfc_path = path.join("atlmfc");
+            if atlmfc_path.exists() {
+                tool.libs.push(atlmfc_path.join("lib").join(sub));
+                tool.include.push(atlmfc_path.join("include"));
+            }
             Some(tool)
         }).next()
     }
diff --git a/src/vendor/gcc/tests/support/mod.rs b/src/vendor/gcc/tests/support/mod.rs
index b5703d2fd8b..5c40984eb6a 100644
--- a/src/vendor/gcc/tests/support/mod.rs
+++ b/src/vendor/gcc/tests/support/mod.rs
@@ -23,6 +23,9 @@ impl Test {
     pub fn new() -> Test {
         let mut gcc = PathBuf::from(env::current_exe().unwrap());
         gcc.pop();
+        if gcc.ends_with("deps") {
+            gcc.pop();
+        }
         gcc.push(format!("gcc-shim{}", env::consts::EXE_SUFFIX));
         Test {
             td: TempDir::new("gcc-test").unwrap(),
diff --git a/x.py b/x.py
index 54148b0d2b2..d281a6abc93 100755
--- a/x.py
+++ b/x.py
@@ -16,4 +16,7 @@ sys.path.append(os.path.abspath(os.path.join(dir, "src", "bootstrap")))
 
 import bootstrap
 
-bootstrap.main()
+try:
+    bootstrap.main()
+except KeyboardInterrupt:
+    sys.exit()