about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
592 files changed, 19005 insertions, 10314 deletions
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(),